我正在用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
}
}
}
使用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)
我对NOP之前的6行代码感到困惑(我已用
*
标记)。按理说,naked
指令应该只留下一个裸函数,对吗?我试图通过此函数将参数直接传递给ABI,因为它遵循与Rust大致相同的调用约定,只需要交换一个或两个寄存器,因此需要内联汇编。
有没有办法摆脱这6行先前的指令呢?我经常调用ABI,以前的调用方式会造成相当大的开销。我希望确保包含任何重要值的寄存器不会被覆盖。
顺便提一下:是否需要使用“volatile”选项?我不确定,但无论如何都添加了它。
self
。 - Simon Whitehead