int square(int num, int i2) {
return num * num;
}
square(int, int):
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov eax, DWORD PTR [rbp-4]
imul eax, eax
pop rbp
ret
我们知道堆栈是从高地址向低地址增长的,我看到书上当函数调用发生时,堆栈可能像函数参数,然后返回地址,然后是旧的ebp。但为什么 rbp - 4 是第一个参数地址,而不是 rbp + 4,因为参数保留在高地址
你能为我解释一下吗?
寄存器
rbp
存储堆栈的当前地址。正如你自己写的那样
我们知道栈是从高地址向低地址增长的
因此,要为函数的局部变量参数分配内存,寄存器
rbp
会按参数类型的大小递减
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
rbp + 4
寻址不属于该函数的调用者的内存。可以看出,参数通过存储在函数参数(局部变量)中的寄存器 edi
和 esi
传递给函数。
64 位 ABI - 前 6 个参数在 寄存器 中传递,而不是在堆栈上。
因此要查看如何从堆栈中获取参数,您需要有更多参数:
int goo(int n1, int n2, int n3, int n4, int n5, int n6, int n7) {
return n1 + n2 + n3 + n4 + n5 + n6 +n7;
}
和代码:
add edi, esi
add edi, edx
add edi, ecx
add edi, r8d
lea eax, [rdi+r9]
add eax, DWORD PTR [rsp+8]
ret
如您所见,参数
n7
正在从堆栈中获取 DWORD PTR [rsp+8]
在 32 位系统上:
goo:
mov eax, DWORD PTR [esp+8]
add eax, DWORD PTR [esp+4]
add eax, DWORD PTR [esp+12]
add eax, DWORD PTR [esp+16]
add eax, DWORD PTR [esp+20]
add eax, DWORD PTR [esp+24]
add eax, DWORD PTR [esp+28]
ret
所有参数均从堆栈中获取。
为什么 x86 汇编函数调用第一个参数是 rbp - 4 而不是 rbp + 4
因为你编译它时没有优化,并且编译器已经为寄存器中传递的那些参数提供了自动存储。
针对 x86-64 编译的相同代码,未进行优化:
goo:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], edi
mov DWORD PTR [rbp-8], esi
mov DWORD PTR [rbp-12], edx
mov DWORD PTR [rbp-16], ecx
mov DWORD PTR [rbp-20], r8d
mov DWORD PTR [rbp-24], r9d
mov edx, DWORD PTR [rbp-4]
mov eax, DWORD PTR [rbp-8]
add edx, eax
mov eax, DWORD PTR [rbp-12]
add edx, eax
mov eax, DWORD PTR [rbp-16]
add edx, eax
mov eax, DWORD PTR [rbp-20]
add edx, eax
mov eax, DWORD PTR [rbp-24]
add edx, eax
mov eax, DWORD PTR [rbp+16]
add eax, edx
pop rbp
ret