Merge pull request #2540 from cfallin/x64-tls
Add ELF TLS support in new x64 backend.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
use crate::binemit::{Addend, Reloc};
|
use crate::binemit::{Addend, Reloc};
|
||||||
use crate::ir::immediates::{Ieee32, Ieee64};
|
use crate::ir::immediates::{Ieee32, Ieee64};
|
||||||
|
use crate::ir::LibCall;
|
||||||
use crate::ir::TrapCode;
|
use crate::ir::TrapCode;
|
||||||
use crate::isa::x64::inst::args::*;
|
use crate::isa::x64::inst::args::*;
|
||||||
use crate::isa::x64::inst::*;
|
use crate::isa::x64::inst::*;
|
||||||
@@ -2988,6 +2989,33 @@ pub(crate) fn emit(
|
|||||||
Inst::EpiloguePlaceholder => {
|
Inst::EpiloguePlaceholder => {
|
||||||
// Generate no code.
|
// Generate no code.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inst::ElfTlsGetAddr { ref symbol } => {
|
||||||
|
// 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();
|
state.clear_post_insn();
|
||||||
|
|||||||
@@ -3904,6 +3904,17 @@ fn test_x64_emit() {
|
|||||||
let trap_code = TrapCode::UnreachableCodeReached;
|
let trap_code = TrapCode::UnreachableCodeReached;
|
||||||
insns.push((Inst::Ud2 { trap_code }, "0F0B", "ud2 unreachable"));
|
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!
|
// Actually run the tests!
|
||||||
let mut flag_builder = settings::builder();
|
let mut flag_builder = settings::builder();
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use crate::binemit::{CodeOffset, StackMap};
|
use crate::binemit::{CodeOffset, StackMap};
|
||||||
use crate::ir::{types, ExternalName, Opcode, SourceLoc, TrapCode, Type};
|
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::x64::settings as x64_settings;
|
||||||
|
use crate::isa::CallConv;
|
||||||
use crate::machinst::*;
|
use crate::machinst::*;
|
||||||
use crate::{settings, settings::Flags, CodegenError, CodegenResult};
|
use crate::{settings, settings::Flags, CodegenError, CodegenResult};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
@@ -474,6 +476,10 @@ pub enum Inst {
|
|||||||
/// reports its own `def`s/`use`s/`mod`s; this adds complexity (the instruction list is no
|
/// 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.
|
/// longer flat) and requires knowledge about semantics and initial-value independence anyway.
|
||||||
XmmUninitializedValue { dst: Writable<Reg> },
|
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 {
|
pub(crate) fn low32_will_sign_extend_to_64(x: u64) -> bool {
|
||||||
@@ -532,7 +538,8 @@ impl Inst {
|
|||||||
| Inst::XmmCmpRmR { .. }
|
| Inst::XmmCmpRmR { .. }
|
||||||
| Inst::XmmLoadConst { .. }
|
| Inst::XmmLoadConst { .. }
|
||||||
| Inst::XmmMinMaxSeq { .. }
|
| Inst::XmmMinMaxSeq { .. }
|
||||||
| Inst::XmmUninitializedValue { .. } => None,
|
| Inst::XmmUninitializedValue { .. }
|
||||||
|
| Inst::ElfTlsGetAddr { .. } => None,
|
||||||
|
|
||||||
// These use dynamic SSE opcodes.
|
// These use dynamic SSE opcodes.
|
||||||
Inst::GprToXmm { op, .. }
|
Inst::GprToXmm { op, .. }
|
||||||
@@ -1780,6 +1787,10 @@ impl PrettyPrint for Inst {
|
|||||||
Inst::Hlt => "hlt".into(),
|
Inst::Hlt => "hlt".into(),
|
||||||
|
|
||||||
Inst::Ud2 { trap_code } => format!("ud2 {}", trap_code),
|
Inst::Ud2 { trap_code } => format!("ud2 {}", trap_code),
|
||||||
|
|
||||||
|
Inst::ElfTlsGetAddr { ref symbol } => {
|
||||||
|
format!("elf_tls_get_addr {:?}", symbol)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2039,6 +2050,18 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) {
|
|||||||
| Inst::Fence { .. } => {
|
| Inst::Fence { .. } => {
|
||||||
// No registers are used.
|
// 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) {
|
||||||
|
collector.add_def(reg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2425,6 +2448,7 @@ fn x64_map_regs<RUM: RegUsageMapper>(inst: &mut Inst, mapper: &RUM) {
|
|||||||
| Inst::Ud2 { .. }
|
| Inst::Ud2 { .. }
|
||||||
| Inst::Hlt
|
| Inst::Hlt
|
||||||
| Inst::AtomicRmwSeq { .. }
|
| Inst::AtomicRmwSeq { .. }
|
||||||
|
| Inst::ElfTlsGetAddr { .. }
|
||||||
| Inst::Fence { .. } => {
|
| Inst::Fence { .. } => {
|
||||||
// Instruction doesn't explicitly mention any regs, so it can't have any virtual
|
// 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.
|
// regs that we'd need to remap. Hence no action required.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ use crate::isa::{x64::X64Backend, CallConv};
|
|||||||
use crate::machinst::lower::*;
|
use crate::machinst::lower::*;
|
||||||
use crate::machinst::*;
|
use crate::machinst::*;
|
||||||
use crate::result::CodegenResult;
|
use crate::result::CodegenResult;
|
||||||
use crate::settings::Flags;
|
use crate::settings::{Flags, TlsModel};
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use cranelift_codegen_shared::condcodes::CondCode;
|
use cranelift_codegen_shared::condcodes::CondCode;
|
||||||
@@ -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));
|
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::IaddImm
|
||||||
| Opcode::ImulImm
|
| Opcode::ImulImm
|
||||||
| Opcode::UdivImm
|
| Opcode::UdivImm
|
||||||
|
|||||||
19
cranelift/filetests/filetests/isa/x64/tls_elf.clif
Normal file
19
cranelift/filetests/filetests/isa/x64/tls_elf.clif
Normal file
@@ -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 }
|
||||||
|
; nextln: movq %rbp, %rsp
|
||||||
|
; nextln: popq %rbp
|
||||||
|
; nextln: ret
|
||||||
Reference in New Issue
Block a user