上一章介绍了汇编语言的基本知识,这一章开始我们深入的理解汇编语言最常操作的寄存器
1. 寄存器
接着上一章的内容,我们现在来剖析一下CPU中所包含的内容:
-
运算器: 进行信息处理
-
寄存器: 进行信息的存储
-
控制器: 控制这个各个器件进行工作
-
内部总线,连接内部的部件.外部总线,连接CPU与主板上的其他部件,并且进行数据之间的传送
而对于汇编语言来讲,我们最常操作的就是寄存器(Register)了
8086CPU总共有14个寄存器,AX,BX,CX,DX,CS,DS,SS,ES,IP,SP,BP,SI,DI,PSW
1.1 通用寄存器
8086CPU中所有的寄存器都是16位的,AX,BX,CX,DX为通用寄存器
同时,为了处理兼容的问题,8086CPU的所有寄存器都可以拆成2个8位寄存器来进行使用
Tips: 8086CPU的寄存器可以拆成两个8位寄存器使用
因为8086CPU的上一代产品(具体叫什么忘了)的原因,8086相对于上一代产品,仅仅做了
寄存器位数上的升级,指令基本没有变化.
所以为了兼容的问题,8086每个寄存器可以拆成两个8位使用
即:
-
AX = AH + AL
-
BX = BH + Bl
-
CX = CH + CL
-
DX = DH + DL
CPU名称的记法,可以根据位的高低,AH(High),高8位.AL(low),低8位
Tips:在汇编语言中的进制
汇编中,我们经常要操作的是寄存器,而寄存器基本都是8位和16位.
所以,我们常用的进制是二进制和十六进制,B表示二进制,H表示十六进制,例: 1001B,02E3H
1.2 寄存器中存储的数据
在计算机的进制单位中,经常操作的是字节与字,之前也进行过相关进制的描述
字节:1 Byte,一次可以由一个8位寄存器进行控制
字: word,为两个字节,每次可以由1个16位寄存器进行控制
那么,问题来了,对于一个字,在16位仅存其中是如何存储的?
在计算机的发展史上,关于数据如何在元件中存储也是一个经典问题
随着,存储器的规模越来越大,这成为了一个不得不考虑的问题
对于少字节的数据,如何在计算机中存储
大端,小端两种模式应运而生
**大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中 **
大端模式和我们的阅读习惯一致。
**小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中 **
这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
很显然的,8086CPU属于** 小端模式 **
1.3 汇编指令
说了这么久,终于看到直观的汇编指令了
汇编指令 | 控制操作 | 高级语言语法描述 |
---|---|---|
mov ax,18 | 将18送入寄存器ax | AX=18 |
add ax,8 | 寄存器AX中的内容加上8 | AX += 8 |
mov ax,bx | 寄存器BX中的内容送入寄存器AX | AX = BX |
add ax,bx | 寄存器AX中的内容加上BX中的内容 | AX += BX |
在汇编指令中,大小写不进行区分,效果相同
下面提到两个在进行进制计算的重要问题:
1.在出现数据溢出时:
如上例,AX,BX的求和结果,应该是1044CH,但是16位寄存器只能存储4位16进制数
所以,AX最后的值位044CH,而不是1044CH,
2.在进行8位寄存器操作时
mov al,85H
add al,93H
上面两条指令的结果是什么呢?
根据进制计算,al的结果是108H,
但是,实质上,最后在寄存器AL中存储的是08H
那么这是为什么呢?
因为AL是AX的低8位,所以AL只是一个8位的寄存器,不能存储3位的16进制数据
能进位吗? 不能,因为AL与AX并无直接关系,这一条add指令进行的是8位运算,不能进位到AH中
**所以,进行数据传送或者运算时,注意指令的两个操作对象是一致的 ! **
8位都是8位,16位都是16位
2. 物理地址
正如之谈到的一样,计算机所有的RAM与ROM抽想成为内存地址空间
所以,我们可以进行访问的内存实际上是线性的,即每个内存单元都有其唯一的物理地址
下面就来看看8086CPU如何生成16位的物理地址
Tips: 16位结构(16位机,字长为16)
16这个数字,在这里描述的是1个CPU的结构特性:
- 运算器一次性可以处理16位的数据
- 寄存器的最大宽度为16位
- 寄存器与运算器之间的通路是16位
总结一下:在8086CPU的内部,一次性可以传输,存储,计算的数据为16位
同时,16一般指CPU通用寄存器的宽度
8086CPU有20位地址总线,,理论上是1MB的寻址空间
但是,8086实际上是16位CPU,所以能生成的寻址宽度,只有64KB
那么,如何实现1MB的寻址空间呢?
伟大创造:使用两个16位寄存器,生成20位的物理地址
来看一张图:
我们来看一看在8086CPU中,当要读写内存时:
-
CPU中的相关部件提供两个地址,一个CS段地址(Code),一个IP偏移地址(instrument)
-
段地址与偏移地址通过,内部总线送入地址加法器中,
-
地址加法器将两个16位地址合并成为一个20位的物理地址
-
地址加法器通过内部总线将20位物理地址送入输入输出控制电路
-
输入输出控制电路将物理地址送上地址总线(外部总线)
-
20位物理地址被地址总线送往存储器,之后进行数据的操作
地址加法器: 物理地址 = 段地址 x 16 + 偏移地址
为什么乘16,因为地址是16进制,即为扩大一个数量级,之后进行偏移
即可理解段地址与偏移地址的含义
2.1 “段地址 x 16 + 偏移地址 = 物理地址” 的本质含义
套用王爽老师,进行解释的例子,
使用这种段地址 + 偏移地址进行寻址的方法 原因就是:
因为手头只有16位的寄存器,但是为了更高效率的寻址
同时,还要保证每一个内存单元都可以寻址到,就是用了这样的一种方法
在基础地址上进行偏移,可以实现访问尽可能多的地址空间,而且,每一个内存单元,都要保证能访问到
2.2 段的含义
上面说了很多的,段的概念,需要注意的是:
**实质上,内存中是没有进行分段的 ! **
所谓的段,是有程序员进行程序设计,操作内存时,自行进行分段的
来看一个例子:
Physical Address CS IP
21F60H 2000H 1F60H
2100H 0F60H
21F0H 0060H
21F6H 0000H
1F00H 2F60H
上面的例子便可以看出,实质上每一个物理地址,可以有多组段地址 + 偏移地址实现访问同一物理地址
所以,段并非是处理器CPU自己进行划分的,实质上是程序员根据程序设计的需要,进行段的划分
所以,在进行编程时,我们可以根据需要进行段的划分
但是,需要注意的是:
1. 段地址一定是16的倍数,因为 X 16
2. 偏移地址只能达到64KB的寻址能力,因为偏移地址,也是一个16位寄存器存储的值,寻址能力只有64KB
寻址范围: 0000H ~ FFFFH
可以将地址连续,起始地址为16倍数的一组内存单元,视为一个段
2.3 段寄存器
现在开始,来介绍另外一类十分重要的寄存器,段寄存器
之前我们介绍的都是通用寄存器,而这些段寄存器,都有着其重要的作用
既然名为段寄存器,那么,这些寄存器中存储的都是段地址的信息,
DS: 数据段地址 (Data)
CS: 指令/代码段地址 (Code)
SS: 栈端段地址 (Stack)
目前常用的是这三个. . . (另外还有一个ES)
CS 与 IP这两个寄存器是8086CPU中最为重要的寄存器之二,CS为代码段寄存器,IP为指令指针寄存器
我们经常要表示当前CPU要执行的指令,就是使用CS,IP进行指向的
**常用表述方法 : **
1.执行CS:IP地址单元开始的指令,
2.或者代码存在CS段中的IP单元中
具体CPU如何读取和执行指令的流程,参考 < 汇编语言 > ( 王爽 ) P26 ~ P31
Tips: CPU如何将内存中的数据视为指令
之前我们曾经说过,CPU将内存中的数据,可以视为代码,数据,或是栈内数据
那么这一切都是如何进行界定的?
很简单:依靠段寄存器,进行识别,数据在内存中没有指令,数据之分,一切都是依靠CPU中的段寄存器
CPU通过修改CS,DS,SS,IP,SP这些寄存器中的内容,使得
CS:IP 内存单元中的数据被视为指令
DS:[x] 内存单元中的数据视为数据
SS:SP 内存单元中的内容视为栈内数据
内存中都是数据,没有指令,数据之分.划分是依靠处理器CPU如何进行代码段的读取界定的
2.4 修改CS,IP的指令
程序员对于处理器唯一能够进行操作的就是寄存器,
而我们通常进行寄存器内容修改的指令便是 mov指令
mov 指令 可以进行寄存器中指的修改.
但是,8086CPU中不能使用mov指令进行段寄存器的修改,因为处理器设计时,就没有提供这样的功能
其中提供了,除传送指令(mov)外的另外一类指令,转移指令
jmp CS:IP 使当前指令跳转至CS:IP处
jmp ax 使当前IP跳转至ax处
最后还是要强调一个概念:内存中,所有的东西,都是数据.到底是指令,还是数据,由CPU来定
使用Debug进行汇编语言的学习,这里的Debug并非是改Bug的意思,实际上是指进行交互式的程序
可以查看内存中的情况,同时还可以查看CPU寄存器中的内容
常见命令:
命令 | 功能 |
---|---|
-R | 查看,改变CPU中寄存器的内容 |
-D | 查看内存中的内容 |
-E | 改写内存中的内容 |
-U | 翻译机器指令 |
-T | 单步执行指令 |
-A | 以汇编指令进行指令的输入 |