在这里插入图片描述

前言

📌

汇编语言是很多相关课程(如数据结构、操作系统、微机原理)的重要基础。但仅仅从课程的角度出发就太片面了,其实学习汇编语言可以深入理解计算机底层工作原理,提升代码效率,尤其在嵌入式系统和性能优化方面有重要作用。此外,它在逆向工程和安全领域不可或缺,帮助分析软件运行机制并增强漏洞修复能力。

本专栏的汇编语言学习章节主要是依据王爽老师的《汇编语言》来写的,和书中一样为了使学习的过程容易展开,我们采用以8086CPU为中央处理器的PC机来进行学习。

下面的内容中我们将学习一些根据cmp指令的比较结果(即,cmp指令执行后,相关标志位的值)进行工作的指令。

1. 检测比较结果的条件转移指令

1.1 什么是条件转移指令?

转移”指的是它能够修改IP,而“条件”指的是它可以根据某种条件,决定是否修改 IP

比如,jcxz就是一个条件转移指令,它可以检测cx中的数值,如果(cx)=0,就修改IP,否则什么也不做。

所有条件转移指令的转移位移都是[-128,127],也就是短转移。

除了jcxz之外,CPU还提供了其他条件转移指令,大多数条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。

它们检测的是哪些标志位呢?

就是被cmp指令影响的那些,表示比较结果的标志位。这些条件转移指令通常都和cmp相配合使用,就好像call和ret指令通常相配合使用一样。

1.2 两类条件转移指令

因为cmp指令可以同时进行两种比较,无符号数比较和有符号数比较,所以根据cmp指令的比较结果进行转移的指令也分为两种,即:

  • 根据无符号数的比较结果进行转移的条件转移指令(它们检测 zf、cf的值)。

  • 根据有符号数的比较结果进行转移的条件转移指令(它们检测 sf、of和 zf的值)。



🚁🚁🚁

下面将会讲解根据无符号数的比较结果进行转移的条件转移指令。

根据有符号数的比较结果进行转移的条件转移指令的工作原理和无符号的相同,只是检测了不同的标志位。

我们在这里主要探讨的是cmp、标志寄存器的相关位、条件转移指令三者配合应用的原理,这个原理具有普遍性,而不是逐条讲解条件转移指令。对这些指令感兴趣的读者可以查看相关的指令手册。



2. 根据无符号比较的条件转移指令

下面是常用的根据无符号数的比较结果进行转移的条件转移指令。

在这里插入图片描述

2.1 如何记忆?

这些指令比较常用,它们都很好记忆,它们的第一个字母都是j,表示jump;后面的字母表示意义如下。

  • e:表示equal;

  • ne:表示not equal;

  • b:表示below;

  • nb:表示not below;

  • a:表示above;

  • na:表示not above。

2.2 如何实现比较转移的功能?

注意观察一下它们所检测的标志位,都是cmp指令进行无符号数比较时候,记录比较结果的标志位。比如je,检测 ZF位,当 ZF=1的时候进行转移,如果在 je 前面使用了 cmp 指令,那么je对ZF的检测,实际上就是间接地检测cmp的比较结果是否为两数相等

2.3 举例说明

2.3.1 例1

下面看一个例子。

编程实现如下功能:

如果(ah)=(bh)则(ah)=(ah)+(ah),否则 (ah)=(ah)+(bh)。

	cmp ah,bh
	je s
	add ah,bh
	jmp short ok
 s: add ah,ah
ok: ...

上面的程序执行时,如果(ah)=(bh),则 cmp ah,bh 使 zf=1,而 je 检测 zf是否为 1,如果为1,将转移到标号s处执行指令add ah,ah。这也可以说,cmp 比较 ah、bh 后所得到的相等的结果使得je指令进行转移。从而很好地体现了je指令的逻辑含义,相等则转移

虽然 je 的逻辑含义是“相等则转移”,但它进行的操作是,ZF=1时则转移

“相等则转移”这种逻辑含义,是通过和 cmp 指令配合使用来体现的,因为是cmp 指令为“ZF=1”赋予了“两数相等”的含义。

至于究竟在je之前使不使用cmp指令,在于我们的安排。

je检测的是ZF位置,不管 je 前面是什么指令,只要CPU执行je指令时,ZF=1,那么就会发生转移。

2.3.2 例2

比如:

	mov ax,0
	add ax,0
	je s
	inc ax
s:  inc ax

执行后,(ax)=1。add ax,0使得ZF=1,所以je指令将进行转移。

可在这个时候发生的转移的确不带有“相等则转移”的含义。

因为此处的je指令检测到的zf=1,不是由cmp等比较指令设置的,而是由add指令设置的,并不具有“两数相等”的含义。

但无论“zf=1”的含义如何,是什么指令设置的,只要是 zf=1,就可以使得 je 指令发生转移

3. 总结

CPU提供了cmp指令,也提供了 je 等条件转移指令,如果将它们配合使用,可以实现根据比较结果进行转移的功能。但这只是“如果”,只是一种合理的建议,和事实上常用的方法。但究竟是否配合使用它们,完全是你自己的事情。这就好像,call和ret指令的关系一样。

对于jne、jb、jnb、ja、jna等指令和cmp指令配合使用的思想和je相同,可以自己分析一下。

虽然我们分别讨论了cmp指令和与其比较结果相关的有条件转移指令,但是它们经常在一起配合使用。所以我们在联合应用它们的时候,不必再考虑cmp指令对相关标志位的影响和 je 等指令对相关标志位的检测。因为相关的标志位,只是为cmp和je等指令传递比较结果。我们可以直接考虑cmp和je等指令配合使用时,表现出来的逻辑含义。它们在联合使用的时候表现出来的功能有些像高级语言中的IF语句。

4. 例题巩固

data段中的8个字节如下:

data segment 
	db 8,11,8,1,8,5,63,38
data ends

4.1 问题一

4.1.1 问题与思路

(1)编程:统计data段中数值为8的字节的个数,用ax保存统计结果。

编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个和8相等的数就将ax的值加1。

4.1.2 问题的分析与解决

程序如下。

		mov ax,data
        mov ds,ax
        mov bx,0             ;ds:bx指向第一个字节
        mov ax,0             ;初始化累加器
        mov cx,0
		
    s:  cmp byte ptr [bx],8  ;和8进行比较
        jne next             ;如果不相等转到next,继续循环
        inc ax               ;如果相等就将计数值加1
		
 next:  inc bx
        loop s               ;程序执行后: (ax)=3

这个程序也可以写成这样:

		mov ax,data
        mov ds,ax
        mov bx,0           	  ;ds:bx指向第一个字节
        mov ax,0        	  ;初始化累加器
        mov cx,0
		
     s: cmp byte ptr [bx],8   ;和8进行比较
        je ok                 ;如果相等就转到ok,继续循环
        jmp short next        ;如果不相等就转到next,继续循环
    ok: inc ax                ;如果相等就将计数值加1
  next: inc bx
        loop s

比起第一个程序,它直接的遵循了“等于8则计数值加1”的原则,用je指令检测等于8的情况,但是没有第一个程序精简。
第一个程序用 jne 检测不等于 8 的情况 ,从而间接地检测等于 8 的情况。
要注意在使用 cmp 和条件转移指令时的这种编程思想。

4.2 问题二

4.2.1 问题与思路

(2)编程:统计data段中数值大于8的字节的个数,用ax保存统计结果。

编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个大于8的数就将ax的值加1。

4.2.2 问题的分析与解决

程序如下。

		mov ax,data
        mov ds,ax
        mov bx,0        	 ;ds:bx指向第一个字节
        mov ax,0       		 ;初始化累加器
        mov cx,0
		
     s: cmp byte ptr [bx],8  ;和8进行比较
        jna next        	 ;如果不大于8转到next,继续循环
        inc ax           	 ;如果大于8就将计数值加1
		
 next:  inc bx
        loop s	            

程序执行后:(ax)=3。

4.3 问题三

4.3.1 问题与思路

(3)编程:统计data段中数值小于8的字节的个数,用ax保存统计结果。

编程思路:初始设置(ax)=0,然后用循环依次比较每个字节的值,找到一个小于8的数就将ax的值加1。

4.3.2 问题的分析与解决

程序如下。

		mov ax,data
		mov ds,ax
        mov bx,0       		 ;ds:bx指向第一个字节
        mov ax,0       		 ;初始化累加器
        mov cx,0
		
     s: cmp byte ptr [bx],8  ;和8进行比较
        jnb next       		 ;如果不小于8转到next,继续循环
        inc ax         		 ;如果小于8就将计数值加1
		
  next: inc bx
        loop s           	

程序执行后:(ax)=2。

结语

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下。

也可以点点关注,避免以后找不到我哦!

Crossoads主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是作者前进的动力!

在这里插入图片描述

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐