在x86-64系统中RFLAGS是64bit位的寄存器,该寄存器包含两种不同类型的信息:
1)Status Bits:状态标识位,提供了算术运算和逻辑运算的结果信息,这些位是由处理器写入,可在任何特权级别下由运行的软件读取。
2)Control Bits:控制标识位,为字符串操作提供系统软件控制和方向信息,其中一些位可能受到权限级别的限制。
1. 状态标识位
以下为RFLAGS寄存器中所有的标识位图:
| 63 | 32 | ||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 预留 | |||||||||||||||||||||||||||||||
| 31 | 22 | 21 | 20 | 19 | 18 | 17 | 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||||||||
| 预留 | ID | VIP | VIF | AC | VM | RF | 预留 | NT | IOPL | OF | DF | IF | TF | SF | ZF | 预留 | AF | 预留 | PF | 预留 | CF | ||||||||||
Bit位:22-63均为预留。
其中的状态标识位如下表:
| Bit位 | 助记符 | 描述 |
| 0 | CF | Carry Flag,算术运算中导致运算的结果最高位产生进位/借位时置1,否则置0 |
| 2 | PF | Parity Flag,运算结果的最低有效字节中Bit位是1的数量为偶数时置1,否则置0 |
| 4 | AF | Auxiliary Carry Flag,运算导致结果中的Bit位3产生进位/借位时置1,否则置0 |
| 6 | ZF | Zero Flag,运算的结果为零时置1,否则置0 |
| 7 | SF | Sign Flag,算术运算的结果为负值时置1,否则置0.即其值为结果的最高有效位 |
| 11 | OF | Overflow 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
发表回复