有些东西让我在x86程序集中混淆了一段时间,它是NASM何时/何时可以推断出操作的大小,这是一个例子:
mov ebx, [eax]
这里我们将存储在eax中保存的地址的4个字节移动到ebx中 . 当寄存器为32位时,操作的大小为4个字节 .
但是,此操作不会被推断并抛出编译错误:
mov [eax], 123456
当然解决方案是这样的:
mov dword [eax], 123456
这将把数字123456的32重新移动到存储在eax保存的地址的字节中 .
但这让我感到困惑,当然它可以看到eax是32位,所以不应该假设我想将它存储为32位值而不必在mov之后指定dword?
当然,如果我想将12位表示12345(是的,我把它降低一个,只是意识到它对于一个16大寄存器来说太大了!)进入eax我会这样做:
mov ax, 12345
3 回答
引用你在另一个答案的评论中所说的话,因为我认为这是你困惑的核心:
BYTE / WORD / DWORD [PTR]注释与存储器地址的大小无关;它是关于该地址的内存变量的大小 . 假设32位寻址平坦,地址总是四个字节长,因此必须进入Exx寄存器 . 因此,目标操作数上的dword(或其他)注释是汇编程序可以知道是否应该修改1,2或4字节RAM的唯一方法 .
如果我演示这些注释对机器代码的影响,也许会有所帮助:
(与
objdump
实际打印它的方式相比,我调整了间距 . )注意两件事:(1)三个不同的操作数前缀产生三个不同的机器指令,(2)使用不同的前缀改变发送到机器代码中的源操作数的长度 .
该指令将使用源操作数的立即寻址和目标操作数的间接寻址,即将十进制123456放入存储在寄存器eax中的存储器地址中,正如您所指出的那样,但是eax点本身不必为32的存储器地址 . 比特大小 . NASM无法推断目标操作数的大小 . 寄存器eax中指针的大小为32位 .
是,但在这里您使用的是源操作数的立即寻址和目标操作数的寄存器寻址 . 汇编程序可以从目标寄存器的大小推断出您希望移动的数据量(在ax寄存器的情况下为16位) .
我觉得你的意思是汇编错误:)
在第一种情况下,它可以毫无问题地确定它,因为EBX是32位寄存器 . 但是在第二个中你使用EAX作为地址,而不是作为目标寄存器,因此nasm开发人员采取安全的路线并让开发人员选择大小 .
如果你做了
mov [eax], 1
,那么nasm可以从中确定什么?是否要将字节,16位或32位内存块设置为1?这完全不为人知 . 这就是强迫开发人员说出规模的原因 .如果你说
mov eax, 123456
从那时起目的地是一个寄存器就完全不同了 .