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

inline AT&T asm syntax for using opcode directly instead of mnemonic

由于不幸的原因我无法进入,我必须支持一个古老的汇编器,它没有我需要的助记符的映射。

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

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

幸运的是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 也使用进位标志,其处理留作 reader 的练习。 gcc6可以使用flag输出操作数,比setcc.

效率更高

试试这个:

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 约束强制编译器对 result 使用 rax 寄存器。这是一般的,但并不令人讨厌。我建议你添加一个配置测试来检查汇编程序是否理解 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

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