EFLAGS 状态
State of EFLAGS
在过去的几天里,我一直在努力解决试图获取 EFLAGS 状态的奇怪行为。为此,我编写了以下代码:
#include <stdio.h>
int flags_state()
{
int flags = 0;
__asm__ __volatile__("pushfq");
__asm__ __volatile__("pop %%rax": "=a"(flags));
return flags;
}
int main()
{
printf("Returning EFLAGS state: 0x%x\n", flags_state());
return 0;
}
当它运行时,我得到:
./flags
Returning EFLAGS state: 0x246
当我打印两次标志时,它变得越来越奇怪
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x206
当我尝试打印 6 次时,它发生了变化
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
最后是最奇怪的(至少对我来说)当我打印 8 次时
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
那么,为什么我第一时间得到的是0x246呢?根据英特尔手册,不应该是 0x2 吗?为什么当我尝试打印更多次并继续更改时它会发生变化?
__asm__ __volatile__("pushfq");
__asm__ __volatile__("pop %%rax": "=a"(flags));
您不能像这样分解 asm 语句之间的指令。当 asm 语句移动堆栈指针而不将其放回原处时,编译器会感到非常困惑。它可能单独看起来没问题,但想象一下内联函数;编译器可以决定针对明显不相关的代码移动 asm。
另一个问题是,由于 ,编译器可能已将重要数据 放在堆栈指针 下方:就在您的 pushfq
会覆盖的位置它。
这不是那么容易解决的。我最好的猜测是
unsigned long get_rflags(void) {
unsigned long result;
asm("sub 8, %%rsp ; pushfq ; pop %0 ; add 8, %%rsp"
: "=r" (result) : : "cc");
return result;
}
或者将其编写为纯粹在 asm 中的“裸”函数,以便您知道编译器不参与。
(如 所述,可以通过编写 add $-128, %%rsp
... sub $-128, %%rsp
进行较小的代码大小优化,因为 -128 适合符号扩展的 8 位,但 +128 没有。)
( sub/add
本身会影响算术标志,如下所述,但它们又一次被频繁更改,以至于很难赋予它们的值太多意义。我想你可以使用 lea -128(%%rsp), %%rsp
如果你真的关心。)
至于变化的值,您会看到第 2 位和第 6 位的变化:奇偶校验标志和零标志。由于几乎每个算术指令都根据结果设置这些,并且其他代码在您的调用之间执行(例如 printf
的所有代码!),我们会看到这些值发生变化也就不足为奇了。进位、符号、溢出和辅助进位标志同样是“易变的”。这没什么奇怪的。
没有理由期望值 0x2:各种代码都已 运行,几乎所有代码都会影响标志,那么为什么所有其他标志都需要清除?
如果愿意,您可以在调试器中逐条指令单步执行代码,并观察 RFLAGS 的变化。您可能会看到它在一个 printf 和下一个之间更改了数百次。
So, why did I get 0x246 at the first time? Shouldn't be 0x2 according
Intel's manual?
在 flags_state()
第一次调用之前,一些代码在系统中执行,结果大多数标志状态是随机的,你不能在通用标志上假设任何值,比如 ZF (0x40)
它可以是和设置并重置..以及如何将 Intel 的手册? 与此处关联起来?
Why did it change when I try to print it more times and continue
change?
函数不得保留 ZF
标志(与 windows 中的 DF
不同 - 在 return 中必须为 0) - 因此此标志在函数后具有哪个值return - 也未定义 - 如果只有你自己不在 asm 上编写所有代码并完全控制它。事实上 ZF
在 flags_state
return 之后被重置并且在 flags_state
的序言中没有改变 - 结果是第一次 - 你有在前面的代码中设置的值然后已经全部时间相同的值,在 flags_state
中设置(你错了,它 继续改变 - 它没有改变,如你的输出所示 - 0x206 一直)
在过去的几天里,我一直在努力解决试图获取 EFLAGS 状态的奇怪行为。为此,我编写了以下代码:
#include <stdio.h>
int flags_state()
{
int flags = 0;
__asm__ __volatile__("pushfq");
__asm__ __volatile__("pop %%rax": "=a"(flags));
return flags;
}
int main()
{
printf("Returning EFLAGS state: 0x%x\n", flags_state());
return 0;
}
当它运行时,我得到:
./flags
Returning EFLAGS state: 0x246
当我打印两次标志时,它变得越来越奇怪
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x206
当我尝试打印 6 次时,它发生了变化
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
Returning EFLAGS state: 0x202
最后是最奇怪的(至少对我来说)当我打印 8 次时
Returning EFLAGS state: 0x246
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
Returning EFLAGS state: 0x206
那么,为什么我第一时间得到的是0x246呢?根据英特尔手册,不应该是 0x2 吗?为什么当我尝试打印更多次并继续更改时它会发生变化?
__asm__ __volatile__("pushfq");
__asm__ __volatile__("pop %%rax": "=a"(flags));
您不能像这样分解 asm 语句之间的指令。当 asm 语句移动堆栈指针而不将其放回原处时,编译器会感到非常困惑。它可能单独看起来没问题,但想象一下内联函数;编译器可以决定针对明显不相关的代码移动 asm。
另一个问题是,由于 pushfq
会覆盖的位置它。
这不是那么容易解决的。我最好的猜测是
unsigned long get_rflags(void) {
unsigned long result;
asm("sub 8, %%rsp ; pushfq ; pop %0 ; add 8, %%rsp"
: "=r" (result) : : "cc");
return result;
}
或者将其编写为纯粹在 asm 中的“裸”函数,以便您知道编译器不参与。
(如 所述,可以通过编写 add $-128, %%rsp
... sub $-128, %%rsp
进行较小的代码大小优化,因为 -128 适合符号扩展的 8 位,但 +128 没有。)
( sub/add
本身会影响算术标志,如下所述,但它们又一次被频繁更改,以至于很难赋予它们的值太多意义。我想你可以使用 lea -128(%%rsp), %%rsp
如果你真的关心。)
至于变化的值,您会看到第 2 位和第 6 位的变化:奇偶校验标志和零标志。由于几乎每个算术指令都根据结果设置这些,并且其他代码在您的调用之间执行(例如 printf
的所有代码!),我们会看到这些值发生变化也就不足为奇了。进位、符号、溢出和辅助进位标志同样是“易变的”。这没什么奇怪的。
没有理由期望值 0x2:各种代码都已 运行,几乎所有代码都会影响标志,那么为什么所有其他标志都需要清除?
如果愿意,您可以在调试器中逐条指令单步执行代码,并观察 RFLAGS 的变化。您可能会看到它在一个 printf 和下一个之间更改了数百次。
So, why did I get 0x246 at the first time? Shouldn't be 0x2 according Intel's manual?
在 flags_state()
第一次调用之前,一些代码在系统中执行,结果大多数标志状态是随机的,你不能在通用标志上假设任何值,比如 ZF (0x40)
它可以是和设置并重置..以及如何将 Intel 的手册? 与此处关联起来?
Why did it change when I try to print it more times and continue change?
函数不得保留 ZF
标志(与 windows 中的 DF
不同 - 在 return 中必须为 0) - 因此此标志在函数后具有哪个值return - 也未定义 - 如果只有你自己不在 asm 上编写所有代码并完全控制它。事实上 ZF
在 flags_state
return 之后被重置并且在 flags_state
的序言中没有改变 - 结果是第一次 - 你有在前面的代码中设置的值然后已经全部时间相同的值,在 flags_state
中设置(你错了,它 继续改变 - 它没有改变,如你的输出所示 - 0x206 一直)