Search code examples
assemblyx86fpux87mmx

MMX Instructions and the x87 FPU Tag Word


section .data
    qVar1: dq 1


section .bss
    var28: resb  28


section .text
    _main:

        ; Use an MMX instruction

            movq mm0, [qVar1] ; Move quadword from r/m64 to mm.

        ; Read Tag Word

            fstenv [var28]
            mov    ax, [var28 + 8] ; move the Tag Word to ax

At this moment ax is 0101 0101 0101 0110

But from Intel manual, section 9.5.1 MMX Instructions and the x87 FPU Tag Word, I quote:

After each MMX instruction, the entire x87 FPU tag word is set to valid (00B).

So why ax is not all zeros?


Solution

  • The section you quoted goes on saying:

    Chapter 12, “Intel® MMX™ Technology System Programming,” in the Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A, provides additional information about the effects of x87 FPU and MMX instructions on the x87 FPU tag word.

    In fact section 12.2 of the third manual clarifies:

    When an MMX instruction writes a value into an MMX register, at the same time, bits 64 through 79 of the corresponding floating-point register are set to all 1s.

    The instruction movq mm0, [qVar1] then set the register R0 to 0xffff_00000000_00000000 that is an invalid double extended precision floating point value starting from the 80387 (previously was a positive infinity).
    This will be important later.

    The fstenv instruction doesn't save the actual tag word, instead it interprets the registers and the actual tag word to compute the tag word that will be stored in memory.
    The tag word register is then reset to empty for all registers.

    The effect of fstenv on the x87 FPU tag word is:

    Tags and register values are read and interpreted; then all tags are set to 11B.

    and the image of the x87 FPU tag word stored in memory is:

    Tags are set according to the actual values in the floating-point registers; that is, empty registers are marked 11B and valid registers are marked 00B (nonzero), 01B (zero), or 10B (special).

    Effects of the MMX and x87 instructions on the x87 FPU tag word

    If you used emms before any XMM code the tags will all be 11b (Empty).
    As soon as movq mm0, [qVar1] is executed all tags are set to 00b (Valid).
    When fstenv is executed, the registers are tagged as not empty and their content is analyzed: all the registers R1-R7 appears to be zero while R0, as previously seen, contains a special value and its tag in the image stored in memory is thus 10b (special).

    The entry for fstenv in the second manual is admittedly deceiving with its pseudo-code written down as

    Operation
    DEST[FPUControlWord] ← FPUControlWord;
    DEST[FPUStatusWord] ← FPUStatusWord;
    DEST[FPUTagWord] ← FPUTagWord;
    DEST[FPUDataPointer] ← FPUDataPointer;
    DEST[FPUInstructionPointer] ← FPUInstructionPointer;
    DEST[FPULastInstructionOpcode] ← FPULastInstructionOpcode;

    which is simply not true.