汇编之控制转移指令


前言

无条件转移指令

无条件转移指令JMP

段内直接近转移

段内直接转移采用相对寻址方式
段内直接转移中,转移的目标地址由指令直接给出。
简单来看就是
JMP LABEL

注意是从当前地址出发,根据位移量进行移动,移动到相应的位置。
段内直接转移的OPR一般情况下就是标号

ip=ip+8位位移量
位移范围是-128~127
ip+ip+16位位移量
位移范围是-32768~32767
因为对8位的二进制数,能表示的有符号数的范围是-128~+127;
而对16位的二进制数,能表示的有符号数的范围是-32768~32767
计算机中的数都是以补码来存储的,8位有符号二进制数用补码来表示,能表示的范围就是-128~127。16位同理。

可以参考这个论坛讨论关于JMP指令的疑惑

在这里插入图片描述
看一下这个程序
XOR BX,BX;将BX清零
JMP SHORT NEXT;跳转到NEXT
执行MOV AX,1
在这里插入图片描述
一定要了解8086CPU读取,执行一条指令的过程!
下面我们先简略的看一下
……控制电路把指令从内存中读出来,送到指令缓冲器中,此时IP就增加增加的大小取决于刚才读出来的这条指令的长度,如果这条指令的长度为3,就IP+3
IP增加完成后,指令执行!

因此在这道题里,执行
JMP SHORT NEXT这条指令时,IP已经指向了下一条指令,而JMP SHORT NEXT这条指令的长度是2,下一条指令的偏移地址是0004,也就是说现在IP指向0004

EB 04

关键是要知道,这里面的04是什么意思
EB 04是机器码,04是跳转的位移
CPU在执行JMP指令的时候并不需要要转移过去的目的地址,CPU只需要知道IP的改变量。
比如这里EB 04,IP就在现在地址的基础上加4
如果向前跳,就用补码表示,比如向前跳9个,机器码就是EB F7
(还记得怎么求负数的补码吗?-9写成原码是1000 1001,反码是1111 0110,补码是1111 0110,注意求反码时取反要把符号位除外
因此EB 04之后,IP指向0008
在这里插入图片描述
因为指令长度比原来多了一个字节,跳转指令的机器码是EB 0004,所以是0005+0004,NEXT这条指令的地址是0009,JMP指令要转移到的地址也是0009。
请注意这里用的是JMP NEAR PTR NEXT,因此位移量应该是16位的,写成0004要比04更严谨

段内间接近转移

段内间接转移由指令中的寄存器或存储器操作数指出目标地址。
转移的目标地址存放在某个16位寄存器或存储器的某两个单元中。
在这里插入图片描述
段内间接转移的OPR通常是寄存器或者内存
在这里插入图片描述
JMP WORD PTR TABLE[BX]
如果TABLE是数据段中定义的一个变量名,偏移地址为0010H,(DS)=1000H,(10015)=12H,(10016H)=34H,(BX)=0005H
TABLE是一个变量名,TABLE应该是一个表,TABLE[BX]是这个表中的一个元素,TABLE[BX]这个元素的偏移地址是1005(请注意看这道题,注意TABLE[BX]这种用法),段地址是1000,因此20位物理地址为11005H
WORD PTR的意思是我们要取出一个字
因此取出3412H
高地址在高字节,低地址在低字节
这条JMP指令可以跳转到CS段的3412H处(因为本来这些指令就是在代码段的)

段间直接远转移

在这里插入图片描述
段内直接远转移的OPR通常也是标号
在这里插入图片描述

段间间接远转移

在这里插入图片描述
段内间接原转移的OPR是存储器的地址
在这里插入图片描述
JMP DWORD PTR TABLE[BX]
TABLE是数据段中定义的变量,偏移地址为0010H,(DS)=1000H,BX=0005H
所以TABLE[BX]的地址是10015H,内容是78563412H
低地址内容送IP,高地址内容送CS
所以(IP)=3412H,(CS)=7856H
(插一嘴,当我们直接使用TABLE[BX]的时候,我们的意思就是要用他的内容,这里有点迷惑还得再研究研究,寻址方式这块真的很容易迷茫要多学习)

无条件转移指令总结

无条件转移指令分为段内直接近转移,段内间接近转移;段间直接远转移,段间间接远转移。
近和远就是形容段内和段间的。段内转移就是近的,段间转移就是远的。
直接转移的操作数常常是标号。
间接转移的操作数是一个存放了地址的地方。对于段内间接转移,可以是内存和寄存器,对于段间间接转移,只能是内存,因为段间间接转移需要32位的数据,高16位作为段地址送CS,低16位作为偏移地址送IP。

条件转移指令

条件转移指令根据上一条指令所设置的标志位来判别测试条件,满足条件则转移到由指令指定的转向地址去执行,不满足条件则顺序执行下一条指令。
条件转移指令是指在满足一定条件时进行相对转移
相对转移指令是指跳转时以当前地址为基准加上相对偏移量进行跳转,一般是在本地址段内跳转。
相对转移指令实现转移的范围为一个字节的偏移量(这个就记着!先当成一种规定)
一个字节是8位,有一位符号位。8位有符号二进制数能表示的范围是-128~127
(IP是16位的,8086有16根数据线,20根地址线)
目标地址应在本条转移指令下一条指令地址的-128~+127个字节的范围之内
条件转移指令都不影响标志位

以单个标志位为条件

在这里插入图片描述
JO:OF=1即溢出时转移
JNO:OF=0不溢出转移
其实所有的都是一样的道理
OF,SF,CF,ZF,PF
这些标志位,有效(=1)的时候用JO,JS,JC,JZ,JP来转移;
无效(=0)的时候用JNO,JNS,JNC,JNZ,JNP来转移。

在这里插入图片描述
程序1:
将AX与TEMP相加,结果存入AX,如果结果等于0,跳转到ACTION_2,否则继续向下执行ACTION_1。

程序2:
将AX与TEMP相加,结果存入AX,如果结果不为0,跳转到ACTION_1,否则继续向下执行ACTION_2。

无符号数比较

在这里插入图片描述
前面以单个标志位为条件的跳转指令的“J”后面跟的那一个字母都是标志寄存器的不同标志位的首字母,是有意义的,很好记的。
这里无符号数的比较相对难记一点
可以记住A是大于,B是小于,AE是大于等于,BE是小于等于
JA/JNBE,大于/不小于等于时跳转
JAE/JNB,大于等于/不小于时跳转
JB/JNAE,小于/不大于等于时跳转
JBE/JNA,小于等于/不大于时跳转

这里的opr可以是一个标号,指示要转移去的地址。

有符号数比较

在这里插入图片描述
和上面比较相似:
G是大于,L是小于;GE是大于等于,LE是小于等于。
SF=OF∩ZF=0
OF和ZF有一个等于0,ZF是0标志位;OF是溢出标志位。

在这里插入图片描述
CMP AX,50
是用AX-50结果不回送
JG大于时转移
如果AX大于50,跳转到TO_HIG
否则SUB AX,Y
如果溢出,即OF位有效,跳转到OVERFLOW(也是一个标号)
JNS,SF=0,结果为正时转移,跳转到NONNEG
如果结果为正,绝对值就是本身,可以直接MOV RESULT,AX
如果结果为负,NEG AX,求负数的补码,也就是求这个负数的绝对值。
然后再MOV RESULT,AX

在这里插入图片描述
双精度数,32位。
CMP DX,BX
JG X;大于的话转移到X
JL Y;小于的话转移到Y
CMP AX,CX
JA X;大于时转移到X
注意是有符号双精度数,比较高位的时候要用有符号数的跳转
高位的大小可以直接判断出两个数的大小,如果运行到JL Y后面依然没有跳转,就说明高位完全一样,这时候就比较低位。
然后,有意思的就来了!

简单的想,会感觉这个程序写错了,干嘛呢,就好比-8900 0000和-8900 0011,高16位相同,低16位显然后者大于前者,但是整体来看前者-8900 0000显然比-8900 0011大啊!因为他们都是负数啊!
CMP AX,CX JA X 这不是显然没考虑符号只考虑大小了嘛

这就是你看到这个程序的第一想法,我们一点一点来看这个想法错在哪里。
首先,带符号的32进制数是1位符号位,32位数值位,它根本表示不了-8900 0000这个16进制数,超出它的表示范围了,而且-8900 0000,这是一个很别扭的数,如果要表示它,可能需要用64位数,最高位是符号位为1,次高的31位全是填位的0,低32位才是8900 000。就好比-9,9的原码是可以用4位二进制表示的,但是-9的原码一般写成1000 1001
你说这个程序错了,考虑不全面,那我们可以举一个例子啊来看看。
数据在计算机中都是以补码来存储的,我们可以直接写出两个补码
A补=1100 0101 0000 0000
B补=1100 0101 0000 0001
显然这是两个负数的补码,那么这两个数谁大呢?
我们知道比较大小要转换成原码
这两个数转换成原码是
A原=1011 1011 0000 0000
B原=1011 1010 1111 1111
还是两个负数(废话),显然A<B(请注意!!这个也比较容易看错)
A的数值部分更大,B的数值部分+1才等于A的数值部分,因此A负的更多,A更小,A<B
再看补码
A和B的补码的高16位是相同的!根据汇编程序接下来要单独看低16位。低16位当成无符号数比较,B的低16位大于A的低16位,因此可以判定A<B
哈哈,怎么样,其实人家写的这个程序是完全正确的!
因此我们可以说,对于两个补码,我们先把高位当成有符号数,用有符号数的比较指令比较高位,大的就是大的。如果高位相等,就再把低位当成无符号数,比较两个无符号数的大小,同样大的就是大的!此时如果低位比较出了一个大小,那么就可以判定整个数的大小。
在这里插入图片描述
在这里插入图片描述

只需要统计个数,不用把为正为负的都找出来。

MOV DI,BX;可以直接MOV DI,0吗?反正要实现的效果就是清零
用MOV DI,0是可以的!是正确的!段寄存器不能直接用立即数赋值,SI和DI不是段寄存器,因此可以用立即数赋值。
如果单单只是要将DI清零,是不需要用两条指令的。单单将DI清零,最优指令用法是用SUB DI, DI或者XOR DI, DI。
但是这里我们需要让两个寄存器清零。 所以我们要知道:如果需要DI寄存器清零,那么,先将0传送到BX后,再用MOV DI, BX比用MOV
DI, 0的代码长度要短。 也就是说用MOV DI, BX比用MOV DI, 0的代码长度要更短,要更简洁。
这里我们需要让两个寄存器清零,所以可以先MOV BX,0,再 MOV DI,BX MOV SI,BX
这样就把DI和SI都清零了,这是我们更常用,更地道的用法,直接放进去0不是不行,只是没有这样好。

研究完这个问题我们回头看代码
在这里插入图片描述
again是标号,cmp是比较,将数组元素和0比较
jle,小于等于时转移
inc加1指令,inc di,di用来记录大于0的数,因此di计数加一
后面的代码理解起来都不难
CX用作计数器
最后
SUB AX,DI
SUB AX,SI
此时DI和SI中已经是所有的就是把大于0和等于0的数的个数都减掉了
这个时候如果AX等于0,就说明没有小于0的数
否则说明有小于0的数,就转到neg_val(这是题目的要求)
PPT上说的不太清楚,他的意思是小于零的数的个数为0的时候转到skip

在这里插入图片描述
注意这里,有条件跳转一定要紧跟在判别条件后面
就是说,CMP的下一条一定就要是条件跳转,在这里就是JLE
如果你这样
CMP WORD PTR ARRAY[BX],0
ADD BX,2
JLE LESS_OR_EQ
这就错了!因为ADD BX,2这条指令一定会影响标志位,就会导致跳转不正确。

其实这道题也可以组织成不同的跳转方式,比如非负跳改成负跳,但是这样你可以试试,写起来是很不顺的。所以我们拿到一道题目,应该先分析分析,想一想,怎样编写能比较顺利,比较容易。

循环指令

在这里插入图片描述
LOOP是一个助记符
循环指令不影响标志位
LOOP里含着做CX-1(注意是减一!)
先做减一,然后判断cx是否为0,如果不为0就跳转
重复循环,多次移位,都要用CX记次数。
AX——累加器
CX——计数器

LOOPZ和LOOPNZ就是比LOOP多了转移的限制条件。
Z,E——相等,ZF=1表示相等,E表示相等

在这里插入图片描述
因为是数组,所以
ADD SI,2

在这里插入图片描述
如果你写一个程序

MOV CX,0
START:ADD ……
……
LOOP START

这个程序是正确的,可以通过,但是你会得到一个很大的结果
关键就在于LOOP这条指令是先-1,再判断是否为0,而不是先判断。
再看这个程序

MOV CX,0
START NOP
LOOP START

NOP就是什么都不做
这段程序创造了一个最大的循环,0减到负数再减到正数,能达到拖延时间的目的。

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值