前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >3.9 控制转移指令

3.9 控制转移指令

作者头像
命运之光
发布2024-09-13 13:15:44
发布2024-09-13 13:15:44
9600
代码可运行
举报
运行总次数:0
代码可运行

3.9 控制转移指令

1. 修改IP, CS
无条件转移指令 JMP 用于直接跳转到指定的代码位置,无需判断任何条件。这在改变程序的执行流程时非常有用。
  • 段内跳转: 常用于同一段中的跳转。
  • 段间跳转: 用于不同段之间的跳转。
  • 直接跳转: 直接指定目标地址或标号。
  • 间接跳转: 通过寄存器或内存地址间接指定跳转目标。
1. 段内直接转移 (JMP 目标标号)
  • 用途: 在同一个代码段内跳转到某个标号。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JMP 目标标号
  • 示例:
代码语言:javascript
代码运行次数:0
复制
JMP START   ; 跳转到标号 START
2. 段内直接转移 (使用 NEAR PTR)段内直接近转移指令
  • 用途: 类似于 JMP 目标标号,显式指定跳转到同一个段内。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JMP NEAR PTR 目标标号
  • 示例:
代码语言:javascript
代码运行次数:0
复制
JMP NEAR PTR NEXT_STEP   ; 跳转到标号 NEXT_STEP
3. 段内直接短转移 (JMP SHORT)
  • 用途: 用于在同一个段内跳转,但跳转距离较小(-128 到 +127 字节内)。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JMP SHORT 目标标号
  • 示例:
代码语言:javascript
代码运行次数:0
复制
JMP SHORT LOOP_END   ; 短跳转到标号 LOOP_END
4. 段内间接转移 (JMP WORD PTR)
  • 用途: 跳转地址由内存中的一个 16 位地址(段内地址)指定。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JMP WORD PTR [内存地址]
  • 示例:
代码语言:javascript
代码运行次数:0
复制
JMP WORD PTR [BX]   ; 跳转到 BX 指向的地址
5. 段间直接转移 (JMP FAR PTR)
  • 用途: 在不同代码段之间进行跳转,指定段选择子和偏移量。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JMP FAR PTR 段:偏移
  • 示例:
代码语言:javascript
代码运行次数:0
复制
JMP FAR PTR 0x1234:0x5678   ; 跳转到段 0x1234 中偏移 0x5678 的位置
6. 段间间接转移 (JMP DWORD PTR)
  • 用途: 跳转地址由内存中的一个 32 位地址(段:偏移)指定,用于段间跳转。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JMP DWORD PTR [内存地址]
  • 示例:
代码语言:javascript
代码运行次数:0
复制
JMP DWORD PTR [SI]   ; 跳转到 SI 指向的 32 位段间地址
2. 条件转移指令 ★★
检测单个标志位
  • 相等/不相等:
    • JZ/JE: ZF=1, 0/相等则转移
    • JNZ/JNE: ZF=0, 非0/不相等则转移
  • 符号:
    • JS: SF=1, 结果为负则转移
    • JNS: SF=0, 结果为正则转移
  • 溢出:
    • JO: OF=1, 结果溢出则转移
    • JNO: OF=0, 结果不溢出则转移
  • 奇偶性:
    • JP/JPE: PF=1, 低8位中“1”的个数为偶数则转移
    • JNP/JPO: PF=0, 低8位中“1”的个数为奇数则转移
  • 进位:
    • JC: CF=1, 有进位则转移
    • JNC: CF=0, 无进位则转移
无符号数比较大小
  • 大于/不低于且不等于:
    • JA/JNBE: CF=0 且 ZF=0, A > B 则转移
  • 大于等于/不低于:
    • JAE/JNB: CF=0 或 ZF=1, A ≥ B 则转移
  • 低于/不高于且不等于:
    • JB/JNAE: CF=1 且 ZF=0, A < B 则转移
  • 低于等于/不高于:
    • JBE/JNA: CF=1 或 ZF=1, A ≤ B 则转移
代码语言:javascript
代码运行次数:0
复制
MOV AL, 5       ; AL = 5
MOV BL, 10      ; BL = 10

CMP AL, BL      ; 比较 AL 和 BL

JA GREATER      ; 如果 AL > BL 跳转到 GREATER(这里不会跳转,因为 AL < BL)
JB LESS_THAN    ; 如果 AL < BL 跳转到 LESS_THAN(这里会跳转到 LESS_THAN)
JAE GREATER_EQUAL ; 如果 AL ≥ BL 跳转到 GREATER_EQUAL(这里不会跳转)
JBE LESS_THAN_OR_EQUAL ; 如果 AL ≤ BL 跳转到 LESS_THAN_OR_EQUAL(这里会跳转到 LESS_THAN_OR_EQUAL)

; 定义标号
GREATER:
    ; AL > BL 的处理代码
    JMP END
LESS_THAN:
    ; AL < BL 的处理代码
    JMP END
GREATER_EQUAL:
    ; AL ≥ BL 的处理代码
    JMP END
LESS_THAN_OR_EQUAL:
    ; AL ≤ BL 的处理代码
    JMP END

END:
    ; 程序结束
1. 大于/不低于且不等于 (**<font style="color:#117CEE;">JA/JNBE</font>**)
  • 条件: 当 CF=0ZF=0 时,表示 A > B(A 大于 B),执行跳转。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JA 目标标号   ; 若 A > B 则跳转
  • 示例:
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX     ; 比较 AX 和 BX
JA  GREATER    ; 若 AX > BX 则跳转到 GREATER
2. 大于等于/不低于 (<font style="color:#117CEE;">JAE/JNB</font>)
  • 条件: 当 CF=0ZF=1 时,表示 A ≥ B(A 大于或等于 B),执行跳转。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JAE 目标标号   ; 若 A ≥ B 则跳转
  • 示例:
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX     ; 比较 AX 和 BX
JAE  NOTLESS   ; 若 AX ≥ BX 则跳转到 NOTLESS
3. 低于/不高于且不等于 (<font style="color:#117CEE;">JB/JNAE</font>)
  • 条件: 当 CF=1ZF=0 时,表示 A < B(A 小于 B),执行跳转。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JB 目标标号   ; 若 A < B 则跳转
  • 示例:
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX     ; 比较 AX 和 BX
JB  LESS       ; 若 AX < BX 则跳转到 LESS
4. 低于等于/不高于 (<font style="color:#117CEE;">JBE/JNA</font>)
  • 条件: 当 CF=1ZF=1 时,表示 A ≤ B(A 小于或等于 B),执行跳转。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
JBE 目标标号   ; 若 A ≤ B 则跳转
  • 示例:
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX     ; 比较 AX 和 BX
JBE  NOTGREATER ; 若 AX ≤ BX 则跳转到 NOTGREATER
具体使用场景
  • 控制程序流程: 这些指令用于控制程序的流程,如在比较两个无符号数后,根据结果决定程序的下一步操作。
  • 循环: 这些指令可以与循环结合使用,根据循环体内某些条件来决定是否继续循环或跳出循环。
  • 分支选择: 根据比较结果在不同的代码路径之间进行选择,实现条件分支。
示例代码
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX      ; 比较 AX 和 BX
JA  GREATER     ; 若 AX > BX 跳转到 GREATER
JBE LESS_EQUAL  ; 否则跳转到 LESS_EQUAL

GREATER:
    ; 执行 AX > BX 时的代码
    JMP END

LESS_EQUAL:
    ; 执行 AX ≤ BX 时的代码
    JMP END

END:
    ; 程序结束

在上述示例中,根据 AXBX 的比较结果,程序会跳转到不同的标号来执行相应的代码。

有符号数比较大小
  • 大于/不小于且不等于:
    • JG/JNLE: SF=OF 且 ZF=0, A > B 则转移
  • 大于等于/不小于:
    • JGE/JNL: SF=OF 或 ZF=1, A ≥ B 则转移
  • 小于/不大于且不等于:
    • JL/JNGE: SF≠OF 且 ZF=0, A < B 则转移
  • 小于等于/不大于:
    • JLE/JNG: SF≠OF 或 ZF=1, A ≤ B 则转移
代码语言:javascript
代码运行次数:0
复制
ORG 100h      ; 指令段的起始地址

MOV AL, -5    ; AL = -5
MOV BL, 3     ; BL = 3

CMP AL, BL    ; 比较 AL 和 BL

; 检查是否大于
JG GREATER    ; 如果 AL > BL (SF=OF 且 ZF=0) 跳转到 GREATER

; 检查是否大于等于
JGE GREATER_EQUAL ; 如果 AL ≥ BL (SF=OF 或 ZF=1) 跳转到 GREATER_EQUAL

; 检查是否小于
JL LESS_THAN  ; 如果 AL < BL (SF≠OF 且 ZF=0) 跳转到 LESS_THAN

; 检查是否小于等于
JLE LESS_THAN_OR_EQUAL ; 如果 AL ≤ BL (SF≠OF 或 ZF=1) 跳转到 LESS_THAN_OR_EQUAL

; 如果没有跳转,执行默认操作
DEFAULT_ACTION:
    MOV DX, OFFSET NOT_JUMPED
    MOV AH, 09h
    INT 21h         ; 打印字符串
    JMP END_PROGRAM

; 大于的处理
GREATER:
    MOV DX, OFFSET GREATER_MSG
    MOV AH, 09h
    INT 21h         ; 打印字符串
    JMP END_PROGRAM

; 大于等于的处理
GREATER_EQUAL:
    MOV DX, OFFSET GREATER_EQUAL_MSG
    MOV AH, 09h
    INT 21h         ; 打印字符串
    JMP END_PROGRAM

; 小于的处理
LESS_THAN:
    MOV DX, OFFSET LESS_THAN_MSG
    MOV AH, 09h
    INT 21h         ; 打印字符串
    JMP END_PROGRAM

; 小于等于的处理
LESS_THAN_OR_EQUAL:
    MOV DX, OFFSET LESS_THAN_OR_EQUAL_MSG
    MOV AH, 09h
    INT 21h         ; 打印字符串
    JMP END_PROGRAM

; 程序结束
END_PROGRAM:
    MOV AH, 4Ch
    INT 21h         ; 终止程序

; 字符串数据
GREATER_MSG DB 'AL is greater than BL$', 0
GREATER_EQUAL_MSG DB 'AL is greater than or equal to BL$', 0
LESS_THAN_MSG DB 'AL is less than BL$', 0
LESS_THAN_OR_EQUAL_MSG DB 'AL is less than or equal to BL$', 0
NOT_JUMPED DB 'No jump occurred$', 0
3. 循环控制指令 ★
1. 基本循环指令 (LOOP)
  • 作用😗* 在每次执行 **LOOP** 指令时,寄存器 **CX** 的值减 1。如果 **CX** 不为 0,**则跳转到指定的标号处继续执行;如果 CX 为 0,则跳出循环,继续执行下一条指令。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
LOOP 目标标号
  • 示例:
代码语言:javascript
代码运行次数:0
复制
MOV CX, 0100H  ; 设置循环次数为 256 次
DELAY: 
    ; 这里可以是一些操作,比如 NOP
    LOOP DELAY  ; 每次循环结束时 CX 减 1,不为 0 则跳转到 DELAY

在这个示例中,程序会在 DELAY 标号处循环 256 次,然后继续执行 LOOP DELAY 之后的代码。

2. 相等/为零计数循环指令 (LOOPE/LOOPZ)
  • 作用: 在每次执行 LOOPE(或 LOOPZ)指令时,寄存器 CX 的值减 1。如果 <font style="color:#DF2A3F;">CX</font> 不为 0 并且零标志位 <font style="color:#DF2A3F;">ZF</font> 为 1,则跳转到指定的标号处继续执行;否则跳出循环,继续执行下一条指令。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
LOOPE 目标标号  ; 或者 LOOPZ 目标标号
  • 示例:
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX     ; 比较 AX 和 BX
MOV CX, 5      ; 设置循环次数为 5 次
L1:
    ; 如果 AX = BX (ZF = 1),则执行以下代码
    LOOPE L1   ; 如果 CX 不为 0 且 ZF = 1,跳转到 L1

在这个示例中,LOOPE L1 会在 CX 不为 0 且 ZF 为 1 的情况下跳转到 L1 继续循环。否则,将跳出循环。

3. 不相等/不为零计数循环指令 (LOOPNE/LOOPNZ)
  • 作用: 在每次执行 LOOPNE(或 LOOPNZ)指令时,寄存器 CX 的值减 1。如果 **<font style="color:#DF2A3F;">CX</font>** 不为 0 并且零标志位 **<font style="color:#DF2A3F;">ZF</font>** 为 0,则跳转到指定的标号处继续执行;否则跳出循环,继续执行下一条指令。
  • 语法:
代码语言:javascript
代码运行次数:0
复制
LOOPNE 目标标号  ; 或者 LOOPNZ 目标标号
  • 示例:
代码语言:javascript
代码运行次数:0
复制
CMP AX, BX     ; 比较 AX 和 BX
MOV CX, 5      ; 设置循环次数为 5 次
L2:
    ; 如果 AX ≠ BX (ZF = 0),则执行以下代码
    LOOPNE L2  ; 如果 CX 不为 0 且 ZF = 0,跳转到 L2

在这个示例中,LOOPNE L2 会在 CX 不为 0 且 ZF 为 0 的情况下跳转到 L2 继续循环。否则,将跳出循环。

总结
  • LOOP 指令简单地基于 CX 的值进行循环控制。
  • LOOPE/LOOPZ 在循环时还考虑 ZF 是否为 1(表示相等或为零的情况)。
  • LOOPNE/LOOPNZ 在循环时考虑 ZF 是否为 0(表示不相等或不为零的情况)。
4. 调用指令

在汇编语言中,CALL 指令用于调用一个子程序(也叫过程或函数)。调用子程序时,程序的执行会跳转到子程序的起始位置,并在子程序执行完成后返回到调用CALL 指令的下一条指令继续执行。

CALL 指令的工作原理:
  1. 保存返回地址: 当 CALL 指令被执行时,当前指令的下一条指令地址(即返回地址)会被压入堆栈,以便在子程序执行完成后能够返回。
  2. 跳转到子程序: 程序控制权会跳转到 CALL 指定的标号处(即子程序的起始地址),开始执行子程序的代码。
  3. 执行子程序: 子程序中的代码会被执行,直到遇到 RET(返回)指令。
  4. 返回主程序: 当子程序执行完毕并遇到 RET 指令时,返回地址会从堆栈中弹出,程序控制权会返回到主程序的 CALL 指令之后的指令继续执行。
语法:
代码语言:javascript
代码运行次数:0
复制
CALL 标号
示例:
代码语言:javascript
代码运行次数:0
复制
MAIN:
    ; 一些主程序代码
    CALL SUBROUTINE   ; 调用子程序 SUBROUTINE
    ; 子程序执行完毕后,程序会回到这里继续执行
    ...

SUBROUTINE:
    ; 子程序的代码
    RET               ; 返回到调用点
示例详解:
  • 在上述代码中,CALL SUBROUTINE 使得程序跳转到 SUBROUTINE 标号处执行子程序的代码。
  • SUBROUTINE 执行完 RET 指令时,程序返回到 CALL SUBROUTINE 之后的代码,继续执行主程序。
总结:
  • CALL 指令用于实现子程序的调用,使得代码模块化、便于复用。
  • CALL 指令配合 RET 指令使用,确保程序在执行完子程序后能够正确返回到调用点继续执行。
5. 返回指令

在汇编语言中,RET 指令用于从子程序(或函数、过程)返回到调用该子程序的主程序位置。它和 CALL 指令相配合使用,以保证在执行完子程序后,程序能够回到主程序继续执行。

RET 指令的工作原理:
  1. 从堆栈中弹出返回地址: 当 RET 指令被执行时,处理器会从堆栈中弹出先前 CALL 指令压入的返回地址。
  2. 跳转到返回地址: 程序的执行将跳转到这个返回地址处,也就是 CALL 指令所在位置的下一条指令,继续执行主程序的代码。
语法:
代码语言:javascript
代码运行次数:0
复制
RET
示例:
代码语言:javascript
代码运行次数:0
复制
MAIN:
    ; 一些主程序代码
    CALL SUBROUTINE   ; 调用子程序 SUBROUTINE
    ; 子程序执行完毕后,程序会回到这里继续执行
    ...

SUBROUTINE:
    ; 子程序的代码
    RET               ; 返回到调用点
示例详解:
  • 在这个示例中,CALL SUBROUTINE 指令调用了一个名为 SUBROUTINE 的子程序。
  • 当子程序执行到 RET 指令时,程序从堆栈中弹出返回地址,并跳回到 CALL SUBROUTINE 指令的下一条指令处,继续执行主程序。
使用场景:
  • RET 指令用于结束子程序的执行,并将程序控制权返回给主程序。
  • 如果子程序中没有 RET 指令,程序将无法正确返回到主程序,可能会导致程序异常或崩溃。
总结:
  • RET 指令确保子程序执行完毕后,程序能够返回到正确的主程序位置继续执行,是实现程序流程控制的重要指令之一。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 3.9 控制转移指令
    • 1. 修改IP, CS
    • 2. 条件转移指令 ★★
    • 3. 循环控制指令 ★
    • 4. 调用指令
    • 5. 返回指令
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档