bug.c
void swap(int a, int b)
{
int c;
c = a;
a = b;
b = c;
}
int main()
{
int a,b;
a = 16;
b = 32;
swap(a, b);
return (a-b);
}
使用gdb调试,main函数反汇编的代码
(gdb) x /20i $pc
=> 0x40135c <main+14>: movl $0x10,0x1c(%esp)
0x401364 <main+22>: movl $0x20,0x18(%esp)
0x40136c <main+30>: mov 0x18(%esp),%eax
0x401370 <main+34>: mov %eax,0x4(%esp)
0x401374 <main+38>: mov 0x1c(%esp),%eax
0x401378 <main+42>: mov %eax,(%esp)
0x40137b <main+45>: call 0x401334 <swap>
0x401380 <main+50>: mov 0x18(%esp),%eax
0x401384 <main+54>: mov 0x1c(%esp),%edx
0x401388 <main+58>: mov %edx,%ecx
0x40138a <main+60>: sub %eax,%ecx
0x40138c <main+62>: mov %ecx,%eax
0x40138e <main+64>: leave
0x40138f <main+65>: ret
swap函数的反汇编代码
(gdb) x /20i 0x401334
0x401334 <swap>: push %ebp
0x401335 <swap+1>: mov %esp,%ebp
0x401337 <swap+3>: sub $0x10,%esp
0x40133a <swap+6>: mov 0x8(%ebp),%eax
0x40133d <swap+9>: mov %eax,-0x4(%ebp)
0x401340 <swap+12>: mov 0xc(%ebp),%eax
0x401343 <swap+15>: mov %eax,0x8(%ebp)
0x401346 <swap+18>: mov -0x4(%ebp),%eax
0x401349 <swap+21>: mov %eax,0xc(%ebp)
0x40134c <swap+24>: leave
0x40134d <swap+25>: ret
在执行到call swap函数之前,main函数的esp和ebp的值,以及栈中内容的情况
main函数的sp和ebp
(gdb) info r esp
esp 0x28ff00 0x28ff00
(gdb) info r ebp
ebp 0x28ff28 0x28ff28
main函数栈中的内容,esp是栈顶
0x28ff00: 0x10 0x00 0x00 0x00 0x20 0x00 0x00 0x00
从这里看,esp存放的是a的值,esp+4存放的是b的值,swap函数进行操作的也是这块内存.
那么a,b真正的地址在哪?
main函数里面
(gdb) p /x &a
$1 = 0x28ff1c
(gdb) p /x &b
$2 = 0x28ff18
swap函数里面
(gdb) p /x &a
$2 = 0x28ff00
(gdb) p /x &b
$3 = 0x28ff04
可见swap函数操作的main函数的a,b在栈上的备份,执行完swap函数返回后,这部分栈就被废弃了,而a,b真正所在地的值并没有得到更改.
而swap函数的堆栈在哪?
从0x28fee8到0x28ff00(一个保存的ebp,三个形参,总计16字节),函数的返回地址是属于main函数的堆栈,从0x28ff00-04,这是swap的返回地址刚好是call swap的下一条指令
(gdb) x /32bx 0x28fee8
0x28fee8: 0x08 0xff 0x28 0x00 0xc4 0xff 0x28 0x00
0x28fef0: 0xd5 0x8c 0x47 0x77 0xd2 0x10 0x70 0x9a
0x28fef8: 0x28 0xff 0x28 0x00 0x80 0x13 0x40 0x00
0x28ff00: 0x10 0x00 0x00 0x00 0x20 0x00 0x00 0x00
swap函数的返回地址
0x401380 <main+50>: mov 0x18(%esp),%eax