问题描述
我试图根据在 Godbolt.org 上的 C++ 中的平方函数来理解这一点。显然,返回、参数和局部变量使用“rbp - 对齐”作为这个函数。 有人可以解释一下这是怎么可能的吗? 那么在这种情况下 rbp + 对齐会做什么?
int square(int num){
int n = 5;// just to test how locals are treated with frame pointer
return num * num;
}
编译器 (x86-64 gcc 11.1)
生成的程序集:
square(int):
push rbp
mov rbp,rsp
mov DWORD PTR [rbp-20],edi. ;\\Both param and local var use rbp-*
mov DWORD PTR[rbp-4],5. ;//
mov eax,DWORD PTR [rbp-20]
imul eax,eax
pop rbp
ret
解决方法
这是可以方便区分参数和实参的情况之一。简而言之:参数是调用者给出的值,而参数是保存它们的变量。
当调用 square
时,调用者根据标准的 x86-64 调用约定将 参数 放在 rdi
寄存器中。 square
然后分配一个局部变量,参数,并将参数放在参数中。这允许参数像任何其他变量一样使用:读取、写入、获取其地址等。由于在这种情况下是被调用者为参数分配了内存,因此它必须驻留在帧指针下方。
使用 ABI,其中参数在堆栈上传递,被调用者将能够重用包含参数的堆栈槽作为参数。这正是 x86-32 上发生的情况(通过 -m32
来查看您自己):
square(int): # @square(int)
push ebp
mov ebp,esp
push eax
mov eax,dword ptr [ebp + 8]
mov dword ptr [ebp - 4],5
mov eax,dword ptr [ebp + 8]
imul eax,dword ptr [ebp + 8]
add esp,4
pop ebp
ret
当然,如果您启用了优化,编译器就不会费心在被调用方的堆栈上分配参数;它只会直接使用寄存器中的值:
square(int): # @square(int)
mov eax,edi
imul eax,edi
ret