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,...@@ -67,7 +67,6 @@ entry_index: ?Symbol.Index = null,
67atoms: std.ArrayListUnmanaged(Atom) = .{},67atoms: std.ArrayListUnmanaged(Atom) = .{},
68atoms_extra: std.ArrayListUnmanaged(u32) = .{},68atoms_extra: std.ArrayListUnmanaged(u32) = .{},
69thunks: std.ArrayListUnmanaged(Thunk) = .{},69thunks: std.ArrayListUnmanaged(Thunk) = .{},
70unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{},
7170
72/// String interning table71/// String interning table
73strings: StringTable = .{},72strings: StringTable = .{},
...@@ -357,7 +356,6 @@ pub fn deinit(self: *MachO) void {...@@ -357,7 +356,6 @@ pub fn deinit(self: *MachO) void {
357 thunk.deinit(gpa);356 thunk.deinit(gpa);
358 }357 }
359 self.thunks.deinit(gpa);358 self.thunks.deinit(gpa);
360 self.unwind_records.deinit(gpa);
361}359}
362360
363pub fn flush(self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {361pub 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 {...@@ -982,12 +980,15 @@ fn parseObject(self: *MachO, path: []const u8) ParseError!void {
982 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));980 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
983 };981 };
984 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));982 const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
985 self.files.set(index, .{ .object = .{983 self.files.set(index, .{
986 .path = try gpa.dupe(u8, path),984 .object = .{
987 .file_handle = handle,985 .offset = 0, // TODO FAT objects
988 .mtime = mtime,986 .path = try gpa.dupe(u8, path),
989 .index = index,987 .file_handle = handle,
990 } });988 .mtime = mtime,
989 .index = index,
990 },
991 });
991 try self.objects.append(gpa, index);992 try self.objects.append(gpa, index);
992993
993 const object = self.getFile(index).?.object;994 const object = self.getFile(index).?.object;
...@@ -4058,18 +4059,6 @@ pub fn getGlobalByName(self: *MachO, name: []const u8) ?Symbol.Index {...@@ -4058,18 +4059,6 @@ pub fn getGlobalByName(self: *MachO, name: []const u8) ?Symbol.Index {
4058 return self.globals.get(off);4059 return self.globals.get(off);
4059}4060}
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
4073pub fn addThunk(self: *MachO) !Thunk.Index {4062pub fn addThunk(self: *MachO) !Thunk.Index {
4074 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));4063 const index = @as(Thunk.Index, @intCast(self.thunks.items.len));
4075 const thunk = try self.thunks.addOne(self.base.comp.gpa);4064 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:...@@ -67,9 +67,9 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index:
67 mem.eql(u8, name, SYMDEF64_SORTED)) continue;67 mem.eql(u8, name, SYMDEF64_SORTED)) continue;
6868
69 const object = Object{69 const object = Object{
70 .archive = .{70 .offset = pos,
71 .in_archive = .{
71 .path = try gpa.dupe(u8, path),72 .path = try gpa.dupe(u8, path),
72 .offset = pos,
73 .size = hdr_size,73 .size = hdr_size,
74 },74 },
75 .path = try gpa.dupe(u8, name),75 .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...@@ -91,14 +91,16 @@ pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Recor
91 if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{};91 if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{};
92 const extra = self.getExtra(macho_file).?;92 const extra = self.getExtra(macho_file).?;
93 return switch (self.getFile(macho_file)) {93 return switch (self.getFile(macho_file)) {
94 .dylib, .zig_object, .internal => unreachable,94 .dylib => unreachable,
95 .object => |x| x.unwind_records.items[extra.unwind_index..][0..extra.unwind_count],95 .zig_object, .internal => &[0]UnwindInfo.Record.Index{},
96 .object => |x| x.unwind_records_indexes.items[extra.unwind_index..][0..extra.unwind_count],
96 };97 };
97}98}
9899
99pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void {100pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void {
101 const object = self.getFile(macho_file).object;
100 for (self.getUnwindRecords(macho_file)) |cu_index| {102 for (self.getUnwindRecords(macho_file)) |cu_index| {
101 const cu = macho_file.getUnwindRecord(cu_index);103 const cu = object.getUnwindRecord(cu_index);
102 cu.alive = false;104 cu.alive = false;
103105
104 if (cu.getFdePtr(macho_file)) |fde| {106 if (cu.getFdePtr(macho_file)) |fde| {
...@@ -1170,6 +1172,7 @@ fn format2(...@@ -1170,6 +1172,7 @@ fn format2(
1170 _ = unused_fmt_string;1172 _ = unused_fmt_string;
1171 const atom = ctx.atom;1173 const atom = ctx.atom;
1172 const macho_file = ctx.macho_file;1174 const macho_file = ctx.macho_file;
1175 const file = atom.getFile(macho_file);
1173 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{1176 try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{
1174 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),1177 atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file),
1175 atom.out_n_sect, atom.alignment, atom.size,1178 atom.out_n_sect, atom.alignment, atom.size,
...@@ -1181,7 +1184,7 @@ fn format2(...@@ -1181,7 +1184,7 @@ fn format2(
1181 try writer.writeAll(" : unwind{ ");1184 try writer.writeAll(" : unwind{ ");
1182 const extra = atom.getExtra(macho_file).?;1185 const extra = atom.getExtra(macho_file).?;
1183 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {1186 for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| {
1184 const rec = macho_file.getUnwindRecord(index);1187 const rec = file.object.getUnwindRecord(index);
1185 try writer.print("{d}", .{index});1188 try writer.print("{d}", .{index});
1186 if (!rec.alive) try writer.writeAll("([*])");1189 if (!rec.alive) try writer.writeAll("([*])");
1187 if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", ");1190 if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", ");
src/link/MachO/Object.zig+94-74
...@@ -1,8 +1,10 @@...@@ -1,8 +1,10 @@
1archive: ?InArchive = null,1/// Non-zero for fat object files or archives
2offset: u64,
2path: []const u8,3path: []const u8,
3file_handle: File.HandleIndex,4file_handle: File.HandleIndex,
4mtime: u64,5mtime: u64,
5index: File.Index,6index: File.Index,
7in_archive: ?InArchive = null,
68
7header: ?macho.mach_header_64 = null,9header: ?macho.mach_header_64 = null,
8sections: std.MultiArrayList(Section) = .{},10sections: std.MultiArrayList(Section) = .{},
...@@ -21,7 +23,8 @@ compact_unwind_sect_index: ?u8 = null,...@@ -21,7 +23,8 @@ compact_unwind_sect_index: ?u8 = null,
21cies: std.ArrayListUnmanaged(Cie) = .{},23cies: std.ArrayListUnmanaged(Cie) = .{},
22fdes: std.ArrayListUnmanaged(Fde) = .{},24fdes: std.ArrayListUnmanaged(Fde) = .{},
23eh_frame_data: std.ArrayListUnmanaged(u8) = .{},25eh_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) = .{},
25data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},28data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
2629
27alive: bool = true,30alive: bool = true,
...@@ -39,7 +42,7 @@ pub fn isObject(path: []const u8) !bool {...@@ -39,7 +42,7 @@ pub fn isObject(path: []const u8) !bool {
39}42}
4043
41pub fn deinit(self: *Object, allocator: Allocator) void {44pub 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);
43 allocator.free(self.path);46 allocator.free(self.path);
44 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {47 for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| {
45 relocs.deinit(allocator);48 relocs.deinit(allocator);
...@@ -54,6 +57,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {...@@ -54,6 +57,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void {
54 self.fdes.deinit(allocator);57 self.fdes.deinit(allocator);
55 self.eh_frame_data.deinit(allocator);58 self.eh_frame_data.deinit(allocator);
56 self.unwind_records.deinit(allocator);59 self.unwind_records.deinit(allocator);
60 self.unwind_records_indexes.deinit(allocator);
57 for (self.stab_files.items) |*sf| {61 for (self.stab_files.items) |*sf| {
58 sf.stabs.deinit(allocator);62 sf.stabs.deinit(allocator);
59 }63 }
...@@ -66,12 +70,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -66,12 +70,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
66 defer tracy.end();70 defer tracy.end();
6771
68 const gpa = macho_file.base.comp.gpa;72 const gpa = macho_file.base.comp.gpa;
69 const offset = if (self.archive) |ar| ar.offset else 0;
70 const handle = macho_file.getFileHandle(self.file_handle);73 const handle = macho_file.getFileHandle(self.file_handle);
7174
72 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;75 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
73 {76 {
74 const amt = try handle.preadAll(&header_buffer, offset);77 const amt = try handle.preadAll(&header_buffer, self.offset);
75 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;78 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
76 }79 }
77 self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;80 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 {...@@ -92,7 +95,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
92 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);95 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
93 defer gpa.free(lc_buffer);96 defer gpa.free(lc_buffer);
94 {97 {
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));
96 if (amt != self.header.?.sizeofcmds) return error.InputOutput;99 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
97 }100 }
98101
...@@ -119,14 +122,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -119,14 +122,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
119 const cmd = lc.cast(macho.symtab_command).?;122 const cmd = lc.cast(macho.symtab_command).?;
120 try self.strtab.resize(gpa, cmd.strsize);123 try self.strtab.resize(gpa, cmd.strsize);
121 {124 {
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);
123 if (amt != self.strtab.items.len) return error.InputOutput;126 if (amt != self.strtab.items.len) return error.InputOutput;
124 }127 }
125128
126 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));129 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
127 defer gpa.free(symtab_buffer);130 defer gpa.free(symtab_buffer);
128 {131 {
129 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset);132 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset);
130 if (amt != symtab_buffer.len) return error.InputOutput;133 if (amt != symtab_buffer.len) return error.InputOutput;
131 }134 }
132 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];135 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 {...@@ -144,7 +147,7 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
144 const buffer = try gpa.alloc(u8, cmd.datasize);147 const buffer = try gpa.alloc(u8, cmd.datasize);
145 defer gpa.free(buffer);148 defer gpa.free(buffer);
146 {149 {
147 const amt = try handle.preadAll(buffer, offset + cmd.dataoff);150 const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff);
148 if (amt != buffer.len) return error.InputOutput;151 if (amt != buffer.len) return error.InputOutput;
149 }152 }
150 const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));153 const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry));
...@@ -218,11 +221,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {...@@ -218,11 +221,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void {
218221
219 // Parse Apple's __LD,__compact_unwind section222 // Parse Apple's __LD,__compact_unwind section
220 if (self.compact_unwind_sect_index) |index| {223 if (self.compact_unwind_sect_index) |index| {
221 try self.initUnwindRecords(index, macho_file);224 try self.initUnwindRecords(gpa, index, handle, macho_file);
222 }225 }
223226
224 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {227 if (self.hasUnwindRecords() or self.hasEhFrameRecords()) {
225 try self.parseUnwindRecords(macho_file);228 try self.parseUnwindRecords(gpa, macho_file.getTarget().cpu.arch, macho_file);
226 }229 }
227230
228 if (self.platform) |platform| {231 if (self.platform) |platform| {
...@@ -987,7 +990,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -987,7 +990,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
987 }990 }
988}991}
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 {
991 const tracy = trace(@src());994 const tracy = trace(@src());
992 defer tracy.end();995 defer tracy.end();
993996
...@@ -1003,19 +1006,22 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -1003,19 +1006,22 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
1003 }1006 }
1004 };1007 };
10051008
1006 const gpa = macho_file.base.comp.gpa;1009 const header = self.sections.items(.header)[sect_id];
1007 const data = try self.getSectionData(sect_id, macho_file);1010 const data = try allocator.alloc(u8, header.size);
1008 defer gpa.free(data);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
1009 const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));1015 const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry));
1010 const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];1016 const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs];
1011 const sym_lookup = SymbolLookup{ .ctx = self };1017 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];
1016 const relocs = self.sections.items(.relocs)[sect_id].items;1022 const relocs = self.sections.items(.relocs)[sect_id].items;
1017 var reloc_idx: usize = 0;1023 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| {
1019 const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry);1025 const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry);
1020 const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry);1026 const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry);
1021 const reloc_start = reloc_idx;1027 const reloc_start = reloc_idx;
...@@ -1023,11 +1029,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -1023,11 +1029,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
1023 relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1)1029 relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1)
1024 {}1030 {}
10251031
1026 out_index.* = try macho_file.addUnwindRecord();1032 const out_index = self.addUnwindRecordAssumeCapacity();
1027 const out = macho_file.getUnwindRecord(out_index.*);1033 self.unwind_records_indexes.appendAssumeCapacity(out_index);
1034 const out = self.getUnwindRecord(out_index);
1028 out.length = rec.rangeLength;1035 out.length = rec.rangeLength;
1029 out.enc = .{ .enc = rec.compactUnwindEncoding };1036 out.enc = .{ .enc = rec.compactUnwindEncoding };
1030 out.file = self.index;
10311037
1032 for (relocs[reloc_start..reloc_idx]) |rel| {1038 for (relocs[reloc_start..reloc_idx]) |rel| {
1033 if (rel.type != .unsigned or rel.meta.length != 3) {1039 if (rel.type != .unsigned or rel.meta.length != 3) {
...@@ -1090,7 +1096,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {...@@ -1090,7 +1096,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void {
1090 }1096 }
1091}1097}
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 {
1094 // Synthesise missing unwind records.1100 // Synthesise missing unwind records.
1095 // The logic here is as follows:1101 // The logic here is as follows:
1096 // 1. if an atom has unwind info record that is not DWARF, FDE is marked dead1102 // 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 {...@@ -1100,8 +1106,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
11001106
1101 const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null };1107 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;1109 var superposition = std.AutoArrayHashMap(u64, Superposition).init(allocator);
1104 var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa);
1105 defer superposition.deinit();1110 defer superposition.deinit();
11061111
1107 const slice = self.symtab.slice();1112 const slice = self.symtab.slice();
...@@ -1119,8 +1124,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -1119,8 +1124,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
1119 }1124 }
1120 }1125 }
11211126
1122 for (self.unwind_records.items) |rec_index| {1127 for (self.unwind_records_indexes.items) |rec_index| {
1123 const rec = macho_file.getUnwindRecord(rec_index);1128 const rec = self.getUnwindRecord(rec_index);
1124 const atom = rec.getAtom(macho_file);1129 const atom = rec.getAtom(macho_file);
1125 const addr = atom.getInputAddress(macho_file) + rec.atom_offset;1130 const addr = atom.getInputAddress(macho_file) + rec.atom_offset;
1126 superposition.getPtr(addr).?.cu = rec_index;1131 superposition.getPtr(addr).?.cu = rec_index;
...@@ -1137,7 +1142,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -1137,7 +1142,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
1137 const fde = &self.fdes.items[fde_index];1142 const fde = &self.fdes.items[fde_index];
11381143
1139 if (meta.cu) |rec_index| {1144 if (meta.cu) |rec_index| {
1140 const rec = macho_file.getUnwindRecord(rec_index);1145 const rec = self.getUnwindRecord(rec_index);
1141 if (!rec.enc.isDwarf(macho_file)) {1146 if (!rec.enc.isDwarf(macho_file)) {
1142 // Mark FDE dead1147 // Mark FDE dead
1143 fde.alive = false;1148 fde.alive = false;
...@@ -1147,15 +1152,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -1147,15 +1152,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
1147 }1152 }
1148 } else {1153 } else {
1149 // Synthesise new unwind info record1154 // Synthesise new unwind info record
1150 const rec_index = try macho_file.addUnwindRecord();1155 const rec_index = try self.addUnwindRecord(allocator);
1151 const rec = macho_file.getUnwindRecord(rec_index);1156 const rec = self.getUnwindRecord(rec_index);
1152 try self.unwind_records.append(gpa, rec_index);1157 try self.unwind_records_indexes.append(allocator, rec_index);
1153 rec.length = @intCast(meta.size);1158 rec.length = @intCast(meta.size);
1154 rec.atom = fde.atom;1159 rec.atom = fde.atom;
1155 rec.atom_offset = fde.atom_offset;1160 rec.atom_offset = fde.atom_offset;
1156 rec.fde = fde_index;1161 rec.fde = fde_index;
1157 rec.file = fde.file;1162 switch (cpu_arch) {
1158 switch (macho_file.getTarget().cpu.arch) {
1159 .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF),1163 .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF),
1160 .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF),1164 .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF),
1161 else => unreachable,1165 else => unreachable,
...@@ -1163,10 +1167,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -1163,10 +1167,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
1163 }1167 }
1164 } else if (meta.cu == null and meta.fde == null) {1168 } else if (meta.cu == null and meta.fde == null) {
1165 // Create a null record1169 // Create a null record
1166 const rec_index = try macho_file.addUnwindRecord();1170 const rec_index = try self.addUnwindRecord(allocator);
1167 const rec = macho_file.getUnwindRecord(rec_index);1171 const rec = self.getUnwindRecord(rec_index);
1168 const atom = macho_file.getAtom(meta.atom).?;1172 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);
1170 rec.length = @intCast(meta.size);1174 rec.length = @intCast(meta.size);
1171 rec.atom = meta.atom;1175 rec.atom = meta.atom;
1172 rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file));1176 rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file));
...@@ -1174,25 +1178,31 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {...@@ -1174,25 +1178,31 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void {
1174 }1178 }
1175 }1179 }
11761180
1177 const sortFn = struct {1181 const SortCtx = struct {
1178 fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {1182 object: *Object,
1179 const lhs = ctx.getUnwindRecord(lhs_index);1183 mfile: *MachO,
1180 const rhs = ctx.getUnwindRecord(rhs_index);1184
1181 const lhsa = lhs.getAtom(ctx);1185 fn sort(ctx: @This(), lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool {
1182 const rhsa = rhs.getAtom(ctx);1186 const lhs = ctx.object.getUnwindRecord(lhs_index);
1183 return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset;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;
1184 }1191 }
1185 }.sortFn;1192 };
1186 mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn);1193 mem.sort(UnwindInfo.Record.Index, self.unwind_records_indexes.items, SortCtx{
1194 .object = self,
1195 .mfile = macho_file,
1196 }, SortCtx.sort);
11871197
1188 // Associate unwind records to atoms1198 // Associate unwind records to atoms
1189 var next_cu: u32 = 0;1199 var next_cu: u32 = 0;
1190 while (next_cu < self.unwind_records.items.len) {1200 while (next_cu < self.unwind_records_indexes.items.len) {
1191 const start = next_cu;1201 const start = next_cu;
1192 const rec_index = self.unwind_records.items[start];1202 const rec_index = self.unwind_records_indexes.items[start];
1193 const rec = macho_file.getUnwindRecord(rec_index);1203 const rec = self.getUnwindRecord(rec_index);
1194 while (next_cu < self.unwind_records.items.len and1204 while (next_cu < self.unwind_records_indexes.items.len and
1195 macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1)1205 self.getUnwindRecord(self.unwind_records_indexes.items[next_cu]).atom == rec.atom) : (next_cu += 1)
1196 {}1206 {}
11971207
1198 const atom = rec.getAtom(macho_file);1208 const atom = rec.getAtom(macho_file);
...@@ -1441,7 +1451,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{...@@ -1441,7 +1451,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{
1441 }1451 }
1442}1452}
14431453
1444pub fn scanRelocs(self: Object, macho_file: *MachO) !void {1454pub fn scanRelocs(self: *Object, macho_file: *MachO) !void {
1445 const tracy = trace(@src());1455 const tracy = trace(@src());
1446 defer tracy.end();1456 defer tracy.end();
14471457
...@@ -1453,8 +1463,8 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void {...@@ -1453,8 +1463,8 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void {
1453 try atom.scanRelocs(macho_file);1463 try atom.scanRelocs(macho_file);
1454 }1464 }
14551465
1456 for (self.unwind_records.items) |rec_index| {1466 for (self.unwind_records_indexes.items) |rec_index| {
1457 const rec = macho_file.getUnwindRecord(rec_index);1467 const rec = self.getUnwindRecord(rec_index);
1458 if (!rec.alive) continue;1468 if (!rec.alive) continue;
1459 if (rec.getFde(macho_file)) |fde| {1469 if (rec.getFde(macho_file)) |fde| {
1460 if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| {1470 if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| {
...@@ -1532,12 +1542,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {...@@ -1532,12 +1542,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
1532 defer tracy.end();1542 defer tracy.end();
15331543
1534 const gpa = macho_file.base.comp.gpa;1544 const gpa = macho_file.base.comp.gpa;
1535 const offset = if (self.archive) |ar| ar.offset else 0;
1536 const handle = macho_file.getFileHandle(self.file_handle);1545 const handle = macho_file.getFileHandle(self.file_handle);
15371546
1538 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;1547 var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined;
1539 {1548 {
1540 const amt = try handle.preadAll(&header_buffer, offset);1549 const amt = try handle.preadAll(&header_buffer, self.offset);
1541 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;1550 if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput;
1542 }1551 }
1543 self.header = @as(*align(1) const macho.mach_header_64, @ptrCast(&header_buffer)).*;1552 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 {...@@ -1558,7 +1567,7 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
1558 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);1567 const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds);
1559 defer gpa.free(lc_buffer);1568 defer gpa.free(lc_buffer);
1560 {1569 {
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));
1562 if (amt != self.header.?.sizeofcmds) return error.InputOutput;1571 if (amt != self.header.?.sizeofcmds) return error.InputOutput;
1563 }1572 }
15641573
...@@ -1571,14 +1580,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {...@@ -1571,14 +1580,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void {
1571 const cmd = lc.cast(macho.symtab_command).?;1580 const cmd = lc.cast(macho.symtab_command).?;
1572 try self.strtab.resize(gpa, cmd.strsize);1581 try self.strtab.resize(gpa, cmd.strsize);
1573 {1582 {
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);
1575 if (amt != self.strtab.items.len) return error.InputOutput;1584 if (amt != self.strtab.items.len) return error.InputOutput;
1576 }1585 }
15771586
1578 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));1587 const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64));
1579 defer gpa.free(symtab_buffer);1588 defer gpa.free(symtab_buffer);
1580 {1589 {
1581 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset);1590 const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset);
1582 if (amt != symtab_buffer.len) return error.InputOutput;1591 if (amt != symtab_buffer.len) return error.InputOutput;
1583 }1592 }
1584 const symtab = @as([*]align(1) const macho.nlist_64, @ptrCast(symtab_buffer.ptr))[0..cmd.nsyms];1593 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...@@ -1613,7 +1622,7 @@ pub fn updateArSymtab(self: Object, ar_symtab: *Archive.ArSymtab, macho_file: *M
1613}1622}
16141623
1615pub fn updateArSize(self: *Object, macho_file: *MachO) !void {1624pub 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: {
1617 const file = macho_file.getFileHandle(self.file_handle);1626 const file = macho_file.getFileHandle(self.file_handle);
1618 break :size (try file.stat()).size;1627 break :size (try file.stat()).size;
1619 };1628 };
...@@ -1622,7 +1631,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {...@@ -1622,7 +1631,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void {
1622pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {1631pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void {
1623 // Header1632 // Header
1624 const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow;1633 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;
1626 try Archive.writeHeader(self.path, size, ar_format, writer);1634 try Archive.writeHeader(self.path, size, ar_format, writer);
1627 // Data1635 // Data
1628 const file = macho_file.getFileHandle(self.file_handle);1636 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...@@ -1630,7 +1638,7 @@ pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writ
1630 const gpa = macho_file.base.comp.gpa;1638 const gpa = macho_file.base.comp.gpa;
1631 const data = try gpa.alloc(u8, size);1639 const data = try gpa.alloc(u8, size);
1632 defer gpa.free(data);1640 defer gpa.free(data);
1633 const amt = try file.preadAll(data, offset);1641 const amt = try file.preadAll(data, self.offset);
1634 if (amt != size) return error.InputOutput;1642 if (amt != size) return error.InputOutput;
1635 try writer.writeAll(data);1643 try writer.writeAll(data);
1636}1644}
...@@ -1680,7 +1688,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {...@@ -1680,7 +1688,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void {
1680 self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir1688 self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir
1681 self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name1689 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| {
1684 self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1));1692 self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1));
1685 } else {1693 } else {
1686 self.output_symtab_ctx.strsize += @as(u32, @intCast(self.path.len + 1));1694 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...@@ -1820,7 +1828,7 @@ pub fn writeStabs(self: *const Object, macho_file: *MachO, ctx: anytype) error{O
1820 index += 1;1828 index += 1;
1821 // N_OSO path1829 // N_OSO path
1822 n_strx = @as(u32, @intCast(ctx.strtab.items.len));1830 n_strx = @as(u32, @intCast(ctx.strtab.items.len));
1823 if (self.archive) |ar| {1831 if (self.in_archive) |ar| {
1824 ctx.strtab.appendSliceAssumeCapacity(ar.path);1832 ctx.strtab.appendSliceAssumeCapacity(ar.path);
1825 ctx.strtab.appendAssumeCapacity('(');1833 ctx.strtab.appendAssumeCapacity('(');
1826 ctx.strtab.appendSliceAssumeCapacity(self.path);1834 ctx.strtab.appendSliceAssumeCapacity(self.path);
...@@ -1989,11 +1997,10 @@ fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 {...@@ -1989,11 +1997,10 @@ fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 {
1989 assert(index < slice.items(.header).len);1997 assert(index < slice.items(.header).len);
1990 const sect = slice.items(.header)[index];1998 const sect = slice.items(.header)[index];
1991 const handle = macho_file.getFileHandle(self.file_handle);1999 const handle = macho_file.getFileHandle(self.file_handle);
1992 const offset = if (self.archive) |ar| ar.offset else 0;
1993 const size = math.cast(usize, sect.size) orelse return error.Overflow;2000 const size = math.cast(usize, sect.size) orelse return error.Overflow;
1994 const buffer = try gpa.alloc(u8, size);2001 const buffer = try gpa.alloc(u8, size);
1995 errdefer gpa.free(buffer);2002 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);
1997 if (amt != buffer.len) return error.InputOutput;2004 if (amt != buffer.len) return error.InputOutput;
1998 return buffer;2005 return buffer;
1999}2006}
...@@ -2002,9 +2009,8 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer:...@@ -2002,9 +2009,8 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer:
2002 assert(buffer.len == atom.size);2009 assert(buffer.len == atom.size);
2003 const slice = self.sections.slice();2010 const slice = self.sections.slice();
2004 const handle = macho_file.getFileHandle(self.file_handle);2011 const handle = macho_file.getFileHandle(self.file_handle);
2005 const offset = if (self.archive) |ar| ar.offset else 0;
2006 const sect = slice.items(.header)[atom.n_sect];2012 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);
2008 if (amt != buffer.len) return error.InputOutput;2014 if (amt != buffer.len) return error.InputOutput;
2009}2015}
20102016
...@@ -2068,6 +2074,23 @@ pub fn asFile(self: *Object) File {...@@ -2068,6 +2074,23 @@ pub fn asFile(self: *Object) File {
2068 return .{ .object = self };2074 return .{ .object = self };
2069}2075}
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
2071pub fn format(2094pub fn format(
2072 self: *Object,2095 self: *Object,
2073 comptime unused_fmt_string: []const u8,2096 comptime unused_fmt_string: []const u8,
...@@ -2171,8 +2194,8 @@ fn formatUnwindRecords(...@@ -2171,8 +2194,8 @@ fn formatUnwindRecords(
2171 const object = ctx.object;2194 const object = ctx.object;
2172 const macho_file = ctx.macho_file;2195 const macho_file = ctx.macho_file;
2173 try writer.writeAll(" unwind records\n");2196 try writer.writeAll(" unwind records\n");
2174 for (object.unwind_records.items) |rec| {2197 for (object.unwind_records_indexes.items) |rec| {
2175 try writer.print(" rec({d}) : {}\n", .{ rec, macho_file.getUnwindRecord(rec).fmt(macho_file) });2198 try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) });
2176 }2199 }
2177}2200}
21782201
...@@ -2211,7 +2234,7 @@ fn formatPath(...@@ -2211,7 +2234,7 @@ fn formatPath(
2211) !void {2234) !void {
2212 _ = unused_fmt_string;2235 _ = unused_fmt_string;
2213 _ = options;2236 _ = options;
2214 if (object.archive) |ar| {2237 if (object.in_archive) |ar| {
2215 try writer.writeAll(ar.path);2238 try writer.writeAll(ar.path);
2216 try writer.writeByte('(');2239 try writer.writeByte('(');
2217 try writer.writeAll(object.path);2240 try writer.writeAll(object.path);
...@@ -2285,7 +2308,6 @@ const CompileUnit = struct {...@@ -2285,7 +2308,6 @@ const CompileUnit = struct {
22852308
2286const InArchive = struct {2309const InArchive = struct {
2287 path: []const u8,2310 path: []const u8,
2288 offset: u64,
2289 size: u32,2311 size: u32,
2290};2312};
22912313
...@@ -2300,11 +2322,10 @@ const x86_64 = struct {...@@ -2300,11 +2322,10 @@ const x86_64 = struct {
2300 const gpa = macho_file.base.comp.gpa;2322 const gpa = macho_file.base.comp.gpa;
23012323
2302 const handle = macho_file.getFileHandle(self.file_handle);2324 const handle = macho_file.getFileHandle(self.file_handle);
2303 const offset = if (self.archive) |ar| ar.offset else 0;
2304 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));2325 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
2305 defer gpa.free(relocs_buffer);2326 defer gpa.free(relocs_buffer);
2306 {2327 {
2307 const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset);2328 const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset);
2308 if (amt != relocs_buffer.len) return error.InputOutput;2329 if (amt != relocs_buffer.len) return error.InputOutput;
2309 }2330 }
2310 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];2331 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];
...@@ -2463,11 +2484,10 @@ const aarch64 = struct {...@@ -2463,11 +2484,10 @@ const aarch64 = struct {
2463 const gpa = macho_file.base.comp.gpa;2484 const gpa = macho_file.base.comp.gpa;
24642485
2465 const handle = macho_file.getFileHandle(self.file_handle);2486 const handle = macho_file.getFileHandle(self.file_handle);
2466 const offset = if (self.archive) |ar| ar.offset else 0;
2467 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));2487 const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info));
2468 defer gpa.free(relocs_buffer);2488 defer gpa.free(relocs_buffer);
2469 {2489 {
2470 const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset);2490 const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset);
2471 if (amt != relocs_buffer.len) return error.InputOutput;2491 if (amt != relocs_buffer.len) return error.InputOutput;
2472 }2492 }
2473 const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc];2493 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 @@...@@ -1,6 +1,6 @@
1/// List of all unwind records gathered from all objects and sorted1/// List of all unwind records gathered from all objects and sorted
2/// by allocated relative function address within the section.2/// by allocated relative function address within the section.
3records: std.ArrayListUnmanaged(Record.Index) = .{},3records: std.ArrayListUnmanaged(Record.Ref) = .{},
44
5/// List of all personalities referenced by either unwind info entries5/// List of all personalities referenced by either unwind info entries
6/// or __eh_frame entries.6/// or __eh_frame entries.
...@@ -25,10 +25,10 @@ pub fn deinit(info: *UnwindInfo, allocator: Allocator) void {...@@ -25,10 +25,10 @@ pub fn deinit(info: *UnwindInfo, allocator: Allocator) void {
25 info.lsdas_lookup.deinit(allocator);25 info.lsdas_lookup.deinit(allocator);
26}26}
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 {
29 const cpu_arch = macho_file.getTarget().cpu.arch;29 const cpu_arch = macho_file.getTarget().cpu.arch;
30 const lhs = macho_file.getUnwindRecord(lhs_index);30 const lhs = lhs_ref.getUnwindRecord(macho_file);
31 const rhs = macho_file.getUnwindRecord(rhs_index);31 const rhs = rhs_ref.getUnwindRecord(macho_file);
32 if (cpu_arch == .x86_64) {32 if (cpu_arch == .x86_64) {
33 if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or33 if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or
34 rhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND)) return false;34 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 {...@@ -52,17 +52,18 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
52 const atom = macho_file.getAtom(atom_index) orelse continue;52 const atom = macho_file.getAtom(atom_index) orelse continue;
53 if (!atom.flags.alive) continue;53 if (!atom.flags.alive) continue;
54 const recs = atom.getUnwindRecords(macho_file);54 const recs = atom.getUnwindRecords(macho_file);
55 const file = atom.getFile(macho_file);
55 try info.records.ensureUnusedCapacity(gpa, recs.len);56 try info.records.ensureUnusedCapacity(gpa, recs.len);
56 for (recs) |rec| {57 for (recs) |rec| {
57 if (!macho_file.getUnwindRecord(rec).alive) continue;58 if (!file.object.getUnwindRecord(rec).alive) continue;
58 info.records.appendAssumeCapacity(rec);59 info.records.appendAssumeCapacity(.{ .record = rec, .file = file.getIndex() });
59 }60 }
60 }61 }
61 }62 }
6263
63 // Encode records64 // Encode records
64 for (info.records.items) |index| {65 for (info.records.items) |ref| {
65 const rec = macho_file.getUnwindRecord(index);66 const rec = ref.getUnwindRecord(macho_file);
66 if (rec.getFde(macho_file)) |fde| {67 if (rec.getFde(macho_file)) |fde| {
67 rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset));68 rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset));
68 if (fde.getLsdaAtom(macho_file)) |lsda| {69 if (fde.getLsdaAtom(macho_file)) |lsda| {
...@@ -83,16 +84,16 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -83,16 +84,16 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
8384
84 // Sort by assigned relative address within each output section85 // Sort by assigned relative address within each output section
85 const sortFn = struct {86 const sortFn = struct {
86 fn sortFn(ctx: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool {87 fn sortFn(ctx: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool {
87 const lhs = ctx.getUnwindRecord(lhs_index);88 const lhs = lhs_ref.getUnwindRecord(ctx);
88 const rhs = ctx.getUnwindRecord(rhs_index);89 const rhs = rhs_ref.getUnwindRecord(ctx);
89 const lhsa = lhs.getAtom(ctx);90 const lhsa = lhs.getAtom(ctx);
90 const rhsa = rhs.getAtom(ctx);91 const rhsa = rhs.getAtom(ctx);
91 if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx);92 if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx);
92 return lhsa.out_n_sect < rhsa.out_n_sect;93 return lhsa.out_n_sect < rhsa.out_n_sect;
93 }94 }
94 }.sortFn;95 }.sortFn;
95 mem.sort(Record.Index, info.records.items, macho_file, sortFn);96 mem.sort(Record.Ref, info.records.items, macho_file, sortFn);
9697
97 // Fold the records98 // Fold the records
98 // Any adjacent two records that share encoding can be folded into one.99 // 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 {...@@ -101,8 +102,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
101 var j: usize = 1;102 var j: usize = 1;
102 while (j < info.records.items.len) : (j += 1) {103 while (j < info.records.items.len) : (j += 1) {
103 if (canFold(macho_file, info.records.items[i], info.records.items[j])) {104 if (canFold(macho_file, info.records.items[i], info.records.items[j])) {
104 const rec = macho_file.getUnwindRecord(info.records.items[i]);105 const rec = info.records.items[i].getUnwindRecord(macho_file);
105 rec.length += macho_file.getUnwindRecord(info.records.items[j]).length + 1;106 rec.length += info.records.items[j].getUnwindRecord(macho_file).length + 1;
106 } else {107 } else {
107 i += 1;108 i += 1;
108 info.records.items[i] = info.records.items[j];109 info.records.items[i] = info.records.items[j];
...@@ -111,14 +112,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -111,14 +112,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
111 info.records.shrinkAndFree(gpa, i + 1);112 info.records.shrinkAndFree(gpa, i + 1);
112 }113 }
113114
114 for (info.records.items) |rec_index| {115 for (info.records.items) |ref| {
115 const rec = macho_file.getUnwindRecord(rec_index);116 const rec = ref.getUnwindRecord(macho_file);
116 const atom = rec.getAtom(macho_file);117 const atom = rec.getAtom(macho_file);
117 log.debug("@{x}-{x} : {s} : rec({d}) : {}", .{118 log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{
118 rec.getAtomAddress(macho_file),119 rec.getAtomAddress(macho_file),
119 rec.getAtomAddress(macho_file) + rec.length,120 rec.getAtomAddress(macho_file) + rec.length,
120 atom.getName(macho_file),121 atom.getName(macho_file),
121 rec_index,122 ref.record,
123 ref.file,
122 rec.enc,124 rec.enc,
123 });125 });
124 }126 }
...@@ -161,8 +163,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -161,8 +163,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
161 ).init(gpa);163 ).init(gpa);
162 defer common_encodings_counts.deinit();164 defer common_encodings_counts.deinit();
163165
164 for (info.records.items) |rec_index| {166 for (info.records.items) |ref| {
165 const rec = macho_file.getUnwindRecord(rec_index);167 const rec = ref.getUnwindRecord(macho_file);
166 if (rec.enc.isDwarf(macho_file)) continue;168 if (rec.enc.isDwarf(macho_file)) continue;
167 const gop = try common_encodings_counts.getOrPut(rec.enc);169 const gop = try common_encodings_counts.getOrPut(rec.enc);
168 if (!gop.found_existing) {170 if (!gop.found_existing) {
...@@ -190,7 +192,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -190,7 +192,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
190 {192 {
191 var i: u32 = 0;193 var i: u32 = 0;
192 while (i < info.records.items.len) {194 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);
194 const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask;196 const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask;
195 var encoding_count: u9 = info.common_encodings_count;197 var encoding_count: u9 = info.common_encodings_count;
196 var space_left: u32 = second_level_page_words -198 var space_left: u32 = second_level_page_words -
...@@ -202,7 +204,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -202,7 +204,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
202 };204 };
203205
204 while (space_left >= 1 and i < info.records.items.len) {206 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);
206 const is_dwarf = next.enc.isDwarf(macho_file);208 const is_dwarf = next.enc.isDwarf(macho_file);
207209
208 if (next.getAtomAddress(macho_file) >= range_start_max) {210 if (next.getAtomAddress(macho_file) >= range_start_max) {
...@@ -244,8 +246,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {...@@ -244,8 +246,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void {
244 // Save records having an LSDA pointer246 // Save records having an LSDA pointer
245 log.debug("LSDA pointers:", .{});247 log.debug("LSDA pointers:", .{});
246 try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len);248 try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len);
247 for (info.records.items, 0..) |index, i| {249 for (info.records.items, 0..) |ref, i| {
248 const rec = macho_file.getUnwindRecord(index);250 const rec = ref.getUnwindRecord(macho_file);
249 info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len));251 info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len));
250 if (rec.getLsdaAtom(macho_file)) |lsda| {252 if (rec.getLsdaAtom(macho_file)) |lsda| {
251 log.debug(" @{x} => lsda({d})", .{ rec.getAtomAddress(macho_file), lsda.atom_index });253 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 {...@@ -301,7 +303,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
301 (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry))));303 (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry))));
302 for (info.pages.items, 0..) |page, i| {304 for (info.pages.items, 0..) |page, i| {
303 assert(page.count > 0);305 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);
305 try writer.writeStruct(macho.unwind_info_section_header_index_entry{307 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
306 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),308 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
307 .secondLevelPagesSectionOffset = @as(u32, @intCast(pages_base_offset + i * second_level_page_bytes)),309 .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 {...@@ -310,7 +312,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
310 });312 });
311 }313 }
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);
314 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));316 const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr));
315 try writer.writeStruct(macho.unwind_info_section_header_index_entry{317 try writer.writeStruct(macho.unwind_info_section_header_index_entry{
316 .functionOffset = sentinel_address,318 .functionOffset = sentinel_address,
...@@ -320,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {...@@ -320,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void {
320 });322 });
321323
322 for (info.lsdas.items) |index| {324 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);
324 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{326 try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{
325 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),327 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
326 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),328 .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)),
...@@ -537,6 +539,15 @@ pub const Record = struct {...@@ -537,6 +539,15 @@ pub const Record = struct {
537 }539 }
538540
539 pub const Index = u32;541 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 };
540};551};
541552
542const max_personalities = 3;553const max_personalities = 3;
...@@ -635,8 +646,8 @@ const Page = struct {...@@ -635,8 +646,8 @@ const Page = struct {
635 .entryCount = page.count,646 .entryCount = page.count,
636 });647 });
637648
638 for (info.records.items[page.start..][0..page.count]) |index| {649 for (info.records.items[page.start..][0..page.count]) |ref| {
639 const rec = macho_file.getUnwindRecord(index);650 const rec = ref.getUnwindRecord(macho_file);
640 try writer.writeStruct(macho.unwind_info_regular_second_level_entry{651 try writer.writeStruct(macho.unwind_info_regular_second_level_entry{
641 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),652 .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)),
642 .encoding = rec.enc.enc,653 .encoding = rec.enc.enc,
...@@ -658,9 +669,9 @@ const Page = struct {...@@ -658,9 +669,9 @@ const Page = struct {
658 }669 }
659670
660 assert(page.count > 0);671 assert(page.count > 0);
661 const first_rec = macho_file.getUnwindRecord(info.records.items[page.start]);672 const first_rec = info.records.items[page.start].getUnwindRecord(macho_file);
662 for (info.records.items[page.start..][0..page.count]) |index| {673 for (info.records.items[page.start..][0..page.count]) |ref| {
663 const rec = macho_file.getUnwindRecord(index);674 const rec = ref.getUnwindRecord(macho_file);
664 const enc_index = blk: {675 const enc_index = blk: {
665 if (info.getCommonEncoding(rec.enc)) |id| break :blk id;676 if (info.getCommonEncoding(rec.enc)) |id| break :blk id;
666 const ncommon = info.common_encodings_count;677 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...@@ -41,8 +41,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho
41 }41 }
4242
43 for (macho_file.objects.items) |index| {43 for (macho_file.objects.items) |index| {
44 for (macho_file.getFile(index).?.object.unwind_records.items) |cu_index| {44 const object = macho_file.getFile(index).?.object;
45 const cu = macho_file.getUnwindRecord(cu_index);45 for (object.unwind_records_indexes.items) |cu_index| {
46 const cu = object.getUnwindRecord(cu_index);
46 if (!cu.alive) continue;47 if (!cu.alive) continue;
47 if (cu.getFde(macho_file)) |fde| {48 if (cu.getFde(macho_file)) |fde| {
48 if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| try markSymbol(sym, roots, macho_file);49 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 {...@@ -127,8 +128,9 @@ fn markLive(atom: *Atom, macho_file: *MachO) void {
127 }128 }
128 }129 }
129130
131 const file = atom.getFile(macho_file);
130 for (atom.getUnwindRecords(macho_file)) |cu_index| {132 for (atom.getUnwindRecords(macho_file)) |cu_index| {
131 const cu = macho_file.getUnwindRecord(cu_index);133 const cu = file.object.getUnwindRecord(cu_index);
132 const cu_atom = cu.getAtom(macho_file);134 const cu_atom = cu.getAtom(macho_file);
133 if (markAtom(cu_atom)) markLive(cu_atom, macho_file);135 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 {...@@ -286,12 +286,15 @@ fn parseObject(macho_file: *MachO, path: []const u8) MachO.ParseError!void {
286 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));286 break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000)));
287 };287 };
288 const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa)));288 const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa)));
289 macho_file.files.set(index, .{ .object = .{289 macho_file.files.set(index, .{
290 .path = try gpa.dupe(u8, path),290 .object = .{
291 .file_handle = handle,291 .offset = 0, // TODO FAT objects
292 .mtime = mtime,292 .path = try gpa.dupe(u8, path),
293 .index = index,293 .file_handle = handle,
294 } });294 .mtime = mtime,
295 .index = index,
296 },
297 });
295 try macho_file.objects.append(gpa, index);298 try macho_file.objects.append(gpa, index);
296299
297 const object = macho_file.getFile(index).?.object;300 const object = macho_file.getFile(index).?.object;
...@@ -420,8 +423,8 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {...@@ -420,8 +423,8 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void {
420423
421 for (macho_file.objects.items) |index| {424 for (macho_file.objects.items) |index| {
422 const object = macho_file.getFile(index).?.object;425 const object = macho_file.getFile(index).?.object;
423 for (object.unwind_records.items) |irec| {426 for (object.unwind_records_indexes.items) |irec| {
424 const rec = macho_file.getUnwindRecord(irec);427 const rec = object.getUnwindRecord(irec);
425 if (!rec.alive) continue;428 if (!rec.alive) continue;
426 size += @sizeOf(macho.compact_unwind_entry);429 size += @sizeOf(macho.compact_unwind_entry);
427 nreloc += 1;430 nreloc += 1;
...@@ -670,8 +673,8 @@ fn writeCompactUnwind(macho_file: *MachO) !void {...@@ -670,8 +673,8 @@ fn writeCompactUnwind(macho_file: *MachO) !void {
670 var offset: i32 = 0;673 var offset: i32 = 0;
671 for (macho_file.objects.items) |index| {674 for (macho_file.objects.items) |index| {
672 const object = macho_file.getFile(index).?.object;675 const object = macho_file.getFile(index).?.object;
673 for (object.unwind_records.items) |irec| {676 for (object.unwind_records_indexes.items) |irec| {
674 const rec = macho_file.getUnwindRecord(irec);677 const rec = object.getUnwindRecord(irec);
675 if (!rec.alive) continue;678 if (!rec.alive) continue;
676679
677 var out: macho.compact_unwind_entry = .{680 var out: macho.compact_unwind_entry = .{