authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-24 23:06:16+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 11:39:34+02:00
log4b934b1f78c57598b5c629cff9d9a02c5e2ffe13
treedc4600f5a8c329c1675b68fe97deec19bc3e9998
parentee02517bce58063ecf087343639620454b9f387d

macho: use TableSection for stub entries in zld driver

Write thunks separately from other atoms - this can still be improved by not using atoms at all, but one thing at a time.

10 files changed, 467 insertions(+), 610 deletions(-)

src/link/MachO.zig+26-21
...@@ -1412,7 +1412,7 @@ fn writeStubHelperPreamble(self: *MachO) !void {...@@ -1412,7 +1412,7 @@ fn writeStubHelperPreamble(self: *MachO) !void {
14121412
1413 const gpa = self.base.allocator;1413 const gpa = self.base.allocator;
1414 const cpu_arch = self.base.options.target.cpu.arch;1414 const cpu_arch = self.base.options.target.cpu.arch;
1415 const size = stubs.calcStubHelperPreambleSize(cpu_arch);1415 const size = stubs.stubHelperPreambleSize(cpu_arch);
14161416
1417 var buf = try std.ArrayList(u8).initCapacity(gpa, size);1417 var buf = try std.ArrayList(u8).initCapacity(gpa, size);
1418 defer buf.deinit();1418 defer buf.deinit();
...@@ -1442,9 +1442,9 @@ fn writeStubTableEntry(self: *MachO, index: usize) !void {...@@ -1442,9 +1442,9 @@ fn writeStubTableEntry(self: *MachO, index: usize) !void {
1442 const laptr_sect_id = self.la_symbol_ptr_section_index.?;1442 const laptr_sect_id = self.la_symbol_ptr_section_index.?;
14431443
1444 const cpu_arch = self.base.options.target.cpu.arch;1444 const cpu_arch = self.base.options.target.cpu.arch;
1445 const stub_entry_size = stubs.calcStubEntrySize(cpu_arch);1445 const stub_entry_size = stubs.stubSize(cpu_arch);
1446 const stub_helper_entry_size = stubs.calcStubHelperEntrySize(cpu_arch);1446 const stub_helper_entry_size = stubs.stubHelperSize(cpu_arch);
1447 const stub_helper_preamble_size = stubs.calcStubHelperPreambleSize(cpu_arch);1447 const stub_helper_preamble_size = stubs.stubHelperPreambleSize(cpu_arch);
14481448
1449 if (self.stub_table_count_dirty) {1449 if (self.stub_table_count_dirty) {
1450 // We grow all 3 sections one by one.1450 // We grow all 3 sections one by one.
...@@ -2800,14 +2800,10 @@ fn populateMissingMetadata(self: *MachO) !void {...@@ -2800,14 +2800,10 @@ fn populateMissingMetadata(self: *MachO) !void {
2800 }2800 }
28012801
2802 if (self.stubs_section_index == null) {2802 if (self.stubs_section_index == null) {
2803 const stub_size = stubs.calcStubEntrySize(cpu_arch);2803 const stub_size = stubs.stubSize(cpu_arch);
2804 self.stubs_section_index = try self.allocateSection("__TEXT2", "__stubs", .{2804 self.stubs_section_index = try self.allocateSection("__TEXT2", "__stubs", .{
2805 .size = stub_size,2805 .size = stub_size,
2806 .alignment = switch (cpu_arch) {2806 .alignment = stubs.stubAlignment(cpu_arch),
2807 .x86_64 => 1,
2808 .aarch64 => @sizeOf(u32),
2809 else => unreachable, // unhandled architecture type
2810 },
2811 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,2807 .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
2812 .reserved2 = stub_size,2808 .reserved2 = stub_size,
2813 .prot = macho.PROT.READ | macho.PROT.EXEC,2809 .prot = macho.PROT.READ | macho.PROT.EXEC,
...@@ -3474,7 +3470,12 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -3474,7 +3470,12 @@ fn writeDyldInfoData(self: *MachO) !void {
3474 });3470 });
34753471
3476 try self.base.file.?.pwriteAll(buffer, rebase_off);3472 try self.base.file.?.pwriteAll(buffer, rebase_off);
3477 try self.populateLazyBindOffsetsInStubHelper(lazy_bind);3473 try populateLazyBindOffsetsInStubHelper(
3474 self,
3475 self.base.options.target.cpu.arch,
3476 self.base.file.?,
3477 lazy_bind,
3478 );
34783479
3479 self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off));3480 self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off));
3480 self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned));3481 self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned));
...@@ -3486,18 +3487,22 @@ fn writeDyldInfoData(self: *MachO) !void {...@@ -3486,18 +3487,22 @@ fn writeDyldInfoData(self: *MachO) !void {
3486 self.dyld_info_cmd.export_size = @as(u32, @intCast(export_size_aligned));3487 self.dyld_info_cmd.export_size = @as(u32, @intCast(export_size_aligned));
3487}3488}
34883489
3489fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void {3490pub fn populateLazyBindOffsetsInStubHelper(
3491 ctx: anytype,
3492 cpu_arch: std.Target.Cpu.Arch,
3493 file: fs.File,
3494 lazy_bind: anytype,
3495) !void {
3490 if (lazy_bind.size() == 0) return;3496 if (lazy_bind.size() == 0) return;
34913497
3492 const stub_helper_section_index = self.stub_helper_section_index.?;3498 const stub_helper_section_index = ctx.stub_helper_section_index.?;
3493 assert(self.stub_helper_preamble_allocated);3499 // assert(ctx.stub_helper_preamble_allocated);
34943500
3495 const header = self.sections.items(.header)[stub_helper_section_index];3501 const header = ctx.sections.items(.header)[stub_helper_section_index];
34963502
3497 const cpu_arch = self.base.options.target.cpu.arch;3503 const preamble_size = stubs.stubHelperPreambleSize(cpu_arch);
3498 const preamble_size = stubs.calcStubHelperPreambleSize(cpu_arch);3504 const stub_size = stubs.stubHelperSize(cpu_arch);
3499 const stub_size = stubs.calcStubHelperEntrySize(cpu_arch);3505 const stub_offset = stubs.stubOffsetInStubHelper(cpu_arch);
3500 const stub_offset = stubs.calcStubOffsetInStubHelper(cpu_arch);
3501 const base_offset = header.offset + preamble_size;3506 const base_offset = header.offset + preamble_size;
35023507
3503 for (lazy_bind.offsets.items, 0..) |bind_offset, index| {3508 for (lazy_bind.offsets.items, 0..) |bind_offset, index| {
...@@ -3505,11 +3510,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void...@@ -3505,11 +3510,11 @@ fn populateLazyBindOffsetsInStubHelper(self: *MachO, lazy_bind: LazyBind) !void
35053510
3506 log.debug("writing lazy bind offset 0x{x} ({s}) in stub helper at 0x{x}", .{3511 log.debug("writing lazy bind offset 0x{x} ({s}) in stub helper at 0x{x}", .{
3507 bind_offset,3512 bind_offset,
3508 self.getSymbolName(lazy_bind.entries.items[index].target),3513 ctx.getSymbolName(lazy_bind.entries.items[index].target),
3509 file_offset,3514 file_offset,
3510 });3515 });
35113516
3512 try self.base.file.?.pwriteAll(mem.asBytes(&bind_offset), file_offset);3517 try file.pwriteAll(mem.asBytes(&bind_offset), file_offset);
3513 }3518 }
3514}3519}
35153520
src/link/MachO/Atom.zig+44-49
...@@ -359,8 +359,6 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {...@@ -359,8 +359,6 @@ pub fn parseRelocTarget(zld: *Zld, ctx: struct {
359}359}
360360
361pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc) ?Index {361pub fn getRelocTargetAtomIndex(zld: *Zld, target: SymbolWithLoc) ?Index {
362 if (zld.getStubsAtomIndexForSymbol(target)) |stubs_atom| return stubs_atom;
363
364 if (target.getFile() == null) {362 if (target.getFile() == null) {
365 const target_sym_name = zld.getSymbolName(target);363 const target_sym_name = zld.getSymbolName(target);
366 if (mem.eql(u8, "__mh_execute_header", target_sym_name)) return null;364 if (mem.eql(u8, "__mh_execute_header", target_sym_name)) return null;
...@@ -400,7 +398,8 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma...@@ -400,7 +398,8 @@ fn scanAtomRelocsArm64(zld: *Zld, atom_index: Index, relocs: []align(1) const ma
400 switch (rel_type) {398 switch (rel_type) {
401 .ARM64_RELOC_BRANCH26 => {399 .ARM64_RELOC_BRANCH26 => {
402 // TODO rewrite relocation400 // TODO rewrite relocation
403 try addStub(zld, target);401 const sym = zld.getSymbol(target);
402 if (sym.undf()) try zld.addStubEntry(target);
404 },403 },
405 .ARM64_RELOC_GOT_LOAD_PAGE21,404 .ARM64_RELOC_GOT_LOAD_PAGE21,
406 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,405 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
...@@ -447,7 +446,8 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach...@@ -447,7 +446,8 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
447 switch (rel_type) {446 switch (rel_type) {
448 .X86_64_RELOC_BRANCH => {447 .X86_64_RELOC_BRANCH => {
449 // TODO rewrite relocation448 // TODO rewrite relocation
450 try addStub(zld, target);449 const sym = zld.getSymbol(target);
450 if (sym.undf()) try zld.addStubEntry(target);
451 },451 },
452 .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => {452 .X86_64_RELOC_GOT, .X86_64_RELOC_GOT_LOAD => {
453 // TODO rewrite relocation453 // TODO rewrite relocation
...@@ -462,23 +462,6 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach...@@ -462,23 +462,6 @@ fn scanAtomRelocsX86(zld: *Zld, atom_index: Index, relocs: []align(1) const mach
462 }462 }
463}463}
464464
465pub fn addStub(zld: *Zld, target: SymbolWithLoc) !void {
466 const target_sym = zld.getSymbol(target);
467 if (!target_sym.undf()) return;
468 if (zld.stubs_table.contains(target)) return;
469
470 const gpa = zld.gpa;
471 _ = try zld.createStubHelperAtom();
472 _ = try zld.createLazyPointerAtom();
473 const atom_index = try zld.createStubAtom();
474 const stubs_index = @as(u32, @intCast(zld.stubs.items.len));
475 try zld.stubs.append(gpa, .{
476 .target = target,
477 .atom_index = atom_index,
478 });
479 try zld.stubs_table.putNoClobber(gpa, target, stubs_index);
480}
481
482pub fn resolveRelocs(465pub fn resolveRelocs(
483 zld: *Zld,466 zld: *Zld,
484 atom_index: Index,467 atom_index: Index,
...@@ -621,16 +604,17 @@ fn resolveRelocsArm64(...@@ -621,16 +604,17 @@ fn resolveRelocsArm64(
621 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());604 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
622 break :blk source_sym.n_value + rel_offset;605 break :blk source_sym.n_value + rel_offset;
623 };606 };
624 const is_via_got = relocRequiresGot(zld, rel);
625 const is_tlv = is_tlv: {
626 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
627 const header = zld.sections.items(.header)[source_sym.n_sect - 1];
628 break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
629 };
630 const target_addr = blk: {607 const target_addr = blk: {
631 if (is_via_got) break :blk zld.getGotEntryAddress(target).?;608 if (relocRequiresGot(zld, rel)) break :blk zld.getGotEntryAddress(target).?;
632 if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())609 if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())
633 break :blk zld.getTlvPtrEntryAddress(target).?;610 break :blk zld.getTlvPtrEntryAddress(target).?;
611 if (relocIsStub(zld, rel) and zld.getSymbol(target).undf())
612 break :blk zld.getStubsEntryAddress(target).?;
613 const is_tlv = is_tlv: {
614 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
615 const header = zld.sections.items(.header)[source_sym.n_sect - 1];
616 break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
617 };
634 break :blk try getRelocTargetAddress(zld, target, is_tlv);618 break :blk try getRelocTargetAddress(zld, target, is_tlv);
635 };619 };
636620
...@@ -638,32 +622,28 @@ fn resolveRelocsArm64(...@@ -638,32 +622,28 @@ fn resolveRelocsArm64(
638622
639 switch (rel_type) {623 switch (rel_type) {
640 .ARM64_RELOC_BRANCH26 => {624 .ARM64_RELOC_BRANCH26 => {
641 const actual_target = if (zld.getStubsAtomIndexForSymbol(target)) |stub_atom_index| inner: {625 log.debug(" source {s} (object({?})), target {s}", .{
642 const stub_atom = zld.getAtom(stub_atom_index);
643 break :inner stub_atom.getSymbolWithLoc();
644 } else target;
645 log.debug(" source {s} (object({?})), target {s} (object({?}))", .{
646 zld.getSymbolName(atom.getSymbolWithLoc()),626 zld.getSymbolName(atom.getSymbolWithLoc()),
647 atom.getFile(),627 atom.getFile(),
648 zld.getSymbolName(target),628 zld.getSymbolName(target),
649 zld.getAtom(getRelocTargetAtomIndex(zld, target).?).getFile(),
650 });629 });
651630
652 const displacement = if (Relocation.calcPcRelativeDisplacementArm64(631 const displacement = if (Relocation.calcPcRelativeDisplacementArm64(
653 source_addr,632 source_addr,
654 zld.getSymbol(actual_target).n_value,633 target_addr,
655 )) |disp| blk: {634 )) |disp| blk: {
656 log.debug(" | target_addr = 0x{x}", .{zld.getSymbol(actual_target).n_value});635 log.debug(" | target_addr = 0x{x}", .{target_addr});
657 break :blk disp;636 break :blk disp;
658 } else |_| blk: {637 } else |_| blk: {
659 const thunk_index = zld.thunk_table.get(atom_index).?;638 const thunk_index = zld.thunk_table.get(atom_index).?;
660 const thunk = zld.thunks.items[thunk_index];639 const thunk = zld.thunks.items[thunk_index];
661 const thunk_sym = zld.getSymbol(thunk.getTrampolineForSymbol(640 const thunk_sym_loc = if (zld.getSymbol(target).undf())
662 zld,641 thunk.getTrampoline(zld, .stub, target).?
663 actual_target,642 else
664 ).?);643 thunk.getTrampoline(zld, .atom, target).?;
665 log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_sym.n_value});644 const thunk_addr = zld.getSymbol(thunk_sym_loc).n_value;
666 break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_sym.n_value);645 log.debug(" | target_addr = 0x{x} (thunk)", .{thunk_addr});
646 break :blk try Relocation.calcPcRelativeDisplacementArm64(source_addr, thunk_addr);
667 };647 };
668648
669 const code = atom_code[rel_offset..][0..4];649 const code = atom_code[rel_offset..][0..4];
...@@ -920,16 +900,17 @@ fn resolveRelocsX86(...@@ -920,16 +900,17 @@ fn resolveRelocsX86(
920 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());900 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
921 break :blk source_sym.n_value + rel_offset;901 break :blk source_sym.n_value + rel_offset;
922 };902 };
923 const is_via_got = relocRequiresGot(zld, rel);
924 const is_tlv = is_tlv: {
925 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
926 const header = zld.sections.items(.header)[source_sym.n_sect - 1];
927 break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
928 };
929 const target_addr = blk: {903 const target_addr = blk: {
930 if (is_via_got) break :blk zld.getGotEntryAddress(target).?;904 if (relocRequiresGot(zld, rel)) break :blk zld.getGotEntryAddress(target).?;
905 if (relocIsStub(zld, rel) and zld.getSymbol(target).undf())
906 break :blk zld.getStubsEntryAddress(target).?;
931 if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())907 if (relocIsTlv(zld, rel) and zld.getSymbol(target).undf())
932 break :blk zld.getTlvPtrEntryAddress(target).?;908 break :blk zld.getTlvPtrEntryAddress(target).?;
909 const is_tlv = is_tlv: {
910 const source_sym = zld.getSymbol(atom.getSymbolWithLoc());
911 const header = zld.sections.items(.header)[source_sym.n_sect - 1];
912 break :is_tlv header.type() == macho.S_THREAD_LOCAL_VARIABLES;
913 };
933 break :blk try getRelocTargetAddress(zld, target, is_tlv);914 break :blk try getRelocTargetAddress(zld, target, is_tlv);
934 };915 };
935916
...@@ -1117,3 +1098,17 @@ pub fn relocIsTlv(zld: *Zld, rel: macho.relocation_info) bool {...@@ -1117,3 +1098,17 @@ pub fn relocIsTlv(zld: *Zld, rel: macho.relocation_info) bool {
1117 else => unreachable,1098 else => unreachable,
1118 }1099 }
1119}1100}
1101
1102pub fn relocIsStub(zld: *Zld, rel: macho.relocation_info) bool {
1103 switch (zld.options.target.cpu.arch) {
1104 .aarch64 => switch (@as(macho.reloc_type_arm64, @enumFromInt(rel.r_type))) {
1105 .ARM64_RELOC_BRANCH26 => return true,
1106 else => return false,
1107 },
1108 .x86_64 => switch (@as(macho.reloc_type_x86_64, @enumFromInt(rel.r_type))) {
1109 .X86_64_RELOC_BRANCH => return true,
1110 else => return false,
1111 },
1112 else => unreachable,
1113 }
1114}
src/link/MachO/Object.zig+7-8
...@@ -20,7 +20,6 @@ const trace = @import("../../tracy.zig").trace;...@@ -20,7 +20,6 @@ const trace = @import("../../tracy.zig").trace;
2020
21const Allocator = mem.Allocator;21const Allocator = mem.Allocator;
22const Atom = @import("Atom.zig");22const Atom = @import("Atom.zig");
23const AtomIndex = @import("zld.zig").AtomIndex;
24const DwarfInfo = @import("DwarfInfo.zig");23const DwarfInfo = @import("DwarfInfo.zig");
25const LoadCommandIterator = macho.LoadCommandIterator;24const LoadCommandIterator = macho.LoadCommandIterator;
26const MachO = @import("../MachO.zig");25const MachO = @import("../MachO.zig");
...@@ -55,7 +54,7 @@ source_section_index_lookup: []Entry = undefined,...@@ -55,7 +54,7 @@ source_section_index_lookup: []Entry = undefined,
55/// Can be undefined as set together with in_symtab.54/// Can be undefined as set together with in_symtab.
56strtab_lookup: []u32 = undefined,55strtab_lookup: []u32 = undefined,
57/// Can be undefined as set together with in_symtab.56/// Can be undefined as set together with in_symtab.
58atom_by_index_table: []?AtomIndex = undefined,57atom_by_index_table: []?Atom.Index = undefined,
59/// Can be undefined as set together with in_symtab.58/// Can be undefined as set together with in_symtab.
60globals_lookup: []i64 = undefined,59globals_lookup: []i64 = undefined,
61/// Can be undefined as set together with in_symtab.60/// Can be undefined as set together with in_symtab.
...@@ -71,8 +70,8 @@ section_relocs_lookup: std.ArrayListUnmanaged(u32) = .{},...@@ -71,8 +70,8 @@ section_relocs_lookup: std.ArrayListUnmanaged(u32) = .{},
71/// Data-in-code records sorted by address.70/// Data-in-code records sorted by address.
72data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},71data_in_code: std.ArrayListUnmanaged(macho.data_in_code_entry) = .{},
7372
74atoms: std.ArrayListUnmanaged(AtomIndex) = .{},73atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
75exec_atoms: std.ArrayListUnmanaged(AtomIndex) = .{},74exec_atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
7675
77eh_frame_sect_id: ?u8 = null,76eh_frame_sect_id: ?u8 = null,
78eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},77eh_frame_relocs_lookup: std.AutoArrayHashMapUnmanaged(u32, Record) = .{},
...@@ -156,7 +155,7 @@ pub fn parse(self: *Object, allocator: Allocator) !void {...@@ -156,7 +155,7 @@ pub fn parse(self: *Object, allocator: Allocator) !void {
156 self.reverse_symtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);155 self.reverse_symtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);
157 self.strtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);156 self.strtab_lookup = try allocator.alloc(u32, self.in_symtab.?.len);
158 self.globals_lookup = try allocator.alloc(i64, self.in_symtab.?.len);157 self.globals_lookup = try allocator.alloc(i64, self.in_symtab.?.len);
159 self.atom_by_index_table = try allocator.alloc(?AtomIndex, self.in_symtab.?.len + nsects);158 self.atom_by_index_table = try allocator.alloc(?Atom.Index, self.in_symtab.?.len + nsects);
160 self.relocs_lookup = try allocator.alloc(Entry, self.in_symtab.?.len + nsects);159 self.relocs_lookup = try allocator.alloc(Entry, self.in_symtab.?.len + nsects);
161 // This is wasteful but we need to be able to lookup source symbol address after stripping and160 // This is wasteful but we need to be able to lookup source symbol address after stripping and
162 // allocating of sections.161 // allocating of sections.
...@@ -572,7 +571,7 @@ fn createAtomFromSubsection(...@@ -572,7 +571,7 @@ fn createAtomFromSubsection(
572 size: u64,571 size: u64,
573 alignment: u32,572 alignment: u32,
574 out_sect_id: u8,573 out_sect_id: u8,
575) !AtomIndex {574) !Atom.Index {
576 const gpa = zld.gpa;575 const gpa = zld.gpa;
577 const atom_index = try zld.createEmptyAtom(sym_index, size, alignment);576 const atom_index = try zld.createEmptyAtom(sym_index, size, alignment);
578 const atom = zld.getAtomPtr(atom_index);577 const atom = zld.getAtomPtr(atom_index);
...@@ -652,7 +651,7 @@ fn parseRelocs(self: *Object, gpa: Allocator, sect_id: u8) !void {...@@ -652,7 +651,7 @@ fn parseRelocs(self: *Object, gpa: Allocator, sect_id: u8) !void {
652 self.section_relocs_lookup.items[sect_id] = start;651 self.section_relocs_lookup.items[sect_id] = start;
653}652}
654653
655fn cacheRelocs(self: *Object, zld: *Zld, atom_index: AtomIndex) !void {654fn cacheRelocs(self: *Object, zld: *Zld, atom_index: Atom.Index) !void {
656 const atom = zld.getAtom(atom_index);655 const atom = zld.getAtom(atom_index);
657656
658 const source_sect_id = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {657 const source_sect_id = if (self.getSourceSymbol(atom.sym_index)) |source_sym| blk: {
...@@ -1059,7 +1058,7 @@ pub fn getGlobal(self: Object, sym_index: u32) ?u32 {...@@ -1059,7 +1058,7 @@ pub fn getGlobal(self: Object, sym_index: u32) ?u32 {
1059 return @as(u32, @intCast(self.globals_lookup[sym_index]));1058 return @as(u32, @intCast(self.globals_lookup[sym_index]));
1060}1059}
10611060
1062pub fn getAtomIndexForSymbol(self: Object, sym_index: u32) ?AtomIndex {1061pub fn getAtomIndexForSymbol(self: Object, sym_index: u32) ?Atom.Index {
1063 return self.atom_by_index_table[sym_index];1062 return self.atom_by_index_table[sym_index];
1064}1063}
10651064
src/link/MachO/Relocation.zig+1-1
...@@ -62,7 +62,7 @@ pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {...@@ -62,7 +62,7 @@ pub fn getTargetBaseAddress(self: Relocation, macho_file: *MachO) ?u64 {
62 const index = macho_file.stub_table.lookup.get(self.target) orelse return null;62 const index = macho_file.stub_table.lookup.get(self.target) orelse return null;
63 const header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];63 const header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];
64 return header.addr +64 return header.addr +
65 index * @import("stubs.zig").calcStubEntrySize(macho_file.base.options.target.cpu.arch);65 index * @import("stubs.zig").stubSize(macho_file.base.options.target.cpu.arch);
66 }66 }
67 switch (self.type) {67 switch (self.type) {
68 .got, .got_page, .got_pageoff => {68 .got, .got_page, .got_pageoff => {
src/link/MachO/UnwindInfo.zig+1-1
...@@ -577,7 +577,7 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {...@@ -577,7 +577,7 @@ pub fn write(info: *UnwindInfo, zld: *Zld) !void {
577 const seg_id = zld.sections.items(.segment_index)[sect_id];577 const seg_id = zld.sections.items(.segment_index)[sect_id];
578 const seg = zld.segments.items[seg_id];578 const seg = zld.segments.items[seg_id];
579579
580 const text_sect_id = zld.getSectionByName("__TEXT", "__text").?;580 const text_sect_id = zld.text_section_index.?;
581 const text_sect = zld.sections.items(.header)[text_sect_id];581 const text_sect = zld.sections.items(.header)[text_sect_id];
582582
583 var personalities: [max_personalities]u32 = undefined;583 var personalities: [max_personalities]u32 = undefined;
src/link/MachO/dead_strip.zig+4-5
...@@ -9,7 +9,6 @@ const math = std.math;...@@ -9,7 +9,6 @@ const math = std.math;
9const mem = std.mem;9const mem = std.mem;
1010
11const Allocator = mem.Allocator;11const Allocator = mem.Allocator;
12const AtomIndex = @import("zld.zig").AtomIndex;
13const Atom = @import("Atom.zig");12const Atom = @import("Atom.zig");
14const MachO = @import("../MachO.zig");13const MachO = @import("../MachO.zig");
15const SymbolWithLoc = MachO.SymbolWithLoc;14const SymbolWithLoc = MachO.SymbolWithLoc;
...@@ -19,7 +18,7 @@ const Zld = @import("zld.zig").Zld;...@@ -19,7 +18,7 @@ const Zld = @import("zld.zig").Zld;
1918
20const N_DEAD = @import("zld.zig").N_DEAD;19const N_DEAD = @import("zld.zig").N_DEAD;
2120
22const AtomTable = std.AutoHashMap(AtomIndex, void);21const AtomTable = std.AutoHashMap(Atom.Index, void);
2322
24pub fn gcAtoms(zld: *Zld, resolver: *const SymbolResolver) !void {23pub fn gcAtoms(zld: *Zld, resolver: *const SymbolResolver) !void {
25 const gpa = zld.gpa;24 const gpa = zld.gpa;
...@@ -127,7 +126,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable, resolver: *const SymbolResolver) !...@@ -127,7 +126,7 @@ fn collectRoots(zld: *Zld, roots: *AtomTable, resolver: *const SymbolResolver) !
127 }126 }
128}127}
129128
130fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {129fn markLive(zld: *Zld, atom_index: Atom.Index, alive: *AtomTable) void {
131 if (alive.contains(atom_index)) return;130 if (alive.contains(atom_index)) return;
132131
133 const atom = zld.getAtom(atom_index);132 const atom = zld.getAtom(atom_index);
...@@ -191,7 +190,7 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {...@@ -191,7 +190,7 @@ fn markLive(zld: *Zld, atom_index: AtomIndex, alive: *AtomTable) void {
191 }190 }
192}191}
193192
194fn refersLive(zld: *Zld, atom_index: AtomIndex, alive: AtomTable) bool {193fn refersLive(zld: *Zld, atom_index: Atom.Index, alive: AtomTable) bool {
195 const atom = zld.getAtom(atom_index);194 const atom = zld.getAtom(atom_index);
196 const sym_loc = atom.getSymbolWithLoc();195 const sym_loc = atom.getSymbolWithLoc();
197196
...@@ -359,7 +358,7 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {...@@ -359,7 +358,7 @@ fn markUnwindRecords(zld: *Zld, object_id: u32, alive: *AtomTable) !void {
359 }358 }
360}359}
361360
362fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: AtomIndex, alive: *AtomTable) !void {361fn markEhFrameRecords(zld: *Zld, object_id: u32, atom_index: Atom.Index, alive: *AtomTable) !void {
363 const cpu_arch = zld.options.target.cpu.arch;362 const cpu_arch = zld.options.target.cpu.arch;
364 const object = &zld.objects.items[object_id];363 const object = &zld.objects.items[object_id];
365 var it = object.getEhFrameRecordsIterator();364 var it = object.getEhFrameRecordsIterator();
src/link/MachO/eh_frame.zig-1
...@@ -7,7 +7,6 @@ const leb = std.leb;...@@ -7,7 +7,6 @@ const leb = std.leb;
7const log = std.log.scoped(.eh_frame);7const log = std.log.scoped(.eh_frame);
88
9const Allocator = mem.Allocator;9const Allocator = mem.Allocator;
10const AtomIndex = @import("zld.zig").AtomIndex;
11const Atom = @import("Atom.zig");10const Atom = @import("Atom.zig");
12const MachO = @import("../MachO.zig");11const MachO = @import("../MachO.zig");
13const Relocation = @import("Relocation.zig");12const Relocation = @import("Relocation.zig");
src/link/MachO/stubs.zig+12-4
...@@ -3,7 +3,7 @@ const aarch64 = @import("../../arch/aarch64/bits.zig");...@@ -3,7 +3,7 @@ const aarch64 = @import("../../arch/aarch64/bits.zig");
33
4const Relocation = @import("Relocation.zig");4const Relocation = @import("Relocation.zig");
55
6pub inline fn calcStubHelperPreambleSize(cpu_arch: std.Target.Cpu.Arch) u5 {6pub inline fn stubHelperPreambleSize(cpu_arch: std.Target.Cpu.Arch) u8 {
7 return switch (cpu_arch) {7 return switch (cpu_arch) {
8 .x86_64 => 15,8 .x86_64 => 15,
9 .aarch64 => 6 * @sizeOf(u32),9 .aarch64 => 6 * @sizeOf(u32),
...@@ -11,7 +11,7 @@ pub inline fn calcStubHelperPreambleSize(cpu_arch: std.Target.Cpu.Arch) u5 {...@@ -11,7 +11,7 @@ pub inline fn calcStubHelperPreambleSize(cpu_arch: std.Target.Cpu.Arch) u5 {
11 };11 };
12}12}
1313
14pub inline fn calcStubHelperEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {14pub inline fn stubHelperSize(cpu_arch: std.Target.Cpu.Arch) u8 {
15 return switch (cpu_arch) {15 return switch (cpu_arch) {
16 .x86_64 => 10,16 .x86_64 => 10,
17 .aarch64 => 3 * @sizeOf(u32),17 .aarch64 => 3 * @sizeOf(u32),
...@@ -19,7 +19,7 @@ pub inline fn calcStubHelperEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {...@@ -19,7 +19,7 @@ pub inline fn calcStubHelperEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {
19 };19 };
20}20}
2121
22pub inline fn calcStubEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {22pub inline fn stubSize(cpu_arch: std.Target.Cpu.Arch) u8 {
23 return switch (cpu_arch) {23 return switch (cpu_arch) {
24 .x86_64 => 6,24 .x86_64 => 6,
25 .aarch64 => 3 * @sizeOf(u32),25 .aarch64 => 3 * @sizeOf(u32),
...@@ -27,7 +27,15 @@ pub inline fn calcStubEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {...@@ -27,7 +27,15 @@ pub inline fn calcStubEntrySize(cpu_arch: std.Target.Cpu.Arch) u4 {
27 };27 };
28}28}
2929
30pub inline fn calcStubOffsetInStubHelper(cpu_arch: std.Target.Cpu.Arch) u4 {30pub inline fn stubAlignment(cpu_arch: std.Target.Cpu.Arch) u8 {
31 return switch (cpu_arch) {
32 .x86_64 => 0,
33 .aarch64 => 2,
34 else => unreachable, // unhandled architecture type
35 };
36}
37
38pub inline fn stubOffsetInStubHelper(cpu_arch: std.Target.Cpu.Arch) u8 {
31 return switch (cpu_arch) {39 return switch (cpu_arch) {
32 .x86_64 => 1,40 .x86_64 => 1,
33 .aarch64 => 2 * @sizeOf(u32),41 .aarch64 => 2 * @sizeOf(u32),
src/link/MachO/thunks.zig+78-85
...@@ -16,14 +16,11 @@ const aarch64 = @import("../../arch/aarch64/bits.zig");...@@ -16,14 +16,11 @@ const aarch64 = @import("../../arch/aarch64/bits.zig");
1616
17const Allocator = mem.Allocator;17const Allocator = mem.Allocator;
18const Atom = @import("Atom.zig");18const Atom = @import("Atom.zig");
19const AtomIndex = @import("zld.zig").AtomIndex;
20const MachO = @import("../MachO.zig");19const MachO = @import("../MachO.zig");
21const Relocation = @import("Relocation.zig");20const Relocation = @import("Relocation.zig");
22const SymbolWithLoc = MachO.SymbolWithLoc;21const SymbolWithLoc = MachO.SymbolWithLoc;
23const Zld = @import("zld.zig").Zld;22const Zld = @import("zld.zig").Zld;
2423
25pub const ThunkIndex = u32;
26
27/// Branch instruction has 26 bits immediate but 4 byte aligned.24/// Branch instruction has 26 bits immediate but 4 byte aligned.
28const jump_bits = @bitSizeOf(i28);25const jump_bits = @bitSizeOf(i28);
2926
...@@ -36,21 +33,35 @@ const max_distance = (1 << (jump_bits - 1));...@@ -36,21 +33,35 @@ const max_distance = (1 << (jump_bits - 1));
36const max_allowed_distance = max_distance - 0x500_000;33const max_allowed_distance = max_distance - 0x500_000;
3734
38pub const Thunk = struct {35pub const Thunk = struct {
39 start_index: AtomIndex,36 start_index: Atom.Index,
40 len: u32,37 len: u32,
4138
42 lookup: std.AutoArrayHashMapUnmanaged(SymbolWithLoc, AtomIndex) = .{},39 targets: std.MultiArrayList(Target) = .{},
40 lookup: std.AutoHashMapUnmanaged(Target, u32) = .{},
41
42 pub const Tag = enum {
43 stub,
44 atom,
45 };
46
47 pub const Target = struct {
48 tag: Tag,
49 target: SymbolWithLoc,
50 };
51
52 pub const Index = u32;
4353
44 pub fn deinit(self: *Thunk, gpa: Allocator) void {54 pub fn deinit(self: *Thunk, gpa: Allocator) void {
55 self.targets.deinit(gpa);
45 self.lookup.deinit(gpa);56 self.lookup.deinit(gpa);
46 }57 }
4758
48 pub fn getStartAtomIndex(self: Thunk) AtomIndex {59 pub fn getStartAtomIndex(self: Thunk) Atom.Index {
49 assert(self.len != 0);60 assert(self.len != 0);
50 return self.start_index;61 return self.start_index;
51 }62 }
5263
53 pub fn getEndAtomIndex(self: Thunk) AtomIndex {64 pub fn getEndAtomIndex(self: Thunk) Atom.Index {
54 assert(self.len != 0);65 assert(self.len != 0);
55 return self.start_index + self.len - 1;66 return self.start_index + self.len - 1;
56 }67 }
...@@ -63,10 +74,9 @@ pub const Thunk = struct {...@@ -63,10 +74,9 @@ pub const Thunk = struct {
63 return @alignOf(u32);74 return @alignOf(u32);
64 }75 }
6576
66 pub fn getTrampolineForSymbol(self: Thunk, zld: *Zld, target: SymbolWithLoc) ?SymbolWithLoc {77 pub fn getTrampoline(self: Thunk, zld: *Zld, tag: Tag, target: SymbolWithLoc) ?SymbolWithLoc {
67 const atom_index = self.lookup.get(target) orelse return null;78 const atom_index = self.lookup.get(.{ .tag = tag, .target = target }) orelse return null;
68 const atom = zld.getAtom(atom_index);79 return zld.getAtom(atom_index).getSymbolWithLoc();
69 return atom.getSymbolWithLoc();
70 }80 }
71};81};
7282
...@@ -96,7 +106,7 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void {...@@ -96,7 +106,7 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void {
96 }106 }
97 }107 }
98108
99 var allocated = std.AutoHashMap(AtomIndex, void).init(gpa);109 var allocated = std.AutoHashMap(Atom.Index, void).init(gpa);
100 defer allocated.deinit();110 defer allocated.deinit();
101 try allocated.ensureTotalCapacity(atom_count);111 try allocated.ensureTotalCapacity(atom_count);
102112
...@@ -180,7 +190,7 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void {...@@ -180,7 +190,7 @@ pub fn createThunks(zld: *Zld, sect_id: u8) !void {
180190
181fn allocateThunk(191fn allocateThunk(
182 zld: *Zld,192 zld: *Zld,
183 thunk_index: ThunkIndex,193 thunk_index: Thunk.Index,
184 base_offset: u64,194 base_offset: u64,
185 header: *macho.section_64,195 header: *macho.section_64,
186) void {196) void {
...@@ -214,10 +224,10 @@ fn allocateThunk(...@@ -214,10 +224,10 @@ fn allocateThunk(
214224
215fn scanRelocs(225fn scanRelocs(
216 zld: *Zld,226 zld: *Zld,
217 atom_index: AtomIndex,227 atom_index: Atom.Index,
218 allocated: std.AutoHashMap(AtomIndex, void),228 allocated: std.AutoHashMap(Atom.Index, void),
219 thunk_index: ThunkIndex,229 thunk_index: Thunk.Index,
220 group_end: AtomIndex,230 group_end: Atom.Index,
221) !void {231) !void {
222 const atom = zld.getAtom(atom_index);232 const atom = zld.getAtom(atom_index);
223 const object = zld.objects.items[atom.getFile().?];233 const object = zld.objects.items[atom.getFile().?];
...@@ -253,40 +263,43 @@ fn scanRelocs(...@@ -253,40 +263,43 @@ fn scanRelocs(
253263
254 const gpa = zld.gpa;264 const gpa = zld.gpa;
255 const target_sym = zld.getSymbol(target);265 const target_sym = zld.getSymbol(target);
256
257 const actual_target: SymbolWithLoc = if (target_sym.undf()) blk: {
258 const stub_atom_index = zld.getStubsAtomIndexForSymbol(target).?;
259 break :blk .{ .sym_index = zld.getAtom(stub_atom_index).sym_index };
260 } else target;
261
262 const thunk = &zld.thunks.items[thunk_index];266 const thunk = &zld.thunks.items[thunk_index];
263 const gop = try thunk.lookup.getOrPut(gpa, actual_target);267
268 const tag: Thunk.Tag = if (target_sym.undf()) .stub else .atom;
269 const thunk_target: Thunk.Target = .{ .tag = tag, .target = target };
270 const gop = try thunk.lookup.getOrPut(gpa, thunk_target);
264 if (!gop.found_existing) {271 if (!gop.found_existing) {
265 const thunk_atom_index = try createThunkAtom(zld);272 gop.value_ptr.* = try pushThunkAtom(zld, thunk, group_end);
266 gop.value_ptr.* = thunk_atom_index;273 try thunk.targets.append(gpa, thunk_target);
274 }
267275
268 const thunk_atom = zld.getAtomPtr(thunk_atom_index);276 try zld.thunk_table.put(gpa, atom_index, thunk_index);
269 const end_atom_index = if (thunk.len == 0) group_end else thunk.getEndAtomIndex();277 }
270 const end_atom = zld.getAtomPtr(end_atom_index);278}
271279
272 if (end_atom.next_index) |first_after_index| {280fn pushThunkAtom(zld: *Zld, thunk: *Thunk, group_end: Atom.Index) !Atom.Index {
273 const first_after_atom = zld.getAtomPtr(first_after_index);281 const thunk_atom_index = try createThunkAtom(zld);
274 first_after_atom.prev_index = thunk_atom_index;
275 thunk_atom.next_index = first_after_index;
276 }
277282
278 end_atom.next_index = thunk_atom_index;283 const thunk_atom = zld.getAtomPtr(thunk_atom_index);
279 thunk_atom.prev_index = end_atom_index;284 const end_atom_index = if (thunk.len == 0) group_end else thunk.getEndAtomIndex();
285 const end_atom = zld.getAtomPtr(end_atom_index);
280286
281 if (thunk.len == 0) {287 if (end_atom.next_index) |first_after_index| {
282 thunk.start_index = thunk_atom_index;288 const first_after_atom = zld.getAtomPtr(first_after_index);
283 }289 first_after_atom.prev_index = thunk_atom_index;
290 thunk_atom.next_index = first_after_index;
291 }
284292
285 thunk.len += 1;293 end_atom.next_index = thunk_atom_index;
286 }294 thunk_atom.prev_index = end_atom_index;
287295
288 try zld.thunk_table.put(gpa, atom_index, thunk_index);296 if (thunk.len == 0) {
297 thunk.start_index = thunk_atom_index;
289 }298 }
299
300 thunk.len += 1;
301
302 return thunk_atom_index;
290}303}
291304
292inline fn relocNeedsThunk(rel: macho.relocation_info) bool {305inline fn relocNeedsThunk(rel: macho.relocation_info) bool {
...@@ -296,13 +309,13 @@ inline fn relocNeedsThunk(rel: macho.relocation_info) bool {...@@ -296,13 +309,13 @@ inline fn relocNeedsThunk(rel: macho.relocation_info) bool {
296309
297fn isReachable(310fn isReachable(
298 zld: *Zld,311 zld: *Zld,
299 atom_index: AtomIndex,312 atom_index: Atom.Index,
300 rel: macho.relocation_info,313 rel: macho.relocation_info,
301 base_offset: i32,314 base_offset: i32,
302 target: SymbolWithLoc,315 target: SymbolWithLoc,
303 allocated: std.AutoHashMap(AtomIndex, void),316 allocated: std.AutoHashMap(Atom.Index, void),
304) bool {317) bool {
305 if (zld.getStubsAtomIndexForSymbol(target)) |_| return false;318 if (zld.stubs_table.lookup.contains(target)) return false;
306319
307 const source_atom = zld.getAtom(atom_index);320 const source_atom = zld.getAtom(atom_index);
308 const source_sym = zld.getSymbol(source_atom.getSymbolWithLoc());321 const source_sym = zld.getSymbol(source_atom.getSymbolWithLoc());
...@@ -317,8 +330,7 @@ fn isReachable(...@@ -317,8 +330,7 @@ fn isReachable(
317 if (!allocated.contains(target_atom_index)) return false;330 if (!allocated.contains(target_atom_index)) return false;
318331
319 const source_addr = source_sym.n_value + @as(u32, @intCast(rel.r_address - base_offset));332 const source_addr = source_sym.n_value + @as(u32, @intCast(rel.r_address - base_offset));
320 const is_via_got = Atom.relocRequiresGot(zld, rel);333 const target_addr = if (Atom.relocRequiresGot(zld, rel))
321 const target_addr = if (is_via_got)
322 zld.getGotEntryAddress(target).?334 zld.getGotEntryAddress(target).?
323 else335 else
324 Atom.getRelocTargetAddress(zld, target, false) catch unreachable;336 Atom.getRelocTargetAddress(zld, target, false) catch unreachable;
...@@ -328,50 +340,31 @@ fn isReachable(...@@ -328,50 +340,31 @@ fn isReachable(
328 return true;340 return true;
329}341}
330342
331fn createThunkAtom(zld: *Zld) !AtomIndex {343fn createThunkAtom(zld: *Zld) !Atom.Index {
332 const sym_index = try zld.allocateSymbol();344 const sym_index = try zld.allocateSymbol();
333 const atom_index = try zld.createEmptyAtom(sym_index, @sizeOf(u32) * 3, 2);345 const atom_index = try zld.createEmptyAtom(sym_index, @sizeOf(u32) * 3, 2);
334 const sym = zld.getSymbolPtr(.{ .sym_index = sym_index });346 const sym = zld.getSymbolPtr(.{ .sym_index = sym_index });
335 sym.n_type = macho.N_SECT;347 sym.n_type = macho.N_SECT;
336348 sym.n_sect = zld.text_section_index.? + 1;
337 const sect_id = zld.getSectionByName("__TEXT", "__text") orelse unreachable;
338 sym.n_sect = sect_id + 1;
339
340 return atom_index;349 return atom_index;
341}350}
342351
343fn getThunkIndex(zld: *Zld, atom_index: AtomIndex) ?ThunkIndex {352pub fn writeThunkCode(zld: *Zld, thunk: *const Thunk, writer: anytype) !void {
344 const atom = zld.getAtom(atom_index);353 const slice = thunk.targets.slice();
345 const sym = zld.getSymbol(atom.getSymbolWithLoc());354 for (thunk.getStartAtomIndex()..thunk.getEndAtomIndex(), 0..) |atom_index, target_index| {
346 for (zld.thunks.items, 0..) |thunk, i| {355 const atom = zld.getAtom(@intCast(atom_index));
347 if (thunk.len == 0) continue;356 const sym = zld.getSymbol(atom.getSymbolWithLoc());
348357 const source_addr = sym.n_value;
349 const thunk_atom_index = thunk.getStartAtomIndex();358 const tag = slice.items(.tag)[target_index];
350 const thunk_atom = zld.getAtom(thunk_atom_index);359 const target = slice.items(.target)[target_index];
351 const thunk_sym = zld.getSymbol(thunk_atom.getSymbolWithLoc());360 const target_addr = switch (tag) {
352 const start_addr = thunk_sym.n_value;361 .stub => zld.getStubsEntryAddress(target).?,
353 const end_addr = start_addr + thunk.getSize();362 .atom => zld.getSymbol(target).n_value,
354363 };
355 if (start_addr <= sym.n_value and sym.n_value < end_addr) {364 const pages = Relocation.calcNumberOfPages(source_addr, target_addr);
356 return @as(u32, @intCast(i));365 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
357 }366 const off = try Relocation.calcPageOffset(target_addr, .arithmetic);
367 try writer.writeIntLittle(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32());
368 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
358 }369 }
359 return null;
360}
361
362pub fn writeThunkCode(zld: *Zld, atom_index: AtomIndex, writer: anytype) !void {
363 const atom = zld.getAtom(atom_index);
364 const sym = zld.getSymbol(atom.getSymbolWithLoc());
365 const source_addr = sym.n_value;
366 const thunk = zld.thunks.items[getThunkIndex(zld, atom_index).?];
367 const target_addr = for (thunk.lookup.keys()) |target| {
368 const target_atom_index = thunk.lookup.get(target).?;
369 if (atom_index == target_atom_index) break zld.getSymbol(target).n_value;
370 } else unreachable;
371
372 const pages = Relocation.calcNumberOfPages(source_addr, target_addr);
373 try writer.writeIntLittle(u32, aarch64.Instruction.adrp(.x16, pages).toU32());
374 const off = try Relocation.calcPageOffset(target_addr, .arithmetic);
375 try writer.writeIntLittle(u32, aarch64.Instruction.add(.x16, .x16, off, false).toU32());
376 try writer.writeIntLittle(u32, aarch64.Instruction.br(.x16).toU32());
377}370}
src/link/MachO/zld.zig+294-435
...@@ -15,7 +15,7 @@ const eh_frame = @import("eh_frame.zig");...@@ -15,7 +15,7 @@ const eh_frame = @import("eh_frame.zig");
15const fat = @import("fat.zig");15const fat = @import("fat.zig");
16const link = @import("../../link.zig");16const link = @import("../../link.zig");
17const load_commands = @import("load_commands.zig");17const load_commands = @import("load_commands.zig");
18const stub_helpers = @import("stubs.zig");18const stubs = @import("stubs.zig");
19const thunks = @import("thunks.zig");19const thunks = @import("thunks.zig");
20const trace = @import("../../tracy.zig").trace;20const trace = @import("../../tracy.zig").trace;
2121
...@@ -67,8 +67,12 @@ pub const Zld = struct {...@@ -67,8 +67,12 @@ pub const Zld = struct {
67 segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},67 segments: std.ArrayListUnmanaged(macho.segment_command_64) = .{},
68 sections: std.MultiArrayList(Section) = .{},68 sections: std.MultiArrayList(Section) = .{},
6969
70 text_section_index: ?u8 = null,
70 got_section_index: ?u8 = null,71 got_section_index: ?u8 = null,
71 tlv_ptr_section_index: ?u8 = null,72 tlv_ptr_section_index: ?u8 = null,
73 stubs_section_index: ?u8 = null,
74 stub_helper_section_index: ?u8 = null,
75 la_symbol_ptr_section_index: ?u8 = null,
7276
73 locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},77 locals: std.ArrayListUnmanaged(macho.nlist_64) = .{},
74 globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},78 globals: std.ArrayListUnmanaged(SymbolWithLoc) = .{},
...@@ -78,17 +82,14 @@ pub const Zld = struct {...@@ -78,17 +82,14 @@ pub const Zld = struct {
78 dso_handle_index: ?u32 = null,82 dso_handle_index: ?u32 = null,
79 dyld_stub_binder_index: ?u32 = null,83 dyld_stub_binder_index: ?u32 = null,
80 dyld_private_atom_index: ?Atom.Index = null,84 dyld_private_atom_index: ?Atom.Index = null,
81 stub_helper_preamble_sym_index: ?u32 = null,
8285
83 strtab: StringTable(.strtab) = .{},86 strtab: StringTable(.strtab) = .{},
8487
85 tlv_ptr_table: TableSection(SymbolWithLoc) = .{},88 tlv_ptr_table: TableSection(SymbolWithLoc) = .{},
86 got_table: TableSection(SymbolWithLoc) = .{},89 got_table: TableSection(SymbolWithLoc) = .{},
90 stubs_table: TableSection(SymbolWithLoc) = .{},
8791
88 stubs: std.ArrayListUnmanaged(IndirectPointer) = .{},92 thunk_table: std.AutoHashMapUnmanaged(Atom.Index, thunks.Thunk.Index) = .{},
89 stubs_table: std.AutoHashMapUnmanaged(SymbolWithLoc, u32) = .{},
90
91 thunk_table: std.AutoHashMapUnmanaged(AtomIndex, thunks.ThunkIndex) = .{},
92 thunks: std.ArrayListUnmanaged(thunks.Thunk) = .{},93 thunks: std.ArrayListUnmanaged(thunks.Thunk) = .{},
9394
94 atoms: std.ArrayListUnmanaged(Atom) = .{},95 atoms: std.ArrayListUnmanaged(Atom) = .{},
...@@ -113,15 +114,18 @@ pub const Zld = struct {...@@ -113,15 +114,18 @@ pub const Zld = struct {
113 }114 }
114115
115 if (sect.isCode()) {116 if (sect.isCode()) {
116 break :blk self.getSectionByName("__TEXT", "__text") orelse try self.initSection(117 if (self.text_section_index == null) {
117 "__TEXT",118 self.text_section_index = try self.initSection(
118 "__text",119 "__TEXT",
119 .{120 "__text",
120 .flags = macho.S_REGULAR |121 .{
121 macho.S_ATTR_PURE_INSTRUCTIONS |122 .flags = macho.S_REGULAR |
122 macho.S_ATTR_SOME_INSTRUCTIONS,123 macho.S_ATTR_PURE_INSTRUCTIONS |
123 },124 macho.S_ATTR_SOME_INSTRUCTIONS,
124 );125 },
126 );
127 }
128 break :blk self.text_section_index.?;
125 }129 }
126130
127 if (sect.isDebug()) {131 if (sect.isDebug()) {
...@@ -228,7 +232,7 @@ pub const Zld = struct {...@@ -228,7 +232,7 @@ pub const Zld = struct {
228 return res;232 return res;
229 }233 }
230234
231 pub fn addAtomToSection(self: *Zld, atom_index: AtomIndex) void {235 pub fn addAtomToSection(self: *Zld, atom_index: Atom.Index) void {
232 const atom = self.getAtomPtr(atom_index);236 const atom = self.getAtomPtr(atom_index);
233 const sym = self.getSymbol(atom.getSymbolWithLoc());237 const sym = self.getSymbol(atom.getSymbolWithLoc());
234 var section = self.sections.get(sym.n_sect - 1);238 var section = self.sections.get(sym.n_sect - 1);
...@@ -244,9 +248,9 @@ pub const Zld = struct {...@@ -244,9 +248,9 @@ pub const Zld = struct {
244 self.sections.set(sym.n_sect - 1, section);248 self.sections.set(sym.n_sect - 1, section);
245 }249 }
246250
247 pub fn createEmptyAtom(self: *Zld, sym_index: u32, size: u64, alignment: u32) !AtomIndex {251 pub fn createEmptyAtom(self: *Zld, sym_index: u32, size: u64, alignment: u32) !Atom.Index {
248 const gpa = self.gpa;252 const gpa = self.gpa;
249 const index = @as(AtomIndex, @intCast(self.atoms.items.len));253 const index = @as(Atom.Index, @intCast(self.atoms.items.len));
250 const atom = try self.atoms.addOne(gpa);254 const atom = try self.atoms.addOne(gpa);
251 atom.* = .{255 atom.* = .{
252 .sym_index = 0,256 .sym_index = 0,
...@@ -280,190 +284,6 @@ pub const Zld = struct {...@@ -280,190 +284,6 @@ pub const Zld = struct {
280 self.addAtomToSection(atom_index);284 self.addAtomToSection(atom_index);
281 }285 }
282286
283 fn createStubHelperPreambleAtom(self: *Zld) !void {
284 if (self.dyld_stub_binder_index == null) return;
285
286 const cpu_arch = self.options.target.cpu.arch;
287 const size: u64 = switch (cpu_arch) {
288 .x86_64 => 15,
289 .aarch64 => 6 * @sizeOf(u32),
290 else => unreachable,
291 };
292 const alignment: u32 = switch (cpu_arch) {
293 .x86_64 => 0,
294 .aarch64 => 2,
295 else => unreachable,
296 };
297 const sym_index = try self.allocateSymbol();
298 const atom_index = try self.createEmptyAtom(sym_index, size, alignment);
299 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
300 sym.n_type = macho.N_SECT;
301
302 const sect_id = self.getSectionByName("__TEXT", "__stub_helper") orelse
303 try self.initSection("__TEXT", "__stub_helper", .{
304 .flags = macho.S_REGULAR |
305 macho.S_ATTR_PURE_INSTRUCTIONS |
306 macho.S_ATTR_SOME_INSTRUCTIONS,
307 });
308 sym.n_sect = sect_id + 1;
309
310 self.stub_helper_preamble_sym_index = sym_index;
311
312 self.addAtomToSection(atom_index);
313 }
314
315 fn writeStubHelperPreambleCode(self: *Zld, writer: anytype) !void {
316 const cpu_arch = self.options.target.cpu.arch;
317 const source_addr = blk: {
318 const sym = self.getSymbol(.{ .sym_index = self.stub_helper_preamble_sym_index.? });
319 break :blk sym.n_value;
320 };
321 const dyld_private_addr = blk: {
322 const atom = self.getAtom(self.dyld_private_atom_index.?);
323 const sym = self.getSymbol(atom.getSymbolWithLoc());
324 break :blk sym.n_value;
325 };
326 const dyld_stub_binder_got_addr = blk: {
327 const sym_loc = self.globals.items[self.dyld_stub_binder_index.?];
328 break :blk self.getGotEntryAddress(sym_loc).?;
329 };
330 try stub_helpers.writeStubHelperPreambleCode(.{
331 .cpu_arch = cpu_arch,
332 .source_addr = source_addr,
333 .dyld_private_addr = dyld_private_addr,
334 .dyld_stub_binder_got_addr = dyld_stub_binder_got_addr,
335 }, writer);
336 }
337
338 pub fn createStubHelperAtom(self: *Zld) !AtomIndex {
339 const cpu_arch = self.options.target.cpu.arch;
340 const stub_size = stub_helpers.calcStubHelperEntrySize(cpu_arch);
341 const alignment: u2 = switch (cpu_arch) {
342 .x86_64 => 0,
343 .aarch64 => 2,
344 else => unreachable,
345 };
346
347 const sym_index = try self.allocateSymbol();
348 const atom_index = try self.createEmptyAtom(sym_index, stub_size, alignment);
349 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
350 sym.n_sect = macho.N_SECT;
351
352 const sect_id = self.getSectionByName("__TEXT", "__stub_helper").?;
353 sym.n_sect = sect_id + 1;
354
355 self.addAtomToSection(atom_index);
356
357 return atom_index;
358 }
359
360 fn writeStubHelperCode(self: *Zld, atom_index: AtomIndex, writer: anytype) !void {
361 const cpu_arch = self.options.target.cpu.arch;
362 const source_addr = blk: {
363 const atom = self.getAtom(atom_index);
364 const sym = self.getSymbol(atom.getSymbolWithLoc());
365 break :blk sym.n_value;
366 };
367 const target_addr = blk: {
368 const sym = self.getSymbol(.{ .sym_index = self.stub_helper_preamble_sym_index.? });
369 break :blk sym.n_value;
370 };
371 try stub_helpers.writeStubHelperCode(.{
372 .cpu_arch = cpu_arch,
373 .source_addr = source_addr,
374 .target_addr = target_addr,
375 }, writer);
376 }
377
378 pub fn createLazyPointerAtom(self: *Zld) !AtomIndex {
379 const sym_index = try self.allocateSymbol();
380 const atom_index = try self.createEmptyAtom(sym_index, @sizeOf(u64), 3);
381 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
382 sym.n_type = macho.N_SECT;
383
384 const sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr") orelse
385 try self.initSection("__DATA", "__la_symbol_ptr", .{
386 .flags = macho.S_LAZY_SYMBOL_POINTERS,
387 });
388 sym.n_sect = sect_id + 1;
389
390 self.addAtomToSection(atom_index);
391
392 return atom_index;
393 }
394
395 fn writeLazyPointer(self: *Zld, stub_helper_index: u32, writer: anytype) !void {
396 const target_addr = blk: {
397 const sect_id = self.getSectionByName("__TEXT", "__stub_helper").?;
398 var atom_index = self.sections.items(.first_atom_index)[sect_id].?;
399 var count: u32 = 0;
400 while (count < stub_helper_index + 1) : (count += 1) {
401 const atom = self.getAtom(atom_index);
402 if (atom.next_index) |next_index| {
403 atom_index = next_index;
404 }
405 }
406 const atom = self.getAtom(atom_index);
407 const sym = self.getSymbol(atom.getSymbolWithLoc());
408 break :blk sym.n_value;
409 };
410 try writer.writeIntLittle(u64, target_addr);
411 }
412
413 pub fn createStubAtom(self: *Zld) !AtomIndex {
414 const cpu_arch = self.options.target.cpu.arch;
415 const alignment: u2 = switch (cpu_arch) {
416 .x86_64 => 0,
417 .aarch64 => 2,
418 else => unreachable, // unhandled architecture type
419 };
420 const stub_size = stub_helpers.calcStubEntrySize(cpu_arch);
421 const sym_index = try self.allocateSymbol();
422 const atom_index = try self.createEmptyAtom(sym_index, stub_size, alignment);
423 const sym = self.getSymbolPtr(.{ .sym_index = sym_index });
424 sym.n_type = macho.N_SECT;
425
426 const sect_id = self.getSectionByName("__TEXT", "__stubs") orelse
427 try self.initSection("__TEXT", "__stubs", .{
428 .flags = macho.S_SYMBOL_STUBS |
429 macho.S_ATTR_PURE_INSTRUCTIONS |
430 macho.S_ATTR_SOME_INSTRUCTIONS,
431 .reserved2 = stub_size,
432 });
433 sym.n_sect = sect_id + 1;
434
435 self.addAtomToSection(atom_index);
436
437 return atom_index;
438 }
439
440 fn writeStubCode(self: *Zld, atom_index: AtomIndex, stub_index: u32, writer: anytype) !void {
441 const cpu_arch = self.options.target.cpu.arch;
442 const source_addr = blk: {
443 const atom = self.getAtom(atom_index);
444 const sym = self.getSymbol(atom.getSymbolWithLoc());
445 break :blk sym.n_value;
446 };
447 const target_addr = blk: {
448 // TODO: cache this at stub atom creation; they always go in pairs anyhow
449 const la_sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr").?;
450 var la_atom_index = self.sections.items(.first_atom_index)[la_sect_id].?;
451 var count: u32 = 0;
452 while (count < stub_index) : (count += 1) {
453 const la_atom = self.getAtom(la_atom_index);
454 la_atom_index = la_atom.next_index.?;
455 }
456 const atom = self.getAtom(la_atom_index);
457 const sym = self.getSymbol(atom.getSymbolWithLoc());
458 break :blk sym.n_value;
459 };
460 try stub_helpers.writeStubCode(.{
461 .cpu_arch = cpu_arch,
462 .source_addr = source_addr,
463 .target_addr = target_addr,
464 }, writer);
465 }
466
467 fn createTentativeDefAtoms(self: *Zld) !void {287 fn createTentativeDefAtoms(self: *Zld) !void {
468 const gpa = self.gpa;288 const gpa = self.gpa;
469289
...@@ -818,7 +638,6 @@ pub const Zld = struct {...@@ -818,7 +638,6 @@ pub const Zld = struct {
818638
819 self.tlv_ptr_table.deinit(gpa);639 self.tlv_ptr_table.deinit(gpa);
820 self.got_table.deinit(gpa);640 self.got_table.deinit(gpa);
821 self.stubs.deinit(gpa);
822 self.stubs_table.deinit(gpa);641 self.stubs_table.deinit(gpa);
823 self.thunk_table.deinit(gpa);642 self.thunk_table.deinit(gpa);
824643
...@@ -953,6 +772,27 @@ pub const Zld = struct {...@@ -953,6 +772,27 @@ pub const Zld = struct {
953 }772 }
954 }773 }
955774
775 pub fn addStubEntry(self: *Zld, target: SymbolWithLoc) !void {
776 if (self.stubs_table.lookup.contains(target)) return;
777 _ = try self.stubs_table.allocateEntry(self.gpa, target);
778 if (self.stubs_section_index == null) {
779 self.stubs_section_index = try self.initSection("__TEXT", "__stubs", .{
780 .flags = macho.S_SYMBOL_STUBS |
781 macho.S_ATTR_PURE_INSTRUCTIONS |
782 macho.S_ATTR_SOME_INSTRUCTIONS,
783 .reserved2 = stubs.stubSize(self.options.target.cpu.arch),
784 });
785 self.stub_helper_section_index = try self.initSection("__TEXT", "__stub_helper", .{
786 .flags = macho.S_REGULAR |
787 macho.S_ATTR_PURE_INSTRUCTIONS |
788 macho.S_ATTR_SOME_INSTRUCTIONS,
789 });
790 self.la_symbol_ptr_section_index = try self.initSection("__DATA", "__la_symbol_ptr", .{
791 .flags = macho.S_LAZY_SYMBOL_POINTERS,
792 });
793 }
794 }
795
956 fn allocateSpecialSymbols(self: *Zld) !void {796 fn allocateSpecialSymbols(self: *Zld) !void {
957 for (&[_]?u32{797 for (&[_]?u32{
958 self.dso_handle_index,798 self.dso_handle_index,
...@@ -984,88 +824,85 @@ pub const Zld = struct {...@@ -984,88 +824,85 @@ pub const Zld = struct {
984824
985 var atom_index = first_atom_index orelse continue;825 var atom_index = first_atom_index orelse continue;
986826
987 var buffer = std.ArrayList(u8).init(gpa);827 var buffer = try gpa.alloc(u8, math.cast(usize, header.size) orelse return error.Overflow);
988 defer buffer.deinit();828 defer gpa.free(buffer);
989 try buffer.ensureTotalCapacity(math.cast(usize, header.size) orelse return error.Overflow);829 @memset(buffer, 0); // TODO with NOPs
990830
991 log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() });831 log.debug("writing atoms in {s},{s}", .{ header.segName(), header.sectName() });
992832
993 var count: u32 = 0;833 while (true) {
994 while (true) : (count += 1) {
995 const atom = self.getAtom(atom_index);834 const atom = self.getAtom(atom_index);
996 const this_sym = self.getSymbol(atom.getSymbolWithLoc());835 if (atom.getFile()) |file| {
997 const padding_size: usize = if (atom.next_index) |next_index| blk: {836 const this_sym = self.getSymbol(atom.getSymbolWithLoc());
998 const next_sym = self.getSymbol(self.getAtom(next_index).getSymbolWithLoc());837 const padding_size: usize = if (atom.next_index) |next_index| blk: {
999 const size = next_sym.n_value - (this_sym.n_value + atom.size);838 const next_sym = self.getSymbol(self.getAtom(next_index).getSymbolWithLoc());
1000 break :blk math.cast(usize, size) orelse return error.Overflow;839 const size = next_sym.n_value - (this_sym.n_value + atom.size);
1001 } else 0;840 break :blk math.cast(usize, size) orelse return error.Overflow;
1002841 } else 0;
1003 log.debug(" (adding ATOM(%{d}, '{s}') from object({?}) to buffer)", .{842
1004 atom.sym_index,843 log.debug(" (adding ATOM(%{d}, '{s}') from object({d}) to buffer)", .{
1005 self.getSymbolName(atom.getSymbolWithLoc()),844 atom.sym_index,
1006 atom.getFile(),845 self.getSymbolName(atom.getSymbolWithLoc()),
1007 });846 file,
1008 if (padding_size > 0) {847 });
1009 log.debug(" (with padding {x})", .{padding_size});848 if (padding_size > 0) {
1010 }849 log.debug(" (with padding {x})", .{padding_size});
1011
1012 const offset = buffer.items.len;
1013
1014 // TODO: move writing synthetic sections into a separate function
1015 if (atom_index == self.dyld_private_atom_index.?) {
1016 buffer.appendSliceAssumeCapacity(&[_]u8{0} ** @sizeOf(u64));
1017 } else if (atom.getFile() == null) outer: {
1018 switch (header.type()) {
1019 macho.S_NON_LAZY_SYMBOL_POINTERS => unreachable,
1020 macho.S_THREAD_LOCAL_VARIABLE_POINTERS => unreachable,
1021 macho.S_LAZY_SYMBOL_POINTERS => {
1022 try self.writeLazyPointer(count, buffer.writer());
1023 },
1024 else => {
1025 if (self.stub_helper_preamble_sym_index) |sym_index| {
1026 if (sym_index == atom.sym_index) {
1027 try self.writeStubHelperPreambleCode(buffer.writer());
1028 break :outer;
1029 }
1030 }
1031 if (header.type() == macho.S_SYMBOL_STUBS) {
1032 try self.writeStubCode(atom_index, count, buffer.writer());
1033 } else if (mem.eql(u8, header.sectName(), "__stub_helper")) {
1034 try self.writeStubHelperCode(atom_index, buffer.writer());
1035 } else if (header.isCode()) {
1036 // A thunk
1037 try thunks.writeThunkCode(self, atom_index, buffer.writer());
1038 } else unreachable;
1039 },
1040 }850 }
1041 } else {851
852 const offset = this_sym.n_value - header.addr;
853 log.debug(" (at offset 0x{x})", .{offset});
854
1042 const code = Atom.getAtomCode(self, atom_index);855 const code = Atom.getAtomCode(self, atom_index);
1043 const relocs = Atom.getAtomRelocs(self, atom_index);856 const relocs = Atom.getAtomRelocs(self, atom_index);
1044 const size = math.cast(usize, atom.size) orelse return error.Overflow;857 const size = math.cast(usize, atom.size) orelse return error.Overflow;
1045 buffer.appendSliceAssumeCapacity(code);858 @memcpy(buffer[offset .. offset + size], code);
1046 try Atom.resolveRelocs(859 try Atom.resolveRelocs(
1047 self,860 self,
1048 atom_index,861 atom_index,
1049 buffer.items[offset..][0..size],862 buffer[offset..][0..size],
1050 relocs,863 relocs,
1051 );864 );
1052 }865 }
1053866
1054 var i: usize = 0;
1055 while (i < padding_size) : (i += 1) {
1056 // TODO with NOPs
1057 buffer.appendAssumeCapacity(0);
1058 }
1059
1060 if (atom.next_index) |next_index| {867 if (atom.next_index) |next_index| {
1061 atom_index = next_index;868 atom_index = next_index;
1062 } else {869 } else break;
1063 assert(buffer.items.len == header.size);
1064 log.debug(" (writing at file offset 0x{x})", .{header.offset});
1065 try self.file.pwriteAll(buffer.items, header.offset);
1066 break;
1067 }
1068 }870 }
871
872 log.debug(" (writing at file offset 0x{x})", .{header.offset});
873 try self.file.pwriteAll(buffer, header.offset);
874 }
875 }
876
877 fn writeDyldPrivateAtom(self: *Zld) !void {
878 const atom_index = self.dyld_private_atom_index orelse return;
879 const atom = self.getAtom(atom_index);
880 const sym = self.getSymbol(atom.getSymbolWithLoc());
881 const sect_id = self.getSectionByName("__DATA", "__data").?;
882 const header = self.sections.items(.header)[sect_id];
883 const offset = sym.n_value - header.addr + header.offset;
884 log.debug("writing __dyld_private at offset 0x{x}", .{offset});
885 const buffer: [@sizeOf(u64)]u8 = [_]u8{0} ** @sizeOf(u64);
886 try self.file.pwriteAll(&buffer, offset);
887 }
888
889 fn writeThunks(self: *Zld) !void {
890 assert(self.requiresThunks());
891 const gpa = self.gpa;
892
893 const sect_id = self.text_section_index orelse return;
894 const header = self.sections.items(.header)[sect_id];
895
896 for (self.thunks.items, 0..) |*thunk, i| {
897 if (thunk.getSize() == 0) continue;
898 var buffer = try std.ArrayList(u8).initCapacity(gpa, thunk.getSize());
899 defer buffer.deinit();
900 try thunks.writeThunkCode(self, thunk, buffer.writer());
901 const thunk_atom = self.getAtom(thunk.getStartAtomIndex());
902 const thunk_sym = self.getSymbol(thunk_atom.getSymbolWithLoc());
903 const offset = thunk_sym.n_value - header.addr + header.offset;
904 log.debug("writing thunk({d}) at offset 0x{x}", .{ i, offset });
905 try self.file.pwriteAll(buffer.items, offset);
1069 }906 }
1070 }907 }
1071908
...@@ -1077,10 +914,94 @@ pub const Zld = struct {...@@ -1077,10 +914,94 @@ pub const Zld = struct {
1077 const sym = self.getSymbol(entry);914 const sym = self.getSymbol(entry);
1078 buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable;915 buffer.writer().writeIntLittle(u64, sym.n_value) catch unreachable;
1079 }916 }
1080 log.debug("writing .got contents at file offset 0x{x}", .{header.offset});917 log.debug("writing __DATA_CONST,__got contents at file offset 0x{x}", .{header.offset});
1081 try self.file.pwriteAll(buffer.items, header.offset);918 try self.file.pwriteAll(buffer.items, header.offset);
1082 }919 }
1083920
921 fn writeStubs(self: *Zld) !void {
922 const gpa = self.gpa;
923 const cpu_arch = self.options.target.cpu.arch;
924 const stubs_header = self.sections.items(.header)[self.stubs_section_index.?];
925 const la_symbol_ptr_header = self.sections.items(.header)[self.la_symbol_ptr_section_index.?];
926
927 var buffer = try std.ArrayList(u8).initCapacity(gpa, stubs_header.size);
928 defer buffer.deinit();
929
930 for (0..self.stubs_table.count()) |index| {
931 try stubs.writeStubCode(.{
932 .cpu_arch = cpu_arch,
933 .source_addr = stubs_header.addr + stubs.stubSize(cpu_arch) * index,
934 .target_addr = la_symbol_ptr_header.addr + index * @sizeOf(u64),
935 }, buffer.writer());
936 }
937
938 log.debug("writing __TEXT,__stubs contents at file offset 0x{x}", .{stubs_header.offset});
939 try self.file.pwriteAll(buffer.items, stubs_header.offset);
940 }
941
942 fn writeStubHelpers(self: *Zld) !void {
943 const gpa = self.gpa;
944 const cpu_arch = self.options.target.cpu.arch;
945 const stub_helper_header = self.sections.items(.header)[self.stub_helper_section_index.?];
946
947 var buffer = try std.ArrayList(u8).initCapacity(gpa, stub_helper_header.size);
948 defer buffer.deinit();
949
950 {
951 const dyld_private_addr = blk: {
952 const atom = self.getAtom(self.dyld_private_atom_index.?);
953 const sym = self.getSymbol(atom.getSymbolWithLoc());
954 break :blk sym.n_value;
955 };
956 const dyld_stub_binder_got_addr = blk: {
957 const sym_loc = self.globals.items[self.dyld_stub_binder_index.?];
958 break :blk self.getGotEntryAddress(sym_loc).?;
959 };
960 try stubs.writeStubHelperPreambleCode(.{
961 .cpu_arch = cpu_arch,
962 .source_addr = stub_helper_header.addr,
963 .dyld_private_addr = dyld_private_addr,
964 .dyld_stub_binder_got_addr = dyld_stub_binder_got_addr,
965 }, buffer.writer());
966 }
967
968 for (0..self.stubs_table.count()) |index| {
969 const source_addr = stub_helper_header.addr + stubs.stubHelperPreambleSize(cpu_arch) +
970 stubs.stubHelperSize(cpu_arch) * index;
971 try stubs.writeStubHelperCode(.{
972 .cpu_arch = cpu_arch,
973 .source_addr = source_addr,
974 .target_addr = stub_helper_header.addr,
975 }, buffer.writer());
976 }
977
978 log.debug("writing __TEXT,__stub_helper contents at file offset 0x{x}", .{
979 stub_helper_header.offset,
980 });
981 try self.file.pwriteAll(buffer.items, stub_helper_header.offset);
982 }
983
984 fn writeLaSymbolPtrs(self: *Zld) !void {
985 const gpa = self.gpa;
986 const cpu_arch = self.options.target.cpu.arch;
987 const la_symbol_ptr_header = self.sections.items(.header)[self.la_symbol_ptr_section_index.?];
988 const stub_helper_header = self.sections.items(.header)[self.stub_helper_section_index.?];
989
990 var buffer = try std.ArrayList(u8).initCapacity(gpa, la_symbol_ptr_header.size);
991 defer buffer.deinit();
992
993 for (0..self.stubs_table.count()) |index| {
994 const target_addr = stub_helper_header.addr + stubs.stubHelperPreambleSize(cpu_arch) +
995 stubs.stubHelperSize(cpu_arch) * index;
996 buffer.writer().writeIntLittle(u64, target_addr) catch unreachable;
997 }
998
999 log.debug("writing __DATA,__la_symbol_ptr contents at file offset 0x{x}", .{
1000 la_symbol_ptr_header.offset,
1001 });
1002 try self.file.pwriteAll(buffer.items, la_symbol_ptr_header.offset);
1003 }
1004
1084 fn pruneAndSortSections(self: *Zld) !void {1005 fn pruneAndSortSections(self: *Zld) !void {
1085 const Entry = struct {1006 const Entry = struct {
1086 index: u8,1007 index: u8,
...@@ -1105,6 +1026,18 @@ pub const Zld = struct {...@@ -1105,6 +1026,18 @@ pub const Zld = struct {
1105 section.header.sectName(),1026 section.header.sectName(),
1106 section.first_atom_index,1027 section.first_atom_index,
1107 });1028 });
1029 for (&[_]*?u8{
1030 &self.text_section_index,
1031 &self.got_section_index,
1032 &self.tlv_ptr_section_index,
1033 &self.stubs_section_index,
1034 &self.stub_helper_section_index,
1035 &self.la_symbol_ptr_section_index,
1036 }) |maybe_index| {
1037 if (maybe_index.* != null and maybe_index.*.? == index) {
1038 maybe_index.* = null;
1039 }
1040 }
1108 continue;1041 continue;
1109 }1042 }
1110 entries.appendAssumeCapacity(.{ .index = @intCast(index) });1043 entries.appendAssumeCapacity(.{ .index = @intCast(index) });
...@@ -1127,8 +1060,12 @@ pub const Zld = struct {...@@ -1127,8 +1060,12 @@ pub const Zld = struct {
1127 }1060 }
11281061
1129 for (&[_]*?u8{1062 for (&[_]*?u8{
1063 &self.text_section_index,
1130 &self.got_section_index,1064 &self.got_section_index,
1131 &self.tlv_ptr_section_index,1065 &self.tlv_ptr_section_index,
1066 &self.stubs_section_index,
1067 &self.stub_helper_section_index,
1068 &self.la_symbol_ptr_section_index,
1132 }) |maybe_index| {1069 }) |maybe_index| {
1133 if (maybe_index.*) |*index| {1070 if (maybe_index.*) |*index| {
1134 index.* = backlinks[index.*];1071 index.* = backlinks[index.*];
...@@ -1140,8 +1077,8 @@ pub const Zld = struct {...@@ -1140,8 +1077,8 @@ pub const Zld = struct {
1140 const slice = self.sections.slice();1077 const slice = self.sections.slice();
1141 for (slice.items(.header), 0..) |*header, sect_id| {1078 for (slice.items(.header), 0..) |*header, sect_id| {
1142 if (header.size == 0) continue;1079 if (header.size == 0) continue;
1143 if (self.requiresThunks()) {1080 if (self.text_section_index) |txt| {
1144 if (header.isCode() and !(header.type() == macho.S_SYMBOL_STUBS) and !mem.eql(u8, header.sectName(), "__stub_helper")) continue;1081 if (txt == sect_id and self.requiresThunks()) continue;
1145 }1082 }
11461083
1147 var atom_index = slice.items(.first_atom_index)[sect_id] orelse continue;1084 var atom_index = slice.items(.first_atom_index)[sect_id] orelse continue;
...@@ -1167,15 +1104,9 @@ pub const Zld = struct {...@@ -1167,15 +1104,9 @@ pub const Zld = struct {
1167 }1104 }
1168 }1105 }
11691106
1170 if (self.requiresThunks()) {1107 if (self.text_section_index != null and self.requiresThunks()) {
1171 for (slice.items(.header), 0..) |header, sect_id| {1108 // Create jump/branch range extenders if needed.
1172 if (!header.isCode()) continue;1109 try thunks.createThunks(self, self.text_section_index.?);
1173 if (header.type() == macho.S_SYMBOL_STUBS) continue;
1174 if (mem.eql(u8, header.sectName(), "__stub_helper")) continue;
1175
1176 // Create jump/branch range extenders if needed.
1177 try thunks.createThunks(self, @as(u8, @intCast(sect_id)));
1178 }
1179 }1110 }
11801111
1181 // Update offsets of all symbols contained within each Atom.1112 // Update offsets of all symbols contained within each Atom.
...@@ -1224,6 +1155,27 @@ pub const Zld = struct {...@@ -1224,6 +1155,27 @@ pub const Zld = struct {
1224 header.size = self.tlv_ptr_table.count() * @sizeOf(u64);1155 header.size = self.tlv_ptr_table.count() * @sizeOf(u64);
1225 header.@"align" = 3;1156 header.@"align" = 3;
1226 }1157 }
1158
1159 const cpu_arch = self.options.target.cpu.arch;
1160
1161 if (self.stubs_section_index) |sect_id| {
1162 const header = &self.sections.items(.header)[sect_id];
1163 header.size = self.stubs_table.count() * stubs.stubSize(cpu_arch);
1164 header.@"align" = stubs.stubAlignment(cpu_arch);
1165 }
1166
1167 if (self.stub_helper_section_index) |sect_id| {
1168 const header = &self.sections.items(.header)[sect_id];
1169 header.size = self.stubs_table.count() * stubs.stubHelperSize(cpu_arch) +
1170 stubs.stubHelperPreambleSize(cpu_arch);
1171 header.@"align" = stubs.stubAlignment(cpu_arch);
1172 }
1173
1174 if (self.la_symbol_ptr_section_index) |sect_id| {
1175 const header = &self.sections.items(.header)[sect_id];
1176 header.size = self.stubs_table.count() * @sizeOf(u64);
1177 header.@"align" = 3;
1178 }
1227 }1179 }
12281180
1229 fn allocateSegments(self: *Zld) !void {1181 fn allocateSegments(self: *Zld) !void {
...@@ -1453,36 +1405,13 @@ pub const Zld = struct {...@@ -1453,36 +1405,13 @@ pub const Zld = struct {
1453 try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table);1405 try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.got_table);
1454 }1406 }
14551407
1456 const slice = self.sections.slice();1408 // Next, unpack __la_symbol_ptr entries
14571409 if (self.la_symbol_ptr_section_index) |sect_id| {
1458 // Next, unpact lazy pointers1410 try MachO.collectRebaseDataFromTableSection(self.gpa, self, sect_id, rebase, self.stubs_table);
1459 // TODO: save la_ptr in a container so that we can re-use the helper
1460 if (self.getSectionByName("__DATA", "__la_symbol_ptr")) |sect_id| {
1461 const segment_index = slice.items(.segment_index)[sect_id];
1462 const seg = self.getSegment(sect_id);
1463 var atom_index = slice.items(.first_atom_index)[sect_id].?;
1464
1465 try rebase.entries.ensureUnusedCapacity(self.gpa, self.stubs.items.len);
1466
1467 while (true) {
1468 const atom = self.getAtom(atom_index);
1469 const sym = self.getSymbol(atom.getSymbolWithLoc());
1470 const base_offset = sym.n_value - seg.vmaddr;
1471
1472 log.debug(" | rebase at {x}", .{base_offset});
1473
1474 rebase.entries.appendAssumeCapacity(.{
1475 .offset = base_offset,
1476 .segment_id = segment_index,
1477 });
1478
1479 if (atom.next_index) |next_index| {
1480 atom_index = next_index;
1481 } else break;
1482 }
1483 }1411 }
14841412
1485 // Finally, unpack the rest.1413 // Finally, unpack the rest.
1414 const slice = self.sections.slice();
1486 for (slice.items(.header), 0..) |header, sect_id| {1415 for (slice.items(.header), 0..) |header, sect_id| {
1487 switch (header.type()) {1416 switch (header.type()) {
1488 macho.S_LITERAL_POINTERS,1417 macho.S_LITERAL_POINTERS,
...@@ -1679,51 +1608,8 @@ pub const Zld = struct {...@@ -1679,51 +1608,8 @@ pub const Zld = struct {
1679 }1608 }
16801609
1681 fn collectLazyBindData(self: *Zld, lazy_bind: *LazyBind) !void {1610 fn collectLazyBindData(self: *Zld, lazy_bind: *LazyBind) !void {
1682 const sect_id = self.getSectionByName("__DATA", "__la_symbol_ptr") orelse return;1611 const sect_id = self.la_symbol_ptr_section_index orelse return;
16831612 try MachO.collectBindDataFromTableSection(self.gpa, self, sect_id, lazy_bind, self.stubs_table);
1684 log.debug("collecting lazy bind data", .{});
1685
1686 const slice = self.sections.slice();
1687 const segment_index = slice.items(.segment_index)[sect_id];
1688 const seg = self.getSegment(sect_id);
1689 var atom_index = slice.items(.first_atom_index)[sect_id].?;
1690
1691 // TODO: we actually don't need to store lazy pointer atoms as they are synthetically generated by the linker
1692 try lazy_bind.entries.ensureUnusedCapacity(self.gpa, self.stubs.items.len);
1693
1694 var count: u32 = 0;
1695 while (true) : (count += 1) {
1696 const atom = self.getAtom(atom_index);
1697
1698 log.debug(" ATOM(%{d}, '{s}')", .{ atom.sym_index, self.getSymbolName(atom.getSymbolWithLoc()) });
1699
1700 const sym = self.getSymbol(atom.getSymbolWithLoc());
1701 const base_offset = sym.n_value - seg.vmaddr;
1702
1703 const stub_entry = self.stubs.items[count];
1704 const bind_sym = stub_entry.getTargetSymbol(self);
1705 const bind_sym_name = stub_entry.getTargetSymbolName(self);
1706 const dylib_ordinal = @divTrunc(@as(i16, @bitCast(bind_sym.n_desc)), macho.N_SYMBOL_RESOLVER);
1707 log.debug(" | lazy bind at {x}, import('{s}') in dylib({d})", .{
1708 base_offset,
1709 bind_sym_name,
1710 dylib_ordinal,
1711 });
1712 if (bind_sym.weakRef()) {
1713 log.debug(" | marking as weak ref ", .{});
1714 }
1715 lazy_bind.entries.appendAssumeCapacity(.{
1716 .target = stub_entry.target,
1717 .offset = base_offset,
1718 .segment_id = segment_index,
1719 .addend = 0,
1720 });
1721
1722 if (atom.next_index) |next_index| {
1723 atom_index = next_index;
1724 } else break;
1725 }
1726
1727 try lazy_bind.finalize(self.gpa, self);1613 try lazy_bind.finalize(self.gpa, self);
1728 }1614 }
17291615
...@@ -1828,7 +1714,12 @@ pub const Zld = struct {...@@ -1828,7 +1714,12 @@ pub const Zld = struct {
1828 });1714 });
18291715
1830 try self.file.pwriteAll(buffer, rebase_off);1716 try self.file.pwriteAll(buffer, rebase_off);
1831 try self.populateLazyBindOffsetsInStubHelper(lazy_bind);1717 try MachO.populateLazyBindOffsetsInStubHelper(
1718 self,
1719 self.options.target.cpu.arch,
1720 self.file,
1721 lazy_bind,
1722 );
18321723
1833 self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off));1724 self.dyld_info_cmd.rebase_off = @as(u32, @intCast(rebase_off));
1834 self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned));1725 self.dyld_info_cmd.rebase_size = @as(u32, @intCast(rebase_size_aligned));
...@@ -1840,36 +1731,6 @@ pub const Zld = struct {...@@ -1840,36 +1731,6 @@ pub const Zld = struct {
1840 self.dyld_info_cmd.export_size = @as(u32, @intCast(export_size_aligned));1731 self.dyld_info_cmd.export_size = @as(u32, @intCast(export_size_aligned));
1841 }1732 }
18421733
1843 fn populateLazyBindOffsetsInStubHelper(self: *Zld, lazy_bind: LazyBind) !void {
1844 if (lazy_bind.size() == 0) return;
1845
1846 const stub_helper_section_index = self.getSectionByName("__TEXT", "__stub_helper").?;
1847 assert(self.stub_helper_preamble_sym_index != null);
1848
1849 const section = self.sections.get(stub_helper_section_index);
1850 const stub_offset = stub_helpers.calcStubOffsetInStubHelper(self.options.target.cpu.arch);
1851 const header = section.header;
1852 var atom_index = section.first_atom_index.?;
1853 atom_index = self.getAtom(atom_index).next_index.?; // skip preamble
1854
1855 var index: usize = 0;
1856 while (true) {
1857 const atom = self.getAtom(atom_index);
1858 const atom_sym = self.getSymbol(atom.getSymbolWithLoc());
1859 const file_offset = header.offset + atom_sym.n_value - header.addr + stub_offset;
1860 const bind_offset = lazy_bind.offsets.items[index];
1861
1862 log.debug("writing lazy bind offset 0x{x} in stub helper at 0x{x}", .{ bind_offset, file_offset });
1863
1864 try self.file.pwriteAll(mem.asBytes(&bind_offset), file_offset);
1865
1866 if (atom.next_index) |next_index| {
1867 atom_index = next_index;
1868 index += 1;
1869 } else break;
1870 }
1871 }
1872
1873 const asc_u64 = std.sort.asc(u64);1734 const asc_u64 = std.sort.asc(u64);
18741735
1875 fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void {1736 fn addSymbolToFunctionStarts(self: *Zld, sym_loc: SymbolWithLoc, addresses: *std.ArrayList(u64)) !void {
...@@ -1973,7 +1834,7 @@ pub const Zld = struct {...@@ -1973,7 +1834,7 @@ pub const Zld = struct {
1973 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa);1834 var out_dice = std.ArrayList(macho.data_in_code_entry).init(self.gpa);
1974 defer out_dice.deinit();1835 defer out_dice.deinit();
19751836
1976 const text_sect_id = self.getSectionByName("__TEXT", "__text") orelse return;1837 const text_sect_id = self.text_section_index orelse return;
1977 const text_sect_header = self.sections.items(.header)[text_sect_id];1838 const text_sect_header = self.sections.items(.header)[text_sect_id];
19781839
1979 for (self.objects.items) |object| {1840 for (self.objects.items) |object| {
...@@ -2171,7 +2032,7 @@ pub const Zld = struct {...@@ -2171,7 +2032,7 @@ pub const Zld = struct {
21712032
2172 fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void {2033 fn writeDysymtab(self: *Zld, ctx: SymtabCtx) !void {
2173 const gpa = self.gpa;2034 const gpa = self.gpa;
2174 const nstubs = @as(u32, @intCast(self.stubs.items.len));2035 const nstubs = @as(u32, @intCast(self.stubs_table.lookup.count()));
2175 const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count()));2036 const ngot_entries = @as(u32, @intCast(self.got_table.lookup.count()));
2176 const nindirectsyms = nstubs * 2 + ngot_entries;2037 const nindirectsyms = nstubs * 2 + ngot_entries;
2177 const iextdefsym = ctx.nlocalsym;2038 const iextdefsym = ctx.nlocalsym;
...@@ -2191,19 +2052,20 @@ pub const Zld = struct {...@@ -2191,19 +2052,20 @@ pub const Zld = struct {
2191 try buf.ensureTotalCapacityPrecise(math.cast(usize, needed_size_aligned) orelse return error.Overflow);2052 try buf.ensureTotalCapacityPrecise(math.cast(usize, needed_size_aligned) orelse return error.Overflow);
2192 const writer = buf.writer();2053 const writer = buf.writer();
21932054
2194 if (self.getSectionByName("__TEXT", "__stubs")) |sect_id| {2055 if (self.stubs_section_index) |sect_id| {
2195 const stubs = &self.sections.items(.header)[sect_id];2056 const header = &self.sections.items(.header)[sect_id];
2196 stubs.reserved1 = 0;2057 header.reserved1 = 0;
2197 for (self.stubs.items) |entry| {2058 for (self.stubs_table.entries.items) |entry| {
2198 const target_sym = entry.getTargetSymbol(self);2059 if (!self.stubs_table.lookup.contains(entry)) continue;
2060 const target_sym = self.getSymbol(entry);
2199 assert(target_sym.undf());2061 assert(target_sym.undf());
2200 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);2062 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?);
2201 }2063 }
2202 }2064 }
22032065
2204 if (self.got_section_index) |sect_id| {2066 if (self.got_section_index) |sect_id| {
2205 const got = &self.sections.items(.header)[sect_id];2067 const header = &self.sections.items(.header)[sect_id];
2206 got.reserved1 = nstubs;2068 header.reserved1 = nstubs;
2207 for (self.got_table.entries.items) |entry| {2069 for (self.got_table.entries.items) |entry| {
2208 if (!self.got_table.lookup.contains(entry)) continue;2070 if (!self.got_table.lookup.contains(entry)) continue;
2209 const target_sym = self.getSymbol(entry);2071 const target_sym = self.getSymbol(entry);
...@@ -2215,13 +2077,14 @@ pub const Zld = struct {...@@ -2215,13 +2077,14 @@ pub const Zld = struct {
2215 }2077 }
2216 }2078 }
22172079
2218 if (self.getSectionByName("__DATA", "__la_symbol_ptr")) |sect_id| {2080 if (self.la_symbol_ptr_section_index) |sect_id| {
2219 const la_symbol_ptr = &self.sections.items(.header)[sect_id];2081 const header = &self.sections.items(.header)[sect_id];
2220 la_symbol_ptr.reserved1 = nstubs + ngot_entries;2082 header.reserved1 = nstubs + ngot_entries;
2221 for (self.stubs.items) |entry| {2083 for (self.stubs_table.entries.items) |entry| {
2222 const target_sym = entry.getTargetSymbol(self);2084 if (!self.stubs_table.lookup.contains(entry)) continue;
2085 const target_sym = self.getSymbol(entry);
2223 assert(target_sym.undf());2086 assert(target_sym.undf());
2224 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry.target).?);2087 try writer.writeIntLittle(u32, iundefsym + ctx.imports_table.get(entry).?);
2225 }2088 }
2226 }2089 }
22272090
...@@ -2343,12 +2206,12 @@ pub const Zld = struct {...@@ -2343,12 +2206,12 @@ pub const Zld = struct {
2343 return buf;2206 return buf;
2344 }2207 }
23452208
2346 pub fn getAtomPtr(self: *Zld, atom_index: AtomIndex) *Atom {2209 pub fn getAtomPtr(self: *Zld, atom_index: Atom.Index) *Atom {
2347 assert(atom_index < self.atoms.items.len);2210 assert(atom_index < self.atoms.items.len);
2348 return &self.atoms.items[atom_index];2211 return &self.atoms.items[atom_index];
2349 }2212 }
23502213
2351 pub fn getAtom(self: Zld, atom_index: AtomIndex) Atom {2214 pub fn getAtom(self: Zld, atom_index: Atom.Index) Atom {
2352 assert(atom_index < self.atoms.items.len);2215 assert(atom_index < self.atoms.items.len);
2353 return self.atoms.items[atom_index];2216 return self.atoms.items[atom_index];
2354 }2217 }
...@@ -2444,12 +2307,10 @@ pub const Zld = struct {...@@ -2444,12 +2307,10 @@ pub const Zld = struct {
2444 return header.addr + @sizeOf(u64) * index;2307 return header.addr + @sizeOf(u64) * index;
2445 }2308 }
24462309
2447 /// Returns stubs atom that references `sym_with_loc` if one exists.2310 pub fn getStubsEntryAddress(self: *Zld, sym_with_loc: SymbolWithLoc) ?u64 {
2448 /// Returns null otherwise.2311 const index = self.stubs_table.lookup.get(sym_with_loc) orelse return null;
2449 pub fn getStubsAtomIndexForSymbol(self: *Zld, sym_with_loc: SymbolWithLoc) ?AtomIndex {2312 const header = self.sections.items(.header)[self.stubs_section_index.?];
2450 const index = self.stubs_table.get(sym_with_loc) orelse return null;2313 return header.addr + stubs.stubSize(self.options.target.cpu.arch) * index;
2451 const entry = self.stubs.items[index];
2452 return entry.atom_index;
2453 }2314 }
24542315
2455 /// Returns symbol location corresponding to the set entrypoint.2316 /// Returns symbol location corresponding to the set entrypoint.
...@@ -2581,7 +2442,7 @@ pub const Zld = struct {...@@ -2581,7 +2442,7 @@ pub const Zld = struct {
25812442
2582 fn generateSymbolStabsForSymbol(2443 fn generateSymbolStabsForSymbol(
2583 self: *Zld,2444 self: *Zld,
2584 atom_index: AtomIndex,2445 atom_index: Atom.Index,
2585 sym_loc: SymbolWithLoc,2446 sym_loc: SymbolWithLoc,
2586 lookup: ?DwarfInfo.SubprogramLookupByName,2447 lookup: ?DwarfInfo.SubprogramLookupByName,
2587 buf: *[4]macho.nlist_64,2448 buf: *[4]macho.nlist_64,
...@@ -2787,30 +2648,26 @@ pub const Zld = struct {...@@ -2787,30 +2648,26 @@ pub const Zld = struct {
2787 scoped_log.debug("{}", .{self.tlv_ptr_table});2648 scoped_log.debug("{}", .{self.tlv_ptr_table});
27882649
2789 scoped_log.debug("stubs entries:", .{});2650 scoped_log.debug("stubs entries:", .{});
2790 for (self.stubs.items, 0..) |entry, i| {2651 scoped_log.debug("{}", .{self.stubs_table});
2791 const atom_sym = entry.getAtomSymbol(self);
2792 const target_sym = entry.getTargetSymbol(self);
2793 const target_sym_name = entry.getTargetSymbolName(self);
2794 assert(target_sym.undf());
2795 scoped_log.debug(" {d}@{x} => import('{s}')", .{
2796 i,
2797 atom_sym.n_value,
2798 target_sym_name,
2799 });
2800 }
28012652
2802 scoped_log.debug("thunks:", .{});2653 scoped_log.debug("thunks:", .{});
2803 for (self.thunks.items, 0..) |thunk, i| {2654 for (self.thunks.items, 0..) |thunk, i| {
2804 scoped_log.debug(" thunk({d})", .{i});2655 scoped_log.debug(" thunk({d})", .{i});
2805 for (thunk.lookup.keys(), 0..) |target, j| {2656 const slice = thunk.targets.slice();
2806 const target_sym = self.getSymbol(target);2657 for (slice.items(.tag), slice.items(.target), 0..) |tag, target, j| {
2807 const atom = self.getAtom(thunk.lookup.get(target).?);2658 const atom_index = @as(u32, @intCast(thunk.getStartAtomIndex() + j));
2659 const atom = self.getAtom(atom_index);
2808 const atom_sym = self.getSymbol(atom.getSymbolWithLoc());2660 const atom_sym = self.getSymbol(atom.getSymbolWithLoc());
2809 scoped_log.debug(" {d}@{x} => thunk('{s}'@{x})", .{2661 const target_addr = switch (tag) {
2662 .stub => self.getStubsEntryAddress(target).?,
2663 .atom => self.getSymbol(target).n_value,
2664 };
2665 scoped_log.debug(" {d}@{x} => {s}({s}@{x})", .{
2810 j,2666 j,
2811 atom_sym.n_value,2667 atom_sym.n_value,
2668 @tagName(tag),
2812 self.getSymbolName(target),2669 self.getSymbolName(target),
2813 target_sym.n_value,2670 target_addr,
2814 });2671 });
2815 }2672 }
2816 }2673 }
...@@ -2836,7 +2693,7 @@ pub const Zld = struct {...@@ -2836,7 +2693,7 @@ pub const Zld = struct {
2836 }2693 }
2837 }2694 }
28382695
2839 pub fn logAtom(self: *Zld, atom_index: AtomIndex, logger: anytype) void {2696 pub fn logAtom(self: *Zld, atom_index: Atom.Index, logger: anytype) void {
2840 if (!build_options.enable_logging) return;2697 if (!build_options.enable_logging) return;
28412698
2842 const atom = self.getAtom(atom_index);2699 const atom = self.getAtom(atom_index);
...@@ -2885,11 +2742,9 @@ pub const Zld = struct {...@@ -2885,11 +2742,9 @@ pub const Zld = struct {
28852742
2886pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1)));2743pub const N_DEAD: u16 = @as(u16, @bitCast(@as(i16, -1)));
28872744
2888pub const AtomIndex = u32;
2889
2890const IndirectPointer = struct {2745const IndirectPointer = struct {
2891 target: SymbolWithLoc,2746 target: SymbolWithLoc,
2892 atom_index: AtomIndex,2747 atom_index: Atom.Index,
28932748
2894 pub fn getTargetSymbol(self: @This(), zld: *Zld) macho.nlist_64 {2749 pub fn getTargetSymbol(self: @This(), zld: *Zld) macho.nlist_64 {
2895 return zld.getSymbol(self.target);2750 return zld.getSymbol(self.target);
...@@ -3321,7 +3176,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3321,7 +3176,6 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
33213176
3322 try zld.createDyldPrivateAtom();3177 try zld.createDyldPrivateAtom();
3323 try zld.createTentativeDefAtoms();3178 try zld.createTentativeDefAtoms();
3324 try zld.createStubHelperPreambleAtom();
33253179
3326 if (zld.options.output_mode == .Exe) {3180 if (zld.options.output_mode == .Exe) {
3327 const global = zld.getEntryPoint();3181 const global = zld.getEntryPoint();
...@@ -3329,7 +3183,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3329,7 +3183,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3329 // We do one additional check here in case the entry point was found in one of the dylibs.3183 // We do one additional check here in case the entry point was found in one of the dylibs.
3330 // (I actually have no idea what this would imply but it is a possible outcome and so we3184 // (I actually have no idea what this would imply but it is a possible outcome and so we
3331 // support it.)3185 // support it.)
3332 try Atom.addStub(&zld, global);3186 try zld.addStubEntry(global);
3333 }3187 }
3334 }3188 }
33353189
...@@ -3373,7 +3227,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3373,7 +3227,14 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3373 }3227 }
33743228
3375 try zld.writeAtoms();3229 try zld.writeAtoms();
3230 if (zld.requiresThunks()) try zld.writeThunks();
3231 try zld.writeDyldPrivateAtom();
33763232
3233 if (zld.stubs_section_index) |_| {
3234 try zld.writeStubs();
3235 try zld.writeStubHelpers();
3236 try zld.writeLaSymbolPtrs();
3237 }
3377 if (zld.got_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.got_table);3238 if (zld.got_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.got_table);
3378 if (zld.tlv_ptr_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.tlv_ptr_table);3239 if (zld.tlv_ptr_section_index) |sect_id| try zld.writePointerEntries(sect_id, &zld.tlv_ptr_table);
33793240
...@@ -3444,14 +3305,12 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr...@@ -3444,14 +3305,12 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
3444 const global = zld.getEntryPoint();3305 const global = zld.getEntryPoint();
3445 const sym = zld.getSymbol(global);3306 const sym = zld.getSymbol(global);
34463307
3447 const addr: u64 = if (sym.undf()) blk: {3308 const addr: u64 = if (sym.undf())
3448 // In this case, the symbol has been resolved in one of dylibs and so we point3309 // In this case, the symbol has been resolved in one of dylibs and so we point
3449 // to the stub as its vmaddr value.3310 // to the stub as its vmaddr value.
3450 const stub_atom_index = zld.getStubsAtomIndexForSymbol(global).?;3311 zld.getStubsEntryAddress(global).?
3451 const stub_atom = zld.getAtom(stub_atom_index);3312 else
3452 const stub_sym = zld.getSymbol(stub_atom.getSymbolWithLoc());3313 sym.n_value;
3453 break :blk stub_sym.n_value;
3454 } else sym.n_value;
34553314
3456 try lc_writer.writeStruct(macho.entry_point_command{3315 try lc_writer.writeStruct(macho.entry_point_command{
3457 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),3316 .entryoff = @as(u32, @intCast(addr - seg.vmaddr)),