获得更多 GPR 的 x86 汇编技巧

x86 assembly tricks to get more GPRs

我写了一个汇编程序,它在 x86-64 上需要 5 个 GPR,运行良好。但我正在尝试将其移植到 32 位 x86。编译器抱怨无法使用 5 个探地雷达。

x86-64 的代码如下:

  __asm__("mov %0,%%r8\n\t"
          "mov %1,%%r10\n\t"
          "lfence\n\t"
          "rdtsc\n\t"
          "mov %%eax,%%edi\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "mov (%%r8), %%r8\n\t"
          "lfence\n\t"
          "rdtsc\n\t"
          "sub %%edi, %%eax\n\t"
          "mov %%eax, (%%r10)\n\t"
          :
          :"r"(head),"r"(time_buf)
          :"eax","edx","edi","r8","r10"
          );

我该如何克服这个问题?

处理器:Intel® Core™2 双核处理器 T9400

你实际上不需要 5 个寄存器,你只需要 4 个。寄存器 EAX 和 EDX 被 RDTSC 指令破坏了,所以是两个。您需要另一个寄存器来保存第一条 RDTSC 指令的 EAX 值。那是三个。第四个寄存器是 head 指针。您正在使用的其他寄存器不需要,没有必要在 asm 语句中计算或存储经过的时间。你可以用普通的 C/C++ 代码做到这一点。

我会将您的 asm 语句重写为如下内容:

unsigned
foo(void *head) {
    unsigned time_start, time_end;

    __asm__("lfence\n\t"
        "rdtsc\n\t"
        "mov %%eax, %0\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "mov (%1), %1\n\t"
        "lfence\n\t"
        "rdtsc"
        : "=r" (time_start), "+r" (head), "=a" (time_end)
        :
        : "edx"
        );
    return time_end - time_start;
}

此 asm 语句让编译器尽可能选择寄存器。 EAX 和 EDX 的使用由 RDTSC 指令固定,但用于保存 time_start 时间戳和 head 指针的寄存器留给编译器选择。

除了少使用一个寄存器外,我的示例 asm 语句还具有无需修改即可在 32 位和 64 位中工作的优势。