Have you ever seen code like this?
mov ecx, 1
push rcx
What is going on here? It appears that the code is pushing a 64-bit value and the upper 32-bits are uninitialized. No further clues arise from scouring through the instruction set reference for MOV in Volume 2B of the Intel® 64 and IA-32 Architectures Software Developer’s Manual, where it says, "Both operands must be the same size, which can be a byte, a word, a doubleword, or a quadword." (page 3-641).
Is this a compiler bug? Well, I posed that question to the Microsoft Visual C++ gurus a while back and they pointed me to another part of the devref, this time section 3.4.1.1 of Volume 1, where it says:
When in 64-bit mode, operand size determines the number of valid bits in the destination general-purpose register:
- 64-bit operands generate a 64-bit result in the destination general-purpose register.
- 32-bit operands generate a 32-bit result, zero-extended to a 64-bit result in the destination general-purpose register.
- 8-bit and 16-bit operands generate an 8-bit or 16-bit result. The upper 56 bits or 48 bits (respectively) of the destination general-purpose register are not be modified by the operation. If the result of an 8-bit or 16-bit operation is intended for 64-bit address calculation, explicitly sign-extend the register to the full 64-bits.
Notice that in 64-bit mode, when the destination is a 32-bit general-purpose register, the upper 32-bits of the same register are zeroed!
Well, I didn't quite believe it, so I went to my handy American Arium and set up a test case. First, I initialized RCX to a known value. Then I stepped over an instruction which reloaded RCX with another value. Then I stepped over an instruction that just did a MOV ECX. See the pictures below.
Sure enough! The upper 32-bits are zeroed and a mystery is solved.



Comments