Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly EFLAGS的状态_Assembly_X86 64_Inline Assembly_Eflags - Fatal编程技术网

Assembly EFLAGS的状态

Assembly EFLAGS的状态,assembly,x86-64,inline-assembly,eflags,Assembly,X86 64,Inline Assembly,Eflags,在过去的几天里,我一直在与一种奇怪的行为作斗争,试图了解EFLAGS的状态。为了实现这一点,我编写了以下代码: #包括 int flags_state() { int标志=0; __asm_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu; __asm_____;volatile_________(“pop%%rax”:“=a”(标

在过去的几天里,我一直在与一种奇怪的行为作斗争,试图了解EFLAGS的状态。为了实现这一点,我编写了以下代码:

#包括
int flags_state()
{
int标志=0;
__asm_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu;
__asm_____;volatile_________(“pop%%rax”:“=a”(标志));
返回旗;
}
int main()
{
printf(“返回EFLAGS状态:0x%x\n”,flags_state());
返回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 $128, %%rsp ; pushfq ; pop %0 ; add $128, %%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和下一个printf之间变化数百次

那么,为什么我第一次得到0x246?不应该是0x2 英特尔手册

在第一次调用
flags_state()
之前,一些代码在系统中执行,因此大多数标志状态都是随机的,您不能假设通用标志上的任何值,例如
ZF(0x40)
可以设置和重置。。英特尔的手册又如何?这里有什么关系

当我尝试打印更多次并继续打印时,为什么会发生变化 换衣服


函数不能保留
ZF
标志(与windows中的示例
DF
不同-返回时必须为0)-因此,函数返回后该标志的值是多少-也未定义-如果您自己不在asm上编写所有代码并对此进行完全控制。事实上,
ZF
flags\u state
返回后被重置,并且在
flags\u state
的序言中没有更改-结果是第一次-您有在前一个代码中设置的值,然后一直都是在
flags\u state
中设置的相同值(您错误地认为它将继续更改-它尚未更改,显示您的输出-始终为0x206)

在x86-64中,它是RFLAGS,不是EFLAGS,是64位长耶,你是对的@phuclv。我说EFLAGS是因为位是从22位到63位保留的。你不可能看到0x2。0x200是中断标志,在用户程序中永远不应该是0。在第一次调用标志状态之前,
ZF(0x40)
标志是在您的情况下设置的。函数在执行过程中重置此标志。因此在下一次调用时-
ZF
已经没有设置。我不明白为什么这会让您困惑。嗯,我现在看到了,并且完全有意义。感谢您的澄清@Nate Eldredgecompiler可能已经将重要数据放在堆栈指针下-确保不能。如果代码在内核中运行l模式,内核堆栈上-中断可以在任何时候,它覆盖所有下面的堆栈指针。不查看windows中的任何红色区域minimum@RbMm:这是正确的,如果您使用GCC/clang编译内核代码,则需要使用
-mno red zone
禁用x86-64系统V ABI的该部分。在非Windows上,ABI包括一个红色区域-GCC/clang将使用的区域。()从问题中,他们使用
/flags
运行测试程序,这对于Linux或Mac系统来说是正常的。@RbMm:是的,这正是我在我的答案中所说的,我已经链接过了。而且是的,问题中的代码中的这个错误只有在经过优化编译后才相关,并且它被内联到带有loc的函数中al变量位于红色区域。可能的错误是
pushf
将编译器保持在RSP以下的其他内容单步执行,而不是asm无法将RFLAGS准确地放入C变量
标志中。@RbMm:不太可能;MSVC对所有内容都有内部函数,而不支持内联asm。GCC/clang具有设计干净的可用内联asm因此,操作系统应该使用它来设置/清除EFLAGS中的控制标志(如IF或AC)。(在编译器生成代码后,从EFLAGS中获取CF/OF/ZF等状态标志并不是特别有用;您不知道它是使用ADD还是LEA,甚至不知道最后一次计算是否来自C源代码。因此,它非常有用