I've been using the following code in assembly language to read performance-monitoring counters using the RDPMC instruction:
rdpmc_reference_cycles proc
mov ecx, 1h
shl ecx, 30
add ecx, 2
xor eax, eax
xor edx, edx
rdpmc
ret
rdpmc_reference_cycles endp
This works fine for a 32-bit environment, but now I'm transitioning to a 64-bit system and I'm having trouble adapting the code. After the rdpmc
instruction, the 32-bit value in eax contains the lower half of the result, and the 32-bit value in edx contains the upper half.
I need to combine these two 32-bit values to produce a 64-bit result. However, I'm not sure how to achieve this in MASM. I've tried a few approaches, but they didn't work as expected. Could anyone guide me on how to modify this code so that it produces a 64-bit result?
The RDPMC instruction only depends on the ECX register for an input (in the 64-bit environment the high dword of RCX is ignored). And the result is returned in EDX:EAX with the high dwords of RAX and RDX reset to zero.
Your code
mov ecx, 1h shl ecx, 30 add ecx, 2 xor eax, eax xor edx, edx rdpmc
is convoluted because
mov ecx, 40000002h
(equivalent to mov ecx, (1<<30) + 2
).So to read the counter and deliver the 64-bit result in the single RAX register, you can do:
mov ecx, (1<<30) + 2
rdpmc ; -> EDX:EAX
shl rdx, 32
or rax, rdx
The shl rdx, 32
shifts the contents of EDX into the high dword of RDX.
The or rax, rdx
combines both dwords in RAX.
It is important to note that this or
could only work well because the shl
made the low dword of RDX zero, and because the rdpmc
made the high dword of RAX zero.