不幸的是,我不能进入的原因,我必须支持一个古老的汇编程序,没有一个Map的助记符,我需要。我知道硬件支持它,但我似乎找不到任何文档在线如何使用操作码而不是助记符。有没有人有一个参考如何在GCC上内联AT&T语法。
enyaitl31#
试试这个:
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寄存器。这是一般的,因为它得到没有令人讨厌。我建议你添加一个configure测试来检查汇编器是否理解rdrand,并使用以下代码:
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寄存器可能会有很小的性能损失,但允许使用任何寄存器所需的复杂组件远远超过了这一点。
gk7wooem2#
幸运的是,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位操作数大小,您将需要一个雷克斯.W(0x48)前缀,但the "=R" constraint而不是"=r"将避免在REX前缀中设置任何其他位。请注意,rdrand也使用进位标志,其处理留给读者作为练习。gcc6可以使用标志输出操作数,这比setcc更有效。
"=R"
"=r"
setcc
1aaf6o9v3#
从binutils 2.41开始,新的directive .insn允许生成任意指令。虽然这可能对您和您的旧汇编程序没有特别的帮助,但它可能对将来遇到这个问题的读者有用。以rdrand为例,它可以是这样的:
.insn
#define rdrand(x) asm (".insn 0x0fc7/6, %0" : "=r"(x))
字符串.insn指令根据给定的操作数自动计算出要使用的编码和指令大小,因此我们可以对所有操作数大小使用如上所述的宏,即使存在内存操作数(尽管对于rdrand来说,这些当然是不允许的)。比如说,
long long example(void) { char foo; short bar; int baz; long long quux; rdrand(foo); rdrand(bar); rdrand(baz); rdrand(quux); return (foo + bar + baz + quux); }
型成为
0000000000000000 <example>: 0: 0f c7 f0 rdrand %eax 3: 66 0f c7 f2 rdrand %dx 7: 0f be c0 movsbl %al,%eax a: 0f bf d2 movswl %dx,%edx d: 01 d0 add %edx,%eax f: 0f c7 f6 rdrand %esi 12: 01 f0 add %esi,%eax 14: 48 98 cltq 16: 48 0f c7 f1 rdrand %rcx 1a: 48 01 c8 add %rcx,%rax 1d: c3 ret
型您可以看到.insn无法区分8位和32位操作数,因为x86指令编码使用单独的操作码而不是前缀来实现8位指令。这可能导致无效结果。如果需要,可以添加Assert以避免这种情况:
#define rdrand(x) do { \ _Static_assert(sizeof (x) > sizeof (char)); \ asm (".insn 0x0fc7/6, %0" : "=r"(x)); \ } while (0)
型
3条答案
按热度按时间enyaitl31#
试试这个:
字符串
a
约束强制编译器为result
使用rax
寄存器。这是一般的,因为它得到没有令人讨厌。我建议你添加一个configure测试来检查汇编器是否理解rdrand
,并使用以下代码:型
如果汇编器不理解
rdrand
,强制编译器使用rax
寄存器可能会有很小的性能损失,但允许使用任何寄存器所需的复杂组件远远超过了这一点。gk7wooem2#
幸运的是,
rdrand
只接受一个参数,这是一个寄存器。因此,如果你想让编译器自由选择,你只需要覆盖几种情况。注意,它仍然很丑:)字符串
对于64位操作数大小,您将需要一个雷克斯.W(0x48)前缀,但the
"=R"
constraint而不是"=r"
将避免在REX前缀中设置任何其他位。请注意,
rdrand
也使用进位标志,其处理留给读者作为练习。gcc6可以使用标志输出操作数,这比setcc
更有效。1aaf6o9v3#
从binutils 2.41开始,新的directive
.insn
允许生成任意指令。虽然这可能对您和您的旧汇编程序没有特别的帮助,但它可能对将来遇到这个问题的读者有用。以rdrand
为例,它可以是这样的:字符串
.insn
指令根据给定的操作数自动计算出要使用的编码和指令大小,因此我们可以对所有操作数大小使用如上所述的宏,即使存在内存操作数(尽管对于rdrand
来说,这些当然是不允许的)。比如说,型
成为
型
您可以看到
.insn
无法区分8位和32位操作数,因为x86指令编码使用单独的操作码而不是前缀来实现8位指令。这可能导致无效结果。如果需要,可以添加Assert以避免这种情况:型