Commit 1afc6917f5

Jakub Konka <kubkon@jakubkonka.com>
2023-11-11 17:03:35
x86_64: get something going for the local exec model
1 parent b48baee
Changed files (4)
src/arch/x86_64/Emit.zig
@@ -120,6 +120,8 @@ pub fn emitMir(emit: *Emit) Error!void {
                                 link.File.Elf.R_X86_64_ZIG_GOT32
                             else if (sym.flags.needs_got)
                                 std.elf.R_X86_64_GOT32
+                            else if (sym.isTls(elf_file))
+                                std.elf.R_X86_64_TPOFF32
                             else
                                 std.elf.R_X86_64_32;
                             try atom.addReloc(elf_file, .{
src/arch/x86_64/Lower.zig
@@ -319,20 +319,25 @@ fn reloc(lower: *Lower, target: Reloc.Target) Immediate {
     return Immediate.s(0);
 }
 
-fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
-    const needsZigGot = struct {
-        fn needsZigGot(sym: bits.Symbol, ctx: *link.File) bool {
-            const elf_file = ctx.cast(link.File.Elf).?;
-            const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);
-            return elf_file.symbol(sym_index).flags.needs_zig_got;
-        }
-    }.needsZigGot;
+fn needsZigGot(sym: bits.Symbol, ctx: *link.File) bool {
+    const elf_file = ctx.cast(link.File.Elf).?;
+    const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);
+    return elf_file.symbol(sym_index).flags.needs_zig_got;
+}
+
+fn isTls(sym: bits.Symbol, ctx: *link.File) bool {
+    const elf_file = ctx.cast(link.File.Elf).?;
+    const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);
+    return elf_file.symbol(sym_index).isTls(elf_file);
+}
 
+fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) Error!void {
     const is_obj_or_static_lib = switch (lower.bin_file.options.output_mode) {
         .Exe => false,
         .Obj => true,
         .Lib => lower.bin_file.options.link_mode == .Static,
     };
+
     var emit_prefix = prefix;
     var emit_mnemonic = mnemonic;
     var emit_ops_storage: [4]Operand = undefined;
@@ -346,6 +351,29 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
                     assert(prefix == .none);
                     assert(mem_op.sib.disp == 0);
                     assert(mem_op.sib.scale_index.scale == 0);
+
+                    if (isTls(sym, lower.bin_file)) {
+                        lower.result_insts[lower.result_insts_len] =
+                            try Instruction.new(.none, .mov, &[_]Operand{
+                            .{ .reg = ops[0].reg.to64() },
+                            .{ .mem = Memory.sib(.qword, .{ .base = .{ .reg = .fs } }) },
+                        });
+                        lower.result_insts_len += 1;
+                        _ = lower.reloc(.{ .linker_reloc = sym });
+                        if (lower.bin_file.cast(link.File.Elf)) |elf_file| {
+                            const sym_index = elf_file.zigObjectPtr().?.symbol(sym.sym_index);
+                            elf_file.symbol(sym_index).flags.needs_zig_got = false;
+                        }
+                        emit_mnemonic = .lea;
+                        switch (mnemonic) {
+                            .lea, .mov => break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{
+                                .base = .{ .reg = ops[0].reg.to64() },
+                                .disp = undefined,
+                            }) },
+                            else => unreachable,
+                        }
+                    }
+
                     _ = lower.reloc(.{ .linker_reloc = sym });
                     break :op if (lower.bin_file.options.pic) switch (mnemonic) {
                         .lea => {
src/link/Elf/Symbol.zig
@@ -51,6 +51,13 @@ pub fn isIFunc(symbol: Symbol, elf_file: *Elf) bool {
     return symbol.type(elf_file) == elf.STT_GNU_IFUNC;
 }
 
+// TODO this check is enough for ZigObject emitted TLS vars but what about those emitted
+// by different backends/compilers?
+pub fn isTls(symbol: Symbol, elf_file: *Elf) bool {
+    if (symbol.file(elf_file) == null) return false;
+    return symbol.type(elf_file) == elf.STT_TLS;
+}
+
 pub fn @"type"(symbol: Symbol, elf_file: *Elf) u4 {
     const esym = symbol.elfSym(elf_file);
     const file_ptr = symbol.file(elf_file).?;
src/link/Elf/ZigObject.zig
@@ -723,7 +723,18 @@ pub fn getOrCreateMetadataForDecl(
 ) !Symbol.Index {
     const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index);
     if (!gop.found_existing) {
-        gop.value_ptr.* = .{ .symbol_index = try self.addAtom(elf_file) };
+        const symbol_index = try self.addAtom(elf_file);
+        const mod = elf_file.base.options.module.?;
+        const decl = mod.declPtr(decl_index);
+        const single_threaded = elf_file.base.options.single_threaded;
+        if (decl.getOwnedVariable(mod)) |variable| {
+            if (variable.is_threadlocal and !single_threaded) {
+                const sym = elf_file.symbol(symbol_index);
+                self.elfSym(sym.esym_index).st_info = elf.STT_TLS;
+            }
+        }
+
+        gop.value_ptr.* = .{ .symbol_index = symbol_index };
     }
     return gop.value_ptr.symbol_index;
 }
@@ -891,7 +902,7 @@ fn updateTlv(
     const decl = mod.declPtr(decl_index);
     const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
 
-    log.debug("updateTlv {s}{*}", .{ decl_name, decl });
+    log.debug("updateTlv {s} ({*})", .{ decl_name, decl });
 
     const required_alignment = decl.getAlignment(mod);
 
@@ -906,7 +917,7 @@ fn updateTlv(
     atom_ptr.flags.alive = true;
     atom_ptr.name_offset = sym.name_offset;
     esym.st_name = sym.name_offset;
-    esym.st_info |= elf.STT_TLS;
+    esym.st_info = elf.STT_TLS;
     esym.st_size = code.len;
 
     atom_ptr.alignment = required_alignment;