TF(Trap Flag)——位8,跟踪标志。置1 则开启单步执行调试模式,置0 则关闭。在单步执行模式下,处理器在每条指令后产生一个调试异常,这样在每条指令执行后都可以查看执行程序的状态。如果程序用POPF、POPFD 或者ET 指令设置TF 标志,那么这之后的第一条指令就会产生调试异常。
IF (Interrupt enable)——位9,中断许可标志。控制处理器对可屏蔽硬件中断请求的响应。置1 则开启可屏蔽硬件中断响应,置0 则关闭可屏蔽硬件中断响应。IF 标志不影响异常和不可屏蔽中断(NMI)的产生。CPL、IOPL 和控制寄存器CR4 中的VME 标志决定着IF 标志是否可由CLI、STI、POPF、POPFD 和IRET 指令修改。
IOPL(I/O Privilege Level Field)——位12&位13, I/O 特权域。标示当前进程或任务的I/O 特权级别。当前进程或任务的CPL 必须小于或等于IOPL 才可以访问I/O 地址空间。只有CPL 为0 的进程才可用POPF 和IRET 指令修改这个域。IOPL 是控制IF 标志修改的机制之一,同时也是当虚拟模式扩展生效时(控制寄存器CR4 中的VME 置位),控制虚拟8086 模式下中断处理的机制之一。
NT (Nested Task)——位14,嵌套任务。控制被中断和被调用的任务的嵌套执行链。处理器调用一个由CALL 指令、中断或者异常触发的任务时设置该位,调用IRET指令返回时检测并修改该位。该标志可以由POPF/POPFD 指令直接置位或置0,然而在应用程序中修改该标志的状态会产生不可预料的异常。
RF(Resume)——位16, 恢复。控制处理器对指令断点的响应。置1 则暂时禁用指令断点产生调试异常(debug exceptions,#DE),但是其它异常情况仍可以产生异常。置0 则指令断点产生调试异常。RF 标志的主要功能是许可从调试异常(指令断点引发的)后面的那个指令开始继续执行。调试软件必须在用IRETD 指令返回到被中断程序之前,将栈中的EFLAGES 映象中的该位置为1,以阻止指令断点产生另外的调试异常。在返回并成功执行断点指令之后,处理器会自动清零该位,从而许可继续产生指令断点故障。
VM (Virtual-8086 mode)——位17,虚拟8086 模式。置1 则进入虚拟8086 模式,置0 则返回保护模式。
AC (Alignment check)——位18,对齐检查。置位该标志和控制寄存器CR0 的AM 标志则启用对内存引用的对齐检查,清除这两个标志则禁用对齐检查。当引用一个没有对齐的操作数时,将会产生一个对齐检查异常,比如在奇地址引用一个字地址或在不是4 的倍数的地址引用一个双字地址。对齐检查异常只在用户态(3 级特权)下产生。默认特权为0 的内存引用,比如段描述符表的装载,并不产生这个异常,尽管同样的操作在用户态会产生异常。对齐检查异常用于检查数据的对齐,当处理器之间交换数据时这很有用,交换数据需要所有的数据对齐。对齐检查异常也可供解释程序使用。让某些指针不对齐就好比做上特殊标记,这样就无需对每个指针都进行检查,只在用到的时候,对这些特殊指针进行处理就可以了。
VIF (Virtual Interrupt)——位19,虚拟中断。是IF 标志的一个虚拟映象。这个标志是和VIP标志一起使用的。当控制寄存器CR4 中的VME 或者PVI 标志置为1 且IOPL小于3 时,处理器只识别VIF 标志(VME 标志用来启用虚拟8086 模式扩展,PVI 标志启用保护模式下的虚拟中断)。
VIP (Virtual interrupt pending)——位20,虚拟中断等待。置1 表明有一个正在等待处理的中断,置0 表明没有等待处理的中断。该标志和VIF 一起使用。处理器读取该标志但从来不修改它。当VME 标志或者控制寄存器CR4 中的PVI 标志置1 且IOPL 小于3 时,处理器只识别VIP 标志。(VME 标志启用虚拟8086模式扩展,PVI 标志启用保护模式虚拟中断)。
ID (Identification)——识别(第21 位)。置1 或0 表明是否支持CPUID 指令。
其它的通用标志:
CF——进位标志
PF——恢复标志
AF——辅助标志
ZF——零标志
SF——负号标志
DF——方向标志
OF——溢出标志
上表是 32 位寄存器 EFLAGS 的低 16 位.
不能直接读写 EFLAGS, 但有些方便的指令, 如:
LAHF: 读取EFLAGS 低 8 位到 AH;
SAHF是将AH存至EFLAG低8位
---------------------------------------------------------------------------------------------------
CLC ;置CF=0
STC ;置CF=1
CMC ;置CF= (Not CF)进位标志求反
CLD ;置DF= 0
STD ;置DF=1
---------------------------------------------------------------------------------------------------
.386
.modelflat,stdcall
include windows.inc
include kernel32.inc
include masm32.inc
include debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.data
szBin1 db 8 dup(?), 0
szBin2 db 8 dup(?), 0
szBin3 db 8 dup(?), 0
szBin4 db 8dup(?), 0
.code
main proc
stc ;置位 CF, CF = 1
lahf
invoke byt2bin_ex,ah,addr szBin1
clc;复位 CF, CF = 0
lahf
invokebyt2bin_ex,ah,addr szBin2
stc
cmc;取反 CF, CF = not CF
lahf
invoke byt2bin_ex,ah,addrszBin3
clc
cmc;取反 CF, CF = not CF
lahf
invokebyt2bin_ex,ah,addr szBin4
PrintString szBin1 ;xxxxxxx1
PrintString szBin2 ;xxxxxxx0
PrintString szBin3 ;xxxxxxx0
PrintString szBin4 ;xxxxxxx1
ret
main endp
end main
---------------------------------------------------------------------------------------------------
如果要观察整个 EFLAGS 的 32 个位, 可用 PUSHFD 和 POPFD 指令让 EFLAGS 进栈、出栈
---------------------------------------------------------------------------------------------------
.586p
.model flat, stdcall
include windows.inc
include kernel32.inc
include masm32.inc
include debug.inc
includelib kernel32.lib
includelib masm32.lib
includelib debug.lib
.data
szBin db 32 dup(?), 0
.code
main proc
stc
pushfd
invoke dw2bin_ex, dword ptr [esp+4],addr szBin
popfd
PrintString szBin ;00000000000000000000001001000111
clc
pushfd
invoke dw2bin_ex, dword ptr [esp+4],addr szBin
popfd
PrintString szBin ;00000000000000000000001010000110
ret
main endp
end main