x86汇编CALL指令编码咨询:近绝对间接调用call r/m32编码方式及示例
理解call r/m32(近绝对间接调用)的编码逻辑
嘿,你提到的FF /2确实是x86架构下近绝对间接call的操作码,这里的/2和ModR/M字节的Reg/Opcode字段直接相关——我来给你拆解清楚,再举几个完整的编码示例:
先搞懂ModR/M字节的结构
x86的ModR/M字节(操作码之后的第一个字节)被拆成3个部分:
- Mod(2位):区分寄存器寻址和内存寻址,以及内存寻址的偏移类型
- Reg/Opcode(3位):在这类带
/digit的指令里,这个字段不是用来指定寄存器,而是作为操作码的扩展——这里的/2就要求这个字段的值是二进制010(也就是十进制的2) - R/M(3位):指定要使用的寄存器,或者内存寻址的基址/索引方式
不同寻址方式的完整编码示例
下面是几种常见场景的编码,都是x86默认的小端序:
1. 直接调用内存中的32位指针:call [0x12345678]
- 固定操作码:
0xFF - ModR/M字节:Mod=
00(无偏移的直接内存寻址),Reg/Opcode=010(对应/2),R/M=101(直接寻址的编码)→ 二进制00010101= 十六进制0x15 - 32位内存地址(小端序):
0x78 0x56 0x34 0x12 - 最终完整编码:
FF 15 78 56 34 12
2. 调用寄存器中存储的指针:call eax
- 固定操作码:
0xFF - ModR/M字节:Mod=
11(寄存器寻址),Reg/Opcode=010,R/M=000(对应eax寄存器)→ 二进制11010000= 十六进制0xD0 - 无额外字节
- 最终完整编码:
FF D0
3. 调用基址+8位偏移的内存指针:call [ebx+0x10]
- 固定操作码:
0xFF - ModR/M字节:Mod=
01(带8位偏移的内存寻址),Reg/Opcode=010,R/M=011(对应ebx寄存器)→ 二进制01010011= 十六进制0x53 - 8位偏移值:
0x10 - 最终完整编码:
FF 53 10
总结
简单来说,操作码里的/2就是要求你把ModR/M字节的中间3位(Reg/Opcode字段)设置为010,而Mod和R/M字段则根据你实际要使用的寻址方式来选择对应的二进制值——这样组合起来就完成了call r/m32的编码。
内容的提问来源于stack exchange,提问作者jtxkopt - STOP GENOCIDE




