Skip to content

Commit

Permalink
macho: update codegen and linker to distributed jump table approach
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed Aug 16, 2024
1 parent 90989be commit 28fe2fd
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 272 deletions.
48 changes: 25 additions & 23 deletions src/arch/x86_64/CodeGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12341,13 +12341,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);
Expand All @@ -12369,6 +12366,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),
Expand All @@ -12387,6 +12393,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;
Expand Down Expand Up @@ -15281,15 +15293,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", .{});
}

Expand Down Expand Up @@ -15380,13 +15383,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) {
Expand Down
16 changes: 2 additions & 14 deletions src/arch/x86_64/Emit.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 13 additions & 7 deletions src/arch/x86_64/Lower.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 3 additions & 3 deletions src/codegen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -911,15 +911,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 GenResult.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 GenResult.mcv(.{ .load_tlv = sym.nlist_idx });
}
return GenResult.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
Expand Down
29 changes: 0 additions & 29 deletions src/link/MachO.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 = .{},
Expand All @@ -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,
Expand Down Expand Up @@ -321,7 +318,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);
Expand Down Expand Up @@ -1818,7 +1814,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,
Expand Down Expand Up @@ -2107,7 +2102,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,
Expand Down Expand Up @@ -3220,18 +3214,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
});
}

{
const filesize = options.symbol_count_hint * @sizeOf(u64);
const off = 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 = self.findFreeSpace(filesize, self.getPageSize());
Expand Down Expand Up @@ -3331,13 +3313,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()) {
Expand Down Expand Up @@ -3564,7 +3539,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,
Expand All @@ -3579,7 +3553,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,
Expand Down Expand Up @@ -3949,7 +3922,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()});
Expand Down Expand Up @@ -4658,7 +4630,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");

Expand Down
22 changes: 1 addition & 21 deletions src/link/MachO/Atom.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
},
Expand Down Expand Up @@ -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 {
Expand All @@ -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),
}),
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 0 additions & 3 deletions src/link/MachO/Relocation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 28fe2fd

Please sign in to comment.