8086汇编程序设计
Published: 5/5/2024
8086
8086是Intel最早推出的X86 16位CPU之一,使用20位地址总线,寻址空间为1MB,共有14个寄存器,其中包含8个通用寄存器,4个段寄存器,1个PC寄存器,1个PSW寄存器。
寄存器
通用寄存器
通用寄存器有AX,BX,CX,DX,BP,SP,SI,DI
共8个寄存器。即使说是通用寄存器,大多数通用寄存器仍然具有使用规范,包括:
- 只有BX和BP用作基地址寻址,因此这两寄存器又被称为基址寄存器,只是BX默认相对于DATA段,而BP默认相对于堆栈段寻址。
- CX用于各种循环指令和重复指令中,根据PSW中的ZF标志位决定加减。
- AX常被用于乘除法的第一个操作数,DX被用来作为AX的高位,在16x16位乘法中
MUL SRC
表示AX * SRC
,结果为DX:AX
总计32位;在32/16位除法中,DIV SRC
表示DX:AX
表示的32位数字除以16位SRC
。 - SI与DI寄存器常被用于串指令中,用于表示串的当前位置。
- SP寄存器表示堆栈栈顶,BP用于非叶子程序参数传递。
需要注意前面四个16位寄存器更多被称为数据寄存器,每个寄存器可以分为2个对应位置的高八位寄存器和低八位寄存器,比如AX可分为高AH和低AL寄存器;后四个16位寄存器更多被称为指针寄存器,且不可像之前那样被分割。
段寄存器
然后就是4个段寄存器SS,DS,CS,ES
分别表示堆栈段,数据端,代码段和附加段;附加段主要用于串指令配合SI
与DI
使用。需要注意在8086中每个段寄存器都需要在程序开始时显式使用指令进行初始化,需要注意段寄存器不能用立即数初始化。
PC寄存器与PSW寄存器
PC寄存器(或者说是IP寄存器,我更喜欢称为PC寄存器)用于表示当前指令地址;PSW寄存器是一个标志位寄存器,用于存储指令在执行过程中产生的各种标志,包括溢出,进位,负数,中断,异常等。
指令集
8086的指令采取OP [DST[,SRC]]
的形式,并且是不定长的CISC指令集。
主要可分为 数据传送指令,逻辑指令,算数指令,串指令 ,循环控制指令以及中断相关指令。
数据传送
最常使用的是MOV DST,SRC
指令,用于将数据复制到另一个地方,这里需要注意传送双方的位长匹配问题,尤其是立即数向内存之间的传递,比如MOV S,0H
就应该改成MOV WORD PTR S,0H
,需要确定所使用内存的字长,并且传送时也应该注意数据的大小不能超过字长。
逻辑指令
主要有AND,OR,XOR,NOT
,指令格式都为OP DST,SRC
。
算数指令
主要有ADD,ADC,INC,DEC,SBB,SUB,NEG
,其中INC <T>
,DEC <T>
分别表示进一和减一。ADD,SUB不带进位和借位,而ADC与SBB则带进位,也就是操作时会带上标志位CF
。NEG指令用于取补码。
移位指令总共有8条,包括算数,逻辑,循环以及进位循环,分别是SHL,SAL,SHR,SAR,ROL,ROR,RCL,RCR <dst>,<count>
需要注意count只能是1或者是CL寄存器,并且会将其移出的位保存在CF标志位中。
串指令
串指令主要用于操作串,指令主要有MOVS,LODS,STOS,CMPS,SCANS
;
LODS用于取出DS:[SI]内存到AL或者AX寄存器中,并将SI + 1或 + 2,STOS功能类似。
MOVS用于将DS:[SI]传送到ES:[DI]中,并将SI与DI同时加1或加2.
CMPS用于比较原串与目标串,SCANS用于扫描目标串中是否出现AL或者AX中指定的字符。
上面的指令根据DF标志位,使用CLD或者STD修改。
重复指令用于配合串指令使用,有REP,REPZ,REPNZ
。REP 串指令会重复执行,并且不断将CX寄存器减1,直到CX位0停止。
REPZ则直到ZF为1并且CX为0,REPNZlei’si
LEA用于加载指定地址偏移到寄存器;LDS,LES分别用于将双字内容存放到对应段寄存器和指定寄存器。
跳转与循环指令
跳转指令主要分为无条件跳转和有条件跳转。
无条件跳转使用JMP <ADDR>
。
有条件跳转根据PSW中的标志位决定是否跳转,主要有JZ/JE, JNE,JAE,JBE TEST
。x86的一个特点是有循环指令,包括LOOP,LOOPE,LOOPNE
,LOOP <label>
会将CX - 1,如果不为0则跳转到label处。
CALL <proc>
用于调用子程序,RET <2N>
用于从子程序返回并修复栈。
中断指令
通过INT <X>
传入中断号进入中断,通过IRET
从中断返回。功能调用通过INT 21H
,通过AH传入功能调用号,常用的功能调用有:
- 01 输入字符并回显
MOV AH,1
INT 21H
输入的符号被存储AL寄存器中。
- 02 输出字符
MOV AH,2
MOV DL,'A'
INT 21H
需要输出的字符需要被存放在DL寄存器中。
- 09 输出字符串,必须以
$
结尾
MOV DX,OFFSET STR1
MOV AH,09H
INT 21H
将字符串地址存放在DX中,使用DS段寄存器。
- 0AH 输入字符串
MOV AH,0AH
MOV DX,OFFSET BF1
INT 21H
将缓冲区地址存放在DX中,第一个字节存放缓冲区最大长度,在返回后,第二个字节存放读取长度,之后才是读取到的字符串内容。
- 4CH 返回命令行
MOV AX,4CXXH
INT 21H
AL表示返回值,AH传递4CH功能调用号。
寻址方式
对于数据的寻址方式,总共有6种:
- 立即数寻址:
MOV AX,01H
,指令所需操作数直接出现在指令中。 - 直接寻址:
MOV AX,[01H]
:操作数的偏移地址直接出现在指令中。 - 寄存器直接寻址:
MOV AX,BX
,操作数是某个寄存器。 - 基址变值寻址:基址寄存器加上变址寄存器如
MOV AX,[BX][SI]
- 寄存器间接寻址: 操作数地址位于基址寄存器或变址寄存器中,如
MOV,AX,[BX]
- 寄存器相对寻址:
MOV AX,[BX + 2]
对于地址的寻址方式,总共有4种:
- 段内直接跳转:
JMP LABEL
SP - 2; SS:[SP] <- 返回地址 - 段内间接跳转
JMP WORD PTR <ADDR>
SP - 2; SS:[SP] <- 返回地址 - 段间直接跳转
JMP FAR LABEL
SP - 2; SS:[SP] <-段地址; SP - 2 ; SS:[SP] <- 返回地址 - 段间间接跳转
JMP DWORD PTR <ADDR>
(IP <- ADDR, CS<- DS:[ADDR + 2]) SS:[SP] <-段地址; SP - 2 ; SS:[SP] <- 返回地址
程序结构
一个8086汇编程序主要有代码段,数据段,堆栈段组成,类似于
DATA_S_NAME SEGMENT PARA
T1 EQU 1H
T2 DB 0FFH
T3 DW 100
DB 10H
T4 DD 100H DUP(0)
DATA_S_NAME ENDS
STACK_S_NAME SEGMENT PARA STACK
STACK_AREA DW 100H DUP(?)
STACK_BTM EQU $ - STACK_AREA
STACK_S_NAME ENDS
CODE_S_NAME SEGMENT PARA
ASSUME CS:XX,DS:XX,SS:XX,ES:XX
MAIN PROC FAR
...
MAIN ENDP
CODE_S_NAME ENDS
END MAIN
-
使用
SEGMENT
与ENDS
定义段,最后在代码中对段寄存器初始化。PARA
让段能够256字节对齐,还有BYTE,PAGE这些选项。 -
使用
END MAIN
来指定程序入口为MAIN子程序。 -
通过
PROC
与ENDP
定义子程序,如果使用FAR
为段间定义,否则为NEAR
则是段内定义。
子程序与宏定义
子程序和宏相比总的程序占用空间更小,但是宏不需要使用堆栈。
子程序
通过PROC
与ENDP
来定义子程序,通过CALL
调用子程序,通过RET <2n>
从子程序返回并修复堆栈。可以使用堆栈来传递参数,比如在调用前使用堆栈存放参数,在子程序中使用BP保存传入时的SP寄存器,通过BP来访问参数,最后通过RET修复堆栈,这一过程需要注意BP的保存和修复。
宏
通过MACRO
与ENDM
来定义宏,宏可以传递参数,如果定义时给定形参,则使用时必须给定实参。
结构体
使用STRUC
与ENDS
来定义结构体数据结构,使用类似于定义段内变量的方式定义结构体的成员变量,使用时使用.
操作符号。
调试
使用debug进行调试
-
A <ADDRESS>
: 修改对应地址的汇编 -
U <ADDRESS>
:反汇编指定地址。 -
G <ADDRESS>
: 执行到对应地址 -
T
逐条指令追踪 -
D <ADDRESS>
导出对应地址的内存 -
E <ADDRESS>
修改对应地址的内存 -
R <reg>
查看或修改对应寄存器的值
PSW寄存器的具体内容
- CF: 进位标志,如果最高位产生了进位,则为1;或者移位时被移除的位。
- PF: 用来对数据提供奇偶校验值,对低8位进行检验。
- ZF:0标志位,如果运算结果为0则为1.
- TF:陷阱标志位,用于调试
- IF:中断标志位,IF为1则允许中断。
- DF:用于控制串操作指令的方向,使用CLD和STD指令设置0和1。
- OF:溢出标志,如果超过机器的补码范围,则为1.
- SF:用于记录运算结果的符号,为负数则为1.、
- AF:辅助进位标志。