调用一个函数之后发生了什么?
假设:
AMD64 Linux
C/C++
首先,我们不需要讲太多的概念。只需要回顾几个基本的寄存器:
%rsp:保存栈顶指针
%rbp:保存栈底指针
%rbp~%rsp 这一段向下伸展的区域,就是栈帧。
%rip:保存下条指令的地址
%rdi:保存函数的第一个参数
%rsi:保存函数的第二个参数
%rax:保存返回值
然后,直接看代码吧!
样例程序 假设有程序如下:
1int sum(int x, int y) 2{ 3 return a + b; 4} 5int main(int argc, char const *argv[]) 6{ 7 int a = 1, b = 2; 8 int c = sum(a, b); 9 return 0; 10} 使用 gcc -g prog.c -o prog 进行编译。
其汇编代码如下:
int sum(int x, int y)
{
1125: 55 push %rbp
1126: 48 89 e5 mov %rsp,%rbp
1129: 89 7d fc mov %edi,-0x4(%rbp)
112c: 89 75 f8 mov %esi,-0x8(%rbp)
return a + b;
112f: 8b 55 fc mov -0x4(%rbp),%edx
1132: 8b 45 f8 mov -0x8(%rbp),%eax
1135: 01 d0 add %edx,%eax
}
1137: 5d pop %rbp
1138: c3 retq
0000000000001139 <main>:
int main(int argc, char const *argv[])
{
1139: 55 push %rbp
113a: 48 89 e5 mov %rsp,%rbp
113d: 48 83 ec 20 sub $0x20,%rsp
1141: 89 7d ec mov %edi,-0x14(%rbp)
1144: 48 89 75 e0 mov %rsi,-0x20(%rbp)
int a = 1;
1148: c7 45 fc 01 00 00 00 movl $0x1,-0x4(%rbp)
int b = 2;
114f: c7 45 f8 02 00 00 00 movl $0x2,-0x8(%rbp)
int c = sum(a, b);
1156: 8b 55 f8 mov -0x8(%rbp),%edx
1159: 8b 45 fc mov -0x4(%rbp),%eax
115c: 89 d6 mov %edx,%esi
115e: 89 c7 mov %eax,%edi
1160: e8 c0 ff ff ff callq 1125 <sum>
1165: 89 45 f4 mov %eax,-0xc(%rbp)
return 0;
1168: b8 00 00 00 00 mov $0x0,%eax
} 执行流程 我们直接从 main 读起。请务必仔细关注调用栈的变化。
Read more...