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

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注