函数栈
这篇文章会详细的讨论:在程序中调用函数时,具体的栈中数据会如何变化。
文章基于64位,所以ebp->rbp、esp->rsp
c代码
#include <stdio.h>
void add(int *x, int *y){
*x = 10;
*y = 10;
}
int main(){
int m, n=0;
add(&m, &n);
printf("%d %d", m, n);
return 0;
}
反汇编代码
Dump of assembler code for function main():
8 int main(){
0x0000000000401573 <+0>: push %rbp //将基指针的值rbp压入栈中,保存当前的栈帧基址
0x0000000000401574 <+1>: mov %rsp,%rbp //创建新的栈帧
0x0000000000401577 <+4>: sub $0x30,%rsp //在栈上为局部变量和保存的寄存器留出空间
0x000000000040157b <+8>: callq 0x401670 <__main>
9 int m, n=0;
=> 0x0000000000401580 <+13>: movl $0x0,-0x8(%rbp) 将变量n的值(0)存储在栈上的某个位置(%rbp-0x8)
10 add(&m, &n);
0x0000000000401587 <+20>: lea -0x8(%rbp),%rdx
0x000000000040158b <+24>: lea -0x4(%rbp),%rax //加载变量m和n的地址到寄存器%rdx和%rax。
0x000000000040158f <+28>: mov %rax,%rcx //将%rax的值复制到%rcx,这是为了将m的地址作为第一个参数传递给函数add。
0x0000000000401592 <+31>: callq 0x401550 <add(int*, int*)>
11 printf("%d %d", m, n);
0x0000000000401597 <+36>: mov -0x8(%rbp),%edx //从栈中加载m和n的值到寄存器%edx和%eax
0x000000000040159a <+39>: mov -0x4(%rbp),%eax
0x000000000040159d <+42>: mov %edx,%r8d
0x00000000004015a0 <+45>: mov %eax,%edx
0x00000000004015a2 <+47>: lea 0x2a57(%rip),%rcx # 0x404000
0x00000000004015a9 <+54>: callq 0x402aa0 <printf>
12
13 return 0;
0x00000000004015ae <+59>: mov $0x0,%eax
14 }
0x00000000004015b3 <+64>: add $0x30,%rsp
0x00000000004015b7 <+68>: pop %rbp
0x00000000004015b8 <+69>: retq
Dump of assembler code for function add(int*, int*):
3 void add(int *x, int *y){
0x0000000000401550 <+0>: push %rbp
0x0000000000401551 <+1>: mov %rsp,%rbp
0x0000000000401554 <+4>: mov %rcx,0x10(%rbp)
0x0000000000401558 <+8>: mov %rdx,0x18(%rbp)
4 *x = 10;
=> 0x000000000040155c <+12>: mov 0x10(%rbp),%rax
0x0000000000401560 <+16>: movl $0xa,(%rax)
5 *y = 10;
0x0000000000401566 <+22>: mov 0x18(%rbp),%rax
0x000000000040156a <+26>: movl $0xa,(%rax)
6 }
0x0000000000401570 <+32>: nop
0x0000000000401571 <+33>: pop %rbp
0x0000000000401572 <+34>: retq
End of assembler dump.