如何解决使用 clang 编译内联汇编时分配的寄存器冲突
考虑以下示例程序(针对 Linux/x86-64):
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
unsigned arg1 = strtoul(argv[1],NULL,0);
unsigned arg2 = strtoul(argv[2],0);
asm(
"mov %[arg1],%%ecx\n\t"
"add %[arg2],%[arg1]\n\t"
"add %[arg2],%%ecx\n\t"
"xchg %%ecx,%[arg2]"
: [arg1] "+&abdSD" (arg1),[arg2] "+&abdSD" (arg2)
:
: "cc","ecx");
printf("%u %u\n",arg1,arg2);
}
(xchg
仅用于在列表中轻松搜索已编译的指令。)
使用 GCC,它按预期工作 - 将不同的寄存器分配给 arg1 和 arg2,例如:
11bf: e8 cc fe ff ff callq 1090 <strtoul@plt>
11c4: 89 da mov %ebx,%edx
11c6: 89 d1 mov %edx,%ecx
11c8: 01 c2 add %eax,%edx
11ca: 01 c1 add %eax,%ecx
11cc: 91 xchg %eax,%ecx
(所以,edx 中的 arg1,eax 中的 arg2)
但是,使用 Clang 编译(在 6.0 和 10.0 上得到确认)会为 arg1 和 arg2 分配相同的寄存器:
401174: e8 d7 fe ff ff callq 401050 <strtoul@plt>
401179: 44 89 f0 mov %r14d,%eax ; <--
40117c: 89 c1 mov %eax,%ecx
40117e: 01 c0 add %eax,%eax ; <-- so,arg1 and arg2 both in eax
401180: 01 c1 add %eax,%ecx
401182: 91 xchg %eax,%ecx
问题仍然存在于多个变体中,例如:约束字符串中的 +
而不是 +&
;像 %0
这样的数字形式来寻址操作数;用另一个罕见的指令替换 xchg
;等等。
我一直期待,从基本原理来看,编译器分配输出位置的逻辑总是会为不同的输出操作数分配不同的位置,无论为它们定义什么约束;并且在输入操作数集之间也是如此。 (像“+”、“&”这样的修饰符为布局逻辑添加了更多规则,但不能破坏主要原则。)
有没有我忽略的一些琐碎的方面?
UPD:reported 到 LLVM。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。