- 论坛徽章:
- 0
|
本帖最后由 liwangli1983 于 2010-12-07 14:30 编辑
0x08048354 <main+0>: lea 0x4(%esp),%ecx
0x08048358 <main+4>: and $0xfffffff0,%esp ##让栈指针按16字节对齐
0x0804835b <main+7>: pushl -0x4(%ecx) ##返回地址入栈
0x0804835e <main+10>: push %ebp ##保存栈帧指针值
0x0804835f <main+11>: mov %esp,%ebp ##栈帧指针指向栈指针指向的位置
0x08048361 <main+13>: push %ecx ##ecx入栈
0x08048362 <main+14>: mov $0x0,%eax ##将main的返回值放入eax
0x08048367 <main+19>: pop %ecx ##ecx出栈
0x08048368 <main+20>: pop %ebp ##恢复栈帧指针值
0x08048369 <main+21>: lea -0x4(%ecx),%esp ##恢复原栈指针值
0x0804836c <main+24>: ret ##返回(ret会自动把esp指向的位置的内容复制到pc中.因为此时esp指向<main+7>时入栈的返回地址,所以此句返回)
大部分普通函数基本上都是从push %ebp开始的.这里两次把返回地址入栈(第一次是调用main的程序入的,就放在刚刚进入main过程时esp指向的位置),第二次大约是因为对栈指针取16字节对齐可能导致栈指针变化,所以重新入栈一次返回地址,再像正常子过程那样把ebp入栈.这样在程序末尾pop %ebp后,%esp就自然指向返回地址了,否则esp指向的内容是不确定的.
如果可能最好把<C语言标准与实现>啃下来,很硬的书,通篇汇编和各种类型数值的分析,看着很容易犯困。但内容确实很不错,认真看下来收获不小。 |
|