2

I want to read the CPU flags by pushing them onto the stack and then pop them to a register like this:

uint32_t getEflags() {
    uint32_t eflags;
    asm ("pushf");
    asm ("pop %eax");
    asm ("mov %%eax, %0" : "=r"(eflags));
    return eflags;
}

Now I saw that this is a mistake because pushf only pushes the lower 16 bits of the EFLAGS, and I'm then popping them into a 32 bit register (i would need pushfd).

That means I'm basically popping more than I'm initially pushing - what happens with my stack when returning here?

maxdev
  • 2,491
  • 1
  • 25
  • 50

1 Answers1

5

The instruction set reference says this:

Decrements the stack pointer by 4 (if the current operand-size attribute is 32) and pushes the entire contents of the EFLAGS register onto the stack

It also says:

The PUSHF (push flags) and PUSHFD (push flags double) mnemonics reference the same opcode. The PUSHF instruction is intended for use when the operand-size attribute is 16 and the PUSHFD instruction for when the operand-size attribute is 32. Some assemblers may force the operand size to 16 when PUSHF is used and to 32 when PUSHFD is used. Others may treat these mnemonics as synonyms (PUSHF/PUSHFD) and use the current setting of the operand-size attribute to deter- mine the size of values to be pushed from the stack, regardless of the mnemonic used.

So no problem there. Your asm is broken, though, it should be something more like this:

__asm__ __volatile__(
    "pushf\n\t"
    "pop %0"
: "=rm" (eflags));
Jester
  • 56,577
  • 4
  • 81
  • 125
  • May I ask, what exactly is the difference between your code and OP's? They both work fine and in exactly the same manner on my computer. – Frxstrem Apr 19 '14 at 22:25
  • Okay, thank you. Could you describe why my asm code doesnt work like this? – maxdev Apr 19 '14 at 22:27
  • 4
    For one thing, the OP's code forgets to tell the compiler that `eax` is clobbered so it may break surrounding code. Also, the separate asm blocks may be reordered by the compiler. Furthermore, as an optimization point, the output operand can be any register or memory, and no need to go through `eax`. – Jester Apr 19 '14 at 22:27
  • Just for future reference, in GNU as with AT&T syntax in 32-bit mode, `pushf` and `pushfl` are both the 32-bit push (which is PUSHFD in Intel syntax). If you want the 16-bit version, it's `pushfw`. – Nate Eldredge Apr 21 '20 at 02:55
  • 1
    I was going to say the output constraint should be `"=r"`, not `"=rm"`, because ESP might be wrong if the compiler happened to pick a local on the stack. But it's actually fine, the addressing mode calculation for the destination happens *after* `pop` modifies ESP. [What is an assembly-level representation of pushl/popl %esp?](https://stackoverflow.com/q/14968824) - so the only danger is in a calling convention with a red-zone, like x86-64 SysV. – Peter Cordes Oct 22 '22 at 14:40