汇编跳转指令异常排查:我的代码是否符合给定要求?
汇编代码合规性排查与修正
原始需求
- 代码首条指令为
jmp - 该
jmp为相对跳转,跳转到当前位置偏移0x51字节处 - 在0x51位置编写以下代码:
- 将栈顶值存入RDI寄存器
jmp到绝对地址0x403000
初始汇编代码
.intel_syntax noprefix .global _start _start: jmp $+0x51 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop pop rdi mov eax, 0x403000 jmp rax
用户疑问
请问这是否完全符合要求?相对跳转或绝对跳转是否存在问题?
补充尝试代码
. . . nop pop rdi mov rax, 0x403000 jmp fword ptr [eax]
问题分析与修正
1. 相对跳转的偏移问题
x86相对跳转的偏移是相对于下一条指令的地址,但GAS汇编器里的$+offset是基于当前指令地址计算的,汇编器会自动把它转换成符合CPU要求的相对偏移。从目标文件信息来看,你的jmp $+0x51最终生成的机器码偏移是0x4C,计算下来正好能跳到_start+0x51的位置,这部分逻辑是对的。不过手动写一堆nop很容易数错数量,建议用汇编器的重复指令自动填充,避免位置偏差。
2. 绝对跳转的错误
- 初始代码里
mov eax, 0x403000在64位环境下会把rax的高32位清零,虽然0x403000是32位有效地址,但直接用mov rax, 0x403000更稳妥,避免潜在的地址截断问题。 - 你补充的
jmp fword ptr [eax]完全错误:fword ptr是6字节宽度,不适合64位环境;而且[eax]是访问内存地址,相当于跳转到0x403000这个地址里存储的内容,而不是跳转到0x403000本身,彻底违背了需求。正确的绝对跳转逻辑就是把目标地址存入通用寄存器,然后通过jmp 寄存器实现跳转。
3. 栈顶取值的正确性
pop rdi本身符合需求,但要确保程序执行到这里时栈顶有合法值,不过这属于调用上下文的问题,代码本身的指令逻辑是正确的。
修正后的代码
.intel_syntax noprefix .global _start _start: jmp $+0x51 # 汇编器自动转换为正确的相对偏移,目标是_start+0x51 .rept 0x51 - 5 # jmp指令占5字节,自动填充对应数量的nop nop .endr pop rdi mov rax, 0x403000 # 64位环境下直接赋值rax jmp rax # 跳转到寄存器存储的绝对地址0x403000
内容的提问来源于stack exchange,提问作者Samir Amir
相关产品推荐
相关产品推荐

