为什么有必要在此内联汇编中使用edi约束?

时间:2015-05-19 08:05:03

标签: gcc constraints inline-assembly

centos 6.5 64bit vps,500MB ram gcc 4.8.2

我有以下函数只有在我使用edi作为约束来保存字符串指针时才有效。如果我尝试使用任何其他寄存器或约束gq等,则会出现段错误。

但只有在链接时间优化和o3一起使用时才会出现此问题。如果o2它没问题。如果我不使用-flto,那很好。但是我们可以使用的唯一一个不会崩溃的寄存器是edi

gcc -flto
CFLAGS=-I. -flto -std=gnu11 -msse4.2 -fno-builtin-printf -Wall -Winline -Wstrict-aliasing -g -pg -O3 -lrt -lpthread

似乎可能会出现某种类型的注册破坏或其他事情。我真的不知道为什么以及如何解决这个问题。另一个有趣的方面是生成的程序集在使用指针之前将rdi放入rdx但是如果我尝试使用任何一个寄存器作为输入约束......那就是段错误!如果它在积极的编译选项下失败,它会向我建议编译器以某种方式填充,或者更可能是我做错了。

char *sse4_strCRLF(char *str)
  {
  __m128i M = _mm_set1_epi8(13);
  char *res;
  __asm__ __volatile__(
     "xor %0,%0\n\t"
     "sub $1, %1\n\t"
"1:" "sub $15,%1\n\t"
    ".align 16\n\t"
"2:" "add $16, %1\n\t"
     "pcmpistri  $0x08,(%1),%2\n\t"
     "ja 2b\n\t"
     "jnc 2f\n\t"

     "cmpb $10,1(%1,%%rcx)\n\t"
     "jne 1b\n\t"
     "add %%rcx,%1\n\t"
     "mov %1,%0\n\t"
"2:"
     :"=q"(res)
     :"edi"(str),"x"(M)  //<-- if use anything except edi, it segfaults
     :"rcx"
     );
return (char*) res;
}

反汇编输出:

00000000000002e0 <sse4_strCRLF>:
2e0:   55                      push   rbp
2e1:   48 89 e5                mov    rbp,rsp
2e4:   e8 00 00 00 00          call   2e9 <sse4_strCRLF+0x9>
2e9:   66 0f 6f 05 00 00 00 00 movdqa xmm0,[rip+0x0]          # 2f1 <sse4_strCRLF+0x11>
2f1:   48 89 fa                mov    rdx,rdi   //<--- puts rdi into rdx!
2f4:   48 31 c0                xor    rax,rax
2f7:   48 83 ea 01             sub    rdx,0x1
2fb:   48 83 ea 0f             sub    rdx,0xf
2ff:   90                      nop
300:   48 83 c2 10             add    rdx,0x10
304:   66 0f 3a 63 02 08       pcmpistri xmm0,[rdx],0x8
30a:   77 f4                   ja     300 <sse4_strCRLF+0x20>
30c:   73 0d                   jae    31b <sse4_strCRLF+0x3b>
30e:   80 7c 0a 01 0a          cmp    byte[rdx+rcx*1+0x1],0xa
313:   75 e6                   jne    2fb <sse4_strCRLF+0x1b>
315:   48 01 ca                add    rdx,rcx
318:   48 89 d0                mov    rax,rdx
31b:   5d                      pop    rbp
31c:   c3                      ret

1 个答案:

答案 0 :(得分:1)

@David Wohlferd给了我答案。由于无知和假设,我正在犯两个愚蠢的错误。修改下面的代码,使得例程不修改输入变量char指针。它被复制到寄存器中并使用该寄存器。另外,我错误地认为我可以直接指定特定的寄存器而不是a b等。

对于我使用的约束,gcc似乎仍然很挑剔。例如如果我分别对ab使用resstr,则会在运行时编译精细但段错误。但是使用SD似乎工作正常。

@David Wohlferd,我想把你称为回答者,但我不认为我可以这样做来发表评论。

char *sse4_strCRLF(char *str)
   {
   __m128i M = _mm_set1_epi8(13);
   char *res;
   __asm__ __volatile__(
     "xor %0,%0\n\t"
     "mov %1,%%rdx\n\t"
     "sub $1,%%rdx\n\t"
"1:" "sub $15,%%rdx\n\t"
     ".align 16\n\t"
"2:" "add $16, %%rdx\n\t"
     "pcmpistri  $0x08,(%%rdx),%2\n\t"
     "ja 2b\n\t"
     "jnc 2f\n\t"

     "cmpb $10,1(%%rdx,%%rcx)\n\t"
     "jne 1b\n\t"
     "add %%rcx,%%rdx\n\t"
     "mov %%rdx,%0\n\t"
"2:"
     :"=S"(res)
     :"D"(str),"x"(M)
     :"rcx","rdx"
     );
  return (char*) res;
}