1. cmp
- 比较指令用于比较两个寄存器中的值, 它实际上是执行一个减法操作, 但不会修改操作数
- cmp 目标操作数, 源操作数
- cmp 是比较指令, cmp 的功能相当于减法。
比较两个无符号数
CMP结果 ZF CF
目的操作数 < 源操作数 0 1
目的操作数 > 源操作数 0 0
目的操作数 = 源操作数 1 0
比较两个有符号数
CMP结果 标志位
目的操作数 < 源操作数 SF ≠ OF
目的操作数 > 源操作数 SF=OF
目的操作数 = 源操作数 ZF=1
正向判断
如果(ax) = (bx) 则(ax)-(bx) = 0, 所以:zf=1。
如果(ax) != (bx) 则(ax)-(bx) != 0, 所以:zf=0。
如果(ax) < (bx) 则(ax)-(bx)将产生借位 所以:cf=1。
如果(ax) >=(bx) 则(ax)-(bx)不产生借位 所以:cf=0。
如果(ax) > (bx) 则(ax)-(bx) != 0, 也不产生借位, 所以:zf=cf=0。
如果(ax) <=(bx) 则(ax)-(bx)可能为0, 也可能产生借位, 所以:zf=1或cf=1
反向判断
指令cmp ax,bx 的逻辑含义是比较ax和bx的值, 如果执行后:
1. zf=1 ===> (ax)=(bx)
2. zf=0 ===> (ax)!=(bx)
3. cf=1 ===> (ax)<(bx)
4. cf=0 ===> (ax)>=(bx)
5. cf=zf=0 ===> (ax)>(bx)
6. cf=1或zf=1 ===> (ax)<=(bx)
如何记忆?
1. zf是0标志寄存器, zf=1时, ax=bx;zf=0时, ax != bx。
2. cf是进位借位标志寄存器, cf=1时, ax<bx;cf=0时, ax>=bx。
3. 根据1、2组合可以推出另外两个。
CMP指令如何起作用?
cmp指令的比较结果需要通过条件转移指令来检测。
指令 解释 含义 检测的相关标志位 范围
je e:equal 等于则转移 zf=1 -128 - 127
jne ne:not equal 不等于则转移 zf=0
jb b:below 低于则转移 cf=1
jnb nb:not below 不低于则转移 cf=0
ja a:above 高于则转移 cf=0且zf=0
jna na:not above 不高于则转移 cf=1或zf=1
2. 简单示例
mov ax, 5
cmp ax,10 ; ZF = 0 and CF = 1
mov ax,1000
mov cx,1000
cmp cx, ax ; ZF = 1 and CF = 0
mov si,105
cmp si, 0 ; ZF = 0 and CF = 0
3. 编写一个子程序, 将包含任意字符,以 0 字符结尾的字符串中的小写字母转变成大写字母
; 160 - 以0结尾的字符串中小写字母转大写
; =================================================================
; 编写一个子程序, 将包含任意字符, 以0结尾的字符串中的小写字母转变为大写字母
; 名称:letterc
; 功能:将以0结尾的字符串中的小写字母转变为大写字母
; 参数:ds:si 指向字符串首地址
;
; =================================================================
assume cs:code, ss:stack, ds:data
; =================================================================
data segment
db "Beginner's All-purpose Symbolic Instruction Code.", 0
data ends
; =================================================================
stack segment stack
db 128 dup (0)
stack ends
; =================================================================
code segment
start: mov ax, stack
mov ss, ax
mov sp, 128
mov ax, data
mov ds, ax
; -d ds:0
; 0E24:0000 42 65 67 69 6E 6E 65 72-27 73 20 41 6C 6C 2D 70 Beginners All-p
; 0E24:0010 75 72 70 6F 73 65 20 53-79 6D 62 6F 6C 69 63 20 urpose Symbolic
; 0E24:0020 49 6E 73 74 72 75 63 74-69 6F 6E 20 43 6F 64 65 Instruction Code
; 0E24:0030 2E 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
mov si, 0
call letterc
mov ax, 4c00h
int 21h
; ----------------------------------------
; 名称:letterc
; 功能:将以0结尾的字符串中的小写字母转变为大写字母
; 参数:ds:si 指向字符串首地址
letterc: push cx
push ds
push si
mov cx, 0
; 65 41 A
; 97 61 a
; 122 7A z
_letterc: mov cl, ds:[si] ; 小写字母ASCII范围:[61H, 7A]
jcxz _retLetterRc ; 退出程序
; 思路:只要是小写字母范围内的, 都and一下
cmp cl, 61H
jb _nextLetter ; 小于a, 不在小写字母范围内, 下一个
cmp cl, 7AH
ja _nextLetter ; 大于z, 超出, 继续下一个
and cl, 11011111B
mov ds:[si], cl
_nextLetter: inc si
jmp _letterc
_retLetterRc:pop si
pop ds
pop cx
ret
; 结果:
; -d ds:0
; 0E24:0000 42 45 47 49 4E 4E 45 52-27 53 20 41 4C 4C 2D 50 BEGINNER S ALL-P
; 0E24:0010 55 52 50 4F 53 45 20 53-59 4D 42 4F 4C 49 43 20 URPOSE SYMBOLIC
; 0E24:0020 49 4E 53 54 52 55 43 54-49 4F 4E 20 43 4F 44 45 INSTRUCTION CODE
; 0E24:0030 2E 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................
code ends
end start
4. 统计 data 段中, 数值为 8 的字节个数
; =================================================================
; 编程:实现以下功能:
; 统计data段中, 数值为8的字节个数
; je =
; jne !=
; jb <
; jnb >=
; ja >
; jna <=
; =================================================================
assume cs:code, ss:stack, ds:data
data segment
db 8,11,8,1,8,5,63,38
data ends
; =================================================================
stack segment stack
db 128 dup (0)
stack ends
code segment
start:
mov ax, stack
mov ss, ax
mov sp, 128
mov ax, data
mov ds, ax
mov bx, 0 ; print to first byte in data segment
mov ax, 0 ; The counter
mov cx, 8 ; loop 8 times
s: cmp byte ptr ds:[bx], 8 ; comparison for 8
jne next ; if not == 8 --> jump to "next"
inc ax
next: inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
; 编程:实现以下功能:
; 统计data段中, 数值为8的字节个数
assume cs:code, ss:stack, ds:data
data segment
db 8,11,8,1,8,5,63,38
data ends
stack segment stack
db 128 dup (0)
stack ends
code segment
start:mov ax, stack
mov ss, ax
mov sp, 128
mov ax, data
mov ds, ax
mov bx, 0 ; print to first byte in data segment
mov ax, 0 ; Tne counter
mov cx, 8 ; loop 8 times
s: cmp byte ptr ds:[bx], 8
je ok ; 等于8去执行累加操作
jmp short next
ok: inc ax
next: inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
5. 统计 data 段中, 数值大于 8 的字节个数
; 编程:实现以下功能:
; 统计data段中, 数值大于8的字节个数
assume cs:code, ss:stack, ds:data
data segment
db 8,11,8,1,8,5,63,38
data ends
stack segment stack
db 128 dup (0)
stack ends
code segment
start:mov ax, stack
mov ss, ax
mov sp, 128
mov ax, data
mov ds, ax
mov bx, 0 ; print to first byte in data segment
mov ax, 0 ; Tne counter
mov cx, 8 ; loop 8 times
s: cmp byte ptr ds:[bx], 8
jna next ; 小于等于, 判断不大于要比直接判断大于等于的代码量和逻辑要好
inc ax
next: inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
6. 统计 data 段中, 数值小于 8 的字节个数
; 编程:实现以下功能:
; 统计data段中, 数值小于8的字节个数
assume cs:code, ss:stack, ds:data
data segment
db 8,11,8,1,8,5,63,38
data ends
stack segment stack
db 128 dup (0)
stack ends
code segment
start:
mov ax, stack
mov ss, ax
mov sp, 128
mov ax, data
mov ds, ax
mov bx, 0 ; print to first byte in data segment
mov ax, 0 ; Tne counter
mov cx, 8 ; loop 8 times
s: cmp byte ptr ds:[bx], 8
jnb next ;大于等于, 判断不小于要比直接判断小于等于的代码量和逻辑要好
inc ax
next: inc bx
loop s
mov ax, 4c00h
int 21h
code ends
end start
7. cmp 指令有符号数-案例 1
-a
0E2D:000C mov ax,0
0E2D:000F mov bx,0
0E2D:0012 mov al,3
0E2D:0014 mov bl,2
0E2D:0016 sub al,bl
AX=0003 BX=0002 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=0016 OV UP EI NG NZ NA PE CY
0E2D:0016 28D8 SUB AL,BL
-t
AX=0001 BX=0002 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=0018 NV UP EI PL NZ NA PO NC
; OF DF IF SF ZF AF PF CF
; NV UP EI PL NZ NA PO NC
; OF: 0
; SF: 0
; CF: 0
-a
0E2D:0018 mov ax,0
0E2D:001B mov bx,0
0E2D:001E mov al,2
0E2D:0020 mov bl,3
0E2D:0022 sub al,bl
-t
AX=0002 BX=0003 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=0022 NV UP EI PL NZ NA PO NC
0E2D:0022 28D8 SUB AL,BL
-t
AX=00FF BX=0003 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=0024 NV UP EI NG NZ AC PE CY
; OF DF IF SF ZF AF PF CF
; NV UP EI PL NZ NA PO NC
; OF: 0
; SF: 1
; CF: 1
8. cmp 指令有符号数-案例 2
- 如果因为溢出导致了实际结果为负, 那么逻辑上的真正结果必然为正
- 如果因为溢出导致了实际结果为正, 那么逻辑上的真正结果必然为负
-a
0E2D:0024 mov ax,0
0E2D:0027 mov bx,0
0E2D:002A mov al,22
0E2D:002C mov bl,a0
0E2D:002E sub al,bl
-t
AX=0022 BX=00A0 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=002E NV UP EI NG NZ AC PE CY
0E2D:002E 28D8 SUB AL,BL
-t
AX=0082 BX=00A0 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=0030 OV UP EI NG NZ NA PE CY
; OF DF IF SF ZF AF PF CF
; NV UP EI PL NZ NA PO NC
; OF: 1
; SF: 1
; CF: 1
; 22(34) - a0(-96) = 130
; al 中的结果被CPU当做有符号数解释为-126,所以sf并不能表示实际结果的正负;
9. cmp 指令有符号数-案例 3
- 如果因为溢出导致了实际结果为负, 那么逻辑上的真正结果必然为正
- 如果因为溢出导致了实际结果为正, 那么逻辑上的真正结果必然为负
-a
0E2D:0030 mov ax,0
0E2D:0033 mov bx,0
0E2D:0036 mov al,8a
0E2D:0038 mov bl,70
0E2D:003A sub al,bl
-t
AX=008A BX=0070 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=003A OV UP EI NG NZ NA PE CY
0E2D:003A 28D8 SUB AL,BL
-t
AX=001A BX=0070 CX=009E DX=0000 SP=0080 BP=0000 SI=0000 DI=0000
DS=0E14 ES=0E14 SS=0E25 CS=0E2D IP=003C OV UP EI PL NZ NA PO NC
; OF DF IF SF ZF AF PF CF
; NV UP EI PL NZ NA PO NC
; OF: 1
; SF: 0
; CF: 0
; -118 - 112 = -230