x86_64: emit pointer to TLV for macho

This commit is contained in:
Jakub Konka 2023-04-12 12:06:49 +02:00
parent 1f6165f621
commit fd52d4537a
5 changed files with 68 additions and 3 deletions

View File

@ -3982,6 +3982,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.got => .load_memory_ptr_got,
.direct => .load_memory_ptr_direct,
.import => unreachable,
.tlv => @panic("TODO TLV support"),
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@ -5510,6 +5511,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
.got => .load_memory_ptr_got,
.direct => .load_memory_ptr_direct,
.import => unreachable,
.tlv => @panic("TODO TLV support"),
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@ -5630,6 +5632,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
.got => .load_memory_got,
.direct => .load_memory_direct,
.import => .load_memory_import,
.tlv => @panic("TODO TLV support"),
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {
@ -5830,6 +5833,7 @@ fn genSetStackArgument(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) I
.got => .load_memory_ptr_got,
.direct => .load_memory_ptr_direct,
.import => unreachable,
.tlv => @panic("TODO TLV support"),
};
const atom_index = switch (self.bin_file.tag) {
.macho => blk: {

View File

@ -736,6 +736,7 @@ fn asmMovLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codege
.got => .got_reloc,
.direct => .direct_reloc,
.import => .import_reloc,
.tlv => .tlv_reloc,
};
_ = try self.addInst(.{
.tag = .mov_linker,
@ -753,6 +754,7 @@ fn asmLeaLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codege
.got => .got_reloc,
.direct => .direct_reloc,
.import => .import_reloc,
.tlv => .tlv_reloc,
};
_ = try self.addInst(.{
.tag = .lea_linker,
@ -765,6 +767,15 @@ fn asmLeaLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codege
});
}
fn genTlvPtr(self: *Self, reg: Register, atom_index: u32, linker_load: codegen.LinkerLoad) !void {
assert(linker_load.type == .tlv);
if (self.bin_file.cast(link.File.MachO)) |_| {
try self.asmMovLinker(.rdi, atom_index, linker_load);
try self.asmMemory(.call, Memory.sib(.qword, .{ .base = .rdi }));
try self.genSetReg(Type.usize, reg, .{ .register = .rax });
} else return self.fail("TODO emit ptr-to-TLV sequence on {s}", .{@tagName(self.bin_file.tag)});
}
fn gen(self: *Self) InnerError!void {
const cc = self.fn_type.fnCallingConvention();
if (cc != .Naked) {
@ -2931,6 +2942,7 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
@ -3805,6 +3817,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -3866,6 +3879,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
switch (load_struct.type) {
.import => unreachable,
.got, .direct => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.tlv => {
try self.genTlvPtr(addr_reg, atom_index, load_struct);
// Load the pointer, which is stored in memory
try self.asmRegisterMemory(.mov, addr_reg, Memory.sib(.qword, .{ .base = addr_reg }));
},
}
},
else => unreachable,
@ -4221,6 +4239,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -4896,6 +4915,7 @@ fn genBinOp(
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -5042,6 +5062,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
.import => unreachable,
.got => try self.asmMovLinker(dst_addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(dst_addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(dst_addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -5087,6 +5108,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s
.import => unreachable,
.got => try self.asmMovLinker(src_addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(src_addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(src_addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -6124,6 +6146,7 @@ fn isNull(self: *Self, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -7081,6 +7104,7 @@ fn genSetStackArg(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue) InnerE
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -7308,6 +7332,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
.import => unreachable,
.got => try self.asmMovLinker(addr_reg, atom_index, load_struct),
.direct => try self.asmLeaLinker(addr_reg, atom_index, load_struct),
.tlv => try self.genTlvPtr(addr_reg, atom_index, load_struct),
}
},
else => unreachable,
@ -7439,6 +7464,11 @@ fn genInlineMemcpy(
switch (load_struct.type) {
.import => unreachable,
.got, .direct => try self.asmMovLinker(.rdi, atom_index, load_struct),
.tlv => {
try self.genTlvPtr(.rdi, atom_index, load_struct);
// Load the pointer, which is stored in memory
try self.asmRegisterMemory(.mov, .rdi, Memory.sib(.qword, .{ .base = .rdi }));
},
}
},
.stack_offset, .ptr_stack_offset => |off| {
@ -7481,6 +7511,11 @@ fn genInlineMemcpy(
switch (load_struct.type) {
.import => unreachable,
.got, .direct => try self.asmMovLinker(.rsi, atom_index, load_struct),
.tlv => {
try self.genTlvPtr(.rsi, atom_index, load_struct);
// Load the pointer, which is stored in memory
try self.asmRegisterMemory(.mov, .rsi, Memory.sib(.qword, .{ .base = .rsi }));
},
}
},
.stack_offset, .ptr_stack_offset => |off| {
@ -7546,6 +7581,11 @@ fn genInlineMemset(
switch (load_struct.type) {
.import => unreachable,
.got, .direct => try self.asmMovLinker(.rdi, atom_index, load_struct),
.tlv => {
try self.genTlvPtr(.rdi, atom_index, load_struct);
// Load the pointer, which is stored in memory
try self.asmRegisterMemory(.mov, .rdi, Memory.sib(.qword, .{ .base = .rdi }));
},
}
},
.stack_offset, .ptr_stack_offset => |off| {
@ -7735,7 +7775,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
switch (ty.zigTypeTag()) {
.Float => {
const base_reg = (try self.register_manager.allocReg(null, gp)).to64();
try self.asmLeaLinker(base_reg, atom_index, load_struct);
switch (load_struct.type) {
.tlv => try self.genTlvPtr(base_reg, atom_index, load_struct),
else => try self.asmLeaLinker(base_reg, atom_index, load_struct),
}
if (intrinsicsAllowed(self.target.*, ty)) {
return self.asmRegisterMemory(
@ -7753,7 +7796,17 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
},
else => try self.asmMovLinker(registerAlias(reg, abi_size), atom_index, load_struct),
else => switch (load_struct.type) {
.tlv => {
try self.genTlvPtr(reg.to64(), atom_index, load_struct);
try self.asmRegisterMemory(
.mov,
registerAlias(reg, abi_size),
Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
);
},
else => try self.asmMovLinker(registerAlias(reg, abi_size), atom_index, load_struct),
},
}
},
.stack_offset => |off| {

View File

@ -76,6 +76,7 @@ pub fn emitMir(emit: *Emit) Error!void {
.type = switch (inst.ops) {
.got_reloc => .got,
.direct_reloc => .signed,
.tlv_reloc => .tlv,
else => unreachable,
},
.target = .{ .sym_index = metadata.sym_index, .file = null },

View File

@ -404,6 +404,9 @@ pub const Inst = struct {
/// Linker relocation - imports table indirection (binding).
/// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
import_reloc,
/// Linker relocation - threadlocal variable via GOT indirection.
/// Uses `payload` payload with extra data of type `LeaRegisterReloc`.
tlv_reloc,
};
pub const Data = union {

View File

@ -912,11 +912,13 @@ fn lowerDeclRef(
/// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc)
/// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc)
/// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc)
/// * tlv - the value is a threadlocal variable referenced indirectly via GOT (the linker emits a got-type reloc)
pub const LinkerLoad = struct {
type: enum {
got,
direct,
import,
tlv,
},
sym_index: u32,
};
@ -991,6 +993,8 @@ fn genDeclRef(
module.markDeclAlive(decl);
const is_threadlocal = tv.val.isPtrToThreadLocal(module) and !bin_file.options.single_threaded;
if (bin_file.cast(link.File.Elf)) |elf_file| {
const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index);
const atom = elf_file.getAtom(atom_index);
@ -999,7 +1003,7 @@ fn genDeclRef(
const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index);
const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?;
return GenResult.mcv(.{ .linker_load = .{
.type = .got,
.type = if (is_threadlocal) .tlv else .got,
.sym_index = sym_index,
} });
} else if (bin_file.cast(link.File.Coff)) |coff_file| {