x86汇编条件跳转指令完全解析:从CMP到有/无符号跳转与If实现
本文系统介绍了x86汇编语言中的条件跳转指令及其应用。主要内容包括:1)CMP指令与JZ/JE指令的工作原理及标志位影响;2)JNE/JNZ、JL/JNGE、JLE/JNG、JG/JNLE等带符号条件跳转指令;3)JA/JNBE、JNB/JAE、JB/JNAE、JBE/JNA等无符号条件跳转指令;4)无条件跳转指令JMP的实现;5)通过代码示例详细展示了各种条件跳转指令在if语句中的具体应用,并对
目录
018-JL,JNGE JLE,JNG JG,JNLE JGE,JNL带符号条件转移指令小结
020-无符号数条件转移指令JNB JAE JNC(大于等于)
条件分支是程序智能的起点。在CPU层面,这完全依赖于标志位与跳转指令的精密舞蹈。 本文将彻底拆解x86汇编中这套机制,并揭示其如何支撑起你写的每一个
if语句。
012-cmp指令与JZ JE指令
知识点:
比较指令CMP
条件跳转指令JZ
ZF(零标志)
一、CMP 和JZ 指令
比较指令CMP
格式: CMP A,B // A-B;
功能: 两个操作数相减,即从A中减去B,其结果不影响操作数,只会影响标志位, 对标志位的影响与SUB指令相同。本条指令主要是用于配合条件转移指令使用。如JZ ZF=0时,跳转
条件转移指令 JE/JZ
格式: JE/JZ标号 //等于跳转
功能: ZF=1,转到指定地址执行
说明:
1. 指令JE与JZ等价,它们是根据标志位ZF进行转移的指令
2. JE,JZ均为一条指令的两种助记符表示方法
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
printf("begin\n");
int a=3;
if (a!=3)
{
printf("do code\n");
}
printf("end");
return 0;
}
汇编代码:
00401000 /$ 55 PUSH EBP
00401001 |. 8BEC MOV EBP,ESP
00401003 |. 51 PUSH ECX
00401004 |. 68 F4204000 PUSH 12.004020F4 ; /format = "begin\n"
00401009 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf // printf("begin\n");
0040100F |. 83C4 04 ADD ESP,4
00401012 |. C745 FC 03000>MOV DWORD PTR SS:[EBP-4],3 //int a=3
00401019 |. 837D FC 03 CMP DWORD PTR SS:[EBP-4],3 //if(a!=3)
0040101D |. 74 0E JE SHORT 12.0040102D //跳转已实现(ZF=1)
0040101F |. 68 FC204000 PUSH 12.004020FC ; /format = "do code\n"
00401024 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf // printf("do code\n");
0040102A |. 83C4 04 ADD ESP,4
0040102D |> 68 08214000 PUSH 12.00402108 ; /format = "end"
00401032 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf // printf("end");
00401038 |. 83C4 04 ADD ESP,4
0040103B |. 33C0 XOR EAX,EAX
0040103D |. 8BE5 MOV ESP,EBP
0040103F |. 5D POP EBP
00401040 \. C3 RETN
如果在OD中修改ZF标志位为0,则跳转变成未实现:

013-JNE指令与标志位(ZF等于)
知识点:
条件转移指令JNE/JNZ
ZF(零标志)
一、 不等于转移指令 JNE/JNZ (等于JE/JZ)
1、 JNE/JNZ功能
条件转移指令JNE/JNZ //不等于转移
格式: JNE/JNZ 标号
功能: ZF=0,转至标号地址处执行
2、代码测试
#include "stdafx.h" (禁止VS自动优化)
int _tmain(int argc, _TCHAR* argv[])
{
printf("begin\n");
int a=4;
if (a==3)
{
printf("do jump\n");
}else{
printf("do not\n");
}
printf("end\n");
return 0;
}
汇编代码为:
00401000 > $ 55 push ebp
00401001 . 8BEC mov ebp,esp
00401003 . 51 push ecx
00401004 . 68 F4204000 push 13.004020F4 ; /format = "begin"
call dword ptr ds:[<&MSVCR100.printf>] ; \printf
0040100F . 83C4 04 add esp,0x4
00401012 . C745 FC 04000>mov dword ptr ss:[ebp-0x4],0x4
00401019 . 837D FC 03 cmp dword ptr ss:[ebp-0x4],0x3
0040101D . 75 10 jnz short 13.0040102F (这里如果不跳转,就一定会执行下面的jmp, 如果跳转,则跳到下面的jmp的后面),这就是if...else在汇编中的一种形式
0040101F 68 db 68 ; CHAR 'h'
00401020 . FC204000 dd 13.004020FC ; ASCII "do jump\n"
call dword ptr ds:[<&MSVCR100.printf>] ; \printf
0040102A . 83C4 04 add esp,0x4
0040102D . EB 0E jmp short 13.0040103D
0040102F > 68 08214000 push 13.00402108 ; ASCII "do not\n"
00401034 . FF15 A0204000 call dword ptr ds:[<&MSVCR100.printf>] ; \printf
0040103A . 83C4 04 add esp,0x4
0040103D > 68 10214000 push offset 13._load_config_used ; /format = "end
"
call dword ptr ds:[<&MSVCR100.printf>] ; \printf
00401048 . 83C4 04 add esp,0x4
0040104B . 33C0 xor eax,eax
0040104D . 8BE5 mov esp,ebp
0040104F . 5D pop ebp
00401050 . C3 retn
用内嵌汇编形式写C++:
int a=4;
__asm
{
mov eax,3
sub eax,a //3-4
jz end; //ZF=1
}
printf("未跳转\n");
JMP xxxx (xxxx为地址)
end:
printf("跳转\n");
xxxx printf("end\n");
getchar();
三、作业
书写汇编代码,用cmp指令及所学条件转移指令模拟 简单的if语句功能。
014-无条件跳转指令jmp
知识点:
无条件跳转指令jmp
goto指令
优化后的指令
一、GOTO与JMP
无条件跳转指令
格式: JMP A
1. 其中A为转移的目的地址。程序转移到目的地址所指向的指令继续往下执行。
// JZ/JE JNZ/JNE 都需要一个条件,条件成立才跳转,而jmp不需要。
2. 本组指令对标志位无影响.
3、代码测试
printf("begin\n");
goto end; //对应汇编中的JMP
printf("do this");
end:
printf("end\n");
完全代码的汇编代码:
00401000 >/$ 56 push esi
mov esi,dword ptr ds:[<&MSVCR100.printf>>; msvcr100.printf
00401007 |. 68 F4204000 push 14.004020F4 ; /format = "begin"
0040100C |. FFD6 call esi ; \printf
0040100E |. 68 04214000 push 14.00402104 ; ASCII "end\n"
00401013 |. FFD6 call esi
00401015 |. 83C4 08 add esp,0x8
00401018 |. 33C0 xor eax,eax
0040101A |. 5E pop esi
0040101B \. C3 retn
二、优化后的指令
/0d 禁用优化
/01 最小化大小
/02 最大化速度
/0x 完全优化
三、作业
1、使用jmp指令实现一个类似while(1){} 的循环,试一试?
015-条件跳转JL JNGE(SF小于)
知识点:
条件转移指令 JNGE
条件转移指令 JL
一、指令格式
条件转移指令 JL/JNGE
格式: JL/JNGE 标号地址
功能: 小于/不大于不等于时转移 标号地址
JNGE 有符号 不大于不等于 则跳转 //Jump if Not Greater or Equal
JL 有符号 小于 则跳转 //Jump if Less
SF=1; 符号标志位为1 则跳转到标号地址执行
二、代码测试
int _tmain(int argc, _TCHAR* argv[])
{
printf("begin\n");
int a=0xA;
int b=0x20;
if (a>=b)
{
printf("do this");
}
printf("end\n");
return 0;
}
__asm
{
mov ebx,b
sub a,ebx
jnge end
mov ebx,ebx
jl end
}
end:
printf("end\n");
三、作业
int a=33;
if (a>=55)
{
printf("do if");
}
printf("end");
试试用汇编替换if语句,实现相同功能,你会怎么写?
016-JLE JNG(小于等于)
知识点:
条件转移指令 JLE
条件转移指令 JNG
一、指令格式
条件转移指令 JLE/JNG
格式: JLE/JNG 标号地址
功能: 小于等于/不大于 时转到标号地址
JNG 有符号 不大于 则跳转 //Jump if Not Greater
JLE 有符号 小于等于 则跳转 //Jump if Less or Equal
SF=1,ZF=1,OF=1 //其中一个或者多个为1 则跳转
二、代码测试
#include <stdio.h> (.C格式,禁止优化)
int main(){
int a=3;
int b=5;
printf("begin\n");
if (a>b)
{
printf("do this");
}
printf("end;\n");
return 0;
}
汇编代码:
00401000 >/$ 55 push ebp
00401001 |. 8BEC mov ebp,esp
00401003 |. 83EC 08 sub esp,0x8
00401006 |. C745 FC 03000>mov [local.1],0x3
0040100D |. C745 F8 05000>mov [local.2],0x5
00401014 |. 68 18304000 push 16.00403018 ; /format = "begin"
00401019 |. FF15 A0204000 call dword ptr ds:[<&MSVCR100.printf>] \printf
0040101F |. 83C4 04 add esp,0x4
00401022 |. 8B45 FC mov eax,[local.1]
00401025 |. 3B45 F8 cmp eax,[local.2]
00401028 |. 7E 0E jle short 16.00401038
0040102A |. 68 20304000 push 16.00403020 /format = "do this"
0040102F |. FF15 A0204000 call dword ptr ds:[<&MSVCR100.printf>] ; \printf
00401035 |. 83C4 04 add esp,0x4
00401038 |> 68 28304000 push 16.00403028 ; /format = "end;"
0040103D |. FF15 A0204000 call dword ptr ds:[<&MSVCR100.printf>] ; \printf
00401043 |. 83C4 04 add esp,0x4
00401046 |. 33C0 xor eax,eax
00401048 |. 8BE5 mov esp,ebp
0040104A |. 5D pop ebp
0040104B \. C3 retn
//OD ctrl+* 设置下一条要执行指令的地址 简单的说就是设置EIP
017-JG JNLE(大于转移)指令
知识点:
条件转移指令 JG(> 时转移)
条件转移指令 JNLE(<=时不转移)
JMP //014
JE/JZ //= //012 Jump if Equl
JNE/JNZ //不= //013
//带符号数条件转移指令
JL /JNGE //不>= //小于 < //015
JLE/JNG //不> //小于等于<= //016
JG/JNLE //不<= //大于 >//017
JGE/JNL //不< //大于等于>= //017
Jump 跳转/转移
Not 不
Equal 相等
Zero 零
Less 小于
Greater 大于
一、指令格式
JG/JNLE 标号地址 //不<= //大于 > // ZF=0 && SF=0 && OF=0
JGE/JNL 标号地址 //不< //大于等于 >=
JG : Jump if Greater // > 跳
JNLE:Jump if Not Less or Equal //不<= 跳
JGE :Jump if Greater or Equal // >= 跳
JNL: Jump if Not Less //不< 跳
二、代码测试
printf("begin\n");
int a=4;
if (a<=3)
if (!(a>3))
{
printf("小于等于");
} //大于时跳转//不小于等于跳转
__asm
{
cmp a,3
JNLE end //JG end
}
printf("do this\n");
printf("小于等于");
end:
printf("end");
return 0;
018-JL,JNGE JLE,JNG JG,JNLE JGE,JNL带符号条件转移指令小结
一、条件转移指令
|
助忆符 |
检测的转移条件 |
功能描述 |
|
|
JE/JZ |
ZF=1 |
Jump Equal == 跳转 |
Jump Zero != 不跳转 |
|
JNE/JNZ |
ZF=0 |
Jump Not Equal != 跳转 |
Jump Not Zero == 不跳转 |
|
JG/JNLE |
ZF=0&&SF=OF |
Jump Greater >跳转 |
Jump Not Less or Equal <= 不跳转 |
|
JGE/JNL |
SF=OF |
Jump Greater Equal >=跳转 |
Jump Not Less < 不跳转 |
|
JL/JNGE |
SF!=OF |
Jump Less <跳转 |
Jump Not Greater or Equal >= 不跳转 |
|
JLE/JNG |
ZF=1 || SF!=OF |
Jump Less or Equal <=跳转 |
Jump Not Greater > 不跳转 |
二、代码测试
JE/JZ != 不跳转
JNZ/JNE == 不跳转
JG/JNLE <= 不跳转
JGE/JNL < 不跳转
JL/JNGE >= 不跳转
JLE/JNG > 不跳转
printf("begin\n");
//unsigned
int a=3,b=5;
if (a!=b) //je [不等于时执行,等于时jmp]
if (a==b) //jnz [等于时执行,不等于时jmp]
if (a<=b) //jg [小于等于时执行,大于时jmp]
if (a<b) //jge [小于时执行,大于等于时jmp]
if (a>=b) //jl [大于等于时执行,小于时jmp]
if (a>b)//jle [大于时执行,小于等于时jmp]
{
printf("do if");
}
printf("end");
return 0;
汇编代码如下:
00401000 /$ 55 PUSH EBP
00401001 |. 8BEC MOV EBP,ESP
00401003 |. 83EC 08 SUB ESP,8
00401006 |. 68 F4204000 PUSH 18.004020F4 ; /format = "begin\n"
0040100B |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf
00401011 |. 83C4 04 ADD ESP,4
00401014 |. C745 FC 03000>MOV DWORD PTR SS:[EBP-4],3
0040101B |. C745 F8 05000>MOV DWORD PTR SS:[EBP-8],5
00401022 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401025 |. 3B45 F8 CMP EAX,DWORD PTR SS:[EBP-8]
00401028 |. 74 36 JE SHORT 18.00401060
0040102A |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
0040102D |. 3B4D F8 CMP ECX,DWORD PTR SS:[EBP-8]
00401030 |. 75 2E JNZ SHORT 18.00401060
00401032 |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
00401035 |. 3B55 F8 CMP EDX,DWORD PTR SS:[EBP-8]
00401038 |. 7F 26 JG SHORT 18.00401060
0040103A |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
0040103D |. 3B45 F8 CMP EAX,DWORD PTR SS:[EBP-8]
00401040 |. 7D 1E JGE SHORT 18.00401060
00401042 |. 8B4D FC MOV ECX,DWORD PTR SS:[EBP-4]
00401045 |. 3B4D F8 CMP ECX,DWORD PTR SS:[EBP-8]
00401048 |. 7C 16 JL SHORT 18.00401060
0040104A |. 8B55 FC MOV EDX,DWORD PTR SS:[EBP-4]
0040104D |. 3B55 F8 CMP EDX,DWORD PTR SS:[EBP-8]
00401050 |. 7E 0E JLE SHORT 18.00401060
00401052 |. 68 FC204000 PUSH 18.004020FC ; /format = "do if"
00401057 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf
0040105D |. 83C4 04 ADD ESP,4
00401060 |> 68 04214000 PUSH 18.00402104 ; /format = "end"
00401065 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf
0040106B |. 83C4 04 ADD ESP,4
0040106E |. 33C0 XOR EAX,EAX
00401070 |. 8BE5 MOV ESP,EBP
00401072 |. 5D POP EBP
00401073 \. C3 RETN
019-无符号数条件转移指令JA JNBE(大于)
知识点:
JA (> 时转移)
JNBE(<=时不转移)
JA与JG的区别
条件转移指令

Above 高于 Greater 大于
Below 低于 Less 小于
一、无符号大于转移指令JA/JNBE
JA : 高于 时跳转 // >时跳转
JNBE: 不低于等于 时跳转 //<=时不跳转
JA与JG区别:
JG是带符号数比较 >
JA是无符号数比较 >
二、代码测试
//CF(进位标志位)
printf("begin\n");
int a=3,b=-5;
unsigned int a2=a,b2=b;
if (a2<=b2) //无符号的生成JA 不够减 借位
if (a<=b) ///<=时不跳转,>时跳转,带符号的生成JG指令
{
printf("do if\n");
}
printf("end\n");
汇编代码:
00401014 |. C745 FC 03000>MOV DWORD PTR SS:[EBP-4],3
0040101B |. C745 F4 FBFFF>MOV DWORD PTR SS:[EBP-C],-5
00401022 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401025 |. 8945 F0 MOV DWORD PTR SS:[EBP-10],EAX
00401028 |. 8B4D F4 MOV ECX,DWORD PTR SS:[EBP-C]
0040102B |. 894D F8 MOV DWORD PTR SS:[EBP-8],ECX
0040102E |. 8B55 F0 MOV EDX,DWORD PTR SS:[EBP-10]
00401031 |. 3B55 F8 CMP EDX,DWORD PTR SS:[EBP-8]
00401034 |. 77 16 JA SHORT 19.0040104C
00401036 |. 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4]
00401039 |. 3B45 F4 CMP EAX,DWORD PTR SS:[EBP-C]
0040103C |. 7F 0E JG SHORT 19.0040104C
0040103E |. 68 FC204000 PUSH 19.004020FC ; /format = "do if\n"
00401043 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf
00401049 |. 83C4 04 ADD ESP,4
0040104C |> 68 04214000 PUSH 19.00402104 ; /format = "end\n"
00401051 |. FF15 A0204000 CALL DWORD PTR DS:[<&MSVCR100.printf>] ; \printf
00401057 |. 83C4 04 ADD ESP,4
020-无符号数条件转移指令JNB JAE JNC(大于等于)
知识点:
JNB (不小于)
JAE (高于等于)
JNC (CF!=1)
JNB与JGE的区别
一、无符号大于转移指令JA/JNBE
JNB : 低于 时不跳转 //>=时跳转 //OD
JAE: 高于等于 时跳转 //>=时跳转
JNC :Jump Not Carry 没进位时跳转 //CF=0
JA与JG区别:
JNB 是带符号数比较 >=
JGE 是无符号数比较 >=
二、代码测试
//CF(进位标志位)
printf("begin\n");
int a=3,b=-5;
unsigned int a2=a,b2=b;
if (a2<b2) //无符号的生成JAE JNB 不够减借位
if (a<b) // <时不跳转,>时跳转,带符号的生成JGE JNL指令
{
printf("do if\n");
}
021-无符号数条件转移指令JB JNAE JC(小于)
知识点:
JB/JNAE/JC <指令
与JL/JNGE区别
一、无符号大于转移指令JB/JNAE/JC
JB: 低于 时跳转 //< 时跳转 //OD
JNAE: 高于等于 时不跳转 //>=时不跳转
JC :Jump Carry 进位时跳转 //CF=1
JB与JL区别:
JB 是无符号数比较 >=
JL 是带符号数比较 >=
二、代码测试
//CF(进位标志位)
printf("begin\n");
int a=3,b=-5;
unsigned int a2=a,b2=b;
if (a2>= b2)//无符号的生成JAE JNB 不够减借位
if (a>= b) ///<时不跳转,>时跳转,带符号的生成JGE JNL指令
{
printf("do if\n");
}
022-无符号数条件转移指令JBE JNA(小于等于)
知识点:
JBE/JNA <=指令
与JLE/JNG区别
一、无符号大于转移指令JBE/JNA
JBE: 低于等于 时跳转 // <=时跳转 //OD
JNA: 高于 时不跳转 //> 不跳转
JBE与JLE区别:
JLE 是带符号数比较 >=
JBE 是无符号数比较 >=
二、代码测试
//CF(进位标志位)
printf("begin\n");
int a=3,b=-5;
unsigned int a2=a,b2=b;
if (a2> b2) //无符号的生成JBE JNA 不够减借位
if (a>b) //<时不跳转,>时跳转,带符号的生成JLE JNG指令
{
printf("do if\n");
}
补充:总结
C的if语句与汇编的跳转指令的对应关系

Jump 跳转/转移
Not 不
Equal 相等
Zero 零
Less 小于
Greater 大于
Above 高于
Below 低于
Carry 进位
一、相等与不相等的判断与跳转
int a=2,b=3;
if(a=b){ => JNE/JNZ
//相等则执行,不等则跳转
printf("not jump");
}
if(a!=b){ => JE/JZ
//不相等则执行,相等等则跳转
printf("not jump");
}
二、有符号条件转移
int a=2,b=3;
if(a>b){ => JLE/JNG
//大于则执行,小于等于则跳转
printf("not jump");
}
if(a<b){ => JGE/JNL
//小于则执行,大于等于则跳转
printf("not jump");
}
if(a>=b){ => JL/JNGE
//大于等于则执行,小于则跳转
printf("not jump");
}
if(a<=b){ => JG/JNLE
//小于等于则执行,大于则跳转
printf("not jump");
}
三、无符号条件转移
unsigned int a=2,b=-3;
if(a>b){ => JBE/JNA
//大于则执行,小于等于则跳转
printf("not jump");
}
unsigned int a=2,b=-3;
if(a<b){ => JAE/JNB
//小于则执行,大于等于则跳转
printf("not jump");
}
unsigned int a=2,b=-3;
if(a>=b){ => JB/JNAE
//大于等于则执行,小于则跳转
printf("not jump");
}
unsigned int a=2,b=-3;
if(a<=b){ => JA/JNBE
//小于等于则执行,大于则跳转
printf("not jump");
}
计算机科学与技术 & 计算机网络技术:双专业课程体系完全导航指南
本系列目录
1、逆向工程基础:Ollydbg(OD)调试器实战与MOV指令寻址方式精讲
2、汇编语言核心概念精讲:从ADD、SUB、MOVSX/MOVZX到LEA与寄存器详解
3、x86汇编条件跳转指令完全解析:从CMP到有/无符号跳转与If实现
4、x86汇编函数调用完全解析:栈帧(EBP/ESP)构建与三种调用约定(cdecl/stdcall/fastcall)对比
5、汇编逆向还原核心:if-else与switch-case结构的识别与C代码重构
6、编译器优化揭秘:对比for循环的汇编实现与INC vs ADD指令的性能抉择
7、x86浮点运算基础:FPU寄存器、FLD/FSTP与FADD/FSUB等指令精讲
8、汇编位移指令全解与逆向实战:从SHR/SHL到ROL/ROR,逆向分析strcmp
9、汇编位运算指令精讲:掌握AND/OR/XOR/NOT四大核心操作
10、x86汇编字符串处理:SCASB/SCASW指令与REPNE/REPE重复前缀详解
11、汇编实战:用REPNZ SCASB与REPZ CMPSB从零实现strcmpA/W
12、x86汇编批量操作指令:LOOP循环控制与STOS/LODS串操作详解
更多推荐



所有评论(0)