陈绍斌 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
=。=第一次弄博客,完全不会啊。请务必指导我。
C程序代码:
int g(int x) { return x + 3; } int f(int x) { return g(x); } int main(void) { return f(4) + 1; }
编译环境:
Ubuntu 14.04,GCC 4.8,GDB 7.7 因为是64位的环境,所以和32位的寄存器名和一些操作有所区别。。。
编译命令:
gcc -o main -g main.c
生成目标文件和调试信息
启动GDB:
gdb ./main
列出源码:
layout src
l
列出汇编指令:
Ctrl + x,再按2,
显示汇编指令
:
依次分析汇编指令:
1. 0x400513 <main> push %rbp 将main函数栈底rbp内存地址压栈
2. 0x400514 <main+1> mov %rsp,%rbp 将栈底指向栈顶(相当于新建一个栈)
3. 0x400517 <main+4> mov $0x4,%edi 将数值4存入寄存器edi
4. 0x40051c <main+9> callq 0x4004fc <f> 跳转到函数f
2. 0x400514 <main+1> mov %rsp,%rbp 将栈底指向栈顶(相当于新建一个栈)
3. 0x400517 <main+4> mov $0x4,%edi 将数值4存入寄存器edi
4. 0x40051c <main+9> callq 0x4004fc <f> 跳转到函数f
5. 0x4004fc <f> push %rbp 将函数f栈底内存地址压栈
6. 0x4004fd <f+1> mov %rsp,%rbp 将函数f栈底指向栈顶(相当于新建一个栈)
7. 0x400500 <f+4> sub $0x8,%rsp 将栈顶内存地址值减8
8. 0x400504 <f+8> mov %edi,-0x4(%rbp) (为什么是减4) int是32位缘故?
9. 0x400507 <f+11> mov -0x4(%rbp),%eax 上面两步实现将数值4写入寄存器eax
10. 0x40050a <f+14> mov %eax,%edi 将eax中存储的数值4写入寄存器edi
11. 0x40050c <f+16> callq 0x4004ed <g> 跳转到函数g
8. 0x400504 <f+8> mov %edi,-0x4(%rbp) (为什么是减4) int是32位缘故?
9. 0x400507 <f+11> mov -0x4(%rbp),%eax 上面两步实现将数值4写入寄存器eax
10. 0x40050a <f+14> mov %eax,%edi 将eax中存储的数值4写入寄存器edi
11. 0x40050c <f+16> callq 0x4004ed <g> 跳转到函数g
12. 0x4004ed <g> push %rbp 将函数g栈底内存地址压栈
13. 0x4004ee <g+1> mov %rsp,%rbp 将函数g栈底指向栈顶(相当于新建一个栈)
14. 0x4004f1 <g+4> mov %edi,-0x4(%rbp)
15. 0x4004f4 <g+7> mov -0x4(%rbp),%eax 上面两步实现将数值4写入寄存器eax
15. 0x4004f4 <g+7> mov -0x4(%rbp),%eax 上面两步实现将数值4写入寄存器eax
16. 0x4004f7 <g+10> add $0x3,%eax 寄存器eax加3
17. 0x4004fa <g+13> pop %rbp 出栈
18. 0x4004fb <g+14> retq 返回,栈顶地址写入eip
17. 0x4004fa <g+13> pop %rbp 出栈
18. 0x4004fb <g+14> retq 返回,栈顶地址写入eip
19. 0x400511 <f+21> leaveq rsp指向栈底,rbp出栈
20. 0x400512 <f+22> retq 返回
20. 0x400512 <f+22> retq 返回
21. 0x400521 <main+14> add $0x1,%eax 寄存器eax加3
22. 0x400524 <main+17> pop %rbp 出栈
23. 0x400525 <main+18> retq 返回
22. 0x400524 <main+17> pop %rbp 出栈
23. 0x400525 <main+18> retq 返回
体会:
应该把栈画出来,把操作用gif动图形式表现出来才直观啊= =。。。文字叙述到自己都快混乱了- -。。。
个人理解是进行函数调用时,把当前执行的指令的下一条地址压栈,再把旧函数的栈底移向栈顶,把调用函数的入口写入栈中。