Re: numatop: %{optflags} fail the 32bit build

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 09/12/2013 02:11 PM, Dridi Boukelmoune wrote:

This version should work in 32 bit mode, and only in 32 bit mode:

void
cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
       unsigned int *edx)
{
   __asm volatile
     ("push %%ebx\n\t"
      "cpuid\n\t"
      "mov %%ebx, (%1)\n\t"
      "pop %%ebx"
      : "=a" (*eax),
        "=S" (ebx),
        "=c" (*ecx),
        "=d" (*edx)
      : "0" (*eax));
}

I "kind of" understand what you're doing here, but it's not all clear.

I get the push/pop instructions save and restore the reserved ebx
register, which is needed because apparently the cpuid instruction
would otherwise overwrite it.

I don't understand the mov instruction, but I suppose you're storing
ebx's value from cpuid "somewhere else" before restoring it with the
pop instruction.

Correct, the intent is to write the %ebx register value to the address in the %esi register. "(%1)" is a pointer dereference, as oppose to plain %1.

I don't understand the last 5 lines of __asm in both functions, I've
never seen this syntax before.

These are register constraints. "a", "c", "d", "S" refer to the %eax, %ecx, %edx, %esi registers, respectively. "=" marks output constraints. The constraints before the final ":" are output registers, and after colon, there are the input registers. There's just one, and "0" means to reuse the first output register.

Okay, silly me, I should have listed "S" among the output registers, instead the inputs:

void
cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
      unsigned int *edx)
{
  __asm volatile
    ("push %%ebx\n\t"
     "cpuid\n\t"
     "mov %%ebx, (%4)\n\t"
     "pop %%ebx"
     : "=a" (*eax),
       "=c" (*ecx),
       "=d" (*edx)
     : "0" (*eax),
       "S" (ebx));
}

I also forget that for full correctness, there should now be a "memory" clobber as well (in the clobber section after yet another colon):

void
cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx,
      unsigned int *edx)
{
  __asm volatile
    ("push %%ebx\n\t"
     "cpuid\n\t"
     "mov %%ebx, (%4)\n\t"
     "pop %%ebx"
     : "=a" (*eax),
       "=c" (*ecx),
       "=d" (*edx)
     : "0" (*eax),
       "S" (ebx)
     : "memory");
}

By the way, we could generate much better code if the registers were passed as an array or struct, so that they are in consecutive memory:

struct regs {
  unsigned eax, ebx, ecx, edx;
};

void
cpuid(struct regs *r)
{
  __asm volatile
    ("push %%ebx\n\t"
     "cpuid\n\t"
     "mov %%eax, (%0)\n\t"
     "mov %%ebx, 4(%0)\n\t"
     "mov %%ecx, 8(%0)\n\t"
     "mov %%edx, 12(%0)\n\t"
     "pop %%ebx"
     :
     : "S" (r)
     : "eax", "ecx", "edx", "memory");
}

Obviously, this needs adjustments to the callers.

--
Florian Weimer / Red Hat Product Security Team
--
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxxx
https://admin.fedoraproject.org/mailman/listinfo/devel
Fedora Code of Conduct: http://fedoraproject.org/code-of-conduct





[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Fedora Announce]     [Fedora Kernel]     [Fedora Testing]     [Fedora Formulas]     [Fedora PHP Devel]     [Kernel Development]     [Fedora Legacy]     [Fedora Maintainers]     [Fedora Desktop]     [PAM]     [Red Hat Development]     [Gimp]     [Yosemite News]
  Powered by Linux