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

Calling a function crashes when the stack pointer is changed with 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, [=10=]
        "
        :"=r"(result):::"volatile"
    );
    result
}

#[inline(always)]
unsafe fn set_sp(value: usize) {
    asm!("
        movq [=10=], %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"
        );
    }
}

在 x86_64 上使用 rust-lldb 在 OS X 上调试程序会产生 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 and x86_64 — i386 变体有更多描述,我认为您需要仔细阅读。这篇文章让我印象深刻:

Each Rust function contains an LLVM-generated prologue that compares the stack space required for the current function to the space remaining in the current stack segment, maintained in a platform-specific TLS slot.

这里是 foo 方法的第一条指令:

a`foo::h5f80496ac1ee3d43zaa:
   0x1000013e0:  cmpq   %gs:0x330, %rsp
   0x1000013e9:  ja     0x100001405               ; foo::h5f80496ac1ee3d43zaa + 37
   0x1000013eb:  movabsq [=11=]x48, %r10
   0x1000013f5:  movabsq [=11=]x0, %r11
-> 0x1000013ff:  callq  0x100001572               ; __morestack

如你所见,我即将调入__morestack,所以比较检查失败。

我认为这表明您不能操纵堆栈指针并尝试调用任何 Rust 函数。

作为旁注,让我们看看您的 get_sp 程序集:

movq %rsp, [=12=]

正在检查 the semantics of movq:

Copies a quadword from the source operand (second operand) to the destination operand (first operand).

这似乎表明您的程序集向后,此外还有所有其他问题。