I have the following inline assembly in C:
unsigned long long result; asm volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax" : "=a" (result) :: "%rdx"); return result;
I tried to rewrite it in Rust:
let result: u64; unsafe { asm!(".byte 15\n\t .byte 49\n\t shlq 32, rdx\n\t orq rdx, rax" : "=a"(result) : : "rdx" : "volatile" ); } result
It doesn't recognize the =a
constraint an it gives me an invalid operand error for rdx
and rax
at shlq
and orq
instructions. What is the proper way to rewrite the above C inline assembly in Rust?
Rust is built on top of LLVM, so a lot of low-level detail like this can be gleaned from what LLVM or Clang do.
If you want to specify a specific register, you use the register name as the constraint: "={rax}"(result)
. Based on the GCC documentation, the a
constraint is the "a" register.
Literals must be prefaced with $$
Registers must be prefaced with %
let result: u64; unsafe { asm!(".byte 15 .byte 49 shlq $$32, %rdx orq %rdx, %rax" : "={rax}"(result) : : "rdx" : "volatile" ); } result
If I'm understanding the discussion about rdtsc
correctly, you can also do:
let upper: u64; let lower: u64; unsafe { asm!("rdtsc" : "={rax}"(lower), "={rdx}"(upper) : : : "volatile" ); } upper << 32 | lower
I advise getting out of inline assembly as soon as it's practical.
The assembly of each function:
playground::thing1: #APP .byte 15 .byte 49 shlq $32, %rdx orq %rdx, %rax #NO_APP retq playground::thing2: #APP rdtsc #NO_APP shlq $32, %rdx orq %rdx, %rax retq
For completeness, here is the same code using the LLVM intrinsic. This requires a different unstable attribute:
#![feature(link_llvm_intrinsics)] extern "C" { #[link_name = "llvm.x86.rdtsc"] fn rdtsc() -> u64; } fn main() { println!("{}", unsafe { rdtsc() }) }
Sources: