有一段时间让我对 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 吗?
当然,如果我想将 12345 的 16 位表示(较小的数字适合 16 位)放入 eax,我会这样做:
mov ax, 12345
最佳答案
对于任何具有内存目标和直接源的指令,操作数大小是不明确的(因此必须指定)。 (即使在寻址模式下使用一个或多个,操作数实际上也不是寄存器。)
地址大小和操作数大小是指令的独立属性。
引用您在对另一个答案的评论中所说的话,因为我认为这是您困惑的核心:
I would expect
mov [eax], 1
to set the 4 bytes held in memory address eax to the 32 bit representation of 1
BYTE/WORD/DWORD [PTR]注解与内存地址的大小无关;它是关于该地址处内存中变量的大小。假设平面 32 位寻址,地址 总是四个字节长,因此必须放在 Exx 寄存器中。因此,当源操作数是立即数时,目标操作数上的双字(或其他)注释是汇编程序知道它是否应该修改 1、2 或 4 字节 RAM 的唯一方法。
如果我演示这些注释对机器代码的影响,也许它会有所帮助:
$ objdump -d -Mintel test.o
...
0: c6 00 01 mov BYTE PTR [eax], 0x1
3: 66 c7 00 01 00 mov WORD PTR [eax], 0x1
8: c7 00 01 00 00 00 mov DWORD PTR [eax], 0x1
(与 objdump
实际打印它的方式相比,我稍微调整了间距。)
请注意两件事:(1) 三个不同的操作数前缀会产生三个不同的机器指令,(2) 使用不同的前缀会更改发送到机器代码中的源操作数的长度。
关于linux - 确定 NASM 何时可以推断出 mov 操作的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30959266/