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) {
143143 CLANG = 0x1,
144144 SWIFT = 0x2,
145145 LD = 0x3,
146 LLD = 0x4, // LLVM's stock LLD linker
147 ZIG = 0x5, // Unofficially Zig
146148 _,
147149};
148150
src/link/MachO.zig+11-28
......@@ -3340,36 +3340,19 @@ fn collectExportData(self: *MachO, trie: *Trie) !void {
33403340 const exec_segment = self.segments.items[self.header_segment_cmd_index.?];
33413341 const base_address = exec_segment.vmaddr;
33423342
3343 if (self.base.options.output_mode == .Exe) {
3344 for (&[_]SymbolWithLoc{
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);
3343 for (self.globals.items) |global| {
3344 const sym = self.getSymbol(global);
33613345
3362 if (sym.undf()) continue;
3363 if (!sym.ext()) continue;
3346 if (sym.undf()) continue;
3347 if (!sym.ext()) continue;
33643348
3365 const sym_name = self.getSymbolName(global);
3366 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
3367 try trie.put(gpa, .{
3368 .name = sym_name,
3369 .vmaddr_offset = sym.n_value - base_address,
3370 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
3371 });
3372 }
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 });
33733356 }
33743357
33753358 try trie.finalize(gpa);
src/link/MachO/DwarfInfo.zig+3-18
......@@ -27,7 +27,7 @@ const CompileUnitIterator = struct {
2727 pub fn next(self: *CompileUnitIterator) !?CompileUnit {
2828 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..]);
3131 var creader = std.io.countingReader(stream.reader());
3232 const reader = creader.reader();
3333
......@@ -37,7 +37,7 @@ const CompileUnitIterator = struct {
3737
3838 const cu = CompileUnit{
3939 .cuh = cuh,
40 .debug_info_off = offset,
40 .debug_info_off = self.pos + offset,
4141 };
4242
4343 self.pos += (math.cast(usize, total_length) orelse return error.Overflow);
......@@ -188,7 +188,7 @@ const AbbrevEntryIterator = struct {
188188 return AbbrevEntry.null();
189189 }
190190
191 const abbrev_pos = lookup.get(kind) orelse return error.MalformedDwarf;
191 const abbrev_pos = lookup.get(kind) orelse return null;
192192 const len = try findAbbrevEntrySize(
193193 self.ctx,
194194 abbrev_pos.pos,
......@@ -290,21 +290,6 @@ pub const Attribute = struct {
290290 };
291291 }
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
308293 pub fn getAddr(self: Attribute, ctx: DwarfInfo, cuh: CompileUnit.Header) ?u64 {
309294 if (self.form != dwarf.FORM.addr) return null;
310295 const debug_info = self.getDebugInfo(ctx);
src/link/MachO/Object.zig+55-43
......@@ -50,7 +50,7 @@ reverse_symtab_lookup: []u32 = undefined,
5050/// Can be undefined as set together with in_symtab.
5151source_address_lookup: []i64 = undefined,
5252/// Can be undefined as set together with in_symtab.
53source_section_index_lookup: []i64 = undefined,
53source_section_index_lookup: []Entry = undefined,
5454/// Can be undefined as set together with in_symtab.
5555strtab_lookup: []u32 = undefined,
5656/// Can be undefined as set together with in_symtab.
......@@ -58,7 +58,7 @@ atom_by_index_table: []AtomIndex = undefined,
5858/// Can be undefined as set together with in_symtab.
5959globals_lookup: []i64 = undefined,
6060/// Can be undefined as set together with in_symtab.
61relocs_lookup: []RelocEntry = undefined,
61relocs_lookup: []Entry = undefined,
6262
6363/// All relocations sorted and flatened, sorted by address descending
6464/// per section.
......@@ -81,11 +81,14 @@ unwind_info_sect_id: ?u8 = null,
8181unwind_relocs_lookup: []Record = undefined,
8282unwind_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
8689const Record = struct {
8790 dead: bool,
88 reloc: RelocEntry,
91 reloc: Entry,
8992};
9093
9194pub fn deinit(self: *Object, gpa: Allocator) void {
......@@ -170,11 +173,11 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
170173 self.strtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);
171174 self.globals_lookup = try allocator.alloc(i64, self.in_symtab.?.len);
172175 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);
174177 // This is wasteful but we need to be able to lookup source symbol address after stripping and
175178 // allocating of sections.
176179 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
179182 for (self.symtab) |*sym| {
180183 sym.* = .{
......@@ -188,11 +191,8 @@ pub fn parse(self: *Object, allocator: Allocator, cpu_arch: std.Target.Cpu.Arch)
188191
189192 mem.set(i64, self.globals_lookup, -1);
190193 mem.set(AtomIndex, self.atom_by_index_table, 0);
191 mem.set(i64, self.source_section_index_lookup, -1);
192 mem.set(RelocEntry, self.relocs_lookup, .{
193 .start = 0,
194 .len = 0,
195 });
194 mem.set(Entry, self.source_section_index_lookup, .{});
195 mem.set(Entry, self.relocs_lookup, .{});
196196
197197 // You would expect that the symbol table is at least pre-sorted based on symbol's type:
198198 // 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)
211211 // is kind enough to specify the symbols in the correct order.
212212 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;
214216 for (sorted_all_syms.items, 0..) |sym_id, i| {
215217 const sym = sym_id.getSymbol(self);
216218
217 if (sym.sect() and self.source_section_index_lookup[sym.n_sect - 1] == -1) {
218 self.source_section_index_lookup[sym.n_sect - 1] = @intCast(i64, i);
219 if (section_index_lookup) |*lookup| {
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 }
219226 }
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
221233 self.symtab[i] = sym;
222234 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)
227239 self.strtab_lookup[i] = @intCast(u32, sym_name_len);
228240 }
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
230248 // Parse __TEXT,__eh_frame header if one exists
231249 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)
234252 self.unwind_info_sect_id = self.getSourceSectionIndexByName("__LD", "__compact_unwind");
235253 if (self.hasUnwindRecords()) {
236254 self.unwind_relocs_lookup = try allocator.alloc(Record, self.getUnwindRecords().len);
237 mem.set(Record, self.unwind_relocs_lookup, .{
238 .dead = true,
239 .reloc = .{
240 .start = 0,
241 .len = 0,
242 },
243 });
255 mem.set(Record, self.unwind_relocs_lookup, .{ .dead = true, .reloc = .{} });
244256 }
245257}
246258
......@@ -620,7 +632,7 @@ fn filterRelocs(
620632 relocs: []align(1) const macho.relocation_info,
621633 start_addr: u64,
622634 end_addr: u64,
623) RelocEntry {
635) Entry {
624636 const Predicate = struct {
625637 addr: u64,
626638
......@@ -712,9 +724,9 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
712724
713725 while (try it.next()) |record| {
714726 const offset = it.pos - record.getSize();
715 const rel_pos = switch (cpu_arch) {
727 const rel_pos: Entry = switch (cpu_arch) {
716728 .aarch64 => filterRelocs(relocs, offset, offset + record.getSize()),
717 .x86_64 => RelocEntry{ .start = 0, .len = 0 },
729 .x86_64 => .{},
718730 else => unreachable,
719731 };
720732 self.eh_frame_relocs_lookup.putAssumeCapacityNoClobber(offset, .{
......@@ -729,13 +741,12 @@ fn parseEhFrameSection(self: *Object, zld: *Zld, object_id: u32) !void {
729741 assert(rel_pos.len > 0); // TODO convert to an error as the FDE eh frame is malformed
730742 // Find function symbol that this record describes
731743 const rel = relocs[rel_pos.start..][rel_pos.len - 1];
732 const target = UnwindInfo.parseRelocTarget(
733 zld,
734 object_id,
735 rel,
736 it.data[offset..],
737 @intCast(i32, offset),
738 );
744 const target = Atom.parseRelocTarget(zld, .{
745 .object_id = object_id,
746 .rel = rel,
747 .code = it.data[offset..],
748 .base_offset = @intCast(i32, offset),
749 });
739750 break :blk target;
740751 },
741752 .x86_64 => {
......@@ -819,13 +830,12 @@ fn parseUnwindInfo(self: *Object, zld: *Zld, object_id: u32) !void {
819830
820831 // Find function symbol that this record describes
821832 const rel = relocs[rel_pos.start..][rel_pos.len - 1];
822 const target = UnwindInfo.parseRelocTarget(
823 zld,
824 object_id,
825 rel,
826 mem.asBytes(&record),
827 @intCast(i32, offset),
828 );
833 const target = Atom.parseRelocTarget(zld, .{
834 .object_id = object_id,
835 .rel = rel,
836 .code = mem.asBytes(&record),
837 .base_offset = @intCast(i32, offset),
838 });
829839 log.debug("unwind record {d} tracks {s}", .{ record_id, zld.getSymbolName(target) });
830840 if (target.getFile() != object_id) {
831841 self.unwind_relocs_lookup[record_id].dead = true;
......@@ -990,13 +1000,15 @@ pub fn getSymbolByAddress(self: Object, addr: u64, sect_hint: ?u8) u32 {
9901000 };
9911001
9921002 if (sect_hint) |sect_id| {
993 if (self.source_section_index_lookup[sect_id] > -1) {
994 const first_sym_index = @intCast(usize, 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{
996 .addr = @intCast(i64, addr),
997 });
1003 if (self.source_section_index_lookup[sect_id].len > 0) {
1004 const lookup = self.source_section_index_lookup[sect_id];
1005 const target_sym_index = @import("zld.zig").lsearch(
1006 i64,
1007 self.source_address_lookup[lookup.start..][0..lookup.len],
1008 Predicate{ .addr = @intCast(i64, addr) },
1009 );
9981010 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);
10001012 }
10011013 }
10021014 return self.getSectionAliasSymbolIndex(sect_id);
src/link/MachO/UnwindInfo.zig+18-56
......@@ -218,13 +218,12 @@ pub fn scanRelocs(zld: *Zld) !void {
218218 record_id,
219219 )) |rel| {
220220 // Personality function; add GOT pointer.
221 const target = parseRelocTarget(
222 zld,
223 @intCast(u32, object_id),
224 rel,
225 mem.asBytes(&record),
226 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
227 );
221 const target = Atom.parseRelocTarget(zld, .{
222 .object_id = @intCast(u32, object_id),
223 .rel = rel,
224 .code = mem.asBytes(&record),
225 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
226 });
228227 try Atom.addGotEntry(zld, target);
229228 }
230229 }
......@@ -266,13 +265,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
266265 @intCast(u32, object_id),
267266 record_id,
268267 )) |rel| {
269 const target = parseRelocTarget(
270 zld,
271 @intCast(u32, object_id),
272 rel,
273 mem.asBytes(&record),
274 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
275 );
268 const target = Atom.parseRelocTarget(zld, .{
269 .object_id = @intCast(u32, object_id),
270 .rel = rel,
271 .code = mem.asBytes(&record),
272 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
273 });
276274 const personality_index = info.getPersonalityFunction(target) orelse inner: {
277275 const personality_index = info.personalities_count;
278276 info.personalities[personality_index] = target;
......@@ -285,13 +283,12 @@ pub fn collect(info: *UnwindInfo, zld: *Zld) !void {
285283 }
286284
287285 if (getLsdaReloc(zld, @intCast(u32, object_id), record_id)) |rel| {
288 const target = parseRelocTarget(
289 zld,
290 @intCast(u32, object_id),
291 rel,
292 mem.asBytes(&record),
293 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
294 );
286 const target = Atom.parseRelocTarget(zld, .{
287 .object_id = @intCast(u32, object_id),
288 .rel = rel,
289 .code = mem.asBytes(&record),
290 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
291 });
295292 record.lsda = @bitCast(u64, target);
296293 }
297294 }
......@@ -668,41 +665,6 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
668665 try zld.file.pwriteAll(buffer.items, sect.offset);
669666}
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
706668fn getRelocs(zld: *Zld, object_id: u32, record_id: usize) []const macho.relocation_info {
707669 const object = &zld.objects.items[object_id];
708670 assert(object.hasUnwindRecords());
src/link/MachO/ZldAtom.zig+76-34
......@@ -15,6 +15,7 @@ const macho = std.macho;
1515const math = std.math;
1616const mem = std.mem;
1717const meta = std.meta;
18const trace = @import("../../tracy.zig").trace;
1819
1920const Allocator = mem.Allocator;
2021const Arch = std.Target.Cpu.Arch;
......@@ -163,7 +164,7 @@ pub fn scanAtomRelocs(zld: *Zld, atom_index: AtomIndex, relocs: []align(1) const
163164}
164165
165166const RelocContext = struct {
166 base_addr: u64 = 0,
167 base_addr: i64 = 0,
167168 base_offset: i32 = 0,
168169};
169170
......@@ -175,7 +176,7 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
175176 if (object.getSourceSymbol(atom.sym_index)) |source_sym| {
176177 const source_sect = object.getSourceSection(source_sym.n_sect - 1);
177178 return .{
178 .base_addr = source_sect.addr,
179 .base_addr = @intCast(i64, source_sect.addr),
179180 .base_offset = @intCast(i32, source_sym.n_value - source_sect.addr),
180181 };
181182 }
......@@ -183,55 +184,71 @@ pub fn getRelocContext(zld: *Zld, atom_index: AtomIndex) RelocContext {
183184 const sect_id = @intCast(u8, atom.sym_index - nbase);
184185 const source_sect = object.getSourceSection(sect_id);
185186 return .{
186 .base_addr = source_sect.addr,
187 .base_addr = @intCast(i64, source_sect.addr),
187188 .base_offset = 0,
188189 };
189190}
190191
191pub fn parseRelocTarget(zld: *Zld, atom_index: AtomIndex, rel: macho.relocation_info) SymbolWithLoc {
192 const atom = zld.getAtom(atom_index);
193 const object = &zld.objects.items[atom.getFile().?];
192pub fn parseRelocTarget(zld: *Zld, ctx: struct {
193 object_id: u32,
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: {
196 const sect_id = @intCast(u8, rel.r_symbolnum - 1);
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);
202 const object = &zld.objects.items[ctx.object_id];
203 log.debug("parsing reloc target in object({d}) '{s}' ", .{ ctx.object_id, object.name });
200204
201 const address_in_section = if (rel.r_pcrel == 0) blk: {
202 break :blk if (rel.r_length == 3)
203 mem.readIntLittle(u64, atom_code[rel_offset..][0..8])
205 const sym_index = if (ctx.rel.r_extern == 0) sym_index: {
206 const sect_id = @intCast(u8, ctx.rel.r_symbolnum - 1);
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])
204212 else
205 mem.readIntLittle(u32, atom_code[rel_offset..][0..4]);
213 mem.readIntLittle(u32, ctx.code[rel_offset..][0..4]);
206214 } 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)) {
208217 .X86_64_RELOC_SIGNED => 0,
209218 .X86_64_RELOC_SIGNED_1 => 1,
210219 .X86_64_RELOC_SIGNED_2 => 2,
211220 .X86_64_RELOC_SIGNED_4 => 4,
212221 else => unreachable,
213222 };
214 const addend = mem.readIntLittle(i32, atom_code[rel_offset..][0..4]);
215 const target_address = @intCast(i64, ctx.base_addr) + rel.r_address + 4 + correction + addend;
223 const addend = mem.readIntLittle(i32, ctx.code[rel_offset..][0..4]);
224 const target_address = @intCast(i64, ctx.base_addr) + ctx.rel.r_address + 4 + correction + addend;
216225 break :blk @intCast(u64, target_address);
217226 };
218227
219228 // Find containing atom
229 log.debug(" | locating symbol by address @{x} in section {d}", .{ address_in_section, sect_id });
220230 const sym_index = object.getSymbolByAddress(address_in_section, sect_id);
221231 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{
225 .sym_index = sym_index,
226 .file = atom.file,
227 };
234 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = ctx.object_id + 1 };
228235 const sym = zld.getSymbol(sym_loc);
229
230 if (sym.sect() and !sym.ext()) {
231 return sym_loc;
232 } else if (object.getGlobal(sym_index)) |global_index| {
233 return zld.globals.items[global_index];
234 } else return sym_loc;
236 const target = target: {
237 if (sym.sect() and !sym.ext()) {
238 // Make sure we are not dealing with a local alias.
239 const atom_index = object.getAtomIndexForSymbol(sym_index) orelse break :target sym_loc;
240 const atom = zld.getAtom(atom_index);
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;
235252}
236253
237254pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc, is_via_got: bool) ?AtomIndex {
......@@ -499,13 +516,25 @@ fn resolveRelocsArm64(
499516 atom.getFile(),
500517 });
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 });
503526 continue;
504527 },
505528 else => {},
506529 }
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 });
509538 const rel_offset = @intCast(u32, rel.r_address - context.base_offset);
510539
511540 log.debug(" RELA({s}) @ {x} => %{d} ('{s}') in object({?})", .{
......@@ -781,19 +810,32 @@ fn resolveRelocsX86(
781810 atom.getFile(),
782811 });
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 });
785820 continue;
786821 },
787822 else => {},
788823 }
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 });
791832 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({?})", .{
794835 @tagName(rel_type),
795836 rel.r_address,
796837 target.sym_index,
838 zld.getSymbolName(target),
797839 target.getFile(),
798840 });
799841
src/link/MachO/dead_strip.zig+53-26
......@@ -102,7 +102,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable) !void {
102102 };
103103
104104 if (is_gc_root) {
105 try roots.putNoClobber(atom_index, {});
105 _ = try roots.getOrPut(atom_index);
106106
107107 log.debug("root(ATOM({d}, %{d}, {?d}))", .{
108108 atom_index,
......@@ -130,14 +130,29 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {
130130 const header = zld.sections.items(.header)[sym.n_sect - 1];
131131 if (header.isZerofill()) return;
132132
133 const code = Atom.getAtomCode(zld, atom_index);
133134 const relocs = Atom.getAtomRelocs(zld, atom_index);
135 const ctx = Atom.getRelocContext(zld, atom_index);
136
134137 for (relocs) |rel| {
135138 const target = switch (cpu_arch) {
136139 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
137140 .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 }),
139148 },
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 }),
141156 else => unreachable,
142157 };
143158 const target_sym = zld.getSymbol(target);
......@@ -175,14 +190,29 @@ fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable) bool {
175190 const header = zld.sections.items(.header)[sym.n_sect - 1];
176191 assert(!header.isZerofill());
177192
193 const code = Atom.getAtomCode(zld, atom_index);
178194 const relocs = Atom.getAtomRelocs(zld, atom_index);
195 const ctx = Atom.getRelocContext(zld, atom_index);
196
179197 for (relocs) |rel| {
180198 const target = switch (cpu_arch) {
181199 .aarch64 => switch (@intToEnum(macho.reloc_type_arm64, rel.r_type)) {
182200 .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 }),
184208 },
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 }),
186216 else => unreachable,
187217 };
188218
......@@ -283,13 +313,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
283313 try markEhFrameRecord(zld, object_id, atom_index, alive);
284314 } else {
285315 if (UnwindInfo.getPersonalityFunctionReloc(zld, object_id, record_id)) |rel| {
286 const target = UnwindInfo.parseRelocTarget(
287 zld,
288 object_id,
289 rel,
290 mem.asBytes(&record),
291 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
292 );
316 const target = Atom.parseRelocTarget(zld, .{
317 .object_id = object_id,
318 .rel = rel,
319 .code = mem.asBytes(&record),
320 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
321 });
293322 const target_sym = zld.getSymbol(target);
294323 if (!target_sym.undf()) {
295324 const target_object = zld.objects.items[target.getFile().?];
......@@ -299,13 +328,12 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
299328 }
300329
301330 if (UnwindInfo.getLsdaReloc(zld, object_id, record_id)) |rel| {
302 const target = UnwindInfo.parseRelocTarget(
303 zld,
304 object_id,
305 rel,
306 mem.asBytes(&record),
307 @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
308 );
331 const target = Atom.parseRelocTarget(zld, .{
332 .object_id = object_id,
333 .rel = rel,
334 .code = mem.asBytes(&record),
335 .base_offset = @intCast(i32, record_id * @sizeOf(macho.compact_unwind_entry)),
336 });
309337 const target_object = zld.objects.items[target.getFile().?];
310338 const target_atom_index = target_object.getAtomIndexForSymbol(target.sym_index).?;
311339 markLive(zld, target_atom_index, alive);
......@@ -333,13 +361,12 @@ fn markEhFrameRecord(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *A
333361 // Mark FDE references which should include any referenced LSDA record
334362 const relocs = eh_frame.getRelocs(zld, object_id, fde_offset);
335363 for (relocs) |rel| {
336 const target = UnwindInfo.parseRelocTarget(
337 zld,
338 object_id,
339 rel,
340 fde.data,
341 @intCast(i32, fde_offset) + 4,
342 );
364 const target = Atom.parseRelocTarget(zld, .{
365 .object_id = object_id,
366 .rel = rel,
367 .code = fde.data,
368 .base_offset = @intCast(i32, fde_offset) + 4,
369 });
343370 const target_sym = zld.getSymbol(target);
344371 if (!target_sym.undf()) blk: {
345372 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 {
308308 },
309309 else => unreachable,
310310 }
311 const target = UnwindInfo.parseRelocTarget(
312 zld,
313 object_id,
314 rel,
315 rec.data,
316 @intCast(i32, source_offset) + 4,
317 );
311 const target = Atom.parseRelocTarget(zld, .{
312 .object_id = object_id,
313 .rel = rel,
314 .code = rec.data,
315 .base_offset = @intCast(i32, source_offset) + 4,
316 });
318317 return target;
319318 }
320319 return null;
......@@ -331,13 +330,12 @@ pub fn EhFrameRecord(comptime is_mutable: bool) type {
331330 const relocs = getRelocs(zld, object_id, ctx.source_offset);
332331
333332 for (relocs) |rel| {
334 const target = UnwindInfo.parseRelocTarget(
335 zld,
336 object_id,
337 rel,
338 rec.data,
339 @intCast(i32, ctx.source_offset) + 4,
340 );
333 const target = Atom.parseRelocTarget(zld, .{
334 .object_id = object_id,
335 .rel = rel,
336 .code = rec.data,
337 .base_offset = @intCast(i32, ctx.source_offset) + 4,
338 });
341339 const rel_offset = @intCast(u32, rel.r_address - @intCast(i32, ctx.source_offset) - 4);
342340 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
294294 .ntools = 1,
295295 });
296296 try lc_writer.writeAll(mem.asBytes(&macho.build_tool_version{
297 .tool = .LD,
297 .tool = .ZIG,
298298 .version = 0x0,
299299 }));
300300}
src/link/MachO/thunks.zig+10-1
......@@ -225,11 +225,20 @@ fn scanRelocs(
225225 break :blk @intCast(i32, source_sym.n_value - source_sect.addr);
226226 } else 0;
227227
228 const code = Atom.getAtomCode(zld, atom_index);
228229 const relocs = Atom.getAtomRelocs(zld, atom_index);
230 const ctx = Atom.getRelocContext(zld, atom_index);
231
229232 for (relocs) |rel| {
230233 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 });
233242 if (isReachable(zld, atom_index, rel, base_offset, target, allocated)) continue;
234243
235244 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 {
477477 mem.eql(u8, sectname, "__gosymtab") or
478478 mem.eql(u8, sectname, "__gopclntab"))
479479 {
480 break :blk self.getSectionByName("__DATA_CONST", "__const") orelse try self.initSection(
481 "__DATA_CONST",
482 "__const",
480 break :blk self.getSectionByName("__TEXT", sectname) orelse try self.initSection(
481 "__TEXT",
482 sectname,
483483 .{},
484484 );
485485 }
......@@ -490,15 +490,13 @@ pub const Zld = struct {
490490 mem.eql(u8, sectname, "__objc_classlist") or
491491 mem.eql(u8, sectname, "__objc_imageinfo"))
492492 {
493 break :blk self.getSectionByName("__DATA_CONST", sectname) orelse
494 try self.initSection(
493 break :blk self.getSectionByName("__DATA_CONST", sectname) orelse try self.initSection(
495494 "__DATA_CONST",
496495 sectname,
497496 .{},
498497 );
499498 } else if (mem.eql(u8, sectname, "__data")) {
500 break :blk self.getSectionByName("__DATA", "__data") orelse
501 try self.initSection(
499 break :blk self.getSectionByName("__DATA", "__data") orelse try self.initSection(
502500 "__DATA",
503501 "__data",
504502 .{},
......@@ -1886,13 +1884,9 @@ pub const Zld = struct {
18861884 if (should_rebase) {
18871885 log.debug(" ATOM({d}, %{d}, '{s}')", .{ atom_index, atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });
18881886
1889 const object = self.objects.items[atom.getFile().?];
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 };
1887 const code = Atom.getAtomCode(self, atom_index);
18951888 const relocs = Atom.getAtomRelocs(self, atom_index);
1889 const ctx = Atom.getRelocContext(self, atom_index);
18961890
18971891 for (relocs) |rel| {
18981892 switch (cpu_arch) {
......@@ -1908,12 +1902,18 @@ pub const Zld = struct {
19081902 },
19091903 else => unreachable,
19101904 }
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 });
19121912 const target_sym = self.getSymbol(target);
19131913 if (target_sym.undf()) continue;
19141914
19151915 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;
19171917 const offset = @intCast(u64, base_offset + rel_offset);
19181918 log.debug(" | rebase at {x}", .{offset});
19191919
......@@ -2023,13 +2023,9 @@ pub const Zld = struct {
20232023 };
20242024
20252025 if (should_bind) {
2026 const object = self.objects.items[atom.getFile().?];
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 };
2026 const code = Atom.getAtomCode(self, atom_index);
20322027 const relocs = Atom.getAtomRelocs(self, atom_index);
2028 const ctx = Atom.getRelocContext(self, atom_index);
20332029
20342030 for (relocs) |rel| {
20352031 switch (cpu_arch) {
......@@ -2046,15 +2042,20 @@ pub const Zld = struct {
20462042 else => unreachable,
20472043 }
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 });
20502052 const bind_sym_name = self.getSymbolName(global);
20512053 const bind_sym = self.getSymbol(global);
20522054 if (!bind_sym.undf()) continue;
20532055
20542056 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);
20562058 const offset = @intCast(u64, base_offset + rel_offset);
2057 const code = Atom.getAtomCode(self, atom_index);
20582059 const addend = mem.readIntLittle(i64, code[rel_offset..][0..8]);
20592060
20602061 const dylib_ordinal = @divTrunc(@bitCast(i16, bind_sym.n_desc), macho.N_SYMBOL_RESOLVER);
......@@ -2143,43 +2144,24 @@ pub const Zld = struct {
21432144 const exec_segment = self.segments.items[segment_index];
21442145 const base_address = exec_segment.vmaddr;
21452146
2146 if (self.options.output_mode == .Exe) {
2147 for (&[_]SymbolWithLoc{
2148 self.getEntryPoint(),
2149 self.globals.items[self.mh_execute_header_index.?],
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;
2147 for (self.globals.items) |global| {
2148 const sym = self.getSymbol(global);
2149 if (sym.undf()) continue;
2150 if (sym.n_desc == N_DEAD) continue;
21662151
2167 const sym_name = self.getSymbolName(global);
2168 log.debug(" (putting '{s}' defined at 0x{x})", .{ sym_name, sym.n_value });
2169 try trie.put(gpa, .{
2170 .name = sym_name,
2171 .vmaddr_offset = sym.n_value - base_address,
2172 .export_flags = macho.EXPORT_SYMBOL_FLAGS_KIND_REGULAR,
2173 });
2174 }
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 });
21752159 }
21762160
21772161 try trie.finalize(gpa);
21782162 }
21792163
2180 fn writeDyldInfoData(
2181 self: *Zld,
2182 ) !void {
2164 fn writeDyldInfoData(self: *Zld) !void {
21832165 const gpa = self.gpa;
21842166
21852167 var rebase = Rebase{};
......@@ -2300,9 +2282,16 @@ pub const Zld = struct {
23002282
23012283 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
23032293 fn writeFunctionStarts(self: *Zld) !void {
23042294 const text_seg_index = self.getSegmentByName("__TEXT") orelse return;
2305 const text_sect_index = self.getSectionByName("__TEXT", "__text") orelse return;
23062295 const text_seg = self.segments.items[text_seg_index];
23072296
23082297 const gpa = self.gpa;
......@@ -2310,17 +2299,18 @@ pub const Zld = struct {
23102299 // We need to sort by address first
23112300 var addresses = std.ArrayList(u64).init(gpa);
23122301 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;
2321 if (sect_id != text_sect_index) continue;
2303 for (self.objects.items) |object| {
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 }
23242314 }
23252315
23262316 std.sort.sort(u64, addresses.items, {}, asc_u64);
......@@ -2456,6 +2446,18 @@ pub const Zld = struct {
24562446 try self.writeStrtab();
24572447 }
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
24592461 fn writeSymtab(self: *Zld) !SymtabCtx {
24602462 const gpa = self.gpa;
24612463
......@@ -2466,14 +2468,12 @@ pub const Zld = struct {
24662468 for (object.atoms.items) |atom_index| {
24672469 const atom = self.getAtom(atom_index);
24682470 const sym_loc = atom.getSymbolWithLoc();
2469 const sym = self.getSymbol(sym_loc);
2470 if (sym.n_strx == 0) continue; // no name, skip
2471 if (sym.ext()) continue; // an export lands in its own symtab section, skip
2472 if (self.symbolIsTemp(sym_loc)) continue; // local temp symbol, skip
2473
2474 var out_sym = sym;
2475 out_sym.n_strx = try self.strtab.insert(gpa, self.getSymbolName(sym_loc));
2476 try locals.append(out_sym);
2471 try self.addLocalToSymtab(sym_loc, &locals);
2472
2473 var it = Atom.getInnerSymbolsIterator(self, atom_index);
2474 while (it.next()) |inner_sym_loc| {
2475 try self.addLocalToSymtab(inner_sym_loc, &locals);
2476 }
24772477 }
24782478 }
24792479