I am trying to use the following inline assembly in C to read the high word (%edx
) of Time Stamp Counter for time measurement:
unsigned int tsc;
asm volatile ("rdtscp; xchgl %%edx, %%eax" : "=r" (tsc));
Unfortunately, the code crashes. If the xchgl
instruction is removed, or use rdtsc
instruction, there is no problem. For the former, although the code does not crash, I have no way to take out what I want -- the value in %edx
register. I have checked an online document about inline assembly in C but failed to find any clue to return the value in %edx
to the output C variable directly without any additional instructions (if I change xchgl
to movl
, the same crash occurs). With little hope that I missed any syntax or did not understand the document correctly, I come here to ask: is there any way to specify %edx
register to be the output instead of conventional %eax
in inline assembly in C? Thank you.
PS1: I am working in Linux on an intel i386 compatible CPU whose TSC works well to me.
PS2: For some reason I just need the value in %edx
.
You need to specify the register as a constraint to tell the compiler that it has to pick a specific register.
unsigned int tsc;
asm volatile ("rdtsc" : "=d" (tsc) : : "eax");
"d" is the edx register as the output operand. "a" is the eax register in the clobber list because its content is altered by the instruction. There are two colons in between because there are no input operands.
Your "=r" lets the compiler pick any register; it only happens to pick EAX in a debug build in a function that doesn't inline. You also need to tell the compiler about all other registers that are modified, even if you don't want them as outputs; the compiler assumes all registers and memory are unmodified and unread unless you tell it otherwise. https://stackoverflow.com/tags/inline-assembly/info
Normally you'd use intrinsics instead of inline asm for portability and to avoid messing with asm:
How to get the CPU cycle count in x86_64 from C++?
But if you did want safe inline asm to get both halves, on both 32 bit and 64 bit:
unsigned int tsc_hi, tsc_lo;
asm volatile ("rdtsc" : "=a" (tsc_lo), "=d" (tsc_hi));
Alternatively, you can use 'A' constraint for the value in the edx:eax register-pair on a 32 bit machine. But in a 64-bit built, "A" lets the compiler pick either RDX or RAX for the 64-bit integer; it would only be both with an unsigned __int128
.
// Beware: breaks silently if compiled as 64-bit code
unsigned long long tsc;
asm volatile ("rdtsc" : "=A" (tsc));