- 论坛徽章:
- 13
|
太累了,反而睡不着。
汇编指令,一定要记住或理解它对应的硬件执行过程,而不只是它的功能或名字。比如AAA,如果只记它是“非压缩BCD码调节指令”,那么思维就会受到局限,只会在调节BCD码时想到它,并且不知道如果给它的不是BCD码,又会怎么样。
(intel手册-卷2:https://software.intel.com/sites ... 3-sdm-vol-2abcd.pdf)
比如在某次面试时,忘记设置AF、CF标志位的指令了,就可以通过mov al,0ah; aaa进行设置。虽然比较负能量,但还是能说明“明白指令的本质,就能灵活运用,达到超过其设计本意之外的目的”。
抓住本质是一种乐趣,学习底层的东西能明显体会到这一点。
同样,对CF、OF的理解,千万不能只停留在“最高位进位标志位”、“溢出标志位”这两个浅显的名称上,要多追究一下它们的来历,和硬件具体什么条件下会给它们置1:
CPU为了简化自己的电路设计,没有为加减乘除各设计一套电路,而是只提供一个加法器,并且也不区分正负数。
编译器要面对要求苛刻的领导(程序里的+-×÷操作,甚至操作数还是有符号的),下属又不愿尽心尽力,所以开始想办法:
① 减乘除转换为加法操作
加法实现减法:想象一下挂钟,从一个刻度到达另一个刻度,可以逆时针走(减),也可以顺时针走(加),所以编译器将所有的-n,都替换成+(-n的补码);
加法实现乘法:10×3=10+10+10;
加法实现除法:10÷3,不断的减3,直到余数1比3小,减的次数3即为商,而上述已说明,减法也是利用加法实现的。
② 正负数区分
相加的结果,需要包含两种信息,一是“和”本身,二是“是否超量程”。
加数正负对“和”的影响:
最高位为0,比如00000001,作为无符号是1,作为有符号也是1,所以不用区分;
最高位为1,比如10000001,是无符号的129,还是有符号的-127呢?
硬件仍然不用区分,因为10000001是根据129来的,还是根据-127来的,那是编译器根据程序的意愿安排的,得到的结果自然也符合程序的要求,硬件既然只提供加法器,它做好加法器该做到的就可以了。
加数正负对“是否超量程”的影响:
显然,程序肯定希望把无符号相加的结果,仍然当作无符号数,有符号相加的结果,仍然当作有符号数。对于8位的寄存器,无符号量程为0〜256,有符号量程为-128〜+127,而硬件不知道自己加的是无符号数还是有符号数,所以分别用CF、OF把这两种情况“是否超量程”都记下来,结果返回到程序后,程序自然知道哪一个才是自己需要的。
硬件将两个加数理解为无符号时,如果结果超量程,即最高位产生进位,CF置1。
从作用来看,和CF一样好理解,比如8位寄存器用于存有符号数相加的结果,量程有7位。
只不过涉及到符号,以及负数的补码,所以硬件对OF置1的条件稍微有点难理解:次高位是否进位(进位1,否则0)异或CF标志位
为了理解清晰,先想清楚两点:
① 相加过程,穿过“0点”即为超量程;
② Tyyyyyyy如果为负数,则本该是沿圆圈外面的路线往结果移动的,只是为了用加法实现减法,才走圆圈里面的路线的,不穿过“0点”反而表示超量程,穿过“0点”反而表示不超量程。
先确定Sxxxxxxx的位置(优先选正数作为Sxxxxxxx),然后:
① 如果Tyyyyyyy是正数(符号位S、T都为0,则CF=0)
超量程,次高位进位,异或得1;不超量程,次高位不进位,异或得0。
结论:对OF的设置,在正数+正数时没问题。
② 如果Tyyyyyyy是负数
如果Sxxxxxxx是正数(符号位T为0):次高位进位,符号位也进位,CF为1,异或得0;次高位不进位,符号位也不会进位,CF为0,异或得0。
结论:与异号数相加不可能产生溢出的事实相符。
如果Sxxxxxxx是负数(符号位S、T都为1,CF=1):不妨分别验证一下-1+-1和-127+-127(注意:加负数的补码穿过“0点”,反而表示实际不超量程)。
此时,再回头看“次高位是否进位(进位1,否则0)异或CF标志位”这个设置OF标志位方法,发现是高手用一个高效的公式,归纳了平常人的一堆if-else!
|
|