linux - 确定 NASM 何时可以推断出 mov 操作的大小

标签 linux x86 nasm addressing-mode

有一段时间让我对 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/

相关文章:

linux - 在 vm 共享文件夹中编译 ONOS 时权限被拒绝

linux - 如何在 Linux 程序集中读取和显示一个值?

assembly - 汇编代码说明

gcc - 如何使用C读取和存储8086中的视频内存?

assembly - 当第二阶段引导加载程序的一部分时,INT 10h/ah=13h 不打印字符串

assembly - 在 x86 NASM 或 YASM 程序集中实现选择排序的问题

c++ - 如果条件不起作用怎么办?

linux - 在目标中构建库以在主机中进行交叉编译

linux - 通过 ssh 运行带有多行输入的 bash 命令

汇编 (x86) : <label> db 'string' , 0 不会被执行,除非有跳转指令