操作' mov [esp - 4], eax '增加额外的字节



我在msvc++中做了一些机器代码的实验,并创建了一个函数,允许我在带有符号位移的寄存器周围构建mov操作。一切都很顺利,直到我用mov [esp-4], eax构建函数。突然,我的程序开始崩溃。在拆卸后偷看了一眼,我注意到一些相当奇怪的事情。对于这个mov操作,从ESP寄存器解引用一个偏移量,在参数字节和带符号位移之间放置了一个额外的字节。这个字节看起来总是0x24。所以出于好奇,我拆卸了下面的__asm块,得到了一些有趣的结果:

mov [eax - 4], eax
mov [ecx - 4], eax
mov [edx - 4], eax
mov [ebx - 4], eax
mov [esp - 4], eax
mov [ebp - 4], eax
mov [esi - 4], eax
mov [edi - 4], eax

机器代码将以上内容翻译成:

89 40 FC
89 41 FC
89 42 FC
89 43 FC
89 44 24 FC      <--- WAT!
89 45 FC
89 46 FC
89 47 FC

我在Windows计算器中输入十六进制24,并将其转换为二进制。结果是00100100显示的是两个假位,后跟两次ESP寄存器。

有人能解释一下为什么会这样吗?我认为这超越了MS c++编译器的怪异怪僻,直接进入了70年代或80年代(90年代?)的遗留功能领域,但我在网上找不到任何关于为什么ESPmov操作的例外的参考资料。谢谢!

[esp]不能仅使用modr/m字节进行编码,它需要SIB字节。参见表2-2。在intel指令集参考中带有ModR/M字节的32位寻址形式。modr/m的44值编码另一个操作数为eax,后跟一个SIB字节和一个位移字节。24SIB值对[esp]进行编码,参见表2-3。具有SIB字节的32位寻址表单

SIB也可以编码所有其他变体,但由于它长1字节,汇编程序不使用该形式。以下是供参考的列表:

89 44 20 FC mov [eax-0x4],eax
89 44 21 FC mov [ecx-0x4],eax
89 44 22 FC mov [edx-0x4],eax
89 44 23 FC mov [ebx-0x4],eax
89 44 24 FC mov [esp-0x4],eax
89 44 25 FC mov [ebp-0x4],eax
89 44 26 FC mov [esi-0x4],eax
89 44 27 FC mov [edi-0x4],eax

这本身不会导致崩溃,但随机尝试覆盖内存中的内容可能会导致崩溃。

如果您查看指令的第二个字节,您会看到一个递增的3位值序列,从0到7,它们表示寄存器操作数,除了4。4的值用于更泛型的操作数类型,Intel选择将esp放在泛型列表中,因为ebp更常用于基于堆栈的引用。

最新更新