【问题标题】:Can I multiply a register's value by an immediate number to add the result to another register?我可以将寄存器的值乘以立即数以将结果添加到另一个寄存器吗?
【发布时间】:2013-09-15 02:39:07
【问题描述】:

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

这是更新后的代码:

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

以上内容告诉我答案是否定的。而乘以10 的原因是因为汇编程序实际上不需要做任何乘法来知道答案。

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

【问题讨论】:

    标签: linux assembly x86 nasm


    【解决方案1】:

    如果你使用lea,你可以在一条指令中做乘法和加法:

    lea ECX,[ECX+EAX*2]
    

    【讨论】:

      【解决方案2】:

      在 x86 中,虽然 lea 支持乘以常数,但 add 指令不支持将寄存器乘以常数的操作数。它支持加法偏移,但不支持乘法。正如您所指出的,我假设在这种情况下,汇编程序在add ECX,EAX*0add ECX,EAX*1 的公认语法中有些宽容,分别相当于add ECX,0add 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
      

      【讨论】:

      • @johnfound 抱歉,我错过了lea 的情况。我将答案修改为不包含支持说明。但需要明确的是,它并不普遍支持该机制。
      • 您的回答通常没有错。仅在问题的上下文中。 :)
      【解决方案3】:

      指令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上都非常快。

      【讨论】:

        猜你喜欢
        • 2017-10-29
        • 2018-02-18
        • 2013-11-29
        • 2020-07-24
        • 1970-01-01
        • 2013-02-03
        • 1970-01-01
        • 2022-11-17
        • 1970-01-01
        相关资源
        最近更新 更多