1.问题描述
众所周知,计算机是20世纪最伟大的发明之一,计算机是如何工作的呢?本文主要通过计算机的组成结构和工作原理,以及汇编代码工作过程来进行详细叙述。
2.解决过程
2.1 冯·诺依曼体系结构
一般来讲,现代计算机结构依据冯·诺依曼结构体系,该结构也成普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。主要由运算器、控制器、存储器、输入设备和输出设备五大部件构成,其中运算器,控制器和部分寄存器合并也称为CPU,整个体系采用二进制逻辑运算,即0/1编码。结构示意图如下所示:
引用链接:计算机系统
2.2 计算机工作原理
计算机运行的基础是CPU,CPU中主要包括算数逻辑单元ALU,程序计数器PC,指令寄存器IR,数据寄存器DR,地址寄存器AR等。CPU内部结构如下图所示:
几乎所有的冯·诺依曼型计算机的CPU执行指令都可以进行5个阶段:取指,译码,访存,执行和写回。
2.2.1 取指
取指令阶段,是将指令从主存中取出到指令寄存器IR的过程,同时程序寄存器PC中的值会指向当前执行指令的下一条指令地址。
2.2.2 译码
取出指令后,指令译码器根据指令的格式,对取出的指令进行拆分和解析,获取不同的操作方法。
2.2.3 访存
根据指令内容,可能会再次根据指令中地址访问主存,读取操作数,用于操作运算。
2.2.4 执行
在取指和取数结束后,根据指令的操作码,会进行一系列不同的操作。
2.2.5 写回
指令执行结束后,会把数据以写回的存储到内部寄存器中或外部存储空间中。
指令执行过程如下图所示:
引用链接:计算机组成原理
2.3 汇编代码的简易工作过程
汇编语言(assembly language)是一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。在汇编语言中,用助记符代替机器指令的操作码,用地址符号或标号代替指令或操作数的地址。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过汇编过程转换成机器指令。
引用链接:汇编语言
接下来将通过汇编一个简单的C语言程序并分析其汇编指令执行过程。
2.3.1 C语言程序
使用vim编辑器编辑mian.c程序,内容如下代码:
int g(int x)
{
return x + 5;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(10) + 2;
}
在实验楼环境中,通过gcc命令编译和执行main.c程序,命令执行代码如下:
#编译C语言代码文件
gcc main.c
#执行a.out可执行文件
./a.out
#输出程序返回值
echo $?
运行程序结果如下图所示:
2.3.2 汇编文件
通过gcc命令将c语言程序文件转化为一个汇编文件main.s,并vim编辑器处理和读取汇编代码,具体操作如下:
#将c语言程序编译为main.s汇编文件
gcc –S –o main.s main.c -m32
#用vi方式打开汇编文件
vi main.s
#在命令模式下取除"."开头的辅助信息
g/\.s*/d
汇编语言显示如下:
2.4 汇编代码的工作栈分析
栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素,栈的最大特点是先进后出。
引用链接:栈
在汇编语言执行过程中,指令和数据等会寄存在以栈未主要形式的寄存器里。32位的8086CPU中,主要由两个指针寄存器ESP和EBP,以及一个常用的数据寄存器EAX。
其中ESP堆栈指针寄存器,用于存放指向系统栈最上面一个栈帧的栈顶,EBP基指针寄存器,用于存放指向系统栈最上面一个栈帧的栈底。通俗地讲在函数调用前,EBP的值会传入栈,ESP存储栈顶地址,然后ESP会把值传给EBP;在函数调用结束后,EBP会把值传回ESP,ESP又指向栈顶地址。本例中建设堆栈空间单元号向下增长,地址向下减小,一个存储单元未4个字节32位,初始状态下,EBP和ESP指针均指向标号为0的初始位置(2000),如下图所示:
下面来分析一下上一小节中main.s各行汇编语言执行过程中,堆栈空间的变化情况:
2.4.1 main函数执行过程
程序先执行18-22行,然后调用f函数。
pushl %ebp
此代码执行后,ESP寄存器将会指向单元号1,然后EBP寄存器的值(地址2000)会存储到堆栈标号1的位置。
movl %esp, %ebp
此代码执行后,EBP寄存器将会指向单元号1。subl $4, %esp
。
movl $10, (%esp)
此代码执行后,立即数10会被存入ESP寄存器指向的2号存储单元。
call f
此代码执行后,ESP寄存器指向下一存储单元,EIP寄存器行号23(运行call f汇编指令的文件行号的下一行)存入3号存储空间,同时EIP寄存器指向f函数的第一条指令行号9。
2.4.2 f函数执行过程
pushl %ebp
movl %esp, %ebp
此代码执行后,ESP寄存器先指向下一存储单元4,然后将EBP寄存器的值存入存储单元4号,然后将EBP指向与ESP相同的地址。
subl $4, %esp
movl 8(%ebp), %eax
此代码执行后,ESP寄存器先指向下一个存储单元5,然后将EBP上移8个地址位置的存储单元2中值存入EAX寄存器,注意此处EBP寄存器指针实际未改变。
movl %eax, (%esp)
此代码执行后,将EAX寄存器中数值存入ESP寄存器所指向的位置,即存储单元5。
call g
此代码执行后,ESP寄存器指向下一存储单元,EIP寄存器行号15(运行call g汇编指令的文件行号的下一行)存入6号存储空间,同时EIP寄存器指向f函数的第一条指令行号2。
2.4.3 g函数执行过程
pushl %ebp
movl %esp, %ebp
此代码执行后,ESP寄存器先指向下一存储单元7,然后将EBP寄存器的值存入存储单元7号,然后将EBP指向与ESP相同的地址。
movl 8(%ebp), %eax
addl $5, %eax
此代码执行后,将EBP寄存器指向位置上移8个位置所在存储单元中的立即数10存入EAX寄存器中,再把立即数5加入寄存器EAX,得到EAX寄存器存储值15。
popl %ebp
ret
此代码执行后,EBP寄存器转回ESP寄存器指向存储单元7中的内容,即恢复函数f的函数调用堆栈基址EBP寄存器,ESP寄存器指向存贮单元6,然后将ESP指向存储单元6的内容15放到EIP寄存器中,ESP寄存器进一步向上移动4个地址指向存储单元5,EIP下一步执行第15行leave指令。
2.4.4 f函数返回过程
leave
此代码执行后,ESP寄存器先指向EBP相同存储单元4,然后将EBP寄存器将跳转至当前存储单元内容所指向的存储单元1,然后将ESP将再向上移动4个地址指向存储单元3。
ret
此代码执行后,ESP寄存器指向内容32将写入EIP,下一步程序跳转值第23行执行addl指令,同时ESP向上移动4个地址。
2.4.5 main函数返回过程
addl $2, %eax
此代码执行后,将立即数$2加入EAX寄存器,然后返回函数值。
leave
ret
此代码执行后,ESP寄存器指向EBP寄存器指向的地址,EBP寄存器根据存储单元1内容跳转至初始地址(2000),然后ESP寄存器基址也向上加4个地址来到初始地址(2000)。
3.总结
本文主要学习了计算机冯·诺依曼体系结构、计算机CPU工作原理以及汇编语言执行过程中堆栈的变化情况,冯·诺依曼体系结构作为当前主流的计算机体系结构,一直沿用至今。早期的冯·诺依曼体系结构是以运算器为中心的,但是由于运算器和控制器集成技术的提高和存储容量的扩大,现在主要以存储器为中心。计算机CPU工作原理涉及指令的操作,以及相关硬件数据流的输入和输出,在之前基础课程计算机组成原理有过一定学习。堆栈的变化可以通过汇编语言来解读,汇编语言位于机器语言上一层,能够较为清洗地描述计算机内部硬件之间的信息交互和数据转存过程,通过这次学习,我对其中的堆栈结构以及ESP和EBP两个指针寄存器留下了深刻的印象。学习较为抽象的知识,可以借鉴灵活的模型和图表来形象演绎,可以提高学习效率。