[计算机基础] 汇编学习(1)

一、汇编环境准备

1.安装DOSbox

下载:https://www.dosbox.com/download.php?main=1

安装完毕后,配置一个根目录,修改以下配置文件:

C:UsersAdministratorAppDataLocalDOSBoxdosbox-0.74-3.conf

最后部分修改为:

[autoexec]
# Lines in this section will be run at startup.
# You can put your MOUNT lines here.
mount c: d:asm
c:

d:asm是我们的工作目录。

2.准备工具

将以下工具都放到工作目录下:

debug.exe
masm.exe
link.exe

二、初识汇编

1.汇编器(汇编编译器)和指令

机器指令:0101001110

汇编指令:MOV AX,000C   人类能识别和编写的指令

汇编器:将汇编指令翻译成机器指令的翻译器。即可以将MOV AX,000C翻译成0110110011这种二进制机器码。

在DOSBOX中输入debug -u,可以看到以下内容:

左边的16进制数据和右边的汇编指令是对等的。即汇编器将右边的汇编指令翻译成了左边的16进制(对应二进制机器码)。

最左边的 073F:0100 是内存编号,他们是连续的,最小单位是byte,所以 74 03 这个指令占2个byte。

在我们使用 debug -u 的时候,该指令将内存中的数据解析成指令,我们也可以使用 debug -d 来查看内存中的原始数据:

可以看到, 073F:0100 开始的内存数据和上一个图中指令对应数据是一致的,只是 -d 指令将其显示为普通数据而已( -u 指令解析为指令)。

三、一些概念

1.地址线

CPU从内存读取数据的时候,要告诉内存我要拿那个地址的数据。由于CPU是通过电信号来传递地址信息的,电信号只有高低电平,也就是0和1。

如果地址线只有一条路,则只能表示2个位置,一个是0,一个是1。

如果地址线有两条路,则可以表示4个位置,00、01、10、11。

如果地址线有三条路,则可以表示8个位置,000、001、010、011、100、101、110、111。

以此类推:

我们所说的32位和64位表示的就是地址线的宽度,也就是地址线有多少个通路。32位就表示用32个二进制来表示内存地址,所以能够发给内存的地址信息是0~232-1,即0~4,294,967,295,这也就是说32位地址的内存有232个格子,每个格子为1 byte,这也就是为什么32位系统只能支持4G内存(4G内存就是232byte)。

在以往的CPU型号中,地址线的数量如下:

8080:16根,寻址能力为64KB

8088:20根,寻址能力为1MB

80286:24根,寻址能力为16MB

80386:32根,寻址能力为4GB

2.数据线

与地址线类似,地址线传送的数据用来表示内存位置,而数据线就是传递的数据本身。

假设数据线有8个通道,每一个通道传递一个二进制,则8个通道一次性就可以传递一个byte的数据。

如果有16个通道,则一次性可以传递两个byte的数据。

以此类推

以往CPU支持数据线的数量:

8080:8根,一次传递一个byte

8088:8根,一次传递一个byte

8086:16根,一次传递两个byte

80286:16根,一次传递两个byte

80386:32根,一次传递四个byte

3.控制线

控制线决定了CPU对其他部件(很多部件)进行控制的能力。

4.外部设备

除了内存、显存、ROM等设备的数据是通过内存地址去访问。还有一些外部设备,例如键盘、鼠标等是通过port端口号去访问的。

我们拆开鼠标或键盘可以看到这些设备都有一个芯片。

这个芯片中也会有一个存储空间,当我们按下一个键时,对应的数据会存储在该芯片的空间中。

然后通过线缆传递到主板的一个端口,然后CPU再通过端口号读取对应端口的数据,从而实现CPU读取外设数据。

四、寄存器

1.什么是寄存器

寄存器就是CPU用来存放指令和数据的地方,通过 debug -r 可以查看:

2.AX、BX、CX、DX寄存器

这四个寄存器就做通用寄存器,用于存储数据。每个寄存器可以存储2byte大小的数据,即16bit。

这四个寄存器有个特殊的地方,就是可以分为两个8bit的寄存器:

AX = AH + AL
BX = BH + BL
CX = CH + CL
DX = DH + DL

H代表高八位,L代表低八位。

例如8086 CPU的数据线为16bit,则一次性最大可以读取2byte的数据,也就是说可以处理两种尺寸的数据:

字节型数据  1byte  放在8位寄存器中
字型数据   2byte  放在16位寄存器中

我们也可以称一个寄存器中,一个字节是这个字型数据的高位字节,另一个字节是这个字型数据的低位字节。

使用 debug -a 来体验一下给寄存器赋值:

注意,由于我们使用mov给AX寄存器赋值,AX寄存器为16bit寄存器,所以5被翻译成了0005H。

当我们对8bit寄存器赋值时,如下所示:

可以看到,mov中的8被翻译成了08H。而且值被赋予到了AH 8位寄存器中。

我们也可以同时输入多条指令,然后一条条执行:

注意:数据大小与寄存器大小必须保证一致性,即8bit寄存器存放8bit数据,16bit寄存器存放16bit数据,否则会报错。

3.寄存器的独立性

寄存器是相互独立,互不影响的,就算是一个16位寄存器分成的H和L两个8位寄存器,也是互不影响的。

例如,我们执行8bit 的加法运算:

至于溢出的部分数据,保存在了其他地方。

4.地址寄存器

前面了解的AX、BX、CX、DX都是用于存储数据的通用寄存器。这节我们了解一下存放内存地址的寄存器。

使用 debug -u 查看内存地址时,我们可以看到两列地址信息:

其中左边部分为段地址,右边部分为偏移地址部分。这两部分分别都是16bit大小,也就是都需要一个16bit寄存器来存储。

为什么要将内存地址分为两部分?

这是因为我们提高寻址能力就是要加宽地址线的数量,例如8086CPU的地址线为20bit,那么一个寄存器已经无法满足存储这个地址信息。

于是就使用了段地址+偏移地址的形式,公式如下:

基础地址 = 段地址 * 10H    # 例如段地址为F230H,向左移一位变为F2300H
物理地址 = 基础地址 + 偏移地址   #F2300H + C8H = F23C8H,即物理地址为F23C8H,刚好为20bit

这里注意,一个物理地址可能对应多个 段地址和偏移地址的组合,例如:

21F60H = 2000H * 10H + 1F60H
21F60H = 2100H * 10H + 0F60H
21F60H = 21F6H * 10H + 0000H
21F60H = 1F00H * 10H + 2F60H

也就是说,内存地址是通过物理地址来表示的,只要段地址和偏移地址的组合生成的物理地址正确,就可以取到正确的数据。

5.查看某块地址的内存

使用-d查看2000:1F60地址开始的内存数据:

使用-u查看2000:1F60地址开始的内存数据,但是解析成指令:

虽然我们可以将内存的数据显示成普通数据和指令,但对于CPU,他只会将内存中某个特殊区域的数据当成指令。下节我们对其进行探究。

6.指令存储位置

当我们使用debug -r查看寄存器时:

可以看到 MOV AL,FC 指令对应的内存地址为073F:0100。

通过观察,我们可以确定IP寄存器保存着该指令的偏移地址。

而DS、ES、SS、CS这四个寄存器中,谁保存了指令的段地址,目前无法确定。

我们可以通过修改这四个寄存器的值,来看指令是否发生变化,从而确定是哪个寄存器保存指令的段地址:

从上面的过程可以看出,当我们修改CS寄存器的值时,指令发生了改变,说明CPU将CS寄存器中存储的数据作为指令的段地址。

总结:在8086 CPU中,CPU将CS:IP地址所保存的内容,全部当做指令来执行。

7.将内存中的数据作为指令运行

首先,我们使用debug -e 2000:0000向指定内存中存入一些数据:

然后使用debug -u查看一下翻译成指令是什么样子:

查看一下当前CS:IP在什么位置:

可以看到,当前CS:IP地址为073F:0100。我们将其修改为2000:0000:

可以看到,下面的指令变为我们存入内存数据对应的指令。

此时就可以用 debug -t 来执行了:

总结:从这一节我们可以看出,数据在内存中是没有区别的,只有当CS:IP指向的内存中的数据,才会被CPU当做指令来执行。

8.寄存器种类

在前面我们已经看到了有很多种寄存器,AX~DX为通用寄存器,用于存储数据(当然也可能有特殊用途,例如BX和CX就可以用来当作偏移地址寄存器使用,而AX和DX一般用于处理数据)。

而DS、ES、SS、CS用于存储段地址,IP用于存储指令偏移地址。

除了以上这些,剩下的SP、BP、SI、DI也是用于存储偏移地址的,我们在后面的章节会对其进行了解。

这些寄存器可能都有特殊的用途,不能对其一概而论。

==

原文地址:https://www.cnblogs.com/leokale-zz/p/12792806.html