Commit 96441bd829
Changed files (11)
src
arch
link
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) {
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
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,
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];
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,
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)
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;
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) = .{},
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");
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");
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 GenResult.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 GenResult.mcv(.{ .lea_symbol = sym.nlist_idx });
} else if (lf.cast(.coff)) |coff_file| {
if (is_extern) {
// TODO audit this