微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何防止GCC在链接时优化期间插入memset?

如何解决如何防止GCC在链接时优化期间插入memset?

在用C为RV32IM目标(RISC-V)开发裸机固件时,启用LTO时遇到链接错误

/home/duranda/riscv/lib/gcc/riscv64-unkNown-elf/10.2.0/../../../../riscv64-unkNown-elf/bin/ld: /tmp/firmware.elf.5cZNyC.ltrans0.ltrans.o: in function `.L0 ':
/home/duranda/whatever/firmware.c:493: undefined reference to `memset'

但是,我的固件中没有调用memset的电话。 memset是由GCC在优化期间as described here插入的。使用GCC -Os-flto -fuse-linker-plugin标志针对大小优化了构建。此外,-fno-builtin-memset -nostdinc -fno-tree-loop-distribute-patterns -nostdlib -ffreestanding标志用于防止在优化过程中使用memset,并且不包括标准库。

如何防止LTO期间插入memset?请注意,不应将固件与libc链接。我还尝试提供memset自定义实现,但链接器不希望将其用于优化过程中插入的memset(仍然抛出 undefined reference )。

解决方法

我不确定-fno-builtin-*是否按照您的想法做。如果使用这些标志,则GCC会尝试调用外部函数。如果您不使用这些标志,那么GCC只会插入内联代码,而不是依赖库。

在我看来,您不应使用任何-fno-builtin标志。

,

几年前,我遇到了类似问题的服务器,并试图解决该问题,但事实证明我误解了-fno-builtin [1]的含义,-fno-builtin不能保证GCC不会致电{{1} },memcpymemmove隐含。

我想最简单的解决方法是,不要用memset编译libc.c,或者换句话说,不要用-flto编译libc.c

这是我对发生的事情的猜测,我不知道如何重现您看到的内容,因此可能不正确,

  • 在LTO的第一阶段,LTO将收集您在程序中使用的任何符号
  • 然后要求链接器提供这些文件,并丢弃所有未使用的符号。
  • 然后将这些文件读入GCC并再次进行优化,这时gcc使用一些内置函数来优化或编码gen,但之前没有引入。
  • 符号引用是在LTO阶段创建的,在当前GCC LTO流程中拉入任何符号都为时过晚,在这种情况下,memset在较早的阶段就被丢弃了...

因此,您可能对为什么使用-fno-lto编译libc.c会产生疑问?因为如果它不参与LTO流程,则意味着它不会在LTO流程中丢弃。

一些示例程序显示即使您使用-fno-builtin进行编译,gcc也会调用memset,aarch64 gcc和riscv gcc会生成对memset的函数调用。

-fno-lto

这是这种情况下的相应gcc源代码[2]。

[1] https://gcc.gnu.org/pipermail/gcc-patches/2014-August/397382.html

[2] https://github.com/riscv/riscv-gcc/blob/riscv-gcc-10.2.0/gcc/expr.c#L3143

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。