Commit fd52d4537a

Jakub Konka <kubkon@jakubkonka.com>
2023-04-12 12:06:49
x86_64: emit pointer to TLV for macho
1 parent 1f6165f
Changed files (5)
src/arch/aarch64/CodeGen.zig
@@ -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: {
src/arch/x86_64/CodeGen.zig
@@ -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| {
src/arch/x86_64/Emit.zig
@@ -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 },
src/arch/x86_64/Mir.zig
@@ -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 {
src/codegen.zig
@@ -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| {