authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-16 14:52:55+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-08-17 08:14:38+02:00
log96441bd829b731cba080753c4833aff3f672a24a
treefc4d4d5eb4654d81dd09e91052be11b55fcb09f8
parentbb70501060a8bfff25818cf1d80491d724f8a634

macho: update codegen and linker to distributed jump table approach


11 files changed, 147 insertions(+), 272 deletions(-)

src/arch/x86_64/CodeGen.zig+25-23
......@@ -12364,13 +12364,10 @@ fn genCall(self: *Self, info: union(enum) {
1236412364 const zo = macho_file.getZigObject().?;
1236512365 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav);
1236612366 const sym = zo.symbols.items[sym_index];
12367 try self.genSetReg(
12368 .rax,
12369 Type.usize,
12370 .{ .load_symbol = .{ .sym = sym.nlist_idx } },
12371 .{},
12372 );
12373 try self.asmRegister(.{ ._, .call }, .rax);
12367 try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
12368 .atom_index = try self.owner.getSymbolIndex(self),
12369 .sym_index = sym.nlist_idx,
12370 }));
1237412371 } else if (self.bin_file.cast(.plan9)) |p9| {
1237512372 const atom_index = try p9.seeNav(pt, func.owner_nav);
1237612373 const atom = p9.getAtom(atom_index);
......@@ -12392,6 +12389,15 @@ fn genCall(self: *Self, info: union(enum) {
1239212389 .atom_index = try self.owner.getSymbolIndex(self),
1239312390 .sym_index = target_sym_index,
1239412391 }));
12392 } else if (self.bin_file.cast(.macho)) |macho_file| {
12393 const target_sym_index = try macho_file.getGlobalSymbol(
12394 @"extern".name.toSlice(ip),
12395 @"extern".lib_name.toSlice(ip),
12396 );
12397 try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
12398 .atom_index = try self.owner.getSymbolIndex(self),
12399 .sym_index = target_sym_index,
12400 }));
1239512401 } else try self.genExternSymbolRef(
1239612402 .call,
1239712403 @"extern".lib_name.toSlice(ip),
......@@ -12410,6 +12416,12 @@ fn genCall(self: *Self, info: union(enum) {
1241012416 .atom_index = try self.owner.getSymbolIndex(self),
1241112417 .sym_index = target_sym_index,
1241212418 }));
12419 } else if (self.bin_file.cast(.macho)) |macho_file| {
12420 const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib);
12421 try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{
12422 .atom_index = try self.owner.getSymbolIndex(self),
12423 .sym_index = target_sym_index,
12424 }));
1241312425 } else try self.genExternSymbolRef(.call, lib.lib, lib.callee),
1241412426 }
1241512427 return call_info.return_value.short;
......@@ -15335,15 +15347,6 @@ fn genExternSymbolRef(
1533515347 .call => try self.asmRegister(.{ ._, .call }, .rax),
1533615348 else => unreachable,
1533715349 }
15338 } else if (self.bin_file.cast(.macho)) |macho_file| {
15339 _ = try self.addInst(.{
15340 .tag = .call,
15341 .ops = .extern_fn_reloc,
15342 .data = .{ .reloc = .{
15343 .atom_index = atom_index,
15344 .sym_index = try macho_file.getGlobalSymbol(callee, lib),
15345 } },
15346 });
1534715350 } else return self.fail("TODO implement calling extern functions", .{});
1534815351}
1534915352
......@@ -15434,13 +15437,12 @@ fn genLazySymbolRef(
1543415437 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1543515438 const sym = zo.symbols.items[sym_index];
1543615439 switch (tag) {
15437 .lea, .call => try self.genSetReg(
15438 reg,
15439 Type.usize,
15440 .{ .load_symbol = .{ .sym = sym.nlist_idx } },
15441 .{},
15442 ),
15443 .mov => try self.genSetReg(reg, Type.usize, .{ .load_symbol = .{ .sym = sym.nlist_idx } }, .{}),
15440 .lea, .call => try self.genSetReg(reg, Type.usize, .{
15441 .lea_symbol = .{ .sym = sym.nlist_idx },
15442 }, .{}),
15443 .mov => try self.genSetReg(reg, Type.usize, .{
15444 .load_symbol = .{ .sym = sym.nlist_idx },
15445 }, .{}),
1544415446 else => unreachable,
1544515447 }
1544615448 switch (tag) {
src/arch/x86_64/Emit.zig+2-14
......@@ -135,23 +135,11 @@ pub fn emitMir(emit: *Emit) Error!void {
135135 });
136136 }
137137 } else if (emit.lower.bin_file.cast(.macho)) |macho_file| {
138 const is_obj_or_static_lib = switch (emit.lower.output_mode) {
139 .Exe => false,
140 .Obj => true,
141 .Lib => emit.lower.link_mode == .static,
142 };
143138 const zo = macho_file.getZigObject().?;
144139 const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?;
145140 const sym = &zo.symbols.items[data.sym_index];
146 if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib) {
147 _ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file);
148 }
149 const @"type": link.File.MachO.Relocation.Type = if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib)
150 .zig_got_load
151 else if (sym.getSectionFlags().needs_got)
152 // TODO: it is possible to emit .got_load here that can potentially be relaxed
153 // however this requires always to use a MOVQ mnemonic
154 .got
141 const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr)
142 .got_load
155143 else if (sym.flags.tlv)
156144 .tlv
157145 else
src/arch/x86_64/Lower.zig+13-7
......@@ -328,12 +328,6 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
328328}
329329
330330fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
331 const is_obj_or_static_lib = switch (lower.output_mode) {
332 .Exe => false,
333 .Obj => true,
334 .Lib => lower.link_mode == .static,
335 };
336
337331 const emit_prefix = prefix;
338332 var emit_mnemonic = mnemonic;
339333 var emit_ops_storage: [4]Operand = undefined;
......@@ -455,10 +449,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
455449 _ = lower.reloc(.{ .linker_reloc = sym });
456450 break :op switch (mnemonic) {
457451 .lea => {
452 if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov;
458453 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
459454 },
460455 .mov => {
461 if (is_obj_or_static_lib and macho_sym.getSectionFlags().needs_zig_got) emit_mnemonic = .lea;
456 if (macho_sym.flags.is_extern_ptr) {
457 const reg = ops[0].reg;
458 lower.result_insts[lower.result_insts_len] =
459 try Instruction.new(.none, .mov, &[_]Operand{
460 .{ .reg = reg.to64() },
461 .{ .mem = Memory.rip(.qword, 0) },
462 });
463 lower.result_insts_len += 1;
464 break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{
465 .reg = reg.to64(),
466 } }) };
467 }
462468 break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) };
463469 },
464470 else => unreachable,
src/codegen.zig+3-3
......@@ -910,15 +910,15 @@ fn genNavRef(
910910 const zo = macho_file.getZigObject().?;
911911 if (is_extern) {
912912 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
913 zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true });
914 return .{ .mcv = .{ .load_symbol = sym_index } };
913 zo.symbols.items[sym_index].flags.is_extern_ptr = true;
914 return GenResult.mcv(.{ .lea_symbol = sym_index });
915915 }
916916 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
917917 const sym = zo.symbols.items[sym_index];
918918 if (!single_threaded and is_threadlocal) {
919919 return .{ .mcv = .{ .load_tlv = sym.nlist_idx } };
920920 }
921 return .{ .mcv = .{ .load_symbol = sym.nlist_idx } };
921 return GenResult.mcv(.{ .lea_symbol = sym.nlist_idx });
922922 } else if (lf.cast(.coff)) |coff_file| {
923923 if (is_extern) {
924924 // TODO audit this
src/link/MachO.zig-29
......@@ -59,7 +59,6 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{},
5959strtab: std.ArrayListUnmanaged(u8) = .{},
6060indsymtab: Indsymtab = .{},
6161got: GotSection = .{},
62zig_got: ZigGotSection = .{},
6362stubs: StubsSection = .{},
6463stubs_helper: StubsHelperSection = .{},
6564objc_stubs: ObjcStubsSection = .{},
......@@ -75,14 +74,12 @@ data_in_code: DataInCode = .{},
7574
7675/// Tracked loadable segments during incremental linking.
7776zig_text_seg_index: ?u8 = null,
78zig_got_seg_index: ?u8 = null,
7977zig_const_seg_index: ?u8 = null,
8078zig_data_seg_index: ?u8 = null,
8179zig_bss_seg_index: ?u8 = null,
8280
8381/// Tracked section headers with incremental updates to Zig object.
8482zig_text_sect_index: ?u8 = null,
85zig_got_sect_index: ?u8 = null,
8683zig_const_sect_index: ?u8 = null,
8784zig_data_sect_index: ?u8 = null,
8885zig_bss_sect_index: ?u8 = null,
......@@ -324,7 +321,6 @@ pub fn deinit(self: *MachO) void {
324321 self.symtab.deinit(gpa);
325322 self.strtab.deinit(gpa);
326323 self.got.deinit(gpa);
327 self.zig_got.deinit(gpa);
328324 self.stubs.deinit(gpa);
329325 self.objc_stubs.deinit(gpa);
330326 self.tlv_ptr.deinit(gpa);
......@@ -1796,7 +1792,6 @@ pub fn sortSections(self: *MachO) !void {
17961792 &self.data_sect_index,
17971793 &self.got_sect_index,
17981794 &self.zig_text_sect_index,
1799 &self.zig_got_sect_index,
18001795 &self.zig_const_sect_index,
18011796 &self.zig_data_sect_index,
18021797 &self.zig_bss_sect_index,
......@@ -2114,7 +2109,6 @@ fn initSegments(self: *MachO) !void {
21142109 &self.text_seg_index,
21152110 &self.linkedit_seg_index,
21162111 &self.zig_text_seg_index,
2117 &self.zig_got_seg_index,
21182112 &self.zig_const_seg_index,
21192113 &self.zig_data_seg_index,
21202114 &self.zig_bss_seg_index,
......@@ -3231,18 +3225,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
32313225 });
32323226 }
32333227
3234 {
3235 const filesize = options.symbol_count_hint * @sizeOf(u64);
3236 const off = try self.findFreeSpace(filesize, self.getPageSize());
3237 self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{
3238 .fileoff = off,
3239 .filesize = filesize,
3240 .vmaddr = base_vmaddr + 0x4000000,
3241 .vmsize = filesize,
3242 .prot = macho.PROT.READ | macho.PROT.WRITE,
3243 });
3244 }
3245
32463228 {
32473229 const filesize: u64 = 1024;
32483230 const off = try self.findFreeSpace(filesize, self.getPageSize());
......@@ -3343,13 +3325,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
33433325 }
33443326 }
33453327
3346 if (!self.base.isRelocatable()) {
3347 self.zig_got_sect_index = try self.addSection("__GOT_ZIG", "__got_zig", .{
3348 .alignment = 3,
3349 });
3350 appendSect(self, self.zig_got_sect_index.?, self.zig_got_seg_index.?);
3351 }
3352
33533328 {
33543329 self.zig_const_sect_index = try self.addSection("__CONST_ZIG", "__const_zig", .{});
33553330 if (self.base.isRelocatable()) {
......@@ -3572,7 +3547,6 @@ inline fn requiresThunks(self: MachO) bool {
35723547pub fn isZigSegment(self: MachO, seg_id: u8) bool {
35733548 inline for (&[_]?u8{
35743549 self.zig_text_seg_index,
3575 self.zig_got_seg_index,
35763550 self.zig_const_seg_index,
35773551 self.zig_data_seg_index,
35783552 self.zig_bss_seg_index,
......@@ -3587,7 +3561,6 @@ pub fn isZigSegment(self: MachO, seg_id: u8) bool {
35873561pub fn isZigSection(self: MachO, sect_id: u8) bool {
35883562 inline for (&[_]?u8{
35893563 self.zig_text_sect_index,
3590 self.zig_got_sect_index,
35913564 self.zig_const_sect_index,
35923565 self.zig_data_sect_index,
35933566 self.zig_bss_sect_index,
......@@ -3957,7 +3930,6 @@ fn fmtDumpState(
39573930 try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)});
39583931 try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)});
39593932 try writer.print("got\n{}\n", .{self.got.fmt(self)});
3960 try writer.print("zig_got\n{}\n", .{self.zig_got.fmt(self)});
39613933 try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)});
39623934 try writer.writeByte('\n');
39633935 try writer.print("sections\n{}\n", .{self.fmtSections()});
......@@ -4665,7 +4637,6 @@ const Value = @import("../Value.zig");
46654637const UnwindInfo = @import("MachO/UnwindInfo.zig");
46664638const WaitGroup = std.Thread.WaitGroup;
46674639const WeakBind = bind.WeakBind;
4668const ZigGotSection = synthetic.ZigGotSection;
46694640const ZigObject = @import("MachO/ZigObject.zig");
46704641const dev = @import("../dev.zig");
46714642
src/link/MachO/Atom.zig+1-21
......@@ -492,10 +492,6 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void {
492492 }
493493 },
494494
495 .zig_got_load => {
496 assert(rel.getTargetSymbol(self, macho_file).getSectionFlags().has_zig_got);
497 },
498
499495 .got => {
500496 rel.getTargetSymbol(self, macho_file).setSectionFlags(.{ .needs_got = true });
501497 },
......@@ -652,8 +648,6 @@ fn resolveRelocInner(
652648 const G: i64 = @intCast(rel.getGotTargetAddress(self, macho_file));
653649 const TLS = @as(i64, @intCast(macho_file.getTlsAddress()));
654650 const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(self, macho_file))) else 0;
655 // Address of the __got_zig table entry if any.
656 const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file)));
657651
658652 const divExact = struct {
659653 fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 {
......@@ -676,13 +670,12 @@ fn resolveRelocInner(
676670 S + A - SUB,
677671 rel.getTargetAtom(self, macho_file).atom_index,
678672 }),
679 .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ZG({x}) ({s})", .{
673 .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ({s})", .{
680674 P,
681675 rel_offset,
682676 rel.fmtPretty(cpu_arch),
683677 S + A - SUB,
684678 G + A,
685 ZIG_GOT + A,
686679 rel.getTargetSymbol(self, macho_file).getName(macho_file),
687680 }),
688681 }
......@@ -745,17 +738,6 @@ fn resolveRelocInner(
745738 }
746739 },
747740
748 .zig_got_load => {
749 assert(rel.tag == .@"extern");
750 assert(rel.meta.length == 2);
751 assert(rel.meta.pcrel);
752 switch (cpu_arch) {
753 .x86_64 => try writer.writeInt(i32, @intCast(ZIG_GOT + A - P), .little),
754 .aarch64 => @panic("TODO resolve __got_zig indirection reloc"),
755 else => unreachable,
756 }
757 },
758
759741 .tlv => {
760742 assert(rel.tag == .@"extern");
761743 assert(rel.meta.length == 2);
......@@ -1065,7 +1047,6 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
10651047 .subtractor => .ARM64_RELOC_SUBTRACTOR,
10661048 .unsigned => .ARM64_RELOC_UNSIGNED,
10671049
1068 .zig_got_load,
10691050 .signed,
10701051 .signed1,
10711052 .signed2,
......@@ -1109,7 +1090,6 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r
11091090 .subtractor => .X86_64_RELOC_SUBTRACTOR,
11101091 .unsigned => .X86_64_RELOC_UNSIGNED,
11111092
1112 .zig_got_load,
11131093 .page,
11141094 .pageoff,
11151095 .got_load_page,
src/link/MachO/Relocation.zig-3
......@@ -92,7 +92,6 @@ fn formatPretty(
9292 .signed4 => "X86_64_RELOC_SIGNED_4",
9393 .got_load => "X86_64_RELOC_GOT_LOAD",
9494 .tlv => "X86_64_RELOC_TLV",
95 .zig_got_load => "ZIG_GOT_LOAD",
9695 .page => "ARM64_RELOC_PAGE21",
9796 .pageoff => "ARM64_RELOC_PAGEOFF12",
9897 .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21",
......@@ -137,8 +136,6 @@ pub const Type = enum {
137136 got_load,
138137 /// RIP-relative TLV load (X86_64_RELOC_TLV)
139138 tlv,
140 /// Zig-specific __got_zig indirection
141 zig_got_load,
142139
143140 // arm64
144141 /// PC-relative load (distance to page, ARM64_RELOC_PAGE21)
src/link/MachO/Symbol.zig+19-24
......@@ -123,6 +123,7 @@ pub fn getSymbolRank(symbol: Symbol, macho_file: *MachO) u32 {
123123
124124pub fn getAddress(symbol: Symbol, opts: struct {
125125 stubs: bool = true,
126 trampoline: bool = true,
126127}, macho_file: *MachO) u64 {
127128 if (opts.stubs) {
128129 if (symbol.getSectionFlags().stubs) {
......@@ -131,6 +132,9 @@ pub fn getAddress(symbol: Symbol, opts: struct {
131132 return symbol.getObjcStubsAddress(macho_file);
132133 }
133134 }
135 if (symbol.flags.trampoline and opts.trampoline) {
136 return symbol.getTrampolineAddress(macho_file);
137 }
134138 if (symbol.getAtom(macho_file)) |atom| return atom.getAddress(macho_file) + symbol.value;
135139 return symbol.value;
136140}
......@@ -169,23 +173,11 @@ pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 {
169173 return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file);
170174}
171175
172const GetOrCreateZigGotEntryResult = struct {
173 found_existing: bool,
174 index: ZigGotSection.Index,
175};
176
177pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult {
178 assert(!macho_file.base.isRelocatable());
179 assert(symbol.getSectionFlags().needs_zig_got);
180 if (symbol.getSectionFlags().has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got };
181 const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file);
182 return .{ .found_existing = false, .index = index };
183}
184
185pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 {
186 if (!symbol.getSectionFlags().has_zig_got) return 0;
187 const extras = symbol.getExtra(macho_file);
188 return macho_file.zig_got.entryAddress(extras.zig_got, macho_file);
176pub fn getTrampolineAddress(symbol: Symbol, macho_file: *MachO) u64 {
177 if (!symbol.flags.trampoline) return 0;
178 const zo = macho_file.getZigObject().?;
179 const index = symbol.getExtra(macho_file).trampoline;
180 return zo.symbols.items[index].getAddress(.{}, macho_file);
189181}
190182
191183pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 {
......@@ -209,12 +201,12 @@ pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 {
209201
210202const AddExtraOpts = struct {
211203 got: ?u32 = null,
212 zig_got: ?u32 = null,
213204 stubs: ?u32 = null,
214205 objc_stubs: ?u32 = null,
215206 objc_selrefs: ?u32 = null,
216207 tlv_ptr: ?u32 = null,
217208 symtab: ?u32 = null,
209 trampoline: ?u32 = null,
218210};
219211
220212pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) void {
......@@ -393,6 +385,13 @@ pub const Flags = packed struct {
393385
394386 /// Whether the symbol makes into the output symtab or not.
395387 output_symtab: bool = false,
388
389 /// ZigObject specific flags
390 /// Whether the symbol has a trampoline
391 trampoline: bool = false,
392
393 /// Whether the symbol is an extern pointer (as opposed to function).
394 is_extern_ptr: bool = false,
396395};
397396
398397pub const SectionFlags = packed struct(u8) {
......@@ -400,10 +399,6 @@ pub const SectionFlags = packed struct(u8) {
400399 needs_got: bool = false,
401400 has_got: bool = false,
402401
403 /// Whether the symbol contains __got_zig indirection.
404 needs_zig_got: bool = false,
405 has_zig_got: bool = false,
406
407402 /// Whether the symbols contains __stubs indirection.
408403 stubs: bool = false,
409404
......@@ -413,7 +408,7 @@ pub const SectionFlags = packed struct(u8) {
413408 /// Whether the symbol contains __objc_stubs indirection.
414409 objc_stubs: bool = false,
415410
416 _: u1 = 0,
411 _: u3 = 0,
417412};
418413
419414pub const Visibility = enum {
......@@ -432,12 +427,12 @@ pub const Visibility = enum {
432427
433428pub const Extra = struct {
434429 got: u32 = 0,
435 zig_got: u32 = 0,
436430 stubs: u32 = 0,
437431 objc_stubs: u32 = 0,
438432 objc_selrefs: u32 = 0,
439433 tlv_ptr: u32 = 0,
440434 symtab: u32 = 0,
435 trampoline: u32 = 0,
441436};
442437
443438pub const Index = u32;
src/link/MachO/ZigObject.zig+84-28
......@@ -795,7 +795,15 @@ pub fn updateFunc(
795795 };
796796
797797 const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code);
798 const old_rva, const old_alignment = blk: {
799 const atom = self.symbols.items[sym_index].getAtom(macho_file).?;
800 break :blk .{ atom.value, atom.alignment };
801 };
798802 try self.updateNavCode(macho_file, pt, func.owner_nav, sym_index, sect_index, code);
803 const new_rva, const new_alignment = blk: {
804 const atom = self.symbols.items[sym_index].getAtom(macho_file).?;
805 break :blk .{ atom.value, atom.alignment };
806 };
799807
800808 if (dwarf_wip_nav) |*wip_nav| {
801809 const sym = self.symbols.items[sym_index];
......@@ -812,6 +820,42 @@ pub fn updateFunc(
812820 }
813821
814822 // Exports will be updated by `Zcu.processExports` after the update.
823 if (old_rva != new_rva and old_rva > 0) {
824 // If we had to reallocate the function, we re-use the existing slot for a trampoline.
825 // In the rare case that the function has been further overaligned we skip creating a
826 // trampoline and update all symbols referring this function.
827 if (old_alignment.order(new_alignment) == .lt) {
828 @panic("TODO update all symbols referring this function");
829 }
830
831 // Create a trampoline to the new location at `old_rva`.
832 if (!self.symbols.items[sym_index].flags.trampoline) {
833 const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{
834 self.symbols.items[sym_index].getName(macho_file),
835 });
836 defer gpa.free(name);
837 const name_off = try self.addString(gpa, name);
838 const tr_size = trampolineSize(macho_file.getTarget().cpu.arch);
839 const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off, macho_file);
840 const tr_sym = &self.symbols.items[tr_sym_index];
841 tr_sym.out_n_sect = macho_file.zig_text_sect_index.?;
842 const tr_nlist = &self.symtab.items(.nlist)[tr_sym.nlist_idx];
843 tr_nlist.n_sect = macho_file.zig_text_sect_index.? + 1;
844 const tr_atom = tr_sym.getAtom(macho_file).?;
845 tr_atom.value = old_rva;
846 tr_atom.setAlive(true);
847 tr_atom.alignment = old_alignment;
848 tr_atom.out_n_sect = macho_file.zig_text_sect_index.?;
849 tr_atom.size = tr_size;
850 self.symtab.items(.size)[tr_sym.nlist_idx] = tr_size;
851 const target_sym = &self.symbols.items[sym_index];
852 target_sym.addExtra(.{ .trampoline = tr_sym_index }, macho_file);
853 target_sym.flags.trampoline = true;
854 }
855 const target_sym = self.symbols.items[sym_index];
856 const source_sym = self.symbols.items[target_sym.getExtra(macho_file).trampoline];
857 try writeTrampoline(source_sym, target_sym, macho_file);
858 }
815859}
816860
817861pub fn updateNav(
......@@ -836,7 +880,7 @@ pub fn updateNav(
836880 const lib_name = @"extern".lib_name.toSlice(ip);
837881 const index = try self.getGlobalSymbol(macho_file, name, lib_name);
838882 const sym = &self.symbols.items[index];
839 sym.setSectionFlags(.{ .needs_got = true });
883 sym.flags.is_extern_ptr = true;
840884 return;
841885 },
842886 else => nav_val,
......@@ -946,13 +990,6 @@ fn updateNavCode(
946990 if (old_vaddr != atom.value) {
947991 sym.value = 0;
948992 nlist.n_value = 0;
949
950 if (!macho_file.base.isRelocatable()) {
951 log.debug(" (updating offset table entry)", .{});
952 assert(sym.getSectionFlags().has_zig_got);
953 const extra = sym.getExtra(macho_file);
954 try macho_file.zig_got.writeOne(macho_file, extra.zig_got);
955 }
956993 }
957994 } else if (code.len < old_size) {
958995 atom.shrink(macho_file);
......@@ -965,13 +1002,7 @@ fn updateNavCode(
9651002 errdefer self.freeNavMetadata(macho_file, sym_index);
9661003
9671004 sym.value = 0;
968 sym.setSectionFlags(.{ .needs_zig_got = true });
9691005 nlist.n_value = 0;
970
971 if (!macho_file.base.isRelocatable()) {
972 const gop = try sym.getOrCreateZigGotEntry(sym_index, macho_file);
973 try macho_file.zig_got.writeOne(macho_file, gop.index);
974 }
9751006 }
9761007
9771008 if (!sect.isZerofill()) {
......@@ -1381,14 +1412,8 @@ fn updateLazySymbol(
13811412 errdefer self.freeNavMetadata(macho_file, symbol_index);
13821413
13831414 sym.value = 0;
1384 sym.setSectionFlags(.{ .needs_zig_got = true });
13851415 nlist.n_value = 0;
13861416
1387 if (!macho_file.base.isRelocatable()) {
1388 const gop = try sym.getOrCreateZigGotEntry(symbol_index, macho_file);
1389 try macho_file.zig_got.writeOne(macho_file, gop.index);
1390 }
1391
13921417 const sect = macho_file.sections.items(.header)[output_section_index];
13931418 const file_offset = sect.offset + atom.value;
13941419 try macho_file.base.file.?.pwriteAll(code, file_offset);
......@@ -1448,6 +1473,31 @@ pub fn getGlobalSymbol(self: *ZigObject, macho_file: *MachO, name: []const u8, l
14481473 return lookup_gop.value_ptr.*;
14491474}
14501475
1476const max_trampoline_len = 12;
1477
1478fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {
1479 const len = switch (cpu_arch) {
1480 .x86_64 => 5, // jmp rel32
1481 else => @panic("TODO implement trampoline size for this CPU arch"),
1482 };
1483 comptime assert(len <= max_trampoline_len);
1484 return len;
1485}
1486
1487fn writeTrampoline(tr_sym: Symbol, target: Symbol, macho_file: *MachO) !void {
1488 const atom = tr_sym.getAtom(macho_file).?;
1489 const header = macho_file.sections.items(.header)[atom.out_n_sect];
1490 const fileoff = header.offset + atom.value;
1491 const source_addr = tr_sym.getAddress(.{}, macho_file);
1492 const target_addr = target.getAddress(.{ .trampoline = false }, macho_file);
1493 var buf: [max_trampoline_len]u8 = undefined;
1494 const out = switch (macho_file.getTarget().cpu.arch) {
1495 .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
1496 else => @panic("TODO implement write trampoline for this CPU arch"),
1497 };
1498 try macho_file.base.file.?.pwriteAll(out, fileoff);
1499}
1500
14511501pub fn getOrCreateMetadataForNav(
14521502 self: *ZigObject,
14531503 macho_file: *MachO,
......@@ -1460,8 +1510,6 @@ pub fn getOrCreateMetadataForNav(
14601510 const sym = &self.symbols.items[sym_index];
14611511 if (isThreadlocal(macho_file, nav_index)) {
14621512 sym.flags.tlv = true;
1463 } else {
1464 sym.setSectionFlags(.{ .needs_zig_got = true });
14651513 }
14661514 gop.value_ptr.* = .{ .symbol_index = sym_index };
14671515 }
......@@ -1482,12 +1530,7 @@ pub fn getOrCreateMetadataForLazySymbol(
14821530 .const_data => .{ &gop.value_ptr.const_symbol_index, &gop.value_ptr.const_state },
14831531 };
14841532 switch (state_ptr.*) {
1485 .unused => {
1486 const symbol_index = try self.newSymbolWithAtom(pt.zcu.gpa, .{}, macho_file);
1487 const sym = &self.symbols.items[symbol_index];
1488 sym.setSectionFlags(.{ .needs_zig_got = true });
1489 symbol_index_ptr.* = symbol_index;
1490 },
1533 .unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, .{}, macho_file),
14911534 .pending_flush => return symbol_index_ptr.*,
14921535 .flushed => {},
14931536 }
......@@ -1749,6 +1792,19 @@ const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymb
17491792const RelocationTable = std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation));
17501793const TlvInitializerTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlvInitializer);
17511794
1795const x86_64 = struct {
1796 fn writeTrampolineCode(source_addr: u64, target_addr: u64, buf: *[max_trampoline_len]u8) ![]u8 {
1797 const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr)) - 5;
1798 var bytes = [_]u8{
1799 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
1800 };
1801 assert(bytes.len == trampolineSize(.x86_64));
1802 mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little);
1803 @memcpy(buf[0..bytes.len], &bytes);
1804 return buf[0..bytes.len];
1805 }
1806};
1807
17521808const assert = std.debug.assert;
17531809const builtin = @import("builtin");
17541810const codegen = @import("../../codegen.zig");
src/link/MachO/dyld_info/Rebase.zig-12
......@@ -56,18 +56,6 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void {
5656 }
5757 }
5858
59 if (macho_file.zig_got_sect_index) |sid| {
60 const seg_id = macho_file.sections.items(.segment_id)[sid];
61 const seg = macho_file.segments.items[seg_id];
62 for (0..macho_file.zig_got.entries.items.len) |idx| {
63 const addr = macho_file.zig_got.entryAddress(@intCast(idx), macho_file);
64 try rebase.entries.append(gpa, .{
65 .offset = addr - seg.vmaddr,
66 .segment_id = seg_id,
67 });
68 }
69 }
70
7159 if (macho_file.got_sect_index) |sid| {
7260 const seg_id = macho_file.sections.items(.segment_id)[sid];
7361 const seg = macho_file.segments.items[seg_id];
src/link/MachO/synthetic.zig-108
......@@ -1,111 +1,3 @@
1pub const ZigGotSection = struct {
2 entries: std.ArrayListUnmanaged(Symbol.Index) = .{},
3 dirty: bool = false,
4
5 pub const Index = u32;
6
7 pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void {
8 zig_got.entries.deinit(allocator);
9 }
10
11 fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index {
12 try zig_got.entries.ensureUnusedCapacity(allocator, 1);
13 // TODO add free list
14 const index = @as(Index, @intCast(zig_got.entries.items.len));
15 _ = zig_got.entries.addOneAssumeCapacity();
16 zig_got.dirty = true;
17 return index;
18 }
19
20 pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index {
21 const gpa = macho_file.base.comp.gpa;
22 const zo = macho_file.getZigObject().?;
23 const index = try zig_got.allocateEntry(gpa);
24 const entry = &zig_got.entries.items[index];
25 entry.* = sym_index;
26 const symbol = &zo.symbols.items[sym_index];
27 assert(symbol.getSectionFlags().needs_zig_got);
28 symbol.setSectionFlags(.{ .has_zig_got = true });
29 symbol.addExtra(.{ .zig_got = index }, macho_file);
30 return index;
31 }
32
33 pub fn entryOffset(zig_got: ZigGotSection, index: Index, macho_file: *MachO) u64 {
34 _ = zig_got;
35 const sect = macho_file.sections.items(.header)[macho_file.zig_got_sect_index.?];
36 return sect.offset + @sizeOf(u64) * index;
37 }
38
39 pub fn entryAddress(zig_got: ZigGotSection, index: Index, macho_file: *MachO) u64 {
40 _ = zig_got;
41 const sect = macho_file.sections.items(.header)[macho_file.zig_got_sect_index.?];
42 return sect.addr + @sizeOf(u64) * index;
43 }
44
45 pub fn size(zig_got: ZigGotSection, macho_file: *MachO) usize {
46 _ = macho_file;
47 return @sizeOf(u64) * zig_got.entries.items.len;
48 }
49
50 pub fn writeOne(zig_got: *ZigGotSection, macho_file: *MachO, index: Index) !void {
51 if (zig_got.dirty) {
52 const needed_size = zig_got.size(macho_file);
53 try macho_file.growSection(macho_file.zig_got_sect_index.?, needed_size);
54 zig_got.dirty = false;
55 }
56 const zo = macho_file.getZigObject().?;
57 const off = zig_got.entryOffset(index, macho_file);
58 const entry = zig_got.entries.items[index];
59 const value = zo.symbols.items[entry].getAddress(.{ .stubs = false }, macho_file);
60
61 var buf: [8]u8 = undefined;
62 std.mem.writeInt(u64, &buf, value, .little);
63 try macho_file.base.file.?.pwriteAll(&buf, off);
64 }
65
66 pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void {
67 const zo = macho_file.getZigObject().?;
68 for (zig_got.entries.items) |entry| {
69 const symbol = zo.symbols.items[entry];
70 const value = symbol.address(.{ .stubs = false }, macho_file);
71 try writer.writeInt(u64, value, .little);
72 }
73 }
74
75 const FormatCtx = struct {
76 zig_got: ZigGotSection,
77 macho_file: *MachO,
78 };
79
80 pub fn fmt(zig_got: ZigGotSection, macho_file: *MachO) std.fmt.Formatter(format2) {
81 return .{ .data = .{ .zig_got = zig_got, .macho_file = macho_file } };
82 }
83
84 pub fn format2(
85 ctx: FormatCtx,
86 comptime unused_fmt_string: []const u8,
87 options: std.fmt.FormatOptions,
88 writer: anytype,
89 ) !void {
90 _ = options;
91 _ = unused_fmt_string;
92 const zig_got = ctx.zig_got;
93 const macho_file = ctx.macho_file;
94 try writer.writeAll("__zig_got\n");
95 for (zig_got.entries.items, 0..) |entry, index| {
96 const zo = macho_file.getZigObject().?;
97 const symbol = zo.symbols.items[entry];
98 try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{
99 index,
100 zig_got.entryAddress(@intCast(index), macho_file),
101 entry,
102 symbol.getAddress(.{}, macho_file),
103 symbol.getName(macho_file),
104 });
105 }
106 }
107};
108
1091pub const GotSection = struct {
1102 symbols: std.ArrayListUnmanaged(MachO.Ref) = .{},
1113