authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-01-29 02:50:40+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-29 02:50:40+01:00
logabb8e7478d365088301a9390c12f86b2ad381ce9
tree800c02a60af03be8dd4136d86d8168491e4f6673
parent96a5f7c8edac4bb2f50bdfe31c1287207d90d29b
parent5b315f8a3a6c925bdcbbc182d5bdc14f5f726146
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18714 from ziglang/macho-mem

macho: reduce heap allocations

11 files changed, 405 insertions(+), 296 deletions(-)

build.zig+1-1
...@@ -623,7 +623,7 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St...@@ -623,7 +623,7 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St
623 .root_source_file = .{ .path = "src/main.zig" },623 .root_source_file = .{ .path = "src/main.zig" },
624 .target = options.target,624 .target = options.target,
625 .optimize = options.optimize,625 .optimize = options.optimize,
626 .max_rss = 8_000_000_000,626 .max_rss = 7_000_000_000,
627 .strip = options.strip,627 .strip = options.strip,
628 .sanitize_thread = options.sanitize_thread,628 .sanitize_thread = options.sanitize_thread,
629 .single_threaded = options.single_threaded,629 .single_threaded = options.single_threaded,
src/link/MachO.zig+17-40
...@@ -610,7 +610,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -610,7 +610,10 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
610 if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately610 if (mem.indexOf(u8, sect.segName(), "ZIG") == null) continue; // Non-Zig sections are handled separately
611 // TODO: we will resolve and write ZigObject's TLS data twice:611 // TODO: we will resolve and write ZigObject's TLS data twice:
612 // once here, and once in writeAtoms612 // once here, and once in writeAtoms
613 const code = zo.getAtomDataAlloc(self, gpa, atom.*) catch |err| switch (err) {613 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
614 const code = try gpa.alloc(u8, atom_size);
615 defer gpa.free(code);
616 atom.getData(self, code) catch |err| switch (err) {
614 error.InputOutput => {617 error.InputOutput => {
615 try self.reportUnexpectedError("fetching code for '{s}' failed", .{618 try self.reportUnexpectedError("fetching code for '{s}' failed", .{
616 atom.getName(self),619 atom.getName(self),
...@@ -625,7 +628,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node...@@ -625,7 +628,6 @@ pub fn flushModule(self: *MachO, arena: Allocator, prog_node: *std.Progress.Node
625 return error.FlushFailure;628 return error.FlushFailure;
626 },629 },
627 };630 };
628 defer gpa.free(code);
629 const file_offset = sect.offset + atom.value - sect.addr;631 const file_offset = sect.offset + atom.value - sect.addr;
630 atom.resolveRelocs(self, code) catch |err| switch (err) {632 atom.resolveRelocs(self, code) catch |err| switch (err) {
631 error.ResolveFailed => has_resolve_error = true,633 error.ResolveFailed => has_resolve_error = true,
...@@ -974,17 +976,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {...@@ -974,17 +976,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
974976
975 const gpa = self.base.comp.gpa;977 const gpa = self.base.comp.gpa;
976 const file = try std.fs.cwd().openFile(path, .{});978 const file = try std.fs.cwd().openFile(path, .{});
977 defer file.close();
978 const mtime: u64 = mtime: {979 const mtime: u64 = mtime: {
979 const stat = file.stat() catch break :mtime 0;980 const stat = file.stat() catch break :mtime 0;
980 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));981 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
981 };982 };
982 const data = try file.readToEndAlloc(gpa, std.math.maxInt(u32));
983 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));983 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
984 self.files.set(index, .{ .object = .{984 self.files.set(index, .{ .object = .{
985 .path = try gpa.dupe(u8, path),985 .path = try gpa.dupe(u8, path),
986 .file = file,
986 .mtime = mtime,987 .mtime = mtime,
987 .data = data,
988 .index = index,988 .index = index,
989 } });989 } });
990 try self.objects.append(gpa, index);990 try self.objects.append(gpa, index);
...@@ -1013,17 +1013,9 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar...@@ -1013,17 +1013,9 @@ fn parseArchive(self: *MachO, lib: SystemLib, must_link: bool, fat_arch: ?fat.Ar
1013 const file = try std.fs.cwd().openFile(lib.path, .{});1013 const file = try std.fs.cwd().openFile(lib.path, .{});
1014 defer file.close();1014 defer file.close();
10151015
1016 const data = if (fat_arch) |arch| blk: {1016 var archive = Archive{};
1017 try file.seekTo(arch.offset);
1018 const data = try gpa.alloc(u8, arch.size);
1019 const nread = try file.readAll(data);
1020 if (nread != arch.size) return error.InputOutput;
1021 break :blk data;
1022 } else try file.readToEndAlloc(gpa, std.math.maxInt(u32));
1023
1024 var archive = Archive{ .path = try gpa.dupe(u8, lib.path), .data = data };
1025 defer archive.deinit(gpa);1017 defer archive.deinit(gpa);
1026 try archive.parse(self);1018 try archive.parse(self, lib.path, file, fat_arch);
10271019
1028 var has_parse_error = false;1020 var has_parse_error = false;
1029 for (archive.objects.items) |extracted| {1021 for (archive.objects.items) |extracted| {
...@@ -1058,18 +1050,9 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch)...@@ -1058,18 +1050,9 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch)
1058 const file = try std.fs.cwd().openFile(lib.path, .{});1050 const file = try std.fs.cwd().openFile(lib.path, .{});
1059 defer file.close();1051 defer file.close();
10601052
1061 const data = if (fat_arch) |arch| blk: {
1062 try file.seekTo(arch.offset);
1063 const data = try gpa.alloc(u8, arch.size);
1064 const nread = try file.readAll(data);
1065 if (nread != arch.size) return error.InputOutput;
1066 break :blk data;
1067 } else try file.readToEndAlloc(gpa, std.math.maxInt(u32));
1068
1069 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1053 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1070 self.files.set(index, .{ .dylib = .{1054 self.files.set(index, .{ .dylib = .{
1071 .path = try gpa.dupe(u8, lib.path),1055 .path = try gpa.dupe(u8, lib.path),
1072 .data = data,
1073 .index = index,1056 .index = index,
1074 .needed = lib.needed,1057 .needed = lib.needed,
1075 .weak = lib.weak,1058 .weak = lib.weak,
...@@ -1077,7 +1060,7 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch)...@@ -1077,7 +1060,7 @@ fn parseDylib(self: *MachO, lib: SystemLib, explicit: bool, fat_arch: ?fat.Arch)
1077 .explicit = explicit,1060 .explicit = explicit,
1078 } });1061 } });
1079 const dylib = &self.files.items(.data)[index].dylib;1062 const dylib = &self.files.items(.data)[index].dylib;
1080 try dylib.parse(self);1063 try dylib.parse(self, file, fat_arch);
10811064
1082 try self.dylibs.append(gpa, index);1065 try self.dylibs.append(gpa, index);
10831066
...@@ -1098,7 +1081,6 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index...@@ -1098,7 +1081,6 @@ fn parseTbd(self: *MachO, lib: SystemLib, explicit: bool) ParseError!File.Index
1098 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));1081 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
1099 self.files.set(index, .{ .dylib = .{1082 self.files.set(index, .{ .dylib = .{
1100 .path = try gpa.dupe(u8, lib.path),1083 .path = try gpa.dupe(u8, lib.path),
1101 .data = &[0]u8{},
1102 .index = index,1084 .index = index,
1103 .needed = lib.needed,1085 .needed = lib.needed,
1104 .weak = lib.weak,1086 .weak = lib.weak,
...@@ -1404,6 +1386,8 @@ pub fn resolveSymbols(self: *MachO) !void {...@@ -1404,6 +1386,8 @@ pub fn resolveSymbols(self: *MachO) !void {
1404 const index = self.objects.items[i];1386 const index = self.objects.items[i];
1405 if (!self.getFile(index).?.object.alive) {1387 if (!self.getFile(index).?.object.alive) {
1406 _ = self.objects.orderedRemove(i);1388 _ = self.objects.orderedRemove(i);
1389 self.files.items(.data)[index].object.deinit(self.base.comp.gpa);
1390 self.files.set(index, .null);
1407 } else i += 1;1391 } else i += 1;
1408 }1392 }
14091393
...@@ -1511,18 +1495,13 @@ fn createObjcSections(self: *MachO) !void {...@@ -1511,18 +1495,13 @@ fn createObjcSections(self: *MachO) !void {
1511 }1495 }
15121496
1513 for (objc_msgsend_syms.keys()) |sym_index| {1497 for (objc_msgsend_syms.keys()) |sym_index| {
1498 const internal = self.getInternalObject().?;
1514 const sym = self.getSymbol(sym_index);1499 const sym = self.getSymbol(sym_index);
1515 sym.value = 0;1500 _ = try internal.addSymbol(sym.getName(self), self);
1516 sym.atom = 0;
1517 sym.nlist_idx = 0;
1518 sym.file = self.internal_object.?;
1519 sym.flags = .{};
1520 sym.visibility = .hidden;1501 sym.visibility = .hidden;
1521 const object = self.getInternalObject().?;
1522 const name = eatPrefix(sym.getName(self), "_objc_msgSend$").?;1502 const name = eatPrefix(sym.getName(self), "_objc_msgSend$").?;
1523 const selrefs_index = try object.addObjcMsgsendSections(name, self);1503 const selrefs_index = try internal.addObjcMsgsendSections(name, self);
1524 try sym.addExtra(.{ .objc_selrefs = selrefs_index }, self);1504 try sym.addExtra(.{ .objc_selrefs = selrefs_index }, self);
1525 try object.symbols.append(gpa, sym_index);
1526 }1505 }
1527}1506}
15281507
...@@ -1659,6 +1638,8 @@ fn deadStripDylibs(self: *MachO) void {...@@ -1659,6 +1638,8 @@ fn deadStripDylibs(self: *MachO) void {
1659 const index = self.dylibs.items[i];1638 const index = self.dylibs.items[i];
1660 if (!self.getFile(index).?.dylib.isAlive(self)) {1639 if (!self.getFile(index).?.dylib.isAlive(self)) {
1661 _ = self.dylibs.orderedRemove(i);1640 _ = self.dylibs.orderedRemove(i);
1641 self.files.items(.data)[index].dylib.deinit(self.base.comp.gpa);
1642 self.files.set(index, .null);
1662 } else i += 1;1643 } else i += 1;
1663 }1644 }
1664}1645}
...@@ -2609,13 +2590,8 @@ fn writeAtoms(self: *MachO) !void {...@@ -2609,13 +2590,8 @@ fn writeAtoms(self: *MachO) !void {
2609 const atom = self.getAtom(atom_index).?;2590 const atom = self.getAtom(atom_index).?;
2610 assert(atom.flags.alive);2591 assert(atom.flags.alive);
2611 const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow;2592 const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow;
2612 const data = switch (atom.getFile(self)) {
2613 .object => |x| try x.getAtomData(atom.*),
2614 .zig_object => |x| try x.getAtomDataAlloc(self, arena.allocator(), atom.*),
2615 else => unreachable,
2616 };
2617 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;2593 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
2618 @memcpy(buffer[off..][0..atom_size], data);2594 try atom.getData(self, buffer[off..][0..atom_size]);
2619 atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) {2595 atom.resolveRelocs(self, buffer[off..][0..atom_size]) catch |err| switch (err) {
2620 error.ResolveFailed => has_resolve_error = true,2596 error.ResolveFailed => has_resolve_error = true,
2621 else => |e| return e,2597 else => |e| return e,
...@@ -3734,6 +3710,7 @@ pub fn getOrCreateGlobal(self: *MachO, off: u32) !GetOrCreateGlobalResult {...@@ -3734,6 +3710,7 @@ pub fn getOrCreateGlobal(self: *MachO, off: u32) !GetOrCreateGlobalResult {
3734 const index = try self.addSymbol();3710 const index = try self.addSymbol();
3735 const global = self.getSymbol(index);3711 const global = self.getSymbol(index);
3736 global.name = off;3712 global.name = off;
3713 global.flags.global = true;
3737 gop.value_ptr.* = index;3714 gop.value_ptr.* = index;
3738 }3715 }
3739 return .{3716 return .{
src/link/MachO/Archive.zig+26-18
...@@ -1,6 +1,3 @@...@@ -1,6 +1,3 @@
1path: []const u8,
2data: []const u8,
3
4objects: std.ArrayListUnmanaged(Object) = .{},1objects: std.ArrayListUnmanaged(Object) = .{},
52
6// Archive files start with the ARMAG identifying string. Then follows a3// Archive files start with the ARMAG identifying string. Then follows a
...@@ -73,62 +70,73 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {...@@ -73,62 +70,73 @@ pub fn isArchive(path: []const u8, fat_arch: ?fat.Arch) !bool {
73}70}
7471
75pub fn deinit(self: *Archive, allocator: Allocator) void {72pub fn deinit(self: *Archive, allocator: Allocator) void {
76 allocator.free(self.data);
77 allocator.free(self.path);
78 self.objects.deinit(allocator);73 self.objects.deinit(allocator);
79}74}
8075
81pub fn parse(self: *Archive, macho_file: *MachO) !void {76pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, file: std.fs.File, fat_arch: ?fat.Arch) !void {
82 const gpa = macho_file.base.comp.gpa;77 const gpa = macho_file.base.comp.gpa;
8378
84 var arena = std.heap.ArenaAllocator.init(gpa);79 var arena = std.heap.ArenaAllocator.init(gpa);
85 defer arena.deinit();80 defer arena.deinit();
8681
87 var stream = std.io.fixedBufferStream(self.data);82 const offset = if (fat_arch) |ar| ar.offset else 0;
88 const reader = stream.reader();83 const size = if (fat_arch) |ar| ar.size else (try file.stat()).size;
89 _ = try reader.readBytesNoEof(SARMAG);84 try file.seekTo(offset);
85
86 const reader = file.reader();
87 _ = try reader.readBytesNoEof(Archive.SARMAG);
9088
89 var pos: usize = Archive.SARMAG;
91 while (true) {90 while (true) {
92 if (stream.pos >= self.data.len) break;91 if (pos >= size) break;
93 if (!mem.isAligned(stream.pos, 2)) stream.pos += 1;92 if (!mem.isAligned(pos, 2)) {
93 try file.seekBy(1);
94 pos += 1;
95 }
9496
95 const hdr = try reader.readStruct(ar_hdr);97 const hdr = try reader.readStruct(ar_hdr);
98 pos += @sizeOf(ar_hdr);
9699
97 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {100 if (!mem.eql(u8, &hdr.ar_fmag, ARFMAG)) {
98 try macho_file.reportParseError(self.path, "invalid header delimiter: expected '{s}', found '{s}'", .{101 try macho_file.reportParseError(path, "invalid header delimiter: expected '{s}', found '{s}'", .{
99 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),102 std.fmt.fmtSliceEscapeLower(ARFMAG), std.fmt.fmtSliceEscapeLower(&hdr.ar_fmag),
100 });103 });
101 return error.MalformedArchive;104 return error.MalformedArchive;
102 }105 }
103106
104 var size = try hdr.size();107 var hdr_size = try hdr.size();
105 const name = name: {108 const name = name: {
106 if (hdr.name()) |n| break :name n;109 if (hdr.name()) |n| break :name n;
107 if (try hdr.nameLength()) |len| {110 if (try hdr.nameLength()) |len| {
108 size -= len;111 hdr_size -= len;
109 const buf = try arena.allocator().alloc(u8, len);112 const buf = try arena.allocator().alloc(u8, len);
110 try reader.readNoEof(buf);113 try reader.readNoEof(buf);
114 pos += len;
111 const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len;115 const actual_len = mem.indexOfScalar(u8, buf, @as(u8, 0)) orelse len;
112 break :name buf[0..actual_len];116 break :name buf[0..actual_len];
113 }117 }
114 unreachable;118 unreachable;
115 };119 };
116 defer {120 defer {
117 _ = stream.seekBy(size) catch {};121 _ = file.seekBy(hdr_size) catch {};
122 pos += hdr_size;
118 }123 }
119124
120 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;125 if (mem.eql(u8, name, "__.SYMDEF") or mem.eql(u8, name, "__.SYMDEF SORTED")) continue;
121126
122 const object = Object{127 const object = Object{
123 .archive = try gpa.dupe(u8, self.path),128 .archive = .{
129 .path = try gpa.dupe(u8, path),
130 .offset = offset + pos,
131 },
124 .path = try gpa.dupe(u8, name),132 .path = try gpa.dupe(u8, name),
125 .data = try gpa.dupe(u8, self.data[stream.pos..][0..size]),133 .file = try std.fs.cwd().openFile(path, .{}),
126 .index = undefined,134 .index = undefined,
127 .alive = false,135 .alive = false,
128 .mtime = hdr.date() catch 0,136 .mtime = hdr.date() catch 0,
129 };137 };
130138
131 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, self.path });139 log.debug("extracting object '{s}' from archive '{s}'", .{ object.path, path });
132140
133 try self.objects.append(gpa, object);141 try self.objects.append(gpa, object);
134 }142 }
src/link/MachO/Atom.zig+19-5
...@@ -43,26 +43,40 @@ prev_index: Index = 0,...@@ -43,26 +43,40 @@ prev_index: Index = 0,
43next_index: Index = 0,43next_index: Index = 0,
4444
45pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 {45pub fn getName(self: Atom, macho_file: *MachO) [:0]const u8 {
46 return macho_file.strings.getAssumeExists(self.name);46 return switch (self.getFile(macho_file)) {
47 .dylib => unreachable,
48 .zig_object => |x| x.strtab.getAssumeExists(self.name),
49 inline else => |x| x.getString(self.name),
50 };
47}51}
4852
49pub fn getFile(self: Atom, macho_file: *MachO) File {53pub fn getFile(self: Atom, macho_file: *MachO) File {
50 return macho_file.getFile(self.file).?;54 return macho_file.getFile(self.file).?;
51}55}
5256
57pub fn getData(self: Atom, macho_file: *MachO, buffer: []u8) !void {
58 assert(buffer.len == self.size);
59 switch (self.getFile(macho_file)) {
60 .internal => |x| try x.getAtomData(self, buffer),
61 .object => |x| try x.getAtomData(self, buffer),
62 .zig_object => |x| try x.getAtomData(macho_file, self, buffer),
63 else => unreachable,
64 }
65}
66
53pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {67pub fn getRelocs(self: Atom, macho_file: *MachO) []const Relocation {
54 return switch (self.getFile(macho_file)) {68 return switch (self.getFile(macho_file)) {
55 .zig_object => |x| x.getAtomRelocs(self),69 .dylib => unreachable,
56 .object => |x| x.getAtomRelocs(self),70 inline else => |x| x.getAtomRelocs(self),
57 else => unreachable,
58 };71 };
59}72}
6073
61pub fn getInputSection(self: Atom, macho_file: *MachO) macho.section_64 {74pub fn getInputSection(self: Atom, macho_file: *MachO) macho.section_64 {
62 return switch (self.getFile(macho_file)) {75 return switch (self.getFile(macho_file)) {
76 .dylib => unreachable,
63 .zig_object => |x| x.getInputSection(self, macho_file),77 .zig_object => |x| x.getInputSection(self, macho_file),
64 .object => |x| x.sections.items(.header)[self.n_sect],78 .object => |x| x.sections.items(.header)[self.n_sect],
65 else => unreachable,79 .internal => |x| x.sections.items(.header)[self.n_sect],
66 };80 };
67}81}
6882
src/link/MachO/DwarfInfo.zig+39-20
...@@ -1,15 +1,17 @@...@@ -1,15 +1,17 @@
1debug_info: []const u8,
2debug_abbrev: []const u8,
3debug_str: []const u8,
4
5/// Abbreviation table indexed by offset in the .debug_abbrev bytestream1/// Abbreviation table indexed by offset in the .debug_abbrev bytestream
6abbrev_tables: std.AutoArrayHashMapUnmanaged(u64, AbbrevTable) = .{},2abbrev_tables: std.AutoArrayHashMapUnmanaged(u64, AbbrevTable) = .{},
7/// List of compile units as they appear in the .debug_info bytestream3/// List of compile units as they appear in the .debug_info bytestream
8compile_units: std.ArrayListUnmanaged(CompileUnit) = .{},4compile_units: std.ArrayListUnmanaged(CompileUnit) = .{},
95/// Debug info string table
10pub fn init(dw: *DwarfInfo, allocator: Allocator) !void {6strtab: std.ArrayListUnmanaged(u8) = .{},
11 try dw.parseAbbrevTables(allocator);7/// Debug info data
12 try dw.parseCompileUnits(allocator);8di_data: std.ArrayListUnmanaged(u8) = .{},
9
10pub fn init(dw: *DwarfInfo, allocator: Allocator, di: DebugInfo) !void {
11 try dw.strtab.ensureTotalCapacityPrecise(allocator, di.debug_str.len);
12 dw.strtab.appendSliceAssumeCapacity(di.debug_str);
13 try dw.parseAbbrevTables(allocator, di);
14 try dw.parseCompileUnits(allocator, di);
13}15}
1416
15pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void {17pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void {
...@@ -18,18 +20,27 @@ pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void {...@@ -18,18 +20,27 @@ pub fn deinit(dw: *DwarfInfo, allocator: Allocator) void {
18 cu.deinit(allocator);20 cu.deinit(allocator);
19 }21 }
20 dw.compile_units.deinit(allocator);22 dw.compile_units.deinit(allocator);
23 dw.strtab.deinit(allocator);
24 dw.di_data.deinit(allocator);
25}
26
27fn appendDiData(dw: *DwarfInfo, allocator: Allocator, values: []const u8) error{OutOfMemory}!u32 {
28 const index: u32 = @intCast(dw.di_data.items.len);
29 try dw.di_data.ensureUnusedCapacity(allocator, values.len);
30 dw.di_data.appendSliceAssumeCapacity(values);
31 return index;
21}32}
2233
23fn getString(dw: DwarfInfo, off: usize) [:0]const u8 {34fn getString(dw: DwarfInfo, off: usize) [:0]const u8 {
24 assert(off < dw.debug_str.len);35 assert(off < dw.strtab.items.len);
25 return mem.sliceTo(@as([*:0]const u8, @ptrCast(dw.debug_str.ptr + off)), 0);36 return mem.sliceTo(@as([*:0]const u8, @ptrCast(dw.strtab.items.ptr + off)), 0);
26}37}
2738
28fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator) !void {39fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator, di: DebugInfo) !void {
29 const tracy = trace(@src());40 const tracy = trace(@src());
30 defer tracy.end();41 defer tracy.end();
3142
32 const debug_abbrev = dw.debug_abbrev;43 const debug_abbrev = di.debug_abbrev;
33 var stream = std.io.fixedBufferStream(debug_abbrev);44 var stream = std.io.fixedBufferStream(debug_abbrev);
34 var creader = std.io.countingReader(stream.reader());45 var creader = std.io.countingReader(stream.reader());
35 const reader = creader.reader();46 const reader = creader.reader();
...@@ -77,11 +88,11 @@ fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator) !void {...@@ -77,11 +88,11 @@ fn parseAbbrevTables(dw: *DwarfInfo, allocator: Allocator) !void {
77 }88 }
78}89}
7990
80fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator) !void {91fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator, di: DebugInfo) !void {
81 const tracy = trace(@src());92 const tracy = trace(@src());
82 defer tracy.end();93 defer tracy.end();
8394
84 const debug_info = dw.debug_info;95 const debug_info = di.debug_info;
85 var stream = std.io.fixedBufferStream(debug_info);96 var stream = std.io.fixedBufferStream(debug_info);
86 var creader = std.io.countingReader(stream.reader());97 var creader = std.io.countingReader(stream.reader());
87 const reader = creader.reader();98 const reader = creader.reader();
...@@ -107,7 +118,7 @@ fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator) !void {...@@ -107,7 +118,7 @@ fn parseCompileUnits(dw: *DwarfInfo, allocator: Allocator) !void {
107 cu.header.address_size = try reader.readInt(u8, .little);118 cu.header.address_size = try reader.readInt(u8, .little);
108119
109 const table = dw.abbrev_tables.get(cu.header.debug_abbrev_offset).?;120 const table = dw.abbrev_tables.get(cu.header.debug_abbrev_offset).?;
110 try dw.parseDie(allocator, cu, table, null, &creader);121 try dw.parseDie(allocator, cu, table, di, null, &creader);
111 }122 }
112}123}
113124
...@@ -116,6 +127,7 @@ fn parseDie(...@@ -116,6 +127,7 @@ fn parseDie(
116 allocator: Allocator,127 allocator: Allocator,
117 cu: *CompileUnit,128 cu: *CompileUnit,
118 table: AbbrevTable,129 table: AbbrevTable,
130 di: DebugInfo,
119 parent: ?u32,131 parent: ?u32,
120 creader: anytype,132 creader: anytype,
121) anyerror!void {133) anyerror!void {
...@@ -140,19 +152,20 @@ fn parseDie(...@@ -140,19 +152,20 @@ fn parseDie(
140 }152 }
141153
142 const decl = table.decls.get(code) orelse return error.MalformedDwarf; // TODO better errors154 const decl = table.decls.get(code) orelse return error.MalformedDwarf; // TODO better errors
143 const data = dw.debug_info;155 const data = di.debug_info;
144 try cu.diePtr(die).values.ensureTotalCapacityPrecise(allocator, decl.attrs.values().len);156 try cu.diePtr(die).values.ensureTotalCapacityPrecise(allocator, decl.attrs.values().len);
145157
146 for (decl.attrs.values()) |attr| {158 for (decl.attrs.values()) |attr| {
147 const start = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow;159 const start = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow;
148 try advanceByFormSize(cu, attr.form, creader);160 try advanceByFormSize(cu, attr.form, creader);
149 const end = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow;161 const end = std.math.cast(usize, creader.bytes_read) orelse return error.Overflow;
150 cu.diePtr(die).values.appendAssumeCapacity(data[start..end]);162 const index = try dw.appendDiData(allocator, data[start..end]);
163 cu.diePtr(die).values.appendAssumeCapacity(.{ .index = index, .len = @intCast(end - start) });
151 }164 }
152165
153 if (decl.children) {166 if (decl.children) {
154 // Open scope167 // Open scope
155 try dw.parseDie(allocator, cu, table, die, creader);168 try dw.parseDie(allocator, cu, table, di, die, creader);
156 }169 }
157 }170 }
158}171}
...@@ -340,7 +353,7 @@ pub const CompileUnit = struct {...@@ -340,7 +353,7 @@ pub const CompileUnit = struct {
340353
341pub const Die = struct {354pub const Die = struct {
342 code: Code,355 code: Code,
343 values: std.ArrayListUnmanaged([]const u8) = .{},356 values: std.ArrayListUnmanaged(struct { index: u32, len: u32 }) = .{},
344 children: std.ArrayListUnmanaged(Die.Index) = .{},357 children: std.ArrayListUnmanaged(Die.Index) = .{},
345358
346 pub fn deinit(die: *Die, gpa: Allocator) void {359 pub fn deinit(die: *Die, gpa: Allocator) void {
...@@ -354,7 +367,7 @@ pub const Die = struct {...@@ -354,7 +367,7 @@ pub const Die = struct {
354 const index = decl.attrs.getIndex(at) orelse return null;367 const index = decl.attrs.getIndex(at) orelse return null;
355 const attr = decl.attrs.values()[index];368 const attr = decl.attrs.values()[index];
356 const value = die.values.items[index];369 const value = die.values.items[index];
357 return .{ .attr = attr, .bytes = value };370 return .{ .attr = attr, .bytes = ctx.di_data.items[value.index..][0..value.len] };
358 }371 }
359372
360 pub const Index = u32;373 pub const Index = u32;
...@@ -458,6 +471,12 @@ pub const Format = enum {...@@ -458,6 +471,12 @@ pub const Format = enum {
458 dwarf64,471 dwarf64,
459};472};
460473
474const DebugInfo = struct {
475 debug_info: []const u8,
476 debug_abbrev: []const u8,
477 debug_str: []const u8,
478};
479
461const assert = std.debug.assert;480const assert = std.debug.assert;
462const dwarf = std.dwarf;481const dwarf = std.dwarf;
463const leb = std.leb;482const leb = std.leb;
src/link/MachO/Dylib.zig+49-50
...@@ -1,8 +1,6 @@...@@ -1,8 +1,6 @@
1path: []const u8,1path: []const u8,
2data: []const u8,
3index: File.Index,2index: File.Index,
43
5header: ?macho.mach_header_64 = null,
6exports: std.MultiArrayList(Export) = .{},4exports: std.MultiArrayList(Export) = .{},
7strtab: std.ArrayListUnmanaged(u8) = .{},5strtab: std.ArrayListUnmanaged(u8) = .{},
8id: ?Id = null,6id: ?Id = null,
...@@ -34,7 +32,6 @@ pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool {...@@ -34,7 +32,6 @@ pub fn isDylib(path: []const u8, fat_arch: ?fat.Arch) !bool {
34}32}
3533
36pub fn deinit(self: *Dylib, allocator: Allocator) void {34pub fn deinit(self: *Dylib, allocator: Allocator) void {
37 allocator.free(self.data);
38 allocator.free(self.path);35 allocator.free(self.path);
39 self.exports.deinit(allocator);36 self.exports.deinit(allocator);
40 self.strtab.deinit(allocator);37 self.strtab.deinit(allocator);
...@@ -44,22 +41,29 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void {...@@ -44,22 +41,29 @@ pub fn deinit(self: *Dylib, allocator: Allocator) void {
44 id.deinit(allocator);41 id.deinit(allocator);
45 }42 }
46 self.dependents.deinit(allocator);43 self.dependents.deinit(allocator);
44 for (self.rpaths.keys()) |rpath| {
45 allocator.free(rpath);
46 }
47 self.rpaths.deinit(allocator);47 self.rpaths.deinit(allocator);
48}48}
4949
50pub fn parse(self: *Dylib, macho_file: *MachO) !void {50pub fn parse(self: *Dylib, macho_file: *MachO, file: std.fs.File, fat_arch: ?fat.Arch) !void {
51 const tracy = trace(@src());51 const tracy = trace(@src());
52 defer tracy.end();52 defer tracy.end();
5353
54 const gpa = macho_file.base.comp.gpa;54 const gpa = macho_file.base.comp.gpa;
55 var stream = std.io.fixedBufferStream(self.data);55 const offset = if (fat_arch) |ar| ar.offset else 0;
56 const reader = stream.reader();
5756
58 log.debug("parsing dylib from binary", .{});57 log.debug("parsing dylib from binary", .{});
5958
60 self.header = try reader.readStruct(macho.mach_header_64);59 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
60 {
61 const amt = try file.preadAll(&header_buffer, offset);
62 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
63 }
64 const header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;
6165
62 const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {66 const this_cpu_arch: std.Target.Cpu.Arch = switch (header.cputype) {
63 macho.CPU_TYPE_ARM64 => .aarch64,67 macho.CPU_TYPE_ARM64 => .aarch64,
64 macho.CPU_TYPE_X86_64 => .x86_64,68 macho.CPU_TYPE_X86_64 => .x86_64,
65 else => |x| {69 else => |x| {
...@@ -72,39 +76,60 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void {...@@ -72,39 +76,60 @@ pub fn parse(self: *Dylib, macho_file: *MachO) !void {
72 return error.InvalidCpuArch;76 return error.InvalidCpuArch;
73 }77 }
7478
75 const lc_id = self.getLoadCommand(.ID_DYLIB) orelse {79 const lc_buffer = try gpa.alloc(u8, header.sizeofcmds);
76 try macho_file.reportParseError2(self.index, "missing LC_ID_DYLIB load command", .{});80 defer gpa.free(lc_buffer);
77 return error.MalformedDylib;81 {
78 };82 const amt = try file.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
79 self.id = try Id.fromLoadCommand(gpa, lc_id.cast(macho.dylib_command).?, lc_id.getDylibPathName());83 if (amt != lc_buffer.len) return error.InputOutput;
84 }
8085
81 var it = LoadCommandIterator{86 var it = LoadCommandIterator{
82 .ncmds = self.header.?.ncmds,87 .ncmds = header.ncmds,
83 .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds],88 .buffer = lc_buffer,
84 };89 };
85 while (it.next()) |cmd| switch (cmd.cmd()) {90 while (it.next()) |cmd| switch (cmd.cmd()) {
86 .REEXPORT_DYLIB => if (self.header.?.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0) {91 .ID_DYLIB => {
92 self.id = try Id.fromLoadCommand(gpa, cmd.cast(macho.dylib_command).?, cmd.getDylibPathName());
93 },
94 .REEXPORT_DYLIB => if (header.flags & macho.MH_NO_REEXPORTED_DYLIBS == 0) {
87 const id = try Id.fromLoadCommand(gpa, cmd.cast(macho.dylib_command).?, cmd.getDylibPathName());95 const id = try Id.fromLoadCommand(gpa, cmd.cast(macho.dylib_command).?, cmd.getDylibPathName());
88 try self.dependents.append(gpa, id);96 try self.dependents.append(gpa, id);
89 },97 },
90 .DYLD_INFO_ONLY => {98 .DYLD_INFO_ONLY => {
91 const dyld_cmd = cmd.cast(macho.dyld_info_command).?;99 const dyld_cmd = cmd.cast(macho.dyld_info_command).?;
92 const data = self.data[dyld_cmd.export_off..][0..dyld_cmd.export_size];100 const data = try gpa.alloc(u8, dyld_cmd.export_size);
101 defer gpa.free(data);
102 const amt = try file.preadAll(data, dyld_cmd.export_off + offset);
103 if (amt != data.len) return error.InputOutput;
93 try self.parseTrie(data, macho_file);104 try self.parseTrie(data, macho_file);
94 },105 },
95 .DYLD_EXPORTS_TRIE => {106 .DYLD_EXPORTS_TRIE => {
96 const ld_cmd = cmd.cast(macho.linkedit_data_command).?;107 const ld_cmd = cmd.cast(macho.linkedit_data_command).?;
97 const data = self.data[ld_cmd.dataoff..][0..ld_cmd.datasize];108 const data = try gpa.alloc(u8, ld_cmd.datasize);
109 defer gpa.free(data);
110 const amt = try file.preadAll(data, ld_cmd.dataoff + offset);
111 if (amt != data.len) return error.InputOutput;
98 try self.parseTrie(data, macho_file);112 try self.parseTrie(data, macho_file);
99 },113 },
100 .RPATH => {114 .RPATH => {
101 const path = cmd.getRpathPathName();115 const path = cmd.getRpathPathName();
102 try self.rpaths.put(gpa, path, {});116 try self.rpaths.put(gpa, try gpa.dupe(u8, path), {});
117 },
118 .BUILD_VERSION,
119 .VERSION_MIN_MACOSX,
120 .VERSION_MIN_IPHONEOS,
121 .VERSION_MIN_TVOS,
122 .VERSION_MIN_WATCHOS,
123 => {
124 self.platform = MachO.Platform.fromLoadCommand(cmd);
103 },125 },
104 else => {},126 else => {},
105 };127 };
106128
107 self.initPlatform();129 if (self.id == null) {
130 try macho_file.reportParseError2(self.index, "missing LC_ID_DYLIB load command", .{});
131 return error.MalformedDylib;
132 }
108133
109 if (self.platform) |platform| {134 if (self.platform) |platform| {
110 if (!macho_file.platform.eqlTarget(platform)) {135 if (!macho_file.platform.eqlTarget(platform)) {
...@@ -168,7 +193,7 @@ const TrieIterator = struct {...@@ -168,7 +193,7 @@ const TrieIterator = struct {
168193
169pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {194pub fn addExport(self: *Dylib, allocator: Allocator, name: []const u8, flags: Export.Flags) !void {
170 try self.exports.append(allocator, .{195 try self.exports.append(allocator, .{
171 .name = try self.insertString(allocator, name),196 .name = try self.addString(allocator, name),
172 .flags = flags,197 .flags = flags,
173 });198 });
174}199}
...@@ -479,24 +504,6 @@ pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void {...@@ -479,24 +504,6 @@ pub fn initSymbols(self: *Dylib, macho_file: *MachO) !void {
479 }504 }
480}505}
481506
482fn initPlatform(self: *Dylib) void {
483 var it = LoadCommandIterator{
484 .ncmds = self.header.?.ncmds,
485 .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds],
486 };
487 self.platform = while (it.next()) |cmd| {
488 switch (cmd.cmd()) {
489 .BUILD_VERSION,
490 .VERSION_MIN_MACOSX,
491 .VERSION_MIN_IPHONEOS,
492 .VERSION_MIN_TVOS,
493 .VERSION_MIN_WATCHOS,
494 => break MachO.Platform.fromLoadCommand(cmd),
495 else => {},
496 }
497 } else null;
498}
499
500pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void {507pub fn resolveSymbols(self: *Dylib, macho_file: *MachO) void {
501 const tracy = trace(@src());508 const tracy = trace(@src());
502 defer tracy.end();509 defer tracy.end();
...@@ -526,8 +533,10 @@ pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void {...@@ -526,8 +533,10 @@ pub fn resetGlobals(self: *Dylib, macho_file: *MachO) void {
526 for (self.symbols.items) |sym_index| {533 for (self.symbols.items) |sym_index| {
527 const sym = macho_file.getSymbol(sym_index);534 const sym = macho_file.getSymbol(sym_index);
528 const name = sym.name;535 const name = sym.name;
536 const global = sym.flags.global;
529 sym.* = .{};537 sym.* = .{};
530 sym.name = name;538 sym.name = name;
539 sym.flags.global = global;
531 }540 }
532}541}
533542
...@@ -589,17 +598,7 @@ pub inline fn getUmbrella(self: Dylib, macho_file: *MachO) *Dylib {...@@ -589,17 +598,7 @@ pub inline fn getUmbrella(self: Dylib, macho_file: *MachO) *Dylib {
589 return macho_file.getFile(self.umbrella).?.dylib;598 return macho_file.getFile(self.umbrella).?.dylib;
590}599}
591600
592fn getLoadCommand(self: Dylib, lc: macho.LC) ?LoadCommandIterator.LoadCommand {601fn addString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 {
593 var it = LoadCommandIterator{
594 .ncmds = self.header.?.ncmds,
595 .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds],
596 };
597 while (it.next()) |cmd| {
598 if (cmd.cmd() == lc) return cmd;
599 } else return null;
600}
601
602fn insertString(self: *Dylib, allocator: Allocator, name: []const u8) !u32 {
603 const off = @as(u32, @intCast(self.strtab.items.len));602 const off = @as(u32, @intCast(self.strtab.items.len));
604 try self.strtab.writer(allocator).print("{s}\x00", .{name});603 try self.strtab.writer(allocator).print("{s}\x00", .{name});
605 return off;604 return off;
src/link/MachO/InternalObject.zig+41-12
...@@ -3,6 +3,7 @@ index: File.Index,...@@ -3,6 +3,7 @@ index: File.Index,
3sections: std.MultiArrayList(Section) = .{},3sections: std.MultiArrayList(Section) = .{},
4atoms: std.ArrayListUnmanaged(Atom.Index) = .{},4atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
5symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},5symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
6strtab: std.ArrayListUnmanaged(u8) = .{},
67
7objc_methnames: std.ArrayListUnmanaged(u8) = .{},8objc_methnames: std.ArrayListUnmanaged(u8) = .{},
8objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64),9objc_selrefs: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64),
...@@ -16,6 +17,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {...@@ -16,6 +17,7 @@ pub fn deinit(self: *InternalObject, allocator: Allocator) void {
16 self.sections.deinit(allocator);17 self.sections.deinit(allocator);
17 self.atoms.deinit(allocator);18 self.atoms.deinit(allocator);
18 self.symbols.deinit(allocator);19 self.symbols.deinit(allocator);
20 self.strtab.deinit(allocator);
19 self.objc_methnames.deinit(allocator);21 self.objc_methnames.deinit(allocator);
20}22}
2123
...@@ -26,7 +28,11 @@ pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO)...@@ -26,7 +28,11 @@ pub fn addSymbol(self: *InternalObject, name: [:0]const u8, macho_file: *MachO)
26 const gop = try macho_file.getOrCreateGlobal(off);28 const gop = try macho_file.getOrCreateGlobal(off);
27 self.symbols.addOneAssumeCapacity().* = gop.index;29 self.symbols.addOneAssumeCapacity().* = gop.index;
28 const sym = macho_file.getSymbol(gop.index);30 const sym = macho_file.getSymbol(gop.index);
29 sym.* = .{ .name = off, .file = self.index };31 sym.file = self.index;
32 sym.value = 0;
33 sym.atom = 0;
34 sym.nlist_idx = 0;
35 sym.flags = .{ .global = true };
30 return gop.index;36 return gop.index;
31}37}
3238
...@@ -45,7 +51,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil...@@ -45,7 +51,7 @@ fn addObjcMethnameSection(self: *InternalObject, methname: []const u8, macho_fil
45 defer gpa.free(name);51 defer gpa.free(name);
46 const atom = macho_file.getAtom(atom_index).?;52 const atom = macho_file.getAtom(atom_index).?;
47 atom.atom_index = atom_index;53 atom.atom_index = atom_index;
48 atom.name = try macho_file.strings.insert(gpa, name);54 atom.name = try self.addString(gpa, name);
49 atom.file = self.index;55 atom.file = self.index;
50 atom.size = methname.len + 1;56 atom.size = methname.len + 1;
51 atom.alignment = .@"1";57 atom.alignment = .@"1";
...@@ -79,7 +85,7 @@ fn addObjcSelrefsSection(...@@ -79,7 +85,7 @@ fn addObjcSelrefsSection(
79 defer gpa.free(name);85 defer gpa.free(name);
80 const atom = macho_file.getAtom(atom_index).?;86 const atom = macho_file.getAtom(atom_index).?;
81 atom.atom_index = atom_index;87 atom.atom_index = atom_index;
82 atom.name = try macho_file.strings.insert(gpa, name);88 atom.name = try self.addString(gpa, name);
83 atom.file = self.index;89 atom.file = self.index;
84 atom.size = @sizeOf(u64);90 atom.size = @sizeOf(u64);
85 atom.alignment = .@"8";91 atom.alignment = .@"8";
...@@ -158,16 +164,39 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,...@@ -158,16 +164,39 @@ fn addSection(self: *InternalObject, allocator: Allocator, segname: []const u8,
158 return n_sect;164 return n_sect;
159}165}
160166
161pub fn getSectionData(self: *const InternalObject, index: u32) []const u8 {167pub fn getAtomData(self: *const InternalObject, atom: Atom, buffer: []u8) !void {
168 assert(buffer.len == atom.size);
162 const slice = self.sections.slice();169 const slice = self.sections.slice();
163 assert(index < slice.items(.header).len);170 const sect = slice.items(.header)[atom.n_sect];
164 const sect = slice.items(.header)[index];171 const extra = slice.items(.extra)[atom.n_sect];
165 const extra = slice.items(.extra)[index];172 const data = if (extra.is_objc_methname) blk: {
166 if (extra.is_objc_methname) {173 const size = std.math.cast(usize, sect.size) orelse return error.Overflow;
167 return self.objc_methnames.items[sect.offset..][0..sect.size];174 break :blk self.objc_methnames.items[sect.offset..][0..size];
168 } else if (extra.is_objc_selref) {175 } else if (extra.is_objc_selref)
169 return &self.objc_selrefs;176 &self.objc_selrefs
170 } else @panic("ref to non-existent section");177 else
178 @panic("ref to non-existent section");
179 const off = std.math.cast(usize, atom.off) orelse return error.Overflow;
180 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
181 @memcpy(buffer, data[off..][0..size]);
182}
183
184pub fn getAtomRelocs(self: *const InternalObject, atom: Atom) []const Relocation {
185 const relocs = self.sections.items(.relocs)[atom.n_sect];
186 return relocs.items[atom.relocs.pos..][0..atom.relocs.len];
187}
188
189fn addString(self: *InternalObject, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {
190 const off: u32 = @intCast(self.strtab.items.len);
191 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
192 self.strtab.appendSliceAssumeCapacity(name);
193 self.strtab.appendAssumeCapacity(0);
194 return off;
195}
196
197pub fn getString(self: InternalObject, off: u32) [:0]const u8 {
198 assert(off < self.strtab.items.len);
199 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
171}200}
172201
173pub fn asFile(self: *InternalObject) File {202pub fn asFile(self: *InternalObject) File {
src/link/MachO/Object.zig+178-117
...@@ -1,13 +1,13 @@...@@ -1,13 +1,13 @@
1archive: ?[]const u8 = null,1archive: ?Archive = null,
2path: []const u8,2path: []const u8,
3file: std.fs.File,
3mtime: u64,4mtime: u64,
4data: []const u8,
5index: File.Index,5index: File.Index,
66
7header: ?macho.mach_header_64 = null,7header: ?macho.mach_header_64 = null,
8sections: std.MultiArrayList(Section) = .{},8sections: std.MultiArrayList(Section) = .{},
9symtab: std.MultiArrayList(Nlist) = .{},9symtab: std.MultiArrayList(Nlist) = .{},
10strtab: []const u8 = &[0]u8{},10strtab: std.ArrayListUnmanaged(u8) = .{},
1111
12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},12symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},13atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
...@@ -22,6 +22,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},...@@ -22,6 +22,7 @@ cies: std.ArrayListUnmanaged(Cie) = .{},
22fdes: std.ArrayListUnmanaged(Fde) = .{},22fdes: std.ArrayListUnmanaged(Fde) = .{},
23eh_frame_data: std.ArrayListUnmanaged(u8) = .{},23eh_frame_data: std.ArrayListUnmanaged(u8) = .{},
24unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{},24unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{},
25data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
2526
26alive: bool = true,27alive: bool = true,
27hidden: bool = false,28hidden: bool = false,
...@@ -29,6 +30,11 @@ hidden: bool = false,...@@ -29,6 +30,11 @@ hidden: bool = false,
29dynamic_relocs: MachO.DynamicRelocs = .{},30dynamic_relocs: MachO.DynamicRelocs = .{},
30output_symtab_ctx: MachO.SymtabCtx = .{},31output_symtab_ctx: MachO.SymtabCtx = .{},
3132
33const Archive = struct {
34 path: []const u8,
35 offset: u64,
36};
37
32pub fn isObject(path: []const u8) !bool {38pub fn isObject(path: []const u8) !bool {
33 const file = try std.fs.cwd().openFile(path, .{});39 const file = try std.fs.cwd().openFile(path, .{});
34 defer file.close();40 defer file.close();
...@@ -37,12 +43,16 @@ pub fn isObject(path: []const u8) !bool {...@@ -37,12 +43,16 @@ pub fn isObject(path: []const u8) !bool {
37}43}
3844
39pub fn deinit(self: *Object, allocator: Allocator) void {45pub fn deinit(self: *Object, allocator: Allocator) void {
46 self.file.close();
47 if (self.archive) |*ar| allocator.free(ar.path);
48 allocator.free(self.path);
40 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {49 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
41 relocs.deinit(allocator);50 relocs.deinit(allocator);
42 sub.deinit(allocator);51 sub.deinit(allocator);
43 }52 }
44 self.sections.deinit(allocator);53 self.sections.deinit(allocator);
45 self.symtab.deinit(allocator);54 self.symtab.deinit(allocator);
55 self.strtab.deinit(allocator);
46 self.symbols.deinit(allocator);56 self.symbols.deinit(allocator);
47 self.atoms.deinit(allocator);57 self.atoms.deinit(allocator);
48 self.cies.deinit(allocator);58 self.cies.deinit(allocator);
...@@ -54,7 +64,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -54,7 +64,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
54 sf.stabs.deinit(allocator);64 sf.stabs.deinit(allocator);
55 }65 }
56 self.stab_files.deinit(allocator);66 self.stab_files.deinit(allocator);
57 allocator.free(self.data);67 self.data_in_code.deinit(allocator);
58}68}
5969
60pub fn parse(self: *Object, macho_file: *MachO) !void {70pub fn parse(self: *Object, macho_file: *MachO) !void {
...@@ -62,10 +72,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -62,10 +72,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
62 defer tracy.end();72 defer tracy.end();
6373
64 const gpa = macho_file.base.comp.gpa;74 const gpa = macho_file.base.comp.gpa;
65 var stream = std.io.fixedBufferStream(self.data);75 const offset = if (self.archive) |ar| ar.offset else 0;
66 const reader = stream.reader();
6776
68 self.header = try reader.readStruct(macho.mach_header_64);77 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
78 {
79 const amt = try self.file.preadAll(&header_buffer, offset);
80 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
81 }
82 self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;
6983
70 const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {84 const this_cpu_arch: std.Target.Cpu.Arch = switch (self.header.?.cputype) {
71 macho.CPU_TYPE_ARM64 => .aarch64,85 macho.CPU_TYPE_ARM64 => .aarch64,
...@@ -80,35 +94,79 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -80,35 +94,79 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
80 return error.InvalidCpuArch;94 return error.InvalidCpuArch;
81 }95 }
8296
83 if (self.getLoadCommand(.SEGMENT_64)) |lc| {97 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
84 const sections = lc.getSections();98 defer gpa.free(lc_buffer);
85 try self.sections.ensureUnusedCapacity(gpa, sections.len);99 {
86 for (sections) |sect| {100 const amt = try self.file.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
87 const index = try self.sections.addOne(gpa);101 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
88 self.sections.set(index, .{ .header = sect });
89
90 if (mem.eql(u8, sect.sectName(), "__eh_frame")) {
91 self.eh_frame_sect_index = @intCast(index);
92 } else if (mem.eql(u8, sect.sectName(), "__compact_unwind")) {
93 self.compact_unwind_sect_index = @intCast(index);
94 }
95 }
96 }
97 if (self.getLoadCommand(.SYMTAB)) |lc| {
98 const cmd = lc.cast(macho.symtab_command).?;
99 self.strtab = self.data[cmd.stroff..][0..cmd.strsize];
100
101 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(self.data.ptr + cmd.symoff))[0..cmd.nsyms];
102 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
103 for (symtab) |nlist| {
104 self.symtab.appendAssumeCapacity(.{
105 .nlist = nlist,
106 .atom = 0,
107 .size = 0,
108 });
109 }
110 }102 }
111103
104 var it = LoadCommandIterator{
105 .ncmds = self.header.?.ncmds,
106 .buffer = lc_buffer,
107 };
108 while (it.next()) |lc| switch (lc.cmd()) {
109 .SEGMENT_64 => {
110 const sections = lc.getSections();
111 try self.sections.ensureUnusedCapacity(gpa, sections.len);
112 for (sections) |sect| {
113 const index = try self.sections.addOne(gpa);
114 self.sections.set(index, .{ .header = sect });
115
116 if (mem.eql(u8, sect.sectName(), "__eh_frame")) {
117 self.eh_frame_sect_index = @intCast(index);
118 } else if (mem.eql(u8, sect.sectName(), "__compact_unwind")) {
119 self.compact_unwind_sect_index = @intCast(index);
120 }
121 }
122 },
123 .SYMTAB => {
124 const cmd = lc.cast(macho.symtab_command).?;
125 try self.strtab.resize(gpa, cmd.strsize);
126 {
127 const amt = try self.file.preadAll(self.strtab.items, cmd.stroff + offset);
128 if (amt != self.strtab.items.len) return error.InputOutput;
129 }
130
131 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
132 defer gpa.free(symtab_buffer);
133 {
134 const amt = try self.file.preadAll(symtab_buffer, cmd.symoff + offset);
135 if (amt != symtab_buffer.len) return error.InputOutput;
136 }
137 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];
138 try self.symtab.ensureUnusedCapacity(gpa, symtab.len);
139 for (symtab) |nlist| {
140 self.symtab.appendAssumeCapacity(.{
141 .nlist = nlist,
142 .atom = 0,
143 .size = 0,
144 });
145 }
146 },
147 .DATA_IN_CODE => {
148 const cmd = lc.cast(macho.linkedit_data_command).?;
149 const buffer = try gpa.alloc(u8, cmd.datasize);
150 defer gpa.free(buffer);
151 {
152 const amt = try self.file.preadAll(buffer, offset + cmd.dataoff);
153 if (amt != buffer.len) return error.InputOutput;
154 }
155 const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));
156 const dice = @as([*]align(1) const macho.data_in_code_entry, @ptrCast(buffer.ptr))[0..ndice];
157 try self.data_in_code.appendUnalignedSlice(gpa, dice);
158 },
159 .BUILD_VERSION,
160 .VERSION_MIN_MACOSX,
161 .VERSION_MIN_IPHONEOS,
162 .VERSION_MIN_TVOS,
163 .VERSION_MIN_WATCHOS,
164 => if (self.platform == null) {
165 self.platform = MachO.Platform.fromLoadCommand(lc);
166 },
167 else => {},
168 };
169
112 const NlistIdx = struct {170 const NlistIdx = struct {
113 nlist: macho.nlist_64,171 nlist: macho.nlist_64,
114 idx: usize,172 idx: usize,
...@@ -170,8 +228,6 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -170,8 +228,6 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
170 try self.parseUnwindRecords(macho_file);228 try self.parseUnwindRecords(macho_file);
171 }229 }
172230
173 self.initPlatform();
174
175 if (self.platform) |platform| {231 if (self.platform) |platform| {
176 if (!macho_file.platform.eqlTarget(platform)) {232 if (!macho_file.platform.eqlTarget(platform)) {
177 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{233 try macho_file.reportParseError2(self.index, "invalid platform: {}", .{
...@@ -237,7 +293,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -237,7 +293,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
237 defer gpa.free(name);293 defer gpa.free(name);
238 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;294 const size = if (nlist_start == nlist_end) sect.size else nlists[nlist_start].nlist.n_value - sect.addr;
239 const atom_index = try self.addAtom(.{295 const atom_index = try self.addAtom(.{
240 .name = name,296 .name = try self.addString(gpa, name),
241 .n_sect = @intCast(n_sect),297 .n_sect = @intCast(n_sect),
242 .off = 0,298 .off = 0,
243 .size = size,299 .size = size,
...@@ -267,7 +323,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -267,7 +323,7 @@ fn initSubsections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
267 else323 else
268 sect.@"align";324 sect.@"align";
269 const atom_index = try self.addAtom(.{325 const atom_index = try self.addAtom(.{
270 .name = self.getString(nlist.nlist.n_strx),326 .name = nlist.nlist.n_strx,
271 .n_sect = @intCast(n_sect),327 .n_sect = @intCast(n_sect),
272 .off = nlist.nlist.n_value - sect.addr,328 .off = nlist.nlist.n_value - sect.addr,
273 .size = size,329 .size = size,
...@@ -300,7 +356,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -300,7 +356,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
300 defer gpa.free(name);356 defer gpa.free(name);
301357
302 const atom_index = try self.addAtom(.{358 const atom_index = try self.addAtom(.{
303 .name = name,359 .name = try self.addString(gpa, name),
304 .n_sect = @intCast(n_sect),360 .n_sect = @intCast(n_sect),
305 .off = 0,361 .off = 0,
306 .size = sect.size,362 .size = sect.size,
...@@ -336,7 +392,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {...@@ -336,7 +392,7 @@ fn initSections(self: *Object, nlists: anytype, macho_file: *MachO) !void {
336}392}
337393
338const AddAtomArgs = struct {394const AddAtomArgs = struct {
339 name: [:0]const u8,395 name: u32,
340 n_sect: u8,396 n_sect: u8,
341 off: u64,397 off: u64,
342 size: u64,398 size: u64,
...@@ -349,7 +405,7 @@ fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index {...@@ -349,7 +405,7 @@ fn addAtom(self: *Object, args: AddAtomArgs, macho_file: *MachO) !Atom.Index {
349 const atom = macho_file.getAtom(atom_index).?;405 const atom = macho_file.getAtom(atom_index).?;
350 atom.file = self.index;406 atom.file = self.index;
351 atom.atom_index = atom_index;407 atom.atom_index = atom_index;
352 atom.name = try macho_file.strings.insert(gpa, args.name);408 atom.name = args.name;
353 atom.n_sect = args.n_sect;409 atom.n_sect = args.n_sect;
354 atom.size = args.size;410 atom.size = args.size;
355 atom.alignment = Atom.Alignment.fromLog2Units(args.alignment);411 atom.alignment = Atom.Alignment.fromLog2Units(args.alignment);
...@@ -376,7 +432,7 @@ fn initLiteralSections(self: *Object, macho_file: *MachO) !void {...@@ -376,7 +432,7 @@ fn initLiteralSections(self: *Object, macho_file: *MachO) !void {
376 defer gpa.free(name);432 defer gpa.free(name);
377433
378 const atom_index = try self.addAtom(.{434 const atom_index = try self.addAtom(.{
379 .name = name,435 .name = try self.addString(gpa, name),
380 .n_sect = @intCast(n_sect),436 .n_sect = @intCast(n_sect),
381 .off = 0,437 .off = 0,
382 .size = sect.size,438 .size = sect.size,
...@@ -475,10 +531,9 @@ fn initSymbols(self: *Object, macho_file: *MachO) !void {...@@ -475,10 +531,9 @@ fn initSymbols(self: *Object, macho_file: *MachO) !void {
475 const index = try macho_file.addSymbol();531 const index = try macho_file.addSymbol();
476 self.symbols.appendAssumeCapacity(index);532 self.symbols.appendAssumeCapacity(index);
477 const symbol = macho_file.getSymbol(index);533 const symbol = macho_file.getSymbol(index);
478 const name = self.getString(nlist.n_strx);
479 symbol.* = .{534 symbol.* = .{
480 .value = nlist.n_value,535 .value = nlist.n_value,
481 .name = try macho_file.strings.insert(gpa, name),536 .name = nlist.n_strx,
482 .nlist_idx = @intCast(i),537 .nlist_idx = @intCast(i),
483 .atom = 0,538 .atom = 0,
484 .file = self.index,539 .file = self.index,
...@@ -638,7 +693,10 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -638,7 +693,10 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
638 const sect = slice.items(.header)[sect_id];693 const sect = slice.items(.header)[sect_id];
639 const relocs = slice.items(.relocs)[sect_id];694 const relocs = slice.items(.relocs)[sect_id];
640695
641 const data = try self.getSectionData(sect_id);696 // TODO: read into buffer directly
697 const data = try self.getSectionData(gpa, sect_id);
698 defer gpa.free(data);
699
642 try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len);700 try self.eh_frame_data.ensureTotalCapacityPrecise(gpa, data.len);
643 self.eh_frame_data.appendSliceAssumeCapacity(data);701 self.eh_frame_data.appendSliceAssumeCapacity(data);
644702
...@@ -739,7 +797,8 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -739,7 +797,8 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
739 };797 };
740798
741 const gpa = macho_file.base.comp.gpa;799 const gpa = macho_file.base.comp.gpa;
742 const data = try self.getSectionData(sect_id);800 const data = try self.getSectionData(gpa, sect_id);
801 defer gpa.free(data);
743 const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));802 const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
744 const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];803 const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];
745 const sym_lookup = SymbolLookup{ .ctx = self };804 const sym_lookup = SymbolLookup{ .ctx = self };
...@@ -934,24 +993,6 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -934,24 +993,6 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
934 }993 }
935}994}
936995
937fn initPlatform(self: *Object) void {
938 var it = LoadCommandIterator{
939 .ncmds = self.header.?.ncmds,
940 .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds],
941 };
942 self.platform = while (it.next()) |cmd| {
943 switch (cmd.cmd()) {
944 .BUILD_VERSION,
945 .VERSION_MIN_MACOSX,
946 .VERSION_MIN_IPHONEOS,
947 .VERSION_MIN_TVOS,
948 .VERSION_MIN_WATCHOS,
949 => break MachO.Platform.fromLoadCommand(cmd),
950 else => {},
951 }
952 } else null;
953}
954
955/// Currently, we only check if a compile unit for this input object file exists996/// Currently, we only check if a compile unit for this input object file exists
956/// and record that so that we can emit symbol stabs.997/// and record that so that we can emit symbol stabs.
957/// TODO in the future, we want parse debug info and debug line sections so that998/// TODO in the future, we want parse debug info and debug line sections so that
...@@ -975,12 +1016,20 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void {...@@ -975,12 +1016,20 @@ fn initDwarfInfo(self: *Object, macho_file: *MachO) !void {
9751016
976 if (debug_info_index == null or debug_abbrev_index == null) return;1017 if (debug_info_index == null or debug_abbrev_index == null) return;
9771018
978 var dwarf_info = DwarfInfo{1019 const debug_info = try self.getSectionData(gpa, @intCast(debug_info_index.?));
979 .debug_info = try self.getSectionData(@intCast(debug_info_index.?)),1020 defer gpa.free(debug_info);
980 .debug_abbrev = try self.getSectionData(@intCast(debug_abbrev_index.?)),1021 const debug_abbrev = try self.getSectionData(gpa, @intCast(debug_abbrev_index.?));
981 .debug_str = if (debug_str_index) |index| try self.getSectionData(@intCast(index)) else "",1022 defer gpa.free(debug_abbrev);
982 };1023 const debug_str = if (debug_str_index) |index| try self.getSectionData(gpa, @intCast(index)) else &[0]u8{};
983 dwarf_info.init(gpa) catch {1024 defer gpa.free(debug_str);
1025
1026 var dwarf_info = DwarfInfo{};
1027 errdefer dwarf_info.deinit(gpa);
1028 dwarf_info.init(gpa, .{
1029 .debug_info = debug_info,
1030 .debug_abbrev = debug_abbrev,
1031 .debug_str = debug_str,
1032 }) catch {
984 try macho_file.reportParseError2(self.index, "invalid __DWARF info found", .{});1033 try macho_file.reportParseError2(self.index, "invalid __DWARF info found", .{});
985 return error.MalformedObject;1034 return error.MalformedObject;
986 };1035 };
...@@ -1049,8 +1098,10 @@ pub fn resetGlobals(self: *Object, macho_file: *MachO) void {...@@ -1049,8 +1098,10 @@ pub fn resetGlobals(self: *Object, macho_file: *MachO) void {
1049 if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;1098 if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;
1050 const sym = macho_file.getSymbol(sym_index);1099 const sym = macho_file.getSymbol(sym_index);
1051 const name = sym.name;1100 const name = sym.name;
1101 const global = sym.flags.global;
1052 sym.* = .{};1102 sym.* = .{};
1053 sym.name = name;1103 sym.name = name;
1104 sym.flags.global = global;
1054 }1105 }
1055}1106}
10561107
...@@ -1137,7 +1188,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {...@@ -1137,7 +1188,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
1137 defer gpa.free(name);1188 defer gpa.free(name);
1138 const atom = macho_file.getAtom(atom_index).?;1189 const atom = macho_file.getAtom(atom_index).?;
1139 atom.atom_index = atom_index;1190 atom.atom_index = atom_index;
1140 atom.name = try macho_file.strings.insert(gpa, name);1191 atom.name = try self.addString(gpa, name);
1141 atom.file = self.index;1192 atom.file = self.index;
1142 atom.size = nlist.n_value;1193 atom.size = nlist.n_value;
1143 atom.alignment = Atom.Alignment.fromLog2Units((nlist.n_desc >> 8) & 0x0f);1194 atom.alignment = Atom.Alignment.fromLog2Units((nlist.n_desc >> 8) & 0x0f);
...@@ -1151,6 +1202,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {...@@ -1151,6 +1202,7 @@ pub fn convertTentativeDefinitions(self: *Object, macho_file: *MachO) !void {
11511202
1152 sym.value = 0;1203 sym.value = 0;
1153 sym.atom = atom_index;1204 sym.atom = atom_index;
1205 sym.flags.global = true;
1154 sym.flags.weak = false;1206 sym.flags.weak = false;
1155 sym.flags.weak_ref = false;1207 sym.flags.weak_ref = false;
1156 sym.flags.tentative = false;1208 sym.flags.tentative = false;
...@@ -1219,8 +1271,8 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1219,8 +1271,8 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1219 self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir1271 self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir
1220 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name1272 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name
12211273
1222 if (self.archive) |path| {1274 if (self.archive) |ar| {
1223 self.output_symtab_ctx.strsize += @as(u32, @intCast(path.len + 1 + self.path.len + 1 + 1));1275 self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1));
1224 } else {1276 } else {
1225 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));1277 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));
1226 }1278 }
...@@ -1365,8 +1417,8 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1365,8 +1417,8 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1365 index += 1;1417 index += 1;
1366 // N_OSO path1418 // N_OSO path
1367 n_strx = @as(u32, @intCast(macho_file.strtab.items.len));1419 n_strx = @as(u32, @intCast(macho_file.strtab.items.len));
1368 if (self.archive) |path| {1420 if (self.archive) |ar| {
1369 macho_file.strtab.appendSliceAssumeCapacity(path);1421 macho_file.strtab.appendSliceAssumeCapacity(ar.path);
1370 macho_file.strtab.appendAssumeCapacity('(');1422 macho_file.strtab.appendAssumeCapacity('(');
1371 macho_file.strtab.appendSliceAssumeCapacity(self.path);1423 macho_file.strtab.appendSliceAssumeCapacity(self.path);
1372 macho_file.strtab.appendAssumeCapacity(')');1424 macho_file.strtab.appendAssumeCapacity(')');
...@@ -1532,30 +1584,26 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void...@@ -1532,30 +1584,26 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO) error{Overflow}!void
1532 }1584 }
1533}1585}
15341586
1535fn getLoadCommand(self: Object, lc: macho.LC) ?LoadCommandIterator.LoadCommand {1587fn getSectionData(self: *const Object, allocator: Allocator, index: u32) ![]u8 {
1536 var it = LoadCommandIterator{
1537 .ncmds = self.header.?.ncmds,
1538 .buffer = self.data[@sizeOf(macho.mach_header_64)..][0..self.header.?.sizeofcmds],
1539 };
1540 while (it.next()) |cmd| {
1541 if (cmd.cmd() == lc) return cmd;
1542 } else return null;
1543}
1544
1545pub fn getSectionData(self: *const Object, index: u32) error{Overflow}![]const u8 {
1546 const slice = self.sections.slice();1588 const slice = self.sections.slice();
1547 assert(index < slice.items(.header).len);1589 assert(index < slice.items(.header).len);
1548 const sect = slice.items(.header)[index];1590 const sect = slice.items(.header)[index];
1549 const off = math.cast(usize, sect.offset) orelse return error.Overflow;1591 const offset = if (self.archive) |ar| ar.offset else 0;
1550 const size = math.cast(usize, sect.size) orelse return error.Overflow;1592 const size = math.cast(usize, sect.size) orelse return error.Overflow;
1551 return self.data[off..][0..size];1593 const buffer = try allocator.alloc(u8, size);
1594 errdefer allocator.free(buffer);
1595 const amt = try self.file.preadAll(buffer, sect.offset + offset);
1596 if (amt != buffer.len) return error.InputOutput;
1597 return buffer;
1552}1598}
15531599
1554pub fn getAtomData(self: *const Object, atom: Atom) error{Overflow}![]const u8 {1600pub fn getAtomData(self: *const Object, atom: Atom, buffer: []u8) !void {
1555 const data = try self.getSectionData(atom.n_sect);1601 assert(buffer.len == atom.size);
1556 const off = math.cast(usize, atom.off) orelse return error.Overflow;1602 const slice = self.sections.slice();
1557 const size = math.cast(usize, atom.size) orelse return error.Overflow;1603 const offset = if (self.archive) |ar| ar.offset else 0;
1558 return data[off..][0..size];1604 const sect = slice.items(.header)[atom.n_sect];
1605 const amt = try self.file.preadAll(buffer, sect.offset + offset + atom.off);
1606 if (amt != buffer.len) return error.InputOutput;
1559}1607}
15601608
1561pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation {1609pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation {
...@@ -1563,9 +1611,17 @@ pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation {...@@ -1563,9 +1611,17 @@ pub fn getAtomRelocs(self: *const Object, atom: Atom) []const Relocation {
1563 return relocs.items[atom.relocs.pos..][0..atom.relocs.len];1611 return relocs.items[atom.relocs.pos..][0..atom.relocs.len];
1564}1612}
15651613
1566fn getString(self: Object, off: u32) [:0]const u8 {1614fn addString(self: *Object, allocator: Allocator, name: [:0]const u8) error{OutOfMemory}!u32 {
1567 assert(off < self.strtab.len);1615 const off: u32 = @intCast(self.strtab.items.len);
1568 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.ptr + off)), 0);1616 try self.strtab.ensureUnusedCapacity(allocator, name.len + 1);
1617 self.strtab.appendSliceAssumeCapacity(name);
1618 self.strtab.appendAssumeCapacity(0);
1619 return off;
1620}
1621
1622pub fn getString(self: Object, off: u32) [:0]const u8 {
1623 assert(off < self.strtab.items.len);
1624 return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.strtab.items.ptr + off)), 0);
1569}1625}
15701626
1571pub fn hasUnwindRecords(self: Object) bool {1627pub fn hasUnwindRecords(self: Object) bool {
...@@ -1600,15 +1656,8 @@ pub fn hasObjc(self: Object) bool {...@@ -1600,15 +1656,8 @@ pub fn hasObjc(self: Object) bool {
1600 return false;1656 return false;
1601}1657}
16021658
1603pub fn getDataInCode(self: Object) []align(1) const macho.data_in_code_entry {1659pub fn getDataInCode(self: Object) []const macho.data_in_code_entry {
1604 const lc = self.getLoadCommand(.DATA_IN_CODE) orelse return &[0]macho.data_in_code_entry{};1660 return self.data_in_code.items;
1605 const cmd = lc.cast(macho.linkedit_data_command).?;
1606 const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));
1607 const dice = @as(
1608 [*]align(1) const macho.data_in_code_entry,
1609 @ptrCast(self.data.ptr + cmd.dataoff),
1610 )[0..ndice];
1611 return dice;
1612}1661}
16131662
1614pub inline fn hasSubsections(self: Object) bool {1663pub inline fn hasSubsections(self: Object) bool {
...@@ -1762,8 +1811,8 @@ fn formatPath(...@@ -1762,8 +1811,8 @@ fn formatPath(
1762) !void {1811) !void {
1763 _ = unused_fmt_string;1812 _ = unused_fmt_string;
1764 _ = options;1813 _ = options;
1765 if (object.archive) |path| {1814 if (object.archive) |ar| {
1766 try writer.writeAll(path);1815 try writer.writeAll(ar.path);
1767 try writer.writeByte('(');1816 try writer.writeByte('(');
1768 try writer.writeAll(object.path);1817 try writer.writeAll(object.path);
1769 try writer.writeByte(')');1818 try writer.writeByte(')');
...@@ -1831,11 +1880,17 @@ const x86_64 = struct {...@@ -1831,11 +1880,17 @@ const x86_64 = struct {
1831 ) !void {1880 ) !void {
1832 const gpa = macho_file.base.comp.gpa;1881 const gpa = macho_file.base.comp.gpa;
18331882
1834 const relocs = @as(1883 const offset = if (self.archive) |ar| ar.offset else 0;
1835 [*]align(1) const macho.relocation_info,1884 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
1836 @ptrCast(self.data.ptr + sect.reloff),1885 defer gpa.free(relocs_buffer);
1837 )[0..sect.nreloc];1886 {
1838 const code = try self.getSectionData(@intCast(n_sect));1887 const amt = try self.file.preadAll(relocs_buffer, sect.reloff + offset);
1888 if (amt != relocs_buffer.len) return error.InputOutput;
1889 }
1890 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
1891
1892 const code = try self.getSectionData(gpa, @intCast(n_sect));
1893 defer gpa.free(code);
18391894
1840 try out.ensureTotalCapacityPrecise(gpa, relocs.len);1895 try out.ensureTotalCapacityPrecise(gpa, relocs.len);
18411896
...@@ -1987,11 +2042,17 @@ const aarch64 = struct {...@@ -1987,11 +2042,17 @@ const aarch64 = struct {
1987 ) !void {2042 ) !void {
1988 const gpa = macho_file.base.comp.gpa;2043 const gpa = macho_file.base.comp.gpa;
19892044
1990 const relocs = @as(2045 const offset = if (self.archive) |ar| ar.offset else 0;
1991 [*]align(1) const macho.relocation_info,2046 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
1992 @ptrCast(self.data.ptr + sect.reloff),2047 defer gpa.free(relocs_buffer);
1993 )[0..sect.nreloc];2048 {
1994 const code = try self.getSectionData(@intCast(n_sect));2049 const amt = try self.file.preadAll(relocs_buffer, sect.reloff + offset);
2050 if (amt != relocs_buffer.len) return error.InputOutput;
2051 }
2052 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
2053
2054 const code = try self.getSectionData(gpa, @intCast(n_sect));
2055 defer gpa.free(code);
19952056
1996 try out.ensureTotalCapacityPrecise(gpa, relocs.len);2057 try out.ensureTotalCapacityPrecise(gpa, relocs.len);
19972058
src/link/MachO/Symbol.zig+11-1
...@@ -55,7 +55,12 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool {...@@ -55,7 +55,12 @@ pub fn weakRef(symbol: Symbol, macho_file: *MachO) bool {
55}55}
5656
57pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 {57pub fn getName(symbol: Symbol, macho_file: *MachO) [:0]const u8 {
58 return macho_file.strings.getAssumeExists(symbol.name);58 if (symbol.flags.global) return macho_file.strings.getAssumeExists(symbol.name);
59 return switch (symbol.getFile(macho_file).?) {
60 .dylib => unreachable, // There are no local symbols for dylibs
61 .zig_object => |x| x.strtab.getAssumeExists(symbol.name),
62 inline else => |x| x.getString(symbol.name),
63 };
59}64}
6065
61pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom {66pub fn getAtom(symbol: Symbol, macho_file: *MachO) ?*Atom {
...@@ -341,6 +346,11 @@ pub const Flags = packed struct {...@@ -341,6 +346,11 @@ pub const Flags = packed struct {
341 /// Whether the symbol is exported at runtime.346 /// Whether the symbol is exported at runtime.
342 @"export": bool = false,347 @"export": bool = false,
343348
349 /// Whether the symbol is effectively an extern and takes part in global
350 /// symbol resolution. Then, its name will be saved in global string interning
351 /// table.
352 global: bool = false,
353
344 /// Whether this symbol is weak.354 /// Whether this symbol is weak.
345 weak: bool = false,355 weak: bool = false,
346356
src/link/MachO/ZigObject.zig+23-30
...@@ -3,6 +3,7 @@ path: []const u8,...@@ -3,6 +3,7 @@ path: []const u8,
3index: File.Index,3index: File.Index,
44
5symtab: std.MultiArrayList(Nlist) = .{},5symtab: std.MultiArrayList(Nlist) = .{},
6strtab: StringTable = .{},
67
7symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},8symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
8atoms: std.ArrayListUnmanaged(Atom.Index) = .{},9atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
...@@ -52,10 +53,12 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {...@@ -52,10 +53,12 @@ pub fn init(self: *ZigObject, macho_file: *MachO) !void {
52 const gpa = comp.gpa;53 const gpa = comp.gpa;
5354
54 try self.atoms.append(gpa, 0); // null input section55 try self.atoms.append(gpa, 0); // null input section
56 try self.strtab.buffer.append(gpa, 0);
55}57}
5658
57pub fn deinit(self: *ZigObject, allocator: Allocator) void {59pub fn deinit(self: *ZigObject, allocator: Allocator) void {
58 self.symtab.deinit(allocator);60 self.symtab.deinit(allocator);
61 self.strtab.deinit(allocator);
59 self.symbols.deinit(allocator);62 self.symbols.deinit(allocator);
60 self.atoms.deinit(allocator);63 self.atoms.deinit(allocator);
61 self.globals_lookup.deinit(allocator);64 self.globals_lookup.deinit(allocator);
...@@ -136,37 +139,24 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index {...@@ -136,37 +139,24 @@ pub fn addAtom(self: *ZigObject, macho_file: *MachO) !Symbol.Index {
136 return symbol_index;139 return symbol_index;
137}140}
138141
139/// Caller owns the memory.142pub fn getAtomData(self: ZigObject, macho_file: *MachO, atom: Atom, buffer: []u8) !void {
140pub fn getAtomDataAlloc(
141 self: ZigObject,
142 macho_file: *MachO,
143 allocator: Allocator,
144 atom: Atom,
145) ![]u8 {
146 assert(atom.file == self.index);143 assert(atom.file == self.index);
144 assert(atom.size == buffer.len);
147 const sect = macho_file.sections.items(.header)[atom.out_n_sect];145 const sect = macho_file.sections.items(.header)[atom.out_n_sect];
148 assert(!sect.isZerofill());146 assert(!sect.isZerofill());
149147
150 switch (sect.type()) {148 switch (sect.type()) {
151 macho.S_THREAD_LOCAL_REGULAR => {149 macho.S_THREAD_LOCAL_REGULAR => {
152 const tlv = self.tlv_initializers.get(atom.atom_index).?;150 const tlv = self.tlv_initializers.get(atom.atom_index).?;
153 const data = try allocator.dupe(u8, tlv.data);151 @memcpy(buffer, tlv.data);
154 return data;
155 },152 },
156 macho.S_THREAD_LOCAL_VARIABLES => {153 macho.S_THREAD_LOCAL_VARIABLES => {
157 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;154 @memset(buffer, 0);
158 const data = try allocator.alloc(u8, size);
159 @memset(data, 0);
160 return data;
161 },155 },
162 else => {156 else => {
163 const file_offset = sect.offset + atom.value - sect.addr;157 const file_offset = sect.offset + atom.value - sect.addr;
164 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;158 const amt = try macho_file.base.file.?.preadAll(buffer, file_offset);
165 const data = try allocator.alloc(u8, size);159 if (amt != buffer.len) return error.InputOutput;
166 errdefer allocator.free(data);
167 const amt = try macho_file.base.file.?.preadAll(data, file_offset);
168 if (amt != data.len) return error.InputOutput;
169 return data;
170 },160 },
171 }161 }
172}162}
...@@ -242,8 +232,10 @@ pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void {...@@ -242,8 +232,10 @@ pub fn resetGlobals(self: *ZigObject, macho_file: *MachO) void {
242 if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;232 if (!self.symtab.items(.nlist)[nlist_idx].ext()) continue;
243 const sym = macho_file.getSymbol(sym_index);233 const sym = macho_file.getSymbol(sym_index);
244 const name = sym.name;234 const name = sym.name;
235 const global = sym.flags.global;
245 sym.* = .{};236 sym.* = .{};
246 sym.name = name;237 sym.name = name;
238 sym.flags.global = global;
247 }239 }
248}240}
249241
...@@ -686,7 +678,7 @@ fn updateDeclCode(...@@ -686,7 +678,7 @@ fn updateDeclCode(
686 sym.out_n_sect = sect_index;678 sym.out_n_sect = sect_index;
687 atom.out_n_sect = sect_index;679 atom.out_n_sect = sect_index;
688680
689 sym.name = try macho_file.strings.insert(gpa, decl_name);681 sym.name = try self.strtab.insert(gpa, decl_name);
690 atom.flags.alive = true;682 atom.flags.alive = true;
691 atom.name = sym.name;683 atom.name = sym.name;
692 nlist.n_strx = sym.name;684 nlist.n_strx = sym.name;
...@@ -796,7 +788,7 @@ fn createTlvInitializer(...@@ -796,7 +788,7 @@ fn createTlvInitializer(
796 atom.out_n_sect = sect_index;788 atom.out_n_sect = sect_index;
797789
798 sym.value = 0;790 sym.value = 0;
799 sym.name = try macho_file.strings.insert(gpa, sym_name);791 sym.name = try self.strtab.insert(gpa, sym_name);
800 atom.flags.alive = true;792 atom.flags.alive = true;
801 atom.name = sym.name;793 atom.name = sym.name;
802 nlist.n_strx = sym.name;794 nlist.n_strx = sym.name;
...@@ -849,7 +841,7 @@ fn createTlvDescriptor(...@@ -849,7 +841,7 @@ fn createTlvDescriptor(
849 atom.out_n_sect = sect_index;841 atom.out_n_sect = sect_index;
850842
851 sym.value = 0;843 sym.value = 0;
852 sym.name = try macho_file.strings.insert(gpa, name);844 sym.name = try self.strtab.insert(gpa, name);
853 atom.flags.alive = true;845 atom.flags.alive = true;
854 atom.name = sym.name;846 atom.name = sym.name;
855 nlist.n_strx = sym.name;847 nlist.n_strx = sym.name;
...@@ -1019,7 +1011,7 @@ fn lowerConst(...@@ -1019,7 +1011,7 @@ fn lowerConst(
1019 };1011 };
10201012
1021 const sym = macho_file.getSymbol(sym_index);1013 const sym = macho_file.getSymbol(sym_index);
1022 const name_str_index = try macho_file.strings.insert(gpa, name);1014 const name_str_index = try self.strtab.insert(gpa, name);
1023 sym.name = name_str_index;1015 sym.name = name_str_index;
1024 sym.out_n_sect = output_section_index;1016 sym.out_n_sect = output_section_index;
10251017
...@@ -1110,7 +1102,7 @@ pub fn updateExports(...@@ -1110,7 +1102,7 @@ pub fn updateExports(
1110 }1102 }
11111103
1112 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);1104 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1113 const global_nlist_index = if (metadata.@"export"(self, macho_file, exp_name)) |exp_index|1105 const global_nlist_index = if (metadata.@"export"(self, exp_name)) |exp_index|
1114 exp_index.*1106 exp_index.*
1115 else blk: {1107 else blk: {
1116 const global_nlist_index = try self.getGlobalSymbol(macho_file, exp_name, null);1108 const global_nlist_index = try self.getGlobalSymbol(macho_file, exp_name, null);
...@@ -1159,7 +1151,7 @@ fn updateLazySymbol(...@@ -1159,7 +1151,7 @@ fn updateLazySymbol(
1159 lazy_sym.ty.fmt(mod),1151 lazy_sym.ty.fmt(mod),
1160 });1152 });
1161 defer gpa.free(name);1153 defer gpa.free(name);
1162 break :blk try macho_file.strings.insert(gpa, name);1154 break :blk try self.strtab.insert(gpa, name);
1163 };1155 };
11641156
1165 const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|1157 const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
...@@ -1247,7 +1239,7 @@ pub fn deleteDeclExport(...@@ -1247,7 +1239,7 @@ pub fn deleteDeclExport(
12471239
1248 const mod = macho_file.base.comp.module.?;1240 const mod = macho_file.base.comp.module.?;
1249 const exp_name = mod.intern_pool.stringToSlice(name);1241 const exp_name = mod.intern_pool.stringToSlice(name);
1250 const nlist_index = metadata.@"export"(self, macho_file, exp_name) orelse return;1242 const nlist_index = metadata.@"export"(self, exp_name) orelse return;
12511243
1252 log.debug("deleting export '{s}'", .{exp_name});1244 log.debug("deleting export '{s}'", .{exp_name});
12531245
...@@ -1268,7 +1260,7 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l...@@ -1268,7 +1260,7 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l
1268 const gpa = macho_file.base.comp.gpa;1260 const gpa = macho_file.base.comp.gpa;
1269 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});1261 const sym_name = try std.fmt.allocPrint(gpa, "_{s}", .{name});
1270 defer gpa.free(sym_name);1262 defer gpa.free(sym_name);
1271 const off = try macho_file.strings.insert(gpa, sym_name);1263 const off = try self.strtab.insert(gpa, sym_name);
1272 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);1264 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1273 if (!lookup_gop.found_existing) {1265 if (!lookup_gop.found_existing) {
1274 const nlist_index = try self.addNlist(gpa);1266 const nlist_index = try self.addNlist(gpa);
...@@ -1276,7 +1268,8 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l...@@ -1276,7 +1268,8 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l
1276 nlist.n_strx = off;1268 nlist.n_strx = off;
1277 nlist.n_type = macho.N_EXT;1269 nlist.n_type = macho.N_EXT;
1278 lookup_gop.value_ptr.* = nlist_index;1270 lookup_gop.value_ptr.* = nlist_index;
1279 const gop = try macho_file.getOrCreateGlobal(off);1271 const global_name_off = try macho_file.strings.insert(gpa, sym_name);
1272 const gop = try macho_file.getOrCreateGlobal(global_name_off);
1280 try self.symbols.append(gpa, gop.index);1273 try self.symbols.append(gpa, gop.index);
1281 }1274 }
1282 return lookup_gop.value_ptr.*;1275 return lookup_gop.value_ptr.*;
...@@ -1406,10 +1399,10 @@ const DeclMetadata = struct {...@@ -1406,10 +1399,10 @@ const DeclMetadata = struct {
1406 /// A list of all exports aliases of this Decl.1399 /// A list of all exports aliases of this Decl.
1407 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},1400 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
14081401
1409 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, macho_file: *MachO, name: []const u8) ?*u32 {1402 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
1410 for (m.exports.items) |*exp| {1403 for (m.exports.items) |*exp| {
1411 const nlist = zig_object.symtab.items(.nlist)[exp.*];1404 const nlist = zig_object.symtab.items(.nlist)[exp.*];
1412 const exp_name = macho_file.strings.getAssumeExists(nlist.n_strx);1405 const exp_name = zig_object.strtab.getAssumeExists(nlist.n_strx);
1413 if (mem.eql(u8, name, exp_name)) return exp;1406 if (mem.eql(u8, name, exp_name)) return exp;
1414 }1407 }
1415 return null;1408 return null;
src/link/MachO/relocatable.zig+1-2
...@@ -290,8 +290,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -290,8 +290,7 @@ fn writeAtoms(macho_file: *MachO) !void {
290 assert(atom.flags.alive);290 assert(atom.flags.alive);
291 const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow;291 const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow;
292 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;292 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
293 const atom_data = try atom.getFile(macho_file).object.getAtomData(atom.*);293 try atom.getFile(macho_file).object.getAtomData(atom.*, code[off..][0..atom_size]);
294 @memcpy(code[off..][0..atom_size], atom_data);
295 try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs);294 try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs);
296 }295 }
297296