GCC x86_64 asm中的寄存器分配冲突。生命周期被忽略

问题描述 投票:0回答:1

我有一个包含一个小的汇编块的函数。由GCC编译的该函数的汇编不正确,因为它将同一寄存器分配给两个不同的变量。这是函数源:

void *ptr;
uint64_t foo(uint64_t arg1) {
  register uint64_t tmp;
  asm ("lea TARGET(%%rip), %[tmp];"
       "shl  $4, %[arg1];"
       "sub  %[arg1], %[tmp];"
       "movq %[tmp], %[ptr];"
      : [ptr] "+m" (ptr), [tmp] "=r" (tmp)
      : [arg1] "r" (arg1)
      :);

  asm ("TARGET:;");
}

因为我写入全局ptr,所以对它使用约束“ + m”,它应该在内存中。因为tmp的约束仅被写入,所以它为“ = r”。输入arg1的约束仅是“ r”。这可能很重要。

汇编块的SSA伪代码为:

tmp_0 = something
arg1_1 = arg1_0 << 4
tmp_1 = tmp_0 - arg_1
*ptr_0 = tmp_1

优化O0时此函数的编译程序集是

00000000000005fa <foo>:
 5fa:   55                      push   %rbp
 5fb:   48 89 e5                mov    %rsp,%rbp
 5fe:   48 89 7d f8             mov    %rdi,-0x8(%rbp)       # Storing arg1 to stack (optimization level O0)
 602:   48 8b 45 f8             mov    -0x8(%rbp),%rax       # arg1_0 is assigned register rax
 606:   48 8d 05 0e 00 00 00    lea    0xe(%rip),%rax        # 61b <TARGET>, tmp_0 is ALSO assigned rax
 60d:   48 c1 e0 04             shl    $0x4,%rax             # arg1_0 is used, its lifetime ends
 611:   48 29 c0                sub    %rax,%rax             # subtracting two vars both assigned the same register
 614:   48 89 05 fd 09 20 00    mov    %rax,0x2009fd(%rip)   # 201018 <ptr>, store to global

000000000000061b <TARGET>:
 61b:   90                      nop
 61c:   5d                      pop    %rbp
 61d:   c3                      retq 

[检查程序集,我们看到在地址0x602中,寄存器rax被分配给SSA寄存器arg1_0,该寄存器的寿命一直到指令0x60d。同时,地址0x606 ALSO的指令还将寄存器rax分配给SSA寄存器tmp_0。似乎在其生存期内,物理寄存器已分配给另一个SSA寄存器。

系统信息:

  • x86_64 CPU
  • gcc版本7.4.0
  • Ubuntu 18.04.3

我的问题:

  • GCC为什么要创建这样的程序集输出?
  • 我对程序集输入和输出的约束是否正确?如果没有,为什么?
  • 这是GCC错误吗?
c gcc assembly inline-assembly
1个回答
3
投票

首先,感谢@Jester的完美回答,回答了这个问题。引用:

manual说:“在不能与输入重叠的所有输出操作数上使用'&'约束修饰符(请参见修饰符)。否则,GCC可以将输出操作数与不相关的输入操作数分配在同一寄存器中。汇编代码在产生输出之前先消耗其输入的假设。如果汇编代码实际上由多个指令组成,则此假设可能为假。

简而言之,我的内联程序集不同意gcc的假设,即在写入输出之前先消耗输入。实际上,gcc提供了适当的约束修饰符(&)来表达这一点。

解决方法:

-       : [ptr] "+m" (ptr), [tmp] "=r" (tmp)
+       : [ptr] "+m" (ptr), [tmp] "=&r" (tmp)

固定组件输出:

00000000000005fa <foo>:
 5fa:   55                      push   %rbp
 5fb:   48 89 e5                mov    %rsp,%rbp
 5fe:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
 602:   48 8b 45 f8             mov    -0x8(%rbp),%rax
 606:   48 8d 15 0e 00 00 00    lea    0xe(%rip),%rdx        # 61b <TARGET>
 60d:   48 c1 e0 04             shl    $0x4,%rax
 611:   48 29 c2                sub    %rax,%rdx
 614:   48 89 15 fd 09 20 00    mov    %rdx,0x2009fd(%rip)        # 201018 <ptr>

000000000000061b <TARGET>:
 61b:   90                      nop
 61c:   5d                      pop    %rbp
 61d:   c3                      retq   
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.