入门汇编语言

一、寄存器


1、4个数据寄存器(16位):
AX(AH、AL)
BX(BH、BL):常用作基数寄存器(即数据段的偏移地址寄存器)
CX(CH、CL)
DX(DH、DL)

2、指针寄存器
BP:基数指针寄存器,用作堆栈段的偏移地址寄存器
SP:堆栈指针寄存器,用于堆栈段的偏移地址寄存器

3、变址寄存器
SI:源变址寄存器,与BX功能相近,但更常用于变址寻址
DI:目的变址寄存器,与BX功能相近,但更常用于变址寻址

4、4个段寄存器
CS:代码段寄存器,存放代码段的段地址
DS:数据段寄存器,存放数据段的段地址
SS:堆栈段寄存器,存放堆栈段的段地址
ES:附加数据段寄存器,当DS被占用后,可以另外使用ES来充当另外一个数据段的寄存器

5、其他
IP:指令指针寄存器(用作代码段的偏移地址寄存器)

6、状态标志寄存器
16位,有9个标志,见下文标志寄存器部分。

7、附:代码段、数据段、堆栈段
CS:IP(即物理地址为CSx16+IP)指向的指令即为当前正要执行的指令。
DS:BP(或DS:BX)指向的数据段,为当前可以读取的数据段
SS:SP指向当前正在读取的堆栈段地址。SS:SP指向的是栈顶元素。

8、附:未显式给出段寄存器时的默认段寄存器
含有BX、DI、SI的寻址,默认段寄存器为DS
含有BP的寻址(同时含有BP和BX/SI/SI也属于这种情况),默认段寄存器位SS

caller-saved(调用者保存), callee-saved(被调用者保存)的特性

二、8086执行指令的过程
从CS:IP指向的内存单元读取指令,读到指令缓冲器中。
IP=IP+指令的长度,指向下一条指令.
执行指令,转到步骤1。

三、8086PC中内存的存储方式
1、8086对字的存储方式
8086的一个内存单元为8位,1字节。对于一个字,8086采用小端模式(little-endian)在内存中存储,即一个字的高字节放到高地址,低字节放到低地址。

2、8086的物理地址
8086CPU有20位地址总线,16位数据总线。
8086的20位物理地址通过16位的段地址和16位的偏移地址合成,公式如下:
物理地址=段地址x16 + 偏移地址

四、基本汇编指令
1、数据传送指令
(1)MOV——移动指令
MOV dest,src ;(dest)=(src)
MOV指令用来完成数据移动操作
MOV指令可以完成的9种操作:
通用寄存器-->通用寄存器
立即数-->通用寄存器
立即数-->内存
内存-->通用寄存器:MOV AX,DS:[BX]
通用寄存器-->内存
段寄存器(CS/IP除外)-->内存
内存-->段寄存器(CS/IP除外)
段寄存器(CS/IP除外)-->通用寄存器
通用寄存器-->段寄存器(CS/IP除外)
MOV指令不能修改CS/IP的内容
不能直接把立即数放到段寄存器中

(2)PUSH、POP——入栈、出栈指令
入栈和出栈操作均只能以字为单位进行。
栈的格式:
栈顶:低地址
栈底:高地址
PUSH AX操作的含义:
SP=SP-2,栈顶指针空出一个字单位
将AX的内容放到SS:SP指向的单元(一个字)中,SS:SP重新指向栈顶
POP AX操作的含义:
将SS:SP指向的单元(一个字)内容送到AX中
SP=SP+2,栈顶指针向下移动一个字单位
PUSH、POP支持的操作:
PUSH/POP 通用寄存器
PUSH/POP 段寄存器
PUSH/POP 内存单元

(3)PUSHF、POPF——标志寄存器入栈、出栈指令
PUSHF——将标志寄存器的值压入栈中
POPF——从栈中弹出数据,送到标志寄存器中

2、算术运算指令
(1)ADD——加指令
ADD dest,src
加指令把右边的数加到左边的数中
其含义为(dest)=(dest)+(src)
可以完成的操作
ADD 通用寄存器,数据
ADD 通用寄存器,通用寄存器
ADD 通用寄存器,内存
ADD 内存,通用寄存器
ADD指令不能对段寄存器操作

(2)ADC——带进位加法指令
ADC dest,src
ADC指令会在执行加法时将CF位的进位值加上
其含义为:(dest)=(dest)+(src)+CF

(3)INC指令——自加1指令
INC BX,即将BX的内容自加1

(4)SUB——减指令
SUB dest,src ;(dest)=(dest)-(src)
减指令从左边的数中减去右边的数
可以完成的操作
SUB 通用寄存器,数据
SUB 通用寄存器,通用寄存器
SUB 通用寄存器,内存
SUB 内存,通用寄存器
SUB指令不能对段寄存器操作

(5)SBB——带借位减指令
SBB dest,src
SBB指令会在执行减法时将CF位的借位值减去
其含义为:(dest)=(dest)-(src)-CF

(6)DEC———自减1指令
DEC BX,即将BX的内容自减1

(7)DIV——除法指令
DIV REG/内存单元
被除数/除数=商
除数:可以为8位或者16位,放在寄存器或者内存单元中,在指令的操作数中显式给出。
被除数:根据除数的位数动态调整:
如果除数为8位,则被除数为16位,需提前放在AX中,不用在指令中给出
如果除数为16位,则被除数为32位,需提前放在DX(高16位)、AX(低16位)中,不需要在指令中给出商:
如果除数为8位,则商将放到AL中,余数将放到AH中
如果除数为16位,则商将放到AX中,余数将放到DX中

(8)MUL——乘法指令
MUL REG/内存单元
两个数相乘,要么都是8位,要么都是16位。
如果是8位一个乘数需要提前放到AL中,无需在指令中给出
另一个乘数可以放到8位寄存器或者内存单元中,需在指令中给出
结果默认放到AX中
如果是16位一个乘数需要提前放到AX中,无需再指令中给出
另一个乘数可以放到16位寄存器或者内存单元中,需在指令中给出
结果默认高位放到DX中,低位放到AX中

(9)CMP——比较指令
CMP 对象1,对象2执行对象对象的运算,但不保留运算结果,只是根据运算结果对相应的标志寄存器进行置位

3、逻辑指令
(1)AND、OR、NOT、XOR、TEST——与、或、非、异或等指令
AND AL,BL:将BL与AL的值进行按位与运算,结果存放到AL中
OR AL,BL:将BL与AL的值进行按位或运算,结果存放到BL中
XOR AL,BL:将BL与AL的值进行按位异或运算,结果存放到BL中
NOT AL:对AL各位取反,不改变标志寄存器的值
TEST AL,BL:将BL与AL的值进行按位与运算,不保存运算结果,只改变标志寄存器。
两个操作数不能同时为内存单元,不能为段寄存器
除了NOT,其他指令都会修改标志寄存器

(2)SHL、SHR——逻辑移位指令
SHL 寄存器/内存单元,1的功能:
对寄存器/内存单元的数据进行向左移位
最高位移出去的一位放到CF中
最低位缺失的位用0补充
SHR 寄存器/内存单元,1的功能:
对寄存器/内存单元的数据进行向右移位
最低位移出去的一位放到CF中
最高位缺失的位用0补充
如果移动位数大于1,则需要把移动位数放到CL寄存器中

4、转移指令
(1)JMP——无条件跳转指令
JMP 2AE3:3 ;CS=2AE3H, IP=0003H
JMP AX ;IP=AX
JMP指令用来修改CS和IP寄存器的值,即实现指令执行位置的跳转功能
JMP指令的几种形式:
段内短转移
JMP SHORT 标号:功能为(IP)=(IP)+转移距离(标号距离当前指令的距离,8位,因为是段内短转移)
段内近转移
JMP NEAR PTR 标号:功能为(IP)=(IP)+转移距离(标号距离当前指令的距离,16位,因为是段内短转移)
段间转移(远转移)
JMP FAR PTR 标号:功能为(CS)=所在段的段地址;(IP)=标号在段中的偏移地址
地址在寄存器中的转移
JMP 16位寄存器:功能为(IP)=(16位寄存器)
地址在内存的段内转移
JMP WORD PTR 内存单元地址(用[]的方式表示):功能为(IP)=该内存单元地址处存放的一个字
地址在内存的段间转移
JMP DWORD PTR 内存单元地址:功能为(CS)=(内存单元地址+2)(即内存单元地址高地址处存放的字);(IP)=(内存单元地址)(即内存单元地址低地址处存放的字)

(2)有条件跳转指令合集
1)JCXZ
形式:JCXZ 标号
功能:如果(CX)=0,则跳转到标号处(即(IP)=(IP)+转移距离(8位));否则不跳转。
所有的有条件跳转指令都只能进行短转移
以下的有条件跳转指令根据标志位的情况置位(常与CMP指令配合,根据CMP指令无符号数的运算结果置位)
2)JE
形式:JE 标号
功能:当标志位ZF=1时,转移到标号处
与CMP配合:当A=B时,跳转到标号处
CMP A B
JE 标号
3)JNE
形式:JNE 标号
功能:当标志位ZF=0时,转移到标号处
与CMP配合:当A!=B时,跳转到标号处
CMP A B
JNE 标号
4)JB
形式:JB 标号(B代表below)
功能:当标志位CF=1时,转移到标号处
与CMP配合:当A<B时,跳转到标号处(如果A<B,则A-B有借位,于是CF=1)
CMP A B
JB 标号
5)JNB
形式:JNB 标号(NB代表not below)
功能:当标志位CF=0时,转移到标号处
与CMP配合:当A>=B时,跳转到标号处(如果A>=B,则A-B无借位,于是CF=0)
CMP A B
JNB 标号
6)JA
形式:JA 标号(A代表above)
功能:当标志位CF=0且ZF=0时,转移到标号处
与CMP配合:当A>B时,跳转到标号处(如果A>B,则A-B无借位,于是CF=0;若A!=B,则ZF=0)
CMP A B
JA 标号
7)JNA
形式:JNA 标号(NA代表not above)
功能:当标志位CF=1或ZF=1时,转移到标号处
与CMP配合:当A<=B时,跳转到标号处(如果A<B,则A-B有借位,于是CF=1;若A=B,则CF=0且ZF=1。故合起来就是CF=1或ZF=1)
CMP A B
JNA 标号
(4)LOOP——循环指令
LOOP S的作用
1.(CX)=(CX)-1
2.判断(CX)是否为0,若不为零,在跳转到标号S处((IP)=(IP)+转移距离(8位)),继续执行程序,否则退出循环
所有的循环指令都只能进行短转移

(5)RET、RETF——返回指令
RET——段内转移
功能:将栈顶数据弹出,然后以栈顶数据作为偏移地址进行段内跳转
详细操作:
(IP)=((SS)*16+(SP))——利用栈顶元素修改(IP),段内跳转
(SP)=(SP)+2——弹出栈顶元素
RETF——段间转移
功能:将栈顶的两个元素先后弹出,弹出的第一个元素作为跳转的偏移地址,弹出的第二个元素作为跳转的段地址
详细操作:
(IP)=((SS)*16+(SP))——利用栈顶元素修改IP,获得偏移地址
(SP)=(SP)+2——弹出栈顶元素
(CS)=((SS)*16+(SP))——利用新栈顶元素修改CS,获得段地址
(SP)=(SP)+2——再次弹出栈顶元素
(6)CALL——调用指令
CALL 标号
功能:将当前的IP值压入栈中,然后转到标号处执行指令
详细操作:
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(IP)——IP压入栈中
(IP)=(IP)+偏移地址(16位)——跳转到标号处
CALL FAR PTR 标号
功能:先将当前的段地址CS压入栈中,然后将当前的偏移地址IP压入到栈中。最后把CS和IP修改为标号的段地址和偏移地址,实现段间转移
详细操作:
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(CS)——CS压入栈中
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(IP)——IP压入栈中
(CS)=标号所在段的段地址
(IP)=标号在段中的偏移地址
CALL 寄存器
功能:将当前的IP值压入栈中,然后转到寄存器指出的偏移地址处执行指令
详细操作:
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(IP)——IP压入栈中
(IP)=(寄存器)——跳转到寄存器偏移地址处
CALL WORD PTR 内存单元地址
功能:将当前的IP值压入栈中,然后转到内存单元指出的偏移地址处执行指令
详细操作:
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(IP)——IP压入栈中
(IP)=(内存单元)——跳转到内存单元偏移地址处
CALL DWORD PTR 内存单元地址
功能:先将当前的段地址CS压入栈中,然后将当前的偏移地址IP压入到栈中。最后把CS改为内存单元的高字,IP改为内存单元的低字,实现段间转移
详细操作:
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(CS)——CS压入栈中
(SP)=(SP)-2——栈顶空出一个元素
((SS)*16+(SP))=(IP)——IP压入栈中
(CS)=(内存单元的高字)
(IP)=(内存单元的低字)

5、串操作指令
(1)MOVSB——字节串传送指令
功能:将DS:SI指向的内存单元的一个字节的数据送入ES:DI指向的内存单元中。然后如果DF=0,则SI自增1,DI自增1;如果DF=1,则SI自减1,DI自减1
详细操作:
((ES)*16+(DI))=((DS)*16+(SI))(字节)
如果DF=0,则(SI)=(SI)+1,(DI)=(DI)+1
如果DF=1,则(SI)=(SI)-1,(DI)=(DI)-1

(2)MOVSW——字串传送指令
功能:将DS:SI指向的内存单元的一个字的数据送入ES:DI指向的内存单元中。然后如果DF=0,则SI自增2,DI自增2;如果DF=1,则SI自减2,DI自减2
详细操作:
((ES)*16+(DI))=((DS)*16+(SI))(字)
如果DF=0,则(SI)=(SI)+2,(DI)=(DI)+2
如果DF=1,则(SI)=(SI)-2,(DI)=(DI)-2

(3)REP——重复指令(与串操作指令配合使用)
REP指令要与MOVSB或者MOVSW配合使用,如下:
REP MOVSB/MOVSW
功能:重复执行MOVSB/MOVSW指令,每执行一次,CX减1。直到减到0,停止重复。
以上指令等价于:
S:  MOVSB/MOVSW
    LOOP S
REP实现了对于CX个连续单位(字节/字)的串操作,需要提前对DF位和CX进行合理设置
DF提供方向信息,CX提供长度信息

(4)CLD/STD——DF方向标志位置位指令
CLD——将DF清0
STD——将DF置1

6、中断处理指令
(1)IRET——中断返回指令
IRET的功能为,先从栈中弹出一个字到IP中,然后再从栈中弹出一个字到CS中,最后从栈中弹出一个字到标志寄存器中。
IRET相当于
POP IP
POP CS
POPF
一般将IRET放到中断程序的最后,表示退出中断程序,返回到原来程序中继续执行。

(2)INT——中断调用指令
INT N
表示引发N号中断,N为中断类型码。整个中断过程如下:
取中断类型码N
标志寄存器入栈,设置IF=0,TF=0
CS,IP先后入栈
(IP)=(N* 4),(CS)=(N* 4+2),即跳转到中断向量表指出的中断程序处执行。
在AH寄存器中需提前存放中断调用的子程序号
INT与IRET配合,类似于CALL与RET配合

(3)STI/SLI——IF位置位指令
STI——设置IF=1
CLI——设置IF=0

(4)INTO——4号中断调用指令
如果OF=1,则INTO相当于INT 4,调用溢出中断。如果OF=0,则什么都不做。

7、端口(I/O)操作指令
IN指令为从端口读入数据指令
OUT指令为从寄存器输出到端口的指令
端口号的范围只能是0~65535
当端口号为0~255时
IN AL,20H表示从20H端口读入一个字节到AL中
OUT 20H,AL表示把AL的值写入到20H端口
当端口号为256~65535时
需要先把端口号放到DX中,然后
IN AL,DX表示从DX端口读入一个字节到AL中
OUT DX,AL表示把AL的值写入到DX端口
IN/OUT指令只能使用AX或AL来存放读出或写入的数据,8位数据用AL,16位数据用AX

五、中断及中断过程
1、中断向量表
中断向量表中存放着每个中断类型码对应的中断程序入口地址。一个入口地址(中断描述符)包含4字节,前两字节为偏移地址,将被放到IP中;后两字节为段地址,将被放到CS中。将所有的入口地址以中断类型码为顺序排列为一张表,即为中断向量表。
中断向量表常存放在内存的开头,从0000:0000开始。

2、中断的过程(INTR请求)
外设通过总线向CPU发送中断请求,CPU接受到INTR信号,且如果IF=1,则响应中断
通过中断响应信号INTA(非),给出两个负脉冲。第一个负脉冲通知外设已受理中断。在第二个负脉冲后,外设通过低8位数据总线,发出中断类型码。CPU收到后,对其进行暂存
保护现场:将标志寄存器的值入栈
避免冲突:将现在标志寄存器的TF、IF设为0
保护现场:将CS、IP先后入栈
根据中断类型码N,在中断向量表中读取对应的中断程序入口地址,并存放到IP和CS中。(IP)=(N* 4),(CS)=(N* 4+2)

3、外中断
(1)可屏蔽中断
由外设通过端口发出的中断类型之一,当IF=0时,可以屏蔽该中断。
其中断过程与内中断基本一致。

(2)不可屏蔽中断
CPU不可屏蔽、必须响应的外中断,中断类型码固定为2,无需取中断类型码。

六、标志寄存器
8086的标志寄存器有16位,其中有9位是有用的,称为9个标志。
1、ZF标志位——zero flag零标志位
相关指令执行后,如果结果位0,则ZF=1;否则ZF=0

2、PF标志位——parity flag奇偶标志位
相关指令执行后,如果结果中1的个数为偶数,则PF=1;如果是奇数,则PF=0

3、SF标志位——signal flag符号标志位
相关指令执行后,如果结果为负数(即结果的最高位为1),则SP=1;如果结果为正数(即结果的最高位为0),则SP=0
在计算机中,不对有符号数和无符号数进行区分,计算机统一当作无符号数进行运算(不管符号位),结果根据需求人为地解读成有符号数或者无符号数
如果要把结果解读成无符号数,则SF位是没有用的;如果要把结果解读成有符号数,则SF位有用。SF一直等于结果的最高位。

4、CF标志位——carry flag进位标志位
在相关指令执行后,在进行无符号运算时,如果加法有进位、或者减法有借位,则CF=1;否则CF=0
注意:这里的加减运算完全按照无符号数规则进行运算,不管符号位,算出多少就是多少

5、OF标志位——overflow flag溢出标志位
在相关指令执行后,在进行有符号运算时,如果有溢出(8位有符号运算超出了-128~127的范围,16位有符号数运算超出了-32768~32767的范围。或者两个正数加出了负数,两个负数加出了正数),则OF=1;否则OF=0
判断溢出的方法(方法1):
(方法1)对需要运算的两个操作数当作无符号数进行简单加减运算,如果两个操作数的最高位均为1,且运算结果最高位为0;或者两个操作数的最高位均为0,且运算结果最高位为1,则发生了溢出,OF=1;否则OF=0
(方法2)如果两个待运算的操作数的最高位为一0一1(一正一负),则需要用此方法。首先将待运算的两个操作数当作补码,还原为两个有符号原码(如果是正数,则补码就是原码;如果是负数,最高符号位不变,其他位取反,然后加1),然后将两个有符号原码化为十进制,进行带符号的运算,查看运算结果。如果运算结果不在(8位运算)或(16位运算)范围内,则发生了溢出,OF=1,否则OF=0

6、DF标志位——direction flag方向标志位
在串操作中,指示串操作方向的标志位。
如果DF=0,则SI、DI在串操作后自增
如果DF=1,则SI、DI在串操作后自减

7、TF标志位——Tracking flag跟踪标志位
用于单步跟踪调试的标志位
如果TF=1,则CPU在每执行完一条指令后就触发单步中断
如果TF=0,则不会单步中断。
8086要求在进入中断处理程序之前,把TF设为0,避免反复调用导致死循环。

8、IF标志位——Interruption enabled flag中断允许标志位
当IF=0时,不响应可屏蔽中断
当IF=1时,响应可屏蔽中断

六、寻址方式
摘自王爽汇编语言

七、MASM汇编的基本语法
1、简化段MASM程序的基本结构
ASSUME CS:CODE,DS:DATA,SS:STACK
;令CODE段与CS寄存器相关联,DATA段与DS寄存器相关联,STACK段与SS寄存器相关联

DATA SEGMENT ;定义DATA段开始
    ....
DATA ENDS ;DATA段结束

STACK SEGMENT ;定义STACK段开始
    ....
STACK ENDS ;STACK段结束
CODE SEGMENT ;定义CODE段开始
START:  MOV AX,0123H ;程序从这里开始
        ......

        MOV AX,4C00H
    I   NT 21H ;程序返回
CODE ENDS ;CODE段结束
END START;程序结束

2、几个重要规则
在简化段中,程序加载后,从DS:0开始为存储的整个MASM程序(包含代码段、数据段、堆栈段),其中前面的256个字节为PSP,因此真正的程序位于CS:0处(包含代码段、数据段、堆栈段,与我们定义的顺序前后有关),其中CS=DS+10H。
我们在定义ASSUME CS:CODE,DS:DATA后,并不意味着CS中存储了CODE段的段地址,DS存储了DATA段的段地址。ASSUME知识将段和寄存器关联起来。
各个段的段名,如CODE、DATA、STACK等本身即为该段的段地址

在写汇编程序时,需要首先完成的步骤:
初始化CS:IP:使用START: END START标号对程序的起始位置进行定义
初始化DS:BX:使用MOV AX,DATA MOV DS,AX MOV BX,0等代码对数据段的位置进行定义
初始化SS:SP:使用MOV AX,STACK MOV SS,AX MOV SP,...,对堆栈段的位置进行定义,使得SS:SP指向堆栈的栈顶。
3、伪指令和操作符
以下定义数据在内存中的存放方式均遵循小端(little-endian)方式
DW:以字为单位在内存中定义数据
DB:以字节为单位在内存中定义数据,也可以定义字符串,需要拿单引号将字符串包起来,每一个字符即为一个ASCII码字节。
DD:以双字为单位在内存中定义数据
WORD/BYTE PTR:指明内存单元操作数的长度,WORD表示长度为字,BYTE表示长度为字节。
DUP:用来定义重复数据,如:DB 3 DUP(0,1,2)即表示DB 0,1,2,0,1,2,0,1,2
OFFSET:取标号的偏移地址。如:MOV AX,OFFSET S相当于把标号S的偏移地址放到AX寄存器中。
4、其他语法细则
汇编程序中,数据不能以字母开头,如A123H必须写为0A123H
在需要暂存数据时(当寄存器数量不够时),常用堆栈来暂存
8086CPU中,只有BX、SI、DI、BP可以用来进行寻址
编译器可以直接处理简单的加减乘除表达式,比如5-2+3可以作为操作数出现在汇编程序中

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值