此问题已在此处有答案:
Using LEA on values that aren't addresses / pointers?(4个答案)
3天前关闭。
下面是C代码:
int baz(int a, int b)
{
return a * 11;
}
它被编译为以下汇编指令集(带有-O2标志):
baz(int, int):
lea eax, [rdi+rdi*4]
lea eax, [rdi+rax*2]
ret
lea
指令计算第二个操作数(源操作数)的有效地址,并将其存储在第一个操作数中。对我来说,似乎第一条指令应该加载一个地址到EAX寄存器,但是,如果是这样的话,在第二条lea
指令中将RAX乘以2就没有意义了,所以我推断这两条lea
指令做的事情并不完全相同。
我想知道是否有人能解释一下这里到底发生了什么。
2条答案
按热度按时间yduiuuwa1#
a
的函数参数存储在rdi
中。不需要从内存加载任何东西。lea eax, [rdi+rdi*4]
不计算任何内存位置的地址以从中检索数据。相反,编译器只是重新利用指令来做乘法。它存储a + a*4
到eax
。我们把这个值称为t
。然后,
lea eax, [rdi+rax*2]
有效地存储a + t*2
到eax
。rax
也是函数返回值的寄存器。所以返回值将是
a + t*2
,即a + (a + a*4)*2
,即a + a*5*2
,即a*11
。chhqkbe12#
Linux使用System V AMD64 ABI调用约定,该约定将第一个整数参数传递到寄存器
RDI
中,并将返回值传递到RAX
中。这里EAX
就足够了,因为它返回一个32位的值。第二个参数未使用。LEA
最初用于8086处理器上的地址计算,但也用于具有常数因子的整数运算,这里就是这种情况。在指令编码中使用SIB字节的标度值来编码常数因子。它可以是1、2、4或8。因此,代码可以解释为
RAX的上半部分(64位值)由第一个
LEA
自动清除,参见this SO question。