[x86] drreg: aflags not preserved on fault if xax dead
On x86, the aflags restore logic seems broken if xax is dead and doesn't need to be spilled.
The current condition for detecting aflags_in_xax
needs xax to be spilled prior to the lahf
.
https://github.com/DynamoRIO/dynamorio/blob/e8fc651f485f858127bf2394defc382d5cdff641/ext/drreg/drreg.c#L1912
PR #4932 demonstrates the issue. drreg-test fails:
196: drreg-test running
196: ERROR: spilled flags value was not preserved in test #17!
196: drreg-test finished
Before:
TAG 0x00007fe0ffe9bd67
+0 L3 @0x00007fdebffeefc8 48 c7 c2 17 f1 00 00 mov $0x000000000000f117 -> %rdx
+7 L3 @0x00007fdebffe1348 48 c7 c2 17 f1 00 00 mov $0x000000000000f117 -> %rdx
+14 L3 @0x00007fdebff71ec0 b4 d7 mov $0xd7 -> %ah
+16 L3 @0x00007fdebffdc928 9e sahf %ah
+17 L3 @0x00007fdebff77a90 90 nop
+18 L3 @0x00007fdebff71120 48 c7 c1 00 00 00 00 mov $0x0000000000000000 -> %rcx
+25 L3 @0x00007fdebffdd1b0 48 8b 09 mov (%rcx)[8byte] -> %rcx
+28 L3 @0x00007fdebff74b10 48 c7 c0 34 12 00 00 mov $0x0000000000001234 -> %rax // rax dead
+35 L3 @0x00007fdebffde9c0 eb 00 jmp $0x00007fe0ffe9bd8c
END 0x00007fe0ffe9bd67
After:
TAG 0x00007fe0ffe9bd67
+0 L3 @0x00007fdebffeefc8 48 c7 c2 17 f1 00 00 mov $0x000000000000f117 -> %rdx
+7 L3 @0x00007fdebffe1348 48 c7 c2 17 f1 00 00 mov $0x000000000000f117 -> %rdx
+14 m4 @0x00007fdebff77178 <label>
+14 L3 @0x00007fdebff71ec0 b4 d7 mov $0xd7 -> %ah
+16 L3 @0x00007fdebffdc928 9e sahf %ah
+17 m4 @0x00007fdebffdd7b8 9f lahf -> %ah // aflags spill
+18 m4 @0x00007fdebffea2d0 0f 90 c0 seto -> %al
+21 m4 @0x00007fdebffdcfb0 48 3b c1 cmp %rax %rcx // overwrite aflags
+24 L3 @0x00007fdebff77a90 90 nop
+25 L3 @0x00007fdebff71120 48 c7 c1 00 00 00 00 mov $0x0000000000000000 -> %rcx
+32 L3 @0x00007fdebffdd1b0 48 8b 09 mov (%rcx)[8byte] -> %rcx // fault
+35 m4 @0x00007fdebffde940 65 48 a3 e0 00 00 00 mov %rax -> %gs:0x000000e0[8byte]
00 00 00 00
+46 m4 @0x00007fdebffdcec8 <label>
+46 L3 @0x00007fdebff74b10 48 c7 c0 34 12 00 00 mov $0x0000000000001234 -> %rax // rax dead so no need to spill xax to slot
+53 m4 @0x00007fdebff763f0 65 48 a3 e8 00 00 00 mov %rax -> %gs:0x000000e8[8byte]
00 00 00 00
+64 m4 @0x00007fdebff76af8 <label>
+64 m4 @0x00007fdebff77a10 65 48 a1 e0 00 00 00 mov %gs:0x000000e0[8byte] -> %rax
00 00 00 00
+75 m4 @0x00007fdebff53e40 3c 81 cmp %al $0x81
+77 m4 @0x00007fdebff50a50 9e sahf %ah
+78 m4 @0x00007fdebfff1480 65 48 a1 e8 00 00 00 mov %gs:0x000000e8[8byte] -> %rax
00 00 00 00
+89 m4 @0x00007fdebffefea8 <label>
+89 L3 @0x00007fdebffde9c0 eb 00 jmp $0x00007fe0ffe9bd8c
END 0x00007fe0ffe9bd67
As expected, if I remove the mov $0x0000000000001234 -> %rax
app instr that's causing rax to be dead, drreg-test passes. This is because then xax is spilled to a slot prior to the lahf.
TAG 0x00007f96f3e6fd67
+0 L3 @0x00007f94b3fb29c0 48 c7 c2 17 f1 00 00 mov $0x000000000000f117 -> %rdx
+7 L3 @0x00007f94b3f45120 48 c7 c2 17 f1 00 00 mov $0x000000000000f117 -> %rdx
+14 m4 @0x00007f94b3fb17b8 <label>
+14 L3 @0x00007f94b3fb11b0 b4 d7 mov $0xd7 -> %ah
+16 L3 @0x00007f94b3f48b10 9e sahf %ah
+17 m4 @0x00007f94b3fb0ec8 65 48 a3 e8 00 00 00 mov %rax -> %gs:0x000000e8[8byte] // xax spilled to slot as it's not dead
00 00 00 00
+28 m4 @0x00007f94b3f4a3f0 <label>
+28 m4 @0x00007f94b3f4aaf8 9f lahf -> %ah
+29 m4 @0x00007f94b3f24a50 0f 90 c0 seto -> %al
+32 m4 @0x00007f94b3f4ba10 48 3b c1 cmp %rax %rcx
+35 L3 @0x00007f94b3f4b178 90 nop
+36 L3 @0x00007f94b3fbe2d0 48 c7 c1 00 00 00 00 mov $0x0000000000000000 -> %rcx
+43 L3 @0x00007f94b3fb0fb0 48 8b 09 mov (%rcx)[8byte] -> %rcx
+46 m4 @0x00007f94b3f27e40 3c 81 cmp %al $0x81
+48 m4 @0x00007f94b3fc2fc8 9e sahf %ah
+49 m4 @0x00007f94b3fc5480 65 48 a1 e8 00 00 00 mov %gs:0x000000e8[8byte] -> %rax
00 00 00 00
+60 m4 @0x00007f94b3fc3ea8 <label>
+60 L3 @0x00007f94b3fb2940 eb 00 jmp $0x00007f96f3e6fd85
END 0x00007f96f3e6fd67