mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 06:40:25 +00:00
Merge pull request #21098 from ziglang/macho-zig-got
macho: replace __got_zig with distributed jump table
This commit is contained in:
commit
5d2bf96c02
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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];
|
||||
|
@ -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) = .{},
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user