authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-04 17:49:35+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-07-18 09:13:07+02:00
log101299e85625faf29b4afce07ad1e3522ea75421
tree365fb3864b1e6a35ff99ba4b81b22ed0963773f9
parenta57479afc2cea1b7c2c6802b7e8a1a7db973a3a3

macho: move unwind info records ownership to Objects


7 files changed, 173 insertions(+), 145 deletions(-)

src/link/MachO.zig+9-20
......@@ -67,7 +67,6 @@ entry_index: ?Symbol.Index = null,
6767atoms: std.ArrayListUnmanaged(Atom) = .{},
6868atoms_extra: std.ArrayListUnmanaged(u32) = .{},
6969thunks: std.ArrayListUnmanaged(Thunk) = .{},
70unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{},
7170
7271/// String interning table
7372strings: StringTable = .{},
......@@ -357,7 +356,6 @@ pub fn deinit(self: *MachO) void {
357356 thunk.deinit(gpa);
358357 }
359358 self.thunks.deinit(gpa);
360 self.unwind_records.deinit(gpa);
361359}
362360
363361pub fn flush(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
......@@ -982,12 +980,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
982980 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
983981 };
984982 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
985 self.files.set(index, .{ .object = .{
986 .path = try gpa.dupe(u8, path),
987 .file_handle = handle,
988 .mtime = mtime,
989 .index = index,
990 } });
983 self.files.set(index, .{
984 .object = .{
985 .offset = 0, // TODO FAT objects
986 .path = try gpa.dupe(u8, path),
987 .file_handle = handle,
988 .mtime = mtime,
989 .index = index,
990 },
991 });
991992 try self.objects.append(gpa, index);
992993
993994 const object = self.getFile(index).?.object;
......@@ -4058,18 +4059,6 @@ pub fn getGlobalByName(self: *MachO, name: []const u8) ?Symbol.Index {
40584059 return self.globals.get(off);
40594060}
40604061
4061pub fn addUnwindRecord(self: *MachO) !UnwindInfo.Record.Index {
4062 const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len));
4063 const rec = try self.unwind_records.addOne(self.base.comp.gpa);
4064 rec.* = .{};
4065 return index;
4066}
4067
4068pub fn getUnwindRecord(self: *MachO, index: UnwindInfo.Record.Index) *UnwindInfo.Record {
4069 assert(index < self.unwind_records.items.len);
4070 return &self.unwind_records.items[index];
4071}
4072
40734062pub fn addThunk(self: *MachO) !Thunk.Index {
40744063 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
40754064 const thunk = try self.thunks.addOne(self.base.comp.gpa);
src/link/MachO/Archive.zig+2-2
......@@ -67,9 +67,9 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index:
6767 mem.eql(u8, name, SYMDEF64_SORTED)) continue;
6868
6969 const object = Object{
70 .archive = .{
70 .offset = pos,
71 .in_archive = .{
7172 .path = try gpa.dupe(u8, path),
72 .offset = pos,
7373 .size = hdr_size,
7474 },
7575 .path = try gpa.dupe(u8, name),
src/link/MachO/Atom.zig+7-4
......@@ -91,14 +91,16 @@ pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Recor
9191 if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{};
9292 const extra = self.getExtra(macho_file).?;
9393 return switch (self.getFile(macho_file)) {
94 .dylib, .zig_object, .internal => unreachable,
95 .object => |x| x.unwind_records.items[extra.unwind_index..][0..extra.unwind_count],
94 .dylib => unreachable,
95 .zig_object, .internal => &[0]UnwindInfo.Record.Index{},
96 .object => |x| x.unwind_records_indexes.items[extra.unwind_index..][0..extra.unwind_count],
9697 };
9798}
9899
99100pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void {
101 const object = self.getFile(macho_file).object;
100102 for (self.getUnwindRecords(macho_file)) |cu_index| {
101 const cu = macho_file.getUnwindRecord(cu_index);
103 const cu = object.getUnwindRecord(cu_index);
102104 cu.alive = false;
103105
104106 if (cu.getFdePtr(macho_file)) |fde| {
......@@ -1170,6 +1172,7 @@ fn format2(
11701172 _ = unused_fmt_string;
11711173 const atom = ctx.atom;
11721174 const macho_file = ctx.macho_file;
1175 const file = atom.getFile(macho_file);
11731176 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{
11741177 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
11751178 atom.out_n_sect, atom.alignment, atom.size,
......@@ -1181,7 +1184,7 @@ fn format2(
11811184 try writer.writeAll(" : unwind{ ");
11821185 const extra = atom.getExtra(macho_file).?;
11831186 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1184 const rec = macho_file.getUnwindRecord(index);
1187 const rec = file.object.getUnwindRecord(index);
11851188 try writer.print("{d}", .{index});
11861189 if (!rec.alive) try writer.writeAll("([*])");
11871190 if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", ");
src/link/MachO/Object.zig+94-74
......@@ -1,8 +1,10 @@
1archive: ?InArchive = null,
1/// Non-zero for fat object files or archives
2offset: u64,
23path: []const u8,
34file_handle: File.HandleIndex,
45mtime: u64,
56index: File.Index,
7in_archive: ?InArchive = null,
68
79header: ?macho.mach_header_64 = null,
810sections: std.MultiArrayList(Section) = .{},
......@@ -21,7 +23,8 @@ compact_unwind_sect_index: ?u8 = null,
2123cies: std.ArrayListUnmanaged(Cie) = .{},
2224fdes: std.ArrayListUnmanaged(Fde) = .{},
2325eh_frame_data: std.ArrayListUnmanaged(u8) = .{},
24unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{},
26unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{},
27unwind_records_indexes: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{},
2528data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
2629
2730alive: bool = true,
......@@ -39,7 +42,7 @@ pub fn isObject(path: []const u8) !bool {
3942}
4043
4144pub fn deinit(self: *Object, allocator: Allocator) void {
42 if (self.archive) |*ar| allocator.free(ar.path);
45 if (self.in_archive) |*ar| allocator.free(ar.path);
4346 allocator.free(self.path);
4447 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
4548 relocs.deinit(allocator);
......@@ -54,6 +57,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
5457 self.fdes.deinit(allocator);
5558 self.eh_frame_data.deinit(allocator);
5659 self.unwind_records.deinit(allocator);
60 self.unwind_records_indexes.deinit(allocator);
5761 for (self.stab_files.items) |*sf| {
5862 sf.stabs.deinit(allocator);
5963 }
......@@ -66,12 +70,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
6670 defer tracy.end();
6771
6872 const gpa = macho_file.base.comp.gpa;
69 const offset = if (self.archive) |ar| ar.offset else 0;
7073 const handle = macho_file.getFileHandle(self.file_handle);
7174
7275 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
7376 {
74 const amt = try handle.preadAll(&header_buffer, offset);
77 const amt = try handle.preadAll(&header_buffer, self.offset);
7578 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
7679 }
7780 self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;
......@@ -92,7 +95,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
9295 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
9396 defer gpa.free(lc_buffer);
9497 {
95 const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
98 const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64));
9699 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
97100 }
98101
......@@ -119,14 +122,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
119122 const cmd = lc.cast(macho.symtab_command).?;
120123 try self.strtab.resize(gpa, cmd.strsize);
121124 {
122 const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset);
125 const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset);
123126 if (amt != self.strtab.items.len) return error.InputOutput;
124127 }
125128
126129 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
127130 defer gpa.free(symtab_buffer);
128131 {
129 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset);
132 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset);
130133 if (amt != symtab_buffer.len) return error.InputOutput;
131134 }
132135 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];
......@@ -144,7 +147,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
144147 const buffer = try gpa.alloc(u8, cmd.datasize);
145148 defer gpa.free(buffer);
146149 {
147 const amt = try handle.preadAll(buffer, offset + cmd.dataoff);
150 const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff);
148151 if (amt != buffer.len) return error.InputOutput;
149152 }
150153 const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));
......@@ -218,11 +221,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
218221
219222 // Parse Apple's __LD,__compact_unwind section
220223 if (self.compact_unwind_sect_index) |index| {
221 try self.initUnwindRecords(index, macho_file);
224 try self.initUnwindRecords(gpa, index, handle, macho_file);
222225 }
223226
224227 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {
225 try self.parseUnwindRecords(macho_file);
228 try self.parseUnwindRecords(gpa, macho_file.getTarget().cpu.arch, macho_file);
226229 }
227230
228231 if (self.platform) |platform| {
......@@ -987,7 +990,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
987990 }
988991}
989992
990fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
993fn initUnwindRecords(self: *Object, allocator: Allocator, sect_id: u8, file: File.Handle, macho_file: *MachO) !void {
991994 const tracy = trace(@src());
992995 defer tracy.end();
993996
......@@ -1003,19 +1006,22 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
10031006 }
10041007 };
10051008
1006 const gpa = macho_file.base.comp.gpa;
1007 const data = try self.getSectionData(sect_id, macho_file);
1008 defer gpa.free(data);
1009 const header = self.sections.items(.header)[sect_id];
1010 const data = try allocator.alloc(u8, header.size);
1011 defer allocator.free(data);
1012 const amt = try file.preadAll(data, header.offset + self.offset);
1013 if (amt != data.len) return error.InputOutput;
1014
10091015 const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
10101016 const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];
10111017 const sym_lookup = SymbolLookup{ .ctx = self };
10121018
1013 try self.unwind_records.resize(gpa, nrecs);
1019 try self.unwind_records.ensureTotalCapacityPrecise(allocator, nrecs);
1020 try self.unwind_records_indexes.ensureTotalCapacityPrecise(allocator, nrecs);
10141021
1015 const header = self.sections.items(.header)[sect_id];
10161022 const relocs = self.sections.items(.relocs)[sect_id].items;
10171023 var reloc_idx: usize = 0;
1018 for (recs, self.unwind_records.items, 0..) |rec, *out_index, rec_idx| {
1024 for (recs, 0..) |rec, rec_idx| {
10191025 const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry);
10201026 const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry);
10211027 const reloc_start = reloc_idx;
......@@ -1023,11 +1029,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
10231029 relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1)
10241030 {}
10251031
1026 out_index.* = try macho_file.addUnwindRecord();
1027 const out = macho_file.getUnwindRecord(out_index.*);
1032 const out_index = self.addUnwindRecordAssumeCapacity();
1033 self.unwind_records_indexes.appendAssumeCapacity(out_index);
1034 const out = self.getUnwindRecord(out_index);
10281035 out.length = rec.rangeLength;
10291036 out.enc = .{ .enc = rec.compactUnwindEncoding };
1030 out.file = self.index;
10311037
10321038 for (relocs[reloc_start..reloc_idx]) |rel| {
10331039 if (rel.type != .unsigned or rel.meta.length != 3) {
......@@ -1090,7 +1096,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
10901096 }
10911097}
10921098
1093fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
1099fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch, macho_file: *MachO) !void {
10941100 // Synthesise missing unwind records.
10951101 // The logic here is as follows:
10961102 // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead
......@@ -1100,8 +1106,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11001106
11011107 const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null };
11021108
1103 const gpa = macho_file.base.comp.gpa;
1104 var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa);
1109 var superposition = std.AutoArrayHashMap(u64, Superposition).init(allocator);
11051110 defer superposition.deinit();
11061111
11071112 const slice = self.symtab.slice();
......@@ -1119,8 +1124,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11191124 }
11201125 }
11211126
1122 for (self.unwind_records.items) |rec_index| {
1123 const rec = macho_file.getUnwindRecord(rec_index);
1127 for (self.unwind_records_indexes.items) |rec_index| {
1128 const rec = self.getUnwindRecord(rec_index);
11241129 const atom = rec.getAtom(macho_file);
11251130 const addr = atom.getInputAddress(macho_file) + rec.atom_offset;
11261131 superposition.getPtr(addr).?.cu = rec_index;
......@@ -1137,7 +1142,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11371142 const fde = &self.fdes.items[fde_index];
11381143
11391144 if (meta.cu) |rec_index| {
1140 const rec = macho_file.getUnwindRecord(rec_index);
1145 const rec = self.getUnwindRecord(rec_index);
11411146 if (!rec.enc.isDwarf(macho_file)) {
11421147 // Mark FDE dead
11431148 fde.alive = false;
......@@ -1147,15 +1152,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11471152 }
11481153 } else {
11491154 // Synthesise new unwind info record
1150 const rec_index = try macho_file.addUnwindRecord();
1151 const rec = macho_file.getUnwindRecord(rec_index);
1152 try self.unwind_records.append(gpa, rec_index);
1155 const rec_index = try self.addUnwindRecord(allocator);
1156 const rec = self.getUnwindRecord(rec_index);
1157 try self.unwind_records_indexes.append(allocator, rec_index);
11531158 rec.length = @intCast(meta.size);
11541159 rec.atom = fde.atom;
11551160 rec.atom_offset = fde.atom_offset;
11561161 rec.fde = fde_index;
1157 rec.file = fde.file;
1158 switch (macho_file.getTarget().cpu.arch) {
1162 switch (cpu_arch) {
11591163 .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF),
11601164 .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF),
11611165 else => unreachable,
......@@ -1163,10 +1167,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11631167 }
11641168 } else if (meta.cu == null and meta.fde == null) {
11651169 // Create a null record
1166 const rec_index = try macho_file.addUnwindRecord();
1167 const rec = macho_file.getUnwindRecord(rec_index);
1170 const rec_index = try self.addUnwindRecord(allocator);
1171 const rec = self.getUnwindRecord(rec_index);
11681172 const atom = macho_file.getAtom(meta.atom).?;
1169 try self.unwind_records.append(gpa, rec_index);
1173 try self.unwind_records_indexes.append(allocator, rec_index);
11701174 rec.length = @intCast(meta.size);
11711175 rec.atom = meta.atom;
11721176 rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file));
......@@ -1174,25 +1178,31 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11741178 }
11751179 }
11761180
1177 const sortFn = struct {
1178 fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
1179 const lhs = ctx.getUnwindRecord(lhs_index);
1180 const rhs = ctx.getUnwindRecord(rhs_index);
1181 const lhsa = lhs.getAtom(ctx);
1182 const rhsa = rhs.getAtom(ctx);
1183 return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset;
1181 const SortCtx = struct {
1182 object: *Object,
1183 mfile: *MachO,
1184
1185 fn sort(ctx: @This(), lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
1186 const lhs = ctx.object.getUnwindRecord(lhs_index);
1187 const rhs = ctx.object.getUnwindRecord(rhs_index);
1188 const lhsa = lhs.getAtom(ctx.mfile);
1189 const rhsa = rhs.getAtom(ctx.mfile);
1190 return lhsa.getInputAddress(ctx.mfile) + lhs.atom_offset < rhsa.getInputAddress(ctx.mfile) + rhs.atom_offset;
11841191 }
1185 }.sortFn;
1186 mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn);
1192 };
1193 mem.sort(UnwindInfo.Record.Index, self.unwind_records_indexes.items, SortCtx{
1194 .object = self,
1195 .mfile = macho_file,
1196 }, SortCtx.sort);
11871197
11881198 // Associate unwind records to atoms
11891199 var next_cu: u32 = 0;
1190 while (next_cu < self.unwind_records.items.len) {
1200 while (next_cu < self.unwind_records_indexes.items.len) {
11911201 const start = next_cu;
1192 const rec_index = self.unwind_records.items[start];
1193 const rec = macho_file.getUnwindRecord(rec_index);
1194 while (next_cu < self.unwind_records.items.len and
1195 macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1)
1202 const rec_index = self.unwind_records_indexes.items[start];
1203 const rec = self.getUnwindRecord(rec_index);
1204 while (next_cu < self.unwind_records_indexes.items.len and
1205 self.getUnwindRecord(self.unwind_records_indexes.items[next_cu]).atom == rec.atom) : (next_cu += 1)
11961206 {}
11971207
11981208 const atom = rec.getAtom(macho_file);
......@@ -1441,7 +1451,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{
14411451 }
14421452}
14431453
1444pub fn scanRelocs(self: Object, macho_file: *MachO) !void {
1454pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
14451455 const tracy = trace(@src());
14461456 defer tracy.end();
14471457
......@@ -1453,8 +1463,8 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void {
14531463 try atom.scanRelocs(macho_file);
14541464 }
14551465
1456 for (self.unwind_records.items) |rec_index| {
1457 const rec = macho_file.getUnwindRecord(rec_index);
1466 for (self.unwind_records_indexes.items) |rec_index| {
1467 const rec = self.getUnwindRecord(rec_index);
14581468 if (!rec.alive) continue;
14591469 if (rec.getFde(macho_file)) |fde| {
14601470 if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| {
......@@ -1532,12 +1542,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
15321542 defer tracy.end();
15331543
15341544 const gpa = macho_file.base.comp.gpa;
1535 const offset = if (self.archive) |ar| ar.offset else 0;
15361545 const handle = macho_file.getFileHandle(self.file_handle);
15371546
15381547 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
15391548 {
1540 const amt = try handle.preadAll(&header_buffer, offset);
1549 const amt = try handle.preadAll(&header_buffer, self.offset);
15411550 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
15421551 }
15431552 self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;
......@@ -1558,7 +1567,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
15581567 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
15591568 defer gpa.free(lc_buffer);
15601569 {
1561 const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64));
1570 const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64));
15621571 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
15631572 }
15641573
......@@ -1571,14 +1580,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
15711580 const cmd = lc.cast(macho.symtab_command).?;
15721581 try self.strtab.resize(gpa, cmd.strsize);
15731582 {
1574 const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset);
1583 const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset);
15751584 if (amt != self.strtab.items.len) return error.InputOutput;
15761585 }
15771586
15781587 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
15791588 defer gpa.free(symtab_buffer);
15801589 {
1581 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset);
1590 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset);
15821591 if (amt != symtab_buffer.len) return error.InputOutput;
15831592 }
15841593 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];
......@@ -1613,7 +1622,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *M
16131622}
16141623
16151624pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
1616 self.output_ar_state.size = if (self.archive) |ar| ar.size else size: {
1625 self.output_ar_state.size = if (self.in_archive) |ar| ar.size else size: {
16171626 const file = macho_file.getFileHandle(self.file_handle);
16181627 break :size (try file.stat()).size;
16191628 };
......@@ -1622,7 +1631,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
16221631pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
16231632 // Header
16241633 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;
1625 const offset: u64 = if (self.archive) |ar| ar.offset else 0;
16261634 try Archive.writeHeader(self.path, size, ar_format, writer);
16271635 // Data
16281636 const file = macho_file.getFileHandle(self.file_handle);
......@@ -1630,7 +1638,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ
16301638 const gpa = macho_file.base.comp.gpa;
16311639 const data = try gpa.alloc(u8, size);
16321640 defer gpa.free(data);
1633 const amt = try file.preadAll(data, offset);
1641 const amt = try file.preadAll(data, self.offset);
16341642 if (amt != size) return error.InputOutput;
16351643 try writer.writeAll(data);
16361644}
......@@ -1680,7 +1688,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
16801688 self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir
16811689 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name
16821690
1683 if (self.archive) |ar| {
1691 if (self.in_archive) |ar| {
16841692 self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1));
16851693 } else {
16861694 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));
......@@ -1820,7 +1828,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
18201828 index += 1;
18211829 // N_OSO path
18221830 n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1823 if (self.archive) |ar| {
1831 if (self.in_archive) |ar| {
18241832 ctx.strtab.appendSliceAssumeCapacity(ar.path);
18251833 ctx.strtab.appendAssumeCapacity('(');
18261834 ctx.strtab.appendSliceAssumeCapacity(self.path);
......@@ -1989,11 +1997,10 @@ fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 {
19891997 assert(index < slice.items(.header).len);
19901998 const sect = slice.items(.header)[index];
19911999 const handle = macho_file.getFileHandle(self.file_handle);
1992 const offset = if (self.archive) |ar| ar.offset else 0;
19932000 const size = math.cast(usize, sect.size) orelse return error.Overflow;
19942001 const buffer = try gpa.alloc(u8, size);
19952002 errdefer gpa.free(buffer);
1996 const amt = try handle.preadAll(buffer, sect.offset + offset);
2003 const amt = try handle.preadAll(buffer, sect.offset + self.offset);
19972004 if (amt != buffer.len) return error.InputOutput;
19982005 return buffer;
19992006}
......@@ -2002,9 +2009,8 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer:
20022009 assert(buffer.len == atom.size);
20032010 const slice = self.sections.slice();
20042011 const handle = macho_file.getFileHandle(self.file_handle);
2005 const offset = if (self.archive) |ar| ar.offset else 0;
20062012 const sect = slice.items(.header)[atom.n_sect];
2007 const amt = try handle.preadAll(buffer, sect.offset + offset + atom.off);
2013 const amt = try handle.preadAll(buffer, sect.offset + self.offset + atom.off);
20082014 if (amt != buffer.len) return error.InputOutput;
20092015}
20102016
......@@ -2068,6 +2074,23 @@ pub fn asFile(self: *Object) File {
20682074 return .{ .object = self };
20692075}
20702076
2077fn addUnwindRecord(self: *Object, allocator: Allocator) !UnwindInfo.Record.Index {
2078 try self.unwind_records.ensureUnusedCapacity(allocator, 1);
2079 return self.addUnwindRecordAssumeCapacity();
2080}
2081
2082fn addUnwindRecordAssumeCapacity(self: *Object) UnwindInfo.Record.Index {
2083 const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len));
2084 const rec = self.unwind_records.addOneAssumeCapacity();
2085 rec.* = .{ .file = self.index };
2086 return index;
2087}
2088
2089pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInfo.Record {
2090 assert(index < self.unwind_records.items.len);
2091 return &self.unwind_records.items[index];
2092}
2093
20712094pub fn format(
20722095 self: *Object,
20732096 comptime unused_fmt_string: []const u8,
......@@ -2171,8 +2194,8 @@ fn formatUnwindRecords(
21712194 const object = ctx.object;
21722195 const macho_file = ctx.macho_file;
21732196 try writer.writeAll(" unwind records\n");
2174 for (object.unwind_records.items) |rec| {
2175 try writer.print(" rec({d}) : {}\n", .{ rec, macho_file.getUnwindRecord(rec).fmt(macho_file) });
2197 for (object.unwind_records_indexes.items) |rec| {
2198 try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) });
21762199 }
21772200}
21782201
......@@ -2211,7 +2234,7 @@ fn formatPath(
22112234) !void {
22122235 _ = unused_fmt_string;
22132236 _ = options;
2214 if (object.archive) |ar| {
2237 if (object.in_archive) |ar| {
22152238 try writer.writeAll(ar.path);
22162239 try writer.writeByte('(');
22172240 try writer.writeAll(object.path);
......@@ -2285,7 +2308,6 @@ const CompileUnit = struct {
22852308
22862309const InArchive = struct {
22872310 path: []const u8,
2288 offset: u64,
22892311 size: u32,
22902312};
22912313
......@@ -2300,11 +2322,10 @@ const x86_64 = struct {
23002322 const gpa = macho_file.base.comp.gpa;
23012323
23022324 const handle = macho_file.getFileHandle(self.file_handle);
2303 const offset = if (self.archive) |ar| ar.offset else 0;
23042325 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
23052326 defer gpa.free(relocs_buffer);
23062327 {
2307 const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset);
2328 const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset);
23082329 if (amt != relocs_buffer.len) return error.InputOutput;
23092330 }
23102331 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
......@@ -2463,11 +2484,10 @@ const aarch64 = struct {
24632484 const gpa = macho_file.base.comp.gpa;
24642485
24652486 const handle = macho_file.getFileHandle(self.file_handle);
2466 const offset = if (self.archive) |ar| ar.offset else 0;
24672487 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
24682488 defer gpa.free(relocs_buffer);
24692489 {
2470 const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset);
2490 const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset);
24712491 if (amt != relocs_buffer.len) return error.InputOutput;
24722492 }
24732493 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
src/link/MachO/UnwindInfo.zig+43-32
......@@ -1,6 +1,6 @@
11/// List of all unwind records gathered from all objects and sorted
22/// by allocated relative function address within the section.
3records: std.ArrayListUnmanaged(Record.Index) = .{},
3records: std.ArrayListUnmanaged(Record.Ref) = .{},
44
55/// List of all personalities referenced by either unwind info entries
66/// or __eh_frame entries.
......@@ -25,10 +25,10 @@ pub fn deinit(info: *UnwindInfo, allocator: Allocator) void {
2525 info.lsdas_lookup.deinit(allocator);
2626}
2727
28fn canFold(macho_file: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool {
28fn canFold(macho_file: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool {
2929 const cpu_arch = macho_file.getTarget().cpu.arch;
30 const lhs = macho_file.getUnwindRecord(lhs_index);
31 const rhs = macho_file.getUnwindRecord(rhs_index);
30 const lhs = lhs_ref.getUnwindRecord(macho_file);
31 const rhs = rhs_ref.getUnwindRecord(macho_file);
3232 if (cpu_arch == .x86_64) {
3333 if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or
3434 rhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND)) return false;
......@@ -52,17 +52,18 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
5252 const atom = macho_file.getAtom(atom_index) orelse continue;
5353 if (!atom.flags.alive) continue;
5454 const recs = atom.getUnwindRecords(macho_file);
55 const file = atom.getFile(macho_file);
5556 try info.records.ensureUnusedCapacity(gpa, recs.len);
5657 for (recs) |rec| {
57 if (!macho_file.getUnwindRecord(rec).alive) continue;
58 info.records.appendAssumeCapacity(rec);
58 if (!file.object.getUnwindRecord(rec).alive) continue;
59 info.records.appendAssumeCapacity(.{ .record = rec, .file = file.getIndex() });
5960 }
6061 }
6162 }
6263
6364 // Encode records
64 for (info.records.items) |index| {
65 const rec = macho_file.getUnwindRecord(index);
65 for (info.records.items) |ref| {
66 const rec = ref.getUnwindRecord(macho_file);
6667 if (rec.getFde(macho_file)) |fde| {
6768 rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset));
6869 if (fde.getLsdaAtom(macho_file)) |lsda| {
......@@ -83,16 +84,16 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
8384
8485 // Sort by assigned relative address within each output section
8586 const sortFn = struct {
86 fn sortFn(ctx: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool {
87 const lhs = ctx.getUnwindRecord(lhs_index);
88 const rhs = ctx.getUnwindRecord(rhs_index);
87 fn sortFn(ctx: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool {
88 const lhs = lhs_ref.getUnwindRecord(ctx);
89 const rhs = rhs_ref.getUnwindRecord(ctx);
8990 const lhsa = lhs.getAtom(ctx);
9091 const rhsa = rhs.getAtom(ctx);
9192 if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx);
9293 return lhsa.out_n_sect < rhsa.out_n_sect;
9394 }
9495 }.sortFn;
95 mem.sort(Record.Index, info.records.items, macho_file, sortFn);
96 mem.sort(Record.Ref, info.records.items, macho_file, sortFn);
9697
9798 // Fold the records
9899 // Any adjacent two records that share encoding can be folded into one.
......@@ -101,8 +102,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
101102 var j: usize = 1;
102103 while (j < info.records.items.len) : (j += 1) {
103104 if (canFold(macho_file, info.records.items[i], info.records.items[j])) {
104 const rec = macho_file.getUnwindRecord(info.records.items[i]);
105 rec.length += macho_file.getUnwindRecord(info.records.items[j]).length + 1;
105 const rec = info.records.items[i].getUnwindRecord(macho_file);
106 rec.length += info.records.items[j].getUnwindRecord(macho_file).length + 1;
106107 } else {
107108 i += 1;
108109 info.records.items[i] = info.records.items[j];
......@@ -111,14 +112,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
111112 info.records.shrinkAndFree(gpa, i + 1);
112113 }
113114
114 for (info.records.items) |rec_index| {
115 const rec = macho_file.getUnwindRecord(rec_index);
115 for (info.records.items) |ref| {
116 const rec = ref.getUnwindRecord(macho_file);
116117 const atom = rec.getAtom(macho_file);
117 log.debug("@{x}-{x} : {s} : rec({d}) : {}", .{
118 log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{
118119 rec.getAtomAddress(macho_file),
119120 rec.getAtomAddress(macho_file) + rec.length,
120121 atom.getName(macho_file),
121 rec_index,
122 ref.record,
123 ref.file,
122124 rec.enc,
123125 });
124126 }
......@@ -161,8 +163,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
161163 ).init(gpa);
162164 defer common_encodings_counts.deinit();
163165
164 for (info.records.items) |rec_index| {
165 const rec = macho_file.getUnwindRecord(rec_index);
166 for (info.records.items) |ref| {
167 const rec = ref.getUnwindRecord(macho_file);
166168 if (rec.enc.isDwarf(macho_file)) continue;
167169 const gop = try common_encodings_counts.getOrPut(rec.enc);
168170 if (!gop.found_existing) {
......@@ -190,7 +192,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
190192 {
191193 var i: u32 = 0;
192194 while (i < info.records.items.len) {
193 const rec = macho_file.getUnwindRecord(info.records.items[i]);
195 const rec = info.records.items[i].getUnwindRecord(macho_file);
194196 const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask;
195197 var encoding_count: u9 = info.common_encodings_count;
196198 var space_left: u32 = second_level_page_words -
......@@ -202,7 +204,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
202204 };
203205
204206 while (space_left >= 1 and i < info.records.items.len) {
205 const next = macho_file.getUnwindRecord(info.records.items[i]);
207 const next = info.records.items[i].getUnwindRecord(macho_file);
206208 const is_dwarf = next.enc.isDwarf(macho_file);
207209
208210 if (next.getAtomAddress(macho_file) >= range_start_max) {
......@@ -244,8 +246,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
244246 // Save records having an LSDA pointer
245247 log.debug("LSDA pointers:", .{});
246248 try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len);
247 for (info.records.items, 0..) |index, i| {
248 const rec = macho_file.getUnwindRecord(index);
249 for (info.records.items, 0..) |ref, i| {
250 const rec = ref.getUnwindRecord(macho_file);
249251 info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len));
250252 if (rec.getLsdaAtom(macho_file)) |lsda| {
251253 log.debug(" @{x} => lsda({d})", .{ rec.getAtomAddress(macho_file), lsda.atom_index });
......@@ -301,7 +303,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
301303 (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry))));
302304 for (info.pages.items, 0..) |page, i| {
303305 assert(page.count > 0);
304 const rec = macho_file.getUnwindRecord(info.records.items[page.start]);
306 const rec = info.records.items[page.start].getUnwindRecord(macho_file);
305307 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
306308 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
307309 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),
......@@ -310,7 +312,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
310312 });
311313 }
312314
313 const last_rec = macho_file.getUnwindRecord(info.records.items[info.records.items.len - 1]);
315 const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file);
314316 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
315317 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
316318 .functionOffset = sentinel_address,
......@@ -320,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
320322 });
321323
322324 for (info.lsdas.items) |index| {
323 const rec = macho_file.getUnwindRecord(info.records.items[index]);
325 const rec = info.records.items[index].getUnwindRecord(macho_file);
324326 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
325327 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
326328 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
......@@ -537,6 +539,15 @@ pub const Record = struct {
537539 }
538540
539541 pub const Index = u32;
542
543 const Ref = struct {
544 record: Index,
545 file: File.Index,
546
547 pub fn getUnwindRecord(ref: Ref, macho_file: *MachO) *Record {
548 return macho_file.getFile(ref.file).?.object.getUnwindRecord(ref.record);
549 }
550 };
540551};
541552
542553const max_personalities = 3;
......@@ -635,8 +646,8 @@ const Page = struct {
635646 .entryCount = page.count,
636647 });
637648
638 for (info.records.items[page.start..][0..page.count]) |index| {
639 const rec = macho_file.getUnwindRecord(index);
649 for (info.records.items[page.start..][0..page.count]) |ref| {
650 const rec = ref.getUnwindRecord(macho_file);
640651 try writer.writeStruct(macho.unwind_info_regular_second_level_entry{
641652 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
642653 .encoding = rec.enc.enc,
......@@ -658,9 +669,9 @@ const Page = struct {
658669 }
659670
660671 assert(page.count > 0);
661 const first_rec = macho_file.getUnwindRecord(info.records.items[page.start]);
662 for (info.records.items[page.start..][0..page.count]) |index| {
663 const rec = macho_file.getUnwindRecord(index);
672 const first_rec = info.records.items[page.start].getUnwindRecord(macho_file);
673 for (info.records.items[page.start..][0..page.count]) |ref| {
674 const rec = ref.getUnwindRecord(macho_file);
664675 const enc_index = blk: {
665676 if (info.getCommonEncoding(rec.enc)) |id| break :blk id;
666677 const ncommon = info.common_encodings_count;
src/link/MachO/dead_strip.zig+5-3
......@@ -41,8 +41,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho
4141 }
4242
4343 for (macho_file.objects.items) |index| {
44 for (macho_file.getFile(index).?.object.unwind_records.items) |cu_index| {
45 const cu = macho_file.getUnwindRecord(cu_index);
44 const object = macho_file.getFile(index).?.object;
45 for (object.unwind_records_indexes.items) |cu_index| {
46 const cu = object.getUnwindRecord(cu_index);
4647 if (!cu.alive) continue;
4748 if (cu.getFde(macho_file)) |fde| {
4849 if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| try markSymbol(sym, roots, macho_file);
......@@ -127,8 +128,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {
127128 }
128129 }
129130
131 const file = atom.getFile(macho_file);
130132 for (atom.getUnwindRecords(macho_file)) |cu_index| {
131 const cu = macho_file.getUnwindRecord(cu_index);
133 const cu = file.object.getUnwindRecord(cu_index);
132134 const cu_atom = cu.getAtom(macho_file);
133135 if (markAtom(cu_atom)) markLive(cu_atom, macho_file);
134136
src/link/MachO/relocatable.zig+13-10
......@@ -286,12 +286,15 @@ fn parseObject(macho_file: *MachO, path: []const u8) MachO.ParseError!void {
286286 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
287287 };
288288 const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa)));
289 macho_file.files.set(index, .{ .object = .{
290 .path = try gpa.dupe(u8, path),
291 .file_handle = handle,
292 .mtime = mtime,
293 .index = index,
294 } });
289 macho_file.files.set(index, .{
290 .object = .{
291 .offset = 0, // TODO FAT objects
292 .path = try gpa.dupe(u8, path),
293 .file_handle = handle,
294 .mtime = mtime,
295 .index = index,
296 },
297 });
295298 try macho_file.objects.append(gpa, index);
296299
297300 const object = macho_file.getFile(index).?.object;
......@@ -420,8 +423,8 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
420423
421424 for (macho_file.objects.items) |index| {
422425 const object = macho_file.getFile(index).?.object;
423 for (object.unwind_records.items) |irec| {
424 const rec = macho_file.getUnwindRecord(irec);
426 for (object.unwind_records_indexes.items) |irec| {
427 const rec = object.getUnwindRecord(irec);
425428 if (!rec.alive) continue;
426429 size += @sizeOf(macho.compact_unwind_entry);
427430 nreloc += 1;
......@@ -670,8 +673,8 @@ fn writeCompactUnwind(macho_file: *MachO) !void {
670673 var offset: i32 = 0;
671674 for (macho_file.objects.items) |index| {
672675 const object = macho_file.getFile(index).?.object;
673 for (object.unwind_records.items) |irec| {
674 const rec = macho_file.getUnwindRecord(irec);
676 for (object.unwind_records_indexes.items) |irec| {
677 const rec = object.getUnwindRecord(irec);
675678 if (!rec.alive) continue;
676679
677680 var out: macho.compact_unwind_entry = .{