// C函数调用堆栈结构分析例程
// 测试环境:平台ubuntu 14.04_3 64位 GCC Ubuntu 4.8.5-2
1 #include <stdio.h>
2 int add(int m, int n)
3 {
4 int x;
5 x = 100;
6 return x+m+n;
7 }
8 int sum(int a, int b, int c, int d, int e, int f)
9 {
10 int a1,a2,a3,a4,a5,a6;
11 a1 = 10;
12 a2 = 20;
13 a3 = 30;
14 a4 = 40;
15 a5 = 50;
16 a6 = 60;
17 return add(a1,a2)+a3+a4+a5+a6+a+b+c+d+e+f;
18 }
19
20 int main()
21 {
22 int x1,x2,x3,x4,sum_of;
23 x1 = 1;
24 x2 = 2;
25 x3 = 3;
26 x4 = 4;
27 sum_of = sum(x1,x2,x3,x4,5,6);
28 return 0;
29 }
//对应的汇编语言程序
0x4004ed <add> push %rbp // bp值压栈
0x4004ee <add+1> mov %rsp,%rbp //当前sp->bp
0x4004f1 <add+4> mov %edi,-0x4(%rbp) //第一实参存储紧邻栈顶
0x4004f4 <add+7> mov %esi,-0x8(%rbp) //第二实参存储
0x4004f7 <add+10> mov -0x8(%rbp),%eax //完成运算
0x4004fa <add+13> mov -0x4(%rbp),%edx
0x4004fd <add+16> add %edx,%eax
0x4004ff <add+18> pop %rbp //恢复bp
0x400500 <add+19> retq //函数返回 返回值通过eax
0x400501 <sum> push %rbp // bp值压栈
0x400502 <sum+1> mov %rsp,%rbp //当前sp->bp
0x400505 <sum+4> sub $0x38,%rsp //根据函数参数及内部变量数调整栈顶指针
0x400509 <sum+8> mov %edi,-0x24(%rbp) //第一实参存储紧邻内部变量
0x40050c <sum+11> mov %esi,-0x28(%rbp) //第二实参存储紧邻内部变量
0x40050f <sum+14> mov %edx,-0x2c(%rbp) //第三实参存储
0x400512 <sum+17> mov %ecx,-0x30(%rbp) //第四实参存储
0x400515 <sum+20> mov %r8d,-0x34(%rbp) //第五实参存储
0x400519 <sum+24> mov %r9d,-0x38(%rbp) //第六实参存储
0x40051d <sum+28> movl $0xa,-0x18(%rbp) //第一个内部变量赋值
0x400524 <sum+35> movl $0x14,-0x14(%rbp) //第二个内部变量赋值
0x40052b <sum+42> movl $0x1e,-0x10(%rbp) //第三个内部变量赋值
0x400532 <sum+49> movl $0x28,-0xc(%rbp) //第四个内部变量赋值
0x400539 <sum+56> movl $0x32,-0x8(%rbp) //第五个内部变量赋值
0x400540 <sum+63> movl $0x3c,-0x4(%rbp) //第六个内部变量赋值
0x400547 <sum+70> mov -0x14(%rbp),%edx //为add函数调用准备参数传递
0x40054a <sum+73> mov -0x18(%rbp),%eax //本编译器通过寄存器传参
0x40054d <sum+76> mov %edx,%esi
0x40054f <sum+78> mov %eax,%edi
0x400551 <sum+80> callq 0x4004ed <add>
0x400556 <sum+85> mov -0x10(%rbp),%edx
0x400559 <sum+88> add %eax,%edx //函数返回值有eax传递
0x40055b <sum+90> mov -0xc(%rbp),%eax
0x40055e <sum+93> add %eax,%edx
0x400560 <sum+95> mov -0x8(%rbp),%eax
0x400563 <sum+98> add %eax,%edx
0x400565 <sum+100> mov -0x4(%rbp),%eax
0x400568 <sum+103> add %eax,%edx
0x40056a <sum+105> mov -0x24(%rbp),%eax
0x40056d <sum+108> add %eax,%edx
0x40056f <sum+110> mov -0x28(%rbp),%eax
0x400572 <sum+113> add %eax,%edx
0x400574 <sum+115> mov -0x2c(%rbp),%eax
0x400577 <sum+118> add %eax,%edx
0x400579 <sum+120> mov -0x30(%rbp),%eax
0x40057c <sum+123> add %eax,%edx
0x40057e <sum+125> mov -0x34(%rbp),%eax
0x400581 <sum+128> add %eax,%edx
0x400583 <sum+130> mov -0x38(%rbp),%eax
0x400586 <sum+133> add %edx,%eax
0x400588 <sum+135> leaveq
0x400589 <sum+136> retq //函数返回
0x40058a <main> push %rbp // bp值压栈
0x40058b <main+1> mov %rsp,%rbp //当前sp->bp
0x40058e <main+4> sub $0x20,%rsp //根据函数参数及内部变量数调整栈顶指针
0x400592 <main+8> movl $0x1,-0x14(%rbp) //第一个内部变量赋值
0x400599 <main+15> movl $0x2,-0x10(%rbp) //第二个内部变量赋值
0x4005a0 <main+22> movl $0x3,-0xc(%rbp) //第三个内部变量赋值
0x4005a7 <main+29> movl $0x4,-0x8(%rbp) //第四个内部变量赋值
0x4005ae <main+36> mov -0x8(%rbp),%ecx //为sum函数调用准备参数
0x4005b1 <main+39> mov -0xc(%rbp),%edx
0x4005b4 <main+42> mov -0x10(%rbp),%esi
0x4005b7 <main+45> mov -0x14(%rbp),%eax
0x4005ba <main+48> mov $0x6,%r9d
0x4005c0 <main+54> mov $0x5,%r8d
0x4005c6 <main+60> mov %eax,%edi
0x4005c8 <main+62> callq 0x400501 <sum>
0x4005cd <main+67> mov %eax,-0x4(%rbp)
0x4005d0 <main+70> mov $0x0,%eax
0x4005d5 <main+75> leaveq
0x4005d6 <main+76> retq
0x4005d7 nopw 0x0(%rax,%rax,1)
0x4005e0 <__libc_csu_init> push %r15
(gdb) b main
Breakpoint 1 at 0x400592: file test.c, line 21.
(gdb) display $rsp //监测sp的值
(gdb) display $rbp //监测bp的值
(gdb) display $rip //监测ip的值
(gdb) layout asm //显示汇编语句窗口
(gdb)r //运行程序
Starting program: /home/cmaxd/src/4-1/test
Breakpoint 1, main () at test.c:21
21 x1 = 1;
(gdb)si //指令级单步执行
3: $rip = (void (*)()) 0x400592 <main+8>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x00000000 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000000
0x7fffffffdc70: 0xffffdd60 0x00007fff 0x00000000 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
//以下完成main函数内部变量x1~x4的赋值,x1~x4的存储空间分配在栈中
(gdb) si
3: $rip = (void (*)()) 0x400599 <main+15>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005a0 <main+22>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005a7 <main+29>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005ae <main+36>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x00000000 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si 7
3: $rip = (void (*)()) 0x4005c8 <main+62>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//这段程序完成sum函数调用前的参数准备
//参数传递顺序为 第一个参数->edi, 第二个参数->esi,第三个参数->edx,第四个参数->ecx,第五个参数->r8,第六个参数->r9
(gdb) info reg
rax 0x1 1
rbx 0x0 0
rcx 0x4 4
rdx 0x3 3
rsi 0x2 2
rdi 0x1 1
rbp 0x7fffffffdc80 0x7fffffffdc80
rsp 0x7fffffffdc60 0x7fffffffdc60
r8 0x5 5
r9 0x6 6
r10 0x7fffffffdb10 140737488345872
r11 0x7ffff7a32e50 140737348054608
r12 0x400400 4195328
r13 0x7fffffffdd60 140737488346464
r14 0x0 0
r15 0x0 0
rip 0x4005c8 0x4005c8 <main+62>
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) si
sum (a=32767, b=-134340608, c=32767, d=-140373512, e=32767, f=-8840) at test.c:7
3: $rip = (void (*)()) 0x400501 <sum>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc58
//系统自动完成函数返回地址的压栈,为sum函数调用作准备
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x400502 <sum+1>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc50
//bp入栈
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x400505 <sum+4>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc50
// sp -> bp
(gdb) si
3: $rip = (void (*)()) 0x400509 <sum+8>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//根据内部变量及函数参数调整栈顶指针
(gdb) si 16
3: $rip = (void (*)()) 0x400551 <sum+80>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//存储实参值、内部变量赋值、为调用add函数进行参数传递准备
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb)info reg
rax 0xa 10
rbx 0x0 0
rcx 0x4 4
rdx 0x14 20
rsi 0x14 20
rdi 0xa 10
rbp 0x7fffffffdc50 0x7fffffffdc50
rsp 0x7fffffffdc18 0x7fffffffdc18
r8 0x5 5
r9 0x6 6
r10 0x7fffffffdb10 140737488345872
r11 0x7ffff7a32e50 140737348054608
r12 0x400400 4195328
r13 0x7fffffffdd60 140737488346464
r14 0x0 0
r15 0x0 0
rip 0x400551 0x400551 <sum+80>
eflags 0x216 [ PF AF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) si
add (m=0, n=-163754450) at test.c:3
3: $rip = (void (*)()) 0x4004ed <add>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc10
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
//系统自动完成返回地址压栈,为add函数调用作准备
(gdb) si
3: $rip = (void (*)()) 0x4004ee <add+1>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc08
//bp压栈
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x4004f1 <add+4>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
// sp->bp
3: $rip = (void (*)()) 0x4004fd <add+16>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
//实参存储、参数到寄存器的转移
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014 0x0000000a 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
rax 0x14 20
rbx 0x0 0
rcx 0x4 4
rdx 0xa 10
rsi 0x14 20
rdi 0xa 10
(gdb) si
3: $rip = (void (*)()) 0x4004ff <add+18>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
rax 0x1e 30
//完成加运算
(gdb) si
3: $rip = (void (*)()) 0x400500 <add+19>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc10
//恢复 bp 准备函数返回
(gdb) si
0x0000000000400556 in sum (a=1, b=2, c=3, d=4, e=5, f=6) at test.c:15
3: $rip = (void (*)()) 0x400556 <sum+85>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//add函数返回
(gdb) si 20
3: $rip = (void (*)()) 0x400588 <sum+135>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
// 完成sum函数中的其他工作
(gdb) si
3: $rip = (void (*)()) 0x400589 <sum+136>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc58
// leaveq 指令完成堆栈指针调整
(gdb) si
0x00000000004005cd in main () at test.c:25
3: $rip = (void (*)()) 0x4005cd <main+67>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//sum函数返回
(gdb) si
3: $rip = (void (*)()) 0x4005d0 <main+70>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//sum函数返回值通过eax寄存器传出并赋值给sum_of变量
(gdb) p &sum_of
$1 = (int *) 0x7fffffffdc7c
(gdb) p sum_of
$2 = 231
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014 0x0000000a 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x000000e7
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x4005d6 <main+76>
2: $rbp = (void *) 0x0
1: $rsp = (void *) 0x7fffffffdc88
//leaveq 函数调整堆栈指针
(gdb) si
__libc_start_main (main=0x40058a <main>, argc=1, argv=0x7fffffffdd68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffffffdd58) at libc-start.c:321
3: $rip = (void (*)()) 0x7ffff7a32f45 <__libc_start_main+245>
2: $rbp = (void *) 0x0
1: $rsp = (void *) 0x7fffffffdc90
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014 0x0000000a 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x000000e7
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
0x7fffffffdc90: 0x00000000 0x00000000 0xffffdd68 0x00007fff
堆栈内容分析
地址 内容 注释
0x7…dc00 0x00000014 实参n
0x7…dc04 0x0000000a 实参m
0x7…dc08 0xffffdc50 add函数后bp的原值存储此,此后pb、sp<-0x7fffffffdc08
0x7…dc0c 0x00007fff
0x7…dc10 0x00400556 add函数调用之后的sp 位置,内容为add函数的返回地址
0x7…dc14 0x00000000
0x7…dc18 0x00000006 实参 f add调用前的sp指针 <sum+4>
0x7…dc1c 0x00000005 实参 e
0x7…dc20 0x00000004 实参 d
0x7…dc24 0x00000003 实参 c
0x7…dc28 0x00000002 实参 b
0x7…dc2c 0x00000001 实参 a
0x7…dc30 0xf7ffe1c8
0x7…dc34 0x00007fff
0x7…dc38 0x0000000a sum内部变量a1
0x7…dc3c 0x00000014 sum内部变量a2
0x7…dc40 0x0000001e sum内部变量a3
0x7…dc44 0x00000028 sum内部变量a4
0x7…dc48 0x00000032 sum内部变量a5
0x7…dc4c 0x0000003c sum内部变量a6
0x7…dc50 0xffffdc80 sum函数后bp的原值存储在此,
此后bp<-0x7fffffffdc50 sp<-0x7fffffffdc18
0x7…dc54 0x00007fff
0x7…dc58 0x004005cd sum函数调用之后的sp位置,内容为sum函数的返回地址,系统自动压栈
0x7…dc5c 0x00000000
0x7…dc60 0x004005e0 sum函数调用之前的sp位置,内容为main函数的返回地址,由<main+4>调整
0x7…dc64 0x00000000
0x7…dc68 0x00400400
0x7…dc6c 0x00000001 main函数内部变量x1
0x7…dc70 0x00000002 main函数内部变量x2
0x7…dc74 0x00000003 main函数内部变量x3
0x7…dc78 0x00000004 main函数内部变量x4
0x7…dc7c 0x000000e7 main函数内部变量sum_of
0x7…dc80 0x00000000 进入main函数后bp的原值存储在此
此后bp<-0x7fffffffdc80 sp<-0x7fffffffdc60
0x7…dc84 0x00000000
// C函数调用堆栈结构分析例程
// 测试环境:平台ubuntu 14.04_3 64位
// GCC Ubuntu 4.8.5-2
1 #include <stdio.h>
2 int add(int m, int n)
3 {
4 int x;
5 x = 100;
6 return x+m+n;
7 }
8 int sum(int a, int b, int c, int d, int e, int f)
9 {
10 int a1,a2,a3,a4,a5,a6;
11 a1 = 10;
12 a2 = 20;
13 a3 = 30;
14 a4 = 40;
15 a5 = 50;
16 a6 = 60;
17 return add(a1,a2)+a3+a4+a5 \ +a6+a+b+c+d+e+f;
18 }
19
20 int main()
21 {
22 int x1,x2,x3,x4,sum_of;
23 x1 = 1;
24 x2 = 2;
25 x3 = 3;
26 x4 = 4;
27 sum_of = sum(x1,x2,x3,x4,5,6);
28 return 0;
29 }
// 测试环境:平台ubuntu 14.04_3 64位 GCC Ubuntu 4.8.5-2
1 #include <stdio.h>
2 int add(int m, int n)
3 {
4 int x;
5 x = 100;
6 return x+m+n;
7 }
8 int sum(int a, int b, int c, int d, int e, int f)
9 {
10 int a1,a2,a3,a4,a5,a6;
11 a1 = 10;
12 a2 = 20;
13 a3 = 30;
14 a4 = 40;
15 a5 = 50;
16 a6 = 60;
17 return add(a1,a2)+a3+a4+a5+a6+a+b+c+d+e+f;
18 }
19
20 int main()
21 {
22 int x1,x2,x3,x4,sum_of;
23 x1 = 1;
24 x2 = 2;
25 x3 = 3;
26 x4 = 4;
27 sum_of = sum(x1,x2,x3,x4,5,6);
28 return 0;
29 }
//对应的汇编语言程序
0x4004ed <add> push %rbp // bp值压栈
0x4004ee <add+1> mov %rsp,%rbp //当前sp->bp
0x4004f1 <add+4> mov %edi,-0x4(%rbp) //第一实参存储紧邻栈顶
0x4004f4 <add+7> mov %esi,-0x8(%rbp) //第二实参存储
0x4004f7 <add+10> mov -0x8(%rbp),%eax //完成运算
0x4004fa <add+13> mov -0x4(%rbp),%edx
0x4004fd <add+16> add %edx,%eax
0x4004ff <add+18> pop %rbp //恢复bp
0x400500 <add+19> retq //函数返回 返回值通过eax
0x400501 <sum> push %rbp // bp值压栈
0x400502 <sum+1> mov %rsp,%rbp //当前sp->bp
0x400505 <sum+4> sub $0x38,%rsp //根据函数参数及内部变量数调整栈顶指针
0x400509 <sum+8> mov %edi,-0x24(%rbp) //第一实参存储紧邻内部变量
0x40050c <sum+11> mov %esi,-0x28(%rbp) //第二实参存储紧邻内部变量
0x40050f <sum+14> mov %edx,-0x2c(%rbp) //第三实参存储
0x400512 <sum+17> mov %ecx,-0x30(%rbp) //第四实参存储
0x400515 <sum+20> mov %r8d,-0x34(%rbp) //第五实参存储
0x400519 <sum+24> mov %r9d,-0x38(%rbp) //第六实参存储
0x40051d <sum+28> movl $0xa,-0x18(%rbp) //第一个内部变量赋值
0x400524 <sum+35> movl $0x14,-0x14(%rbp) //第二个内部变量赋值
0x40052b <sum+42> movl $0x1e,-0x10(%rbp) //第三个内部变量赋值
0x400532 <sum+49> movl $0x28,-0xc(%rbp) //第四个内部变量赋值
0x400539 <sum+56> movl $0x32,-0x8(%rbp) //第五个内部变量赋值
0x400540 <sum+63> movl $0x3c,-0x4(%rbp) //第六个内部变量赋值
0x400547 <sum+70> mov -0x14(%rbp),%edx //为add函数调用准备参数传递
0x40054a <sum+73> mov -0x18(%rbp),%eax //本编译器通过寄存器传参
0x40054d <sum+76> mov %edx,%esi
0x40054f <sum+78> mov %eax,%edi
0x400551 <sum+80> callq 0x4004ed <add>
0x400556 <sum+85> mov -0x10(%rbp),%edx
0x400559 <sum+88> add %eax,%edx //函数返回值有eax传递
0x40055b <sum+90> mov -0xc(%rbp),%eax
0x40055e <sum+93> add %eax,%edx
0x400560 <sum+95> mov -0x8(%rbp),%eax
0x400563 <sum+98> add %eax,%edx
0x400565 <sum+100> mov -0x4(%rbp),%eax
0x400568 <sum+103> add %eax,%edx
0x40056a <sum+105> mov -0x24(%rbp),%eax
0x40056d <sum+108> add %eax,%edx
0x40056f <sum+110> mov -0x28(%rbp),%eax
0x400572 <sum+113> add %eax,%edx
0x400574 <sum+115> mov -0x2c(%rbp),%eax
0x400577 <sum+118> add %eax,%edx
0x400579 <sum+120> mov -0x30(%rbp),%eax
0x40057c <sum+123> add %eax,%edx
0x40057e <sum+125> mov -0x34(%rbp),%eax
0x400581 <sum+128> add %eax,%edx
0x400583 <sum+130> mov -0x38(%rbp),%eax
0x400586 <sum+133> add %edx,%eax
0x400588 <sum+135> leaveq
0x400589 <sum+136> retq //函数返回
0x40058a <main> push %rbp // bp值压栈
0x40058b <main+1> mov %rsp,%rbp //当前sp->bp
0x40058e <main+4> sub $0x20,%rsp //根据函数参数及内部变量数调整栈顶指针
0x400592 <main+8> movl $0x1,-0x14(%rbp) //第一个内部变量赋值
0x400599 <main+15> movl $0x2,-0x10(%rbp) //第二个内部变量赋值
0x4005a0 <main+22> movl $0x3,-0xc(%rbp) //第三个内部变量赋值
0x4005a7 <main+29> movl $0x4,-0x8(%rbp) //第四个内部变量赋值
0x4005ae <main+36> mov -0x8(%rbp),%ecx //为sum函数调用准备参数
0x4005b1 <main+39> mov -0xc(%rbp),%edx
0x4005b4 <main+42> mov -0x10(%rbp),%esi
0x4005b7 <main+45> mov -0x14(%rbp),%eax
0x4005ba <main+48> mov $0x6,%r9d
0x4005c0 <main+54> mov $0x5,%r8d
0x4005c6 <main+60> mov %eax,%edi
0x4005c8 <main+62> callq 0x400501 <sum>
0x4005cd <main+67> mov %eax,-0x4(%rbp)
0x4005d0 <main+70> mov $0x0,%eax
0x4005d5 <main+75> leaveq
0x4005d6 <main+76> retq
0x4005d7 nopw 0x0(%rax,%rax,1)
0x4005e0 <__libc_csu_init> push %r15
(gdb) b main
Breakpoint 1 at 0x400592: file test.c, line 21.
(gdb) display $rsp //监测sp的值
(gdb) display $rbp //监测bp的值
(gdb) display $rip //监测ip的值
(gdb) layout asm //显示汇编语句窗口
(gdb)r //运行程序
Starting program: /home/cmaxd/src/4-1/test
Breakpoint 1, main () at test.c:21
21 x1 = 1;
(gdb)si //指令级单步执行
3: $rip = (void (*)()) 0x400592 <main+8>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x00000000 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000000
0x7fffffffdc70: 0xffffdd60 0x00007fff 0x00000000 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
//以下完成main函数内部变量x1~x4的赋值,x1~x4的存储空间分配在栈中
(gdb) si
3: $rip = (void (*)()) 0x400599 <main+15>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005a0 <main+22>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005a7 <main+29>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005ae <main+36>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x00000000 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si 7
3: $rip = (void (*)()) 0x4005c8 <main+62>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//这段程序完成sum函数调用前的参数准备
//参数传递顺序为 第一个参数->edi, 第二个参数->esi,第三个参数->edx,第四个参数->ecx,第五个参数->r8,第六个参数->r9
(gdb) info reg
rax 0x1 1
rbx 0x0 0
rcx 0x4 4
rdx 0x3 3
rsi 0x2 2
rdi 0x1 1
rbp 0x7fffffffdc80 0x7fffffffdc80
rsp 0x7fffffffdc60 0x7fffffffdc60
r8 0x5 5
r9 0x6 6
r10 0x7fffffffdb10 140737488345872
r11 0x7ffff7a32e50 140737348054608
r12 0x400400 4195328
r13 0x7fffffffdd60 140737488346464
r14 0x0 0
r15 0x0 0
rip 0x4005c8 0x4005c8 <main+62>
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) si
sum (a=32767, b=-134340608, c=32767, d=-140373512, e=32767, f=-8840) at test.c:7
3: $rip = (void (*)()) 0x400501 <sum>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc58
//系统自动完成函数返回地址的压栈,为sum函数调用作准备
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x400502 <sum+1>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc50
//bp入栈
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0xffffdd78 0x00007fff
0x7fffffffdc20: 0xf7a211f8 0x00007fff 0xf7fe2000 0x00007fff
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x00000000 0x00000000
0x7fffffffdc40: 0x00000001 0x00000000 0x0040062d 0x00000000
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x400505 <sum+4>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc50
// sp -> bp
(gdb) si
3: $rip = (void (*)()) 0x400509 <sum+8>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//根据内部变量及函数参数调整栈顶指针
(gdb) si 16
3: $rip = (void (*)()) 0x400551 <sum+80>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//存储实参值、内部变量赋值、为调用add函数进行参数传递准备
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0xffffffff 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb)info reg
rax 0xa 10
rbx 0x0 0
rcx 0x4 4
rdx 0x14 20
rsi 0x14 20
rdi 0xa 10
rbp 0x7fffffffdc50 0x7fffffffdc50
rsp 0x7fffffffdc18 0x7fffffffdc18
r8 0x5 5
r9 0x6 6
r10 0x7fffffffdb10 140737488345872
r11 0x7ffff7a32e50 140737348054608
r12 0x400400 4195328
r13 0x7fffffffdd60 140737488346464
r14 0x0 0
r15 0x0 0
rip 0x400551 0x400551 <sum+80>
eflags 0x216 [ PF AF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) si
add (m=0, n=-163754450) at test.c:3
3: $rip = (void (*)()) 0x4004ed <add>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc10
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0x0040030b 0x00000000
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
//系统自动完成返回地址压栈,为add函数调用作准备
(gdb) si
3: $rip = (void (*)()) 0x4004ee <add+1>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc08
//bp压栈
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e 0x00000000 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x4004f1 <add+4>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
// sp->bp
3: $rip = (void (*)()) 0x4004fd <add+16>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
//实参存储、参数到寄存器的转移
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014 0x0000000a 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x00000000
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
rax 0x14 20
rbx 0x0 0
rcx 0x4 4
rdx 0xa 10
rsi 0x14 20
rdi 0xa 10
(gdb) si
3: $rip = (void (*)()) 0x4004ff <add+18>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
rax 0x1e 30
//完成加运算
(gdb) si
3: $rip = (void (*)()) 0x400500 <add+19>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc10
//恢复 bp 准备函数返回
(gdb) si
0x0000000000400556 in sum (a=1, b=2, c=3, d=4, e=5, f=6) at test.c:15
3: $rip = (void (*)()) 0x400556 <sum+85>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//add函数返回
(gdb) si 20
3: $rip = (void (*)()) 0x400588 <sum+135>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
// 完成sum函数中的其他工作
(gdb) si
3: $rip = (void (*)()) 0x400589 <sum+136>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc58
// leaveq 指令完成堆栈指针调整
(gdb) si
0x00000000004005cd in main () at test.c:25
3: $rip = (void (*)()) 0x4005cd <main+67>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//sum函数返回
(gdb) si
3: $rip = (void (*)()) 0x4005d0 <main+70>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//sum函数返回值通过eax寄存器传出并赋值给sum_of变量
(gdb) p &sum_of
$1 = (int *) 0x7fffffffdc7c
(gdb) p sum_of
$2 = 231
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014 0x0000000a 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x000000e7
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
(gdb) si
3: $rip = (void (*)()) 0x4005d6 <main+76>
2: $rbp = (void *) 0x0
1: $rsp = (void *) 0x7fffffffdc88
//leaveq 函数调整堆栈指针
(gdb) si
__libc_start_main (main=0x40058a <main>, argc=1, argv=0x7fffffffdd68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
stack_end=0x7fffffffdd58) at libc-start.c:321
3: $rip = (void (*)()) 0x7ffff7a32f45 <__libc_start_main+245>
2: $rbp = (void *) 0x0
1: $rsp = (void *) 0x7fffffffdc90
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014 0x0000000a 0xffffdc50 0x00007fff
0x7fffffffdc10: 0x00400556 0x00000000 0x00000006 0x00000005
0x7fffffffdc20: 0x00000004 0x00000003 0x00000002 0x00000001
0x7fffffffdc30: 0xf7ffe1c8 0x00007fff 0x0000000a 0x00000014
0x7fffffffdc40: 0x0000001e 0x00000028 0x00000032 0x0000003c
0x7fffffffdc50: 0xffffdc80 0x00007fff 0x004005cd 0x00000000
0x7fffffffdc60: 0x004005e0 0x00000000 0x00400400 0x00000001
0x7fffffffdc70: 0x00000002 0x00000003 0x00000004 0x000000e7
0x7fffffffdc80: 0x00000000 0x00000000 0xf7a32f45 0x00007fff
0x7fffffffdc90: 0x00000000 0x00000000 0xffffdd68 0x00007fff
堆栈内容分析
地址 内容 注释
0x7…dc00 0x00000014 实参n
0x7…dc04 0x0000000a 实参m
0x7…dc08 0xffffdc50 add函数后bp的原值存储此,此后pb、sp<-0x7fffffffdc08
0x7…dc0c 0x00007fff
0x7…dc10 0x00400556 add函数调用之后的sp 位置,内容为add函数的返回地址
0x7…dc14 0x00000000
0x7…dc18 0x00000006 实参 f add调用前的sp指针 <sum+4>
0x7…dc1c 0x00000005 实参 e
0x7…dc20 0x00000004 实参 d
0x7…dc24 0x00000003 实参 c
0x7…dc28 0x00000002 实参 b
0x7…dc2c 0x00000001 实参 a
0x7…dc30 0xf7ffe1c8
0x7…dc34 0x00007fff
0x7…dc38 0x0000000a sum内部变量a1
0x7…dc3c 0x00000014 sum内部变量a2
0x7…dc40 0x0000001e sum内部变量a3
0x7…dc44 0x00000028 sum内部变量a4
0x7…dc48 0x00000032 sum内部变量a5
0x7…dc4c 0x0000003c sum内部变量a6
0x7…dc50 0xffffdc80 sum函数后bp的原值存储在此,
此后bp<-0x7fffffffdc50 sp<-0x7fffffffdc18
0x7…dc54 0x00007fff
0x7…dc58 0x004005cd sum函数调用之后的sp位置,内容为sum函数的返回地址,系统自动压栈
0x7…dc5c 0x00000000
0x7…dc60 0x004005e0 sum函数调用之前的sp位置,内容为main函数的返回地址,由<main+4>调整
0x7…dc64 0x00000000
0x7…dc68 0x00400400
0x7…dc6c 0x00000001 main函数内部变量x1
0x7…dc70 0x00000002 main函数内部变量x2
0x7…dc74 0x00000003 main函数内部变量x3
0x7…dc78 0x00000004 main函数内部变量x4
0x7…dc7c 0x000000e7 main函数内部变量sum_of
0x7…dc80 0x00000000 进入main函数后bp的原值存储在此
此后bp<-0x7fffffffdc80 sp<-0x7fffffffdc60
0x7…dc84 0x00000000
// C函数调用堆栈结构分析例程
// 测试环境:平台ubuntu 14.04_3 64位
// GCC Ubuntu 4.8.5-2
1 #include <stdio.h>
2 int add(int m, int n)
3 {
4 int x;
5 x = 100;
6 return x+m+n;
7 }
8 int sum(int a, int b, int c, int d, int e, int f)
9 {
10 int a1,a2,a3,a4,a5,a6;
11 a1 = 10;
12 a2 = 20;
13 a3 = 30;
14 a4 = 40;
15 a5 = 50;
16 a6 = 60;
17 return add(a1,a2)+a3+a4+a5 \ +a6+a+b+c+d+e+f;
18 }
19
20 int main()
21 {
22 int x1,x2,x3,x4,sum_of;
23 x1 = 1;
24 x2 = 2;
25 x3 = 3;
26 x4 = 4;
27 sum_of = sum(x1,x2,x3,x4,5,6);
28 return 0;
29 }
