assembly - 从 Rust 更改 x86 中的执行堆栈
问题描述
我正在尝试手动设置 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\n" \
"xor %%rdx, %%rdx\n" \
"jmp *%[entry]" \
: /* None */ \
: [stack] "r" (jump_stack), [entry] "r" (jump_addr) \
: "rdx", "memory" \
);
}
这是反汇编:
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
而这个 Rust 代码没有:
#![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!();
}
这是生锈的拆卸:
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
(两个反汇编输出都来自 Godbolt explorer)
我不明白两者之间的区别或生成代码的区别意味着什么。
解决方案
jmp [$1]
是您的 AT&T 版本中没有的额外间接级别。
AT&Tjmp *%1
相当于英特尔jmp %1
。
请注意,这%[entry]
只是一种象征性的书写方式%1
;方括号是操作数名称语法的一部分,不会作为寻址模式语法出现在最终的 asm 输出中。
(你的问题也是一团糟,因为你-masm=intel
在 Godbolt 上使用,而你的 GNU C 内联 asm 被编写为使用默认构建-masm=att
。)
其他主要区别是 GCC 默认为-O0
(反优化调试模式),而您在构建 Rust 代码时启用了优化。
您可能应该__builtin_unreachable()
在 Casm("")
语句之后使用,以确保编译器知道执行确实不会从 asm 语句的另一端出来。我担心标记包装函数noreturn
可能不足以阻止编译器假设它可以将存储延迟到 asm 语句之后,在内联之后。(跳出asm
语句通常需要asm goto
已知标签,否则__builtin_unreachable()
建议使用。)
推荐阅读
- c# - 可空值已启用,但“值不能为空”
- reactjs - 如何解决 Material-UI ToggleButtonGroup 中的这种长时间延迟?
- html - 如何制作一个html滚动页面
- python - 手动更改的量化权重未反映在 state_dict()
- c++ - 错误 LNK2019:函数 _main 中引用的未解析外部符号“public:__thiscall RNG::RNG(unsigned __int64)”(??0RNG@@QAE@_K@Z)
- apache-nifi - 恢复 NiFi 项目
- asp.net-mvc - 使用 MVC 5 创建 OAuth2.0 登录应用程序
- java - 弄清楚用户是否输入了数值或其他内容?
- javascript - 如何在我的 Vuex 商店中返回 Promise 而不会收到错误消息?
- html - 这个网格容器的高度是如何计算的?