• 汇编运算中的标志位与标志位检查


    (AT&T格式汇编)

    零、有符号数的补码(two's-complement)表示(复习)

    1. 反码(ones' complement,用 ~a 表示 -a,a 为无符号形式)和 原码(sign-magnitude 用最高有效位作为符号位)都存在一个问题:0 有两种编码形式,+0 和 -0.
      反码的属性:a + (-a) => 0xFFFF... = -0,也可表示为 [1111...] - a => -a. (that's why it's called ones' complement)
    2. 补码:
      属性:a + (-a) => [10000....(w个0)] = 2^w = 0,其中 w 为计算机表示的位数。(用 2^w - a 来表示 a 的负数,that's why it's called two's complement)
      注意 a + (-a) 最高位产生了进位,实际运算结果会成为 [0000....(w个)],刚好是 0 的表示。所以有符号计算中,进位标志 CF 不代表其真实意义。
      这种表示方式可直接做加减法,只要最高位为 1,一定为负数,而且 0 只有一种形式,因而被广泛使用。
      补码的特性:
      1. 因为其最高位实际上也相当于符号位,可知其负数域、和非负数域是一样大的。对 4 位的表示,非负数域是 0 ~ 7,而负数域是 -1 ~ -8,负数域比正数域大1.
      2. 在任意的位表示中,都有一个数,使 2^w - a = a成立,这就使 a 的负数表示成了它本身,这个数就是 [1000...(w-1个0)]。因为仍然用最高位表示符号位,因此在符号表示中,该数只存在负数形式,而没有正数形式了。在 4 位的表示中,它就是 -8,[10000000].

    一、四个算术逻辑操作的标志位

    1. CF(carry flag): 进位标志,针对无符号运算。当最高位产生进位(加法),或者从更高位借位(减法)时,被置 1.
    2. ZF(zero flag): 当上一次运算的结果为 0 时,置 1.
    3. SF(sign flag): 符号标志,针对有符号运算。当上一次运算结果的最高位为 1(即为负数时),被置 1.
    4. OF(overflow flag): 有符号运算的溢出标志(补码)。(对 t = a + b 溢出的情况是 (a>0 && b > 0 && t <0) || (a<0 && b<0 && t>=0),若 a 或 b 有一个为 0,就不可能溢出,所以不需要考虑。)
      要理清 OF 标志位的设置情况(对 a + b,减法可转换成补码加法 a + (-b))
      • 首先考虑到,a 和 b 必须同号,才可能溢出,因为异号、或者其中有一个是 0 的话,结果必定在范围内。
      • 若 a 和 b 均 大于 0,t 小于 0,判断为正溢出(两正数求和溢出,结果一定异号)
      • 若 a 和 b 均 小于 0,t 大于等于 0,判断为负溢出(同理,负数和溢出,必定异号。但是负溢出也可能溢出到 0 )
        更精确地描述溢出,考虑 有符号数 a 和 b,用 w 位来表示它们,则其取值范围为 [-2^(w-1), 2^(w-1)-1](这很容易从负数域、和非负数域是一样大的推得)
        则补码加法 [a + b] 的结果有三种情况:(这里引入 [a+b] 表示补码加法,而 a + b 表示理想的加法)
        1. 正溢出:a + b >= 2^(w-1) 时,运算结果越过了上界,被截断为 a + b - 2^w,这表示最高位的进位(2^w)被舍弃。可看出溢出的结果一定为负数,当a = b = 2^(w-1)-1 时,运算结果有最大值 -2。
        2. 正常:a + b 仍在 [-2^(w-1), 2^(w-1)-1] 内,结果正常,为 a + b.
        3. 负溢出:a + b < -2^(w-1) 时,运算结果越过了下界,从位表示上看,这也是最高位产生了进位。这个进位本该表示 -2^w. 但是被舍弃,因而结果是 a + b + 2^w. 可看出溢出的结果一定为非正数,当a = b = -2^(w-1) 时,运算结果有最小值 0。

    二、设置标志位的操作

    1. 所有逻辑运算,移位运算 和 加、减、乘 运算。
    2. cmp s1, s2 基于从 s2 减去 s1 的结果来设置标志位。(与 sub 的行为是一样的,只是它只设置标志位,并不保存运算结果)
    3. test s1, s2 与 and 的行为是一样的,只是它只设置标志位,并不保存运算结果

    三、访问条件码

    1. SET 指令

    分为三类:通用指令(为 0 的测试是通用的)、有符号指令(greater less)、无符号指令(above below)

    难点:setl 指令

    (其他有符号的 set 指令都基于 OF^SF)

    ; a in %rdi, b in %rsi
    comp:
        cmpq %rsi, %rdi   ;会根据 a-b 的结果设置标志位
        setl %al
        movzbl %al, %eax
        ret
    

    setl 会在 a<b 时设置 %al. 下面考虑一下它的实现。

    1. 当没有发生溢出时(OF 为 0),运算正常,所以 SF 为 1 时,a-b<0,否则 SF 为 0.
    2. 若 OF 为 1,又分两种情况。
      • 若为正溢出,结果会为负数,因此 SF 会置 1。 [a-b] 发生正溢出,说明 b 为负数 a 为 正数,a>b
      • 若为负溢出,结果会为正数或者 0,这都会有 a 为负数,b 为正数,a<b。

    综上,当 OF 和 SF 相异时,a<b成立,即OF^SF

    而无符号的比较,相对简单很多,略过了。

    2. 跳转指令

    跳转指令也和 SET 指令很类似,分为 无条件跳转(jmp)、通用跳转(为 0 的测试)、有符号的、无符号的。
    只要理解了 SET,这里标志位与命令后缀的对应关系完全类似。不多讲。

    3. 条件转送

    传统的条件跳转指令,不适合现代处理器的流水线处理。在可能的情况下,使用数据的条件传送会使程序更高效。
    原因在于数据的条件传送指令,避免了条件分支,使程序更适合使用流水线( pipelining )处理。(但是当分支代码量很多时,使用条件传送会造成巨大的开销。而且有些代码并不能使用这种方式,会造成非法操作如空指针、指针越界等。。)

    条件传送指令的后缀意义与跳转指令的完全类似。

    参考

    汇编语言--标志寄存器
    CSAPP-深入理解计算机系统

  • 相关阅读:
    Windows8 游戏开发教程开篇
    IPAD 游戏开发方案,windows开发
    谈一谈 Windows 8 的软件开发架构
    html5 大家一起来瞅吧瞅吧
    silverlight5中CLGF的推进
    html5 游戏界面问题
    挑战SVN,最纯洁的SVN客户端计划
    章鱼哥的暴走,HTML5也开始了
    MySQL的常用操作!
    两种屏蔽鼠标右键的方法
  • 原文地址:https://www.cnblogs.com/kirito-c/p/8784182.html
Copyright © 2020-2023  润新知