我有这个密码
   
    
     memcpy
    
   
   作为标准C库实现的一部分,它从
   
    src
   
   到
   
    dest
   
   一次一个字节:
  
  void *memcpy(void *restrict dest, const void *restrict src, size_t len)
{
    char *dp = (char *restrict)dest;
    const char *sp = (const char *restrict)src;
    while( len-- )
    {
        *dp++ = *sp++;
    }
    return dest;
}
  
   用
   
    gcc -O2
   
   ,生成的代码是合理的:
  
  memcpy:
.LFB0:
        movq    %rdi, %rax
        testq   %rdx, %rdx
        je      .L2
        xorl    %ecx, %ecx
.L3:
        movzbl  (%rsi,%rcx), %r8d
        movb    %r8b, (%rax,%rcx)
        addq    $1, %rcx
        cmpq    %rdx, %rcx
        jne     .L3
.L2:
        ret
.LFE0:
  
   但是,在
   
    gcc -O3
   
   ,gcc优化这个简单的逐字节复制到
   
    曼皮西
   
   呼叫:
  
  memcpy:
.LFB0:
        testq   %rdx, %rdx
        je      .L7
        subq    $8, %rsp
        call    memcpy
        addq    $8, %rsp
        ret
.L7:
        movq    %rdi, %rax
        ret
.LFE0:
  
   由于明显的原因,这是次优的,并且会导致一个segfault。
  
  
   以下是复制segfault的示例(编译时使用
   
    gcc -O3 -fno-builtin-memcpy test.c memcpy.c
   
   )
   
    test.c
   
   :
  
  #include <string.h>
#include <stdio.h>
int main(void)
{
        int c, a[] = {1, 2, 3, 4}, b[4];
        memcpy(b, a, sizeof(b));
        for( c = 0; c < sizeof(b)/sizeof(b[0]); c++ )
                printf("%d\n", b[c]);
        return 0;
}
  
   我试过传球
   
    -fno-builtin-memcpy
   
   和
   
    -fno-loop-optimizations
   
   同样的事情也发生了。
  
  
   我使用的是GCC 8.3.0版:
  
  Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-cros-linux-gnu/8.3.0/lto-wrapper
Target: x86_64-cros-linux-gnu
Configured with: ../configure --prefix=/usr/local --libdir=/usr/local/lib64 --build=x86_64-cros-linux-gnu --host=x86_64-cros-linux-gnu --target=x86_64-cros-linux-gnu --enable-checking=release --disable-multilib --enable-threads=posix --disable-bootstrap --disable-werror --disable-libmpx --enable-static --enable-shared --program-suffix=-8.3.0 --with-arch-64=x86-64
Thread model: posix
gcc version 8.3.0 (GCC) 
  
   如何禁用导致副本转换为
   
    曼皮西
   
   调用(最好在编译时使用
   
    -O3
   
   ?