How do I translate x86 GCC-style C inline assembly to Rust inline assembly?

匿名 (未验证) 提交于 2019-12-03 01:20:02

问题:

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?

回答1:

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.

  1. 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.

  2. Literals must be prefaced with $$

  3. 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:



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!