Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions cranelift/codegen/src/isa/x64/inst/emit.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::binemit::{Addend, Reloc};
use crate::ir::immediates::{Ieee32, Ieee64};
use crate::ir::LibCall;
use crate::ir::TrapCode;
use crate::isa::x64::inst::args::*;
use crate::isa::x64::inst::*;
Expand Down Expand Up @@ -2988,6 +2989,33 @@ pub(crate) fn emit(
Inst::EpiloguePlaceholder => {
// Generate no code.
}

Inst::ElfTlsGetAddr { ref symbol } => {
Comment thread
cfallin marked this conversation as resolved.
// N.B.: Must be exactly this byte sequence; the linker requires it,
// because it must know how to rewrite the bytes.

// data16 lea gv@tlsgd(%rip),%rdi
sink.put1(0x66); // data16
sink.put1(0b01001000); // REX.W
sink.put1(0x8d); // LEA
sink.put1(0x3d); // ModRM byte
emit_reloc(sink, state, Reloc::ElfX86_64TlsGd, symbol, -4);
sink.put4(0); // offset

// data16 data16 callq __tls_get_addr-4
sink.put1(0x66); // data16
sink.put1(0x66); // data16
sink.put1(0b01001000); // REX.W
sink.put1(0xe8); // CALL
emit_reloc(
sink,
state,
Reloc::X86CallPLTRel4,
&ExternalName::LibCall(LibCall::ElfTlsGetAddr),
-4,
);
sink.put4(0); // offset
}
}

state.clear_post_insn();
Expand Down
11 changes: 11 additions & 0 deletions cranelift/codegen/src/isa/x64/inst/emit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3904,6 +3904,17 @@ fn test_x64_emit() {
let trap_code = TrapCode::UnreachableCodeReached;
insns.push((Inst::Ud2 { trap_code }, "0F0B", "ud2 unreachable"));

insns.push((
Inst::ElfTlsGetAddr {
symbol: ExternalName::User {
namespace: 0,
index: 0,
},
},
"66488D3D00000000666648E800000000",
"elf_tls_get_addr User { namespace: 0, index: 0 }",
));

// ========================================================
// Actually run the tests!
let mut flag_builder = settings::builder();
Expand Down
26 changes: 25 additions & 1 deletion cranelift/codegen/src/isa/x64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

use crate::binemit::{CodeOffset, StackMap};
use crate::ir::{types, ExternalName, Opcode, SourceLoc, TrapCode, Type};
use crate::isa::x64::abi::X64ABIMachineSpec;
use crate::isa::x64::settings as x64_settings;
use crate::isa::CallConv;
use crate::machinst::*;
use crate::{settings, settings::Flags, CodegenError, CodegenResult};
use alloc::boxed::Box;
Expand Down Expand Up @@ -474,6 +476,10 @@ pub enum Inst {
/// reports its own `def`s/`use`s/`mod`s; this adds complexity (the instruction list is no
/// longer flat) and requires knowledge about semantics and initial-value independence anyway.
XmmUninitializedValue { dst: Writable<Reg> },

/// A call to the `ElfTlsGetAddr` libcall. Returns address
/// of TLS symbol in rax.
ElfTlsGetAddr { symbol: ExternalName },
}

pub(crate) fn low32_will_sign_extend_to_64(x: u64) -> bool {
Expand Down Expand Up @@ -532,7 +538,8 @@ impl Inst {
| Inst::XmmCmpRmR { .. }
| Inst::XmmLoadConst { .. }
| Inst::XmmMinMaxSeq { .. }
| Inst::XmmUninitializedValue { .. } => None,
| Inst::XmmUninitializedValue { .. }
| Inst::ElfTlsGetAddr { .. } => None,

// These use dynamic SSE opcodes.
Inst::GprToXmm { op, .. }
Expand Down Expand Up @@ -1780,6 +1787,10 @@ impl PrettyPrint for Inst {
Inst::Hlt => "hlt".into(),

Inst::Ud2 { trap_code } => format!("ud2 {}", trap_code),

Inst::ElfTlsGetAddr { ref symbol } => {
format!("elf_tls_get_addr {:?}", symbol)
}
}
}
}
Expand Down Expand Up @@ -2039,6 +2050,18 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
| Inst::Fence { .. } => {
// No registers are used.
}

Inst::ElfTlsGetAddr { .. } => {
// All caller-saves are clobbered.
//
// We use the SysV calling convention here because the
// pseudoinstruction (and relocation that it emits) is specific to
// ELF systems; other x86-64 targets with other conventions (i.e.,
// Windows) use different TLS strategies.
for reg in X64ABIMachineSpec::get_regs_clobbered_by_call(CallConv::SystemV) {
Comment thread
cfallin marked this conversation as resolved.
collector.add_def(reg);
}
}
}
}

Expand Down Expand Up @@ -2425,6 +2448,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
| Inst::Ud2 { .. }
| Inst::Hlt
| Inst::AtomicRmwSeq { .. }
| Inst::ElfTlsGetAddr { .. }
| Inst::Fence { .. } => {
// Instruction doesn't explicitly mention any regs, so it can't have any virtual
// regs that we'd need to remap. Hence no action required.
Expand Down
18 changes: 17 additions & 1 deletion cranelift/codegen/src/isa/x64/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::isa::{x64::X64Backend, CallConv};
use crate::machinst::lower::*;
use crate::machinst::*;
use crate::result::CodegenResult;
use crate::settings::Flags;
use crate::settings::{Flags, TlsModel};
use alloc::boxed::Box;
use alloc::vec::Vec;
use cranelift_codegen_shared::condcodes::CondCode;
Expand Down Expand Up @@ -5324,6 +5324,22 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
ctx.emit(Inst::gen_move(dst_hi, src.regs()[1], types::I64));
}

Opcode::TlsValue => match flags.tls_model() {
TlsModel::ElfGd => {
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let (name, _, _) = ctx.symbol_value(insn).unwrap();
let symbol = name.clone();
ctx.emit(Inst::ElfTlsGetAddr { symbol });
ctx.emit(Inst::gen_move(dst, regs::rax(), types::I64));
}
_ => {
todo!(
"Unimplemented TLS model in x64 backend: {:?}",
flags.tls_model()
);
}
},

Opcode::IaddImm
| Opcode::ImulImm
| Opcode::UdivImm
Expand Down
19 changes: 19 additions & 0 deletions cranelift/filetests/filetests/isa/x64/tls_elf.clif
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
test compile
set tls_model=elf_gd
target x86_64
feature "experimental_x64"

function u0:0(i32) -> i64 {
gv0 = symbol colocated tls u1:0

block0(v0: i32):
v1 = global_value.i64 gv0
return v1
}

; check: pushq %rbp
; nextln: movq %rsp, %rbp
; nextln: elf_tls_get_addr User { namespace: 1, index: 0 }
Comment thread
cfallin marked this conversation as resolved.
; nextln: movq %rbp, %rsp
; nextln: popq %rbp
; nextln: ret