您的位置:首页 > 理论基础

计算机是如何工作的?--通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

2017-02-16 21:59 856 查看
王雪 原创作品转载请注明出处 《Linux内核分析》MOOC课程 http://mooc.study.163.com/course/USTC-1000029000

一、理论基础

(1)冯诺依曼体系结构:存储程序计算机的工作模型



从硬件角度看程序的执行过程:其中IP(instruction pointer)为CPU中的寄存器,指向内存中的某一块,CPU执行指令时,会从IP中取出一条指令后执行,执行过后,IP自加一(增加一个指令的长度),取下一条指令执行。

从程序员的角度看: CPU是一个大的for循环,不停地执行next instruction命令,存储器主要负责数据和代码等信息的存储,CPU与Main Memory通过总线进行连接。

注意:

1.程序员不可以直接修改IP的值,只能通过一些指令,如CALL、RET、JMP等间接修改IP的值

2.IP在32位机器中表示为eip(本次实验以32位作为分析),在64位机器中表示为rip。

(2)x86汇编基础知识(32位机器)

一.寄存器:在x86体系中,寄存器可分为通用寄存器、段寄存器、标志寄存器

1通用寄存器:

EAX:累加器

EBX:基地址寄存器

ECX:计数寄存器

EDX:数据寄存器

EBP:堆栈基指针

ESI,EDI:变址寄存器

ESP:堆栈顶指针

2.段寄存器:CS,DS,ES,SS,FS,GS

3.标志寄存器

CPU在实际取指令时根据CS:eip来准确确定某一个指令在内存中的地址。

二:汇编指令(以常见的MOV,PUSH,POP,CALL等进行说明)

(1)MOV指令及寻址方式

1.MOV指令,能实现以下操作:

① CPU内部寄存器之间数据的任意传送(除了码段寄存器CS和指令指针IP以外)。

② 立即数传送至CPU内部的通用寄存器组(即AX、BX、CX、DX、BP、SP、SI、DI),给这些寄存器赋初值。

③ CPU内部寄存器(除了CS和IP以外)与存储器(所有寻址方式)之间的数据传送,可以实现一个字节或一个字的传送。

④ 能实现用立即数给存储单元赋初值。

movb,movl,movw,movq分别针对8位,16位,32位,64位系统

(2)pushl和pop指令,pushl用于入栈(栈的扩张),pop用于出栈(栈的收缩)

栈是向下生长的,也就是说栈底位于高地址,栈顶位于低地址,用ebp指向栈底,用esp指向栈顶。

入栈操作:pushl %eax完成的操作包括两步

subl $4,%esp
movl %eax,(%esp)


出栈操作:pop %eax完成的操作包括两步

movl (%esp),%eax
addl $4,%esp


(3)CALL主要用于函数调用

call 0x12345 完成的操作包括两步

push %eip
movl %0x12345,%eip


(4)RET指令用于恢复操作,完成pop %eip操作

(5)enter和leave操作

enter 置为空栈,完成的操作包括两步

pushl %ebp
movl %esp,%ebp


leave用于撤销函数调用堆栈,完成的操作包括两步

movl %ebp,%esp
popl %ebp


注:

(1)函数调用堆栈是由逻辑上多个堆栈叠加起来的(比如函数的嵌套)

(2)函数的返回值默认使用eax寄存器存储返回给上一级函数

(3)一定要注意的是eip不能由程序员直接修改,程序员想修改eip只能通过特殊指令间接修改。

2.寻址方式

(1)寄存器寻址(不访问内存)

movl % eax,% edx <==>edx= eax,将eax中的值赋值给edx

(2)立即寻址(不访问内存)用$表示立即数

movl $ 0x1234,%edx <==>edx = 0x1234

(3)直接寻址

movl 0x123,%edx <==>edx = * (int32_t*)0x123

将内存地址0x123所指向的内存数据赋值给edx

(4)间接寻址

movl (%ebx),%edx <==>edx = * (int32_t*)ebx

(5)变址寻址

movl 4(%ebx),%edx <==>edx = * (int32_t*)(ebx+4)

二、通过实验分析计算机是如何工作的

(1)实验代码与截图

在实验楼的linux终端下创建一个main.c文件(注意实验楼的环境为64位)



利用指令(64位下生成32位的汇编文件)

gcc –S –o main.s main.c -m32




进入main.s汇编文件,去掉所有以.开始的代码行(以.开始的代码是连接时的辅助信息)得到纯汇编代码



可以看到刚才介绍过的指令操作。

(2)实验分析——-对执行过程的分析

与C语言类似,汇编代码的入口也为main函数

初始时栈的状态



进入main函数,执行18行代码

pushl %ebp


执行后栈的状态



0标号下下存放ebp的内容,esp指向标号1处

movl %esp,%ebp




esp和ebp指向相同位置

subl $4,%esp




movl $8,(%esp)




call f


执行call时实际执行两个动作,pushl %eip ; movl f ,%eip

此时eip指向第23行代码



执行后,eip指向f

跳转到f中执行:

pushl %ebp
movl %esp,%ebp
subl $4,%esp




在执行过movl%esp,%ebp后,esp和ebp置于相同的标号处(4)

执行subl $4,%esp,esp向下移动到标号5



movl 8(%ebp),%eax
movl %eax,(%esp)


movl 8(%ebp),%eax 变址寻址,将ebp(此处为标号4)加8(向上移动两个标号,也就是标号2处)的值赋给eax,所以%eax = 8

movl %eax,(%esp),将eax的内容也就是8赋值到esp下也就是标号5处



call g
leave


执行call时实际执行两个动作,pushl %eip ; movl g,%eip

此时eip指向第15行代码leave的位置,此时eip指向g跳转到g中去执行



在g中执行:

pushl %ebp
movl %esp,%ebp


pushl %ebp同上,将esp向下移动,将ebp(标号为4)压栈



movl %esp,%ebp

esp和ebp指向相同的位置



movl 8(%ebp),%eax


强ebp向上移动两个标号的值(也就是8)赋给eax

addl $57,%eax
popl %ebp
ret


%eax中存放的值为8,addl操作,将eax的值与立即数57相加,结果为65,将65存回到eax

popl %ebp,将ebp的值放回到ebp,执行效果:ebp重新指向标号为4的位置,同时esp减4



ret执行popl %eip,也就是说esp向上移动指向5的标号的位置,同时eip指向15行指令的位置(call的下一条指令)



回到f中执行

leave
ret


leave执行两条指令,

movl %ebp,%esp

popl %ebp

首先,将esp指向ebp相同的位置(也就是标号4的位置),popl %ebp,将ebp出栈,此时ebp指回标号1的位置,由于popl,esp向上移动





ret执行popl %eip

由于popl,esp向上增加一个,指向标号2,eip指向第23行代码处



eip执行第23行代码,回到main处,执行

addl $1,%eax
leave ret


eax此时的值为65,执行addl,65+1 = 66,将66存回到eax。

函数返回值默认使用eax来存储

执行leave,分为两步,

movl %ebp,%esp,将esp指向ebp的位置,popl %ebp,将ebp出栈(ebp指向0的位置),popl指令时esp向上移动,也就是说esp,ebp均指向标号0的位置,栈回到main函数最初的状态。

ret,return的是main函数之前的堆栈,此处由操作系统管理。



栈向下生长,向上还原,增增减减,将程序变为指令流,从CPU上流过。

此时,小程序执行完成

三、实验总结–对计算机如何工作的理解

1.计算机的基本原理是存储程序和程序控制,预先要把指挥计算机如何进行操作的指令序列(称为程序)和原始数据通过输入设备输送到计算机内存贮器中。每一条指令中明确规定了计算机从哪个地址取数,进行什么操作,然后送到什么地址去等步骤。

计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操作等加工,然后再按地址把结果送到内存中去。接下来,再取出第二条指令,在控制器的指挥下完成规定操作。依此进行下去。直至遇到停止指令。简单来说就是CPU负责处理和运算,存储器负责保存指令和数据。通过操作系统得调度和安排,不停地进行取址、译码、执行的循环。

2.汇编代码是什么?

计算机语言的发展过程从机器语言(计算机能直接识别的二进制0和1的组合)->汇编语言(为了减轻使用机器语言编程的痛苦,人们进行了一种有益的改进:用一些简洁的英文字母、符号串来替代一个特定的指令的二进制串,依赖于硬件)->高级语言(接近于数学语言或人的自然语言,同时又不依赖于计算机硬件,编出的程序能在所有机器上通用)。

我们编写了一个小程序,比如上面实验中写到的main.c文件,编译器执行的过程,


可执行的二进制文件是计算机“认识”的文件,可以直接执行。

3.以上便是我对这次实验的总结,计算机很“单纯”,它可以执行很多复杂的指令,但它也是被“告诉”要执行什么,才会去执行什么,通过对汇编语言的分析可以方便我们理解计算机处理的过程,了解计算机如何工作等等,这也会成为我今后学习的重点。感谢为我们辛苦准备课程的老师!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐