[汇编] 关于补码和汇编语言的cmp指令

复习背景

事情是这样的:cmp指令配合SF和OF两个标志寄存器进行逻辑上的判断。可这个判断下面,会涉及二进制数据间的加减,而加减又要区分有符号、无符号情况,以及存储的规律。于是,我在补码知识上的欠缺让整个学习过程摇摇欲坠

分析"三码"

原码众所周知,不再赘述。

反码

反码的意义:

在计算机的数字电路中只有加法器,没有所谓的“减法器”。不是说计算机厂商不会设计减法器,因为聪明的人既然发明了方法能够用加法来实现减法操作,那为什么还需要画蛇添足的弄一个减法器?

示例:3+[-5]=[-2]的计算过程为:
[0_0000011]+[1_1111010]=[1_11111101]

补码

补码的出现是因为“0”。

00000000和11111111分别表示 +0和-0,可0作为一个数据,不能有两种表现方式而引起矛盾。所以+0被保留了下来,而-0的归处则是同其他负数 一起增加1位,从-0~ -127 变为 -1 ~ -128 。
关于这一点:

  1. 这是为什么同一内存空间的数据范围,负数绝对值的最值要比正数大1。
  2. 这也是补码是反码+1的原因。
  3. 这也解释了:-128为什么没有原码、反码。

至此,通过补码就成功解决了数字0在计算机中非唯一编码的问题,且也能实现减法变加法。

一个比方:
反码就是讨巧了数位循环,好比时钟一圈12小时,往后拨5小时与往前拨7小时是等效的;而现在换成1个字节,一整圈以255为循环(+0和-0重叠),-5和+250等效。补码的意义就是把0的重叠问题解决了,一整圈以256为循环,-5和+251等效。

所以,在计算机的世界里,0是正数。这点和我们学的数学不一样。

{0_1111111}=+127 (补码)

{0_0000000}=+0 (补码)

{1_1111111}=-1 (补码)

{1_0000000}=-128 (补码)

扩展:

  1. 减法变加法只是CPU的一个运算过程,它并不会去修改参与运算数存储的值,你可以理解为CPU从BX里面把5取出来之后,有专门的电路负责把它变成-5的补码,然后再参与加法运算。BX的值是我们人为赋予的5,当然不能为了做这样一个减法而随意去修改它。

  2. 计算机真正的编码过程,不需要考虑和判断所谓的第一位正负号“符号位”,只要看到符号“-”就重复“反码+1”的取相反数过程。

  3. 配合 2 来说,补码就是一种取相反数的机制,这种相反数的机制使计算机在底层算术运算时不需要人为判断符号位。但在抽象层高了以后的操作中,像输出到屏幕API、printf语句等,会由编译器来判断符号位。

    例如,对一个编码0xF0,当它存储在内存中的时候,如果是无符号数,应等于240;如果是有符号数,应等于-16。那它究竟是代表哪个数呢?计算机在硬件层面并不需要知道它代表的是240还是-16,因为它是正是负都不影响和别的任何数字做加减操作。比如在与数字2的编码值0x02相加之后,编码值是0xF2,那这个编码值就可以代表是242或-14

  4. 乘除法的过程,符号位会参与运算。因为符号位参与了计算过程,因此你在做乘除法之前,就必须在硬件层面指定0xF0代表的是正数240还是负数-16。正因为如此,汇编程序在做乘除法的时候,必须要指定是无符号乘除还是有符号乘除,无符号除法用指令:DIV,有符号除法用指令:IDIV。

  5. 循环进位:反码的符号位相加后,如果有进位出现,则要把它送回到最低位去相加,如:3 + (-2) 和 3 +(-1)

PS:这里存在大量摘录,(同时更详细的实现过程可以看)源网页:
—>参考:为什么用补码

当然,补码作为计算机能够处理的最终数据形态,将是真正存放在内存和硬盘里的数据。不信我们看下补码定义:

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理。

引出问题

困扰我的问题是:
对于同一个存储的数据,它何时作为正数补码,何时作为负数补码?

这里我给出的解释是,底层数据中,正数补码和负数补码当然是一模一样的,也就是说计算机会把这两种情况都考虑在内,然后凭借标志寄存器(程序状态字)同时记录两种情况需要的标志。

问题背景下,CF与OF的深入

如:无符号情况的CF的借位,有符号情况的OF的溢出。
(同一问题的两个方面)

对于CF来说:

  • 进位:无符号数相加时,最高有效位向更高位进位,表示无符号数运算发生上溢出
  • 借位:无符号数相减时,最高有效位向更高位借值,表示无符号数运算发生下溢出

对于OF来说:

溢出是针对有符号数而言的,即运算结果超出最大范围。只有当两个相同符号数相加,而运算结果符号原数据符号相反时(MSB为符号位),产生溢出。
(概括:溢出只会出现在两正数或负数相加的情况
不过需要注意的是,两个负数的补码,原最高位相加后的进位由硬件自动舍出,不考虑在数据和溢出范围之内。

—>参考:借位与溢出

解决:回到cmp

cmp的操作会发生溢出的情况,这种情况下,sf的值可能会产生“误导”,即cmp的比较结果只能记录实际结果的正负,不能得到真正的逻辑结果。它还需要借助OF。

;关于逻辑结果和实际结果:
mov ah,08ah
mov bh,070h
cmp ah,bh
;实际结果得到1AH, 值为26 ,SF=0;
;逻辑结果应为(-118)-112=-230; 即包括溢出位的11AH
;溢出会让逻辑结果与实际结果相反。

cmp要配合SF,OF。
cmp A B :无外乎四种情况:

  • SF = 1 ,OF = 0

    OF=0没有溢出,实际结果=逻辑结果。
    SF=1,实际结果为负数。A-B<0。
    A<B

  • SF = 0 ,OF = 0

    OF=0没有溢出,实际结果=逻辑结果。
    SF=0, 实际结果为非负(正数或0)。A-B≥0。
    A≥B

  • SF = 1 ,OF = 1

    OF=1存在溢出,实际结果与逻辑结果相反。
    SF=1,实际结果为负,逻辑结果为正。A-B>0
    A>B

  • SF = 0 ,OF = 1

    OF=1存在溢出,实际结果与逻辑结果相反。
    SF=0,实际结果为正,逻辑结果为非负。A-B≤0
    A≤B

溢出导致实际结果与逻辑结果相反的解释:这个结果是配合cmp造成的。注意cmp A B ,从运算角度看,是A-B。这个减号意味着只有A和B异号的情况才会导致溢出(即两负数或两正数加和的情况)。
在AB异号的条件下

  • 正数加和(正减负)溢出的实际结果一定为负数。以8位内存数据为例,0~127的两个数据,溢出的情况无外乎127+1到127+127。而这个范围内的和 不会摆脱 -1 ~ -128 的补码形式。(说到这里,你想起上文提到的“循环”"钟表"例子了吗)

  • 负数加和(负减正)与之同理。

附赠(debug模式查看标志寄存器)

标志中文YN
OF溢出(是/否)OV OVerflowNV Not oVerflow
DF方向(减量/增量)DN DowNUP UP
IF中断(允许/关闭)EI Enable InterruptDI Disable Interrupt
SF符号(负/正)NG NeGativePL PLus
ZF零(是/否)ZR ZeRoNZ Not Zero
AF辅助进位(是/否)AC Auxiliary CarryNA Not Auxiliary
PF奇偶(是/否)PE Parity EvenPO Parity Odd
CF进位(是/否)CY CarrYNC Not Carry
  • 18
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
嵌入式系统的数据处理汇编指令系统主要包括数据传输指令、算术运算指令、逻辑运算指令、移位指令和比较指令等。 1. 数据传输指令:用于将数据从一个地方传输到另一个地方,包括 LDR、STR、MOV 等指令。例如: ``` LDR r0, [r1] ; 从地址r1处读取数据,存放到r0中 STR r0, [r2] ; 将r0中的数据存放到地址r2处 MOV r0, #10 ; 将10存放到r0中 ``` 2. 算术运算指令:用于进行加、减、乘、除等算术运算,包括 ADD、SUB、MUL、DIV 等指令。例如: ``` ADD r0, r1, r2 ; 将r1和r2中的数据相加,结果存放到r0中 SUB r0, r1, r2 ; 将r1和r2中的数据相减,结果存放到r0中 MUL r0, r1, r2 ; 将r1和r2中的数据相乘,结果存放到r0中 DIV r0, r1, r2 ; 将r1和r2中的数据相除,结果存放到r0中 ``` 3. 逻辑运算指令:用于进行与、或、非、异或等逻辑运算,包括 AND、ORR、MVN、EOR 等指令。例如: ``` AND r0, r1, r2 ; 将r1和r2中的数据进行与运算,结果存放到r0中 ORR r0, r1, r2 ; 将r1和r2中的数据进行或运算,结果存放到r0中 MVN r0, r1 ; 对r1中的数据进行取反操作,结果存放到r0中 EOR r0, r1, r2 ; 将r1和r2中的数据进行异或运算,结果存放到r0中 ``` 4. 移位指令:用于进行左移、右移等移位操作,包括 LSL、LSR、ASR、ROR 等指令。例如: ``` LSL r0, r1, #2 ; 将r1中的数据左移2位,结果存放到r0中 LSR r0, r1, #2 ; 将r1中的数据右移2位,结果存放到r0中 ASR r0, r1, #2 ; 将r1中的数据算术右移2位,结果存放到r0中 ROR r0, r1, #2 ; 将r1中的数据右旋2位,结果存放到r0中 ``` 5. 比较指令:用于进行大小比较等操作,包括 CMP、CMN、TST、TEQ 等指令。例如: ``` CMP r0, r1 ; 比较r0和r1中的数据,设置条件码 CMN r0, r1 ; 比较r0和r1中的数据的补码,设置条件码 TST r0, r1 ; 对r0和r1中的数据进行与运算,设置条件码 TEQ r0, r1 ; 对r0和r1中的数据进行异或运算,设置条件码 ``` 以上是嵌入式系统常用的汇编指令系统,并举例说明了一些常用的指令。在实际应用中,需要根据具体的需选择合适的指令进行使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值