Linux内核分析
2016-02-28 14:29 KG35 阅读(354) 评论(0) 编辑 收藏 举报通过分析汇编代码理解计算机是如何工作的
网易云课堂《Linux内核分析》作业
实验目的:
通过反汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
实验过程:
登陆实验楼虚拟机http://www.shiyanlou.com/courses/195
准备main.c源码
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228142906127-379797555.png)
打开终端shell,输入以下命令:
gcc –S –o main.s main.c -m32
生成汇编代码main.s
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228142918674-703054282.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228142933034-1894116887.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228142945596-624799546.png)
精简后的汇编代码
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228142957080-220420857.png)
实验分析:
先看C语言代码,该程序由3个函数组成,分别是main()、f()、g(),实现了2+7+5的简单数学计算。
程序首先从main()开始,将数字2传入f(),f()又将main()传入的数字2原封不动的传给g(),g()实现了将传入2加5的操作,结果7返回给f(),f()获得7后直接返回给main(),mian()将获得的7加7后返回最终结果14.
理论上编译后的汇编语言也应该实现上述功能,即计算2+5+7值。
下面我们来分析精简后的汇编代码:
左边代码行标表示eip,红框表示当前运行的代码,eax初始化为未知变量,右边蓝色格子表示内存段,为简化描述在32位环境下1个内存单元格表示4byte,ebp和esp初始值均为0
程序从main开始
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143016643-461817337.png)
将ebp压栈,相当于执行以下两条语句:
subl $4, %esp //esp减4byte,向下移动1格,此时esp指向1
movl %ebp, (%esp) //将ebp的值存入esp指向的存储单元内
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143044565-81567488.png)
将esp的值赋值给ebp,即ebp也指向1
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143107143-1182291837.png)
将esp的值减4,即esp向下移动1格,此时esp指向2
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143119487-848334406.png)
将数字2存入esp指向的内存块
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143131893-673237514.png)
调用f,相当于执行以下两条语句:
pushl %eip
move f, %eip
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143147159-9548874.png)
call f执行完后的状态,此时程序完成由main跳转到f
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143227127-1522894959.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143310659-1131678088.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143323752-1227842383.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143342862-941457707.png)
该条指令将ebp-8的位置,即标号为2的内存单元所存放的数字2赋值给eax,此时eax等于2
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143406112-1994325458.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143425221-2007309833.png)
跳转到g
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143441627-994719337.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143456393-1721851719.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143509143-1737243580.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143525237-47005473.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143539440-1149476397.png)
将eax的值加5后再存入eax,此时eax等于7
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143620455-1048297377.png)
出栈操作,相当于以下两条语句:
movl (%esp), %ebp
addl $4, %esp
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143641424-256557107.png)
ret相当于执行以下语句:
popl %eip
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143703737-188922722.png)
leave相当于执行以下两条语句:
movl %ebp, %esp
popl %ebp
g没有leave指令语句的原因是它没有再调用其他函数
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143717643-1356262908.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143736002-1205964037.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143751080-2037590465.png)
将数字7累加到eax,此时eax等于14
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143840877-1483404185.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143824330-856609336.png)
![](https://images2015.cnblogs.com/blog/745807/201602/745807-20160228143905174-1074553725.png)
至此整个程序完成了所有操作,结果存放在eax,即14为最终计算结果,与C语言代码一致。
实验总结:
计算机有一套规则来控制程序运行,在C语言和汇编语言中,CPU从程序main函数所在的内存地址开始做取指操作,根据当前状态和输入计算出新值,并且进入一个新的状态,同时改变寄存器所存储的数值。
参考:计算机实际上是如何工作的