Search code examples
c++assemblyx86inline-assemblyosdev

RDTSCP and Instruction order


I'm using the rdtscp instruction to read the ecx register for detecting cpu and numa node ids (I'm developing an os).

The code looks like the following

inline static long get(unsigned char *node_id = 0, unsigned char *cpu_id = 0)
{
    unsigned int p;
    __asm__ __volatile__("rdtscp\n" : "=c" (p) : : "memory");

    if (node_id) {
        *node_id = p >> 12;
    }

    if (cpu_id) {
        *cpu_id = p & 0xfff;
    }

    return 0;
}

On using this function, I have a not understandable behaviour: The CPU tells me a lot of exceptions (page fault, general protection fault, ...). That indicates to me, that the cpu or node id is not read, but if I log the id, all seems right and no exception appears.

So in code:

// ...
unsigned char cpu, numa;
get(&numa, &cpu);
// use cpu and numa id creates exception

but

// ...
unsigned char cpu, numa;
get(&numa, &cpu);
print(cpu); // <--- this makes cpu reading ok?
// use cpu and numa id is ok

Is the cpu reordering my instructions, so that he will use cpu_id/numa_id before reading it?


Solution

  • Tell the compiler that the registers eax and edx are clobbered. Add them to the clobbered list:

    __asm__ __volatile__("rdtscp\n" : "=c" (p) : : "memory", "eax", "edx");