实践!C语言是怎么变成汇编的
2015-03-08 19:09
204 查看
“郭孟琦 + 原创作品转载请注明CSDN博客 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”
在大学计算机组成原理一课中学习各种汇编语言跟C语言的关系,同时在单片机接口技术中也学习了C51的汇编语言,在一些MCU调试中也看到了反汇编的内容。但是从来没亲自实践一下C语言是怎么变成汇编的过程以及他们之间的对应关系。作为作业今天就在这里写下我的发现吧。
按照要求这是一段很简单的c语言程序
![](https://img-blog.csdn.net/20150308192331915?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb0NvcmVDb2Rl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
进行编译生成汇编文件
![](https://img-blog.csdn.net/20150308192300607?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb0NvcmVDb2Rl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
生成的main.s文件 已经把多余的命令删除了(gvim好像确实没vim好用。。。)
![](https://img-blog.csdn.net/20150308192447529?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvb0NvcmVDb2Rl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
一开始是这样的 空栈
程序从main标签处运行,开始push,mov后(我用ebp!和esp!来表示实际的ebp esp所指向的位置吧,表示起来好麻烦 ebp(main)是指向0那个位置的ebp 就是表格最上边那个位置)
到了subl esp减4 向下移动一个字节 并且把立即数233存到了esp指向的位置(间接寻址?)
当执行call f时 eip会被push
接下来看f标签
在push 和movl后 ebp(f)是指向第二行那个ebp
同样esp在减4后向下移动1个地址
接下来因为栈空间向下生长,变址寻址向上加8也就是向上2个位置(就是233)存入eax
接下来要把eax的内容存入esp指向的位置就成了
又一次的Call
进入g标签,前两句类似(其实就是存储原来ebp的位置将ebp指向新的位置),变址寻址向上加8也就是向上2个位置(就是233)存入eax
然后666加上eax里的内容也就是c语言中的 “x +666”啦 到这里函数的嵌套总算是完事了开始一层层恢复,首先是popl ebp,ebp指向f 中的ebp位置了 同时 esp也会加4向上移动
然后ret相当于 pop eip程序回到 刚才 eip(f)的那个位置啦
leave实际上是
mov %ebp %esp
pop %ebp
也就是将上一级的栈恢复回来(有个问题为什么在g里没有leave? 我认为popl %ebp就ok了 因为当时后序操作并未改变esp,esp和ebp指向同一位置 就没必要mov %ebp %esp 了可能就被优化掉了。)
要注意mov后pop操作又再一次改变了esp指向的位置
我们继续走ret
别忘了结果一直在存着eax,现在再加1 就是c语言里 的f(233)+1
最后leave恢复之前的 ebp和esp
跟刚开始是不是一样了!
那么到现在为止,计算机是如何工作的?
我认为计算机的工作方式就是执行一系列指令,在其中当我们只用高级语言中的“函数调用”等需要跳转时计算机总会先保存现在的状态然后再处理完成后再依次恢复之前的状态,同时需要“带回去”的数据另存在其他地方比如:eax。此外我终于明白为什么C语言只能有一个返回值了。。。。
在大学计算机组成原理一课中学习各种汇编语言跟C语言的关系,同时在单片机接口技术中也学习了C51的汇编语言,在一些MCU调试中也看到了反汇编的内容。但是从来没亲自实践一下C语言是怎么变成汇编的过程以及他们之间的对应关系。作为作业今天就在这里写下我的发现吧。
按照要求这是一段很简单的c语言程序
进行编译生成汇编文件
生成的main.s文件 已经把多余的命令删除了(gvim好像确实没vim好用。。。)
一开始是这样的 空栈
ebp!esp! |
ebp!esp!ebp(main) |
ebp!ebp(main) |
esp! 233 |
ebp!ebp(main) |
233 |
esp!eip(main) |
在push 和movl后 ebp(f)是指向第二行那个ebp
ebp(main) |
233 |
eip(main) |
esp!ebp!ebp(f) |
ebp(main) |
233 |
eip(main) |
ebp!ebp(f) |
esp! |
接下来要把eax的内容存入esp指向的位置就成了
ebp(main) |
233 |
eip(main) |
ebp!ebp(f) |
esp!233 |
ebp(main) |
233 |
eip(main) |
ebp!ebp(f) |
233 |
esp!eip(f) |
ebp(main) |
233 |
eip(main) |
ebp(f) |
233 |
eip(f) |
ebp!esp!ebp(g) |
ebp(main) |
233 |
eip(main) |
ebp!ebp(f) |
233 |
esp!eip(f) |
ebp(g) |
ebp(main) |
233 |
eip(main) |
ebp!ebp(f) |
esp!233 |
eip(f) |
ebp(g) |
mov %ebp %esp
pop %ebp
也就是将上一级的栈恢复回来(有个问题为什么在g里没有leave? 我认为popl %ebp就ok了 因为当时后序操作并未改变esp,esp和ebp指向同一位置 就没必要mov %ebp %esp 了可能就被优化掉了。)
要注意mov后pop操作又再一次改变了esp指向的位置
ebp!ebp(main) |
233 |
esp!eip(main) |
ebp(f) |
233 |
eip(f) |
ebp(g) |
ebp!ebp(main) |
esp!233 |
eip(main) |
ebp(f) |
233 |
eip(f) |
ebp(g) |
最后leave恢复之前的 ebp和esp
ebp!esp! |
ebp(main) |
233 |
eip(main) |
ebp(f) |
233 |
eip(f) |
ebp(g) |
那么到现在为止,计算机是如何工作的?
我认为计算机的工作方式就是执行一系列指令,在其中当我们只用高级语言中的“函数调用”等需要跳转时计算机总会先保存现在的状态然后再处理完成后再依次恢复之前的状态,同时需要“带回去”的数据另存在其他地方比如:eax。此外我终于明白为什么C语言只能有一个返回值了。。。。
相关文章推荐
- 源程序怎么变成可执行文件—学C语言难免碰到的困惑
- 我们拿计算机来拆,去研究里头有什么,把核心的软件剖析一下,怎么写的,这样我就会Basce汇编语言了,我就可以去讲Basce和汇编的课了。为研究计算机怎么上显示器,我就去研究,当时我们的那台显示器
- 怎么就变成写流水账了?
- 汇编语言与C语言的混合使用
- C语言与汇编语言的相互调用
- 把一行文字内多余的文字变成...的css怎么写?
- 汇编语言和C语言的混合编程
- 昏昏昏昏昏昏,怎么变成这样了。:-(
- C语言嵌入汇编实现音乐发声器
- c语言的实践技巧
- 汇编怎么嵌套进vc或者tc
- 流川枫是怎么变成唐僧的
- 汇编语言与C语言的混合使用
- c语言与汇编的混合编程代码
- C语言复杂类型声明怎么理解?
- 汇编怎么嵌套进vc或者tc
- 怎么把工资从400变成40000的!
- 编译一个汇编程序怎么居然折腾我如此....
- 唉,领了工资总是拿去花.真是不得了!怎么会变成这样?
- C语言中怎么把Int型转成字符型