//(前面启动gdb,设置参数和断点的步骤省略……)
(gdb) r
Starting program: /media/Personal/MyProject/C/StackOver/test abc
Address of foo = 0x80483d4
//函数foo的地址
Address of bar = 0x8048419
//函数bar的地址
Breakpoint 1, main (argc=2, argv=0xbfe5ab24) at test.c:24
24
foo(argv[1]);
//在调用foo函数前,我们查看ebp值
(gdb) info registers ebp
ebp
0xbfe5aa88
0xbfe5aa88
//ebp值为0xbfe5aa88
(gdb) n
Breakpoint 2, foo (input=0xbfe5c652 "abc") at test.c:4
4
{
(gdb) n
6
printf("My stack looks like:"n%p"n%p"n%p"n%p"n%p"n%p"n%p"n"n");
//执行到foo后,我们再查看ebp值
(gdb) info registers ebp
ebp
0xbfe5aa68
0xbfe5aa68
//ebp值变成了0xbfe5aa68
//我们来查看一下地址0xbfe5aa68究竟是啥东东:
(gdb) x/ 0xbfe5aa68
0xbfe5aa68:
0xbfe5aa88
//原来地址0xbfe5aa68存放的居然是我们之前的ebp值,其实豁然开朗了,因为这是执行了push %ebp后将之前的ebp保存起来了,和前面说的居然是一样的!
(gdb) n
My stack looks like:
0xb7ee04e0
0x8048616
0xbfe5aa74
0xbfe5aa74
0xb7edfff4
0xbfe5aa88
//看,在代码中输入堆栈信息中也出现了熟悉的0xbfe5aa88,因此可以断定该处为保存的上一级的ebp值。对应上上面那个图中的sfp。
0x8048499
//假如0xbfe5aa88就是sfp的话,那0x8048499应该就是ret(返回地址)了,下面来验证一下
7
strcpy(buf, input);
//查看0x8048499里面是什么东东
(gdb) x/i 0x8048499
0x8048499 <main+108>:
movl
$0x8048653,(%esp)
//这句代码是main函数中的代码,正是我们执行完foo函数后的下一个地址。不信,看看main的assemble:
(gdb) disassemble main
Dump of assembler code for function main:
0x0804842d <main+0>:
lea
0x4(%esp),%ecx
0x08048431 <main+4>:
and
$0xfffffff0,%esp
0x08048434 <main+7>:
pushl -0x4(%ecx)
0x08048437 <main+10>:
push
%ebp
//(中间省略……)
0x08048494 <main+103>: call
0x80483d4 <foo>
0x08048499 <main+108>: movl
$0x8048653,(%esp)
//就是这里了!哈
0x080484a0 <main+115>: call
0x8048340 <puts@plt>