让GCC编译而不插入对memcpy的调用

时间:2011-06-20 11:43:40

标签: gcc compiler-construction memcpy libc

我目前正在使用GCC 4.5.3,为PowerPC 440编译,并且正在编译一些不需要libc的代码。我没有直接调用memcpy(),但编译器似乎在构建期间插入了一个。

有像-nostdlib,-nostartfiles,-nodefaultlibs这样的链接器选项但我无法使用它们,因为我没有进行链接阶段。我只是在编译。有这样的事情:

$ powerpc-440-eabi-gcc -O2 -g -c -o output.o input.c

如果我用nm检查output.o,我会看到对memcpy的引用:

$ powerpc-440-eabi-nm output.o | grep memcpy
     U memcpy
$ 

GCC手册页明确了如何使用链接器删除对memcpy和其他libc调用的调用,但我不希望编译器首先插入它们,因为我使用的是完全不同的链接器(不是GNU的ld,它不知道libc)。

感谢您提供的任何帮助。

5 个答案:

答案 0 :(得分:6)

您需要使用-fno-builtin禁用该优化。尝试编译C库的memcpy时,我遇到过这个问题。它自称。糟糕!

答案 1 :(得分:5)

在某些情况下,Gcc会发出对memcpy的调用,例如,如果要复制结构。 无法更改GCC行为,但您可以尝试通过修改代码来避免此类复制。最好的办法是查看程序集,找出为什么gcc发出memcpy并尝试解决它。这会很烦人,因为你基本上需要了解gcc是如何工作的。

摘自http://gcc.gnu.org/onlinedocs/gcc/Standards.html

GCC使用的大多数编译器支持例程都存在于libgcc中,但也有一些例外。 GCC要求独立环境提供memcpy,memmove,memset和memcmp。最后,如果使用了__builtin_trap,并且目标没有实现陷阱模式,那么GCC将发出中止调用。

答案 2 :(得分:3)

您还可以将二进制文件设为“独立”二进制文件:

  

ISO C标准(在第4节中)定义了两类符合要求的实现。符合标准的托管实现支持整个标准[...];只有提供某些图书馆设施才需要符合标准的独立实施:在,,,和;从AMD1开始,也是那些;在C99中,也是在和。 [...]。

     

该标准还为程序定义了两个环境,一个独立的环境,所有实现都需要,并且可能没有超出独立实现所需的库设施,其中程序启动和终止的处理是实现定义的,并且是托管的环境,这是不需要的,其中提供了所有库设施,并通过函数int main(void)或int main(int,char * [])启动。

     

操作系统内核将是一个独立的环境;使用操作系统功能的程序通常位于托管实现中。

(我添加的段落)

更多here。并且可以找到相应的gcc选项/ s(关键字-freestanding-fno-builtin){。{3}}。

答案 3 :(得分:3)

不需要-fno-builtins-ffreestanding,因为它们会不必要地禁用许多重要的优化

这实际上是由gcc的tree-loop-distribute-patterns“优化”的,所以要在保留有用的内置功能的同时禁用不需要的行为,你可以使用:

<强> -fno-tree-loop-distribute-patterns

Musl-libc使用此标志进行构建,并在其配置脚本中有以下注释(我查看了源代码并找不到任何宏,因此应该就足够了)

  

#检查防止编译器可能需要的选项   #生成memcpy,memmove,memcmp,
的自引用版本   #和memset。真的,我们应该添加一个检查来确定是否这个   #选项就足够了,如果没有,添加一个宏来削弱这些   #function with volatile ...
  #tryflag CFLAGS_MEMOPS -fno-tree-loop-distribute-patterns

您还可以使用其optimize属性将此属性作为属性添加到gcc中的各个函数,以便其他函数可以从调用mem*()

中受益

答案 4 :(得分:1)

这是一个很老的问题,但我遇到了同样的问题,这里的解决方案都没有奏效。

所以我定义了这个函数:

static __attribute__((always_inline)) inline void* imemcpy (void *dest, const void *src, size_t len) {
  char *d = dest;
  const char *s = src;
  while (len--)
    *d++ = *s++;
  return dest;
}

然后用它代替memcpy。这已经永久解决了我的内联问题。但是,如果您正在编译某种库,则不是很有用。