Reputation: 3424
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?
Upvotes: 5
Views: 2246
Reputation: 430791
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:
asm
.Upvotes: 6