authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-22 18:30:00+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-22 18:30:00+01:00
logdc6b05408a4bf0a9a52eb0532b7dddc06914ad5d
tree00ad49556b68468097f4916d23f91491e07a3a20
parentd61ac0db8c62f706ea65b70d2772cbb8c4efb416
parent1eb4264b7aa9e9e2b8ec46a95b508dfa7a7ab0f7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15041 from ziglang/fix-14923

macho: fix Go mislinking on aarch64-macos, and misc cleanup

11 files changed, 314 insertions(+), 294 deletions(-)

lib/std/macho.zig+2
...@@ -143,6 +143,8 @@ pub const TOOL = enum(u32) {...@@ -143,6 +143,8 @@ pub const TOOL = enum(u32) {
143 CLANG = 0x1,143 CLANG = 0x1,
144 SWIFT = 0x2,144 SWIFT = 0x2,
145 LD = 0x3,145 LD = 0x3,
146 LLD = 0x4, // LLVM's stock LLD linker
147 ZIG = 0x5, // Unofficially Zig
146 _,148 _,
147};149};
148150
src/link/MachO.zig+11-28
...@@ -3340,36 +3340,19 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {...@@ -3340,36 +3340,19 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {
3340 const exec_segment = self.segments.items[self.header_segment_cmd_index.?];3340 const exec_segment = self.segments.items[self.header_segment_cmd_index.?];
3341 const base_address = exec_segment.vmaddr;3341 const base_address = exec_segment.vmaddr;
33423342
3343 if (self.base.options.output_mode == .Exe) {3343 for (self.globals.items) |global| {
3344 for (&[_]SymbolWithLoc{3344 const sym = self.getSymbol(global);
3345 try self.getEntryPoint(),
3346 self.getGlobal("__mh_execute_header").?,
3347 }) |global| {
3348 const sym = self.getSymbol(global);
3349 const sym_name = self.getSymbolName(global);
3350 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
3351 try trie.put(gpa, .{
3352 .name = sym_name,
3353 .vmaddr_offset = sym.n_value - base_address,
3354 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
3355 });
3356 }
3357 } else {
3358 assert(self.base.options.output_mode == .Lib);
3359 for (self.globals.items) |global| {
3360 const sym = self.getSymbol(global);
33613345
3362 if (sym.undf()) continue;3346 if (sym.undf()) continue;
3363 if (!sym.ext()) continue;3347 if (!sym.ext()) continue;
33643348
3365 const sym_name = self.getSymbolName(global);3349 const sym_name = self.getSymbolName(global);
3366 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });3350 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
3367 try trie.put(gpa, .{3351 try trie.put(gpa, .{
3368 .name = sym_name,3352 .name = sym_name,
3369 .vmaddr_offset = sym.n_value - base_address,3353 .vmaddr_offset = sym.n_value - base_address,
3370 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,3354 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
3371 });3355 });
3372 }
3373 }3356 }
33743357
3375 try trie.finalize(gpa);3358 try trie.finalize(gpa);
src/link/MachO/DwarfInfo.zig+3-18
...@@ -27,7 +27,7 @@ const CompileUnitIterator = struct {...@@ -27,7 +27,7 @@ const CompileUnitIterator = struct {
27 pub fn next(self: *CompileUnitIterator) !?CompileUnit {27 pub fn next(self: *CompileUnitIterator) !?CompileUnit {
28 if (self.pos >= self.ctx.debug_info.len) return null;28 if (self.pos >= self.ctx.debug_info.len) return null;
2929
30 var stream = std.io.fixedBufferStream(self.ctx.debug_info);30 var stream = std.io.fixedBufferStream(self.ctx.debug_info[self.pos..]);
31 var creader = std.io.countingReader(stream.reader());31 var creader = std.io.countingReader(stream.reader());
32 const reader = creader.reader();32 const reader = creader.reader();
3333
...@@ -37,7 +37,7 @@ const CompileUnitIterator = struct {...@@ -37,7 +37,7 @@ const CompileUnitIterator = struct {
3737
38 const cu = CompileUnit{38 const cu = CompileUnit{
39 .cuh = cuh,39 .cuh = cuh,
40 .debug_info_off = offset,40 .debug_info_off = self.pos + offset,
41 };41 };
4242
43 self.pos += (math.cast(usize, total_length) orelse return error.Overflow);43 self.pos += (math.cast(usize, total_length) orelse return error.Overflow);
...@@ -188,7 +188,7 @@ const AbbrevEntryIterator = struct {...@@ -188,7 +188,7 @@ const AbbrevEntryIterator = struct {
188 return AbbrevEntry.null();188 return AbbrevEntry.null();
189 }189 }
190190
191 const abbrev_pos = lookup.get(kind) orelse return error.MalformedDwarf;191 const abbrev_pos = lookup.get(kind) orelse return null;
192 const len = try findAbbrevEntrySize(192 const len = try findAbbrevEntrySize(
193 self.ctx,193 self.ctx,
194 abbrev_pos.pos,194 abbrev_pos.pos,
...@@ -290,21 +290,6 @@ pub const Attribute = struct {...@@ -290,21 +290,6 @@ pub const Attribute = struct {
290 };290 };
291 }291 }
292292
293 pub fn getReference(self: Attribute, ctx: DwarfInfo) !?u64 {
294 const debug_info = self.getDebugInfo(ctx);
295 var stream = std.io.fixedBufferStream(debug_info);
296 const reader = stream.reader();
297
298 return switch (self.form) {
299 dwarf.FORM.ref1 => debug_info[0],
300 dwarf.FORM.ref2 => mem.readIntLittle(u16, debug_info[0..2]),
301 dwarf.FORM.ref4 => mem.readIntLittle(u32, debug_info[0..4]),
302 dwarf.FORM.ref8 => mem.readIntLittle(u64, debug_info[0..8]),
303 dwarf.FORM.ref_udata => try leb.readULEB128(u64, reader),
304 else => null,
305 };
306 }
307
308 pub fn getAddr(self: Attribute, ctx: DwarfInfo, cuh: CompileUnit.Header) ?u64 {293 pub fn getAddr(self: Attribute, ctx: DwarfInfo, cuh: CompileUnit.Header) ?u64 {
309 if (self.form != dwarf.FORM.addr) return null;294 if (self.form != dwarf.FORM.addr) return null;
310 const debug_info = self.getDebugInfo(ctx);295 const debug_info = self.getDebugInfo(ctx);
src/link/MachO/Object.zig+55-43
...@@ -50,7 +50,7 @@ reverse_symtab_lookup: []u32 = undefined,...@@ -50,7 +50,7 @@ reverse_symtab_lookup: []u32 = undefined,
50/// Can be undefined as set together with in_symtab.50/// Can be undefined as set together with in_symtab.
51source_address_lookup: []i64 = undefined,51source_address_lookup: []i64 = undefined,
52/// Can be undefined as set together with in_symtab.52/// Can be undefined as set together with in_symtab.
53source_section_index_lookup: []i64 = undefined,53source_section_index_lookup: []Entry = undefined,
54/// Can be undefined as set together with in_symtab.54/// Can be undefined as set together with in_symtab.
55strtab_lookup: []u32 = undefined,55strtab_lookup: []u32 = undefined,
56/// Can be undefined as set together with in_symtab.56/// Can be undefined as set together with in_symtab.
...@@ -58,7 +58,7 @@ atom_by_index_table: []AtomIndex = undefined,...@@ -58,7 +58,7 @@ atom_by_index_table: []AtomIndex = undefined,
58/// Can be undefined as set together with in_symtab.58/// Can be undefined as set together with in_symtab.
59globals_lookup: []i64 = undefined,59globals_lookup: []i64 = undefined,
60/// Can be undefined as set together with in_symtab.60/// Can be undefined as set together with in_symtab.
61relocs_lookup: []RelocEntry = undefined,61relocs_lookup: []Entry = undefined,
6262
63/// All relocations sorted and flatened, sorted by address descending63/// All relocations sorted and flatened, sorted by address descending
64/// per section.64/// per section.
...@@ -81,11 +81,14 @@ unwind_info_sect_id: ?u8 = null,...@@ -81,11 +81,14 @@ unwind_info_sect_id: ?u8 = null,
81unwind_relocs_lookup: []Record = undefined,81unwind_relocs_lookup: []Record = undefined,
82unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},82unwind_records_lookup: std.AutoHashMapUnmanaged(AtomIndex, u32) = .{},
8383
84const RelocEntry = struct { start: u32, len: u32 };84const Entry = struct {
85 start: u32 = 0,
86 len: u32 = 0,
87};
8588
86const Record = struct {89const Record = struct {
87 dead: bool,90 dead: bool,
88 reloc: RelocEntry,91 reloc: Entry,
89};92};
9093
91pub fn deinit(self: *Object, gpa: Allocator) void {94pub fn deinit(self: *Object, gpa: Allocator) void {
...@@ -170,11 +173,11 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -170,11 +173,11 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
170 self.strtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);173 self.strtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);
171 self.globals_lookup = try allocator.alloc(i64, self.in_symtab.?.len);174 self.globals_lookup = try allocator.alloc(i64, self.in_symtab.?.len);
172 self.atom_by_index_table = try allocator.alloc(AtomIndex, self.in_symtab.?.len + nsects);175 self.atom_by_index_table = try allocator.alloc(AtomIndex, self.in_symtab.?.len + nsects);
173 self.relocs_lookup = try allocator.alloc(RelocEntry, self.in_symtab.?.len + nsects);176 self.relocs_lookup = try allocator.alloc(Entry, self.in_symtab.?.len + nsects);
174 // This is wasteful but we need to be able to lookup source symbol address after stripping and177 // This is wasteful but we need to be able to lookup source symbol address after stripping and
175 // allocating of sections.178 // allocating of sections.
176 self.source_address_lookup = try allocator.alloc(i64, self.in_symtab.?.len);179 self.source_address_lookup = try allocator.alloc(i64, self.in_symtab.?.len);
177 self.source_section_index_lookup = try allocator.alloc(i64, nsects);180 self.source_section_index_lookup = try allocator.alloc(Entry, nsects);
178181
179 for (self.symtab) |*sym| {182 for (self.symtab) |*sym| {
180 sym.* = .{183 sym.* = .{
...@@ -188,11 +191,8 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -188,11 +191,8 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
188191
189 mem.set(i64, self.globals_lookup, -1);192 mem.set(i64, self.globals_lookup, -1);
190 mem.set(AtomIndex, self.atom_by_index_table, 0);193 mem.set(AtomIndex, self.atom_by_index_table, 0);
191 mem.set(i64, self.source_section_index_lookup, -1);194 mem.set(Entry, self.source_section_index_lookup, .{});
192 mem.set(RelocEntry, self.relocs_lookup, .{195 mem.set(Entry, self.relocs_lookup, .{});
193 .start = 0,
194 .len = 0,
195 });
196196
197 // You would expect that the symbol table is at least pre-sorted based on symbol's type:197 // You would expect that the symbol table is at least pre-sorted based on symbol's type:
198 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,198 // local < extern defined < undefined. Unfortunately, this is not guaranteed! For instance,
...@@ -211,12 +211,24 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -211,12 +211,24 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
211 // is kind enough to specify the symbols in the correct order.211 // is kind enough to specify the symbols in the correct order.
212 sort.sort(SymbolAtIndex, sorted_all_syms.items, self, SymbolAtIndex.lessThan);212 sort.sort(SymbolAtIndex, sorted_all_syms.items, self, SymbolAtIndex.lessThan);
213213
214 var prev_sect_id: u8 = 0;
215 var section_index_lookup: ?Entry = null;
214 for (sorted_all_syms.items, 0..) |sym_id, i| {216 for (sorted_all_syms.items, 0..) |sym_id, i| {
215 const sym = sym_id.getSymbol(self);217 const sym = sym_id.getSymbol(self);
216218
217 if (sym.sect() and self.source_section_index_lookup[sym.n_sect - 1] == -1) {219 if (section_index_lookup) |*lookup| {
218 self.source_section_index_lookup[sym.n_sect - 1] = @intCast(i64, i);220 if (sym.n_sect != prev_sect_id or sym.undf()) {
221 self.source_section_index_lookup[prev_sect_id - 1] = lookup.*;
222 section_index_lookup = null;
223 } else {
224 lookup.len += 1;
225 }
219 }226 }
227 if (sym.sect() and section_index_lookup == null) {
228 section_index_lookup = .{ .start = @intCast(u32, i), .len = 1 };
229 }
230
231 prev_sect_id = sym.n_sect;
220232
221 self.symtab[i] = sym;233 self.symtab[i] = sym;
222 self.source_symtab_lookup[i] = sym_id.index;234 self.source_symtab_lookup[i] = sym_id.index;
...@@ -227,6 +239,12 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -227,6 +239,12 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
227 self.strtab_lookup[i] = @intCast(u32, sym_name_len);239 self.strtab_lookup[i] = @intCast(u32, sym_name_len);
228 }240 }
229241
242 // If there were no undefined symbols, make sure we populate the
243 // source section index lookup for the last scanned section.
244 if (section_index_lookup) |lookup| {
245 self.source_section_index_lookup[prev_sect_id - 1] = lookup;
246 }
247
230 // Parse __TEXT,__eh_frame header if one exists248 // Parse __TEXT,__eh_frame header if one exists
231 self.eh_frame_sect_id = self.getSourceSectionIndexByName("__TEXT", "__eh_frame");249 self.eh_frame_sect_id = self.getSourceSectionIndexByName("__TEXT", "__eh_frame");
232250
...@@ -234,13 +252,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)...@@ -234,13 +252,7 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
234 self.unwind_info_sect_id = self.getSourceSectionIndexByName("__LD", "__compact_unwind");252 self.unwind_info_sect_id = self.getSourceSectionIndexByName("__LD", "__compact_unwind");
235 if (self.hasUnwindRecords()) {253 if (self.hasUnwindRecords()) {
236 self.unwind_relocs_lookup = try allocator.alloc(Record, self.getUnwindRecords().len);254 self.unwind_relocs_lookup = try allocator.alloc(Record, self.getUnwindRecords().len);
237 mem.set(Record, self.unwind_relocs_lookup, .{255 mem.set(Record, self.unwind_relocs_lookup, .{ .dead = true, .reloc = .{} });
238 .dead = true,
239 .reloc = .{
240 .start = 0,
241 .len = 0,
242 },
243 });
244 }256 }
245}257}
246258
...@@ -620,7 +632,7 @@ fn filterRelocs(...@@ -620,7 +632,7 @@ fn filterRelocs(
620 relocs: []align(1) const macho.relocation_info,632 relocs: []align(1) const macho.relocation_info,
621 start_addr: u64,633 start_addr: u64,
622 end_addr: u64,634 end_addr: u64,
623) RelocEntry {635) Entry {
624 const Predicate = struct {636 const Predicate = struct {
625 addr: u64,637 addr: u64,
626638
...@@ -712,9 +724,9 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {...@@ -712,9 +724,9 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
712724
713 while (try it.next()) |record| {725 while (try it.next()) |record| {
714 const offset = it.pos - record.getSize();726 const offset = it.pos - record.getSize();
715 const rel_pos = switch (cpu_arch) {727 const rel_pos: Entry = switch (cpu_arch) {
716 .aarch64 => filterRelocs(relocs, offset, offset + record.getSize()),728 .aarch64 => filterRelocs(relocs, offset, offset + record.getSize()),
717 .x86_64 => RelocEntry{ .start = 0, .len = 0 },729 .x86_64 => .{},
718 else => unreachable,730 else => unreachable,
719 };731 };
720 self.eh_frame_relocs_lookup.putAssumeCapacityNoClobber(offset, .{732 self.eh_frame_relocs_lookup.putAssumeCapacityNoClobber(offset, .{
...@@ -729,13 +741,12 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {...@@ -729,13 +741,12 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
729 assert(rel_pos.len > 0); // TODO convert to an error as the FDE eh frame is malformed741 assert(rel_pos.len > 0); // TODO convert to an error as the FDE eh frame is malformed
730 // Find function symbol that this record describes742 // Find function symbol that this record describes
731 const rel = relocs[rel_pos.start..][rel_pos.len - 1];743 const rel = relocs[rel_pos.start..][rel_pos.len - 1];
732 const target = UnwindInfo.parseRelocTarget(744 const target = Atom.parseRelocTarget(zld, .{
733 zld,745 .object_id = object_id,
734 object_id,746 .rel = rel,
735 rel,747 .code = it.data[offset..],
736 it.data[offset..],748 .base_offset = @intCast(i32, offset),
737 @intCast(i32, offset),749 });
738 );
739 break :blk target;750 break :blk target;
740 },751 },
741 .x86_64 => {752 .x86_64 => {
...@@ -819,13 +830,12 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {...@@ -819,13 +830,12 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
819830
820 // Find function symbol that this record describes831 // Find function symbol that this record describes
821 const rel = relocs[rel_pos.start..][rel_pos.len - 1];832 const rel = relocs[rel_pos.start..][rel_pos.len - 1];
822 const target = UnwindInfo.parseRelocTarget(833 const target = Atom.parseRelocTarget(zld, .{
823 zld,834 .object_id = object_id,
824 object_id,835 .rel = rel,
825 rel,836 .code = mem.asBytes(&record),
826 mem.asBytes(&record),837 .base_offset = @intCast(i32, offset),
827 @intCast(i32, offset),838 });
828 );
829 log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) });839 log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) });
830 if (target.getFile() != object_id) {840 if (target.getFile() != object_id) {
831 self.unwind_relocs_lookup[record_id].dead = true;841 self.unwind_relocs_lookup[record_id].dead = true;
...@@ -990,13 +1000,15 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {...@@ -990,13 +1000,15 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
990 };1000 };
9911001
992 if (sect_hint) |sect_id| {1002 if (sect_hint) |sect_id| {
993 if (self.source_section_index_lookup[sect_id] > -1) {1003 if (self.source_section_index_lookup[sect_id].len > 0) {
994 const first_sym_index = @intCast(usize, self.source_section_index_lookup[sect_id]);1004 const lookup = self.source_section_index_lookup[sect_id];
995 const target_sym_index = @import("zld.zig").lsearch(i64, self.source_address_lookup[first_sym_index..], Predicate{1005 const target_sym_index = @import("zld.zig").lsearch(
996 .addr = @intCast(i64, addr),1006 i64,
997 });1007 self.source_address_lookup[lookup.start..][0..lookup.len],
1008 Predicate{ .addr = @intCast(i64, addr) },
1009 );
998 if (target_sym_index > 0) {1010 if (target_sym_index > 0) {
999 return @intCast(u32, first_sym_index + target_sym_index - 1);1011 return @intCast(u32, lookup.start + target_sym_index - 1);
1000 }1012 }
1001 }1013 }
1002 return self.getSectionAliasSymbolIndex(sect_id);1014 return self.getSectionAliasSymbolIndex(sect_id);
src/link/MachO/UnwindInfo.zig+18-56
...@@ -218,13 +218,12 @@ pub fn scanRelocs(zld: *Zld) !void {...@@ -218,13 +218,12 @@ pub fn scanRelocs(zld: *Zld) !void {
218 record_id,218 record_id,
219 )) |rel| {219 )) |rel| {
220 // Personality function; add GOT pointer.220 // Personality function; add GOT pointer.
221 const target = parseRelocTarget(221 const target = Atom.parseRelocTarget(zld, .{
222 zld,222 .object_id = @intCast(u32, object_id),
223 @intCast(u32, object_id),223 .rel = rel,
224 rel,224 .code = mem.asBytes(&record),
225 mem.asBytes(&record),225 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
226 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),226 });
227 );
228 try Atom.addGotEntry(zld, target);227 try Atom.addGotEntry(zld, target);
229 }228 }
230 }229 }
...@@ -266,13 +265,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {...@@ -266,13 +265,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
266 @intCast(u32, object_id),265 @intCast(u32, object_id),
267 record_id,266 record_id,
268 )) |rel| {267 )) |rel| {
269 const target = parseRelocTarget(268 const target = Atom.parseRelocTarget(zld, .{
270 zld,269 .object_id = @intCast(u32, object_id),
271 @intCast(u32, object_id),270 .rel = rel,
272 rel,271 .code = mem.asBytes(&record),
273 mem.asBytes(&record),272 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
274 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),273 });
275 );
276 const personality_index = info.getPersonalityFunction(target) orelse inner: {274 const personality_index = info.getPersonalityFunction(target) orelse inner: {
277 const personality_index = info.personalities_count;275 const personality_index = info.personalities_count;
278 info.personalities[personality_index] = target;276 info.personalities[personality_index] = target;
...@@ -285,13 +283,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {...@@ -285,13 +283,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
285 }283 }
286284
287 if (getLsdaReloc(zld, @intCast(u32, object_id), record_id)) |rel| {285 if (getLsdaReloc(zld, @intCast(u32, object_id), record_id)) |rel| {
288 const target = parseRelocTarget(286 const target = Atom.parseRelocTarget(zld, .{
289 zld,287 .object_id = @intCast(u32, object_id),
290 @intCast(u32, object_id),288 .rel = rel,
291 rel,289 .code = mem.asBytes(&record),
292 mem.asBytes(&record),290 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
293 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),291 });
294 );
295 record.lsda = @bitCast(u64, target);292 record.lsda = @bitCast(u64, target);
296 }293 }
297 }294 }
...@@ -668,41 +665,6 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {...@@ -668,41 +665,6 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
668 try zld.file.pwriteAll(buffer.items, sect.offset);665 try zld.file.pwriteAll(buffer.items, sect.offset);
669}666}
670667
671pub fn parseRelocTarget(
672 zld: *Zld,
673 object_id: u32,
674 rel: macho.relocation_info,
675 code: []const u8,
676 base_offset: i32,
677) SymbolWithLoc {
678 const tracy = trace(@src());
679 defer tracy.end();
680
681 const object = &zld.objects.items[object_id];
682
683 const sym_index = if (rel.r_extern == 0) blk: {
684 const sect_id = @intCast(u8, rel.r_symbolnum - 1);
685 const rel_offset = @intCast(u32, rel.r_address - base_offset);
686 assert(rel.r_pcrel == 0 and rel.r_length == 3);
687 const address_in_section = mem.readIntLittle(u64, code[rel_offset..][0..8]);
688 const sym_index = object.getSymbolByAddress(address_in_section, sect_id);
689 break :blk sym_index;
690 } else object.reverse_symtab_lookup[rel.r_symbolnum];
691
692 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 };
693 const sym = zld.getSymbol(sym_loc);
694
695 if (sym.sect() and !sym.ext()) {
696 // Make sure we are not dealing with a local alias.
697 const atom_index = object.getAtomIndexForSymbol(sym_index) orelse
698 return sym_loc;
699 const atom = zld.getAtom(atom_index);
700 return atom.getSymbolWithLoc();
701 } else if (object.getGlobal(sym_index)) |global_index| {
702 return zld.globals.items[global_index];
703 } else return sym_loc;
704}
705
706fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info {668fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info {
707 const object = &zld.objects.items[object_id];669 const object = &zld.objects.items[object_id];
708 assert(object.hasUnwindRecords());670 assert(object.hasUnwindRecords());
src/link/MachO/ZldAtom.zig+76-34
...@@ -15,6 +15,7 @@ const macho = std.macho;...@@ -15,6 +15,7 @@ const macho = std.macho;
15const math = std.math;15const math = std.math;
16const mem = std.mem;16const mem = std.mem;
17const meta = std.meta;17const meta = std.meta;
18const trace = @import("../../tracy.zig").trace;
1819
19const Allocator = mem.Allocator;20const Allocator = mem.Allocator;
20const Arch = std.Target.Cpu.Arch;21const Arch = std.Target.Cpu.Arch;
...@@ -163,7 +164,7 @@ pub fn scanAtomRelocs(zld: *Zld, atom_index: AtomIndex, relocs: []align(1) const...@@ -163,7 +164,7 @@ pub fn scanAtomRelocs(zld: *Zld, atom_index: AtomIndex, relocs: []align(1) const
163}164}
164165
165const RelocContext = struct {166const RelocContext = struct {
166 base_addr: u64 = 0,167 base_addr: i64 = 0,
167 base_offset: i32 = 0,168 base_offset: i32 = 0,
168};169};
169170
...@@ -175,7 +176,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {...@@ -175,7 +176,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
175 if (object.getSourceSymbol(atom.sym_index)) |source_sym| {176 if (object.getSourceSymbol(atom.sym_index)) |source_sym| {
176 const source_sect = object.getSourceSection(source_sym.n_sect - 1);177 const source_sect = object.getSourceSection(source_sym.n_sect - 1);
177 return .{178 return .{
178 .base_addr = source_sect.addr,179 .base_addr = @intCast(i64, source_sect.addr),
179 .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr),180 .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr),
180 };181 };
181 }182 }
...@@ -183,55 +184,71 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {...@@ -183,55 +184,71 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
183 const sect_id = @intCast(u8, atom.sym_index - nbase);184 const sect_id = @intCast(u8, atom.sym_index - nbase);
184 const source_sect = object.getSourceSection(sect_id);185 const source_sect = object.getSourceSection(sect_id);
185 return .{186 return .{
186 .base_addr = source_sect.addr,187 .base_addr = @intCast(i64, source_sect.addr),
187 .base_offset = 0,188 .base_offset = 0,
188 };189 };
189}190}
190191
191pub fn parseRelocTarget(zld: *Zld, atom_index: AtomIndex, rel: macho.relocation_info) SymbolWithLoc {192pub fn parseRelocTarget(zld: *Zld, ctx: struct {
192 const atom = zld.getAtom(atom_index);193 object_id: u32,
193 const object = &zld.objects.items[atom.getFile().?];194 rel: macho.relocation_info,
195 code: []const u8,
196 base_addr: i64 = 0,
197 base_offset: i32 = 0,
198}) SymbolWithLoc {
199 const tracy = trace(@src());
200 defer tracy.end();
194201
195 const sym_index = if (rel.r_extern == 0) sym_index: {202 const object = &zld.objects.items[ctx.object_id];
196 const sect_id = @intCast(u8, rel.r_symbolnum - 1);203 log.debug("parsing reloc target in object({d}) '{s}' ", .{ ctx.object_id, object.name });
197 const ctx = getRelocContext(zld, atom_index);
198 const atom_code = getAtomCode(zld, atom_index);
199 const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset);
200204
201 const address_in_section = if (rel.r_pcrel == 0) blk: {205 const sym_index = if (ctx.rel.r_extern == 0) sym_index: {
202 break :blk if (rel.r_length == 3)206 const sect_id = @intCast(u8, ctx.rel.r_symbolnum - 1);
203 mem.readIntLittle(u64, atom_code[rel_offset..][0..8])207 const rel_offset = @intCast(u32, ctx.rel.r_address - ctx.base_offset);
208
209 const address_in_section = if (ctx.rel.r_pcrel == 0) blk: {
210 break :blk if (ctx.rel.r_length == 3)
211 mem.readIntLittle(u64, ctx.code[rel_offset..][0..8])
204 else212 else
205 mem.readIntLittle(u32, atom_code[rel_offset..][0..4]);213 mem.readIntLittle(u32, ctx.code[rel_offset..][0..4]);
206 } else blk: {214 } else blk: {
207 const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, rel.r_type)) {215 assert(zld.options.target.cpu.arch == .x86_64);
216 const correction: u3 = switch (@intToEnum(macho.reloc_type_x86_64, ctx.rel.r_type)) {
208 .X86_64_RELOC_SIGNED => 0,217 .X86_64_RELOC_SIGNED => 0,
209 .X86_64_RELOC_SIGNED_1 => 1,218 .X86_64_RELOC_SIGNED_1 => 1,
210 .X86_64_RELOC_SIGNED_2 => 2,219 .X86_64_RELOC_SIGNED_2 => 2,
211 .X86_64_RELOC_SIGNED_4 => 4,220 .X86_64_RELOC_SIGNED_4 => 4,
212 else => unreachable,221 else => unreachable,
213 };222 };
214 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);223 const addend = mem.readIntLittle(i32, ctx.code[rel_offset..][0..4]);
215 const target_address = @intCast(i64, ctx.base_addr) + rel.r_address + 4 + correction + addend;224 const target_address = @intCast(i64, ctx.base_addr) + ctx.rel.r_address + 4 + correction + addend;
216 break :blk @intCast(u64, target_address);225 break :blk @intCast(u64, target_address);
217 };226 };
218227
219 // Find containing atom228 // Find containing atom
229 log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id });
220 const sym_index = object.getSymbolByAddress(address_in_section, sect_id);230 const sym_index = object.getSymbolByAddress(address_in_section, sect_id);
221 break :sym_index sym_index;231 break :sym_index sym_index;
222 } else object.reverse_symtab_lookup[rel.r_symbolnum];232 } else object.reverse_symtab_lookup[ctx.rel.r_symbolnum];
223233
224 const sym_loc = SymbolWithLoc{234 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };
225 .sym_index = sym_index,
226 .file = atom.file,
227 };
228 const sym = zld.getSymbol(sym_loc);235 const sym = zld.getSymbol(sym_loc);
229236 const target = target: {
230 if (sym.sect() and !sym.ext()) {237 if (sym.sect() and !sym.ext()) {
231 return sym_loc;238 // Make sure we are not dealing with a local alias.
232 } else if (object.getGlobal(sym_index)) |global_index| {239 const atom_index = object.getAtomIndexForSymbol(sym_index) orelse break :target sym_loc;
233 return zld.globals.items[global_index];240 const atom = zld.getAtom(atom_index);
234 } else return sym_loc;241 break :target atom.getSymbolWithLoc();
242 } else if (object.getGlobal(sym_index)) |global_index| {
243 break :target zld.globals.items[global_index];
244 } else break :target sym_loc;
245 };
246 log.debug(" | target %{d} ('{s}') in object({?d})", .{
247 target.sym_index,
248 zld.getSymbolName(target),
249 target.getFile(),
250 });
251 return target;
235}252}
236253
237pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc, is_via_got: bool) ?AtomIndex {254pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc, is_via_got: bool) ?AtomIndex {
...@@ -499,13 +516,25 @@ fn resolveRelocsArm64(...@@ -499,13 +516,25 @@ fn resolveRelocsArm64(
499 atom.getFile(),516 atom.getFile(),
500 });517 });
501518
502 subtractor = parseRelocTarget(zld, atom_index, rel);519 subtractor = parseRelocTarget(zld, .{
520 .object_id = atom.getFile().?,
521 .rel = rel,
522 .code = atom_code,
523 .base_addr = context.base_addr,
524 .base_offset = context.base_offset,
525 });
503 continue;526 continue;
504 },527 },
505 else => {},528 else => {},
506 }529 }
507530
508 const target = parseRelocTarget(zld, atom_index, rel);531 const target = parseRelocTarget(zld, .{
532 .object_id = atom.getFile().?,
533 .rel = rel,
534 .code = atom_code,
535 .base_addr = context.base_addr,
536 .base_offset = context.base_offset,
537 });
509 const rel_offset = @intCast(u32, rel.r_address - context.base_offset);538 const rel_offset = @intCast(u32, rel.r_address - context.base_offset);
510539
511 log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{540 log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
...@@ -781,19 +810,32 @@ fn resolveRelocsX86(...@@ -781,19 +810,32 @@ fn resolveRelocsX86(
781 atom.getFile(),810 atom.getFile(),
782 });811 });
783812
784 subtractor = parseRelocTarget(zld, atom_index, rel);813 subtractor = parseRelocTarget(zld, .{
814 .object_id = atom.getFile().?,
815 .rel = rel,
816 .code = atom_code,
817 .base_addr = context.base_addr,
818 .base_offset = context.base_offset,
819 });
785 continue;820 continue;
786 },821 },
787 else => {},822 else => {},
788 }823 }
789824
790 const target = parseRelocTarget(zld, atom_index, rel);825 const target = parseRelocTarget(zld, .{
826 .object_id = atom.getFile().?,
827 .rel = rel,
828 .code = atom_code,
829 .base_addr = context.base_addr,
830 .base_offset = context.base_offset,
831 });
791 const rel_offset = @intCast(u32, rel.r_address - context.base_offset);832 const rel_offset = @intCast(u32, rel.r_address - context.base_offset);
792833
793 log.debug(" RELA({s}) @ {x} => %{d} in object({?})", .{834 log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
794 @tagName(rel_type),835 @tagName(rel_type),
795 rel.r_address,836 rel.r_address,
796 target.sym_index,837 target.sym_index,
838 zld.getSymbolName(target),
797 target.getFile(),839 target.getFile(),
798 });840 });
799841
src/link/MachO/dead_strip.zig+53-26
...@@ -102,7 +102,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {...@@ -102,7 +102,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
102 };102 };
103103
104 if (is_gc_root) {104 if (is_gc_root) {
105 try roots.putNoClobber(atom_index, {});105 _ = try roots.getOrPut(atom_index);
106106
107 log.debug("root(ATOM({d}, %{d}, {?d}))", .{107 log.debug("root(ATOM({d}, %{d}, {?d}))", .{
108 atom_index,108 atom_index,
...@@ -130,14 +130,29 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {...@@ -130,14 +130,29 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {
130 const header = zld.sections.items(.header)[sym.n_sect - 1];130 const header = zld.sections.items(.header)[sym.n_sect - 1];
131 if (header.isZerofill()) return;131 if (header.isZerofill()) return;
132132
133 const code = Atom.getAtomCode(zld, atom_index);
133 const relocs = Atom.getAtomRelocs(zld, atom_index);134 const relocs = Atom.getAtomRelocs(zld, atom_index);
135 const ctx = Atom.getRelocContext(zld, atom_index);
136
134 for (relocs) |rel| {137 for (relocs) |rel| {
135 const target = switch (cpu_arch) {138 const target = switch (cpu_arch) {
136 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {139 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
137 .ARM64_RELOC_ADDEND => continue,140 .ARM64_RELOC_ADDEND => continue,
138 else => Atom.parseRelocTarget(zld, atom_index, rel),141 else => Atom.parseRelocTarget(zld, .{
142 .object_id = atom.getFile().?,
143 .rel = rel,
144 .code = code,
145 .base_offset = ctx.base_offset,
146 .base_addr = ctx.base_addr,
147 }),
139 },148 },
140 .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel),149 .x86_64 => Atom.parseRelocTarget(zld, .{
150 .object_id = atom.getFile().?,
151 .rel = rel,
152 .code = code,
153 .base_offset = ctx.base_offset,
154 .base_addr = ctx.base_addr,
155 }),
141 else => unreachable,156 else => unreachable,
142 };157 };
143 const target_sym = zld.getSymbol(target);158 const target_sym = zld.getSymbol(target);
...@@ -175,14 +190,29 @@ fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable) bool {...@@ -175,14 +190,29 @@ fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable) bool {
175 const header = zld.sections.items(.header)[sym.n_sect - 1];190 const header = zld.sections.items(.header)[sym.n_sect - 1];
176 assert(!header.isZerofill());191 assert(!header.isZerofill());
177192
193 const code = Atom.getAtomCode(zld, atom_index);
178 const relocs = Atom.getAtomRelocs(zld, atom_index);194 const relocs = Atom.getAtomRelocs(zld, atom_index);
195 const ctx = Atom.getRelocContext(zld, atom_index);
196
179 for (relocs) |rel| {197 for (relocs) |rel| {
180 const target = switch (cpu_arch) {198 const target = switch (cpu_arch) {
181 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {199 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
182 .ARM64_RELOC_ADDEND => continue,200 .ARM64_RELOC_ADDEND => continue,
183 else => Atom.parseRelocTarget(zld, atom_index, rel),201 else => Atom.parseRelocTarget(zld, .{
202 .object_id = atom.getFile().?,
203 .rel = rel,
204 .code = code,
205 .base_offset = ctx.base_offset,
206 .base_addr = ctx.base_addr,
207 }),
184 },208 },
185 .x86_64 => Atom.parseRelocTarget(zld, atom_index, rel),209 .x86_64 => Atom.parseRelocTarget(zld, .{
210 .object_id = atom.getFile().?,
211 .rel = rel,
212 .code = code,
213 .base_offset = ctx.base_offset,
214 .base_addr = ctx.base_addr,
215 }),
186 else => unreachable,216 else => unreachable,
187 };217 };
188218
...@@ -283,13 +313,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {...@@ -283,13 +313,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
283 try markEhFrameRecord(zld, object_id, atom_index, alive);313 try markEhFrameRecord(zld, object_id, atom_index, alive);
284 } else {314 } else {
285 if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {315 if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {
286 const target = UnwindInfo.parseRelocTarget(316 const target = Atom.parseRelocTarget(zld, .{
287 zld,317 .object_id = object_id,
288 object_id,318 .rel = rel,
289 rel,319 .code = mem.asBytes(&record),
290 mem.asBytes(&record),320 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
291 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),321 });
292 );
293 const target_sym = zld.getSymbol(target);322 const target_sym = zld.getSymbol(target);
294 if (!target_sym.undf()) {323 if (!target_sym.undf()) {
295 const target_object = zld.objects.items[target.getFile().?];324 const target_object = zld.objects.items[target.getFile().?];
...@@ -299,13 +328,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {...@@ -299,13 +328,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
299 }328 }
300329
301 if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {330 if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {
302 const target = UnwindInfo.parseRelocTarget(331 const target = Atom.parseRelocTarget(zld, .{
303 zld,332 .object_id = object_id,
304 object_id,333 .rel = rel,
305 rel,334 .code = mem.asBytes(&record),
306 mem.asBytes(&record),335 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
307 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),336 });
308 );
309 const target_object = zld.objects.items[target.getFile().?];337 const target_object = zld.objects.items[target.getFile().?];
310 const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;338 const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
311 markLive(zld, target_atom_index, alive);339 markLive(zld, target_atom_index, alive);
...@@ -333,13 +361,12 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A...@@ -333,13 +361,12 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A
333 // Mark FDE references which should include any referenced LSDA record361 // Mark FDE references which should include any referenced LSDA record
334 const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);362 const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);
335 for (relocs) |rel| {363 for (relocs) |rel| {
336 const target = UnwindInfo.parseRelocTarget(364 const target = Atom.parseRelocTarget(zld, .{
337 zld,365 .object_id = object_id,
338 object_id,366 .rel = rel,
339 rel,367 .code = fde.data,
340 fde.data,368 .base_offset = @intCast(i32, fde_offset) + 4,
341 @intCast(i32, fde_offset) + 4,369 });
342 );
343 const target_sym = zld.getSymbol(target);370 const target_sym = zld.getSymbol(target);
344 if (!target_sym.undf()) blk: {371 if (!target_sym.undf()) blk: {
345 const target_object = zld.objects.items[target.getFile().?];372 const target_object = zld.objects.items[target.getFile().?];
src/link/MachO/eh_frame.zig+12-14
...@@ -308,13 +308,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {...@@ -308,13 +308,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
308 },308 },
309 else => unreachable,309 else => unreachable,
310 }310 }
311 const target = UnwindInfo.parseRelocTarget(311 const target = Atom.parseRelocTarget(zld, .{
312 zld,312 .object_id = object_id,
313 object_id,313 .rel = rel,
314 rel,314 .code = rec.data,
315 rec.data,315 .base_offset = @intCast(i32, source_offset) + 4,
316 @intCast(i32, source_offset) + 4,316 });
317 );
318 return target;317 return target;
319 }318 }
320 return null;319 return null;
...@@ -331,13 +330,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {...@@ -331,13 +330,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
331 const relocs = getRelocs(zld, object_id, ctx.source_offset);330 const relocs = getRelocs(zld, object_id, ctx.source_offset);
332331
333 for (relocs) |rel| {332 for (relocs) |rel| {
334 const target = UnwindInfo.parseRelocTarget(333 const target = Atom.parseRelocTarget(zld, .{
335 zld,334 .object_id = object_id,
336 object_id,335 .rel = rel,
337 rel,336 .code = rec.data,
338 rec.data,337 .base_offset = @intCast(i32, ctx.source_offset) + 4,
339 @intCast(i32, ctx.source_offset) + 4,338 });
340 );
341 const rel_offset = @intCast(u32, rel.r_address - @intCast(i32, ctx.source_offset) - 4);339 const rel_offset = @intCast(u32, rel.r_address - @intCast(i32, ctx.source_offset) - 4);
342 const source_addr = ctx.sect_addr + rel_offset + ctx.out_offset + 4;340 const source_addr = ctx.sect_addr + rel_offset + ctx.out_offset + 4;
343341
src/link/MachO/load_commands.zig+1-1
...@@ -294,7 +294,7 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo...@@ -294,7 +294,7 @@ pub fn writeBuildVersionLC(options: *const link.Options, lc_writer: anytype) !vo
294 .ntools = 1,294 .ntools = 1,
295 });295 });
296 try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{296 try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{
297 .tool = .LD,297 .tool = .ZIG,
298 .version = 0x0,298 .version = 0x0,
299 }));299 }));
300}300}
src/link/MachO/thunks.zig+10-1
...@@ -225,11 +225,20 @@ fn scanRelocs(...@@ -225,11 +225,20 @@ fn scanRelocs(
225 break :blk @intCast(i32, source_sym.n_value - source_sect.addr);225 break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
226 } else 0;226 } else 0;
227227
228 const code = Atom.getAtomCode(zld, atom_index);
228 const relocs = Atom.getAtomRelocs(zld, atom_index);229 const relocs = Atom.getAtomRelocs(zld, atom_index);
230 const ctx = Atom.getRelocContext(zld, atom_index);
231
229 for (relocs) |rel| {232 for (relocs) |rel| {
230 if (!relocNeedsThunk(rel)) continue;233 if (!relocNeedsThunk(rel)) continue;
231234
232 const target = Atom.parseRelocTarget(zld, atom_index, rel);235 const target = Atom.parseRelocTarget(zld, .{
236 .object_id = atom.getFile().?,
237 .rel = rel,
238 .code = code,
239 .base_offset = ctx.base_offset,
240 .base_addr = ctx.base_addr,
241 });
233 if (isReachable(zld, atom_index, rel, base_offset, target, allocated)) continue;242 if (isReachable(zld, atom_index, rel, base_offset, target, allocated)) continue;
234243
235 log.debug("{x}: source = {s}@{x}, target = {s}@{x} unreachable", .{244 log.debug("{x}: source = {s}@{x}, target = {s}@{x} unreachable", .{
src/link/MachO/zld.zig+73-73
...@@ -477,9 +477,9 @@ pub const Zld = struct {...@@ -477,9 +477,9 @@ pub const Zld = struct {
477 mem.eql(u8, sectname, "__gosymtab") or477 mem.eql(u8, sectname, "__gosymtab") or
478 mem.eql(u8, sectname, "__gopclntab"))478 mem.eql(u8, sectname, "__gopclntab"))
479 {479 {
480 break :blk self.getSectionByName("__DATA_CONST", "__const") orelse try self.initSection(480 break :blk self.getSectionByName("__TEXT", sectname) orelse try self.initSection(
481 "__DATA_CONST",481 "__TEXT",
482 "__const",482 sectname,
483 .{},483 .{},
484 );484 );
485 }485 }
...@@ -490,15 +490,13 @@ pub const Zld = struct {...@@ -490,15 +490,13 @@ pub const Zld = struct {
490 mem.eql(u8, sectname, "__objc_classlist") or490 mem.eql(u8, sectname, "__objc_classlist") or
491 mem.eql(u8, sectname, "__objc_imageinfo"))491 mem.eql(u8, sectname, "__objc_imageinfo"))
492 {492 {
493 break :blk self.getSectionByName("__DATA_CONST", sectname) orelse493 break :blk self.getSectionByName("__DATA_CONST", sectname) orelse try self.initSection(
494 try self.initSection(
495 "__DATA_CONST",494 "__DATA_CONST",
496 sectname,495 sectname,
497 .{},496 .{},
498 );497 );
499 } else if (mem.eql(u8, sectname, "__data")) {498 } else if (mem.eql(u8, sectname, "__data")) {
500 break :blk self.getSectionByName("__DATA", "__data") orelse499 break :blk self.getSectionByName("__DATA", "__data") orelse try self.initSection(
501 try self.initSection(
502 "__DATA",500 "__DATA",
503 "__data",501 "__data",
504 .{},502 .{},
...@@ -1886,13 +1884,9 @@ pub const Zld = struct {...@@ -1886,13 +1884,9 @@ pub const Zld = struct {
1886 if (should_rebase) {1884 if (should_rebase) {
1887 log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });1885 log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });
18881886
1889 const object = self.objects.items[atom.getFile().?];1887 const code = Atom.getAtomCode(self, atom_index);
1890 const base_rel_offset: i32 = blk: {
1891 const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0;
1892 const source_sect = object.getSourceSection(source_sym.n_sect - 1);
1893 break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
1894 };
1895 const relocs = Atom.getAtomRelocs(self, atom_index);1888 const relocs = Atom.getAtomRelocs(self, atom_index);
1889 const ctx = Atom.getRelocContext(self, atom_index);
18961890
1897 for (relocs) |rel| {1891 for (relocs) |rel| {
1898 switch (cpu_arch) {1892 switch (cpu_arch) {
...@@ -1908,12 +1902,18 @@ pub const Zld = struct {...@@ -1908,12 +1902,18 @@ pub const Zld = struct {
1908 },1902 },
1909 else => unreachable,1903 else => unreachable,
1910 }1904 }
1911 const target = Atom.parseRelocTarget(self, atom_index, rel);1905 const target = Atom.parseRelocTarget(self, .{
1906 .object_id = atom.getFile().?,
1907 .rel = rel,
1908 .code = code,
1909 .base_offset = ctx.base_offset,
1910 .base_addr = ctx.base_addr,
1911 });
1912 const target_sym = self.getSymbol(target);1912 const target_sym = self.getSymbol(target);
1913 if (target_sym.undf()) continue;1913 if (target_sym.undf()) continue;
19141914
1915 const base_offset = @intCast(i32, sym.n_value - segment.vmaddr);1915 const base_offset = @intCast(i32, sym.n_value - segment.vmaddr);
1916 const rel_offset = rel.r_address - base_rel_offset;1916 const rel_offset = rel.r_address - ctx.base_offset;
1917 const offset = @intCast(u64, base_offset + rel_offset);1917 const offset = @intCast(u64, base_offset + rel_offset);
1918 log.debug(" | rebase at {x}", .{offset});1918 log.debug(" | rebase at {x}", .{offset});
19191919
...@@ -2023,13 +2023,9 @@ pub const Zld = struct {...@@ -2023,13 +2023,9 @@ pub const Zld = struct {
2023 };2023 };
20242024
2025 if (should_bind) {2025 if (should_bind) {
2026 const object = self.objects.items[atom.getFile().?];2026 const code = Atom.getAtomCode(self, atom_index);
2027 const base_rel_offset: i32 = blk: {
2028 const source_sym = object.getSourceSymbol(atom.sym_index) orelse break :blk 0;
2029 const source_sect = object.getSourceSection(source_sym.n_sect - 1);
2030 break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
2031 };
2032 const relocs = Atom.getAtomRelocs(self, atom_index);2027 const relocs = Atom.getAtomRelocs(self, atom_index);
2028 const ctx = Atom.getRelocContext(self, atom_index);
20332029
2034 for (relocs) |rel| {2030 for (relocs) |rel| {
2035 switch (cpu_arch) {2031 switch (cpu_arch) {
...@@ -2046,15 +2042,20 @@ pub const Zld = struct {...@@ -2046,15 +2042,20 @@ pub const Zld = struct {
2046 else => unreachable,2042 else => unreachable,
2047 }2043 }
20482044
2049 const global = Atom.parseRelocTarget(self, atom_index, rel);2045 const global = Atom.parseRelocTarget(self, .{
2046 .object_id = atom.getFile().?,
2047 .rel = rel,
2048 .code = code,
2049 .base_offset = ctx.base_offset,
2050 .base_addr = ctx.base_addr,
2051 });
2050 const bind_sym_name = self.getSymbolName(global);2052 const bind_sym_name = self.getSymbolName(global);
2051 const bind_sym = self.getSymbol(global);2053 const bind_sym = self.getSymbol(global);
2052 if (!bind_sym.undf()) continue;2054 if (!bind_sym.undf()) continue;
20532055
2054 const base_offset = sym.n_value - segment.vmaddr;2056 const base_offset = sym.n_value - segment.vmaddr;
2055 const rel_offset = @intCast(u32, rel.r_address - base_rel_offset);2057 const rel_offset = @intCast(u32, rel.r_address - ctx.base_offset);
2056 const offset = @intCast(u64, base_offset + rel_offset);2058 const offset = @intCast(u64, base_offset + rel_offset);
2057 const code = Atom.getAtomCode(self, atom_index);
2058 const addend = mem.readIntLittle(i64, code[rel_offset..][0..8]);2059 const addend = mem.readIntLittle(i64, code[rel_offset..][0..8]);
20592060
2060 const dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER);2061 const dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER);
...@@ -2143,43 +2144,24 @@ pub const Zld = struct {...@@ -2143,43 +2144,24 @@ pub const Zld = struct {
2143 const exec_segment = self.segments.items[segment_index];2144 const exec_segment = self.segments.items[segment_index];
2144 const base_address = exec_segment.vmaddr;2145 const base_address = exec_segment.vmaddr;
21452146
2146 if (self.options.output_mode == .Exe) {2147 for (self.globals.items) |global| {
2147 for (&[_]SymbolWithLoc{2148 const sym = self.getSymbol(global);
2148 self.getEntryPoint(),2149 if (sym.undf()) continue;
2149 self.globals.items[self.mh_execute_header_index.?],2150 if (sym.n_desc == N_DEAD) continue;
2150 }) |global| {
2151 const sym = self.getSymbol(global);
2152 const sym_name = self.getSymbolName(global);
2153 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
2154 try trie.put(gpa, .{
2155 .name = sym_name,
2156 .vmaddr_offset = sym.n_value - base_address,
2157 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2158 });
2159 }
2160 } else {
2161 assert(self.options.output_mode == .Lib);
2162 for (self.globals.items) |global| {
2163 const sym = self.getSymbol(global);
2164 if (sym.undf()) continue;
2165 if (sym.n_desc == N_DEAD) continue;
21662151
2167 const sym_name = self.getSymbolName(global);2152 const sym_name = self.getSymbolName(global);
2168 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });2153 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
2169 try trie.put(gpa, .{2154 try trie.put(gpa, .{
2170 .name = sym_name,2155 .name = sym_name,
2171 .vmaddr_offset = sym.n_value - base_address,2156 .vmaddr_offset = sym.n_value - base_address,
2172 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,2157 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2173 });2158 });
2174 }
2175 }2159 }
21762160
2177 try trie.finalize(gpa);2161 try trie.finalize(gpa);
2178 }2162 }
21792163
2180 fn writeDyldInfoData(2164 fn writeDyldInfoData(self: *Zld) !void {
2181 self: *Zld,
2182 ) !void {
2183 const gpa = self.gpa;2165 const gpa = self.gpa;
21842166
2185 var rebase = Rebase{};2167 var rebase = Rebase{};
...@@ -2300,9 +2282,16 @@ pub const Zld = struct {...@@ -2300,9 +2282,16 @@ pub const Zld = struct {
23002282
2301 const asc_u64 = std.sort.asc(u64);2283 const asc_u64 = std.sort.asc(u64);
23022284
2285 fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void {
2286 const sym = self.getSymbol(sym_loc);
2287 if (sym.n_strx == 0) return;
2288 if (sym.n_desc == N_DEAD) return;
2289 if (self.symbolIsTemp(sym_loc)) return;
2290 try addresses.append(sym.n_value);
2291 }
2292
2303 fn writeFunctionStarts(self: *Zld) !void {2293 fn writeFunctionStarts(self: *Zld) !void {
2304 const text_seg_index = self.getSegmentByName("__TEXT") orelse return;2294 const text_seg_index = self.getSegmentByName("__TEXT") orelse return;
2305 const text_sect_index = self.getSectionByName("__TEXT", "__text") orelse return;
2306 const text_seg = self.segments.items[text_seg_index];2295 const text_seg = self.segments.items[text_seg_index];
23072296
2308 const gpa = self.gpa;2297 const gpa = self.gpa;
...@@ -2310,17 +2299,18 @@ pub const Zld = struct {...@@ -2310,17 +2299,18 @@ pub const Zld = struct {
2310 // We need to sort by address first2299 // We need to sort by address first
2311 var addresses = std.ArrayList(u64).init(gpa);2300 var addresses = std.ArrayList(u64).init(gpa);
2312 defer addresses.deinit();2301 defer addresses.deinit();
2313 try addresses.ensureTotalCapacityPrecise(self.globals.items.len);
2314
2315 for (self.globals.items) |global| {
2316 const sym = self.getSymbol(global);
2317 if (sym.undf()) continue;
2318 if (sym.n_desc == N_DEAD) continue;
23192302
2320 const sect_id = sym.n_sect - 1;2303 for (self.objects.items) |object| {
2321 if (sect_id != text_sect_index) continue;2304 for (object.exec_atoms.items) |atom_index| {
2305 const atom = self.getAtom(atom_index);
2306 const sym_loc = atom.getSymbolWithLoc();
2307 try self.addSymbolToFunctionStarts(sym_loc, &addresses);
23222308
2323 addresses.appendAssumeCapacity(sym.n_value);2309 var it = Atom.getInnerSymbolsIterator(self, atom_index);
2310 while (it.next()) |inner_sym_loc| {
2311 try self.addSymbolToFunctionStarts(inner_sym_loc, &addresses);
2312 }
2313 }
2324 }2314 }
23252315
2326 std.sort.sort(u64, addresses.items, {}, asc_u64);2316 std.sort.sort(u64, addresses.items, {}, asc_u64);
...@@ -2456,6 +2446,18 @@ pub const Zld = struct {...@@ -2456,6 +2446,18 @@ pub const Zld = struct {
2456 try self.writeStrtab();2446 try self.writeStrtab();
2457 }2447 }
24582448
2449 fn addLocalToSymtab(self: *Zld, sym_loc: SymbolWithLoc, locals: *std.ArrayList(macho.nlist_64)) !void {
2450 const sym = self.getSymbol(sym_loc);
2451 if (sym.n_strx == 0) return; // no name, skip
2452 if (sym.n_desc == N_DEAD) return; // garbage-collected, skip
2453 if (sym.ext()) return; // an export lands in its own symtab section, skip
2454 if (self.symbolIsTemp(sym_loc)) return; // local temp symbol, skip
2455
2456 var out_sym = sym;
2457 out_sym.n_strx = try self.strtab.insert(self.gpa, self.getSymbolName(sym_loc));
2458 try locals.append(out_sym);
2459 }
2460
2459 fn writeSymtab(self: *Zld) !SymtabCtx {2461 fn writeSymtab(self: *Zld) !SymtabCtx {
2460 const gpa = self.gpa;2462 const gpa = self.gpa;
24612463
...@@ -2466,14 +2468,12 @@ pub const Zld = struct {...@@ -2466,14 +2468,12 @@ pub const Zld = struct {
2466 for (object.atoms.items) |atom_index| {2468 for (object.atoms.items) |atom_index| {
2467 const atom = self.getAtom(atom_index);2469 const atom = self.getAtom(atom_index);
2468 const sym_loc = atom.getSymbolWithLoc();2470 const sym_loc = atom.getSymbolWithLoc();
2469 const sym = self.getSymbol(sym_loc);2471 try self.addLocalToSymtab(sym_loc, &locals);
2470 if (sym.n_strx == 0) continue; // no name, skip2472
2471 if (sym.ext()) continue; // an export lands in its own symtab section, skip2473 var it = Atom.getInnerSymbolsIterator(self, atom_index);
2472 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip2474 while (it.next()) |inner_sym_loc| {
24732475 try self.addLocalToSymtab(inner_sym_loc, &locals);
2474 var out_sym = sym;2476 }
2475 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
2476 try locals.append(out_sym);
2477 }2477 }
2478 }2478 }
24792479