使用内联汇编更改堆栈指针时调用函数会崩溃
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).
这似乎表明您的程序集向后,此外还有所有其他问题。
我已经编写了一些代码,通过修改内联汇编中的堆栈指针来更改当前使用的堆栈。虽然我可以调用函数和创建局部变量,但调用 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).
这似乎表明您的程序集向后,此外还有所有其他问题。