// min-llvm-version: 12.0.1 // only-x86_64 // only-linux // needs-asm-support // run-pass #![feature(thread_local, asm_sym)] use std::arch::asm; extern "C" fn f1() -> i32 { 111 } // The compiler will generate a shim to hide the caller location parameter. #[track_caller] fn f2() -> i32 { 222 } macro_rules! call { ($func:path) => { unsafe { let result: i32; asm!("call {}", sym $func, out("rax") result, out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _, out("r8") _, out("r9") _, out("r10") _, out("r11") _, out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _, out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _, out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _, out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _, ); result } } } macro_rules! static_addr { ($s:expr) => { unsafe { let result: *const u32; // LEA performs a RIP-relative address calculation and returns the address asm!("lea {}, [rip + {}]", out(reg) result, sym $s); result } } } macro_rules! static_tls_addr { ($s:expr) => { unsafe { let result: *const u32; asm!( " # Load TLS base address mov {out}, qword ptr fs:[0] # Calculate the address of sym in the TLS block. The @tpoff # relocation gives the offset of the symbol from the start # of the TLS block. lea {out}, [{out} + {sym}@tpoff] ", out = out(reg) result, sym = sym $s ); result } } } static S1: u32 = 111; #[thread_local] static S2: u32 = 222; fn main() { assert_eq!(call!(f1), 111); assert_eq!(call!(f2), 222); assert_eq!(static_addr!(S1), &S1 as *const u32); assert_eq!(static_tls_addr!(S2), &S2 as *const u32); std::thread::spawn(|| { assert_eq!(static_addr!(S1), &S1 as *const u32); assert_eq!(static_tls_addr!(S2), &S2 as *const u32); }) .join() .unwrap(); }