Linux操作系统实验一:计算机是怎样工作的

时间:2023-01-16 20:53:20

姓名: 张泽尧    学号:SA12226383

实验环境:Win7下虚拟机VMware,虚拟机系统Ubuntu12.04。

实验内容:通过分析汇编代码在CPU上的执行过程来分析单任务计算机是如何工作的。

实验步骤:

一、编写编译测试代码example.c。

example.c代码如下:

#include <stdio.h>

int g(int x) {
return x+3;
}

int f(int x) {
return g(x);
}

int main() {
return f(8)+1;
}

编译:

Linux操作系统实验一:计算机是怎样工作的

二、分析汇编代码

输入命令gdb example,进入调试模式,用disas命令查看汇编代码。

Linux操作系统实验一:计算机是怎样工作的


Linux操作系统实验一:计算机是怎样工作的


Linux操作系统实验一:计算机是怎样工作的


1、从main函数开始执行,main函数首地址 0x080483d2 ,先把原%ebp指针压入栈内保存起来,以便main函数执行完返回。再使%ebp指向%esp,即原函数的栈顶,新函数(此处即main函数)的栈底。

   0x080483d2 <+0>: push   %ebp
   0x080483d3 <+1>: mov    %esp,%ebp

2、下移栈顶指针(栈开辟控件按照满递减的规则),为局部变量准备空间,再将值8放入刚才预留的栈空间,作为调用函数f的参数。再调用函数f,此处的call相当于如下步骤:1、把%eip中保存的下一条指令地址0x080483e4压入栈中保存,这样从f返回的时候能找到这个地址。2、把函数f的首地址0x80483bf放入%eip寄存器,这样下面CPU从%eip中获取指令地址开始执行f函数。

   0x080483d5 <+3>: sub    $0x4,%esp
   0x080483d8 <+6>: movl   $0x8,(%esp)

   0x080483df <+13>: call   0x80483bf <f>

3、进入f函数,和第一步相同,将原%ebp压入栈保存起来,再使%ebp指向新函数的栈底。下移%esp开辟栈空间,通过0x8(%ebp)取得参数,即第二步中存入的8,放入%eax,再把值放入刚才开辟的栈空间,作为下面调用函数g的参数,最后通过call调用函数g,具体如第二步的分析,通过%eip实现。

   0x080483bf <+0>: push   %ebp
   0x080483c0 <+1>: mov    %esp,%ebp
   0x080483c2 <+3>: sub    $0x4,%esp
   0x080483c5 <+6>: mov    0x8(%ebp),%eax
   0x080483c8 <+9>: mov    %eax,(%esp)
   0x080483cb <+12>: call   0x80483b4 <g>

4、进入函数g,和前面相同,保存旧的%ebp,设置%ebp指向新的栈底,通过0x8(%ebp)获取第三步存入栈的参数8,放入%eax寄存器,将其加3存入%eax,作为返回值。把之前存入栈的旧%ebp,即上一级函数的栈底地址pop出来赋给%ebp,再ret,即把第3步压入栈的%eip弹出给%eip,CPU读取%eip进入到函数f内执行f内callg后面那条语句,即leave

   0x080483b4 <+0>: push   %ebp
   0x080483b5 <+1>: mov    %esp,%ebp
   0x080483b7 <+3>: mov    0x8(%ebp),%eax
   0x080483ba <+6>: add    $0x3,%eax
   0x080483bd <+9>: pop    %ebp
   0x080483be <+10>: ret 


5、如第4步所说,CPU开始执行函数f的leave,相当于mov  %ebp,%esp;  pop %ebp,恢复栈指针,再ret,如上分析返回main函数,CPU开始执行main函数call调用下面的那句指令。

   0x080483d0 <+17>: leave  
   0x080483d1 <+18>: ret 

6、由第四步所说,返回值保存在%eax,这里将%eax中的返回值加1得到最终的结果依然保存在%eax,执行leave,恢复栈指针,执行ret返回上一级函数。

   0x080483e4 <+18>: add    $0x1,%eax
   0x080483e7 <+21>: leave  
   0x080483e8 <+22>: ret 


如上整个程序的执行流程。


实验总结:

如上分析单任务计算机中程序执行在调用函数及返回大底过程如下:

1、call调用函数,把%eip中存的下一条指令地址换成被调用函数首地址,并把原地址压入栈中;

2、push %ebp,move %esp, %ebp开辟新函数运行的栈空间,参数从栈中获取,执行完后把返回值放入%eax,上一级函数可以通过%eax获得返回值;

3、leave,释放栈空间;

4、ret,把第一步存入栈中的下一条指令地址pop出来放入%eip,CPU读取。


单任务计算机一次只能执行一个任务,若因为请求某资源而*中断时CPU进入空闲状态,使用效率低。

多任务计算机可以在多个任务之间进行调度,使CPU保持工作状态,使用效率高。

从main函数开始执行,main函数首地址 0x080483d2 ,