8086汇编-逻辑运算和位移指令
9unk Lv5

这组指令主要分为逻辑指令、位移指令和循环指令三个部分。

逻辑指令

逻辑指令中,除 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]

常见用途:

  1. 保证操作数不变的情况下,让 CF 位清 0
    1

  2. 将一个字节数据的高 4 位置 0
    2

OR(或)

指令格式:

OR OPRD1,OPRD2

使用逻辑 “或” 运算,结果送到目的操作数 OPRD1

范例:

OR AX,8080H
OR CL,AL
OR [BX-3],AX

MOV AL,41H
OR AL,20H

3

XOR(异或)

指令格式:
XOR OPRD1,OPRD2

常见用途:

  1. 操作数和 CF 位同时置 0
    4

  2. 将一个字节数据的低 4 位取反
    5

TEST(测试指令)

指令格式:

TEST OPRD1,OPRD2

使用逻辑 “与” 运算,只影响标志位,不会改变 OPRD1。

常见用途:

  1. 判断某个位是否为1
    6

  2. 判断这个值是否为0
    7

test 指令没有改变操作数,不完全属于逻辑运算指令。

位移指令

所有位移指令如果位移多位,需要将移位位数存放在 CL 寄存器中。

SAL/SHL(算数左移指令/逻辑左移指令)

算数左移和逻辑左移的硬编码相同,没有区别。根据编译器的不同,它只会选择一种汇编指令编译。

指令格式:

SAL OPRD,m
SHL OPRD,m

8

  1. 判断某个位是否为1
    9

  2. 乘法运算:计算4*2
    10

SAR(算数右移指令)

指令格式:

SAR OPRD,m

操作数右移m位,同时每一栋一位,左边符号位保持不变,移出的最低位进入标志位CF。

范例:

SAR AL,1
SAR BX,CL

对于有符号数而言,算数右移一位相当于除以2

11

不建议用在无符号数,容易出错。

SHR(逻辑右移指令)

指令格式:

SHR OPRD,m

范例:

SHR BL,1
SHR AX,CL

对于无符号数而言,逻辑右移相当于除以2
12

循环位移指令

8086 有四条循环位移指令:ROL(左循环位移),ROR(右循环位移),RCL(带进位左循环位移),RCR(带进位右循环位移)。
13

ROL(左循环位移指令)

每移位一次,操作数左移,其最高位移入最低位,同时最高位也移入进位标志 CF
14

ROR(右循环位移指令)

每移位一次,操作数右移,其最低位移入最高位,同时最低位也移入进位标志 CF
15

RCL(带进位左循环位移指令)

每移位一次,操作数左移,其最高位移入进位标志 CF,CF 移入最低位。
16

RCR(带进位右循环位移指令)

每移位一次,操作数右移,其最低位移入进位标志 CF,CF 移入最高位。

17

转移指令

无条件转移指令

指令格式:

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 填充。
18

19

如果确认一个字节可以表示地址差,那么可以在标号前使用 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

20

由此可见,在当时硬盘和内存还很小的情况下,编写程序使用 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

21

使用存储单元跳转是直接,将内存数据传输到 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

22

段间直接转移

23
24

段间间接转移

25

条件转移指令

26
27

循环指令

条件转移指令和无条件转移指令可以实现循环,但为了方便循环指令的实现,8086 还提供了四条循环指令。

循环指令不影响各标志位

LOOP(计数循环指令)

28

LOOPE/LOOPZ(等于/全零循环指令)

29

LOOPNE/LOOPNZ(不等于/非零循环指令)

30

JCXZ(跳转指令)

31

代码补充

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
  • 本文标题:8086汇编-逻辑运算和位移指令
  • 本文作者:9unk
  • 创建时间:2022-05-22 14:58:29
  • 本文链接:https://9unkk.github.io/2022/05/22/8086-hui-bian-luo-ji-yun-suan-he-wei-yi-zhi-ling/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!