姓名: 张泽尧 学号: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;
}
编译:
二、分析汇编代码
输入命令gdb example,进入调试模式,用disas命令查看汇编代码。
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 ,