我编写了一些代码,通过修改内联汇编中的堆栈指针来更改当前堆栈。虽然我可以调用函数并创建局部变量,但是调用println!
和来自std::rt
的一些函数会导致应用程序在the playpen中使用信号4(非法指令)异常终止。我应该如何改进代码以防止崩溃?
#![feature(asm, box_syntax)]
#[allow(unused_assignments)]
#[inline(always)]
unsafe fn get_sp() -> usize {
let mut result = 0usize;
asm!("
movq %rsp, $0
"
:"=r"(result):::"volatile"
);
result
}
#[inline(always)]
unsafe fn set_sp(value: usize) {
asm!("
movq $0, %rsp
"
::"r"(value)::"volatile"
);
}
#[inline(never)]
unsafe fn foo() {
println!("Hello World!");
}
fn main() {
unsafe {
let mut stack = box [0usize; 500];
let len = stack.len();
stack[len-1] = get_sp();
set_sp(std::mem::transmute(stack.as_ptr().offset((len as isize)-1)));
foo();
asm!("
movq (%rsp), %rsp
"
::::"volatile"
);
}
}
答案 0 :(得分:2)
在OS X上的x86_64上使用rust-lldb调试程序会产生300K堆栈跟踪,一遍又一遍地重复这些行:
frame #299995: 0x00000001000063c4 a`rt::util::report_overflow::he556d9d2b8eebb88VbI + 36
frame #299996: 0x0000000100006395 a`rust_stack_exhausted + 37
frame #299997: 0x000000010000157f a`__morestack + 13
morestack
是每个平台的汇编,例如i386
和x86_64
- i386变体有更多描述,我认为您需要仔细阅读。这篇文章对我说:
每个Rust函数都包含一个LLVM生成的序言,它将当前函数所需的堆栈空间与当前堆栈段中剩余的空间进行比较,并在特定于平台的TLS插槽中进行维护。
以下是foo
方法的第一条说明:
a`foo::h5f80496ac1ee3d43zaa:
0x1000013e0: cmpq %gs:0x330, %rsp
0x1000013e9: ja 0x100001405 ; foo::h5f80496ac1ee3d43zaa + 37
0x1000013eb: movabsq $0x48, %r10
0x1000013f5: movabsq $0x0, %r11
-> 0x1000013ff: callq 0x100001572 ; __morestack
如您所见,我即将调用__morestack
,因此比较检查失败。
我相信这表明你无法操纵堆栈指针并尝试调用任何Rust函数。
作为旁注,让我们来看看你的get_sp
汇编:
movq %rsp, $0
将源操作数(第二个操作数)中的四字复制到目标操作数(第一个操作数)。
除了所有其他问题之外,这似乎表明您的程序集向后。