前言
之前有一篇 java 的方法调用堆栈信息的分析 main方法的栈帧信息
这里 我们来看一下 c 语言的函数调用的堆栈信息, 相比于 java 的堆栈信息, 这里是要简单一些
因为 堆栈信息的所有的东西都在对应的汇编中能够看到
但是 java 的方法调用自己又封装了一层, 成本稍微高一些
测试用例
#include "stdio.h"
int func_3(int arg3) {
int locals_3 = 3;
int locals_4 = 4;
return locals_3 + locals_4 + arg3;
}
int func_2(int arg2) {
int locals_2 = 2;
return func_3(locals_2 + arg2);
}
int func_1(int arg1) {
int locals_1 = 1;
return func_2(locals_1 + arg1);
}
int main(int argc, char **argv) {
int locals_0 = 10;
int result = func_1(locals_0);
printf(" func_1 arg0 : %d, result : %d \n", locals_0, result);
}
堆栈信息
堆栈信息如下
(gdb) x /20gx 0x7fffffffe3d0
0x7fffffffe3d0: 0x0000000000000000 0x0000000d00000000 // func_3_locals | arg3
0x7fffffffe3e0: 0x0000000000000000 0x0000000400000003 // func_3_locals | local_3, locals_4
0x7fffffffe3f0: 0x00007fffffffe418 0x000000000040056b // func_2's bp, func_2'sreturnAddress
0x7fffffffe400: 0x0000000b00000000 0x0000000000000000 // func_2_locals | arg2
0x7fffffffe410: 0x0000000200000000 0x00007fffffffe440 // func_2_locals, func_1's bp | locals_2
0x7fffffffe420: 0x000000000040058e 0x0000000a00000000 // func_1's returnAddress, func_1_locals | arg1
0x7fffffffe430: 0x0000000000000001 0x000000010040062d // func_1_locals | locals_1
0x7fffffffe440: 0x00007fffffffe470 0x00000000004005b0 // main's bp, main'sReturnAddress
0x7fffffffe450: 0x00007fffffffe558 0x0000000100400430 // main_locals | si, di
0x7fffffffe460: 0x00007fffffffe550 0x000000000000000a // main_locals | locals_0
0x7fffffffe470: 0x00000000004005e0 0x00007ffff7a2d840 // caller's bp, x
0x7fffffffe480: 0x0000000000000000 0x00007fffffffe558
我们分别列一下 各个函数的内容, 可以对照上面的堆栈信息看一下
这里只是举得一个简单点额例子, 如果参数过多, 会有一部分参数 也放置在 堆栈中
(gdb) disassemble main
Dump of assembler code for function main:
0x0000000000400590 <+0>: push %rbp
0x0000000000400591 <+1>: mov %rsp,%rbp
0x0000000000400594 <+4>: sub $0x20,%rsp
0x0000000000400598 <+8>: mov %edi,-0x14(%rbp)
0x000000000040059b <+11>: mov %rsi,-0x20(%rbp)
0x000000000040059f <+15>: movl $0xa,-0x8(%rbp)
0x00000000004005a6 <+22>: mov -0x8(%rbp),%eax
0x00000000004005a9 <+25>: mov %eax,%edi
0x00000000004005ab <+27>: callq 0x40056d <func_1>
0x00000000004005b0 <+32>: mov %eax,-0x4(%rbp)
0x00000000004005b3 <+35>: mov -0x4(%rbp),%edx
0x00000000004005b6 <+38>: mov -0x8(%rbp),%eax
0x00000000004005b9 <+41>: mov %eax,%esi
0x00000000004005bb <+43>: mov $0x400668,%edi
0x00000000004005c0 <+48>: mov $0x0,%eax
0x00000000004005c5 <+53>: callq 0x400400 <printf@plt>
0x00000000004005ca <+58>: mov $0x0,%eax
0x00000000004005cf <+63>: leaveq
0x00000000004005d0 <+64>: retq
End of assembler dump.
(gdb) disassemble func_1
Dump of assembler code for function func_1:
0x000000000040056d <+0>: push %rbp
0x000000000040056e <+1>: mov %rsp,%rbp
0x0000000000400571 <+4>: sub $0x18,%rsp
0x0000000000400575 <+8>: mov %edi,-0x14(%rbp)
0x0000000000400578 <+11>: movl $0x1,-0x4(%rbp)
0x000000000040057f <+18>: mov -0x4(%rbp),%edx
0x0000000000400582 <+21>: mov -0x14(%rbp),%eax
0x0000000000400585 <+24>: add %edx,%eax
0x0000000000400587 <+26>: mov %eax,%edi
0x0000000000400589 <+28>: callq 0x40054a <func_2>
0x000000000040058e <+33>: leaveq
0x000000000040058f <+34>: retq
End of assembler dump.
(gdb) disassemble func_2
Dump of assembler code for function func_2:
0x000000000040054a <+0>: push %rbp
0x000000000040054b <+1>: mov %rsp,%rbp
0x000000000040054e <+4>: sub $0x18,%rsp
0x0000000000400552 <+8>: mov %edi,-0x14(%rbp)
0x0000000000400555 <+11>: movl $0x2,-0x4(%rbp)
0x000000000040055c <+18>: mov -0x4(%rbp),%edx
0x000000000040055f <+21>: mov -0x14(%rbp),%eax
0x0000000000400562 <+24>: add %edx,%eax
0x0000000000400564 <+26>: mov %eax,%edi
0x0000000000400566 <+28>: callq 0x400526 <func_3>
0x000000000040056b <+33>: leaveq
0x000000000040056c <+34>: retq
End of assembler dump.
(gdb) disassemble func_3
Dump of assembler code for function func_3:
0x0000000000400526 <+0>: push %rbp
0x0000000000400527 <+1>: mov %rsp,%rbp
0x000000000040052a <+4>: mov %edi,-0x14(%rbp)
0x000000000040052d <+7>: movl $0x3,-0x8(%rbp)
0x0000000000400534 <+14>: movl $0x4,-0x4(%rbp)
0x000000000040053b <+21>: mov -0x8(%rbp),%edx
0x000000000040053e <+24>: mov -0x4(%rbp),%eax
0x0000000000400541 <+27>: add %eax,%edx
0x0000000000400543 <+29>: mov -0x14(%rbp),%eax
=> 0x0000000000400546 <+32>: add %edx,%eax
0x0000000000400548 <+34>: pop %rbp
0x0000000000400549 <+35>: retq
完