Linux操作系统实验一:计算机的工作原理

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

SA*****210          胡*


一、实验目的

通过对初级简单程序的逐步分析,了解计算机的基本工作原理,通过分步执行预处理,编译,汇编,链接各步骤,观察各步中生成的文件,并分析.s代码在CPU中的执行过程。


二、实验内容

源代码E.c如代码段1所示,

gcc -E -o E.cpp E.c命令对.c文件进行预处理,生成.cpp文件,如代码段2所示,

gcc -x cpp-output -S -o E.s E.cpp命令对.cpp文件进行汇编,生成E.s汇编文件,如代码段3所示,

gcc -x assembler -c -c  E.s -o E.o命令对.s文件进行处理,生成.o文件

gcc -o E.o命令对.o文件进行处理,生成最后的ELF



三、实验步骤

这是给出的源代码E.c

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

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

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


gcc -E -o E.cpp E.c命令后生的代码如下所示 

# 1 "E.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "E.c"
int g(int x)
{
return x+3;
}


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


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


gcc -x cpp-output -S -o E.s E.cpp命令生成的代码如下所示

每一步命令的作用已详细标示在注释中。

.file"E.c"
.text
.globl g
.typeg, @function
g:
pushl%ebp//将ebp2压栈
movl%esp, %ebp//和上步一起,创建函数g的栈帧,确定ebp3和esp3
movl8(%ebp), %eax//把刚压栈的eip和ebp前的参数,即x=8传到eax寄存器里
addl$3, %eax//eaxl里保存的值加3,即x=8+3=11
popl%ebp//将刚压入栈中的ebp2值弹出到基址寄存器中,即销毁函数g的栈帧
ret//将刚压栈的eip2弹出到eip寄存器中,即继续跳转前的下一条指令
.sizeg, .-g
.globl f
.typef, @function
f:
pushl%ebp//ebp1压栈
movl%esp, %ebp//和上步一起,创建函数f的栈帧,确定ebp2和esp2
subl$4, %esp//esp2下移4位,即在栈顶产生空余的4B空间
movl8(%ebp), %eax//将x的值8存入eax寄存器
movl%eax, (%esp)//将eax中的值x=8存进栈顶空余的4B空间中
callg//将eip2指针压栈,并将函数g的指令地址装入eip寄存器
leave//销毁f函数栈帧中的所有内容,即销毁保存8的空间,并弹出ebp1
ret//弹出eip1返回eip寄存器
.sizef, .-f.globl main
.typemain, @functionmain:
leal4(%esp), %ecx//将最初的esp0加4后保存在ecx寄存器中
andl$-16, %esp//将esp中的内容与-16按位与
pushl-4(%ecx)//将esp0的值压栈
pushl%ebp//将ebp0的值压栈
movl%esp, %ebp//和上步一起,建立main函数的栈帧,确定ebp1和esp1
pushl%ecx//ecx寄存器中的值压栈
subl$4, %esp//esp指针下移4位,栈顶空出4B
movl$8, (%esp)//将立即数8存入空闲的4B位置中
callf//调用函数f,即将现在的eip1压栈,并进入f函数区的代码
addl$1, %eax//eax寄存器中的值加1
addl$4, %esp//esp指针上移4位,即撤销栈顶的4B
popl%ecx//将原先压栈的ecx寄存器中的值弹回ecx寄存器
popl%ebp//将原先保存的ebp0弹回机制寄存器
leal-4(%ecx), %esp//esp回到原先esp0的位置
ret//将之前压栈的eip0弹出到eip寄存器,一切回到原点
.sizemain, .-main
.ident"GCC: (GNU) 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"
.section.note.GNU-stack,"",@progbits

用框图表示程序执行期间,栈区和寄存器的变化如下所示:


首先是main函数部分

Linux操作系统实验一:计算机的工作原理

Linux操作系统实验一:计算机的工作原理

Linux操作系统实验一:计算机的工作原理

Linux操作系统实验一:计算机的工作原理


然后是f函数部分

Linux操作系统实验一:计算机的工作原理


g函数部分

Linux操作系统实验一:计算机的工作原理

调用结束,进入返回部分

Linux操作系统实验一:计算机的工作原理


四、实验总结

通过以上实验可以得出,最简单的计算机原理图如下所示

Linux操作系统实验一:计算机的工作原理

由于本实验只是最基本的单任务程序,所以我在这里暂且只分析单任务模型的运行情况:

CPU中有若干寄存器,如eip,esp,ebp,eax,ebx,ecx等。

其中eip保存下一条命令所在的地址,esp保存当前程序栈帧的栈顶地址,ebp保存程序栈帧的基地址。eip指向保存代码段的cs部分,esp和ebp指向保存数据的ss部分,而eax,ebx,ecx等通用寄存器用来保存一些临时变量。

可以看出,计算机为每一个函数均分配一个栈帧用来执行各函数。这表现在汇编代码中,每一个函数的代码均被开头的pushl %ebp;movl %esp,%ebp;结尾的popl %ebp;ret包裹。这几行代码起到的作用是开始的保存初始基址指针,并让当前的基址指针指向栈顶,即开始一个新的栈帧。后两行代码的意思是恢复原先的基址指针和eip,即销毁之前最后开辟的栈帧,恢复上一个栈帧的环境。

由此可见,call func命令将当前eip压栈,ret将之前压栈的eip弹出,leave销毁当前栈帧。通过循环调用,计算机不断的保护现场,创建新栈帧,直到最里层的函数执行完毕后,一层层返回,不断销毁新创建的栈帧,直到最后回复到初始状态。并将保存在通用寄存器中的运算结果返回,完成程序功能。