Masm64:转移指令JMP/Jx/LOOP

在MASM64中,转移指令用于改变程序的执行顺序。转移指令较丰富,这些条件转移指令的前一条指令常常是改变标志位的指令,前面介绍过了(参考:Masm64:标志寄存器状态位操作指令),下面再介绍两个重要的比较指令:

1. CMP(Compare)指令

功能:CMP指令用于比较两个操作数。它执行减法操作,但不保存结果,而是根据结果设置相应的标志位(如零标志位ZF、符号标志位SF、溢出标志位OF、进位标志位CF等),以便后续的条件转移指令根据这些标志位做出判断。

操作数可以是寄存器与寄存器、寄存器与内存、内存与寄存器、内存与立即数等。

寄存器与寄存器比较:cmp rax, rbx                   ;将比较rax和rbx的值。

寄存器与内存比较:cmp eax, [var1]                  ;将eax的值与变量var1中的值进行比较。

内存与立即数比较:cmp byte ptr [var2], 10h    ;字节类型的变量var2中的值与十六进制数10h进行比较。

2. TEST指令

功能:TEST指令执行按位与(AND)操作,但同样不保存结果,而是根据结果设置标志位。通常用于测试某个操作数中的特定位是否为0或1。

测试寄存器中的特定位:test rax, 0001h    ;将rax与0001h进行按位与操作。如果结果为0(即rax的最低位为0),则零标志位ZF = 1;否则ZF = 0。

判断一个数是否为偶数:test eax, 1    ;如果eax是偶数(最低位为0),则ZF = 1,否则ZF = 0。然后可以结合条件转移指令如 jz 来进行相应的操作。

一、无条件转移指令

1. JMP(Jump)

功能:无条件地跳转到指定的目标地址。目标地址可以是一个标号(在代码段内定义的标识符,表示一个指令的地址)、一个寄存器(其中包含目标地址)或者一个内存单元(存储着目标地址)。

jmp label1      ;程序将无条件跳转到名为label1的标号处继续执行。
jmp rax        ;如果rax寄存器中存储着目标地址

二、条件转移指令

1. 基于标志位的条件转移指令

JE / JZ(Jump if Equal / Jump if Zero)

功能:当零标志位ZF = 1时,即两个操作数相等(相减结果为0)时跳转。

cmp rax, rbx          ;比较rax和rbx的值。
je equal_label         ;如果rax等于rbx,则跳转到equal_label标号处。

JNE / JNZ(Jump if Not Equal / Jump if Not Zero)

功能:当零标志位ZF = 0时,即两个操作数不相等(相减结果不为0)时跳转。

cmp rax, rbx
jne not_equal_label     ;如果rax不等于rbx,则跳转到not_equal_label处。

JG / JNLE(Jump if Greater / Jump if Not Less or Equal)

功能:当符号标志位SF和溢出标志位OF具有相同的值(表示没有溢出或者同是正溢出或同是负溢出),并且零标志位ZF = 0时跳转,用于有符号数比较,表示大于。

cmp rax, rbx
jg greater_label        ;如果rax大于rbx(有符号数比较),则跳转到greater_label。

JGE / JNL(Jump if Greater or Equal / Jump if Not Less)

功能:当符号标志位SF和溢出标志位OF具有相同的值(表示没有溢出或者同是正溢出或同是负溢出)时跳转,用于有符号数比较,表示大于或等于。

cmp rax, rbx
jge greater_equal_label ;如果rax大于或等于rbx(有符号数比较),则跳转到greater_equal_label。

JL / JNGE(Jump if Less / Jump if Not Greater or Equal)

功能:当符号标志位SF和溢出标志位OF具有不同的值(表示有溢出且结果不正确)时跳转,用于有符号数比较,表示小于。

cmp rax, rbx
jl less_label           ;如果rax小于rbx(有符号数比较),则跳转到less_label。

JLE / JNG(Jump if Less or Equal / Jump if Not Greater)

功能:当符号标志位SF和溢出标志位OF具有不同的值(表示有溢出且结果不正确)或者零标志位ZF = 1时跳转,用于有符号数比较,表示小于或等于。

cmp rax, rbx
jle less_equal_label    ;如果rax小于或等于rbx(有符号数比较),则跳转到less_equal_label。

2. 基于无符号数比较的条件转移指令

JA / JNBE(Jump if Above / Jump if Not Below or Equal)

功能:当进位标志位CF = 0且零标志位ZF = 0时跳转,用于无符号数比较,表示大于。

cmp rax, rbx           ;(假设rax和rbx为无符号数)
ja above_label          ;如果rax大于rbx(无符号数比较),则跳转到above_label。

JAE / JNB(Jump if Above or Equal / Jump if Not Below)

功能:当进位标志位CF = 0时跳转,用于无符号数比较,表示大于或等于。

cmp rax, rbx            ;(假设rax和rbx为无符号数)
jae above_equal_label    ;如果rax大于或等于rbx(无符号数比较),则跳转到above_equal_label。

JB / JNAE(Jump if Below / Jump if Not Above or Equal)

功能:当进位标志位CF = 1时跳转,用于无符号数比较,表示小于。

cmp rax, rbx            ;(假设rax和rbx为无符号数)
jb below_label           ;如果rax小于rbx(无符号数比较),则跳转到below_label。

JBE / JNA(Jump if Below or Equal / Jump if Not Above)

功能:当进位标志位CF = 1或者零标志位ZF = 1时跳转,用于无符号数比较,表示小于或等于。

cmp rax, rbx            ;(假设rax和rbx为无符号数)
jbe below_equal_label    ;如果rax小于或等于rbx(无符号数比较),则跳转到below_equal_label。

条件转移指令表

指令条件描述用于比较类型
JE / JZZF = 1相等/结果为零则跳转有符号数和无符号数
JNE / JNZZF = 0不相等/结果不为零则跳转有符号数和无符号数
JG / JNLE(SF = OF) AND (ZF = 0)大于(有符号数)/不小于等于(有符号数)则跳转有符号数
JGE / JNLSF = OF大于等于(有符号数)/不小于(有符号数)则跳转有符号数
JL / JNGESF ≠ OF小于(有符号数)/不大于等于(有符号数)则跳转有符号数
JLE / JNG(SF ≠ OF) OR (ZF = 1)小于等于(有符号数)/不大于(有符号数)则跳转有符号数
JA / JNBE(CF = 0) AND (ZF = 0)高于(无符号数)/不低于等于(无符号数)则跳转无符号数
JAE / JNBCF = 0高于等于(无符号数)/不低于(无符号数)则跳转无符号数
JB / JNAECF = 1低于(无符号数)/不高于等于(无符号数)则跳转无符号数
JBE / JNA(CF = 1) OR (ZF = 1)低于等于(无符号数)/不高于(无符号数)则跳转无符号数
JCCF = 1进位标志为1则跳转无符号数操作中的进位情况判断等
JNCCF = 0进位标志为0则跳转无符号数操作中的进位情况判断等
JOOF = 1溢出标志为1则跳转有符号数运算中的溢出判断
JNOOF = 0溢出标志为0则跳转有符号数运算中的溢出判断
JPE / JPPF = 1奇偶标志为1则跳转(PF:结果低8位中1的个数为偶数)数据传输或处理中对奇偶性有要求的情况
JPO / JNPPF = 0奇偶标志为0则跳转(PF:结果低8位中1的个数为奇数)数据传输或处理中对奇偶性有要求的情况
JSSF = 1符号标志为1则跳转(结果为负)有符号数运算结果的正负判断
JNSSF = 0符号标志为0则跳转(结果为正或零)有符号数运算结果的正负判断

条件转移指令的速记口诀:

一、有符号数比较口诀

1. 相等判断

“E(equal)是相等零(ZF = 1),NE(not equal)不等零相反。”

2. 大小判断

“G(greater)大要把规则看,SF和OF同且零(ZF)断。”

“GE(greater or equal)大等SF与OF伴。”

“L(less)小SF、OF不同站。”

“LE(less or equal)小等规则不难判,SF、OF不同或零(ZF)现。”

二、无符号数比较口诀

1. 高低判断

“A(above)高CF和零(ZF)全不见,AE(above or equal)高等于CF断。”

“B(below)低CF为1很简单,BE(below or equal)低等CF或零(ZF)算。”

三、其他标志位相关口诀

1. 进位标志

“C(carry)进为1跳得欢,NC(no carry)不进零相关。”

2. 溢出标志

“O(overflow)溢为1就跳转,NO(no overflow)不溢零来判。”

3. 奇偶标志

“PE(parity even)偶跳PF为1时,PO(parity odd)奇跳PF为零事。”

4. 符号标志

“S(sign)负SF为1跳,NS(no sign)非负零来找。”

3. 基于计数器转移指令

(1). JCXZ(Jump if CX is Zero)

功能:在16位和32位模式下使用。该指令检查CX寄存器(16位模式)或ECX寄存器(32位模式)的值是否为零。如果CX/ECX的值为零,则发生跳转;如果不为零,则程序顺序执行下一条指令。

(2). JECXZ(Jump if ECX is Zero)

功能:这是专门用于32位模式下的指令,功能与JCXZ类似,只是针对的是32位的ECX寄存器。它检查ECX寄存器的值是否为零,如果为零则跳转到指定的目标地址(通常是一个标号),否则顺序执行下一条指令。

mov ecx, 0;将ECX设置为0
jecxz label1 ; 因为ECX为0,所以会跳转到label1处
; 这里的指令不会被执行,如果ECX不为0则会执行
label1:
; label1处的指令

在MASM64(64位模式)中,JCXZ和JECXZ指令的功能被部分替代。在64位模式下,主要使用64位寄存器,如RCX。虽然可以在兼容模式下使用JCXZ和JECXZ,但对于纯64位编程,更多地会使用与64位寄存器相关的逻辑和指令或接下来要介绍的JRCXZ指令。例如,可以通过比较RCX寄存器与零,然后使用条件转移指令(如JZ - Jump if Zero)来实现类似的功能:

mov rcx, 0
cmp rcx, 0
jz label2
; 如果RCX为0,将跳转到label2
label2:
; label2处的指令

(3). JRCXZ(Jump if RCX is Zero)指令

功能:在MASM64(64 - bit模式)中,JRCXZ指令用于检查RCX寄存器的值是否为零。如果RCX的值为零,则程序跳转到指定的目标地址(通常为一个标号);如果RCX不为零,则程序继续顺序执行下一条指令。

mov rcx, 0
jrcxz zero_label    ; 如果rcx为0,会跳过下面这行指令直接跳转到zero_label
add rax, 1
zero_label:
; 这里是跳转到的代码位置

应用场景:常用于循环结构中,作为循环的前置判断条件。例如,当需要根据一个初始值可能为零的计数器(存储在RCX中)来决定是否执行一段代码块时,可以使用JRCXZ指令。它类似于16位模式下的JCXZ和32位模式下的JECXZ指令,但专门用于64位环境中的RCX寄存器。

三、循环指令(本质上也是一种条件转移指令)

1. LOOP

功能:首先将rcx寄存器的值减1,如果减1后rcx的值不为0,则跳转到指定的标号处继续执行循环;如果rcx的值为0,则退出循环。在64 - bit模式下,rcx通常用作循环计数器。

mov rcx, 10
loop_label:
; 循环体中的指令
loop loop_label:这个循环将执行10次。

2. LOOPE / LOOPZ(Loop if Equal / Loop if Zero)

功能:首先将rcx寄存器的值减1,如果减1后rcx的值不为0且零标志位ZF = 1,则跳转到指定的标号处继续执行循环;如果rcx的值为0或者零标志位ZF = 0,则退出循环。

在一些需要根据相等条件判断是否继续循环的场景中使用。

3. LOOPNE / LOOPNZ(Loop if Not Equal / Loop if Not Zero)

功能:首先将rcx寄存器的值减1,如果减1后rcx的值不为0且零标志位ZF = 0,则跳转到指定的标号处继续执行循环;如果rcx的值为0或者零标志位ZF = 1,则退出循环。

64位汇编语言基础