Pregunta

I have a struct:

typedef struct {
    unsigned int EAX;
    unsigned int EBX;
    unsigned int ECX;
    unsigned int EDX;
} CPUIDinfo;

And that struct is used in a function:

void get_cpuid_info(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc)
{
    __asm__ __volatile__ (
        "push %%rax       ;\n"
        "push %%rcx       ;\n"
        "mov %0, %%eax    ;\n"
        "mov %1, %%ecx    ;\n"
        "cpuid            ;\n"
        "mov %%eax, %2    ;\n"
        "mov %%ebx, %3    ;\n"
        "mov %%ecx, %4    ;\n"
        "mov %%edx, %5    ;\n"
        "pop %%rcx        ;\n"
        "pop %%rax        ;\n"

        : "=m"(info->EAX), "=m"(info->EBX), "=m"(info->ECX), "=m"(info->EDX)
        : "m"(func), "m"(subfunc)
        : "%eax", "%ebx", "%ecx", "%edx"
    );
}

The assembler is matching the reads correctly (%0 and %1), but its not matching the writes correctly. When writing, its using {%0, %1, %2, %3} rather than {%2, %3, %4, %5}. That means info->EAX gets assigned func, info->EBX gets assigned subfunc, info->ECX gets what should have been placed in info->EAX, etc.

From the Extended ASM manual, I know the assembler has name constraints:

"mov %[func],    %%eax    ;\n"
"mov %[subfunc], %%ecx    ;\n"

But I receive an error when I try to use them:

error: undefined named operand 'func'
error: undefined named operand 'subfunc'

I also tried to tell the assembler what to use where:

    : [2]"=m"(info->EAX), [3]"=m"(info->EBX), [4]"=m"(info->ECX), [5]"=m"(info->EDX)
    : [0]"m"(func), [1]"m"(subfunc)
    : "%eax", "%ebx", "%ecx", "%edx"

But that results in more errors like:

error: expected identifier before numeric constant
error: expected ']' before numeric constant
error: expected string-literal before numeric constant

How can I match my operands so the writes (e.g., mov %%eax, %2) perform as expected?

¿Fue útil?

Solución

Using the proper register constraints, your function could look something like this:

void get_cpuid_info(CPUIDinfo *info, const unsigned int func, const unsigned int subfunc)
{
    __asm__ __volatile__ (
        "cpuid"
        : "=a"(info->EAX), "=b"(info->EBX), "=c"(info->ECX), "=d"(info->EDX)
        : "a"(func), "c"(subfunc)
    );
}

But to address your particular problem: the name you want to use should be specified in the constraint. That is instead of [0]"m"(func), [1]"m"(subfunc) you should have written: [func] "m" (func), [subfunc] "m" (subfunc) and similarly for the output constraints. The point of this whole business is to get rid of numbers. You should put the symbolic name inside the square brackets, and the value in the round brackets.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top