汇编语言
汇编语言
寄存器
对于8086、8088或80286,阴影区域是不可用的
FS和GS寄存器无专用名称
-
通用寄存器
- 数据寄存器:AX(accumulator)、BX(base)、CX(count)、DX(data)
- 指针寄存器:SP(stack pointer)、BP(base pointer)
- 变址寄存器:DI(destination index)、SI(source index)
-
控制寄存器
- IP(instruction pointer)、FLAGS
-
段寄存器
- CS(code segment)、DS(data segment)、ES(extra segment)、SS(stack segment)
-
标志寄存器
- OF溢出标志,运算过程溢出置1,否则置0
- SF符号标志,结果为负置1,否则置0
- ZF零标志,运算结果为0置1,否则置0
- CF进位标志,e.g.加法运算中,有进位置1,否则置0
- AF辅助进位标志,记录运算时第三位产生的进位值
- PF奇偶标志。结果操作数中1个数为偶置1,否则置0
标志位
| 标志名 | 标志为1 | 标志为0 |
|---|---|---|
| OF 溢出(是/否) | OV | NV |
| DF 方向(减量/增量) | DN | UP |
| IF 中断(允许/关闭) | EI | DI |
| SF 符号(负/正) | NG | PL |
| ZF 零(是/否) | ZR | NZ |
| AF 辅助进位(是/否) | AC | NA |
| PF 奇偶(偶/奇) | PE | PO |
| CF 进位(是/否) | CY | NC |
80x86寻址方式
与数据有关的寻址方式
-
立即寻址方式(immediate addressing)
MOV AL,5MOV AX,3064HMOV EAX,12345678H
-
寄存器寻址方式(register addressing)
MOV AX,BXMOV ECX,EDX
-
直接寻址方式(direct addressing)
MOV AX,[2000H]MOV AX,VALUE等价MOV AX,[VALUE]MOV AX,ES:VALUE(段跨越前缀,默认为DS)
-
寄存器间接寻址方式(register indirect addressing)
MOV AX,[BX]MOV AX,ES:[BX](段跨越前缀,默认为DS)
使用BP、SP时,默认段位SS。其他寄存器的默认段位DS寄存器。
-
寄存器相对寻址方式(register relative addressing)(或称直接变址寻址方式)
MOV AX,COUNT[SI]等价于MOV AX,[COUNT+SI]MOV DL,ES:STRING[SI]
-
基址变址寻址方式(based indexed addressing)
MOV AX,[BX][DI]等价于MOV AX,[BX+DI]MOV AX,ES:[BX][DI]
-
相对基址变址寻址方式(relative based indexed addressing)
MOV AX,MASK[BX][SI]
-
比例变址寻址方式(scaled indexed addressing)
-
机制比例变址寻址方式(based scaled indexed addressing)
-
相对基址比例变址寻址方式(relative based scaled index addressing)
与转移地址有关的寻址方式
- 段内直接寻址(intrasegment direct addressing)
- 段内间接寻址(intrasegment indirect addressing)
- 段间直接寻址(intersegment direct addressing)
- 段间间接寻址(intersegment indirect addressing)
指令
数据传送指令
通用数据传送指令
-
MOV
MOV DST,SRC将SRC内容传送至DST
双操作数指令不允许两个操作数都使用存储器,必须有一个是寄存器
DST不允许是立即数、不允许是CS寄存区(代码段)
-
MOVSX
MOVSX DST,SRC,带符号拓展传送指令
-
MOVSX
MOVZX DST,SRC,带符号拓展传送指令
-
PUSH
PUSH SRC:先移动指针,后压入数据(所以压完数据后,指针是指向着该数据的)
-
POP
POP DST:先弹出数据,后移动指针
-
PUSHA/PUSHAD,所有寄存器进栈指令
-
POPA/POPAD,所有寄存器出栈指令
-
XCHG
XCHG OPR1,OPR2,由于是双操作数指令,必须有一个在寄存器中
累加器专用传送指令
- IN
- OUT
- XLAT
地址传送指令
- LEA
LEA REG,SRC,指令把原操作数的有效地址送到指定的寄存器中(用于获得地址的)
- LDS、LES、LFS、LGS、LSS
标志寄存器传送指令
- LAHF、SAHF、PUSHF/PUSHFD、POPF/POPFD
类型转换指令
- CBW,字节转换为字
- CWD/CWDE,字转换为双字
- CDQ,双字转换为4字
- BSWAP,字节转换为字指令
算术指令
加法指令
ADD、INC常用
除INC外,其余指令影响标志位
- ADD
ADD DST,SRC
- ADC
ADC DST,SRC,带进位加法
- INC
INC OPR,加一
- XADD
XADD DST,SRC- 执行操作:
TEMP←(SRC)+(DST),(SRC)←(DST),(DST)←TEMP
加法指令(除INC指令)会影响标志位,CF位可表示无符号数的溢出,OF位可表示带符号数的溢出
故,若是无符号数的加法运算下,CF=1,则运算错误;若是带符号数的加法运算,OF=1,运算错误。
INC不会影响CF标志位
减法指令
SUB、DEC、CMP常用
除DEC外,其余指令均影响CF标志位
- SUB
SUB DST,SRC,执行(DST)←(DST-SRC)操作
- SBB
SBB DST,SRC,带借位减法指令,执行(DST)←(DST)-(SRC)-CF操作
- DEC
DEC OPR,减一指令,执行(OPR)←(OPR)-1操作
- NEG
NEG OPR,求补指令,执行(OPR)←-(OPR)操作(或表示为(OPR)←0FFFH-(OPR)+1)
- CMP
CMP DST,SRC,执行(DST-SRC)操作,不保存结果,但影响标志位CF,后常接跳转指令
CF位表示无符号数的溢出,OF代表带符号位数的溢出。
故,减法中:无符号数减法,被减数-减数 < 0,CF设置为1(“不够减”),否则为0;带符号数减法,若被减数与减数符号相同,减后结果符号与被减数(或减数)相反,则OF设置为1,其余情况为0。
乘法指令
- MUL
MUL SRC,无符号乘法,执行操作如下:- 字节操作数:
(AX)←(AL)*(SRC) - 字操作数:
(DX,AX)←(AX)*(SRC) - 双字操作数:
(EDX,EAX)←(EAX)*(SRC)
- 字节操作数:
- 执行操作视SRC类型而定
- IMUL
IMUL SRC,带符号乘法,执行操作与MUL指令一致
以使用MUL指令、SRC是AL为例,若结果(AX)的高8位为0,则CF位和OF位均为0,否则CF、OF位均设置为1
乘法指令中,CF、OF标志位可用于检查字节相乘的结果是字节还是字、字相乘的结果是字还是双字、……
除法指令
- DIV
DIV SRC,无符号数除法,执行操作如下:- 字节操作:
(AL)←(AX)/(SRC)的商,(AH)←(AX)/(SRC)的余数 - 字操作:
(AX)←(DX,AX)/(SRC)的商,(DX)←(DX,AX)/(SRC)的余数 - 双字操作:
(EAX)←(EDX,EAX)/(SRC)的商,(EDX)←(EDX,EAX)/(SRC)的余数
- 字节操作:
- IDIV
IDIV SRC,带符号数除法,执行操作同上
逻辑指令
逻辑运算指令
NOT的操作数不能是立即数,其余指令DST必须是寄存器
- AND
AND DST,SRC,逻辑与,执行(DST)←(DST)⋀(SRC)操作
- OR
OR DST,SRC,逻辑或,执行(DST)←(DST)⋁(SRC)操作
- NOT
NOT OPR,逻辑非,执行(DST)←(OPR)的非操作
- XOR
OR DST,SRC,异或,执行(DST)←(DST)与(SRC)的异或操作
- TEST
TEST OPR1,OPR2,测试,执行(DST)⋀(SRC)操作
位测试并修改指令(略)
- BT
- BTS
- BTR
- BTC
位扫描指令(略)
- BSF
- BSR
移位指令
-
移位指令
-
SHL
-
SAL
-
SHR
-
SAR
-
-
循环移位指令
-
ROL
-
ROR
-
RCL
-
RCR
-
-
双精度移位指令
-
SHLD
-
SHRD
-
串处理指令(略)
- MOVS
- CMPS
- SCAS
- LODS
- STOS
- INS
- OUTS
与上述配合使用前缀有
- REP
- REPE/REPZ
- REPNE/REPNZ
控制转移指令
无条件转移指令
JMP跳转指令
JMP SHORT OPRJMP NEAR PTR OPR
条件转移指令
条件设置指令(略)
循环指令
子程序
汇编语言程序(练习)
把BX寄存器内的二进制数以十六机制的形式在屏幕上打印
-
在
print_loop中:-
rol bx, 4会将BX循环左移4位,比如原先为0010,1010,1111,0011B则变为1010,1111,0011,0010B,也就是原先的最高的4位到了BX的末尾的4位上 -
下一步——使用
mov al, bl指令将bl内容移动至al(bl是bx的后八位) -
由于一个十六进制数需要4位进行表示,所以此时al中的高4位是不需要的,使用
and al, 0Fh指令对高四位进行消除 -
处理得到
0000????这样一个低四位有效的al后,要判断al是属于0-9还是A-F -
al的数值有效范围是0-15,若是0-9,直接打印(后续加上’0’即可)
-
-
若是10-15,先加上7(这样的话,后续也加上’0’,就能对应上ASCII的’A’-‘F’)
-
-
关于在屏幕上打印(固定语句)
1 | prognam segment ; 定义一个名为 prognam 的段(Segment) |
从键盘接受十六进制数并存入BX
- 关于从屏幕输入
-
- 关于输入的数字的判断——判断是属于’0’-‘9’还是’A’-‘F’(后续还可以拓展为’a’-‘f’)
-
- 首先我们从屏幕输入的都是ASCII,比如输入的是’0’,实际上al中的十进制值是48,故减去48以使其范围落到数值0-9(若不是后续判断)
-
-
1 | prognam segment ; 定义代码段 |
往有序数组中插入数据
- 已知是一个有限数组,要求插入一个数据,思路是从后向前找
- 逐个比较,每次比较时,若待插入数小于当前数,则将当前位置的数后移
1 | datarea segment |
冒泡排序
1 | datarea segment |
例5.5
1 | datarea segment |
折半查找(二分)
1 | data segment |
已做实验
1.1:在数据段DATA中有两个字数据X和Y, 假设X=1122H,Y=3344H, 编程求两个字的和,结果存放到Z单元中。
1.2:从SOURCE_BUFFER单元开始存放了20个字母A, 编程将这20个字母A的字符串传送到DEST_BUFFER开始的单元中。
2.1:计算1+2+3+…+10,将结果显示在屏幕上。对1-10求和、将结果打印(这个比较关键、利用除法进行输出)(div指令的商在AX、余数在DX)(所以每次得到一个DX就进行PUSH、并同时用CX记录位数)(最后POP DX即可输出——记得转成ascii)
1 | MOV AH, 1 ; AH存入子功能号1 |
2.2:利用01H号功能调用输入10个一位数字,将其由数字字符转换为相应整数,并依次保存到字节变量BUF。编程求出这10个数中的最大数和最小数,分别存入字节变量MAX和MIN,并分别将其在屏幕上显示出来。
1 | MOV AH, 2 ; AH存入子功能号2 |
2.3:输入一个不大于65535的十进制非负整数,判断其是否为素数,如果是素数,输出字符串“It’s a prime.”,否则输出字符串“It’s not a prime.”。
1 | 数据段: |
3.1:从键盘上输入多个长度小于30的字符串,直到输入空行为止,将其中最长的一行字符串显示输出。
要求:(1)定义子过程GETS,实现从键盘输入字符串到参数数组中,读取包括空格在内的所有字符,直到遇到换行符为止,在字符数组中以‘\0’字符作为字符串末尾标记,该过程的返回值为输入的字符串的长度,返回值用寄存器AX传递。
(2)定义子过程PUTS,实现输出参数数组中的字符串,该过程的返回值为输出的字符个数,返回值用寄存器AX传递。
(3)定义主过程MAIN,调用两个子过程实现程序功能。
(4)输入一个字符通过调用21H号DOS中断的1号功能,输出一个字符通过该中断的2号功能调用。
3.2:编写十进制数到十六进制的转换程序。用户从键盘输入一个十进制无符号整数,然后把该数以十六进制形式(包括后缀字符H)在屏幕上显示出来。
要求:(1)定义两个子过程INPUT和OUTPUT。过程INPUT实现键盘输入一个十进制无符号整数,存入寄存器BX。过程OUTPUT实现以十六进制形式(包括后缀字符H)在屏幕上输出寄存器BX的值。
(2)定义主过程MAIN调用两个子过程实现程序功能。
other
自写:输入一连串数字保存、再输出(每个位上+1)
1 | ; multi-segment executable file template. |





