C语言 为什么x86汇编函数调用的第一个参数是rbp - 4而不是rbp + 4 [重复]

kokeuurv  于 2023-10-16  发布在  其他
关注(0)|答案(2)|浏览(130)

此问题已在此处有答案

Why are parameters allocated below the frame pointer instead of above?(2个答案)
上个月关门了。

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,因为参数保持在高地址
能给我解释一下吗?

4jb9z9bj

4jb9z9bj1#

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


(C)copyright - https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ posted without any permission

qncylg1j

qncylg1j2#

寄存器rbp存储堆栈的当前地址。就像你自己写的
我们知道堆栈是从高地址向低地址增长
因此,为了为作为函数的局部变量的参数分配存储器,

push    rbp
    mov     rbp, rsp
    mov     DWORD PTR [rbp-4], edi
    mov     DWORD PTR [rbp-8], esi

rbp + 4寻址不属于函数的调用者的内存。在这个简单的函数中可以看到,参数通过寄存器ediesi传递给函数,这些寄存器存储在函数的参数(局部变量)中。如果参数的数量大于编译器用来存储参数的寄存器的数量,那么在这种情况下,要访问函数中的参数,可以向rbp添加一个正值,以访问调用者存储在堆栈中的参数。通过寄存器传递参数更有效。

相关问题