【王爽汇编】检测点11.2分析

很抱歉,由于我在写本篇博客的时候比较早期,对汇编指令和计算机原理的理解不到位,导致出现了很多错误。因此我决定重新做一遍这个检测点。这一次我会加入编程实践,使用bochs模拟器在我的内核里执行汇编指令并查看PSW程序状态字,来验证每一步的操作,这样会给大家形象的看出现象,并且还能确保真实性和正确性。这里要感谢评论区指正我之前的错误

王爽老师的书里使用的是masm+dosbox进行调试汇编语言程序,而我现在的内核已经进入了x86_64的长模式,是nasm/gas/gcc+bochs进行调试,我会在必要的地方进行说明。

我认为这里还是很有难度的,如果觉得这里有点理解不了,可以去看看附录里的对补码的说明,看了之后会对数据的存储更加清晰。

先来复习一下PSW标志寄存器的标志们的作用:

1、ZF标志(Zero Flag零标志):判断执行相关指令后的结果,若结果是0,则把ZF标志位的值设置为1;若结果不是0,则设置为1.

以下是书上的例子代码,我会把它转换成AT&T风格运行。

mov ax,1
sub ax,1

clear_rflags()函数是用于清空flags寄存器的所有位(全部置0)

print_current_rflags()是查看当前flags寄存器情况,它会打印出flags的值,也会打印出哪些标志为1

asm 是一个c语言内嵌汇编语言的关键字,使用gcc默认的AT&T风格的汇编,语法稍微和Intel风格有所区别。

由于我的内核现在处于长模式,因此函数名里出现了rflags,表明是64位的PSW。以上函数是我自己编写的,大家知道是什么功能就好,我们主要看现象。

rflags的第二位是保留位,因此0x10中的1是为Intel保留的,不被使用的,可以忽略。

大家可以看到在运行例子代码之后,PF = 1,ZF = 1

这就说明:

结果是0,则ZF=1

结果中所有bit位为1的个数是0个(偶数),则PF=1

2、PF标志(Parity Flag奇偶标志):判断执行相关指令后的结果,若结果的所有bit位中1的个数是偶数个,则把PF标志位的值设置为1;反之则设置为0.

mov al,1
add al,10

运行结果为 0b00001011   奇数个1

PF=0成立

mov al,1
or al,2

运行结果为 0b00000011  偶数个1

PF=1成立

3、SF标志(Sign Flag符号标志):判断执行相关指令后的结果,若结果是负数,则把SF的值设置为1;如果非负数,则设置为0.

mov al,10000001B
add al,1

执行后的结果为 10000010B 为负数

则SF=1 如果你是当作有符号数来计算,则这个标志对你就有意义,如果你仅仅是当作无符号数来计算,那么可以忽略这个SF=1,不使用它。

并且结果中有偶数个1

PF=1

4、CF标志(Carry Flag进位标志):在进行无符号数运算的时候,它记录了运算结果的最高有效位向更高位的进位值,或从最高位的借位值。

mov al,98H
add al,al

98H + 98H > FFH

超过了al寄存器能存储的范围,出现了进位,则CF=1

执行后的al=30=0b00110000 其中有偶数个1,则PF=1

大家可以看到其中OF=1

书中已经说明:计算机并不关心你做的加法到底是有符号的加法还是无符号的加法,作为无符号数它进位了,而作为有符号数它溢出了。重要的是程序员怎么使用使用这两个标志位,你认为你做的是有符号加法,那就只看OF,不看CF;你认为你做的是无符号加法,那就只看CF,不看OF.

5、OF标志(Overflow Flag溢出标志):在进行有符号数运算的时候,如果结果超过了机器所能表示的范围时,把OF的值设置为1;如果没有超过则设置为0.

mov al,99
add al,98

这里的情况和上面的例子情况是一样的。

先把答案放一放:

组数CFOFSFZFPF
1sub al,al00011
2mov al,10h00011
3add al,90h00101
4mov al,80h00101
5add al,80h11011
6mov al,0FCH11011
7add al,05h10000
8mov al,7Dh10000
9add al,0BH01101

首先,我们来回忆一下,作者在讲标志寄存器的时候,曾经说过一句话:

在8086的指令集中,一般来说运算指令会影响标志寄存器,比如sub,mul,div,inc,or,and

一般来说传送指令不会影响标志寄存器,比如mov,push,pop

因此遇到传送指令的时候,把上一行的结果抄到当前行就好。

1、sub al,al

结果为0,则ZF=1

有0个1,是偶数个,则PF=1

2、mov al,10H

mov是转移指令,不影响flags

3、add al,90H

10H + 90H = A0H = 0b10100000

有偶数个1,所以PF=1

最高位为1,所以SF=1

OF标志位在确定的时候,CPU会假定你相加的两个数都是有符号数。10H的二进制表示是00010000,可以看见,最高位为0,因此这是一个正数,计算机在存储的时候使用的是补码,正数的原码和补码表示是一样的,因此00010000这个补码的原码还是00010000,转换成十进制是16.而90H则稍微复杂一些,90H=0b10010000,最高位是1,因此这是一个负数,那么我们需要把补码转换成原码01110000,这个原码代表了这个数的数值大小,再加上符号就是-112.

于是,16 - 112 = -96

8位有符号数能表示的范围是-128 ~ 127.那么在范围内,没有溢出,OF=0

结果为负数,所以SF=1

CF标志位在确定的时候,CPU会假定你相加的两个数都是无符号数,16 + 144 = 160,在0 ~ 255的范围内,没有进位。或者也可以看二进制的结果A0H = 0b10100000,没有产生进位。

总结:一个数放在寄存器里面,计算机(CPU)不知道它到底是有符号数还是无符号数,计算机也不想知道。在执行运算的时候,计算机在判断标志位的时候才会关注它。当确定CF标志的时候,把两个运算数都看成是无符号数,在确定OF,SF标志位的时候都看成有符号数。

如果程序员认为这是有符号数的运算,那么在运算结束后去判断OF或SF标志位即可,CF标志位忽略掉就好、CF位是1还是0对咱们来说没有意义;同理,程序员如果认为这是无符号数的运算,那么运算结束后就不需要关注OF或SF位,认为它们没有意义就好。

在手动判断标志位的时候,ZF、PF是比较简单的,就看看结果就好,不用管什么有无符号。

4、mov al,80h

5、add al,80H

80H + 80H = 100H = 0b100000000

结果=0b00000000则ZF=1

最高位的1进位出去了,则CF=1

结果里面有0个1,则PF=1

判断OF的时候当成是有符号数,0b10000000 + 0b10000000

-128 - 128 = -256

不在-128 ~ 127的范围之内,所以OF=1

6、mov al,0FCH

7、add al,05H

FCH + 5H = 101H

结果为1H

发生了进位,CF=1

我们判断一下OF标志位:0b11111100 + 0b00000101

其中0b11111100是负数,0b00000101 是正数,我们转换一下。

-4 + 5 = 1

这个结果在-128 ~ 127 这个范围内,没有溢出。

8、mov al,7DH

9、add al,0BH

7DH + BH = 88H = 0b10001000

其中有2个1,那么PF=1

最高位是1,那么结果为负数,则SF=1

我们再来判断OF位

7DH = 0b01111101 是一个正数 125

BH = 0b00001011 也是一个正数 11

125 + 11 = 136 > 128,那么就是溢出了,OF=1

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

April__Zhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值