所有寄存器均为16位,可以存放两个字节。8086CPU共有14个寄存器,分别是:AX、BX、CX、DX、SI、DI、SP、BP、IP、CS、SS、DS、ES、FLAG。
这 14 个寄存器按照一定方式又分为了通用寄存器,控制寄存器和段寄存器。
寄存器 | 英文名 | 分类 | 具体名称 | 常用关联 |
---|---|---|---|---|
AX | Accumulator | 数据寄存器 | 累加寄存器 | div除法指令和mul乘法指令会调用;端口的输入输出只能用ax、al存放 |
BX | Base | 数据寄存器 | 基地址寄存器 | 经常与ds, es 连用;[bx] 默认调用ds:[bx] |
CX | Count | 数据寄存器 | 计数器寄存器 | 储存循环次数,loop, jcxz指令会调用cx |
DX | Data | 数据寄存器 | 数据寄存器 | 常用来储存数据 |
SP | Stack Pointer | 指针寄存器 | 堆栈指针寄存器 | 存放栈顶的偏移地址 |
BP | Base Pointer | 指针寄存器 | 基指针寄存器 | 默认与ss相关联,比如 [bp] 默认调用 ss:[bp] |
SI | Source Index | 变址寄存器 | 源变址寄存器 | 常用于 ds:[si],存放偏移地址,数据从哪里来 |
DI | Destination Index | 变址寄存器 | 目的地址寄存器 | 常用于 es:[di],存放偏移地址,数据到哪里去 |
DS | Data Segment | 段寄存器 | 数据段寄存器 | 常用于 ds:[si],存放段地址,数据从哪里来 |
ES | Extra Segment | 段寄存器 | 附加段寄存器 | 常用于 es:[di],存放偏移地址,数据到哪里去 |
SS | Stack Segment | 段寄存器 | 堆栈段寄存器 | 存放栈的段地址 |
CS | Code Segment | 段寄存器 | 代码段寄存器 | 存放执行指令的段地址 |
IP | Instruction Pointer | 控制寄存器 | 指令指针寄存器 | 存放执行指令的偏移地址 |
FLAG | Flag | 控制寄存器 | 标志寄存器 | 按位作用,详见正文 |
AX、BX、CX、DX用于存放一般性数据,被统称为通用寄存器。
以AX为例,寄存器的逻辑结构如图:
AX、BX、CX、DX这4个寄存器均可分为两个可独立使用的8位寄存器来使用,仍以AX为例,16位寄存器分为两个8位寄存器的情况如图:
AX寄存器又被称为累加寄存器或简称为累加器,除其暂存数据的作用外,还有一些特殊作用,即在使用MUL指令和DIV指令时。
除了暂存一般性数据的功能外,BX主要还是用于其专属功能——寻址(寻找物理内存地址)上,BX寄存器中存放的数据一般是用来作为偏移地址使用的。在 8086 CPU 中,CPU 是根据 <段地址:偏移地址> 来进行寻址操作,经常与DS、ES连用,如DS:[BX]
,[BX]
默认调用DS:[BX]
。
除了暂存一般性数据的功能外,CX也有其专门用途——储存循环次数,loop, jcxz指令会调用cx。
当使用LOOP循环指令时,可以通过CX指定需要循环的次数,CPU每一次执行LOOP指令时,都会做两件事:
CX=CX-1
,即令CX计数器减去一除了暂存一般性数据的功能外,DX在其他方面也具有用途,已在介绍AX寄存器时有所介绍过了。
BP为基指针寄存器,与其他几个用来寻址操作所使用的寄存器(BX,SI,DI)没有太大区别。
它作为通用寄存器的一种,其可以暂存数据,而BP又不是数据寄存器,意味着其不能分割成为两个8位寄存器使用。
以 […] 的方式访问内存单元而且在 […] 中使用了寄存器 BP 的话,那么如果在指令中没有明确或者说是显示的给出段地址时,段地址则使用默认的 SS 寄存器中的值(BX,SI,DI 会默认使用 DS 段寄存器),比如DS:[BP]中明确给出了段地址位于DS中。
SP寄存器必须与SS段寄存器一起使用,所以SP寄存器将在后文中与SS段寄存器一起作介绍
SI (Source Index) 是源变址寄存器,DI (Destination Index) 即是目的变址寄存器。
8086 CPU 中的 SI 寄存器和 DI 寄存器其实和 BX 寄存器的功能是差不多的,即寻址操作和暂存一般性数据,只不过 SI 寄存器和 DI 寄存器均不是数据寄存器,所以它们不能够拆分为 2 个独立的 8 位寄存器。
SI:常用于 DS:[SI],存放偏移地址,数据从哪里来
DI:常用于 ES:[DI],存放段地址,数据到哪里来
示例:
MOV SI,0 ;初始化偏移地址为 0
MOV AX,[SI] ;将段地址为 DS 偏移地址为 SI 的内存单元中的值移入 AX 中
MOV AX,DS:[SI] ;将段地址为 DS 偏移地址为 SI 的内存单元中的值移入 AX 中
MOV AX,SS:[SI] ;将段地址为 SS 偏移地址为 SI 的内存单元中的值移入 AX 中
MOV DI,0 ;初始化偏移地址为 0
MOV AX,[DI] ;将段地址为 DS 偏移地址为 DI 的内存单元中的值移入 AX 中
MOV AX,DS:[DI] ;将段地址为 DS 偏移地址为 DI 的内存单元中的值移入 AX 中
MOV AX,SS:[DI] ;将段地址为 SS 偏移地址为 DI 的内存单元中的值移入 AX 中
CS:IP 两个寄存器指示了 CPU 当前将要读取的指令的地址,其中 CS 为代码段寄存器,而 IP 为指令指针寄存器 。
当我们运行一个可执行文件时,我们需要另外一个程序来将这个可执行文件加载到内存当中,一般是通过操作系统的外壳程序( Shell 程序)将可执行文件加载到内存中以后,就会设置 CPU 中的两个寄存器,即设置 CS:IP 两个寄存器指向可执行文件的起始地址,此后 CPU 便从这个起始地址开始读取内存中的指令,并且执行。
我们在写汇编程序时,通常会使用 START 标记,其实这个标记就是用来标记起始地址的,当将一个汇编程序编译,连接成可执行文件以后,再通过操作系统的 Shell 程序将可执行文件加载到内存中以后,这个 START 所标记处的地址就是整个可执行文件的起始地址了 。
即,当一个可执行文件加载到内存中以后,CS:IP 两个寄存器便指向了这个可执行文件的起始地址,然后 CPU 就可以从这个起始地址开始往下读取指令,当读取完指令后,CS:IP 将会自动的改变(基本上是改变 IP) ,从而指向下一条要读取的指令,这样就可以执行这个可执行文件了 。
在任何时刻,SS:SP 都是指向栈顶元素,要注意8086 CPU 并不会保证我们对栈的操作会不会越界,所以我们在使用栈的时候需要特别注意栈的越界问题 。
当使用 PUSH 指令向栈中压入 1 个字节单元时,SP = SP - 1;即栈顶元素会发生变化;
当使用 PUSH 指令向栈中压入 2 个字节的字单元时,SP = SP – 2 ;即栈顶元素也要发生变化;
当使用 POP 指令从栈中弹出 1 个字节单元时, SP = SP + 1;即栈顶元素会发生变化;
当使用 POP 指令从栈中弹出 2 个字节单元的字单元时, SP = SP + 2 ;即栈顶元素会发生变化;
DS 段寄存器来存放要访问的数据的段地址;ES段寄存器是一个附加段寄存器,当其他段寄存器不够用时,可以考虑使用ES段寄存器。
FLAG寄存器与其他寄存器不同,其他寄存器都是用来存放数据的,而FLAG寄存器按位起作用。
8086CPU的FLAG寄存器结构如图所示:
通常与CS寄存器配合使用,已在前文的CS介绍中介绍过。
王爽. 汇编语言.第3版[M]. 清华大学出版社, 2013.
https://blog.csdn.net/ulan420/article/details/126329586