《coredump问题原理探究》Linux x86版3.5节栈布局之-fomit-frame-pointer编译选项
上面探讨了没有使用-fomit-frame-pointer编译选项的程序的栈桢规律,那么如果一个程序是通过-fomit-frame-pointer编译选项来编译,它运行时的栈桢规律有没有可能不同呢?
先看一个例子:
(gdb) tbreak funcTemporary breakpoint 1 at 0x8048470(gdb) rStarting program: /home/buckxu/work/3/4/xuzhina_dump_c3_s4 Temporary breakpoint 1, 0x08048470 in func(int) () (gdb) bt #0 0x08048470 in func(int) ()#1 0x080484ac in test(int, int) ()#2 0x080484ec in main ()(gdb) x /32x $esp0xbffff448: 0x080484ac 0x00000000 0x437c43c4 0x43647f360xbffff458: 0x080497b8 0x08048552 0x00000001 0xbffff5240xbffff468: 0xbffff52c 0x43647f4d 0x437c43c4 0x43cb75ec0xbffff478: 0x0804850b 0x00000000 0x080484ec 0x000000050xbffff488: 0x00000064 0x4362f635 0x00000001 0xbffff5240xbffff498: 0xbffff52c 0xb7ffef18 0x00000001 0x000000010xbffff4a8: 0x00000000 0x00000008 0x00000002 0x437c3ff40xbffff4b8: 0x00000000 0x00000000 0x00000000 0xdd2af16c
从上面可以看到,0x080484ac的地址是0xbffff448,而0x080484ec的地址是0xbffff480。0xbffff480-0xbffff448=0x38 = 0x34 + 4(返回地址大小)。和上面推断一致。
在-fomit-frame-pointer编译选项生成的程序里,栈布局有这样的规律:
两个相邻的返回地址ret1,ret2,其中ret1属于函数func1,ret2属于函数func2,且func1调用func2。当func2调用func3时,ret2被压入栈。其中func2的局部变量空间大小为var_size,func3压入栈中的参数大小为par_size,那么它们会满足下面的条件:
1. addr(ret1)-addr(ret2)= var_size + par_size + 4
2. info symbol ret1, info symbol ret2都能够显示出func1, func2
PS:这个规律是更加通用的,不止在x86平台下,在sparc,mips,arm都是这样。