汇编之算术运算指令


前言

运算类指令影响标志位。
除了自加1指令(INC)和自减1指令(DEC)之外,运算类指令都影响全部6个标志位。
本文参考博文
汇编语言标志位介绍
影响标志位的汇编指令

加法指令

ADD加法指令

在这里插入图片描述

ADC带进位加法指令

在这里插入图片描述

ADD AX,24
ADC DX,0(高位记得用ADC,带着进位)

的作用和
   DX AX
+0000 0000 0000 0018
是一样的

INC加1指令

在这里插入图片描述
CF
在这里插入图片描述
ZF:零标志位

减法指令

SUB减法指令

在这里插入图片描述

SBB带结尾减法指令

在这里插入图片描述

DEC减1指令

在这里插入图片描述
注意这里
在这里插入图片描述
这个例子。
1000 0000 0000 0000-1=0111 1111 1111 1111
正数减一变成负数了,这很明显是溢出了!

NEG求补指令

在这里插入图片描述
NEG指令只对负数
如果你知道AX里是个正数,就不要对他做NEG

在计算机系统中,数值一律用补码来表示和存储
补码的最高位是1,就表示这个数是负数。
计算机中存储的本来就是补码,补码的补码是原码的绝对值。(补充一句,补码里正零和负零相同,都是00000000)
也就是说对于计算机中存储的一个负数求补,其实就是求这个负数的绝对值。
比如10110101是一个二进制补码,它表示的值是-75
显然它是负数,对他求补码是取反加一,得到的结果是01001011,显然这是一个正数,是一个二进制原码,表示的值是75。

当然汇编这门课的关键也不在于研究补码原码反码,所以你就知道NEG是求补命令,是对负数求绝对值就行了

NEG的对负数求补相当于对负数求绝对值的原因是:
NEG的求补连同符号位一起运算!我们知道我们求补码的时候,先取反再加一,取反的时候是不带符号位的!但是计算机中的求补命令,也就是NEG,它运算的时候是带着符号位的,即全部位取反然后再加1!
之前我们还说:

“数在计算机中都是用补码存储的”

这句话里的补码,就是咱们平常求的补码,是咱们从一开始就在学的那一种,从原码转换到补码需要除开符号位取反再加一的那一种。
所以你想,一个负数的补码,最高位也就是符号位肯定是1,这时用NEG指令求补码,连同符号位取反加1,没有溢出的话,得到的结果的符号位肯定是0(因为取反了嘛),这时候我们得到了一个符号位为0的二进制数,也就是一个正数,正数的补码等于原码,因此可以直接读出这个二进制数的值。
之前我们就学

“补码的补码是原码。”

所以你看出区别了吗,如果用我们的方法,对一个负数补码求补码,会得到原码,原码符号位肯定为1,因为原来就是一个负数嘛。
但是对计算机里存储的一个负数,这个负数肯定是以补码存储的,我们使用NEG对这个负数求补码,NEG会连带着符号位运算,所以求出来的是这个负数的绝对值!差就差在了这个符号位,带着符号位求反加1,会得到绝对值,不带符号位求反加1,会得到原码。
总之,就是NEG稍微区别于咱们的求补操作,它连带着符号位做取反加一,而正是因为这个区别,NEG可以用来求负数的绝对值(或者说它的功能就是求负数的绝对值)

仔细琢磨琢磨真的很完美,这也是计算机的一种美啊。

CMP比较指令

在这里插入图片描述
CMP也是一个双操作数指令,注意第一个立即数可以是内存和寄存器,第二个操作数可以是内存、寄存器和立即数
还要注意是OPR1-OPR2,也就是目的操作数-源操作数
CMP做的是减法操作,但是结果不回送,所以它不会影响原数据。(相应的,SUB就会对原数产生影响)
CMP指令后往往跟着一条条件转移指令。

计算机中分为有符号数和无符号数。
最典型的无符号数是地址;
最典型的有符号数是补码。
两个负数相加,负数减正数,都有可能变成正数。
有符号数——溢出
无符号数——进位
(或者说无符号数的溢出就是进位,也可以说只有有符号数才有溢出,只有无符号数才有进位,反过来说是根本不成立的)

CMP用于数的比较

对两个数使用了CMP指令后
若ZF=1,则两数相等;
若ZF=0,则两数不等。
(ZF是零标志位,相减等于0说明两个数相等)

  • 如果两数不等且为无符号数时:
    若CF=1,则目的操作数小于源操作数;
    若CF=0,则目的操作数大于源操作数
    CF是进位标志位,做减法时进位标志位为1,说明有借位
  • 如果两数不等且为有符号数时:
    若OF XOR SF=0(OF=SF),则目的数大于等于原数
    若OF XOR SF=1(OD≠SF),则目的数小于原数
    SF是符号标志,反应运算结果的正负号,SF=0表示运算结果为正;OF是溢出标志,反应运算结果是否溢出,OF=0表示没有溢出。
    XOR是异或(同或是XNOR)
    OF异或SF=0,表示OF和SF的内容相同。

没有溢出的两种情况:

  • OF=0且SF=0
    没有溢出,并且符号为正,说明目的操作数大于等于源操作数(为什么是大于等于呢?因为如果结果是0,0的补码是00000000,符号位是正的,也没有溢出,所以没有溢出和符号为正加在一起只能说明是大于等于,至于是否等于要看ZF的值)
  • OF=0且SF=1
    没有溢出并且符号为负,说明目的操作数小于源操作数

溢出的两种情况
为了研究溢出的情况,我们先看一下哪些情况会溢出
首先,两个同号的数相减是不可能溢出的,因此CMP指令的结果溢出的情况无非是

  1. 负数减正数,得到了正数
  2. 正数减负数,得到了负数

因为CMP本质是做减法,所以溢出只有这两种情况,如果放宽范围,问你所有的可能溢出的情况,那应该是

  1. 负数减正数,得到了正数
  2. 正数减负数,得到了负数
  3. 正数加正数,得到了负数
  4. 负数加负数,得到了正数
    可以概括的总结为**“同号相加,异号相减”**

下面看CMP的有溢出的结果的分析。

  • OF=1且SF=0
    溢出了并且结果为正。CMP做的是减法,所以应该是负数减正数得到了正数,因此目的操作数小于源操作数(负数当然小于正数)

  • OF=1且SF=1
    溢出了并且结果为负,CMP做的是减法,所以应该是正数减负数得到了负数,因此目的操作数大于源操作数(正数当然大于负数)

参考博文CMP详解

前面因为还包含了对补码以及溢出的讲解,所以写的比较乱,下面整齐的总结一下:

CMP OPR1,OPR2
若ZF=1,则两数相等;
若ZF=0,则两数不等。
如果两数不等且为无符号数时:
若CF=1,则目的操作数小于源操作数;
若CF=0,则目的操作数大于源操作数
如果两数不等且为有符号数时:
若OF XOR SF=0(OF=SF),则目的操作数数大于等于原操作数
若OF XOR SF=1(OD≠SF),则目的操作数小于原操作数
若OF=1且SF=0,则目的操作数小于源操作数
若OF=1且SF=1,则目的操作数大于源操作数

乘法指令

MUL无符号数乘法指令

在这里插入图片描述
在这里插入图片描述
注意例子

MUL DL

MUL语句中只有一个操作数,另一个操作数默认放在AX中。
MUL操作也要求两个数的类型匹配,也就是说只能是8位×8位=16位,16位×16位=32位,32位×32位=64位
所以MUL DL语句实际上是DL与AL的内容进行乘法运算。
(注意因为DL是8位,就自动与AL乘了)

MUL WORD PTR [2000H]

这是把[2000H]和[2001H]单元里的字和AX中的内容进行乘法。
WORD PTR:伪指令助记符

IMUL带符号数乘法指令

在这里插入图片描述
无定义:就算产生变化,这个变化也与你无关,你不用管。注意无定义≠无影响。无定义是有影响,但是这个变化与你无关。
CF:进位标志
OF:溢出标志
“高一半是低一半的符号扩展”:比如低一半是0100 1110,因为是有符号数,最高位为符号位,符号位为0说明这个数是正的。这个时候如果高一半是0000 0000,那CF和OF均为0。同样如果低一半的符号位是1,高一半的全都是1,那同样符合这种情况,CF和OF位均为0。

除法指令

DIV无符号数除法指令

在这里插入图片描述
除法只能算16位÷8位,32位÷16位
16位÷8位的商和余数都是8位
32位÷16位的商和余数都是16位

IDIV带符号数除法指令

在这里插入图片描述
无定义:有影响,但是这个变化与你无关。
IDIV字节相除时,商的范围是1000 0000~0111 1111
除法运算和CBW,CBD配合使用

乘除法都隐含一个操作数

MUL,DIV的语句中都只有一个操作数,另外一个操作数是隐含的。隐含在AX,DX中。

类型转换指令

CBW字节转换为字指令

在这里插入图片描述
注意CBW是符号扩展
若AL<1000 0000,则AH=0
AL小于1000 0000,那么AL应该是0XXX XXXX
如果把这个数看成一个有符号数,那么这会是一个正数,符号位是0,CBW做符号扩展,把符号位扩展到AH,所以AH全是0

若AL>1000 0000,则AH=0FFH,也就是1111 1111
AL大于1000 0000,那么AL的形式一定是1XXX XXXX
如果把这个数看成一个有符号数,那么这会是一个负数,符号位是1,CBW做符号扩展,把符号位扩展到AH,所以AH全是1

并且CBW是一个无操作数指令
它使用累加器,将AL中的内容扩展为字,并存在AX中。

CWD字转换为双字指令

在这里插入图片描述
CWD也是符号扩展,具体和上面CBW类似。如果AX中的最高位是1,那么DX中全1;如果AX中的最高位是0,那么DX中全0。
CWD是无操作数指令,将AX中的字扩展为双字,并存放在DX,AX中
CBW/CWD常被安排在IDIV指令(带符号数除法)之前。
因为人可以做8位除8位的除法,但是计算机不行,计算机只能做16位÷8位,32位÷16位,所以如果我们想求AL中的字节除BL中的字节的结果,就要先用CBW将AL中的字节扩展成字存在AX中,再让计算机去计算这个16位÷8位的运算。也就是说做除法之前必须要将运算数扩展到规定的位数,才能交给计算机去运算。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值