如何使用Intel的文档获得与x86中的“ call dword ptr”指令相对应的“ ModeR / M”字节?

Ale*_*der 4 x86 assembly encoding intel machine-code

我在VS2017中调试了以下代码(请注意下面的断点):

在此处输入图片说明

接下来,您会发现上面提到的断点的反汇编:

在此处输入图片说明

如上图所示,编译器为该指令生成的机器代码call dword ptr [fp]FF 55 F8,其中FF是调用指令的操作码,55ModeR/M字节的值,F8是值为-8的8位位移,将在下面解释。

现在,如果您查看下面的“表2-2:具有ModeR / M的32位寻址形式”字节,该字节是从英特尔的“ 64 IA-32体系结构软件开发人员手册”第2A卷获得的,上面提到的55号对应于一个有效地址[EBP]+disp8。也就是说,CALL汇编器中的指令将跳转到其地址是从寄存器EBP中的地址加上上述值-8的8位位移获得的指令。这个地址是正确的。它对应于一条JMP指令的地址,该地址最终将代码传递给函数f

在此处输入图片说明

因此,一切看起来都很好。但是我缺少一个重要的点:我应该已经ModeR/M使用英特尔手册中的CALL指令参考以及上面的表2.2 获取了该字节。但是我仍然不知道该怎么做。任何提示都会受到高度赞赏,因为我已经为此工作了几天,而我对此一无所知。

Ros*_*dge 6

您所缺少的是操作码的一部分被编码为ModR / M字节。通常,ModR / M字节编码两个操作数。第一个操作数是表左侧行标签中给出的寄存器或内存操作数,而第二个操作数是由表顶部列标题给出的寄存器。对于只有一个操作数的指令(例如CALL指令),第二个操作数将用于提供其他操作码位。

如果查看CALL指令的文档,您会发现“调用r / m32中给出的绝对,间接间接地址”指令的操作码列为FF /2。该/2指示在MODR / M字节的附加操作码位在这指令值2。然后,如果您查看“(以十进制表示)/ digit(操作码)”列标题,则会看到数字2出现在该列的开头。如果您向下看该列,您会55在标有“ [EBP] + disp8”的行上看到。

指令摘要表(无VEX前缀的指令)中的“英特尔软件开发人员手册第二卷”的第3.1.1.1节“操作码”列中对此进行了说明:

  • / digit — 0到7之间的数字表示指令的ModR / M字节仅使用r / m(寄存器或存储器)操作数。reg字段包含提供指令操作码扩展名的数字。

您唯一缺少的另一件事是call dword ptr [fp]反汇编程序生成的文本。它从未组装过,如何组装取决于如何fp定义。反汇编程序从调试信息中知道编译器生成了局部变量fp在堆栈中的位置,并知道[ebp - 8]可用于访问它。之所以显示它fp,是[ebp - 8]因为前者在大多数情况下会更有意义。取消选中“显示符号名称”,以后应该可以看到。

请注意,该call std::operator<<std:char_traits<char> >行不能不管如何组装stdoperator等被定义的,因此表明,你看是不是实际上意味着拆卸组装。反汇编程序通常是这种情况。输出的目的是提供信息,比查看十六进制字节序列更好。这并不是一个可逆的过程。

  • @Alexander从哪里开始?如果您从反汇编中知道操作码字节为FF且ModR / M字节为55,则知道有效地址为“ [EBP] + disp8”。如果您知道指令是带有“近,绝对间接”操作数的CALL,并且有效地址是“ [EBP] + disp8”,那么您就知道操作码字节是FF,而ModR / M字节是55。 。编译器在生成的代码中发出这些字节时就知道这一点。它还知道您的局部变量“ fp”相对于EBP位于-8位移处,因此也发出了后续的“ F8”字节。 (2认同)