cmp

Tutorial: 汇编基础 Category: C语言 Published: 2026-04-07 13:58:26 Views: 20 Likes: 0 Comments: 0
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.	根据12组合可以推出另外两个。


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 的字节个数
  • 方法 1
; =================================================================
; 编程:实现以下功能:
; 统计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

  • 方法 2:
; 编程:实现以下功能:
; 统计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
Prev: sbb Next: df