我目前正在使用 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)。
感谢您提供的任何帮助。
无需
-fno-builtins
或-ffreestanding
,因为它们会不必要地禁用许多重要的优化
这实际上是由 gcc 的树循环分布模式“优化”的,因此要在保留有用的内置功能的同时禁用不需要的行为,您可以使用:
-fno-tree-loop-distribute-patterns
Musl-libc 使用此标志进行构建,并在其配置脚本中具有以下注释(我查看了源代码,没有找到任何宏,所以这应该足够了)
# 检查可能需要阻止编译器的选项
# 生成 memcpy,, memmove, memcmp,
的自引用版本 # 和内存集。真的,我们应该添加一个检查来确定这是否
# 选项就足够了,如果没有,添加一个宏来削弱这些
# 具有易失性的函数...
# tryflag CFLAGS_MEMOPS -fno-tree-loop-distribute-patterns
您还可以使用其优化属性将其作为属性添加到 gcc 中的各个函数中,以便其他函数可以从调用中受益
mem*()
__attribute__((optimize("no-tree-loop-distribute-patterns")))
size_t strlen(const char *s){ //without attribute, gcc compiles to jmp strlen
size_t i = -1ull;
do { ++i; } while (s[i]);
return i;
}
或者,(至少现在)您可以在循环中添加一个令人困惑的 null asm 语句来阻止模式识别。
size_t strlen(const char *s){
size_t i = -1ull;
do {
++i;
asm("");
} while (s[i]) ;
return i;
}
Gcc 在某些情况下会发出对 memcpy 的调用,例如,如果您正在复制结构。 无法更改 GCC 行为,但您可以尝试通过修改代码来避免这种复制。最好的办法是查看程序集,找出 gcc 发出 memcpy 的原因并尝试解决它。但这会很烦人,因为你基本上需要了解 gcc 的工作原理。
摘自http://gcc.gnu.org/onlinedocs/gcc/Standards.html:
GCC 使用的大多数编译器支持例程都存在于 libgcc 中,但也有一些例外。 GCC 要求独立环境提供 memcpy、memmove、memset 和 memcmp。最后,如果使用 __builtin_trap,并且目标未实现陷阱模式,则 GCC 将发出中止调用。
您需要使用
-fno-builtin
禁用该优化。我在尝试为 C 库编译 memcpy
时遇到过这个问题。它自称。哎呀!
您还可以使您的二进制文件成为“独立”的:
ISO C 标准(在第 4 条中)定义了两类一致性实现。合格的托管实施支持整个标准[...];仅需要一个符合要求的独立实现来提供某些图书馆设施: 、 、 和 中的设施;自 AMD1 以来,也包括 ;在 C99 中,还有 和 中的那些。 [...].
该标准还定义了两种程序环境,一个是所有实现所需的独立环境,除了独立实现所需的库设施之外,可能没有库设施,其中程序启动和终止的处理是实现定义的,另一个是托管环境,这不是必需的,其中提供了所有库设施,并且通过函数 int main (void) 或 int main (int, char *[]) 启动。
操作系统内核将是一个独立的环境;使用操作系统设施的程序通常是在托管实现中。
(我添加的段落)
更多这里。相应的 gcc 选项(关键字
-ffreestanding
或 -fno-builtin
)可以在 here 找到。
这是一个相当老的问题,但我遇到了同样的问题,并且这里的解决方案都不起作用。
所以我定义了这个函数:
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。这已经永久解决了我的内联问题。如果您正在编译某种库,则不是很有用。