如何将x86 GCC样式的C内联汇编转换为Rust内联汇编?

时间:2018-01-04 15:54:06

标签: assembly rust

我在C中有以下内联汇编:

unsigned long long result;
asm volatile(".byte 15;.byte 49;shlq $32,%%rdx;orq %%rdx,%%rax"
    : "=a" (result) ::  "%rdx");
return result;

我试图在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

它无法识别=a约束,它会在rdxraxshlqorq给出一个无效的操作数错误。在Rust中重写上述C内联汇编的正确方法是什么?

1 个答案:

答案 0 :(得分:5)

Rust是建立在LLVM之上的,所以很多像这样的低级细节可以从LLVM或Clang那里收集。

  1. 如果要指定特定寄存器,请使用寄存器名称作为约束:"={rax}"(result)。基于the GCC documentationa约束是“a”寄存器。

  2. 文字必须以$$

  3. 开头
  4. 注册表必须以%

  5. 开头
    let result: u64;
    unsafe {
        asm!(".byte 15
              .byte 49
              shlq $$32, %rdx
              orq  %rdx, %rax"
             : "={rax}"(result)
             :
             : "rdx"
             : "volatile"
        );
    }
    result
    

    如果我正确理解有关rdtsc的讨论,您也可以这样做:

    let upper: u64;
    let lower: u64;
    unsafe {
        asm!("rdtsc"
             : "={rax}"(lower), 
               "={rdx}"(upper)
             :
             :
             : "volatile"
        );
    }
    upper << 32 | lower
    

    我建议在实际操作时尽快 out out

    每个功能的组装:

    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
    

    为了完整性,这里使用LLVM内在的代码相同。这需要不同的不稳定属性:

    #![feature(link_llvm_intrinsics)]
    
    extern "C" {
        #[link_name = "llvm.x86.rdtsc"]
        fn rdtsc() -> u64;
    }
    
    fn main() {
        println!("{}", unsafe { rdtsc() })
    }
    

    来源: