为什么裸 Rust 函数中有额外的 ASM 指令?

Cha*_*den 5 x86 abi wrapper rust

我在 Rust 中包装了一个低级别的 ABI,利用了naked函数特性。这是我的代码和相关的反汇编

#![feature(asm)]
#![feature(naked_functions)]

struct MyStruct {
    someVar: i64, // not important
                  // ...
}

impl MyStruct {
    #[naked]
    extern "C" fn wrap(&self) {
        unsafe {
            asm!("NOP" :::: "volatile");
            // not sure if the volatile option is needed, but I
            // figured it wouldn't hurt
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用LLDB反汇编:

ABIWrap`ABIWrap::{{impl}}::wrap:
  * 0x100001310 <+0>:  movq   %rdi, -0x10(%rbp)
  * 0x100001314 <+4>:  movq   %rsi, -0x8(%rbp)
  * 0x100001318 <+8>:  movq   -0x10(%rbp), %rax
  * 0x10000131c <+12>: movq   -0x8(%rbp), %rcx
  * 0x100001320 <+16>: movq   %rax, -0x20(%rbp)
  * 0x100001324 <+20>: movq   %rcx, -0x18(%rbp)
    0x100001328 <+24>: nop    
    0x100001329 <+25>: retq   
    0x10000132a <+26>: nopw   (%rax,%rax)
Run Code Online (Sandbox Code Playgroud)

NOP 前面的 6 行(我用 标记*)是我所困惑的。naked由于缺乏更好的术语,该指令不应该留下一个裸函数吗?

我试图让参数只通过这个函数传递给 ABI,因为它遵循与 Rust 大致相同的调用约定,我只需要交换一两个寄存器,因此是内联汇编。

有没有办法摆脱这 6 个前面的指令?我经常反对 ABI,而我以前反对它的方式造成了相当大的开销。我想确保包含任何重要值的寄存器不会被覆盖。

旁注:是否需要“易失性”选项?我不确定,但还是添加了它。

Cha*_*den 3

经过更多修改(并弄清楚如何有效地反汇编我的发布版本),我发现额外的指令仅在调试版本期间添加(或至少在 -O0 时)。

当使用 -O2 编译代码时,我发现所有程序集都是内联的,但这很容易用指令修复#[inline(never)]。现在参数已正确传递,而无需额外的指令破坏我的寄存器:)

现在我只需要让代码只在这些函数上运行 -O2,而不是调试构建的其余部分......