啥都不会 发表于 2022-5-30 10:20

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

前言:
这篇笔记主要逻辑指令、位移指令和循环指令相关知识。

编程语言:
汇编语言

以下为主题内容:

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

常见用途:
1. 保证操作数不变的情况下,让 CF 位清 0



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



OR(或)
指令格式:
OR OPRD1,OPRD2

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

范例:
OR AX,8080H
OR CL,AL
OR ,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 标号

条件转移指令分为段内转移和段间转移。


;程序名: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 表示。


;程序名: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 可以节省一些硬盘和内存空间。
使用 "存储单元" 进行跳转

;程序名: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 \$+立即数" 可以跳转到相应地址。

;程序名: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(跳转指令)



代码补充

;程序名: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



;程序名: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



;程序名: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



;程序名:shift.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



;程序名: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



;程序名: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



;程序名: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
    ;
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,al
    jmp loop_end
    ;
char:
    add al,37h
    mov result,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



;程序名:loop1.asm
;功能:把从偏移 1000H 开始的 512 个字节的数据复制到从偏移 3000H 开始的缓冲区中
assume cs:code

code segment
start:
    mov si,1000H
    mov di,3000H
    mov cx,512
next:
    mov al,
    inc si
    mov ,al
    inc di
    loop next
    ;
    mov ax,4c00h
    int 21h
code ends
end start

;程序名: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
    inc si
    cmp al,41h
    ;loopz:cx不为0 and zf 标志位为 1 才会继续循环,只要其中一个条件不成立就会跳出循环
    loopz loop_start
    cmp byte ptr ,24H
    jz no_find
    mov bx,si
    jmp stop
no_find:
    mov bx,-1
stop:
    mov ax,4c00h
    int 21h
code ends
end start



;程序名: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
    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



;程序名: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
    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


RmKcTkHa 发表于 2022-5-30 10:36

感谢楼主

omgTsQ6917 发表于 2022-5-30 10:37

楼主的帖子不错,多发点~

IKfTXCG95807 发表于 2022-5-30 10:39

感谢楼主

JYmejiO 发表于 2022-5-30 10:44

谢谢分享

oQP27 发表于 2022-5-30 10:45

感谢楼主

SzuPpJd5860 发表于 2022-5-30 10:48

感谢楼主

YkwPF 发表于 2022-5-30 10:59

谢谢分享

uYtUSF 发表于 2022-5-30 11:09

谢谢分享

veUDqa251 发表于 2022-5-30 11:12

有楼主这样的热心人真好
页: [1] 2 3 4 5 6 7
查看完整版本: 8086汇编-逻辑运算和位移指令