diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-07-04 17:49:35 +0200 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-07-18 09:13:07 +0200 |
| commit | 101299e85625faf29b4afce07ad1e3522ea75421 (patch) | |
| tree | 365fb3864b1e6a35ff99ba4b81b22ed0963773f9 /src/link | |
| parent | a57479afc2cea1b7c2c6802b7e8a1a7db973a3a3 (diff) | |
| download | zig-101299e85625faf29b4afce07ad1e3522ea75421.tar.gz zig-101299e85625faf29b4afce07ad1e3522ea75421.zip | |
macho: move unwind info records ownership to Objects
Diffstat (limited to 'src/link')
| -rw-r--r-- | src/link/MachO.zig | 29 | ||||
| -rw-r--r-- | src/link/MachO/Archive.zig | 4 | ||||
| -rw-r--r-- | src/link/MachO/Atom.zig | 11 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 168 | ||||
| -rw-r--r-- | src/link/MachO/UnwindInfo.zig | 75 | ||||
| -rw-r--r-- | src/link/MachO/dead_strip.zig | 8 | ||||
| -rw-r--r-- | src/link/MachO/relocatable.zig | 23 |
7 files changed, 173 insertions, 145 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index ff083d367c..ed1a78c2ae 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -67,7 +67,6 @@ entry_index: ?Symbol.Index = null, atoms: std.ArrayListUnmanaged(Atom) = .{}, atoms_extra: std.ArrayListUnmanaged(u32) = .{}, thunks: std.ArrayListUnmanaged(Thunk) = .{}, -unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, /// String interning table strings: StringTable = .{}, @@ -357,7 +356,6 @@ pub fn deinit(self: *MachO) void { thunk.deinit(gpa); } self.thunks.deinit(gpa); - self.unwind_records.deinit(gpa); } pub 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 { break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); }; const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); - self.files.set(index, .{ .object = .{ - .path = try gpa.dupe(u8, path), - .file_handle = handle, - .mtime = mtime, - .index = index, - } }); + self.files.set(index, .{ + .object = .{ + .offset = 0, // TODO FAT objects + .path = try gpa.dupe(u8, path), + .file_handle = handle, + .mtime = mtime, + .index = index, + }, + }); try self.objects.append(gpa, index); const object = self.getFile(index).?.object; @@ -4058,18 +4059,6 @@ pub fn getGlobalByName(self: *MachO, name: []const u8) ?Symbol.Index { return self.globals.get(off); } -pub fn addUnwindRecord(self: *MachO) !UnwindInfo.Record.Index { - const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len)); - const rec = try self.unwind_records.addOne(self.base.comp.gpa); - rec.* = .{}; - return index; -} - -pub fn getUnwindRecord(self: *MachO, index: UnwindInfo.Record.Index) *UnwindInfo.Record { - assert(index < self.unwind_records.items.len); - return &self.unwind_records.items[index]; -} - pub fn addThunk(self: *MachO) !Thunk.Index { const index = @as(Thunk.Index, @intCast(self.thunks.items.len)); const thunk = try self.thunks.addOne(self.base.comp.gpa); diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index c1ce582036..c478a9bef7 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -67,9 +67,9 @@ pub fn parse(self: *Archive, macho_file: *MachO, path: []const u8, handle_index: mem.eql(u8, name, SYMDEF64_SORTED)) continue; const object = Object{ - .archive = .{ + .offset = pos, + .in_archive = .{ .path = try gpa.dupe(u8, path), - .offset = pos, .size = hdr_size, }, .path = try gpa.dupe(u8, name), diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index 1a315330e3..c0a53da7e4 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -91,14 +91,16 @@ pub fn getUnwindRecords(self: Atom, macho_file: *MachO) []const UnwindInfo.Recor if (!self.flags.unwind) return &[0]UnwindInfo.Record.Index{}; const extra = self.getExtra(macho_file).?; return switch (self.getFile(macho_file)) { - .dylib, .zig_object, .internal => unreachable, - .object => |x| x.unwind_records.items[extra.unwind_index..][0..extra.unwind_count], + .dylib => unreachable, + .zig_object, .internal => &[0]UnwindInfo.Record.Index{}, + .object => |x| x.unwind_records_indexes.items[extra.unwind_index..][0..extra.unwind_count], }; } pub fn markUnwindRecordsDead(self: Atom, macho_file: *MachO) void { + const object = self.getFile(macho_file).object; for (self.getUnwindRecords(macho_file)) |cu_index| { - const cu = macho_file.getUnwindRecord(cu_index); + const cu = object.getUnwindRecord(cu_index); cu.alive = false; if (cu.getFdePtr(macho_file)) |fde| { @@ -1170,6 +1172,7 @@ fn format2( _ = unused_fmt_string; const atom = ctx.atom; const macho_file = ctx.macho_file; + const file = atom.getFile(macho_file); try writer.print("atom({d}) : {s} : @{x} : sect({d}) : align({x}) : size({x}) : nreloc({d})", .{ atom.atom_index, atom.getName(macho_file), atom.getAddress(macho_file), atom.out_n_sect, atom.alignment, atom.size, @@ -1181,7 +1184,7 @@ fn format2( try writer.writeAll(" : unwind{ "); const extra = atom.getExtra(macho_file).?; for (atom.getUnwindRecords(macho_file), extra.unwind_index..) |index, i| { - const rec = macho_file.getUnwindRecord(index); + const rec = file.object.getUnwindRecord(index); try writer.print("{d}", .{index}); if (!rec.alive) try writer.writeAll("([*])"); if (i < extra.unwind_index + extra.unwind_count - 1) try writer.writeAll(", "); diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index c856c65d4e..8ecd88b413 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -1,8 +1,10 @@ -archive: ?InArchive = null, +/// Non-zero for fat object files or archives +offset: u64, path: []const u8, file_handle: File.HandleIndex, mtime: u64, index: File.Index, +in_archive: ?InArchive = null, header: ?macho.mach_header_64 = null, sections: std.MultiArrayList(Section) = .{}, @@ -21,7 +23,8 @@ compact_unwind_sect_index: ?u8 = null, cies: std.ArrayListUnmanaged(Cie) = .{}, fdes: std.ArrayListUnmanaged(Fde) = .{}, eh_frame_data: std.ArrayListUnmanaged(u8) = .{}, -unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, +unwind_records: std.ArrayListUnmanaged(UnwindInfo.Record) = .{}, +unwind_records_indexes: std.ArrayListUnmanaged(UnwindInfo.Record.Index) = .{}, data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{}, alive: bool = true, @@ -39,7 +42,7 @@ pub fn isObject(path: []const u8) !bool { } pub fn deinit(self: *Object, allocator: Allocator) void { - if (self.archive) |*ar| allocator.free(ar.path); + if (self.in_archive) |*ar| allocator.free(ar.path); allocator.free(self.path); for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { relocs.deinit(allocator); @@ -54,6 +57,7 @@ pub fn deinit(self: *Object, allocator: Allocator) void { self.fdes.deinit(allocator); self.eh_frame_data.deinit(allocator); self.unwind_records.deinit(allocator); + self.unwind_records_indexes.deinit(allocator); for (self.stab_files.items) |*sf| { sf.stabs.deinit(allocator); } @@ -66,12 +70,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { defer tracy.end(); const gpa = macho_file.base.comp.gpa; - const offset = if (self.archive) |ar| ar.offset else 0; const handle = macho_file.getFileHandle(self.file_handle); var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; { - const amt = try handle.preadAll(&header_buffer, offset); + const amt = try handle.preadAll(&header_buffer, self.offset); if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; } 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 { const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); defer gpa.free(lc_buffer); { - const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); + const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); if (amt != self.header.?.sizeofcmds) return error.InputOutput; } @@ -119,14 +122,14 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { const cmd = lc.cast(macho.symtab_command).?; try self.strtab.resize(gpa, cmd.strsize); { - const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset); + const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); if (amt != self.strtab.items.len) return error.InputOutput; } const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); defer gpa.free(symtab_buffer); { - const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset); + const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); if (amt != symtab_buffer.len) return error.InputOutput; } 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 { const buffer = try gpa.alloc(u8, cmd.datasize); defer gpa.free(buffer); { - const amt = try handle.preadAll(buffer, offset + cmd.dataoff); + const amt = try handle.preadAll(buffer, self.offset + cmd.dataoff); if (amt != buffer.len) return error.InputOutput; } const ndice = @divExact(cmd.datasize, @sizeOf(macho.data_in_code_entry)); @@ -218,11 +221,11 @@ pub fn parse(self: *Object, macho_file: *MachO) !void { // Parse Apple's __LD,__compact_unwind section if (self.compact_unwind_sect_index) |index| { - try self.initUnwindRecords(index, macho_file); + try self.initUnwindRecords(gpa, index, handle, macho_file); } if (self.hasUnwindRecords() or self.hasEhFrameRecords()) { - try self.parseUnwindRecords(macho_file); + try self.parseUnwindRecords(gpa, macho_file.getTarget().cpu.arch, macho_file); } if (self.platform) |platform| { @@ -987,7 +990,7 @@ fn initEhFrameRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { } } -fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { +fn initUnwindRecords(self: *Object, allocator: Allocator, sect_id: u8, file: File.Handle, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1003,19 +1006,22 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { } }; - const gpa = macho_file.base.comp.gpa; - const data = try self.getSectionData(sect_id, macho_file); - defer gpa.free(data); + const header = self.sections.items(.header)[sect_id]; + const data = try allocator.alloc(u8, header.size); + defer allocator.free(data); + const amt = try file.preadAll(data, header.offset + self.offset); + if (amt != data.len) return error.InputOutput; + const nrecs = @divExact(data.len, @sizeOf(macho.compact_unwind_entry)); const recs = @as([*]align(1) const macho.compact_unwind_entry, @ptrCast(data.ptr))[0..nrecs]; const sym_lookup = SymbolLookup{ .ctx = self }; - try self.unwind_records.resize(gpa, nrecs); + try self.unwind_records.ensureTotalCapacityPrecise(allocator, nrecs); + try self.unwind_records_indexes.ensureTotalCapacityPrecise(allocator, nrecs); - const header = self.sections.items(.header)[sect_id]; const relocs = self.sections.items(.relocs)[sect_id].items; var reloc_idx: usize = 0; - for (recs, self.unwind_records.items, 0..) |rec, *out_index, rec_idx| { + for (recs, 0..) |rec, rec_idx| { const rec_start = rec_idx * @sizeOf(macho.compact_unwind_entry); const rec_end = rec_start + @sizeOf(macho.compact_unwind_entry); const reloc_start = reloc_idx; @@ -1023,11 +1029,11 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { relocs[reloc_idx].offset < rec_end) : (reloc_idx += 1) {} - out_index.* = try macho_file.addUnwindRecord(); - const out = macho_file.getUnwindRecord(out_index.*); + const out_index = self.addUnwindRecordAssumeCapacity(); + self.unwind_records_indexes.appendAssumeCapacity(out_index); + const out = self.getUnwindRecord(out_index); out.length = rec.rangeLength; out.enc = .{ .enc = rec.compactUnwindEncoding }; - out.file = self.index; for (relocs[reloc_start..reloc_idx]) |rel| { if (rel.type != .unsigned or rel.meta.length != 3) { @@ -1090,7 +1096,7 @@ fn initUnwindRecords(self: *Object, sect_id: u8, macho_file: *MachO) !void { } } -fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { +fn parseUnwindRecords(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch, macho_file: *MachO) !void { // Synthesise missing unwind records. // The logic here is as follows: // 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 { const Superposition = struct { atom: Atom.Index, size: u64, cu: ?UnwindInfo.Record.Index = null, fde: ?Fde.Index = null }; - const gpa = macho_file.base.comp.gpa; - var superposition = std.AutoArrayHashMap(u64, Superposition).init(gpa); + var superposition = std.AutoArrayHashMap(u64, Superposition).init(allocator); defer superposition.deinit(); const slice = self.symtab.slice(); @@ -1119,8 +1124,8 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { } } - for (self.unwind_records.items) |rec_index| { - const rec = macho_file.getUnwindRecord(rec_index); + for (self.unwind_records_indexes.items) |rec_index| { + const rec = self.getUnwindRecord(rec_index); const atom = rec.getAtom(macho_file); const addr = atom.getInputAddress(macho_file) + rec.atom_offset; superposition.getPtr(addr).?.cu = rec_index; @@ -1137,7 +1142,7 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { const fde = &self.fdes.items[fde_index]; if (meta.cu) |rec_index| { - const rec = macho_file.getUnwindRecord(rec_index); + const rec = self.getUnwindRecord(rec_index); if (!rec.enc.isDwarf(macho_file)) { // Mark FDE dead fde.alive = false; @@ -1147,15 +1152,14 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { } } else { // Synthesise new unwind info record - const rec_index = try macho_file.addUnwindRecord(); - const rec = macho_file.getUnwindRecord(rec_index); - try self.unwind_records.append(gpa, rec_index); + const rec_index = try self.addUnwindRecord(allocator); + const rec = self.getUnwindRecord(rec_index); + try self.unwind_records_indexes.append(allocator, rec_index); rec.length = @intCast(meta.size); rec.atom = fde.atom; rec.atom_offset = fde.atom_offset; rec.fde = fde_index; - rec.file = fde.file; - switch (macho_file.getTarget().cpu.arch) { + switch (cpu_arch) { .x86_64 => rec.enc.setMode(macho.UNWIND_X86_64_MODE.DWARF), .aarch64 => rec.enc.setMode(macho.UNWIND_ARM64_MODE.DWARF), else => unreachable, @@ -1163,10 +1167,10 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { } } else if (meta.cu == null and meta.fde == null) { // Create a null record - const rec_index = try macho_file.addUnwindRecord(); - const rec = macho_file.getUnwindRecord(rec_index); + const rec_index = try self.addUnwindRecord(allocator); + const rec = self.getUnwindRecord(rec_index); const atom = macho_file.getAtom(meta.atom).?; - try self.unwind_records.append(gpa, rec_index); + try self.unwind_records_indexes.append(allocator, rec_index); rec.length = @intCast(meta.size); rec.atom = meta.atom; rec.atom_offset = @intCast(addr - atom.getInputAddress(macho_file)); @@ -1174,25 +1178,31 @@ fn parseUnwindRecords(self: *Object, macho_file: *MachO) !void { } } - const sortFn = struct { - fn sortFn(ctx: *MachO, lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { - const lhs = ctx.getUnwindRecord(lhs_index); - const rhs = ctx.getUnwindRecord(rhs_index); - const lhsa = lhs.getAtom(ctx); - const rhsa = rhs.getAtom(ctx); - return lhsa.getInputAddress(ctx) + lhs.atom_offset < rhsa.getInputAddress(ctx) + rhs.atom_offset; + const SortCtx = struct { + object: *Object, + mfile: *MachO, + + fn sort(ctx: @This(), lhs_index: UnwindInfo.Record.Index, rhs_index: UnwindInfo.Record.Index) bool { + const lhs = ctx.object.getUnwindRecord(lhs_index); + const rhs = ctx.object.getUnwindRecord(rhs_index); + const lhsa = lhs.getAtom(ctx.mfile); + const rhsa = rhs.getAtom(ctx.mfile); + return lhsa.getInputAddress(ctx.mfile) + lhs.atom_offset < rhsa.getInputAddress(ctx.mfile) + rhs.atom_offset; } - }.sortFn; - mem.sort(UnwindInfo.Record.Index, self.unwind_records.items, macho_file, sortFn); + }; + mem.sort(UnwindInfo.Record.Index, self.unwind_records_indexes.items, SortCtx{ + .object = self, + .mfile = macho_file, + }, SortCtx.sort); // Associate unwind records to atoms var next_cu: u32 = 0; - while (next_cu < self.unwind_records.items.len) { + while (next_cu < self.unwind_records_indexes.items.len) { const start = next_cu; - const rec_index = self.unwind_records.items[start]; - const rec = macho_file.getUnwindRecord(rec_index); - while (next_cu < self.unwind_records.items.len and - macho_file.getUnwindRecord(self.unwind_records.items[next_cu]).atom == rec.atom) : (next_cu += 1) + const rec_index = self.unwind_records_indexes.items[start]; + const rec = self.getUnwindRecord(rec_index); + while (next_cu < self.unwind_records_indexes.items.len and + self.getUnwindRecord(self.unwind_records_indexes.items[next_cu]).atom == rec.atom) : (next_cu += 1) {} const atom = rec.getAtom(macho_file); @@ -1441,7 +1451,7 @@ pub fn checkDuplicates(self: *Object, dupes: anytype, macho_file: *MachO) error{ } } -pub fn scanRelocs(self: Object, macho_file: *MachO) !void { +pub fn scanRelocs(self: *Object, macho_file: *MachO) !void { const tracy = trace(@src()); defer tracy.end(); @@ -1453,8 +1463,8 @@ pub fn scanRelocs(self: Object, macho_file: *MachO) !void { try atom.scanRelocs(macho_file); } - for (self.unwind_records.items) |rec_index| { - const rec = macho_file.getUnwindRecord(rec_index); + for (self.unwind_records_indexes.items) |rec_index| { + const rec = self.getUnwindRecord(rec_index); if (!rec.alive) continue; if (rec.getFde(macho_file)) |fde| { if (fde.getCie(macho_file).getPersonality(macho_file)) |sym| { @@ -1532,12 +1542,11 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { defer tracy.end(); const gpa = macho_file.base.comp.gpa; - const offset = if (self.archive) |ar| ar.offset else 0; const handle = macho_file.getFileHandle(self.file_handle); var header_buffer: [@sizeOf(macho.mach_header_64)]u8 = undefined; { - const amt = try handle.preadAll(&header_buffer, offset); + const amt = try handle.preadAll(&header_buffer, self.offset); if (amt != @sizeOf(macho.mach_header_64)) return error.InputOutput; } 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 { const lc_buffer = try gpa.alloc(u8, self.header.?.sizeofcmds); defer gpa.free(lc_buffer); { - const amt = try handle.preadAll(lc_buffer, offset + @sizeOf(macho.mach_header_64)); + const amt = try handle.preadAll(lc_buffer, self.offset + @sizeOf(macho.mach_header_64)); if (amt != self.header.?.sizeofcmds) return error.InputOutput; } @@ -1571,14 +1580,14 @@ pub fn parseAr(self: *Object, macho_file: *MachO) !void { const cmd = lc.cast(macho.symtab_command).?; try self.strtab.resize(gpa, cmd.strsize); { - const amt = try handle.preadAll(self.strtab.items, cmd.stroff + offset); + const amt = try handle.preadAll(self.strtab.items, cmd.stroff + self.offset); if (amt != self.strtab.items.len) return error.InputOutput; } const symtab_buffer = try gpa.alloc(u8, cmd.nsyms * @sizeOf(macho.nlist_64)); defer gpa.free(symtab_buffer); { - const amt = try handle.preadAll(symtab_buffer, cmd.symoff + offset); + const amt = try handle.preadAll(symtab_buffer, cmd.symoff + self.offset); if (amt != symtab_buffer.len) return error.InputOutput; } 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 } pub fn updateArSize(self: *Object, macho_file: *MachO) !void { - self.output_ar_state.size = if (self.archive) |ar| ar.size else size: { + self.output_ar_state.size = if (self.in_archive) |ar| ar.size else size: { const file = macho_file.getFileHandle(self.file_handle); break :size (try file.stat()).size; }; @@ -1622,7 +1631,6 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { // Header const size = std.math.cast(usize, self.output_ar_state.size) orelse return error.Overflow; - const offset: u64 = if (self.archive) |ar| ar.offset else 0; try Archive.writeHeader(self.path, size, ar_format, writer); // Data 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 const gpa = macho_file.base.comp.gpa; const data = try gpa.alloc(u8, size); defer gpa.free(data); - const amt = try file.preadAll(data, offset); + const amt = try file.preadAll(data, self.offset); if (amt != size) return error.InputOutput; try writer.writeAll(data); } @@ -1680,7 +1688,7 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) error{Overflow}!void { self.output_symtab_ctx.strsize += @as(u32, @intCast(comp_dir.len + 1)); // comp_dir self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name - if (self.archive) |ar| { + if (self.in_archive) |ar| { self.output_symtab_ctx.strsize += @as(u32, @intCast(ar.path.len + 1 + self.path.len + 1 + 1)); } else { 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 index += 1; // N_OSO path n_strx = @as(u32, @intCast(ctx.strtab.items.len)); - if (self.archive) |ar| { + if (self.in_archive) |ar| { ctx.strtab.appendSliceAssumeCapacity(ar.path); ctx.strtab.appendAssumeCapacity('('); ctx.strtab.appendSliceAssumeCapacity(self.path); @@ -1989,11 +1997,10 @@ fn getSectionData(self: *const Object, index: u32, macho_file: *MachO) ![]u8 { assert(index < slice.items(.header).len); const sect = slice.items(.header)[index]; const handle = macho_file.getFileHandle(self.file_handle); - const offset = if (self.archive) |ar| ar.offset else 0; const size = math.cast(usize, sect.size) orelse return error.Overflow; const buffer = try gpa.alloc(u8, size); errdefer gpa.free(buffer); - const amt = try handle.preadAll(buffer, sect.offset + offset); + const amt = try handle.preadAll(buffer, sect.offset + self.offset); if (amt != buffer.len) return error.InputOutput; return buffer; } @@ -2002,9 +2009,8 @@ pub fn getAtomData(self: *const Object, macho_file: *MachO, atom: Atom, buffer: assert(buffer.len == atom.size); const slice = self.sections.slice(); const handle = macho_file.getFileHandle(self.file_handle); - const offset = if (self.archive) |ar| ar.offset else 0; const sect = slice.items(.header)[atom.n_sect]; - const amt = try handle.preadAll(buffer, sect.offset + offset + atom.off); + const amt = try handle.preadAll(buffer, sect.offset + self.offset + atom.off); if (amt != buffer.len) return error.InputOutput; } @@ -2068,6 +2074,23 @@ pub fn asFile(self: *Object) File { return .{ .object = self }; } +fn addUnwindRecord(self: *Object, allocator: Allocator) !UnwindInfo.Record.Index { + try self.unwind_records.ensureUnusedCapacity(allocator, 1); + return self.addUnwindRecordAssumeCapacity(); +} + +fn addUnwindRecordAssumeCapacity(self: *Object) UnwindInfo.Record.Index { + const index = @as(UnwindInfo.Record.Index, @intCast(self.unwind_records.items.len)); + const rec = self.unwind_records.addOneAssumeCapacity(); + rec.* = .{ .file = self.index }; + return index; +} + +pub fn getUnwindRecord(self: *Object, index: UnwindInfo.Record.Index) *UnwindInfo.Record { + assert(index < self.unwind_records.items.len); + return &self.unwind_records.items[index]; +} + pub fn format( self: *Object, comptime unused_fmt_string: []const u8, @@ -2171,8 +2194,8 @@ fn formatUnwindRecords( const object = ctx.object; const macho_file = ctx.macho_file; try writer.writeAll(" unwind records\n"); - for (object.unwind_records.items) |rec| { - try writer.print(" rec({d}) : {}\n", .{ rec, macho_file.getUnwindRecord(rec).fmt(macho_file) }); + for (object.unwind_records_indexes.items) |rec| { + try writer.print(" rec({d}) : {}\n", .{ rec, object.getUnwindRecord(rec).fmt(macho_file) }); } } @@ -2211,7 +2234,7 @@ fn formatPath( ) !void { _ = unused_fmt_string; _ = options; - if (object.archive) |ar| { + if (object.in_archive) |ar| { try writer.writeAll(ar.path); try writer.writeByte('('); try writer.writeAll(object.path); @@ -2285,7 +2308,6 @@ const CompileUnit = struct { const InArchive = struct { path: []const u8, - offset: u64, size: u32, }; @@ -2300,11 +2322,10 @@ const x86_64 = struct { const gpa = macho_file.base.comp.gpa; const handle = macho_file.getFileHandle(self.file_handle); - const offset = if (self.archive) |ar| ar.offset else 0; const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); defer gpa.free(relocs_buffer); { - const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset); + const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); if (amt != relocs_buffer.len) return error.InputOutput; } const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; @@ -2463,11 +2484,10 @@ const aarch64 = struct { const gpa = macho_file.base.comp.gpa; const handle = macho_file.getFileHandle(self.file_handle); - const offset = if (self.archive) |ar| ar.offset else 0; const relocs_buffer = try gpa.alloc(u8, sect.nreloc * @sizeOf(macho.relocation_info)); defer gpa.free(relocs_buffer); { - const amt = try handle.preadAll(relocs_buffer, sect.reloff + offset); + const amt = try handle.preadAll(relocs_buffer, sect.reloff + self.offset); if (amt != relocs_buffer.len) return error.InputOutput; } const relocs = @as([*]align(1) const macho.relocation_info, @ptrCast(relocs_buffer.ptr))[0..sect.nreloc]; diff --git a/src/link/MachO/UnwindInfo.zig b/src/link/MachO/UnwindInfo.zig index 44bb9bfab1..252333d5bb 100644 --- a/src/link/MachO/UnwindInfo.zig +++ b/src/link/MachO/UnwindInfo.zig @@ -1,6 +1,6 @@ /// List of all unwind records gathered from all objects and sorted /// by allocated relative function address within the section. -records: std.ArrayListUnmanaged(Record.Index) = .{}, +records: std.ArrayListUnmanaged(Record.Ref) = .{}, /// List of all personalities referenced by either unwind info entries /// or __eh_frame entries. @@ -25,10 +25,10 @@ pub fn deinit(info: *UnwindInfo, allocator: Allocator) void { info.lsdas_lookup.deinit(allocator); } -fn canFold(macho_file: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool { +fn canFold(macho_file: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool { const cpu_arch = macho_file.getTarget().cpu.arch; - const lhs = macho_file.getUnwindRecord(lhs_index); - const rhs = macho_file.getUnwindRecord(rhs_index); + const lhs = lhs_ref.getUnwindRecord(macho_file); + const rhs = rhs_ref.getUnwindRecord(macho_file); if (cpu_arch == .x86_64) { if (lhs.enc.getMode() == @intFromEnum(macho.UNWIND_X86_64_MODE.STACK_IND) or 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 { const atom = macho_file.getAtom(atom_index) orelse continue; if (!atom.flags.alive) continue; const recs = atom.getUnwindRecords(macho_file); + const file = atom.getFile(macho_file); try info.records.ensureUnusedCapacity(gpa, recs.len); for (recs) |rec| { - if (!macho_file.getUnwindRecord(rec).alive) continue; - info.records.appendAssumeCapacity(rec); + if (!file.object.getUnwindRecord(rec).alive) continue; + info.records.appendAssumeCapacity(.{ .record = rec, .file = file.getIndex() }); } } } // Encode records - for (info.records.items) |index| { - const rec = macho_file.getUnwindRecord(index); + for (info.records.items) |ref| { + const rec = ref.getUnwindRecord(macho_file); if (rec.getFde(macho_file)) |fde| { rec.enc.setDwarfSectionOffset(@intCast(fde.out_offset)); if (fde.getLsdaAtom(macho_file)) |lsda| { @@ -83,16 +84,16 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { // Sort by assigned relative address within each output section const sortFn = struct { - fn sortFn(ctx: *MachO, lhs_index: Record.Index, rhs_index: Record.Index) bool { - const lhs = ctx.getUnwindRecord(lhs_index); - const rhs = ctx.getUnwindRecord(rhs_index); + fn sortFn(ctx: *MachO, lhs_ref: Record.Ref, rhs_ref: Record.Ref) bool { + const lhs = lhs_ref.getUnwindRecord(ctx); + const rhs = rhs_ref.getUnwindRecord(ctx); const lhsa = lhs.getAtom(ctx); const rhsa = rhs.getAtom(ctx); if (lhsa.out_n_sect == rhsa.out_n_sect) return lhs.getAtomAddress(ctx) < rhs.getAtomAddress(ctx); return lhsa.out_n_sect < rhsa.out_n_sect; } }.sortFn; - mem.sort(Record.Index, info.records.items, macho_file, sortFn); + mem.sort(Record.Ref, info.records.items, macho_file, sortFn); // Fold the records // 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 { var j: usize = 1; while (j < info.records.items.len) : (j += 1) { if (canFold(macho_file, info.records.items[i], info.records.items[j])) { - const rec = macho_file.getUnwindRecord(info.records.items[i]); - rec.length += macho_file.getUnwindRecord(info.records.items[j]).length + 1; + const rec = info.records.items[i].getUnwindRecord(macho_file); + rec.length += info.records.items[j].getUnwindRecord(macho_file).length + 1; } else { i += 1; info.records.items[i] = info.records.items[j]; @@ -111,14 +112,15 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { info.records.shrinkAndFree(gpa, i + 1); } - for (info.records.items) |rec_index| { - const rec = macho_file.getUnwindRecord(rec_index); + for (info.records.items) |ref| { + const rec = ref.getUnwindRecord(macho_file); const atom = rec.getAtom(macho_file); - log.debug("@{x}-{x} : {s} : rec({d}) : {}", .{ + log.debug("@{x}-{x} : {s} : rec({d}) : object({d}) : {}", .{ rec.getAtomAddress(macho_file), rec.getAtomAddress(macho_file) + rec.length, atom.getName(macho_file), - rec_index, + ref.record, + ref.file, rec.enc, }); } @@ -161,8 +163,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { ).init(gpa); defer common_encodings_counts.deinit(); - for (info.records.items) |rec_index| { - const rec = macho_file.getUnwindRecord(rec_index); + for (info.records.items) |ref| { + const rec = ref.getUnwindRecord(macho_file); if (rec.enc.isDwarf(macho_file)) continue; const gop = try common_encodings_counts.getOrPut(rec.enc); if (!gop.found_existing) { @@ -190,7 +192,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { { var i: u32 = 0; while (i < info.records.items.len) { - const rec = macho_file.getUnwindRecord(info.records.items[i]); + const rec = info.records.items[i].getUnwindRecord(macho_file); const range_start_max: u64 = rec.getAtomAddress(macho_file) + compressed_entry_func_offset_mask; var encoding_count: u9 = info.common_encodings_count; var space_left: u32 = second_level_page_words - @@ -202,7 +204,7 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { }; while (space_left >= 1 and i < info.records.items.len) { - const next = macho_file.getUnwindRecord(info.records.items[i]); + const next = info.records.items[i].getUnwindRecord(macho_file); const is_dwarf = next.enc.isDwarf(macho_file); if (next.getAtomAddress(macho_file) >= range_start_max) { @@ -244,8 +246,8 @@ pub fn generate(info: *UnwindInfo, macho_file: *MachO) !void { // Save records having an LSDA pointer log.debug("LSDA pointers:", .{}); try info.lsdas_lookup.ensureTotalCapacityPrecise(gpa, info.records.items.len); - for (info.records.items, 0..) |index, i| { - const rec = macho_file.getUnwindRecord(index); + for (info.records.items, 0..) |ref, i| { + const rec = ref.getUnwindRecord(macho_file); info.lsdas_lookup.appendAssumeCapacity(@intCast(info.lsdas.items.len)); if (rec.getLsdaAtom(macho_file)) |lsda| { 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 { (info.lsdas.items.len * @sizeOf(macho.unwind_info_section_header_lsda_index_entry)))); for (info.pages.items, 0..) |page, i| { assert(page.count > 0); - const rec = macho_file.getUnwindRecord(info.records.items[page.start]); + const rec = info.records.items[page.start].getUnwindRecord(macho_file); try writer.writeStruct(macho.unwind_info_section_header_index_entry{ .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), .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 { }); } - const last_rec = macho_file.getUnwindRecord(info.records.items[info.records.items.len - 1]); + const last_rec = info.records.items[info.records.items.len - 1].getUnwindRecord(macho_file); const sentinel_address = @as(u32, @intCast(last_rec.getAtomAddress(macho_file) + last_rec.length - seg.vmaddr)); try writer.writeStruct(macho.unwind_info_section_header_index_entry{ .functionOffset = sentinel_address, @@ -320,7 +322,7 @@ pub fn write(info: UnwindInfo, macho_file: *MachO, buffer: []u8) !void { }); for (info.lsdas.items) |index| { - const rec = macho_file.getUnwindRecord(info.records.items[index]); + const rec = info.records.items[index].getUnwindRecord(macho_file); try writer.writeStruct(macho.unwind_info_section_header_lsda_index_entry{ .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), .lsdaOffset = @as(u32, @intCast(rec.getLsdaAddress(macho_file) - seg.vmaddr)), @@ -537,6 +539,15 @@ pub const Record = struct { } pub const Index = u32; + + const Ref = struct { + record: Index, + file: File.Index, + + pub fn getUnwindRecord(ref: Ref, macho_file: *MachO) *Record { + return macho_file.getFile(ref.file).?.object.getUnwindRecord(ref.record); + } + }; }; const max_personalities = 3; @@ -635,8 +646,8 @@ const Page = struct { .entryCount = page.count, }); - for (info.records.items[page.start..][0..page.count]) |index| { - const rec = macho_file.getUnwindRecord(index); + for (info.records.items[page.start..][0..page.count]) |ref| { + const rec = ref.getUnwindRecord(macho_file); try writer.writeStruct(macho.unwind_info_regular_second_level_entry{ .functionOffset = @as(u32, @intCast(rec.getAtomAddress(macho_file) - seg.vmaddr)), .encoding = rec.enc.enc, @@ -658,9 +669,9 @@ const Page = struct { } assert(page.count > 0); - const first_rec = macho_file.getUnwindRecord(info.records.items[page.start]); - for (info.records.items[page.start..][0..page.count]) |index| { - const rec = macho_file.getUnwindRecord(index); + const first_rec = info.records.items[page.start].getUnwindRecord(macho_file); + for (info.records.items[page.start..][0..page.count]) |ref| { + const rec = ref.getUnwindRecord(macho_file); const enc_index = blk: { if (info.getCommonEncoding(rec.enc)) |id| break :blk id; const ncommon = info.common_encodings_count; diff --git a/src/link/MachO/dead_strip.zig b/src/link/MachO/dead_strip.zig index e91682ca58..84e56c9249 100644 --- a/src/link/MachO/dead_strip.zig +++ b/src/link/MachO/dead_strip.zig @@ -41,8 +41,9 @@ fn collectRoots(roots: *std.ArrayList(*Atom), objects: []const File.Index, macho } for (macho_file.objects.items) |index| { - for (macho_file.getFile(index).?.object.unwind_records.items) |cu_index| { - const cu = macho_file.getUnwindRecord(cu_index); + const object = macho_file.getFile(index).?.object; + for (object.unwind_records_indexes.items) |cu_index| { + const cu = object.getUnwindRecord(cu_index); if (!cu.alive) continue; if (cu.getFde(macho_file)) |fde| { 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 { } } + const file = atom.getFile(macho_file); for (atom.getUnwindRecords(macho_file)) |cu_index| { - const cu = macho_file.getUnwindRecord(cu_index); + const cu = file.object.getUnwindRecord(cu_index); const cu_atom = cu.getAtom(macho_file); if (markAtom(cu_atom)) markLive(cu_atom, macho_file); diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 3fc37ef9ac..a2979eafe0 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -286,12 +286,15 @@ fn parseObject(macho_file: *MachO, path: []const u8) MachO.ParseError!void { break :mtime @as(u64, @intCast(@divFloor(stat.mtime, 1_000_000_000))); }; const index = @as(File.Index, @intCast(try macho_file.files.addOne(gpa))); - macho_file.files.set(index, .{ .object = .{ - .path = try gpa.dupe(u8, path), - .file_handle = handle, - .mtime = mtime, - .index = index, - } }); + macho_file.files.set(index, .{ + .object = .{ + .offset = 0, // TODO FAT objects + .path = try gpa.dupe(u8, path), + .file_handle = handle, + .mtime = mtime, + .index = index, + }, + }); try macho_file.objects.append(gpa, index); const object = macho_file.getFile(index).?.object; @@ -420,8 +423,8 @@ fn calcCompactUnwindSize(macho_file: *MachO, sect_index: u8) void { for (macho_file.objects.items) |index| { const object = macho_file.getFile(index).?.object; - for (object.unwind_records.items) |irec| { - const rec = macho_file.getUnwindRecord(irec); + for (object.unwind_records_indexes.items) |irec| { + const rec = object.getUnwindRecord(irec); if (!rec.alive) continue; size += @sizeOf(macho.compact_unwind_entry); nreloc += 1; @@ -670,8 +673,8 @@ fn writeCompactUnwind(macho_file: *MachO) !void { var offset: i32 = 0; for (macho_file.objects.items) |index| { const object = macho_file.getFile(index).?.object; - for (object.unwind_records.items) |irec| { - const rec = macho_file.getUnwindRecord(irec); + for (object.unwind_records_indexes.items) |irec| { + const rec = object.getUnwindRecord(irec); if (!rec.alive) continue; var out: macho.compact_unwind_entry = .{ |
