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

时间:2018-09-05 17:02:15

标签: gcc assembly x86 inline-assembly

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

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

有人在GCC上以嵌入式AT&T语法进行操作的参考吗?

2 个答案:

答案 0 :(得分: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寄存器。这是不令人讨厌的一般情况。我建议您添加一个配置测试,以检查汇编器是否理解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寄存器可能会导致微小的性能损失,但要允许任何寄存器执行以下操作会产生复杂的麻烦,这远远超出了预期的范围。被使用。

答案 1 :(得分: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前缀中设置任何其他位。 / p>

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