我在x86_64 Linux上试验了Rust的内联汇编功能。我编写了一个简单的程序,使用值23调用exit
系统调用。
#![feature(asm)]
fn main() {
unsafe {
asm!(
"
mov $$60, %rax
mov $$23, %rdi
syscall
"
:
:
: "%rax", "%rdi"
);
}
}
这个程序工作正常,我可以rustc exit.rs; ./exit; echo $?
得到23.现在我想用rust做asm代码接口。因此,我将23英寸从锈中传出,而不是在装配中硬编码。
#![feature(asm)]
fn main() {
unsafe {
asm!(
"
mov $$60, %rax
mov $0, %rdi
syscall
"
:
: "r"(23)
: "%rax", "%rdi"
);
}
}
再次,这是有效的。现在我尝试使用变量传递23。
#![feature(asm)]
fn main() {
let x = 23i;
unsafe {
asm!(
"
mov $$60, %rax
mov $0, %rdi
syscall
"
:
: "r"(x)
: "%rax", "%rdi"
);
}
}
这打破了。它以60而不是23退出。查看生成的程序集显示原因:
movq $23, (%rsp)
movq (%rsp), %rax
#APP
movq $60, %rax
movq %rax, %rdi
syscall
编译器尝试将23保存到%rax
,但在内联程序集中,%rax
会被60覆盖。
那么,这是一个编译器错误吗?或者我现在不知道如何使用内联汇编? (后者很可能)。
编辑:根据请求,LLVM IR输出为:
; ModuleID = 'exit.0.rs'
target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; Function Attrs: uwtable
define internal void @_ZN4main20h2dd3717eeddb6da6eaaE() unnamed_addr #0 {
entry-block:
%x = alloca i64
store i64 23, i64* %x
%0 = load i64* %x
call void asm "\0A mov $$60, %rax\0A mov $0, %rdi\0A syscall\0A ", "r,~{%rax},~{%rdi},~{dirflag},~{fpsr},~{flags}"(i64 %0), !srcloc !0
ret void
}
define i64 @main(i64, i8**) unnamed_addr #1 {
top:
%2 = call i64 @_ZN2rt10lang_start20h6ebacfb5a732c9b9PfyE(i8* bitcast (void ()* @_ZN4main20h2dd3717eeddb6da6eaaE to i8*), i64 %0, i8** %1)
ret i64 %2
}
declare i64 @_ZN2rt10lang_start20h6ebacfb5a732c9b9PfyE(i8*, i64, i8**) unnamed_addr #1
attributes #0 = { uwtable "split-stack" }
attributes #1 = { "split-stack" }
!0 = metadata !{i32 21}
答案 0 :(得分:3)
解决了,感谢github上的@pczarn。问题是,应该写下"rax", "rdi"
而不是"%rax", "%rdi"
。