From 984c5985907fdb6f48543e3d1e27ffd4d54b0957 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 12 Nov 2023 10:28:45 +0100 Subject: [PATCH] x86_64: emit TLS local dynamic model when PIC --- src/arch/x86_64/Emit.zig | 18 +++++++++++ src/arch/x86_64/Lower.zig | 68 ++++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/arch/x86_64/Emit.zig b/src/arch/x86_64/Emit.zig index 9fac24f5f2..baa438b0d1 100644 --- a/src/arch/x86_64/Emit.zig +++ b/src/arch/x86_64/Emit.zig @@ -84,6 +84,24 @@ pub fn emitMir(emit: *Emit) Error!void { } else return emit.fail("TODO implement extern reloc for {s}", .{ @tagName(emit.lower.bin_file.tag), }), + .linker_tlsld => |data| { + const elf_file = emit.lower.bin_file.cast(link.File.Elf).?; + const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; + try atom.addReloc(elf_file, .{ + .r_offset = end_offset - 4, + .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_TLSLD, + .r_addend = -4, + }); + }, + .linker_dtpoff => |data| { + const elf_file = emit.lower.bin_file.cast(link.File.Elf).?; + const atom = elf_file.symbol(data.atom_index).atom(elf_file).?; + try atom.addReloc(elf_file, .{ + .r_offset = end_offset - 4, + .r_info = (@as(u64, @intCast(data.sym_index)) << 32) | std.elf.R_X86_64_DTPOFF32, + .r_addend = 0, + }); + }, .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| { const is_obj_or_static_lib = switch (emit.lower.bin_file.options.output_mode) { .Exe => false, diff --git a/src/arch/x86_64/Lower.zig b/src/arch/x86_64/Lower.zig index d3b2e7cfb4..fb3b60c5fd 100644 --- a/src/arch/x86_64/Lower.zig +++ b/src/arch/x86_64/Lower.zig @@ -11,6 +11,7 @@ result_relocs_len: u8 = undefined, result_insts: [ std.mem.max(usize, &.{ 1, // non-pseudo instructions + 3, // TLS local dynamic (LD) sequence in PIC mode 2, // cmovcc: cmovcc \ cmovcc 3, // setcc: setcc \ setcc \ logicop 2, // jcc: jcc \ jcc @@ -28,6 +29,7 @@ result_relocs: [ 2, // jcc: jcc \ jcc 2, // test \ jcc \ probe \ sub \ jmp 1, // probe \ sub \ jcc + 3, // TLS local dynamic (LD) sequence in PIC mode }) ]Reloc = undefined, @@ -51,6 +53,8 @@ pub const Reloc = struct { const Target = union(enum) { inst: Mir.Inst.Index, linker_reloc: bits.Symbol, + linker_tlsld: bits.Symbol, + linker_dtpoff: bits.Symbol, linker_extern_fn: bits.Symbol, linker_got: bits.Symbol, linker_direct: bits.Symbol, @@ -353,24 +357,56 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand) 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, .{ + // TODO handle extern TLS vars, i.e., emit GD model + if (lower.bin_file.options.pic) { + // Here, we currently assume local dynamic TLS vars, and so + // we emit LD model. + _ = lower.reloc(.{ .linker_tlsld = sym }); + lower.result_insts[lower.result_insts_len] = + try Instruction.new(.none, .lea, &[_]Operand{ + .{ .reg = ops[0].reg.to64() }, + .{ .mem = Memory.rip(mem_op.sib.ptr_size, 0) }, + }); + lower.result_insts_len += 1; + if (lower.bin_file.cast(link.File.Elf)) |elf_file| { + _ = lower.reloc(.{ .linker_extern_fn = .{ + .atom_index = sym.atom_index, + .sym_index = try elf_file.getGlobalSymbol("__tls_get_address", null), + } }); + } + lower.result_insts[lower.result_insts_len] = + try Instruction.new(.none, .call, &[_]Operand{ + .{ .imm = Immediate.s(0) }, + }); + lower.result_insts_len += 1; + _ = lower.reloc(.{ .linker_dtpoff = 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; + break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ .base = .{ .reg = ops[0].reg.to64() }, .disp = undefined, - }) }, - else => unreachable, + }) }; + } else { + // Since we are linking statically, we emit LE model directly. + 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; + break :op .{ .mem = Memory.sib(mem_op.sib.ptr_size, .{ + .base = .{ .reg = ops[0].reg.to64() }, + .disp = undefined, + }) }; } }