对于无条件跳转指令0xFF,Mod R/M字节有什么含义(如果有的话)?

mer*_*011 8 x86 assembly

考虑下面的代码,在32位编译Ubuntu 14.04.2gcc 4.8.2

#include <unistd.h>

int main(){
    _exit(0);
}
Run Code Online (Sandbox Code Playgroud)

如果我打开gdb并运行此代码disas /r _exit,我会得到以下内容.

(gdb) disas /r _exit
Dump of assembler code for function _exit@plt:
   0x080482f0 <+0>:     ff 25 0c a0 04 08       jmp    *0x804a00c
   0x080482f6 <+6>:     68 00 00 00 00  push   $0x0
   0x080482fb <+11>:    e9 e0 ff ff ff  jmp    0x80482e0
End of assembler dump.
(gdb)
Run Code Online (Sandbox Code Playgroud)

英特尔手册告诉我们这ff是操作码JMP,而后四个字节显然是目标地址.在对Intel指令的结构进行一些研究之后,25看起来是一个Mod R/M字节,但是我找不到如何Mod R/M根据JMP指令解释该字节.

我已经阅读了Mod R/M字节一般解释,但我不明白字节0x25disas上面的输出中具有什么特定含义.

0x25这里具体含义是什么,Mod R/M字节的一般解释是JMP什么?

Ira*_*ter 10

对于操作码0xFF,MODRM字节的含义与使用MODRM字节的任何其他指令的含义相同.

您最好的参考是在线英特尔指令集手册.第2节和JMP指令页面是您正确解释此操作码的MODRM位所需的页面.

"0x25"的解释是:

  • (第7-6位)MOD =二进制00
  • (比特5-3)Reg/Opcode =二进制100
  • (比特2-0)R/M =二进制101

MOD = 00和R/M =二进制101表示MODRM字节之后的"use disp32"(32位地址).MODRM字节后面的32位偏移是存储单元.您可以看到它与调试列表中反汇编的jmp指令中的值匹配.

您可能会对操作码0xFF的含义感到困惑; 它并不一定意味着"JMP".x86通常使用MODRM Reg/Opcode位来修改操作码字节的含义,以选择特定指令.

使用操作码0xFF,Reg/Opcode位被解释为更多的操作码位:

  • Reg/Opcode位=二进制100(在Intel手册中写为"/ 4")选择指令"jmp near absolute indirect".x86具有所谓的段寄存器,包括CS; 在这种情况下,"jmp near"表示"不加载CS".
  • Reg/Opcode == 101("/ 5")表示"jmp far"(加载CS)并且在现代实践中不使用.
  • 具有其他值的Reg/Opcode指定不是JMP的指令.


har*_*old 5

实际上,最后 4 个字节不是目标地址。该指令ff 25 0c a0 04 08jmp rm32(跳转绝对间接)的一个实例,最后4个字节实际上是将读取跳转目标的地址。

正如您在此表中所见,ModRM 字节 25h的 /digit 部分为 4(这使它成为 a jmp rm32,其他具有操作码字节的指令ffinc rm32, dec rm32, call rm32, call m16:32, jmp m16:m32, push rm32, 均由 ModRM 字节区分)。ModRM 字节的其余部分 25h 表示操作数是形式的内存地址[sdword]