使用内联汇编更改堆栈指针时,调用函数会崩溃

时间:2015-04-17 21:36:13

标签: stack rust inline-assembly

我编写了一些代码,通过修改内联汇编中的堆栈指针来更改当前堆栈。虽然我可以调用函数并创建局部变量,但是调用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"
        );
    }
}

1 个答案:

答案 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是每个平台的汇编,例如i386x86_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

检查the semantics of movq

  

将源操作数(第二个操作数)中的四字复制到目标操作数(第一个操作数)。

除了所有其他问题之外,这似乎表明您的程序集向后