如何在Linux内联扩展汇编中实现jmp [rip+foo]?
实现64位绝对地址的RIP相对间接跳转(Linux内联汇编)
需求说明
我需要在Linux环境下,用GCC/G++的扩展汇编实现等价于jmp [rip+foo]的代码(foo为64位绝对地址),目标是让编译器生成如下机器码:
ff 25 00 00 00 00 xx xx xx xx xx xx xx xx
其中xx xx xx xx xx xx xx xx是来自内联汇编的64位绝对地址。优先选择将汇编逻辑嵌入C文件,而非单独编写.s文件再链接。
尝试过的错误写法
以下几种写法均无法通过编译:
直接指定立即数的写法
__asm__("jmp $1000000000000000(%rip)"); __asm__("jmp *$1000000000000000(%rip)");
使用寄存器传参的写法
unsigned long absAddr; __asm__("jmp %0(%rip)":: "r"(absAddr)); __asm__("jmp *%0(%rip)":: "r"(absAddr));
我知道*用于表示间接访问,试过各种组合都没找到可编译的方案。
对反馈方案的问题
针对他人给出的asm("jmp *%0":: "r"(absAddr));方案,编译后生成的汇编代码如下:
00000000000000f1 <_Z11asmFarJmp64m>: f1: f3 0f 1e fa endbr64 f5: 55 push %rbp f6: 48 89 e5 mov %rsp,%rbp f9: 48 89 7d f8 mov %rdi,-0x8(%rbp) fd: 48 8b 45 f8 mov -0x8(%rbp),%rax 101: ff e0 jmp *%rax 103: 90 nop 104: 5d pop %rbp 105: c3 ret
但我的场景有严格要求:跳转前不能修改任何寄存器(包括rax),这是单向跳转,必须生成ff 25 00 00 00 00 xx xx xx xx xx xx xx xx这种形式的指令。另外,我想知道如何在内联汇编中使用.quad?尝试jmp .quad ...时编译器报错了。
机器码验证与理解
我用NASM编写了测试汇编文件,将目标地址设为0x12345678aabbccdd:
SECTION .text ;;jmp 0x12345678aabbccdd db 0xff, 0x25, 0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78, 0xaa, 0xbb, 0xcc, 0xdd
用objdump反汇编后的结果如下:
jmp64.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <.text>: 0: ff 25 00 00 00 00 jmp *0x0(%rip) # 0x6 6: 12 34 56 adc (%rsi,%rdx,2),%dh 9: 78 aa js 0xffffffffffffffb5 b: bb .byte 0xbb c: cc int3 d: dd .byte 0xdd
一开始误以为objdump没有正确识别64位绝对跳转,后来才明白:ff 25 00 00 00 00对应的就是jmp quad ptr [rip+0000],RIP的偏移0000是相对于当前指令结束后的地址,所以紧跟在该指令后的8字节就是实际要跳转的目标地址。
内容的提问来源于stack exchange,提问作者suncowiam
相关产品推荐
相关产品推荐

