Reputation: 1550
While developping a bare metal firmware in C for a RV32IM target (RISC-V), I encountered a linking error when LTO is enabled:
/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'
There are however no call to memset
in my firmware. The memset
is inserted by GCC during optimization as described here. The build is optimized for size using GCC -Os
and -flto -fuse-linker-plugin
flags. In addition, the -fno-builtin-memset -nostdinc -fno-tree-loop-distribute-patterns -nostdlib -ffreestanding
flags are used to prevent the use of memset
during optimization and to not include standard libs.
How to prevent memset
insertion during LTO? Note that the firmware should not be linked against libc. I also tried providing a custom implementation of memset
but the linker does not want to use it for memset
inserted during optimization (still throws undefined reference).
Upvotes: 4
Views: 3306
Reputation: 46
I hit similar issue servers years ago and tried to fixed that, but it turns out I misunderstanding the meaning of -fno-builtin
[1], -fno-builtin
not guaranteed GCC won't call memcpy
, memmove
or memset
implicitly.
I guess the simplest solution is, DO NOT compile your libc.c
with -flto
, or in another word, compile libc.c
with -fno-lto
.
That's my guess about what happen, I don't have know how to reproduce what you see, so it might incorrect,
So you might have question about why compile libc.c
with -fno-lto
will work? because if it didn't involved into LTO flow, which means it won't be discarded in the LTO flow.
Some sample program to show the gcc will call memset even you compile with -fno-builtin, aarch64 gcc and riscv gcc will generate a function call to 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;
}
Here is the corresponding gcc source code[2] for this case.
[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
Upvotes: 3
Reputation: 51832
I'm not sure -fno-builtin-*
does what you think it does. If you use those flags, then GCC will try to call an external function. If you don't use those flags, GCC will instead just insert inline code instead of relying on the library.
So it would appear to me you should simply not use any -fno-builtin
flags.
Upvotes: 1