Assembly 从Rust更改x86中的执行堆栈
我正在尝试手动设置RSP,并使用内嵌x86_64程序集在Rust中的自定义地址开始执行 我有一个C代码,它可以工作:Assembly 从Rust更改x86中的执行堆栈,assembly,rust,x86,inline-assembly,Assembly,Rust,X86,Inline Assembly,我正在尝试手动设置RSP,并使用内嵌x86_64程序集在Rust中的自定义地址开始执行 我有一个C代码,它可以工作: #include <stddef.h> void __attribute ((noreturn)) jump_with_stack(size_t jump_addr, size_t *jump_stack) { __asm__ volatile ( \ "movq %[stack], %%rsp
#include <stddef.h>
void __attribute ((noreturn)) jump_with_stack(size_t jump_addr, size_t *jump_stack) {
__asm__ volatile ( \
"movq %[stack], %%rsp\n" \
"xor %%rdx, %%rdx\n" \
"jmp *%[entry]" \
: /* None */ \
: [stack] "r" (jump_stack), [entry] "r" (jump_addr) \
: "rdx", "memory" \
);
}
该防锈代码不:
#![feature(asm)]
pub unsafe extern fn rust_jump_with_stack(target: usize, targ_stack: *mut usize) -> ! {
asm!("mov rsp, $0
xor rdx, rdx
jmp [$1]"
:
:"r"(targ_stack), "r"(target)
: "rdx", "memory"
: "intel");
unreachable!();
}
以下是除锈程序:
jump_with_stack:
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov QWORD PTR [rbp-16], rsi
mov rax, QWORD PTR [rbp-16]
mov rcx, QWORD PTR [rbp-8]
movq rax, %rsp
xor %rdx, %rdx
jmp *rcx
nop
pop rbp
ret
example::rust_jump_with_stack:
push rax
mov rsp, rsi
xor rdx, rdx
jmp qword ptr [rdi]
lea rdi, [rip + .L__unnamed_3]
lea rdx, [rip + .L__unnamed_4]
mov rax, qword ptr [rip + std::panicking::begin_panic@GOTPCREL]
mov esi, 40
call rax
ud2
(两个拆解输出均来自导栓资源管理器)
我不理解两者之间的区别,也不理解生成的代码中的区别意味着什么
jmp[$1]
是AT&t版本中没有的额外间接寻址级别
AT&Tjmp*%1
相当于英特尔jmp%1
请注意,%[entry]
只是一种符号化的书写方式%1
;方括号是操作数名称语法的一部分,不会作为寻址模式语法出现在最终asm输出中
(另外,您的问题完全是一团糟,因为您在Godbolt上使用了-masm=intel
,而您的GNU C内联asm是用默认的-masm=att
构建的)
另一个主要区别是GCC默认为
-O0
(反优化调试模式),而您构建的代码启用了优化
您可能应该在C
asm(“”
语句)之后使用\u builtin\u unreachable()。我担心标记包装函数noreturn
可能不足以防止编译器假定它可以将存储延迟到asm语句之后、内联之后。(跳出asm
语句通常要求已知标签使用asm goto
,否则建议使用\uuuuuu builtin\u unreachable()
。由于您指定了英特尔语法,第一个mov
被颠倒。看起来您编译的锈迹代码启用了优化,但C使用了gcc-O0
。这可能是两个编译器的默认值-O0
是GCC的默认值。您可能希望在asm语句之后使用\uuuuuu attribute\uuuuuuuuu((noinline))
或\uuuuu buildin\u unreachable()
,以确保C函数不能以不安全的方式内联到调用方。我不确定在包装器函数上放置noreturn
是否足够。不过,您仍然在asm模板中使用AT&T语法jmp*%rcx
是AT&T版本的jmp rcx
。您正在RDX上使用%
装饰。在英特尔语法中,应使用xor edx,edx
将RDX归零。另外,如果您有一个指向指针的指针,您希望jmp*([entry])
与您的Rust匹配,或者告诉编译器为您取消对它的引用。e、 g.“rm”(*跳转地址)
对于无效**跳转地址
。无论如何,尝试Godbolt上的二进制模式,将其实际组装为机器代码,然后进行反汇编,而不是仅仅进行内联asm文本替换,而不显示它甚至会进行组装。哦,然后更改Rust版本以匹配C版本,通过使用jmp$1
匹配AT&Tjmp*%1
来消除额外的间接级别。在AT&T中,[entry]
是操作数名称语法的一部分,而不是寻址模式的一部分。