ADD 指令还是加号?
ADD instruction or plus sign?
很简单的问题,但我没有找到好的答案,所以我在这里问。
我看到有时加法我们使用 ADD 指令,有时我看到使用加号 (+)。
请看以下内容:
mov eax,[esi + TYPE DWORD]
好吧,我了解到我应该使用 ADD 指令来添加数字,但它似乎是这样工作的。
我认为应该这样做:
add esi, TYPE DWORD
mov eax,[esi]
sub esi, TYPE DWORD
我的意思是,计算机如何在不执行加法指令的情况下访问内存地址esi + TYPE DWORD?太奇怪了...
非常感谢您阅读 (:
首先,它们被编码为两种不同的东西 - ADD
是一条指令,将带有完整的操作码,而 +
将由您的汇编程序转换为引用模式对于它所附的主要指令(在本例中为 MOV
)。
然而,主要区别在于第一个将由内存单元(或更准确地说 - 地址生成单元)执行,而不会在加载执行之上消耗任何额外的仲裁,而后者将执行ALU,并相应地消耗所需的资源(取决于微架构,但在您的示例中,在任何现代乱序 CPU 上至少需要一些队列条目、解码槽、调度槽,端口等)。
从这个意义上说,第一个通常是 "cheaper",这就是为什么它经常用于没有内存引用的普通算术运算,正如哈罗德指出的那样,通过使用 LEA
指令。
为了更通用一点,您在第一个示例中看到的是寻址模式的一部分,而不是操作码。
最简单的地址寄存器形式就是指向您感兴趣的内容(基地址)的指针
[bx]
如果您正在查看数组或结构,那么您必须调整基址寄存器才能查看其他内容。随着时间的推移,寻址变得更加灵活。您可以有一个基数和一个索引:
[ebx+eax] ; add 2 registers to get the pointers - array + index
现在,如果您有一个字节数组,您可以保留基数并调整索引。如果您正在查看 2、4 或 8 个字节,您可以根据目标的大小调整索引:
[ebx+eax*2] ; 2 byte target, array + (index*2)
现在,如果您正在查看 C 风格的结构,那么您也可以向结果地址添加位移:
[ebx+eax*2+16]
这些在编译时被编码到指令中,而不是变成汇编指令。熟悉寻址模式 - 如果您对正确的解决方案使用正确的模式,它们将为您节省大量时间。
很简单的问题,但我没有找到好的答案,所以我在这里问。
我看到有时加法我们使用 ADD 指令,有时我看到使用加号 (+)。
请看以下内容:
mov eax,[esi + TYPE DWORD]
好吧,我了解到我应该使用 ADD 指令来添加数字,但它似乎是这样工作的。
我认为应该这样做:
add esi, TYPE DWORD
mov eax,[esi]
sub esi, TYPE DWORD
我的意思是,计算机如何在不执行加法指令的情况下访问内存地址esi + TYPE DWORD?太奇怪了...
非常感谢您阅读 (:
首先,它们被编码为两种不同的东西 - ADD
是一条指令,将带有完整的操作码,而 +
将由您的汇编程序转换为引用模式对于它所附的主要指令(在本例中为 MOV
)。
然而,主要区别在于第一个将由内存单元(或更准确地说 - 地址生成单元)执行,而不会在加载执行之上消耗任何额外的仲裁,而后者将执行ALU,并相应地消耗所需的资源(取决于微架构,但在您的示例中,在任何现代乱序 CPU 上至少需要一些队列条目、解码槽、调度槽,端口等)。
从这个意义上说,第一个通常是 "cheaper",这就是为什么它经常用于没有内存引用的普通算术运算,正如哈罗德指出的那样,通过使用 LEA
指令。
为了更通用一点,您在第一个示例中看到的是寻址模式的一部分,而不是操作码。
最简单的地址寄存器形式就是指向您感兴趣的内容(基地址)的指针
[bx]
如果您正在查看数组或结构,那么您必须调整基址寄存器才能查看其他内容。随着时间的推移,寻址变得更加灵活。您可以有一个基数和一个索引:
[ebx+eax] ; add 2 registers to get the pointers - array + index
现在,如果您有一个字节数组,您可以保留基数并调整索引。如果您正在查看 2、4 或 8 个字节,您可以根据目标的大小调整索引:
[ebx+eax*2] ; 2 byte target, array + (index*2)
现在,如果您正在查看 C 风格的结构,那么您也可以向结果地址添加位移:
[ebx+eax*2+16]
这些在编译时被编码到指令中,而不是变成汇编指令。熟悉寻址模式 - 如果您对正确的解决方案使用正确的模式,它们将为您节省大量时间。