Merge pull request #21098 from ziglang/macho-zig-got

macho: replace __got_zig with distributed jump table
This commit is contained in:
Jakub Konka 2024-08-17 17:17:01 +02:00 committed by GitHub
commit 5d2bf96c02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 147 additions and 272 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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");

View File

@ -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,

View File

@ -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)

View File

@ -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;

View File

@ -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");

View File

@ -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];

View File

@ -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) = .{},