1

在对为什么我的寄存器常量比较在 NASM 大会中不起作用感到头疼之后?,原来我一直在将 1 字节变量 ( db) 复制到EAX,这意味着变量后面的三个字节也将被复制。既然我知道了这一点,我正在查看类似场景的代码,并发现了这一点:

.data我有一个数组,它的大小定义在一个常量中:

array  db   1,2,3,4
size   equ  $-array

后来,在.text我有这个:

mov EAX,size

这让我想知道:那里到底发生了什么?尺寸是size多少?是一个字节吗?一个字?EAX 是否收到不应该的额外字节?

4

2 回答 2

3

它是一个立即数,汇编器应该为它选择最合适的大小(如果有多个可能的编码)。如果最小可能的大小超过了目标寄存器的大小,您应该得到一个错误,或者至少是一个警告。

在您的示例中,该行将mov EAX,size像您键入一样组装mov EAX,4

于 2013-09-16T07:02:05.510 回答
2

它是从实际位置减去开始计算的立即值arrayequ和之间的重要区别在于%define编译器在使用的$地方直接替换符号equ,而%define在预处理代码时只是文本表示有用,因此$每次出现都不同。对应的代码使用%defineis

array: db 1, 2, 3, 4
array_end: 
%define array_end - array

虽然equ对于数组数据操作看起来很完美,但%define对字符串很有用。

当编译器得到你的指令时究竟会发生什么?
它只是用已经计算的值替换常量的名称。然后编译器将指令编码如下:

mov r32, imm -> 0xB8 + 0x00 (for EAX)
size         -> 0x04 0x00 0x00 0x00

其他寄存器具有不同的值,可在英特尔手册中找到。除了0xB8是英特尔节省 1 个字节的技巧,它将用于REG以字节存储代码ModR/M

指令一般不使用这种技巧,但一些频繁的指令通过使用累加器寄存器的特殊操作码来节省一个字节。

于 2013-09-16T13:06:19.063 回答