在优化、操作系统或嵌入式开发或其他类型的底层编程过程中,您有时可能需要为正在运行的处理器编写本机汇编代码。“内联汇编”提供了一种简单的方法,将一些汇编指令集成到 Rust 程序中,将 Rust 表达式作为输入寄存器,并将输出直接放入 Rust 变量中。我们在 nightly Rust 中引入了一种新的内联汇编语法,并且我们正在寻求对其的反馈;我们相信这种新语法未来有望稳定下来。
Nightly Rust 长期以来都有一种“内联汇编”(asm!
)的语法;但是,这种语法只是暴露了 LLVM 汇编结构的非常原始的版本,没有任何安全措施来帮助开发人员使用它。即使稍微弄错此语法的任何细节,也往往会产生内部编译器错误 (ICE),而不是您期望从 rustc 获得的友好错误消息。此语法也很容易出错,原因还在于:它看起来与 GCC 的内联汇编语法相似,但存在细微的差异(例如寄存器约束中的名称)。此外,此语法几乎没有希望在任何非 LLVM 后端上得到支持。由于所有这些限制,尽管 asm!
语法是最受欢迎的功能之一,但它极不可能从 nightly 版本升级到 stable Rust 版本。
为了改进 asm!
并将其带给更多用户,Amanieu d'Antras 设计并实现了一种新的、更友好的 asm!
语法。这种语法从概念到编译器实现经历了一个漫长的过程
- 该提案最初是以 内部预 RFC 的形式开始的。
- 内联汇编成为语言团队的第一个 项目组 之一,并在 项目组存储库 中迭代设计 RFC。
- RFC 2873(仍在讨论中)提供了语法及其与 Rust 语言交互的规范。
- 我们将现有的
asm!
重命名为llvm_asm!
,以便目前在 nightly 版本上使用内联汇编的人员可以继续使用现有的语法。(我们计划最终删除此语法,因为它具有脆弱的 ICE 易发特性,但在评估新语法时,我们希望提供旧语法以供比较和替代。) - PR 69171(同样由 Amanieu 完成)在 nightly 版本中实现了新的
asm!
语法。
这是一个使用新的内联汇编语法的示例,用于使用直接的 write
系统调用 在 x86-64 Linux 上将消息打印到标准输出
#![feature(asm)]
fn main() {
let buf = "Hello from asm!\n";
let ret: i32;
unsafe {
asm!(
"syscall",
in("rax") 1, // syscall number
in("rdi") 1, // fd (stdout)
in("rsi") buf.as_ptr(),
in("rdx") buf.len(),
out("rcx") _, // clobbered by syscalls
out("r11") _, // clobbered by syscalls
lateout("rax") ret,
);
}
println!("write returned: {}", ret);
}
(您可以在 playground 上尝试此示例。)
上面的示例指定了 Linux 系统调用约定所需的精确输入、输出和副作用。您还可以通过任意寄存器提供输入和输出,编译器将为您选择合适的寄存器。以下示例使用位操作指令来计算值中所有设置位的位号,并将它们存储在内存切片中
#![feature(asm)]
fn main() {
let mut bits = [0u8; 64];
for value in 0..=1024u64 {
let popcnt;
unsafe {
asm!(
"popcnt {popcnt}, {v}",
"2:",
"blsi rax, {v}",
"jz 1f",
"xor {v}, rax",
"tzcnt rax, rax",
"stosb",
"jmp 2b",
"1:",
v = inout(reg) value => _,
popcnt = out(reg) popcnt,
out("rax") _, // scratch
inout("rdi") bits.as_mut_ptr() => _,
);
}
println!("bits of {}: {:?}", value, &bits[0..popcnt]);
}
}
(您可以在 playground 上尝试此示例。请注意,此代码用于演示内联汇编,而不是演示任何特定算法的有效实现。)
请注意,value
和 popcnt
已为其选择寄存器,而 bits.as_mut_ptr()
必须放入 rdi
寄存器中才能与 stosb
指令一起使用。
另请注意,在 x86 平台上,asm!
默认使用 Intel 语法;但是,您可以使用 option(att_syntax)
使用 AT&T 语法。当将现有的内联汇编代码转换为新的 asm!
语法时,您可能会发现这很有用。
有关新的 asm!
语法的完整详细信息,请参阅RFC 2873。请尝试一下(包括将现有的内联汇编转换为新语法),并通过带有 F-asm
标签的rust issue tracker 报告任何错误。您还可以通过在 Zulip 中的 project-inline-asm 流上创建主题来讨论内联汇编。