drreg eflags restoration is destructive and destroys the value when kept in eax
I split this from #511 because it is interesting and worth documenting and may affect how core DR or other components handle eflags.
In 00d39c73 I changed drreg to keep aflags in eax where possible on x86, something that Dr. Memory was already doing. Thus there's only one spill (zero if eax is dead) and no need to store the app eflags value to memory. We saved the 6 arithmetic flags ("aflags") via the technique developed for DR:
lahf
seto %al
However, when doing this, if we need to restore the app's value to the eflags register, we were again using the technique developed inside DR:
add 0x7f, %al
sahf
The problem is, that add is destructive: it changes al
, and that's our only copy of the overflow flag, thus corrupting our saved flags.
This shows up when I add a simple test to drreg-test.dll.c, which reserves and unreserves aflags before every app instr:
res = drreg_reserve_aflags(drcontext, bb, inst);
CHECK(res == DRREG_SUCCESS, "reserve of aflags should work");
res = drreg_unreserve_aflags(drcontext, bb, inst);
CHECK(res == DRREG_SUCCESS, "unreserve of aflags");
This messes up drreg-test.c (in an interesting way):
$ bin64/drrun -c suite/tests/bin/libclient.drreg-test.dll.so -- suite/tests/bin/client.drreg-test
<Starting application /work/dr/git/build_x64_dbg_tests/suite/tests/bin/client.drreg-test (11121)>
FATAL: kernel too old
<Stopping application /work/dr/git/build_x64_dbg_tests/suite/tests/bin/client.drreg-test (11121)>
To solve this there is a better, non-destructive method for restoring the flags, to use a cmp
instead of an add
:
cmp 0x81, %al
sahf