1 转移指令:条件转移和无条件转移
2 条件转移指令:
| 条件转移指令 | |||
| JXX 标号 | |||
| 单标志条件转移: | |||
| JC (JNC) | 有(无)进位则转 | CF=1(CF=0) | |
| JP (JNP) | 1个数为偶数则转 | PF=1 | |
| JZ (JNZ) | 为零则转 | ZF=1 | |
| JS (JNS) | 为负数则转 | SF=1 | |
| JO (JNO) | 溢出则转 | OF=1 | |
| 无符号数专用: | |||
| JA (JBE) | > (JBE<=) | CF=0 && Zf=0 | JA与JBE相反 |
| JB (JAE) | < (JAE>=) | CF=1 | JB与JAE相反 |
| 有符号数专用: | |||
| JG (JLE) | > | SF=OF且ZF=0 | JG与JLE相反 |
| JL (JGE) | < | SF!=OF且ZF=0 |
附上ADD对标志位的影响:(SUB与ADD基本一致,CMP除不更改目的操作符之外,与SUB一致)
| OF | 字节运算结果超出字节有符号数的范围(-128~+127)或字运算超出字有符号数范围(-32768~+32767)时,OF=1否则OF=0。把操作数视为有符号数时,可以通过此标志了解是否溢出。 |
| SF | 运算结果的最高位为1时,SF=1,否者SF=0 (SF与结果的最高位一致) |
| ZF | 运算结果为0时,ZF=1,否则=0 |
| AF | 运算结果时,D3向D4产生进位时AF=1,否则AF=0 |
| PF | 运算结果中1的个数为偶数时PF=1,否则=0 |
| CF | 运算结果的最高位产生进位时,即字节运算结果超出字节无符号数范围(0~65535)或者字运算结果超出0~65535时,CF=1,否则=0,可以通过此标志了解无符号运算符的溢出情况。 |
再附上各个标志:
|
溢出标志OF(Over flow flag) OV(1) NV(0)
方向标志DF(Direction flag) DN(1) UP(0)
中断标志IF(Interrupt flag) EI(1) DI(0)
符号标志SF(Sign flag) NG(1) PL(0)
零标志ZF(Zero flag) ZR(1) NZ(0)
辅助标志AF(Auxiliary carry flag) AC(1) NA(0)
奇偶标志PF(Parity flag) PE(1) PO(0)
进位标志CF(Carry flag) CY(1) NC(0)
|
| mov al, 76h cmp al, 80h jnz lab2 ;成立 | |
| mov bl, 38h SHL bl,1 ;D7 move to CF JC LAB2 ;不成立 | SHL等同SAL,低位进0,高位进CF,在本次学习中D0到D7用来表示一个字节从最低位到最高位。 |
关于有符号数和无符号数
| 其实很简单理解,这里写出来以防那天糊涂了看下: 有符号数大小的比较标准与无符号数不同; 对于无符号数:每一位均为数值位。 对于有符号数:在机器中以补码表示,其最高位为符号数。当最高位为0时,正数,其余位为数值;最高位为1时,负数,所有位取反加一方为数值。 以单字节数为例: 无符号数的大小关系为: 00h(1)-> 01h -> FFh (255) 有符号数大小关系为:80h(-128)->81h(-127)->...->FFh(-1)->00h(0)->...7Fh (127) 因此: mov al, 76h cmp al, 80h JL 是不成立的,76这个时候作为负数是大于80h的,不要混淆,一定要看清楚是有符号数跳转还是无符号。 |
2.2 条件转移中标号的限制:
【1】80386以上的指令集:只能是近标号(统一代码段);
【2】8086和80286的只能是短标号(不仅必须处于同一代码段,而且相距的字节数在 128~+127之间。(但是不需要加短转移标识符SHORT).当需要转移的目的地超过上述限制时,就必须结合使用无条件转移指令。
3 无条件转移指令
JMP 目的位置
远近是看是否在同一代码段;直接和间接是看是否使用标号(还是偏移地址)
| 指令 | 功能 |
| JMP SHORT 标号 | 转移到指定标号处,该标号与该指令不仅须处于同一代码段,而且相距字节数在-128和127之间,即实现短转移 |
| JMP 近标号 | 同一代码段(直接近转移) |
| JMP 远标号 | 不处于同一代码段(直接远转移) |
| JMP MEM16/REG16 | 由16位存储器操作数或者寄存器操作数间接给出目的地址的偏移地址,实现间接近转移。 |
| JMP MEM32 | 由32位存储器操作数间接给出目的位置的偏移地址和段地址,实现间接远转移。 |
| JMP REG32 | 此为80386以上指令集的指令,由32位寄存器操作数间接给出目的地址的偏移地址,实现间接近转移。 |
3.1 无条件转移使用场合(三个):
| 1)配合条件转移指令实现条件远转移 | ||
| CMP AL, 80H JB LAB2 如果: JB LAB2 中的标号Lab2与条件转移指令不再同一代码段,就会出错,可以改为: | CMP AX, 80h JAE LAB1 JMP LAB2 | 就是用一个相反的指令来铺垫,然后接着JMP到远标号。 |
| 2)避免一个分支“滑入”另一个程序分支 | ||
| 以下面的例子为例: 将有符号数X和Y中的较大者送变量Z,试写出程序段。 X DB 60H Y DB 94H Z DB ? ... mov al, x cmp al, y JL YG; AL <Y则转YG处 mov Z,AL YG: mov BL, Y mov BL, Z OK: | 此例中,正常来说,MOV X,AL执行完毕后,就应该转入 OK了,但是如果按照左边代码的话,代码却会顺序执行到YG, 因此需要无条件转移JMP JMP OK。 | X DB 60H Y DB 94H Z DB ? ... mov al, x cmp al, y JL YG; AL <Y则转YG处 mov Z,AL JMP SHORT OK YG: mov BL, Y mov BL, Z OK: |
| 3)实现多分支程序结构 | JMP不想条件转移指令,它的目的操作数可以是存储器也可以是寄存器,因此 可用来构建多分枝程序。 | |
| 下面是个实例,将分支的标号放入一个数组 中,然后利用数组来引导到对应分支。 例子1: BASE DW ZERO, ONE, TWO, ..., N ... JMP BASE[BX] ... ... ZERO: ... ... JMP OK ONE: ... ... JMP OK ... ... N: ... OK: ... 例子2: 直接利用cx值来转移 JMP CX JMP ECX | 说明: 1 近转移的实质在于:改变IP(EIP)总是指向当前代码段下一顺序指令的顺序,而只想目的位置处的指令,即把目的位置的偏移地址送IP或EIP。 【区别:远转移还要送段地址到CS】 2 近转移指令一般用于向下转移,即目的位置的偏移地址>本转移指令的偏移地址,有时也可用于向上转移。 3 转移指令本身不影响状态标志; 4 在需要根据两个数的比较结果确定流向时,应根据实际问题所设计的数据来选择是无符号数,还是有符号数来选用对应的条件转移指令。 5 有些条件转移指令的助记符有其他表示形式 |
7.3 分支程序设计:
两种设计方法:
1 测试法分支程序设计:选用影响状态标志的指令和条件转移指令;
2 跳转表法分支程序设计:间接寻址的无条件转移指令
7.3.1 测试法
| 测试法 | |
| 常用影响状态标志的指令:CMP | |
| 例子1:求Z=|X-Y| (X,Y有符号数) name example_7.3.1 dseg segment x db 40h y db 73h z db ? dseg ends sseg segment stack db 80h dup(0) sseg ends cseg segment assume cs:cseg, ds:dseg, ss:sseg start: mov ax, dseg mov ds, ax xor ax, ax mov al, x cmp al, y jl xl jmp yl xl: mov bl,y sub bl,al mov z,bl jmp ok yl: ;如果只有两个分支,红色部分常防止在jl xl后,而不用jmp。 sub al,y mov z, al ok: mov ah, 4ch int 21h cseg ends end start | 例子1的另外一种写法: 直接求差值,如果符号是负数,则直接取反,然后再转移。 mov al, x sub al,y jns xg NEG AL ; 取反 xg: mov z, al |
| 例子:7.11 根据键盘输入的0,1,2,3分别显示信息"8086" "80386", "pentium" | 难点: 1 键盘上的0,1,2,3转换为数值1,2,3(也可以不转,但要明白其ASCII码与数值的区别,直接用ASCII码来判断当然也可以) |
| 如果利用 测试法实现如下: | |
| mess0 db '8086','$' ... mov ah, 07h int 21h and al, 0fh ;将对应字符的ascii码转换为0,1,2,3 cmp al,0 jz M0 cmp al,1 jz M1 CMP al,2 jz M2 CMP al,3 jz M3 m3: mov dx, offset mess3 jmp short disp m2: ... disp: mov ah, 09h int 21h ; | |
| 例子7.12 将Blks为首址的连续N个字节数传送至以BLKD为首址的存储区 | 分析问题: 1 难点是数据块的相对位置
2 怎么处理数据传送问题:常用方法 使用编制寄存器 SI, DI (SI指向源,DI指向目的), SI, DI不断加1, 而次数用CX控制(后面的循环结构也是这样的),CX要传输一次就减1.
|
| name example_7.3.1 dseg segment ORG $+24h qiaoString db 'happy national day',0ah, 0dh, '$' N EQU $-qiaoString ; used to get the strs' length BLKS DW qiaoString BLKD DW qiaoString+5 dseg ends sseg segment stack db 80h dup(0) sseg ends cseg segment assume cs:cseg, ds:dseg, ss:sseg start: mov ax, dseg mov ds, ax xor ax, ax ;................. mov dX, blks mov ah, 09h int 21h ; mov cx, N mov SI, BLKS mov DI, BLKD mov BX,1 ; uesd to as a statue, and can join add to replace INC cmp si, di ja move add SI, CX DEC SI add DI, CX DEC DI NEG bx ja move ; not userful, just to make a notification move: mov al, [SI] mov [DI], al add SI, bx add SI, bx dec cx jnz move; end_move ; output the string: mov dX, blks mov ah, 09h int 21h mov dX, blkd mov ah, 09h int 21h ;................. ok: mov ah, 4ch int 21h cseg ends end start | org : 让IP从后面数值处开始 $: 当前位置的偏移地址 SI, DI , CX, BX 的专业用法 DEC, INC NEG 在处理显示字符串时,出了3个错误:
|
跳转表法:
| 1 分支地址表法 | 思想:通过dw指令将n个分支入口处的偏移地址BRi(i=0,1,***, n-1) 按序列放在一段连续的存储区中,构成跳转表。 设改存储区的首地址为BASE,则第i个分支入口处的偏移地址的存放 地址则为BASE+2*i,程序需要转向时,只需将2*i送BX,使用指令: JMP BASE[BX]即可。 【其实我们前面得到立方数的例子时就是这么做的】 | |
| 重新实现7.11 | ||
| 改变体现在两个地方: | ||
| 1) 数据区: | DSEG SEGMENT BASE DW M0 ; 多分支入口处偏移地址构成的跳转表 DW M1 DW M2 DW M3 | |
| 2) 下文调用时 | SHL AL,1 ;二倍 CBW mov bx, ax jmp base[bx] m0:... m1:... | |
| 2 转移指令表法 | 与分支地址表法的区别:(多直接啊,呵呵)
| |
| 举个例子: | 此时,跳转表没有放在数据段,而是放在了代码段。 MOV bx, offset BASE add bx, ax jmp BX base: jmp short M0 ; jmp short M1 ... |
本章注意:
| 1 | 要为每个分支安排出口,避免滑入其他入口 |
| 2 | 多分支的宜选择 跳转表法 |
| 3 | 应该不同实验数据来检查每一个分支都正确。 |
这篇博客深入探讨了80x86汇编语言中的分支程序设计,包括条件转移和无条件转移指令。文章详细介绍了条件转移指令如何根据标志位进行判断,并给出了ADD指令对标志位的影响。此外,还强调了8086和80286中短标号的限制以及80386以上指令集对近标号的使用。无条件转移指令JMP的应用场景也被提及,分为直接和间接两种方式。最后,文章讨论了测试法和跳转表法这两种常见的分支程序设计方法,为读者提供了全面的理解。
8112

被折叠的 条评论
为什么被折叠?



