计算机是怎样工作的

              计算机是怎样工作的

本文是菜鸟借助于对C程序的执行过程,以及对反汇编代码的分析来描述计算机是如何工作的,本文不考虑中断,一些异常情况。如果本文分析中有错误,望老师,同学批评指正,菜鸟将不甚感激!

实验内容:

通过对example.c程序的分析,将example.c代码分别生成example.cpp、example.s、example.o以及可执行的ELF文件,并且加载运行,并分析example.s汇编代码的执行过程。

实验目的:

通过本次实验解释分析,单任务计算机是怎样工作的,并在此基础上讨论多任务计算机是怎样工作的。

实验环境:

Ubuntu13.04, Gcc, Gdb, oracle VM virtualBox

实验过程: 

1、example.c程序的源代码如下

2、  对example.c程序进行预处理,生成example.cpp程序,然后将example.cpp程序编译成汇编程序example.s,然后将生成的example.s程序,编译成二进制example.o的目标程序,最后通过链接器生成example这个可执行文件

(1)、编写makefile

(2)、make之后生成的预编译文件,汇编文件,目标文件,可执行文件如下:

(3)、用cat example.s查看汇编代码不清楚,这里我使用gdb中的disas反汇编查看。

操作如下:gdb example

disas main   //查看main()函数对应的汇编程序代码

disas f      //查看f()函数对应的汇编程序代码

disas g     //查看g()函数对应的汇编程序代码

main()函数反汇编代码如下:

f()函数的反汇编代码如下:

g()函数的反汇编代码如下:

3、对整个程序的汇编代码进行分析

(1)   、浅谈汇编程序中子函数调用相关的指令

每一个函数在内存空间中以栈的形式存储,对于堆栈而言有两个十分重要的指针,一个是堆栈的基址指针ebp,另一个是栈顶指针esp。

汇编程序中,调用子函数过程中所用的几条重要指令的介绍

1、入栈/出栈指令

Pushl  p  等价于以下两条指令: subl  $4, %esp

movl p, (%esp)

Popl  p   等价于以下两条指令:movl (%esp), p

add $4, %esp

2、 转移控制指令

call  子函数的调用指令

例如:call f(),等价于执行,两个操作,先将call f()指令后面的下一条指令的地址入栈,然后再将f()函数的地址赋值给ip,然后开始执行子程序。

call  0x800300 等价于pushl  %eip     //下一条指令的地址

movl  $0x800300, %eip //子程序入口地址给eip

ret  子函数的调用返回指令.ret 指令用于子函数的调用返回,等价于popl %eip     //eip指向子函数调用前下一条指令的地址。

Leave 释放栈操作,等价于:

Movl  %ebp, %esp

Popl   %ebp

(2)、对整个程序的汇编代码结合相应的栈操作进行深入分析

在没有执行main()函数前,栈的形式为:

执行main()函数时:

Push  %ebp  将main()函数执行前较早帧的ebp压入main()函数的栈帧中

Mov  %esp,%ebp 将基址指针赋值给栈顶指针,相关栈操作如下:

Sub $0x4, % esp 执行后栈的变化为:

Movl  $0x8 , (%esp) 将8写入esp所指的内存单元中。

Call  0x800483f7 <f> 执行后,栈的变化情况如下:

注意返回地址为addl指令的地址,实质是将下一条指令的%eip入栈

Push %ebp  将main()函数的栈帧的基址指针入栈

Mov  %esp ,%ebp 将基址指针的值赋值给栈顶指针,f()函数栈帧变化为:

Subl  $4, %esp   执行后f()栈帧的变化为:

Movl  8(%ebp), %eax

这条指令,将ebp+8所指地址里面的值,赋值给寄存器%eax,执行玩这个程序后,%eax里面的值为8.

Movl %eax, (%esp)  这条指令将%eax的值存入%esp指针所指的单元中

Call 0x80483ec <g> 执行后栈的变化情况为:

返回地址为call下面语句leave指令的%eip地址,将其入栈保护现场。

Push  %ebp   将f()函数所处栈帧的基址指针入栈,栈的变化为:

Mov %esp ,%ebp 指令执行完后,栈的变化为:

 

Movl  8(%ebp),  %eax ,这条指令,是将%ebp+8指针所指内容的值赋给%eax寄存器,执行该指令后%eax里面的值为8.

Add $0x3, %eax  该指令执行完后,%eax寄存器里面的值为11

Pop %ebp 该指令,执行后,栈的变化为:

ret 指令执行结束,对应的操作是pop %eip 对应栈的变化为:

Leave 指令,相当于,Movl  %ebp, %esp

Popl   %ebp

执行后栈的变化为:

ret 指令相当于pop %eip , 栈的变化为:

Add  $0x1,%eax这条指令执行后寄存器%eax里面的值为12

Leave 指令执行后,栈的变化为:

ret 指令执行后,栈的变化为:

个人总结:

      1、对这个实验的认识:这个实验,通过在main()函数里调用f()函数,在f()函数里调用   g()函数,通过调用子函数,观察相应栈的变化情况,来明白对于cup内指令的执行情况。

2、对于每一个函数而言,都有这里特定的栈空间,通过%ebp,%esp来执行栈操作,通过leave指令执行,释放栈空间的操作。

3、对于单任务执行的计算机而言,指令是顺序执行,一个指令周期内执行一条指令,通过CPU里门的%eip寄存器不断的从内存中取指令,执行指令。

4、对于多任务执行的计算机而言,指令是并行执行,比如通过流水线技术,在一个指令周期内,执行不同的指令。但是在微观上,多任务执行是基于时间片轮转方法的单任务执行,在某种意义上说,多任务执行,在本质上也是单任务的执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值