使用NASM学习装配,Ubuntu,32位。
.data
中的我的数组:
ary db 1,2,2,4,5 ; Five elements of one byte each
还有一些数字:
tmp db 2 ; Holds the number 2
假设我想在数组中的索引4处打印元素(因此它将是5
)。
我知道我可以这样做:
mov EAX,4
mov EBX,0
mov ECX,ary ; Put the array's address in ECX
add ECX,4 ; Move address four bytes to the right
add byte [ECX],'0' ; The value at this address to ASCII
mov EDX,1
int 0x80
然而,无论出于何种原因,我决定不是写常数4
,而是想通过将我的变量(2
)乘以2
来实现。< / p>
这是更新的代码:
mov EAX,[tmp] ; Put the number 2 in EAX
mov ECX,ary ; Put the array's address in ECX
add ECX,EAX * 2 ; Move (2 * 2) = 4 bytes to the right
add byte [ECX],'0' ; Decimal to ASCII
mov EAX,4
mov EBX,0
mov EDX,1
int 0x80
这不适用于add ECX,EAX * 2
:
invalid operand type
但为什么呢? ECX
评价不到2
?相当于
add ECX,2 * 2
奇怪的是,这些确实有效:
add ECX,EAX * 1 ; Moves by 2
add ECX,EAX * 0 ; Moves by 0
以上建议我答案是否定的。而乘以1
或0
的原因是因为汇编程序实际上并不需要进行任何乘法来首先知道答案。
这是否意味着为了达到我的目的,我必须使用mul
指令?
答案 0 :(得分:4)
如果您使用lea
:
lea ECX,[ECX+EAX*2]
答案 1 :(得分:2)
在x86中,尽管lea
支持乘以常数,但add
指令不支持将寄存器乘以常量的操作数。它支持附加偏移,但不支持乘法。正如你所指出的那样,我假设汇编程序在这种情况下在add ECX,EAX*0
和add ECX,EAX*1
的公认语法中有点宽容,分别等同于add ECX,0
和add ECX,EAX
你需要做这样的事情:
mov ECX,ary ; Put the array's address in ECX
mov EAX,[tmp] ; Put the number 2 in EAX
shl EAX,1 ; (instead of mul EAX,2)
add ECX,EAX ; Move (2 * 2) = 4 bytes to the right
add byte [ECX],'0' ; Decimal to ASCII
mov EAX,4
mov EBX,0
mov EDX,1
int 0x80
答案 2 :(得分:1)
指令LEA
可用于一次提供两个加法和一个有限乘法。常用语法是:
lea reg, [offset+reg+const*reg]
此处,reg
是任何寄存器,offset
是一些常数,const
是1,2,4或8常数之一。
这样,这条指令非常强大,是为了计算一些相当复杂的方程式:
问题中的等式:
add ECX,EAX * 2
可以这样计算:
lea ecx, [ecx+2*eax]
还有许多其他用途:
lea eax, [ebx+2*ebx] ; eax = 3*ebx
lea eax, [eax+4*eax] ; eax = 5*eax
lea eax, [ecx+8*ecx] ; eax = 9*ecx
lea eax, [1234+ebx+8*ecx]
请注意,FASM允许上述示例的语法更短:
lea eax, [3*ebx]
lea eax, [5*eax]
lea eax, [9*ecx]
lea
指令的另一个优点是它不会影响标志。在所有x86 CPU上,该指令的执行速度非常快。