Linux 函数调用的栈帧
example 1
int func(int a, int b, int c, int d, int e ,int f, int g)
{
int h=10;
int i;
return a+b;
}
int main(int argc, char* argv[])
{
func(1,2,3,4);
return 3;
}
0000000000000608 <func>:
608: 55 push %rbp //4. 保存旧rbp
609: 48 89 e5 mov %rsp,%rbp //5. rbp=rsp
60c: 89 7d ec mov %edi,-0x14(%rbp) //6. 通过ebp来赋值栈,sp并没有变化
60f: 89 75 e8 mov %esi,-0x18(%rbp)
612: 89 55 e4 mov %edx,-0x1c(%rbp)
615: 89 4d e0 mov %ecx,-0x20(%rbp)
618: 44 89 45 dc mov %r8d,-0x24(%rbp)
61c: 44 89 4d d8 mov %r9d,-0x28(%rbp)
620: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) //7. 局部变量
627: 8b 55 ec mov -0x14(%rbp),%edx
62a: 8b 45 e8 mov -0x18(%rbp),%eax
62d: 01 d0 add %edx,%eax //8.计算,结果保存在eax
62f: 5d pop %rbp //9. sp此时还指向旧的rbp,相当于还原rbp
630: c3 retq //10. pc=之前保存的返回地址.
0000000000000631 <main>:
631: 55 push %rbp
632: 48 89 e5 mov %rsp,%rbp
635: 48 83 ec 10 sub $0x10,%rsp
639: 89 7d fc mov %edi,-0x4(%rbp)
63c: 48 89 75 f0 mov %rsi,-0x10(%rbp)
640: 6a 07 pushq $0x7 // 1.main->fun start here 从右往左,参宿入栈
642: 41 b9 06 00 00 00 mov $0x6,%r9d //2.其余参数先存直接寄存器,也可压栈
648: 41 b8 05 00 00 00 mov $0x5,%r8d
64e: b9 04 00 00 00 mov $0x4,%ecx
653: ba 03 00 00 00 mov $0x3,%edx
658: be 02 00 00 00 mov $0x2,%esi
65d: bf 01 00 00 00 mov $0x1,%edi
662: e8 a1 ff ff ff callq 608 <func> //3.callq会保存返回地址,再调用func
667: 48 83 c4 08 add $0x8,%rsp
66b: b8 03 00 00 00 mov $0x3,%eax
670: c9 leaveq
671: c3 retq
672: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
679: 00 00 00
67c: 0f 1f 40 00 nopl 0x0(%rax)
从步骤 6 来看,整个 sp 是没动过的,不用先减后加,而且局部变量借用了寄存器完成临时保存,先存到寄存器,再恢复到栈里.
example 2