diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index e18f1487c3..86fb2bf3e9 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -12364,13 +12364,10 @@ fn genCall(self: *Self, info: union(enum) { const zo = macho_file.getZigObject().?; const sym_index = try zo.getOrCreateMetadataForNav(macho_file, func.owner_nav); const sym = zo.symbols.items[sym_index]; - try self.genSetReg( - .rax, - Type.usize, - .{ .load_symbol = .{ .sym = sym.nlist_idx } }, - .{}, - ); - try self.asmRegister(.{ ._, .call }, .rax); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ + .atom_index = try self.owner.getSymbolIndex(self), + .sym_index = sym.nlist_idx, + })); } else if (self.bin_file.cast(.plan9)) |p9| { const atom_index = try p9.seeNav(pt, func.owner_nav); const atom = p9.getAtom(atom_index); @@ -12392,6 +12389,15 @@ fn genCall(self: *Self, info: union(enum) { .atom_index = try self.owner.getSymbolIndex(self), .sym_index = target_sym_index, })); + } else if (self.bin_file.cast(.macho)) |macho_file| { + const target_sym_index = try macho_file.getGlobalSymbol( + @"extern".name.toSlice(ip), + @"extern".lib_name.toSlice(ip), + ); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ + .atom_index = try self.owner.getSymbolIndex(self), + .sym_index = target_sym_index, + })); } else try self.genExternSymbolRef( .call, @"extern".lib_name.toSlice(ip), @@ -12410,6 +12416,12 @@ fn genCall(self: *Self, info: union(enum) { .atom_index = try self.owner.getSymbolIndex(self), .sym_index = target_sym_index, })); + } else if (self.bin_file.cast(.macho)) |macho_file| { + const target_sym_index = try macho_file.getGlobalSymbol(lib.callee, lib.lib); + try self.asmImmediate(.{ ._, .call }, Immediate.rel(.{ + .atom_index = try self.owner.getSymbolIndex(self), + .sym_index = target_sym_index, + })); } else try self.genExternSymbolRef(.call, lib.lib, lib.callee), } return call_info.return_value.short; @@ -15335,15 +15347,6 @@ fn genExternSymbolRef( .call => try self.asmRegister(.{ ._, .call }, .rax), else => unreachable, } - } else if (self.bin_file.cast(.macho)) |macho_file| { - _ = try self.addInst(.{ - .tag = .call, - .ops = .extern_fn_reloc, - .data = .{ .reloc = .{ - .atom_index = atom_index, - .sym_index = try macho_file.getGlobalSymbol(callee, lib), - } }, - }); } else return self.fail("TODO implement calling extern functions", .{}); } @@ -15434,13 +15437,12 @@ fn genLazySymbolRef( return self.fail("{s} creating lazy symbol", .{@errorName(err)}); const sym = zo.symbols.items[sym_index]; switch (tag) { - .lea, .call => try self.genSetReg( - reg, - Type.usize, - .{ .load_symbol = .{ .sym = sym.nlist_idx } }, - .{}, - ), - .mov => try self.genSetReg(reg, Type.usize, .{ .load_symbol = .{ .sym = sym.nlist_idx } }, .{}), + .lea, .call => try self.genSetReg(reg, Type.usize, .{ + .lea_symbol = .{ .sym = sym.nlist_idx }, + }, .{}), + .mov => try self.genSetReg(reg, Type.usize, .{ + .load_symbol = .{ .sym = sym.nlist_idx }, + }, .{}), else => unreachable, } switch (tag) { diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 8a7b2a2b5c..f168464f6f 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -135,23 +135,11 @@ pub fn emitMir(emit: *Emit) Error!void { }); } } else if (emit.lower.bin_file.cast(.macho)) |macho_file| { - const is_obj_or_static_lib = switch (emit.lower.output_mode) { - .Exe => false, - .Obj => true, - .Lib => emit.lower.link_mode == .static, - }; const zo = macho_file.getZigObject().?; const atom = zo.symbols.items[data.atom_index].getAtom(macho_file).?; const sym = &zo.symbols.items[data.sym_index]; - if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib) { - _ = try sym.getOrCreateZigGotEntry(data.sym_index, macho_file); - } - const @"type": link.File.MachO.Relocation.Type = if (sym.getSectionFlags().needs_zig_got and !is_obj_or_static_lib) - .zig_got_load - else if (sym.getSectionFlags().needs_got) - // TODO: it is possible to emit .got_load here that can potentially be relaxed - // however this requires always to use a MOVQ mnemonic - .got + const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr) + .got_load else if (sym.flags.tlv) .tlv else diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 15322ce4f6..2275ed5f9b 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -328,12 +328,6 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate { } fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void { - const is_obj_or_static_lib = switch (lower.output_mode) { - .Exe => false, - .Obj => true, - .Lib => lower.link_mode == .static, - }; - const emit_prefix = prefix; var emit_mnemonic = mnemonic; var emit_ops_storage: [4]Operand = undefined; @@ -455,10 +449,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) _ = lower.reloc(.{ .linker_reloc = sym }); break :op switch (mnemonic) { .lea => { + if (macho_sym.flags.is_extern_ptr) emit_mnemonic = .mov; break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; }, .mov => { - if (is_obj_or_static_lib and macho_sym.getSectionFlags().needs_zig_got) emit_mnemonic = .lea; + if (macho_sym.flags.is_extern_ptr) { + const reg = ops[0].reg; + lower.result_insts[lower.result_insts_len] = + try Instruction.new(.none, .mov, &[_]Operand{ + .{ .reg = reg.to64() }, + .{ .mem = Memory.rip(.qword, 0) }, + }); + lower.result_insts_len += 1; + break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ + .reg = reg.to64(), + } }) }; + } break :op .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }; }, else => unreachable, diff --git a/src/codegen.zig b/src/codegen.zig index 4ac4b849c0..af77dcc50c 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -910,15 +910,15 @@ fn genNavRef( const zo = macho_file.getZigObject().?; if (is_extern) { const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip)); - zo.symbols.items[sym_index].setSectionFlags(.{ .needs_got = true }); - return .{ .mcv = .{ .load_symbol = sym_index } }; + zo.symbols.items[sym_index].flags.is_extern_ptr = true; + return .{ .mcv = .{ .lea_symbol = sym_index } }; } const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index); const sym = zo.symbols.items[sym_index]; if (!single_threaded and is_threadlocal) { return .{ .mcv = .{ .load_tlv = sym.nlist_idx } }; } - return .{ .mcv = .{ .load_symbol = sym.nlist_idx } }; + return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } }; } else if (lf.cast(.coff)) |coff_file| { if (is_extern) { // TODO audit this diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 5d6802154f..f3a6ffc58d 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -59,7 +59,6 @@ symtab: std.ArrayListUnmanaged(macho.nlist_64) = .{}, strtab: std.ArrayListUnmanaged(u8) = .{}, indsymtab: Indsymtab = .{}, got: GotSection = .{}, -zig_got: ZigGotSection = .{}, stubs: StubsSection = .{}, stubs_helper: StubsHelperSection = .{}, objc_stubs: ObjcStubsSection = .{}, @@ -75,14 +74,12 @@ data_in_code: DataInCode = .{}, /// Tracked loadable segments during incremental linking. zig_text_seg_index: ?u8 = null, -zig_got_seg_index: ?u8 = null, zig_const_seg_index: ?u8 = null, zig_data_seg_index: ?u8 = null, zig_bss_seg_index: ?u8 = null, /// Tracked section headers with incremental updates to Zig object. zig_text_sect_index: ?u8 = null, -zig_got_sect_index: ?u8 = null, zig_const_sect_index: ?u8 = null, zig_data_sect_index: ?u8 = null, zig_bss_sect_index: ?u8 = null, @@ -324,7 +321,6 @@ pub fn deinit(self: *MachO) void { self.symtab.deinit(gpa); self.strtab.deinit(gpa); self.got.deinit(gpa); - self.zig_got.deinit(gpa); self.stubs.deinit(gpa); self.objc_stubs.deinit(gpa); self.tlv_ptr.deinit(gpa); @@ -1796,7 +1792,6 @@ pub fn sortSections(self: *MachO) !void { &self.data_sect_index, &self.got_sect_index, &self.zig_text_sect_index, - &self.zig_got_sect_index, &self.zig_const_sect_index, &self.zig_data_sect_index, &self.zig_bss_sect_index, @@ -2114,7 +2109,6 @@ fn initSegments(self: *MachO) !void { &self.text_seg_index, &self.linkedit_seg_index, &self.zig_text_seg_index, - &self.zig_got_seg_index, &self.zig_const_seg_index, &self.zig_data_seg_index, &self.zig_bss_seg_index, @@ -3231,18 +3225,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { }); } - { - const filesize = options.symbol_count_hint * @sizeOf(u64); - const off = try self.findFreeSpace(filesize, self.getPageSize()); - self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{ - .fileoff = off, - .filesize = filesize, - .vmaddr = base_vmaddr + 0x4000000, - .vmsize = filesize, - .prot = macho.PROT.READ | macho.PROT.WRITE, - }); - } - { const filesize: u64 = 1024; const off = try self.findFreeSpace(filesize, self.getPageSize()); @@ -3343,13 +3325,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { } } - if (!self.base.isRelocatable()) { - self.zig_got_sect_index = try self.addSection("__GOT_ZIG", "__got_zig", .{ - .alignment = 3, - }); - appendSect(self, self.zig_got_sect_index.?, self.zig_got_seg_index.?); - } - { self.zig_const_sect_index = try self.addSection("__CONST_ZIG", "__const_zig", .{}); if (self.base.isRelocatable()) { @@ -3572,7 +3547,6 @@ inline fn requiresThunks(self: MachO) bool { pub fn isZigSegment(self: MachO, seg_id: u8) bool { inline for (&[_]?u8{ self.zig_text_seg_index, - self.zig_got_seg_index, self.zig_const_seg_index, self.zig_data_seg_index, self.zig_bss_seg_index, @@ -3587,7 +3561,6 @@ pub fn isZigSegment(self: MachO, seg_id: u8) bool { pub fn isZigSection(self: MachO, sect_id: u8) bool { inline for (&[_]?u8{ self.zig_text_sect_index, - self.zig_got_sect_index, self.zig_const_sect_index, self.zig_data_sect_index, self.zig_bss_sect_index, @@ -3957,7 +3930,6 @@ fn fmtDumpState( try writer.print("stubs\n{}\n", .{self.stubs.fmt(self)}); try writer.print("objc_stubs\n{}\n", .{self.objc_stubs.fmt(self)}); try writer.print("got\n{}\n", .{self.got.fmt(self)}); - try writer.print("zig_got\n{}\n", .{self.zig_got.fmt(self)}); try writer.print("tlv_ptr\n{}\n", .{self.tlv_ptr.fmt(self)}); try writer.writeByte('\n'); try writer.print("sections\n{}\n", .{self.fmtSections()}); @@ -4665,7 +4637,6 @@ const Value = @import("../Value.zig"); const UnwindInfo = @import("MachO/UnwindInfo.zig"); const WaitGroup = std.Thread.WaitGroup; const WeakBind = bind.WeakBind; -const ZigGotSection = synthetic.ZigGotSection; const ZigObject = @import("MachO/ZigObject.zig"); const dev = @import("../dev.zig"); diff --git a/src/link/MachO/Atom.zig b/src/link/MachO/Atom.zig index d0e0fe377d..d2072278a9 100644 --- a/src/link/MachO/Atom.zig +++ b/src/link/MachO/Atom.zig @@ -492,10 +492,6 @@ pub fn scanRelocs(self: Atom, macho_file: *MachO) !void { } }, - .zig_got_load => { - assert(rel.getTargetSymbol(self, macho_file).getSectionFlags().has_zig_got); - }, - .got => { rel.getTargetSymbol(self, macho_file).setSectionFlags(.{ .needs_got = true }); }, @@ -652,8 +648,6 @@ fn resolveRelocInner( const G: i64 = @intCast(rel.getGotTargetAddress(self, macho_file)); const TLS = @as(i64, @intCast(macho_file.getTlsAddress())); const SUB = if (subtractor) |sub| @as(i64, @intCast(sub.getTargetAddress(self, macho_file))) else 0; - // Address of the __got_zig table entry if any. - const ZIG_GOT = @as(i64, @intCast(rel.getZigGotTargetAddress(macho_file))); const divExact = struct { fn divExact(atom: Atom, r: Relocation, num: u12, den: u12, ctx: *MachO) !u12 { @@ -676,13 +670,12 @@ fn resolveRelocInner( S + A - SUB, rel.getTargetAtom(self, macho_file).atom_index, }), - .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ZG({x}) ({s})", .{ + .@"extern" => relocs_log.debug(" {x}<+{d}>: {}: [=> {x}] G({x}) ({s})", .{ P, rel_offset, rel.fmtPretty(cpu_arch), S + A - SUB, G + A, - ZIG_GOT + A, rel.getTargetSymbol(self, macho_file).getName(macho_file), }), } @@ -745,17 +738,6 @@ fn resolveRelocInner( } }, - .zig_got_load => { - assert(rel.tag == .@"extern"); - assert(rel.meta.length == 2); - assert(rel.meta.pcrel); - switch (cpu_arch) { - .x86_64 => try writer.writeInt(i32, @intCast(ZIG_GOT + A - P), .little), - .aarch64 => @panic("TODO resolve __got_zig indirection reloc"), - else => unreachable, - } - }, - .tlv => { assert(rel.tag == .@"extern"); assert(rel.meta.length == 2); @@ -1065,7 +1047,6 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r .subtractor => .ARM64_RELOC_SUBTRACTOR, .unsigned => .ARM64_RELOC_UNSIGNED, - .zig_got_load, .signed, .signed1, .signed2, @@ -1109,7 +1090,6 @@ pub fn writeRelocs(self: Atom, macho_file: *MachO, code: []u8, buffer: []macho.r .subtractor => .X86_64_RELOC_SUBTRACTOR, .unsigned => .X86_64_RELOC_UNSIGNED, - .zig_got_load, .page, .pageoff, .got_load_page, diff --git a/src/link/MachO/Relocation.zig b/src/link/MachO/Relocation.zig index bfb551f224..c732dc3a89 100644 --- a/src/link/MachO/Relocation.zig +++ b/src/link/MachO/Relocation.zig @@ -92,7 +92,6 @@ fn formatPretty( .signed4 => "X86_64_RELOC_SIGNED_4", .got_load => "X86_64_RELOC_GOT_LOAD", .tlv => "X86_64_RELOC_TLV", - .zig_got_load => "ZIG_GOT_LOAD", .page => "ARM64_RELOC_PAGE21", .pageoff => "ARM64_RELOC_PAGEOFF12", .got_load_page => "ARM64_RELOC_GOT_LOAD_PAGE21", @@ -137,8 +136,6 @@ pub const Type = enum { got_load, /// RIP-relative TLV load (X86_64_RELOC_TLV) tlv, - /// Zig-specific __got_zig indirection - zig_got_load, // arm64 /// PC-relative load (distance to page, ARM64_RELOC_PAGE21) diff --git a/src/link/MachO/Symbol.zig b/src/link/MachO/Symbol.zig index 6e5af75fc2..7d8dc9c046 100644 --- a/src/link/MachO/Symbol.zig +++ b/src/link/MachO/Symbol.zig @@ -123,6 +123,7 @@ pub fn getSymbolRank(symbol: Symbol, macho_file: *MachO) u32 { pub fn getAddress(symbol: Symbol, opts: struct { stubs: bool = true, + trampoline: bool = true, }, macho_file: *MachO) u64 { if (opts.stubs) { if (symbol.getSectionFlags().stubs) { @@ -131,6 +132,9 @@ pub fn getAddress(symbol: Symbol, opts: struct { return symbol.getObjcStubsAddress(macho_file); } } + if (symbol.flags.trampoline and opts.trampoline) { + return symbol.getTrampolineAddress(macho_file); + } if (symbol.getAtom(macho_file)) |atom| return atom.getAddress(macho_file) + symbol.value; return symbol.value; } @@ -169,23 +173,11 @@ pub fn getTlvPtrAddress(symbol: Symbol, macho_file: *MachO) u64 { return macho_file.tlv_ptr.getAddress(extra.tlv_ptr, macho_file); } -const GetOrCreateZigGotEntryResult = struct { - found_existing: bool, - index: ZigGotSection.Index, -}; - -pub fn getOrCreateZigGotEntry(symbol: *Symbol, symbol_index: Index, macho_file: *MachO) !GetOrCreateZigGotEntryResult { - assert(!macho_file.base.isRelocatable()); - assert(symbol.getSectionFlags().needs_zig_got); - if (symbol.getSectionFlags().has_zig_got) return .{ .found_existing = true, .index = symbol.getExtra(macho_file).zig_got }; - const index = try macho_file.zig_got.addSymbol(symbol_index, macho_file); - return .{ .found_existing = false, .index = index }; -} - -pub fn getZigGotAddress(symbol: Symbol, macho_file: *MachO) u64 { - if (!symbol.getSectionFlags().has_zig_got) return 0; - const extras = symbol.getExtra(macho_file); - return macho_file.zig_got.entryAddress(extras.zig_got, macho_file); +pub fn getTrampolineAddress(symbol: Symbol, macho_file: *MachO) u64 { + if (!symbol.flags.trampoline) return 0; + const zo = macho_file.getZigObject().?; + const index = symbol.getExtra(macho_file).trampoline; + return zo.symbols.items[index].getAddress(.{}, macho_file); } pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 { @@ -209,12 +201,12 @@ pub fn getOutputSymtabIndex(symbol: Symbol, macho_file: *MachO) ?u32 { const AddExtraOpts = struct { got: ?u32 = null, - zig_got: ?u32 = null, stubs: ?u32 = null, objc_stubs: ?u32 = null, objc_selrefs: ?u32 = null, tlv_ptr: ?u32 = null, symtab: ?u32 = null, + trampoline: ?u32 = null, }; pub fn addExtra(symbol: *Symbol, opts: AddExtraOpts, macho_file: *MachO) void { @@ -393,6 +385,13 @@ pub const Flags = packed struct { /// Whether the symbol makes into the output symtab or not. output_symtab: bool = false, + + /// ZigObject specific flags + /// Whether the symbol has a trampoline + trampoline: bool = false, + + /// Whether the symbol is an extern pointer (as opposed to function). + is_extern_ptr: bool = false, }; pub const SectionFlags = packed struct(u8) { @@ -400,10 +399,6 @@ pub const SectionFlags = packed struct(u8) { needs_got: bool = false, has_got: bool = false, - /// Whether the symbol contains __got_zig indirection. - needs_zig_got: bool = false, - has_zig_got: bool = false, - /// Whether the symbols contains __stubs indirection. stubs: bool = false, @@ -413,7 +408,7 @@ pub const SectionFlags = packed struct(u8) { /// Whether the symbol contains __objc_stubs indirection. objc_stubs: bool = false, - _: u1 = 0, + _: u3 = 0, }; pub const Visibility = enum { @@ -432,12 +427,12 @@ pub const Visibility = enum { pub const Extra = struct { got: u32 = 0, - zig_got: u32 = 0, stubs: u32 = 0, objc_stubs: u32 = 0, objc_selrefs: u32 = 0, tlv_ptr: u32 = 0, symtab: u32 = 0, + trampoline: u32 = 0, }; pub const Index = u32; diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index e678d53f79..4827dae268 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -795,7 +795,15 @@ pub fn updateFunc( }; const sect_index = try self.getNavOutputSection(macho_file, zcu, func.owner_nav, code); + const old_rva, const old_alignment = blk: { + const atom = self.symbols.items[sym_index].getAtom(macho_file).?; + break :blk .{ atom.value, atom.alignment }; + }; try self.updateNavCode(macho_file, pt, func.owner_nav, sym_index, sect_index, code); + const new_rva, const new_alignment = blk: { + const atom = self.symbols.items[sym_index].getAtom(macho_file).?; + break :blk .{ atom.value, atom.alignment }; + }; if (dwarf_wip_nav) |*wip_nav| { const sym = self.symbols.items[sym_index]; @@ -812,6 +820,42 @@ pub fn updateFunc( } // Exports will be updated by `Zcu.processExports` after the update. + if (old_rva != new_rva and old_rva > 0) { + // If we had to reallocate the function, we re-use the existing slot for a trampoline. + // In the rare case that the function has been further overaligned we skip creating a + // trampoline and update all symbols referring this function. + if (old_alignment.order(new_alignment) == .lt) { + @panic("TODO update all symbols referring this function"); + } + + // Create a trampoline to the new location at `old_rva`. + if (!self.symbols.items[sym_index].flags.trampoline) { + const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{ + self.symbols.items[sym_index].getName(macho_file), + }); + defer gpa.free(name); + const name_off = try self.addString(gpa, name); + const tr_size = trampolineSize(macho_file.getTarget().cpu.arch); + const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off, macho_file); + const tr_sym = &self.symbols.items[tr_sym_index]; + tr_sym.out_n_sect = macho_file.zig_text_sect_index.?; + const tr_nlist = &self.symtab.items(.nlist)[tr_sym.nlist_idx]; + tr_nlist.n_sect = macho_file.zig_text_sect_index.? + 1; + const tr_atom = tr_sym.getAtom(macho_file).?; + tr_atom.value = old_rva; + tr_atom.setAlive(true); + tr_atom.alignment = old_alignment; + tr_atom.out_n_sect = macho_file.zig_text_sect_index.?; + tr_atom.size = tr_size; + self.symtab.items(.size)[tr_sym.nlist_idx] = tr_size; + const target_sym = &self.symbols.items[sym_index]; + target_sym.addExtra(.{ .trampoline = tr_sym_index }, macho_file); + target_sym.flags.trampoline = true; + } + const target_sym = self.symbols.items[sym_index]; + const source_sym = self.symbols.items[target_sym.getExtra(macho_file).trampoline]; + try writeTrampoline(source_sym, target_sym, macho_file); + } } pub fn updateNav( @@ -836,7 +880,7 @@ pub fn updateNav( const lib_name = @"extern".lib_name.toSlice(ip); const index = try self.getGlobalSymbol(macho_file, name, lib_name); const sym = &self.symbols.items[index]; - sym.setSectionFlags(.{ .needs_got = true }); + sym.flags.is_extern_ptr = true; return; }, else => nav_val, @@ -946,13 +990,6 @@ fn updateNavCode( if (old_vaddr != atom.value) { sym.value = 0; nlist.n_value = 0; - - if (!macho_file.base.isRelocatable()) { - log.debug(" (updating offset table entry)", .{}); - assert(sym.getSectionFlags().has_zig_got); - const extra = sym.getExtra(macho_file); - try macho_file.zig_got.writeOne(macho_file, extra.zig_got); - } } } else if (code.len < old_size) { atom.shrink(macho_file); @@ -965,13 +1002,7 @@ fn updateNavCode( errdefer self.freeNavMetadata(macho_file, sym_index); sym.value = 0; - sym.setSectionFlags(.{ .needs_zig_got = true }); nlist.n_value = 0; - - if (!macho_file.base.isRelocatable()) { - const gop = try sym.getOrCreateZigGotEntry(sym_index, macho_file); - try macho_file.zig_got.writeOne(macho_file, gop.index); - } } if (!sect.isZerofill()) { @@ -1381,14 +1412,8 @@ fn updateLazySymbol( errdefer self.freeNavMetadata(macho_file, symbol_index); sym.value = 0; - sym.setSectionFlags(.{ .needs_zig_got = true }); nlist.n_value = 0; - if (!macho_file.base.isRelocatable()) { - const gop = try sym.getOrCreateZigGotEntry(symbol_index, macho_file); - try macho_file.zig_got.writeOne(macho_file, gop.index); - } - const sect = macho_file.sections.items(.header)[output_section_index]; const file_offset = sect.offset + atom.value; 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 return lookup_gop.value_ptr.*; } +const max_trampoline_len = 12; + +fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 { + const len = switch (cpu_arch) { + .x86_64 => 5, // jmp rel32 + else => @panic("TODO implement trampoline size for this CPU arch"), + }; + comptime assert(len <= max_trampoline_len); + return len; +} + +fn writeTrampoline(tr_sym: Symbol, target: Symbol, macho_file: *MachO) !void { + const atom = tr_sym.getAtom(macho_file).?; + const header = macho_file.sections.items(.header)[atom.out_n_sect]; + const fileoff = header.offset + atom.value; + const source_addr = tr_sym.getAddress(.{}, macho_file); + const target_addr = target.getAddress(.{ .trampoline = false }, macho_file); + var buf: [max_trampoline_len]u8 = undefined; + const out = switch (macho_file.getTarget().cpu.arch) { + .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf), + else => @panic("TODO implement write trampoline for this CPU arch"), + }; + try macho_file.base.file.?.pwriteAll(out, fileoff); +} + pub fn getOrCreateMetadataForNav( self: *ZigObject, macho_file: *MachO, @@ -1460,8 +1510,6 @@ pub fn getOrCreateMetadataForNav( const sym = &self.symbols.items[sym_index]; if (isThreadlocal(macho_file, nav_index)) { sym.flags.tlv = true; - } else { - sym.setSectionFlags(.{ .needs_zig_got = true }); } gop.value_ptr.* = .{ .symbol_index = sym_index }; } @@ -1482,12 +1530,7 @@ pub fn getOrCreateMetadataForLazySymbol( .const_data => .{ &gop.value_ptr.const_symbol_index, &gop.value_ptr.const_state }, }; switch (state_ptr.*) { - .unused => { - const symbol_index = try self.newSymbolWithAtom(pt.zcu.gpa, .{}, macho_file); - const sym = &self.symbols.items[symbol_index]; - sym.setSectionFlags(.{ .needs_zig_got = true }); - symbol_index_ptr.* = symbol_index; - }, + .unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, .{}, macho_file), .pending_flush => return symbol_index_ptr.*, .flushed => {}, } @@ -1749,6 +1792,19 @@ const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymb const RelocationTable = std.ArrayListUnmanaged(std.ArrayListUnmanaged(Relocation)); const TlvInitializerTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlvInitializer); +const x86_64 = struct { + fn writeTrampolineCode(source_addr: u64, target_addr: u64, buf: *[max_trampoline_len]u8) ![]u8 { + const disp = @as(i64, @intCast(target_addr)) - @as(i64, @intCast(source_addr)) - 5; + var bytes = [_]u8{ + 0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32 + }; + assert(bytes.len == trampolineSize(.x86_64)); + mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little); + @memcpy(buf[0..bytes.len], &bytes); + return buf[0..bytes.len]; + } +}; + const assert = std.debug.assert; const builtin = @import("builtin"); const codegen = @import("../../codegen.zig"); diff --git a/src/link/MachO/dyld_info/Rebase.zig b/src/link/MachO/dyld_info/Rebase.zig index 8809f130ff..2bee8ad22c 100644 --- a/src/link/MachO/dyld_info/Rebase.zig +++ b/src/link/MachO/dyld_info/Rebase.zig @@ -56,18 +56,6 @@ pub fn updateSize(rebase: *Rebase, macho_file: *MachO) !void { } } - if (macho_file.zig_got_sect_index) |sid| { - const seg_id = macho_file.sections.items(.segment_id)[sid]; - const seg = macho_file.segments.items[seg_id]; - for (0..macho_file.zig_got.entries.items.len) |idx| { - const addr = macho_file.zig_got.entryAddress(@intCast(idx), macho_file); - try rebase.entries.append(gpa, .{ - .offset = addr - seg.vmaddr, - .segment_id = seg_id, - }); - } - } - if (macho_file.got_sect_index) |sid| { const seg_id = macho_file.sections.items(.segment_id)[sid]; const seg = macho_file.segments.items[seg_id]; diff --git a/src/link/MachO/synthetic.zig b/src/link/MachO/synthetic.zig index 5285412bb7..35f9d45536 100644 --- a/src/link/MachO/synthetic.zig +++ b/src/link/MachO/synthetic.zig @@ -1,111 +1,3 @@ -pub const ZigGotSection = struct { - entries: std.ArrayListUnmanaged(Symbol.Index) = .{}, - dirty: bool = false, - - pub const Index = u32; - - pub fn deinit(zig_got: *ZigGotSection, allocator: Allocator) void { - zig_got.entries.deinit(allocator); - } - - fn allocateEntry(zig_got: *ZigGotSection, allocator: Allocator) !Index { - try zig_got.entries.ensureUnusedCapacity(allocator, 1); - // TODO add free list - const index = @as(Index, @intCast(zig_got.entries.items.len)); - _ = zig_got.entries.addOneAssumeCapacity(); - zig_got.dirty = true; - return index; - } - - pub fn addSymbol(zig_got: *ZigGotSection, sym_index: Symbol.Index, macho_file: *MachO) !Index { - const gpa = macho_file.base.comp.gpa; - const zo = macho_file.getZigObject().?; - const index = try zig_got.allocateEntry(gpa); - const entry = &zig_got.entries.items[index]; - entry.* = sym_index; - const symbol = &zo.symbols.items[sym_index]; - assert(symbol.getSectionFlags().needs_zig_got); - symbol.setSectionFlags(.{ .has_zig_got = true }); - symbol.addExtra(.{ .zig_got = index }, macho_file); - return index; - } - - pub fn entryOffset(zig_got: ZigGotSection, index: Index, macho_file: *MachO) u64 { - _ = zig_got; - const sect = macho_file.sections.items(.header)[macho_file.zig_got_sect_index.?]; - return sect.offset + @sizeOf(u64) * index; - } - - pub fn entryAddress(zig_got: ZigGotSection, index: Index, macho_file: *MachO) u64 { - _ = zig_got; - const sect = macho_file.sections.items(.header)[macho_file.zig_got_sect_index.?]; - return sect.addr + @sizeOf(u64) * index; - } - - pub fn size(zig_got: ZigGotSection, macho_file: *MachO) usize { - _ = macho_file; - return @sizeOf(u64) * zig_got.entries.items.len; - } - - pub fn writeOne(zig_got: *ZigGotSection, macho_file: *MachO, index: Index) !void { - if (zig_got.dirty) { - const needed_size = zig_got.size(macho_file); - try macho_file.growSection(macho_file.zig_got_sect_index.?, needed_size); - zig_got.dirty = false; - } - const zo = macho_file.getZigObject().?; - const off = zig_got.entryOffset(index, macho_file); - const entry = zig_got.entries.items[index]; - const value = zo.symbols.items[entry].getAddress(.{ .stubs = false }, macho_file); - - var buf: [8]u8 = undefined; - std.mem.writeInt(u64, &buf, value, .little); - try macho_file.base.file.?.pwriteAll(&buf, off); - } - - pub fn writeAll(zig_got: ZigGotSection, macho_file: *MachO, writer: anytype) !void { - const zo = macho_file.getZigObject().?; - for (zig_got.entries.items) |entry| { - const symbol = zo.symbols.items[entry]; - const value = symbol.address(.{ .stubs = false }, macho_file); - try writer.writeInt(u64, value, .little); - } - } - - const FormatCtx = struct { - zig_got: ZigGotSection, - macho_file: *MachO, - }; - - pub fn fmt(zig_got: ZigGotSection, macho_file: *MachO) std.fmt.Formatter(format2) { - return .{ .data = .{ .zig_got = zig_got, .macho_file = macho_file } }; - } - - pub fn format2( - ctx: FormatCtx, - comptime unused_fmt_string: []const u8, - options: std.fmt.FormatOptions, - writer: anytype, - ) !void { - _ = options; - _ = unused_fmt_string; - const zig_got = ctx.zig_got; - const macho_file = ctx.macho_file; - try writer.writeAll("__zig_got\n"); - for (zig_got.entries.items, 0..) |entry, index| { - const zo = macho_file.getZigObject().?; - const symbol = zo.symbols.items[entry]; - try writer.print(" {d}@0x{x} => {d}@0x{x} ({s})\n", .{ - index, - zig_got.entryAddress(@intCast(index), macho_file), - entry, - symbol.getAddress(.{}, macho_file), - symbol.getName(macho_file), - }); - } - } -}; - pub const GotSection = struct { symbols: std.ArrayListUnmanaged(MachO.Ref) = .{},