这组指令主要分为逻辑指令、位移指令和循环指令三个部分。
逻辑指令
逻辑指令中,除 NOT 指令不影响标志位,其他逻辑指令都会影响标志位。指令执行之后会使 CF 和 OF 清 0,PF、ZF、SF反映运算结果。
NOT(取反)
指令格式:
NOT OPRD
这条指令把 OPRD 取反,然后再送回 OPRD
范例:
NOT AX
NOT VAR
AND(与)
指令格式:
AND OPRD1,OPRD2
使用逻辑 “与” 运算,将结果传送到目的操作数 OPRD1
范例:
AND DH,DH
AND AX,ES:[SI]
常见用途:
保证操作数不变的情况下,让 CF 位清 0
将一个字节数据的高 4 位置 0
OR(或)
指令格式:
OR OPRD1,OPRD2
使用逻辑 “或” 运算,结果送到目的操作数 OPRD1
范例:
OR AX,8080H
OR CL,AL
OR [BX-3],AX
MOV AL,41H
OR AL,20H
XOR(异或)
指令格式:
XOR OPRD1,OPRD2
常见用途:
操作数和 CF 位同时置 0
将一个字节数据的低 4 位取反
TEST(测试指令)
指令格式:
TEST OPRD1,OPRD2
使用逻辑 “与” 运算,只影响标志位,不会改变 OPRD1。
常见用途:
判断某个位是否为1
判断这个值是否为0
test 指令没有改变操作数,不完全属于逻辑运算指令。
位移指令
所有位移指令如果位移多位,需要将移位位数存放在 CL 寄存器中。
SAL/SHL(算数左移指令/逻辑左移指令)
算数左移和逻辑左移的硬编码相同,没有区别。根据编译器的不同,它只会选择一种汇编指令编译。
指令格式:
SAL OPRD,m
SHL OPRD,m
判断某个位是否为1
乘法运算:计算4*2
SAR(算数右移指令)
指令格式:
SAR OPRD,m
操作数右移m位,同时每一栋一位,左边符号位保持不变,移出的最低位进入标志位CF。
范例:
SAR AL,1
SAR BX,CL
对于有符号数而言,算数右移一位相当于除以2
不建议用在无符号数,容易出错。
SHR(逻辑右移指令)
指令格式:
SHR OPRD,m
范例:
SHR BL,1
SHR AX,CL
对于无符号数而言,逻辑右移相当于除以2
循环位移指令
8086 有四条循环位移指令:ROL(左循环位移),ROR(右循环位移),RCL(带进位左循环位移),RCR(带进位右循环位移)。
ROL(左循环位移指令)
每移位一次,操作数左移,其最高位移入最低位,同时最高位也移入进位标志 CF
ROR(右循环位移指令)
每移位一次,操作数右移,其最低位移入最高位,同时最低位也移入进位标志 CF
RCL(带进位左循环位移指令)
每移位一次,操作数左移,其最高位移入进位标志 CF,CF 移入最低位。
RCR(带进位右循环位移指令)
每移位一次,操作数右移,其最低位移入进位标志 CF,CF 移入最高位。
转移指令
无条件转移指令
指令格式:
jmp 标号
条件转移指令分为段内转移和段间转移。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ;程序名:jmp1.asm ;测试转移指令 ;=============================
assume cs:code
code segment start:
N: mov ax,0 mov bx,0 jmp S P: add ax,1 S: jmp O inc ax inc ax O: mov ax,4c00h int 21h code ends end start
|
段内转移
段内转移的范围是 -128~127,默认使用一个字表示地址差。
使用 “标号” 进行跳转
“jmp+标号” 硬编码是 “EB+地址”,默认地址是一个字大小,不足一个字会使用 90 填充。
如果确认一个字节可以表示地址差,那么可以在标号前使用 short 表示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ;程序名:jmp2.asm ;测试转移指令 ;=============================
assume cs:code
code segment start:
N: mov ax,0 mov bx,0 jmp short S P: add ax,1 S: jmp short O inc ax inc ax O: mov ax,4c00h int 21h code ends end start
|
由此可见,在当时硬盘和内存还很小的情况下,编写程序使用 short 可以节省一些硬盘和内存空间。
使用 “存储单元” 进行跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ;程序名:jmp3.asm ;转移指令 ;=============================
assume cs:code,ds:data
data segment addr dw 0eh data ends
code segment start: mov ax,data mov ds,ax N: mov ax,0 mov bx,0 jmp addr P: add ax,1 S: jmp O inc ax inc ax O: mov ax,4c00h int 21h code ends end start
|
使用存储单元跳转是直接,将内存数据传输到 IP 寄存器中。如果要这样写,需要手动计算 IP 的值,很容易出错。
使用 “$+立即数” 进行跳转
“$“ 伪指令表示 IP 寄存器的值。使用 “jmp $+立即数” 可以跳转到相应地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ;程序名:jmp$.asm ;转移指令 ;=============================
assume cs:code,ds:data
data segment addr dw 0eh data ends
code segment start: mov ax,data mov ds,ax N: mov ax,0 mov bx,0 jmp $+5 P: add ax,1 S: jmp O inc ax inc ax O: mov ax,4c00h int 21h code ends end start
|
段间直接转移
段间间接转移
条件转移指令
循环指令
条件转移指令和无条件转移指令可以实现循环,但为了方便循环指令的实现,8086 还提供了四条循环指令。
循环指令不影响各标志位
LOOP(计数循环指令)
LOOPE/LOOPZ(等于/全零循环指令)
LOOPNE/LOOPNZ(不等于/非零循环指令)
JCXZ(跳转指令)
代码补充
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| ;程序名:shr.asm ;功能:假设 DATA1 和 DATA2各长4位,分别存放在 AL 寄存器的低 4 位和高 4 位中, ;现在要把它们分别存放在BL寄存器和BH寄存器的低 4 位 ;========================================================================== assume cs:code,ds:data
data segment DATA1 db 08h DATA2 db 04h data ends code segment start: mov ax,data mov ds,ax ; mov ax,0 mov cl,4 ; mov al,DATA1 shl al,cl or al,DATA2 mov bl,al shl bx,cl shr bl,cl ; mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| ;程序名:ROL.asm ;功能:实现把AL的高4位与低4位交换。 ;================================
assume cs:code
code segment start: xor ax,ax mov al,37h mov cl,4 rol al,cl ; mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| ;程序名:ROR.asm ;功能:实现把AL的最低位送入BL的最低位,仍保持AL不变 ;=================================================
assume cs:code
code segment start: xor ax,ax xor bx,bx mov al,29h mov bl,28h ; loop1: ror bl,1 ror al,1 rcl bl,1 rol al,1 ; mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| ;程序名:yiwei.asm ;功能:设DATA1存放在AL的低4位,DATA2存放在AH的低4位,DATA3存放在SI的低4位,DATA4存放在SI的高4位。 ; 现在要把这四个数据合并为16位,并存放到DX寄存器中。
assume cs:code,ds:data
data segment DATA1 db 1 DATA2 db 2 DATA3 db 3 DATA4 db 4 data ends
code segment start: mov ax,data mov ds,ax ; mov cl,4 mov al,DATA1 mov ah,DATA2 mov bl,DATA3 mov bh,DATA4 shl bh,cl mov si,bx xor bx,bx ; rol ax,cl shr ah,cl or ah,al ; mov dx,si shl dl,cl shr dh,cl or dl,dh mov dh,ah ; mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ;程序名:jae.asm ;功能:比较两个无符号数的大小,较大的数存放在 AX 中,较小的数存放在 BX 中 assume cs:code,ds:data
data segment num1 dw 24 num2 dw 35 data ends
code segment start: mov ax,data mov ds,ax ; mov ax,num1 mov bx,num2 cmp ax,bx jae stop xchg ax,bx stop: mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ;程序名:jge.asm ;功能:比较两个无符号数的大小,较大的数存放在 AX 中,较小的数存放在 BX 中 assume cs:code,ds:data
data segment num1 dw 24 num2 dw 35 data ends
code segment start: mov ax,data mov ds,ax ; mov ax,num1 mov bx,num2 cmp ax,bx jge stop xchg ax,bx stop: mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| ;程序名:loop.asm ;功能:十六进制数转换成ASCII输出 ;============================= assume cs:code,ds:data
data segment val dw 0A2B4h result db ?,?,?,?,'H',24H data ends
code segment start: mov ax,data mov ds,ax xor si,si mov cx,4 mov ax,val[si] ; loop_start: push cx mov cl,4 rol ax,cl push ax and al,0fh cmp al,9 jnb char add al,30h mov result[si],al jmp loop_end ; char: add al,37h mov result[si],al ; loop_end: pop ax pop cx inc si loop loop_start ; mov dx,offset result mov ah,9 int 21h ; mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ;程序名:loop1.asm ;功能:把从偏移 1000H 开始的 512 个字节的数据复制到从偏移 3000H 开始的缓冲区中 assume cs:code
code segment start: mov si,1000H mov di,3000H mov cx,512 next: mov al,[si] inc si mov [di],al inc di loop next ; mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| ;程序名:loopz.asm ;功能:查找第一个非 'A' 字符,找到 BX 保存该字符的偏移地址,找不到 BX=0FFFFh ;========================================================================= assume cs:code,ds:data
data segment val db 'AAAAAAAA',24h data ends
code segment start: mov ax,data mov ds,ax mov cx,8 xor si,si ; loop_start: mov al,val[si] inc si cmp al,41h ;loopz:cx不为0 and zf 标志位为 1 才会继续循环,只要其中一个条件不成立就会跳出循环 loopz loop_start cmp byte ptr [si],24H jz no_find mov bx,si jmp stop no_find: mov bx,-1 stop: mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| ;程序名:loopz2.asm ;功能:查找第一个非 'A' 字符,找到 BX 保存该字符的偏移地址,找不到 BX=0FFFFh ;========================================================================= assume cs:code,ds:data
data segment val db 'AAABABAA' len = $ - val data ends
code segment start: mov ax,data mov ds,ax mov cx,len xor si,si ; loop_start: mov al,val[si] inc si cmp al,41h ;循环判断字符串中的字符 'A' loopz loop_start ;如果 CX = 0,说明没有找到字符 'A' cmp cx,0 jz no_find mov bx,si jmp stop no_find: mov bx,-1 stop: mov ax,4c00h int 21h code ends end start
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| ;程序名:loopz3.asm ;功能:查找第一个非 'A' 字符,找到 BX 保存该字符的偏移地址,找不到 BX=0FFFFh ;========================================================================= assume cs:code,ds:data
data segment val db 'AAABABAA' len = $ - val data ends
code segment start: mov ax,data mov ds,ax mov cx,len xor si,si loop_start: mov al,val[si] inc si cmp al,41h loopz loop_start ;正常循环结束后的 CX = 0 jz no_find mov bx,si jmp stop no_find: mov bx,-1 stop: mov ax,4c00h int 21h code ends end start
|