我试图编写一些适用于16,32,64,128位英特尔机器的内联汇编(将来某个时候有128位)。想法是使用通用寄存器名称,以便编译器或汇编器在i866(AX
),{{1}上的8086(-m16
?),EAX
上选择-m32
}在x86_64(RAX
)上,等等。
我认为我可以使用-m64
,a
或ax
的{{1}}注册来实现此目的。 eax
,rax
或b
的{{1}};等等。但是,我在调用" generic" bx
在代码中注册:
ebx
编译器抱怨:
rbx
如果我从clobber列表中删除a
(以便它以unsigned char* ptr = ...;
size_t size = ...;
__asm__ __volatile__
(
"xor %a, %a"
"lea ptr, %b\n"
"lea size, %c\n"
"1:\n"
"movb 0, %b(%a)\n"
"inc %a\n"
"loop 1b\n"
: /* no outputs */
: "b" (ptr), "c" (size)
: "a", "b", "c", "cc"
);
开头),那么我得到:
error: unknown register name 'a' in asm
: "a", "b", "c", "cc"
我还尝试在clobber列表中将其指定为"a"
,但我收到了相同的错误消息。
根据GCC手册中的Machine Constraints,"b"
是error: unknown register name 'b' in asm
: "b", "c", "cc"
。所以我很确定我的名字是正确的。但是,我也非常确定我做错了什么,或者我不太了解事物的全貌。
问题:我如何一般性地指定英特尔注册名称,以便内联汇编"正常工作"当那一天到来时,"%a"
或a
(甚至是a register
)?
OS X是10.8.5,x64,完全打补丁。汇编程序是:
-m32
相关:在上面的代码中,我使用-m64
来支持单步机字大小。例如,我以这种方式编写它,因此生成的代码是-m128
(32位)或$ /usr/bin/as -v
Apple Inc version cctools-855, GNU assembler version 1.38
(64位)。我不确定它是否是推荐的方法(或者它是否有效,因为我无法运行它)。请更正。
答案 0 :(得分:3)
您似乎无法检查代码中是否(size == 0)
,因此我将遵循该断言。如果任何输出参数被更新而不是随后使用,则__volatile__
是必要的 - 编译器不知道存储器ptr[size]
已经归零,并且看不到副作用,它将会只是省略了asm块。
我们使用'临时'参数,所以我们可以更新值,然后丢弃它们。编译器知道临时参数已被修改,并且看到它们从未再次使用过,不需要维护这些寄存器。我建议像:
{
size_t tmp_size = size;
__asm__ __volatile__ (
"%=:\n\t" /* generate a unique label. */
"sub $1, %0\n\t"
"movb $0, %1(%0)\n\t" /* 0 -> ptr[size - 1] .. ptr[0] */
"jnz %=b\n\t" /* jump 'back' */
: "+r" (tmp_size) : "r" (ptr) : "memory", "cc");
}
这也让编译器选择寄存器,这是更好的选择。我不认为这会给你共同的64位,32位(或16位)代码。您可能希望查看operand modifiers。否则,您可能需要' q'和' l'分别为64位和32位版本的指令后缀。
BTW,sub/jnz
在现代处理器上通常比inc/dec
(部分标志失速危险)和loop
(复杂微码'东西')更好。
答案 1 :(得分:1)
我尽了最大努力,但不能比这更接近。
#include <stddef.h>
void f(unsigned char* ptr, size_t size) {
__asm__ __volatile__
(
"xor %%eax, %%eax\n\t"
"lea ptr, %0\n\t"
"lea size, %1\n\t"
"1:\n\t"
"movb 0, %0\n\t"
"inc %%eax\n\t"
"loop 1\n\t"
: /* no outputs */
: "b" (ptr), "c" (size)
: "0", "1", "%eax", "cc"
);
}
它与你的不同,但显示正确的路径:很明显,"a"
不能在clobber列表中使用,为什么呢。所以我这样做了。
使用gcc -S x.c -o-
编译此模块会向我显示
... [ start of function, irrelevant here ]
#APP
# 5 "x.c" 1
xor %eax, %eax
lea ptr, %ebx
lea size, %ecx
1:
movb 0, %ebx
inc %eax
loop 1
# 0 "" 2
#NO_APP
... [ end of function, irrelevant here ]
我希望尽管有所帮助。
让我们再试一次:
#include <stddef.h>
#include <stdint.h>
void f(unsigned char* ptr, size_t size) {
uint32_t junk;
size_t countdown;
__asm__ __volatile__
(
"xor %0, %0\n\t"
"lea ptr, %2\n\t"
"lea size, %3\n\t"
"1:\n\t"
"movb 0, %2(%0)\n\t"
"inc %0\n\t"
"dec %1\n\t"
"loopnz 1\n\t"
: "=a" (junk) /* junk output */, "=c" (countdown)
: "b" (ptr), "c" (size)
: "cc", "memory"
);
}
(顺便说一句,我在某处添加了dec %1
和loopnz
...
答案 2 :(得分:1)
你不能。 使用特定于体系结构的预定义和复制粘贴。甚至更好地使用编译器内在函数或单独的asm文件。
其他一些有用的信息
苹果这样预定义的宏对我有用_11P64__它在x86_64架构上设置 所以你的代码看起来像:
#ifdef __LP64__
void myfunctionfor64bitArch()
#else
void myfunctionfor32bitArch()
#endif
使用__x86_64__也应该更正确,但我没有尝试。
想想你为什么要这么多跨平台汇编程序?您的代码可能不大:ABI有所不同,请参阅http://en.wikipedia.org/wiki/X86_calling_conventions#List_of_x86_calling_conventions,因此您的代码不能以通用形式存在,汇编程序太不同
在clang Visual-Studio样式汇编程序的最新版本中工作。恕我直言,它更方便。试试
__asm
{
mov eax, your_variable ; Get first argument
}
有趣的是它适用于x64,而在原版工作室它只适用于32位