1

使用 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

但是,无论出于何种原因,我决定不写常数 number ,而是想通过将我的变量(即)4乘以 来做到这一点。22

这是更新的代码:

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

以上表明我的答案是否定的。乘以1or0起作用的原因是因为汇编器实际上不需要做任何乘法来首先知道答案。

这是否意味着要实现我想要的,我必须使用mul指令?

4

3 回答 3

4

如果您使用,您可以在一条指令中进行乘法和加法lea

lea ECX,[ECX+EAX*2]
于 2013-09-15T03:30:14.807 回答
2

在 x86 中,虽然lea支持乘以常数,但该add指令不支持将寄存器乘以常数的操作数。它支持加法偏移,但不支持乘法。正如您所指出的,我假设在这种情况下,汇编程序在可接受的语法中有点宽容,add ECX,EAX*0并且分别add ECX,EAX*1等同于add ECX,0and 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
于 2013-09-15T02:48:37.917 回答
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 上都非常快。

于 2013-09-15T09:20:10.050 回答