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?
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).
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.