确定NASM何时可以推断mov操作的大小
有些东西让我在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位大的寄存器来说太大了),我会这样做:
mov ax, 12345
引用你在评论另一个答案时所说的话,因为我认为这是你的困惑的核心:
我期望mov [eax], 1
将保存在内存地址eax中的4个字节设置为1的32位表示形式
BYTE / WORD / DWORD [PTR]注释与存储器地址的大小无关; 这是关于该地址内存中变量的大小。 假设平面32位寻址,地址总是4个字节长,因此必须放在Exx寄存器中。 因此,目标操作数的dword(或其他)注释是汇编程序能够知道是否应该修改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)使用不同的前缀改变源操作数的长度,使其发射到机器代码中。
mov [eax],123456
该指令将使用源操作数的立即寻址和目标操作数的间接寻址,即如指出的那样将十进制数123456放入存储在寄存器eax中的存储器地址中,但eax点本身不必为32的存储器地址位大小。 NASM无法推断目标操作数的大小。 寄存器eax中指针的大小是32位。
当然,如果我想把123456的16位重映射到eax中,我会这么做:mov ax,123456
是的,但是在这里,您正在使用目标操作数的源操作数和寄存器寻址的立即寻址。 汇编器可以根据目标寄存器的大小推断你希望移动的数据量(在ax寄存器的情况下为16位)。
编译错误
我认为你的意思是组装错误:)
在你的第一个案例中,它可以确定它没有问题,因为EBX是一个32位寄存器。 但在第二个中,您使用EAX作为地址,而不是目的地寄存器,所以nasm开发人员采用了安全路线并让开发人员选择大小。
如果你确实使用了mov [eax], 1
,那么nasm可以从中判断出什么? 你是否想将字节,16位或32位的存储器块设置为1? 这完全是未知的。 这就是为什么强迫开发人员说明其大小的原因。
如果你说mov eax, 123456
就完全不同了mov eax, 123456
因为目的地是寄存器。
上一篇: Determining when NASM can infer the size of the mov operation