There’s a nifty trick for saving and restoring the flags register on x86 and x86_64 that I ran across in DyninstAPI while working on my research. I can’t find it anywhere else that describes it with a quick Google search, so I figured I’d post it here.
WARNING: This is pretty technical.
Any x86 assembly programmer is aware of the PUSHF/POPF instructions. They save and restore the FLAGS register to the top of the stack, respectively. When inserting instrumentation, you will want to do this around every bit of code you insert so as not to perturb the original program. However, this can become quite expensive in terms of CPU time.
Luckily there is a faster alternative if you only care about saving a specific subset of commonly-used flags, specifically OF (overflow), SF (sign), ZF (zero), AF (auxiliary), PF (parity), and CF (carry). This alternative uses the LAHF and SAHF instructions to load and save the flags to AH (the high-order 8 bytes of AX); it also uses SETO to save the overflow bit and an additional trick (described below) to restore it.
Here is the saving sequence:
9f lahf ; save lower-order flags 0f 90 c0 seto %al ; save OF 86 c4 xchg %al, %ah 50 push %eax
And here is the restoring sequence:
58 pop %eax 86 c4 xchg %al, %ah 80 c0 7f add 0x7f, %al ; restore OF 9e sahf ; restore lower-order flags
The XCHG instructions aren’t strictly necessary unless you want the saved values to reflect the correct byte order of the original FLAGS register. If you’re just saving and restoring the flags around a bit of code and don’t plan to modify those stored flags yourself, you don’t care what byte order they’re saved in.
The OF restore is the only part of this that isn’t entirely straightforward: basically, it performs an in-place 8-bit addition that is designed to overflow only if the overflow flag was set in the EAX-stored value. The addition won’t modify the higher bytes of EAX even if the overflow occurs, so this is safe.
The only other caveat is that these excerpts assume that EAX can be clobbered. If you can’t make this assumption, you can just add an extra push/pop of EAX around these excerpts to save and restore that register as well.
I hope this is helpful to someone besides myself.