一、寄存器部分
8086的寄存器分为通用寄存器、标志寄存器、指令指针寄存器和段寄存器。
通用寄存器
通用寄存器是指处理器最常使用的整数通用寄存器,可以用于保存整数数据、地址等。具体来说,分为以下几种:
- AX(累加器):使用频度最高,用于算数、逻辑运算和与外设传递信息等。
- BX(基址寄存器):用于存放存储器地址,方便指向变量或者数组中的元素
- CX(计数器):作为循环操作等指令中的计数器
- DX(数据寄存器):存放数据,在输入、输出指令中存放外设端口地址
- SI(源变址寄存器):指向字符串或者数组的源操作数
- DI(目的变址寄存器)指向字符串或者数组的目的操作数
- BP(基址指针寄存器):默认指向程序堆栈区域的数据,主要用于在子程序中访问通过堆栈传递的参数和局部变量
- SP(堆栈指针寄存器):用于指向程序堆栈顶部的数据,在设计堆栈指令中会自动增加或者减少,所以总是指向堆栈顶部。
标志寄存器
标志寄存器用于反映指令执行的结果或者控制指令执行格式。8086处理器中各种常用的标志形成一个16位的标志寄存器。标志分为状态标志和控制标志。
状态标志:
- 进位标志CF(carry flag)
- 奇偶标志PF(Parity flag)
- 调整标志AF(Adjust flag)
- 零标志ZF(Zero flag)
- 符号标志SF(Sign flag)
- 溢出标志OF(Overflow flag)
控制标志:
- 方向标志DF
- 中断允许标志IF
- 陷阱标志TF
指令指针寄存器
8086的指令指针存储器存放在16位寄存器IP中。当执行完一条指令时,IP的值自动加上该指令的字节数,从而指向下一条指令。IP不能像通用寄存器一样被直接赋值修改,需要执行控制类指令,或者被处理器赋值改变。
段寄存器
为了指明程序各部分在主存中的位置,将程序分为四个段:代码段CS,堆栈段SS,数据段DS,附加段ES(FS,GS)。段寄存器指明主存中段的位置。
8086允许进行段超越,只需要在源操作数前方表明超越前缀,例如:
下方代码中SP的默认段是SS段,使用段超越前缀将段知名到了DS段。
MOV AL DS:[SP]
二、存储器部分
数据的存储格式:
8086的字长尾16位,称为字;80386的字长为32位,称为双字。字和双字占连续的存储单元。其中,低字节存入低地址,高字节存入高地址,这种形式叫做“小端方式”。
同时,存储数据是还需要注意对齐地址的问题。如果n字节的数据可以起始于被n整除的地址的位置,这种方式叫做地址边界对齐。地址边界对齐使得访问可以更加的迅捷。在某些其他的处理器上,不进行地址对齐是非法的。
存储器的分段管理
存储器将1Mb存储空间分为逻辑段。并且规定:
1.每个逻辑段的大小不能超过64Kb
2.每个逻辑段的起始地址必须为模16地址
这样,可以通过16位的段寄存器表达段所在地址。同时,由于逻辑段的大小不超过64Kb,因此逻辑段内的偏移地址也可以用16位寄存器来表达。
物理地址可以由段基地址:偏移地址的逻辑地址得到。例如:1460H:100H就表示14700H。一个物理地址可能会有多个逻辑地址。这一般取决于是否有段重叠。
段重叠:一般来说,四种段分布在不同的逻辑段中,方便分工工作,但是在节省内存的极致情况下可以让各段的大小根据实际需要来分配,甚至让四个段都分布在同一个逻辑段内(在这种情况下,段寄存器会保存相同的段基地址,因为他们分布在同一个逻辑段内)。
三、8086的寻址方式
8086的基本机器代码格式
8086的机器代码格式如下:
1/2字节 | 0/1字节 | 0/1/2字节 | 0/1/2字节 |
操作码 | mod reg r/m | 位移量 | 立即数 |
8086指令最多可以有两个操作数。在mod reg r/m中,reg指代寄存器寻址的操作数,占用三位
mod 和 r/m表示另一个操作数 的寻址方式。
- mod = 00时,表示无偏移量的存储器寻址方式。其中,当[r/m]=110时,为直接寻址方式,此时该字节后跟16为有效地址d16。
- mod=01时,表示带有8为偏移量的存储器寻址方式。该字节后跟1字节量表示8位偏移量d8,
- mod=10时,位带有16位偏移量的存储器寻址方式,此时该字节后跟两字节量表示16位偏移量d16
- mod=11时,表示寄存器寻址方式,由r/m指定寄存器
。下面讲述上方提到的寻址方式。
直接数寻址方式
直接数寻址方式中,源操作数直接给出,并且根据指令进行操作。例如如下代码:
MOV AX, 2000H ;机器代码为B8 02 01
该指令直接将立即数2000H传入AX寄存器。在机器代码中,B8表示操作码,去除了mod reg r/m和位移量,直接在操作码的后面跟入了立即数。注意:在机器码中,采用了小端方式。
寄存器寻址方式
寄存器寻址方式不仅应用于目的操作数中,也可以应用于源操作数中,可以是8位,16位通用寄存器或者段寄存器(CS,DS,SS,ES)中。例如
MOV AX,1234H; 目的操作数采用寄存器寻址方式,源操作数采用立即数寻址方式
MOV AX,BX; 两个操作数均采用寄存器寻址方式
存储器寻址方式
8086的存储器是分段管理的,所以指令中给出的一般都是操作数的逻辑地址或者仅有偏移地址(有效地址EA)。
1.直接寻址方式
例如如下指令
MOV AX,[2000H]; AX<--DS:2000H
当使用直接寻址时,偏移地址加上中括号,默认段基地址使用DS,可以进行相应的段超越。
2.寄存器间接寻址方式
在这种情况下,有效地址存储在寄存器中,先从寄存器中取出对应的整数EA,然后进行直接寻址。例如
MOV AX,[SI]; AX<-DS:[SI] 机器代码为8B 04
反复提醒,不同的寄存器,默认段也不相同。例如上方指令中的SI寄存器,默认段是DS段。而某些寄存器例如BP,SP,其默认段是SS段。
如果SI中存放的内容是2000H,那么该指令等同于"MOV AX,[2000H]"。
3.寄存器相对寻址方式
在寄存器相对寻址方式下,实际得到的EA为寄存器中内容与8位/16位偏移量之和。例如如下指令:
MOV AX,[SI+06H]; AX<-[SI+06H]
注意,括号内进行了一次算术运算,可能存在溢出(超过64K)的情况。在这种情况下,会取对于64K的模。例若SI为FFFEH,则SI+6的有效地址为0004H。
4.基址变址寻址方式
在这种寻址方式下,EA是将基址寄存器的内容加上变址寄存器的内容得到的。当出现算数溢出时,取其对64K的模。例如如下指令:
MOV AX,[BX+SI]; AX<-DS:[BX+SI]
当基址寄存器选择BX时,默认段是DS;当选择BP时,默认段是SS。
5.相对基址变址寻址方式
“相对”即指存在偏移量,EA是以基址变址为相对地址进行偏移得到的。同样的,当出现算数溢出时,取其对64K的模。例如如下指令:
MOV AX,[BX+SI+06H]; AX<-DS:[BX+SI+06H]
总结
8086的汇编语言中设置了多种数据的寻址方式。其中,源操作数可以是立即数IMM,寄存器寻址REG或者存储器寻址MEM,但是目的操作数必须是寄存器寻址REG或者存储器寻址MEM。在更高级语言中通常情况下不讨论数据寻址的方式,但是在底层的执行过程中依然需要执行这些操作,所以了解处理器为何设置如此多样的寻址方式实际上是有意义的。