我编译了这个c函数:

int calc(int x, int y, int z) {
   return x + 3*y + 19*z;
}

我在Calc.s上得到了这个,我正在注释正在发生的事情:
        .file   "calc.c"
        .text
.globl calc
        .type   calc, @function
calc:
        pushl   %ebp                    //Save paramaters
        movl    %esp, %ebp              //Move stack pointer into %ebp
        movl    12(%ebp), %eax          //Move y into %eax
        movl    16(%ebp), %ecx          //Move z into %ecx
        leal    (%eax,%eax,2), %eax     //%eax = 3*y
        addl    8(%ebp), %eax           //%eax = x+3y
        leal    (%ecx,%ecx,8), %edx     // ?
        leal    (%ecx,%edx,2), %edx     // ?
        addl    %edx, %eax              //%eax = (x+3*y)+(19*z)
        popl    %ebp                    //Pop the previous pointer
        ret
        .size   calc, .-calc
        .ident  "GCC: (Ubuntu 4.3.3-5ubuntu4) 4.3.3"
        .section        .note.GNU-stack,"",@progbits

我完全理解最后两条指令。为什么19*z需要两个leal指令,而3*y在一个指令中完成。

最佳答案

leal是一种廉价地用一个小常数进行乘法运算的方法,如果常数是二加一的幂。其思想是不带偏移量的leal相当于“reg1=reg2+reg3*scale”。如果reg2和reg3恰好匹配,则表示“reg1=reg2*(scale+1)”。
leal只支持高达8的比例因子,因此要乘以19,需要2。
影响

leal   (%eax,%eax,2), %eax

是:
eax = eax + eax*2

也就是说,乘以3。
后两个leals一起执行乘法19:
leal    (%ecx,%ecx,8), %edx     // edx = ecx+ecx*8
leal    (%ecx,%edx,2), %edx     // edx = ecx+edx*2 (but edx is already z*9)

08-17 15:11