使用 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 (将#修改为@)

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...