标签: rflags

  • RFLAGS中的状态标识位

    在x86-64系统中RFLAGS是64bit位的寄存器,该寄存器包含两种不同类型的信息:

    1)Status Bits:状态标识位,提供了算术运算和逻辑运算的结果信息,这些位是由处理器写入,可在任何特权级别下由运行的软件读取。

    2)Control Bits:控制标识位,为字符串操作提供系统软件控制和方向信息,其中一些位可能受到权限级别的限制。

    1. 状态标识位

    以下为RFLAGS寄存器中所有的标识位图:

    6332
    预留
    31222120191817161514131211109876543210
    预留IDVIPVIFACVMRF预留NTIOPLOFDFIFTFSFZF预留AF预留PF预留CF

    Bit位:22-63均为预留。

    其中的状态标识位如下表:

    Bit位助记符描述
    0CFCarry Flag,算术运算中导致运算的结果最高位产生进位/借位时置1,否则置0
    2PFParity Flag,运算结果的最低有效字节中Bit位是1的数量为偶数时置1,否则置0
    4AFAuxiliary Carry Flag,运算导致结果中的Bit位3产生进位/借位时置1,否则置0
    6ZFZero Flag,运算的结果为零时置1,否则置0
    7SFSign Flag,算术运算的结果为负值时置1,否则置0.即其值为结果的最高有效位
    11OFOverflow Flag,整数运算结果作为正数过大(溢出)或负数过小(下溢),无法容纳到目标操作数中时置1,否则置0.

    2. 打印标识位

    我们将通过运算示例说明每个状态标识位的变化并使用GDB脚本来打印标识:

    GDB脚本共用,代码如下(脚本名称:show_rflags.gdb):

    # 自定义命令,行尾续行符 '\'
    define show_rflags
        printf "RFLAGS = 0x%lx\n",$eflags
        printf "CF=%d  PF=%d  AF=%d  ZF=%d  SF=%d  TF=%d  IF=%d  DF=%d  OF=%d\n", \
        ($eflags>>0)&1, ($eflags>>2)&1, ($eflags>>4)&1, \
        ($eflags>>6)&1, ($eflags>>7)&1, ($eflags>>8)&1, \
        ($eflags>>9)&1, ($eflags>>10)&1, ($eflags>>11)&1
    end
    
    # 每次停下自动打印 flags
    define hook-stop
      show_rflags
    end

    注意:GDB中引用RFLAGS时,GDB中只能使用 $eflags

    测试汇编代码(test_rflags.s):

    .global _start
    .section .text
    
    _start:
        mov $0xFF, %al
        add $1, %al
        nop
    
        mov $60, %rax
        xor %rdi, %rdi     # exit code 0
        syscall

    编译和链接:

    $ as -o test_rflags.o test_rflags.s
    $ ld -o test_rflags test_rflags

    在GDB调试查看各个状态的变化:

    $ gdb -q ./test_rflags
    # 在 _start 处打个断点
    (gdb) b _start
    # 加载GDB脚本
    (gdb) source show_rflags.gdb
    # 运行程序
    (gdb) run
    RFLAGS = 0x202
    CF=0  PF=0  AF=0  ZF=0  SF=0  TF=0  IF=1  DF=0  OF=0
    
    Breakpoint 1, 0x0000000000401000 in _start ()
    # 显式汇编源码和执行行数指示
    (gdb) layout asm
    # mov $0xFF, %al
    (gdb) si
    RFLAGS = 0x202
    CF=0  PF=0  AF=0  ZF=0  SF=0  TF=0  IF=1  DF=0  OF=0
    0x0000000000401002 in _start ()
    (gdb) si
    RFLAGS = 0x257
    CF=1  PF=1  AF=1  ZF=1  SF=0  TF=0  IF=1  DF=0  OF=0
    0x0000000000401004 in _start ()
    

    从显式可以看出在执行 add $1, %al 加法运算后对应的标识发生了改变:

    0xFF=1111 1111
      1111 1111
     +        1
    ------------
     10000 0000
    
    运算结果超出al寄存器表示的范围,截取结果后result=0,所以ZF=1。
    结果的最高位产生了进位,所以CF=1.
    结果中的bi3到bit4产生了进位,所以AF=1.
    结果中的所有bit位都是0,因此bit是1的数量为0,是偶数,因此PF=1.

    示例2:

        mov $0x7F, %al
        add $1, %al

    运行GDB:

    (gdb) si 
    RFLAGS = 0x202
    CF=0  PF=0  AF=0  ZF=0  SF=0  TF=0  IF=1  DF=0  OF=0
    # 执行 add $1,%al
    (gdb) si
    RFLAGS = 0xa92
    CF=0  PF=0  AF=1  ZF=0  SF=1  TF=0  IF=1  DF=0  OF=1
      0111 1111
     +        1
    ------------
     1000 0000
    result=0x80 ===> 128
    result未超出AL可表示的无符号数范围([0,255]),所以CF=0
    result的最高位是1,所以SF=1
    result超出AL可表示的有符号数范围([-128, +127]),所以OF=1
    result中的bit3到bit4产生了进位,所以AF=1