[Lab1]计算机是怎样工作的
来源:互联网 发布:mac发送文件给iphone 编辑:程序博客网 时间:2024/05/10 08:12
SA12***266 王星
gcc编译过程可以划分为以下四个阶段:
gcc -S -o example.s example.c
同时也可以将预处理之后的文件cpp编译成汇编代码,命令如下:
gcc -x cpp-output -S -o example.s example.cpp
4.链接生成可执行文件,命令如下:
gcc -o example example.o
以上便解释了gcc在将一个源文件编译成可执行文件时所经过的四个主要过程。
接下来便进入到example.s 中看看里面的汇编代码,以此对程序的执行过程有一个印象
现在可以直奔main标记处了,在第27行,可以看到main函数马上就要执行了。
然而突然出现了第28,29,30行的代码,而不是直接从pushl %ebp 开始的,这是一个问题
之后上网查阅之后才发现这是gcc 对代码优化产生的,具体分析过程如下:
leal 4(%esp),%ecx
andl $-16,%esp
pushl -4(%ecx)
在普通的情况下,进入一个函数时的初始堆栈如下:
|arg n|
|arg ...|
|arg 0|
因为gcc中默认的堆栈是16字节对其的,所以此处便会出现
andl $-16,%esp 实则是将esp低4位设为0,从而达到内存对其的目的
leal 4(%esp),%ecx //将ret address的地址加4赋值给ecx
pushl -4(ecx) //将ecx中的地址减4指向的值压栈,实则是将retaddress压栈
此时栈的结构如下
|arg0|
|ret address|
|填充|
|填充|
|ret address|<--esp
以上的疑问解决了,便可以继续下去(此处答案引用了一个未知名作者的文档以及瀚海foxman和xhacker的帖子)
接着是
pushl %ebp
mov %esp,%ebp
其作用时将old ebp压栈,并设置新的ebp,结果如下:
|arg0|
|ret address|
|填充|
|填充|
|ret address|
subl $4,%esp
movl $8,(%esp) 这两句等价于push $8
call f 调用f
至此,程序的栈结构如下:
|arg0|
|ret address|
|填充|
|填充|
|ret address|
|old ebp|
|8|
|ret address1|<--esp
接着进入函数f执行
代码如下:
pushl %ebp
movl %esp,%ebp
subl $4,%esp
movl 8(%ebp),%eax
call g
此时程序的栈结构如下:
|arg0|
|ret address|
|填充|
|填充|
|ret address|
|old ebp|
|8|
|ret address1|
|8|
|ret address2|<--esp
程序进入g
代码如下:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax
addl $3,%eax
popl %ebp
ret
此处的代码执行流程比较明朗,故不多言
只需注意的一点是:返回值存放在eax中
接着函数返回到f中,继续执行,代码如下:
leave
ret
leave的作用包括两点
1.addl $4,%esp 释放f的栈空间
2.popl %ebp 为main恢复ebp
经过ret之后,程序回到了main中:
addl $1,%eax 执行加1的操作
addl $4,%esp 释放main使用的栈
popl %ecx 恢复ecx的值
popl %ebp 恢复ebp
|arg0|
|ret address|<--esp
接着程序执行
ret
程序返回,大致流程就是这样的
系统栈所产生的变化
系统通过栈来保存函数现场,并以argument retaddress ebp的顺序入栈。
实验内容:
example代码见图1:
图1
gcc编译过程可以划分为以下四个阶段:
1.预处理阶段,输出文件为:*.cpp(c preprocess)
2.编译成汇编代码输出文件为:*.s
3.汇编成目标代码输出文件为:*.o
4.链接成可执行文件
下面介绍使用gcc逐步进行以上四个步骤的过程:
1.预处理阶段
结果见图2:
图2
2.编译成汇编代码
gcc -S -o example.s example.c
同时也可以将预处理之后的文件cpp编译成汇编代码,命令如下:
gcc -x cpp-output -S -o example.s example.cpp
结果见图3:
图3
3.汇编成目标代码,命令如下:
gcc -x assembler -c example.s -o example.o结果见图4:
4.链接生成可执行文件,命令如下:
gcc -o example example.o
结果见图5:
图5
以上便解释了gcc在将一个源文件编译成可执行文件时所经过的四个主要过程。
接下来便进入到example.s 中看看里面的汇编代码,以此对程序的执行过程有一个印象
example.s 全部代码见图6:
现在可以直奔main标记处了,在第27行,可以看到main函数马上就要执行了。
然而突然出现了第28,29,30行的代码,而不是直接从pushl %ebp 开始的,这是一个问题
之后上网查阅之后才发现这是gcc 对代码优化产生的,具体分析过程如下:
leal 4(%esp),%ecx
andl $-16,%esp
pushl -4(%ecx)
在普通的情况下,进入一个函数时的初始堆栈如下:
|arg n|
|arg ...|
|arg 0|
|ret address|<--esp
因为gcc中默认的堆栈是16字节对其的,所以此处便会出现
andl $-16,%esp 实则是将esp低4位设为0,从而达到内存对其的目的
leal 4(%esp),%ecx //将ret address的地址加4赋值给ecx
pushl -4(ecx) //将ecx中的地址减4指向的值压栈,实则是将retaddress压栈
此时栈的结构如下
|arg0|
|ret address|
|填充|
|填充|
|ret address|<--esp
以上的疑问解决了,便可以继续下去(此处答案引用了一个未知名作者的文档以及瀚海foxman和xhacker的帖子)
接着是
pushl %ebp
mov %esp,%ebp
其作用时将old ebp压栈,并设置新的ebp,结果如下:
|arg0|
|ret address|
|填充|
|填充|
|ret address|
|old ebp|<--esp
subl $4,%esp
movl $8,(%esp) 这两句等价于push $8
call f 调用f
至此,程序的栈结构如下:
|arg0|
|ret address|
|填充|
|填充|
|ret address|
|old ebp|
|8|
|ret address1|<--esp
接着进入函数f执行
代码如下:
pushl %ebp
movl %esp,%ebp
subl $4,%esp
movl 8(%ebp),%eax
call g
此时程序的栈结构如下:
|arg0|
|ret address|
|填充|
|填充|
|ret address|
|old ebp|
|8|
|ret address1|
|8|
|ret address2|<--esp
程序进入g
代码如下:
pushl %ebp
movl %esp,%ebp
movl 8(%ebp),%eax
addl $3,%eax
popl %ebp
ret
此处的代码执行流程比较明朗,故不多言
只需注意的一点是:返回值存放在eax中
接着函数返回到f中,继续执行,代码如下:
leave
ret
leave的作用包括两点
1.addl $4,%esp 释放f的栈空间
2.popl %ebp 为main恢复ebp
经过ret之后,程序回到了main中:
addl $1,%eax 执行加1的操作
addl $4,%esp 释放main使用的栈
popl %ecx 恢复ecx的值
popl %ebp 恢复ebp
leal -4(%ecx),%esp 恢复esp
|arg0|
|ret address|<--esp
接着程序执行
ret
程序返回,大致流程就是这样的
实验总结
系统栈所产生的变化
系统通过栈来保存函数现场,并以argument retaddress ebp的顺序入栈。
- [Lab1]计算机是怎样工作的
- 计算机是怎样工作的
- 计算机是怎样工作的?
- 计算机是怎样工作的
- 计算机是怎样工作的
- linux 操作系统-lab1计算机怎么工作的?
- 【实验一】计算机是怎样工作的?
- 实验:计算机是怎样工作的?
- lab1:通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
- 【Linux操作系统分析】计算机是怎样工作的
- 【Linux操作系统分析】计算机是怎样工作的
- Linux操作系统实验一:计算机是怎样工作的
- 【Linux操作系统分析】实验一:计算机是怎样工作的
- 计算机是怎样识字的
- Google是怎样工作的
- Internet是怎样工作的
- HTTP是怎样工作的
- HTTP是怎样工作的
- Android模拟器使用SD卡
- Jetty服务器架构及调优
- 汇编基础——常用寄存器及其用途
- 统计32位二进制数中有多少个1
- UVA 10180 Rope Crisis in Ropeland!【判断圆与直线位置】
- [Lab1]计算机是怎样工作的
- svn常用命令
- C语言--第三篇 控制流
- 二分法查找
- MyEclipse中如何关联jar包源代码
- python字符串编码
- non-virtual和virtual
- 关于在VC6.0下网络编程出现的错误unresolved external symbol __imp__closesocket@4
- 类图和对象图的讲解