From 1afc6917f5e6acc7f7f700b54023a82e4ad923a6 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sat, 11 Nov 2023 17:03:35 +0100 Subject: [PATCH] x86_64: get something going for the local exec model --- src/arch/x86_64/Emit.zig | 2 ++ src/arch/x86_64/Lower.zig | 44 +++++++++++++++++++++++++++++++------- src/link/Elf/Symbol.zig | 7 ++++++ src/link/Elf/ZigObject.zig | 17 ++++++++++++--- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index aa091a89ad..9fac24f5f2 100644 --- a/src/arch/x86_64/Emit.zig +++ b/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, .{ diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index 935fbe8f46..d3b2e7cfb4 100644 --- a/src/arch/x86_64/Lower.zig +++ b/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 => { diff --git a/src/link/Elf/Symbol.zig b/src/link/Elf/Symbol.zig index 1040515de5..eced2880c6 100644 --- a/src/link/Elf/Symbol.zig +++ b/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).?; diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index d79d3eff2c..52f7250cf7 100644 --- a/src/link/Elf/ZigObject.zig +++ b/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;