diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs index e1253b9597..6622903452 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit.rs @@ -3016,6 +3016,19 @@ pub(crate) fn emit( ); sink.put4(0); // offset } + + Inst::MachOTlsGetAddr { ref symbol } => { + // movq gv@tlv(%rip), %rdi + sink.put1(0x48); // REX.w + sink.put1(0x8b); // MOV + sink.put1(0x3d); // ModRM byte + emit_reloc(sink, state, Reloc::MachOX86_64Tlv, symbol, -4); + sink.put4(0); // offset + + // callq *(%rdi) + sink.put1(0xff); + sink.put1(0x17); + } } state.clear_post_insn(); diff --git a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs index f1e74ae22a..a3e1c9b658 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs @@ -3915,6 +3915,17 @@ fn test_x64_emit() { "elf_tls_get_addr User { namespace: 0, index: 0 }", )); + insns.push(( + Inst::MachOTlsGetAddr { + symbol: ExternalName::User { + namespace: 0, + index: 0, + }, + }, + "488B3D00000000FF17", + "macho_tls_get_addr User { namespace: 0, index: 0 }", + )); + // ======================================================== // Actually run the tests! let mut flag_builder = settings::builder(); diff --git a/cranelift/codegen/src/isa/x64/inst/mod.rs b/cranelift/codegen/src/isa/x64/inst/mod.rs index edc7a65109..d1302cacbc 100644 --- a/cranelift/codegen/src/isa/x64/inst/mod.rs +++ b/cranelift/codegen/src/isa/x64/inst/mod.rs @@ -480,6 +480,10 @@ pub enum Inst { /// A call to the `ElfTlsGetAddr` libcall. Returns address /// of TLS symbol in rax. ElfTlsGetAddr { symbol: ExternalName }, + + /// A Mach-O TLS symbol access. Returns address of the TLS + /// symbol in rax. + MachOTlsGetAddr { symbol: ExternalName }, } pub(crate) fn low32_will_sign_extend_to_64(x: u64) -> bool { @@ -539,7 +543,8 @@ impl Inst { | Inst::XmmLoadConst { .. } | Inst::XmmMinMaxSeq { .. } | Inst::XmmUninitializedValue { .. } - | Inst::ElfTlsGetAddr { .. } => None, + | Inst::ElfTlsGetAddr { .. } + | Inst::MachOTlsGetAddr { .. } => None, // These use dynamic SSE opcodes. Inst::GprToXmm { op, .. } @@ -1791,6 +1796,10 @@ impl PrettyPrint for Inst { Inst::ElfTlsGetAddr { ref symbol } => { format!("elf_tls_get_addr {:?}", symbol) } + + Inst::MachOTlsGetAddr { ref symbol } => { + format!("macho_tls_get_addr {:?}", symbol) + } } } } @@ -2051,7 +2060,7 @@ fn x64_get_regs(inst: &Inst, collector: &mut RegUsageCollector) { // No registers are used. } - Inst::ElfTlsGetAddr { .. } => { + Inst::ElfTlsGetAddr { .. } | Inst::MachOTlsGetAddr { .. } => { // All caller-saves are clobbered. // // We use the SysV calling convention here because the @@ -2449,6 +2458,7 @@ fn x64_map_regs(inst: &mut Inst, mapper: &RUM) { | Inst::Hlt | Inst::AtomicRmwSeq { .. } | Inst::ElfTlsGetAddr { .. } + | Inst::MachOTlsGetAddr { .. } | 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. diff --git a/cranelift/codegen/src/isa/x64/lower.rs b/cranelift/codegen/src/isa/x64/lower.rs index 3339f21b24..45014fca17 100644 --- a/cranelift/codegen/src/isa/x64/lower.rs +++ b/cranelift/codegen/src/isa/x64/lower.rs @@ -5333,6 +5333,13 @@ fn lower_insn_to_regs>( ctx.emit(Inst::ElfTlsGetAddr { symbol }); ctx.emit(Inst::gen_move(dst, regs::rax(), types::I64)); } + TlsModel::Macho => { + 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::MachOTlsGetAddr { symbol }); + ctx.emit(Inst::gen_move(dst, regs::rax(), types::I64)); + } _ => { todo!( "Unimplemented TLS model in x64 backend: {:?}",