NB: I normally dabble with disassembly (i.e. mnemonics) and only ever look at the raw opcodes when I can't avoid it.
I have the following line of disassembly of a Windows x64 kernel mode driver, created by IDA Pro 7.1.180227:
xor edx, edx
Now I know for a fact that this is in preparation of passing the second parameter to a function via rdx
. I also know that the intention of that code is to set said pointer argument to NULL
.
The opcode is 33 D2
. And cross-referencing that with the reference or looking at it in ODA yields the same as with IDA: xor edx, edx
.
Now what itches me wrong with this disassembly is that rdx
, as a superset of edx
, is used elsewhere on that exact code path to store other pointers. So in theory the upper double-word of rdx
could be "dirty".
And going by the fact that this is x64 code, I'd expect this to read xor rdx, rdx
. Why is that not how it's presented in the disassembly?
Now I understand that, as per section 3.6.1 (Table 3-4) of the Intel SDM (05/2018) the REX.W Prefix of the opcode can affect the operand size.
For this opcode neither the operand-size (66h) nor the address-size (67h) prefix are present.
So going by the Intel SDM (section "XOR—Logical Exclusive OR") I should indeed be dealing with opcode 33 /r
or instruction XOR r32, r/m32
, confirming IDAs translation of the opcode. Referring to section 2.1.5 ("Addressing-Mode Encoding of ModR/M and SIB Bytes") of the Intel SDM gives us a clue as to how the operand (D2
) is encoded and so gives us, from Table 2-2 ("32-Bit Addressing Forms with the ModR/M Byte"): EDX/DX/DL/MM2/XMM2
as operand.
Figures.
However, that would mean that the "dirty" upper double-word in rdx
would not be zeroed out and thus a garbled/truncated pointer would end up being passed. Given this is kernel mode code, the consequences should be clear.
I just can't believe that the compiler would make such mistake. So what am I missing?
xor r10d, r10d
is not shorter thanxor r10,r10
, but Silvermont only recognizes 32-bit operand size as a zeroing idiom!)