内联AT&T asm语法直接使用操作码而不是助记符

问题描述 投票:1回答:2

出于不幸的原因,我无法进入,我必须支持一个没有我需要的助记符映射的古代汇编程序。

我知道硬件支持它,但我似乎无法在线找到任何关于如何使用操作码而不是助记符的文档。

有没有人有关于如何在GCC上使用内联AT&T语法进行操作的参考。

gcc assembly x86 inline-assembly
2个回答
2
投票

幸运的是rdrand只接受一个参数,这是一个寄存器。因此,如果要允许编译器自由选择,您只需要涵盖几种情况。小心,它仍然很难看:)

inline int rdrand()
{
    int result;
    __asm__ __volatile__ (
        ".byte 0x0f, 0xc7\n\t"
        ".ifc %0, %%eax\n\t"
        ".byte 0xf0\n\t"
        ".else\n\t"
        ".ifc %0, %%ebx\n\t"
        ".byte 0xf3\n\t"
        ".else\n\t"
        ".ifc %0, %%ecx\n\t"
        ".byte 0xf1\n\t"
        ".else\n\t"
        ".ifc %0, %%edx\n\t"
        ".byte 0xf2\n\t"
        ".else\n\t"
        ".ifc %0, %%esi\n\t"
        ".byte 0xf6\n\t"
        ".else\n\t"
        ".ifc %0, %%edi\n\t"
        ".byte 0xf7\n\t"
        ".else\n\t"
        ".ifc %0, %%ebp\n\t"
        ".byte 0xf5\n\t"
        ".else\n\t"
        ".error \"uknown register\"\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
        ".endif\n\t"
    : "=R" (result) : : "cc");

    // "=R" excludes r8d..r15d in 64-bit mode
    return result;
}

对于64位操作数大小,您需要一个REX.W(0x48)前缀,但the "=R" constraint而不是"=r"将避免在REX前缀中设置任何其他位。

请注意,rdrand还使用进位标志,其处理作为读者的练习。 gcc6可以使用标志输出操作数,这比setcc更有效。


4
投票

试试这个:

long result;
char success = 0; /* make sure we don't get surprised by setc only writing 8 bits */

/* "rdrand %%rax ; setc %b1" */
asm volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %b1" : "=a"(result), "=qm"(success) :: "cc");

a约束强制编译器将rax寄存器用于result。这是一般的,因为它没有令人讨厌。我建议你添加一个configure测试来检查汇编程序是否理解rdrand并使用以下代码:

long result;
char success = 0;

#ifdef HAVE_RDRAND
asm volatile ("rdrand %0; setc %b1" : "=r"(result), "=qm"(success) :: "cc");
#else
asm volatile (".byte 0x48, 0x0f, 0xc7, 0xf0; setc %b1" : "=a"(result), "=qm"(success) :: "cc");
#endif

虽然如果汇编程序不理解rax,强制编译器使用rdrand寄存器可能会有很小的性能损失,但它远远超过了允许使用任何寄存器所需的复杂kludges。

© www.soinside.com 2019 - 2024. All rights reserved.