我不知道为什么,但这个汇编程序指令困扰着我LEA
。
C++
int f(int t)
{
return t+1;
}
int f(int*t)
{
return *t+1;
}
int f(int& t)
{
return t+1;
}
汇编器
f(int): # @f(int)
lea eax, [rdi + 1]
ret
f(int*): # @f(int*)
mov eax, dword ptr [rdi]
inc eax
ret
f(int&): # @f(int&)
mov eax, dword ptr [rdi]
inc eax
ret
如果命令MOV
很清楚,那么命令LEA
就不清楚了!
我知道指令LEA
计算第二个操作数的地址并将其写入第一个操作数(我只知道这些)
在通过引用的示例中,即: lea eax,[rdi + 1]
这显然不是地址计算,也不是第一个操作数的条目,不会有条目,但很可能是其他内容。还是我误解了什么?请按照C++代码解释。
PS 我搜索过,但没有找到我问题的详尽答案,我什至在卡拉什尼科夫冲锋枪的书中搜索过,但我什至没有在那里找到这个命令......嗯。
eax
此命令将位于地址 rdi + 1 的值加载到地址中。她eax
刚装进去rdi+1
。它看起来很奇怪,为了理解为什么需要它
lea
,以及为什么它比仅仅类似调用mov
或手动计算地址更好,您需要了解命令是如何写入内存并由处理器执行的。例如,您有一个读取值的命令:
它编译成类似的东西
那些。在
66 67 8B 47 01
假设您需要获取地址
rdi+1
本身eax
您可以执行以下两项操作之一:
手工计算:
你将不得不写:
那些。遵循两个指示。可能是一个不错的选择,但仅适用于简单的 +1。对于像这样的地址
[bp+si+4]
?或执行
lea
:比较
mov
:字节码:
66 67 8D 47 01
只有操作码不同,8B -> 8D。
处理器有一个现成的、非常有效的机制来进行地址的基本操作。并且它已经为操作实现了
mov
——毕竟它mov
可以获取地址处的值!。使用时,
lea
处理器会执行它所做的所有操作mov
,但会跳过最后一步,检索地址处的值。相反,它加起来eax
就是地址本身。rdi + 1
这比考虑单独的命令之类的事情要方便和快捷得多。这与您的示例有什么关系?
在您的示例中,参数在 中
rdi
,您必须在 中返回结果eax
。老实说,编译器应该写的好吧,对于 1 你可以使用
inc
:但它仍然是两支球队。处理器将依次执行它们。
编译器很聪明。他知道处理器在处理一条指令时可以用小常量将寄存器值相加
lea
。并且它插入一个将产生相同结果的命令。没有地址实际加载到任何地方并不重要 - 主要是它会以完全相同的方式工作,而且速度更快 - 因为。处理器计算内存中的地址比添加数字更快:)
此命令加载到
eax
右侧的地址 - 即rdi+1
. 如此巧妙的结合方式那些。从某种意义上说,翻译成C++,这就是
:) IE。获取位于 address 的对象的地址
[rdi+1]
。例如,请参见此处。
这个命令
eax
将值放入寄存器rdi + 1
中,其中rdi
存储了参数的值。在其他两种情况下,当通过引用传递参数或传递指向原始参数的指针时,寄存器
rdi
包含参数的地址。因此,
eax
参数的值首先被输入到寄存器中,使用的地址是rdi
然后寄存器的值
eax
加 1。也就是说,第一个函数定义和随后两个函数定义之间的区别在于,在第一种情况下,寄存器
rdi
包含参数值的副本,而在后两种情况下,寄存器rdi
接收原始参数的地址。