【问题标题】:How to prevent GCC from inserting memset during link-time optimization?如何防止 GCC 在链接时优化期间插入 memset?
【发布时间】:2020-11-02 15:20:23
【问题描述】:

在使用 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'

但是在我的固件中没有调用memsetmemset 由 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(仍然抛出未定义引用)。

【问题讨论】:

    标签: gcc linker compiler-optimization lto freestanding


    【解决方案1】:

    几年前我遇到了类似的问题服务器并试图修复它,但事实证明我误解了-fno-builtin[1]、-fno-builtin 的含义不保证 GCC 不会调用 memcpymemmovememset 隐含。

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

    这是我对发生的事情的猜测,我不知道如何重现您所看到的,所以它可能不正确,

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

    所以你可能会问为什么用-fno-lto 编译libc.c 会起作用?因为如果它没有参与到 LTO 流程中,这意味着它不会在 LTO 流程中被丢弃。

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

    // $ riscv64-unknown-elf-gcc x.c -o - -O3  -S -fno-builtin
    struct bar {
        int a[100];
    };
    
    struct bar y;
    
    void foo(){
      struct bar x = {{0}};
      y = x;
    }
    

    这里是本案例对应的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

    【讨论】:

      【解决方案2】:

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

      所以在我看来,您根本不应该使用任何 -fno-builtin 标志。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-07-10
        • 2021-11-23
        • 2011-01-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-03
        • 1970-01-01
        相关资源
        最近更新 更多