我有这个密码
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
?