Assembly CMP与2的补码
我已经开始学习CMP指令,它比较两个整数。 当使用无符号整数时,我读到: ZF=1表示目的地和来源相等。 ZF=0&&CF=0表示目的地>来源 ZF=0&&CF=1表示目的地<来源地 据我所知,CMP指令使用隐含减法,而不改变操作数的值。 减法没有意义 假设我执行以下指令:Assembly CMP与2的补码,assembly,x86,masm,Assembly,X86,Masm,我已经开始学习CMP指令,它比较两个整数。 当使用无符号整数时,我读到: ZF=1表示目的地和来源相等。 ZF=0&&CF=0表示目的地>来源 ZF=0&&CF=1表示目的地
CMP 1, 4
1 - 4 = 1 + (-4)
...001
.+.100
= 101
我看这里没有进位,我的意思是,进位是0,不是吗?所以我上面说的,我读到的是正确的,是错误的。
我只是不明白为什么减法会设置进位标志。我一点也没带!如果进位只是数字的第四位,则为零。
我花了好几个小时试图弄明白。考虑进位只是结果中的下一个最重要的位 考虑在一个步骤中减去一个补码,加1,全部相加。在硬件中,这是通过LSB的进位实现的:0表示add,1表示sub,C表示addc 示例: 1-4 -一至二
1.111 // -1
0.001 + 1 // -2 complemented, carry in
+ -----
0.001 // 1, no carry out
显示的CMP条件代码用于无符号算术。对于有符号算术,必须对进位和符号位进行异或运算。通常对此也会进行测试 例如,JG跳跃大于ZF=0,SF=OF 编辑,多亏@Blechdose的提示,下面是一个例子,说明当补减数的符号未传播到CF中时会发生什么,从而导致x86将CF反转为减法: 1-4 4-1
让我们在3位系统中尝试所有3位数字
000 - 000 = 0000 : +0 - +0 = + 0 Z
000 - 001 = 1111 : +0 - +1 = +15 [-1] C
000 - 010 = 1110 : +0 - +2 = +14 [-2] C
000 - 011 = 1101 : +0 - +3 = +13 [-3] C
000 - 100 = 1100 : +0 - +4 = +12 [-4] C
000 - 101 = 1011 : +0 - +5 = +11 [-5] C
000 - 110 = 1010 : +0 - +6 = +10 [-6] C
000 - 111 = 1001 : +0 - +7 = + 9 [-7] C
001 - 000 = 0001 : +1 - +0 = + 1
001 - 001 = 0000 : +1 - +1 = + 0 Z
001 - 010 = 1111 : +1 - +2 = +15 [-1] C
001 - 011 = 1110 : +1 - +3 = +14 [-2] C
001 - 100 = 1101 : +1 - +4 = +13 [-3] C
001 - 101 = 1100 : +1 - +5 = +12 [-4] C
001 - 110 = 1011 : +1 - +6 = +11 [-5] C
001 - 111 = 1010 : +1 - +7 = +10 [-6] C
010 - 000 = 0010 : +2 - +0 = + 2
010 - 001 = 0001 : +2 - +1 = + 1
010 - 010 = 0000 : +2 - +2 = + 0 Z
010 - 011 = 1111 : +2 - +3 = +15 [-1] C
010 - 100 = 1110 : +2 - +4 = +14 [-2] C
010 - 101 = 1101 : +2 - +5 = +13 [-3] C
010 - 110 = 1100 : +2 - +6 = +12 [-4] C
010 - 111 = 1011 : +2 - +7 = +11 [-5] C
011 - 000 = 0011 : +3 - +0 = + 3
011 - 001 = 0010 : +3 - +1 = + 2
011 - 010 = 0001 : +3 - +2 = + 1
011 - 011 = 0000 : +3 - +3 = + 0 Z
011 - 100 = 1111 : +3 - +4 = +15 [-1] C
011 - 101 = 1110 : +3 - +5 = +14 [-2] C
011 - 110 = 1101 : +3 - +6 = +13 [-3] C
011 - 111 = 1100 : +3 - +7 = +12 [-4] C
100 - 000 = 0100 : +4 - +0 = + 4 [-4]
100 - 001 = 0011 : +4 - +1 = + 3
100 - 010 = 0010 : +4 - +2 = + 2
100 - 011 = 0001 : +4 - +3 = + 1
100 - 100 = 0000 : +4 - +4 = + 0 Z
100 - 101 = 1111 : +4 - +5 = +15 [-1] C
100 - 110 = 1110 : +4 - +6 = +14 [-2] C
100 - 111 = 1101 : +4 - +7 = +13 [-3] C
101 - 000 = 0101 : +5 - +0 = + 5 [-3]
101 - 001 = 0100 : +5 - +1 = + 4 [-4]
101 - 010 = 0011 : +5 - +2 = + 3
101 - 011 = 0010 : +5 - +3 = + 2
101 - 100 = 0001 : +5 - +4 = + 1
101 - 101 = 0000 : +5 - +5 = + 0 Z
101 - 110 = 1111 : +5 - +6 = +15 [-1] C
101 - 111 = 1110 : +5 - +7 = +14 [-2] C
110 - 000 = 0110 : +6 - +0 = + 6 [-2]
110 - 001 = 0101 : +6 - +1 = + 5 [-3]
110 - 010 = 0100 : +6 - +2 = + 4 [-4]
110 - 011 = 0011 : +6 - +3 = + 3
110 - 100 = 0010 : +6 - +4 = + 2
110 - 101 = 0001 : +6 - +5 = + 1
110 - 110 = 0000 : +6 - +6 = + 0 Z
110 - 111 = 1111 : +6 - +7 = +15 [-1] C
111 - 000 = 0111 : +7 - +0 = + 7 [-1]
111 - 001 = 0110 : +7 - +1 = + 6 [-2]
111 - 010 = 0101 : +7 - +2 = + 5 [-3]
111 - 011 = 0100 : +7 - +3 = + 4 [-4]
111 - 100 = 0011 : +7 - +4 = + 3
111 - 101 = 0010 : +7 - +5 = + 2
111 - 110 = 0001 : +7 - +6 = + 1
111 - 111 = 0000 : +7 - +7 = + 0 Z
式中,C为执行/借用,Z为零
您的规则严格来说是未签名的规则。对于签名,我认为这类似于如果N!=然后V小于,如果N==V则大于
所以0-0表示它们相等
然后是0-1和0-2,以此类推。第二个操作数大于Z not set和进位set
直到我们得到1-0,这不是零,C没有设置,左边的数字更大
然后我们打了1-1的平局
更多的Z不是集C,所以正确的数字更大
然后2-0,2-1左大于Z不设置C不设置,然后2-2 Z设置,然后2-3到2-7 Z不设置C设置,所以右大于
这种模式会重复
当然,诀窍是什么是源和目标的定义,这通常没有记录在指令集中,你必须通过实验来确定这一点,出于某种原因,至少对我来说,我总是猜错了
你的具体例子
1与41-4=1+-4相比,4=0b100,所以-4=011+1
向加法器馈电,减法意味着反转进位并反转第二个操作数:
1
001
+ 011
=======
填写
0111
001
+ 011
=======
101
1-4=-3。Z是0,C是0,所以1<4
注意:要从进位中获取借位,需要反转进位借位=~进位。“执行”为0表示发生了借用,如果您尝试使用十进制铅笔和纸张从1中减去4,这是显而易见的
如果没有借用,则设置执行,例如,取4-1:
1001
100
+ 110
========
011
4-1=3,无借土。Z未设置,C设置为4>1
我认为这里的底线是哪个操作数是源,哪个是目标,为什么他们很少正确地记录它?任何时候在指令集中使用比较时,都必须用固定的数字做一些实验,以确定哪个操作数是哪个操作数。您还必须非常小心地使用大于或小于的有符号或无符号,这会产生影响。有些指令集不提供一种或另一种风格,但这没关系,你真的不需要一个有符号和无符号的长列表,左右切换操作数,了解标志,你可以找到一个简单的if-carry或not-carry或if-which,几乎所有信息,有时你会得到额外的好处,当Z被设置时,进位是一个零对,这意味着进位未被设置为a或等于a。这些二进制数中你的符号在哪里-4是2的32位补码中的0FFFFFFFCh。进位可以是借位的同义词,具体取决于最后执行的指令…这取决于处理器。假设这是X86,则比较或减去使用进位作为借用位。溢出位是基于数字是有符号的假设设置的。我明白你的意思,但是让我们假设我们正在处理的处理器是一个3位处理器。进位是如何发生的,当你刚才给我看的多余的列没有空间时?多余的列只是数字中符号位的重复。不需要额外的房间。这个额外列和第3位的进位的结果就是进位。您还碰巧使用了一个非常糟糕的twos补码值:注意,4和-4的位表示实际上是相同的。这是一个已知的两两补语。3位2补中没有4的3位表示。试试你的例子
使用较小的值,比如1和3。实际上,这也是我有问题的部分。当我用2的补码做1-4运算时,例如用虚4位寄存器:我没有得到进位:0001 1-01004=0001 1+1100-4=1101-3。至少进位不是从最高位的进位生成的。当我做双减法0001 1-01004时,我会得到一个借来的,但CPU不是这样计算的,对吗?它将使用2个补码。您显示的CMP条件代码用于无符号算术。对于有符号算术,必须对进位和符号位进行异或运算。通常对此也会进行测试。我编辑了答案以反映这一点。嘿,我终于开始理解这个问题了。当计算1-4时,进位是0,但它被反转,所以它是1。这是拼图中缺失的一块,所以我不明白为什么要设置进位标志。最后一个问题,硬件如何知道何时反转进位,何时保持原样?非常感谢你!每个指令集或处理器设计(arm vs x86 vs powerpc等)都有不同的设计人员来做不同的事情。Twos补码允许我们不需要进行减法逻辑,因为这没有任何意义,而是使用加法逻辑,反转第二个操作数,反转进位,通常第一位单元上加法的进位为0,但是对于一个减法运算,a 1意味着+1,所以你得到一个倒数,加上两个补码否定a-b=a+-b。现在有些结构做了,有些结构没有倒数进行减法运算,进入加法器的东西你必须做你没有做的。最好的办法就是在那个处理器上做一个实验。和/或检查进位和其他标志定义是否大于或小于,这也会告诉您。这在输出标志以及如何使用它们方面很重要处理器是否有带借位的减法运算也很重要,因为减法运算是否会反转进位。没有一条规则,没有计算机体系结构之神规定,事实上,如果你把别人的设计复制得太近,那么上帝的律师和法官会让你受苦。因此,一些处理器系列在减法运算中有一个未反转的执行,而另一些处理器系列在借用运算中有一个反转的执行。一旦你选择了这条路,你就会坚持下去,这是有道理的,我不希望x86兼容机会时不时地改变定义,但arm没有理由像x86那样做……没有律师不在乎是否每个人都使用借用,不会因此而被起诉,但处理器设计中有一些架构方面的东西是获得专利的,你必须远离它们……我想知道,在没有人声称你在某个国家侵犯了他们的专利的情况下,想出一个新的架构有多难。
1
001
+ 011
=======
0111
001
+ 011
=======
101
1001
100
+ 110
========
011