汇编基础概述

  • Post author:
  • Post category:其他



1 汇编概述

机器能够直接读懂的语言是机器语言(指令),本质上是可执行的二进制代码,用机器语言编程会要命的。为了便于编程,就出现了汇编语言,汇编语言本质上是和机器语言一一对应的,每一句汇编都能够转化成一句机器语言。

汇编语言由三个部分组成:


2 CPU概述

中央处理单元(CPU)主要由运算器、控制器、寄存器三部分组成,从字面意思看运算器就是起着运算的作用,控制器就是负责发出CPU每条指令所需要的信息,寄存器就是保存运算或者指令的一些临时文件,这样可以保证更高的速度。

所以,简单点来说,寄存器就是CPU中可以储存数据的器件,一个CPU中有多个寄存器。

寄存器跟存储器还是有一定的区别的。存储器范围最大,它几乎涵盖了所有关于存储的范畴。寄存器,内存,都是存储器里面的一种。凡是有存储能力的硬件,都可以称之为存储器,这是自然,硬盘更加明显了,它归入外存储器行列。在计算机中,内存(也就是常说的存储器)他是指令和数据存放的地方,内存要向CPU提供指令和数据,CUP才能正常工作。磁盘中存放的数据,也必须要读取到内存中,才能被CPU使用。缓存是放在CPU之间的一块内存,负责将内存的数据与寄存器的数据进行交换,提高交换的速度。

1、寄存器存在于CPU中,速度很快,数目有限;存储器就是内存,速度稍慢,但数量很大;计算机做运算时,必须将数据读入寄存器才能运算。(要从内存读入缓存中)

2、存储器包括寄存器,存储器有ROM和RAM寄存器只是用来暂时存储,是临时分配出来的,断电,后,里面的内容就没了

CPU对存储器的读写主要有三类信息,设计三条总线:地址、控制、数据。CPU中,专门连接CPU和其他芯片的导线称为总线(bus),通过总线,来进行这三类信息的传递。

CPU通过地址总线来指定存储单元,地址总线的位数,32,64就是我们常说的多少位多少位,地址总线能传送多少个不同的信息,CPU就可以对多少个存储单元进行寻址。地址总线的宽度决定了能对多大的内存进行映射。

数据总线的宽度决定了一次能传输多少数据,控制总线的宽度决定了CPU对外部器件的控制能力,一根总线就有0,1两种状态,分别代表了读写,有多少根总线,就能控制多少外部器件。


2.1 寄存器中的通用寄存器

以8086(X86)CPU为例,其有14个寄存器,每一个寄存器有16位,两个字节。AX,BX,CX,DX属于通用寄存器,存放一般数据,

为了兼容性考虑,这4个寄存器可以分为两个独立的8位寄存器使用。其中AX的高位8为AH,低8位为AL。其他寄存器同理。

可以通过如下的几条简单的汇编指令来对寄存器的值进行控制:

值得注意的是,汇编指令时不会区分大小写的,也就是说,MOV AX,18也行。

通过两个简单的例子来熟悉一下汇编指令对寄存器的操作:

其他的移动和相加都好理解啊,最后一个相加,add ax,bx,把bx和ax相加再放回ax,也就是8226+8226,结果为1044C,但是呢,AX寄存器只能存放16位,也就是044C,溢出的1存放不了,此时,这个溢出的1CPU会额外处理,后续学到再回收吧,最后AX存放的是044C。

第二个例子,这个例子中啊,我们可以看出,能够对AL和AH进行分别操作,并且,在进行分别操作时,AL和AH会作为两个独立的容器,比如最后一个命令ADD AL,93H,在AL上加93,得到158,但是在存放的时候,AL存放58,溢出的1,不会存放在AH中,整个AX存放的为0058H。也就是说在AH和AL分开使用时,作为独立使用,互不会干扰。至于溢出的1,后面再说吧。


2.2 CPU寻址

8086CPU有20位地址总线,但是8086是具有16位结构的CPU,为了解决CPU寻址问题,8086CPU采用了使用两个内部16位地址合成一个20位的地址,其逻辑结构如下图:

当8086CPU要读写内存时,一共干了这么几件事:

通过地址加法器得打的物理地址的方法:物理地址=段地址X16+偏移地址。段地址X16也就是左移4位。


2.2.1 段寄存器

在8086CPU中,有4个段寄存器:CS,DS,SS,ES。S代表segment段,C代表code,D代表Date,S代表stack,E代表extra。

CS和IP是8086CPU中最关键的寄存器,CS为代码段寄存器,IP为指令指针寄存器。在8086PC机中,任意时刻,CS的内容为M,IP内容为N,CPU会从内存的MX16+N单元开始,读取一跳指令并且执行。也就是,CPU将CS:IP指向的内容当做指令执行。

8086CPU工作的过程可以简单的描述为:

(1)从CS:IP指向的内存单元开始读取指令,将读取的指令放入指令缓冲器。

(2)IP=IP+所读取指令的长度,从而指向下一条指令。

(3)执行指令,并且重复这个步骤。

在CPU上电之后,会自动的将CS,IP寄存器设置到指定的值。


2.2.2 修改CS,IP的指令

在之前的学习中,我们知道了,可以通过MOV指令来对AX,BX等寄存器的值进行修改,那么我们是不是也可以通过MOV指令对CS:IP进行修改呢。

当然是不行,哈哈哈哈。MOV指令常被我们称为传送指令。为了对CS:IP的值进行修改,我们使用转移指令。最简单的转移指令:jmp指令。

想要同时修改CS,IP的内容,可以使用: JMP 段地址:偏移地址   的方式来完成。                    例如:jmp 2AE3:3就是CS=2AE3,IP=0003,得到的物理地址为2AE33,也就是CPU从2AE33处读取命令。

还可以通过JMP命令单独修改IP的值,例如:jmp ax(等效于:mov IP,ax,当然只是等效)                我们将AX的值设置成1000,然后jam ax,就能把IP的值设置成1000.


2.3 通过寄存器访问内存


2.3.1 内存中字的存储

引出了字单元的概念,即存放一个字型数据的内存单元。在8086CPU中,一个字,有两个字节,16位。因此,一个字单元由两个连续的内存单元组成。且数据存储为小端存储。


2.3.2 DS和[address]

在之前的内容中已经讲过了,计算机为了执行一条命令,需要通过CS:IP来指向内存中的一处地址,读取该地址的指令,放到指令缓冲器中。同样的,如果CPU想要读写一个内存单元时,就需要得到这个内存单元的地址。此时通过另一个寄存器DS得到。比如,如果想要读取10000H单元时:

mov bx,1000H

mov dx,bx

mov al,[0]

通过以上三条命令就能够实现将10000H内存单元的数据读取的al中。

在之前的学习中,我们知道了mov指令可以完成两种传送:                                                              ①将数据直接放入寄存器 mov ax, 1000H;②将一个寄存器的值放入另一个寄存器mov ax,bx。

现在,多了一个传送函数,将一个内存单元的内容送入一个寄存器,通过mov ax,[…],来实现。其中[…]为偏移地址,只有偏移地址是不能确定一个内存单元的,为了确定内存单元地址,在执行命令时,会自动读取ds寄存器中的数据作为段地址。

在上面的代码中,我们是通过mov dx,bx,来修改DS段寄存器的值的。能不能直接修改呢,答案是不行,在8086CPU中,是不支持将数据直接放入段寄存器中的,得先用通用寄存器作为中转。

值得注意的是,由于8086CPU的数据总线有16位,所以一次可以传送2个字节的数据,也就是一个字。当用mov指令传送数据时,有两种情况:

mov ax,[0],将偏移地址为0的内存单元的字型数据(两个字节16位)传入ax寄存器。

mov al,[0],将便宜地址为0的内存单元的字节传到al寄存器中。

到目前为止,我们可以用mov指令干以下的几件事:

通过验证,除了以上几个mov指令能干的事情以外,通过验证,可以可到以下三个命令也是合法的:

mov 寄存器,段寄存器        如:mov ax,ds                                                                                        mov 内存单元,段寄存器        如: mov [0],cs                                                                                  mov 段寄存器,内存单元        如: mov ds,[0](切记mov ds,数据,是不行的,内存单元可以)

但是CS是不能通过这种方式更改的也就是说mov cs,ax是错的,CS只能通过jmp由系统更改。

add和sub指令和mov指令一样,可以进行如下操作:

但是,不同的是,add命令和sub命令是不能够对段寄存器进行操作的。


2.3 CPU中的栈


2.3.1 栈

现今的CPU都有栈的设计,以8086CPU为例,其提供了相关的指令,来以栈的方式访问内存空间。包括push入栈和pop出栈指令。

push ax:将寄存器ax中的数据送入栈中;pop ax:将栈顶取出数据送入ax中。

入栈和出栈的操作都是以字为单位进行的。

由此可以引出两个问题:

(1)CPU是如何知道某一个段空间是被当做栈来使用的呢?                                                            (2)在push和pop执行的时候,CPU是这么确定栈顶单元的呢?

参考之前学过的CS:IP来指向当前执行的命令所存储的内存单元。同理,在任意时刻,CPU通过SS:SP来指向栈顶元素,SS为stack segment栈段寄存器,其指向的段地址,就能告诉CPU,这块空间被当做栈来使用,SP为堆栈指针寄存器。

当执行push ax命令的时候,CPU一共有两步操作:

(1)SP=SP-2,SS:SP指向当前栈顶前面的单元,以当前单元为新的栈顶。

(2)将ax中的内容放到SS:SP指向的内存单元中。

从图中可以看出两个事:第一个事,栈顶的位置,是在高地址处,入栈时,地址减小。第二个事,就是原理上和数据结构的一样。

push ax,可以将栈顶元素放入到ax寄存器,除此之外

push 寄存器; push 段寄存器; push […](内存单元)都能使用。pop同理,但是pop cs是错误的,CS只能通过JMP更改。


2.3.2 栈顶超界问题

8086CPU是不能保证我们对栈进行操作的时候不会越界的。



版权声明:本文为MLuhuihui原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。