That seems... problematic. Do compilers know this and just ignore the flags if/when they use these instructions?
Weird things I learned while writing an x86 emulator
11–20 of 75 posts
Re: Weird things I learned while writing an x86 emulator
#12> Other instructions leave some of the flags in an undefined state, although in some cases they are conditionally undefined. > I’ve heard that the Atom line of CPUs used a cheaper/slower way of doing bit shifts in the ALU, which results in the undefined flags having different values, although I haven’t tested this myself. That seems... problematic. Do compilers know this and just ignore the flags if/when they use the…
(This is a common feature of ISAs, and makes sense in terms of component reuse: it allows you to cheaply reuse the ALU, for example, without needing extra wires/control signals telling it not to update the flag state.)
Re: Weird things I learned while writing an x86 emulator
#13Neither does DEC, and I believe the original reason for this was multiple-precision arithmetic routines --- you need to propagate the carry flag, but also update loop counters and pointers.
It seems that the actual behavior of the undefined flags is related to the internal implementation of the shift operation, and is different between different architectures.
According to https://www.sandpile.org/x86/flags.htm which unfortunately hasn't been updated nor is exhaustive, all of the P6 family behave the same, but different from the P5 and the P4, and probably the earlier generations too. "Undefined" values are often used by anti-debugging/anti-emulation/VM detection code to determine if the CPU is real hardware or not, so it's actually quite important to emulate them correctly.
Re: Weird things I learned while writing an x86 emulator
#14This is a good list! Another fun quirk: because x86 is a register-memory architecture and allows all kinds of variants of reg/mem operand encodings, there are a handful of equivalent encodings with exactly the same lengths (and just slightly different ModR/M bytes). You can take advantage of this to do software fingerprinting or, in my case, steganography without changing an executable’s size or semantics[1]. [1]: ht…
Re: Weird things I learned while writing an x86 emulator
#15> You can add quite a few until you get to 15 bytes. This length is a hard limit on current x86-compatible CPUs. Any instruction longer than 15 bytes is considered invalid and will generate an exception. There's a few valid 16 byte instructions though.. Sandpile lists a few examples: https://www.sandpile.org/x86/opc_enc.htm 36 67 8F EA 78 10 84 24 disp32 imm32 = bextr eax,[ss:esp*1+disp32],imm32 64 67 8F EA F8 10 84…
The longest structurally valid x86 instruction is 26 bytes, from some research I did a few years ago[1]. But as others have noted, structurally valid does not mean that any x86 CPU will accept them: they’ll all produce #UD or similar, including these 16 byte ones. [1]: https://yossarian.net/res/pub/mishegos-langsec-2021.pdf
Re: Weird things I learned while writing an x86 emulator
#16Earlier quoted context omitted.
The longest structurally valid x86 instruction is 26 bytes, from some research I did a few years ago[1]. But as others have noted, structurally valid does not mean that any x86 CPU will accept them: they’ll all produce #UD or similar, including these 16 byte ones. [1]: https://yossarian.net/res/pub/mishegos-langsec-2021.pdf
What is it? I can't seem to find it in the paper.
(There may be even longer valid productions; my analysis was pretty naive. But 26 is already substantially longer than the limit!)
Re: Weird things I learned while writing an x86 emulator
#17> Other instructions leave some of the flags in an undefined state, although in some cases they are conditionally undefined. > I’ve heard that the Atom line of CPUs used a cheaper/slower way of doing bit shifts in the ALU, which results in the undefined flags having different values, although I haven’t tested this myself. That seems... problematic. Do compilers know this and just ignore the flags if/when they use the…
Yes. In general, compilers only test emit flag testing instructions after instructions that are explicitly defined as having flag-modifying semantics. (This is a common feature of ISAs, and makes sense in terms of component reuse: it allows you to cheaply reuse the ALU, for example, without needing extra wires/control signals telling it not to update the flag state.)
I think compiler writers sometimes also have to know that instructions do not modify the flags.
Such instructions can be inserted between flag-setting ones and the test of that flag.
Re: Weird things I learned while writing an x86 emulator
#18Earlier quoted context omitted.
Yes. In general, compilers only test emit flag testing instructions after instructions that are explicitly defined as having flag-modifying semantics. (This is a common feature of ISAs, and makes sense in terms of component reuse: it allows you to cheaply reuse the ALU, for example, without needing extra wires/control signals telling it not to update the flag state.)
> compilers only emit flag testing instructions after instructions that are explicitly defined as having flag-modifying semantics. I think compiler writers sometimes also have to know that instructions do not modify the flags. Such instructions can be inserted between flag-setting ones and the test of that flag.
Re: Weird things I learned while writing an x86 emulator
#19An ADD instruction will update the carry flag but the INC instruction does not! Neither does DEC, and I believe the original reason for this was multiple-precision arithmetic routines --- you need to propagate the carry flag, but also update loop counters and pointers. It seems that the actual behavior of the undefined flags is related to the internal implementation of the shift operation, and is different between di…
Re: Weird things I learned while writing an x86 emulator
#20An ADD instruction will update the carry flag but the INC instruction does not! Neither does DEC, and I believe the original reason for this was multiple-precision arithmetic routines --- you need to propagate the carry flag, but also update loop counters and pointers. It seems that the actual behavior of the undefined flags is related to the internal implementation of the shift operation, and is different between di…