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

时间:2014-03-21 01:50:13

标签: assembly intel cpu-registers machine-code

我正在用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年代?)的遗留功能领域,但我找不到任何关于为什么ESP的在线参考这种mov操作的例外是一个例外。谢谢!

2 个答案:

答案 0 :(得分:9)

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

[esp]也可以编码所有其他变体,但由于这长1个字节,因此汇编程序不会使用该表单。以下是参考清单:

SIB

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

答案 1 :(得分:2)

如果查看指令的第二个字节,可以看到3位值的递增序列,0到7,表示寄存器操作数,4除外.4的值用于更通用的操作数类型和Intel选择将esp放在通用列表中,因为ebp更常用于基于堆栈的引用。