问题引入
最近在使用某个版本的交叉编译工具链gcc时发现一个问题,示例如下:
首先创建一个lto.c文件,内容如下:
int issue_func(int a0, int a1)
{
return a0+a1;
}
创建main.c
extern int issue_func(int a0, int a1);
int main()
{
return issue_func(5,6);
}
然后按照如下方式编译代码
riscv-nuclei-elf-gcc -flto -o lto.o -c lto.c
riscv-nuclei-elf-gcc -flto -o main.o -c main.c
riscv-nuclei-elf-ar rc liblto.a lto.o
riscv-nuclei-elf-gcc -flto -fuse-linker-plugin main.o -L. -llto -u issue_func -o main.elf
此时就会发现,ar时报警告,最后链接报错
/gcc/bin/riscv-nuclei-elf-ar: lto.o: plugin needed to handle lto object
/gcc/bin/../lib/gcc/riscv-nuclei-elf/9.2.0/../../../../riscv-nuclei-elf/bin/ld: /tmp/main.elf.uPsr4n.ltrans0.ltrans.o: in function `main':
<artificial>:(.text+0xc): undefined reference to `issue_func'
collect2: error: ld returned 1 exit status
问题就是这样,即使用flto选项生成的lib文件会在链接时提示找不到库内的函数,但是曾经在以前的版本gcc时没有这个问题,那么究竟是怎么回事(⊙o⊙)?
资料查找
仔细对比就会发现,在生成的lib文件中存在的符号表不正确,而.o文件则是正确的,那么ar的打包警告就很可疑,警告一番查找在gcc文档中对-flto系列的选项有如下说明:
-fno-fat-lto-objects improves compilation time over plain LTO, but requires the complete toolchain to be aware of LTO. It requires a linker with linker plugin support for basic functionality. Additionally, nm, ar and ranlib need to support linker plugins to allow a full-featured build environment (capable of building static libraries etc). GCC provides the gcc-ar, gcc-nm, gcc-ranlib wrappers to pass the right options to these tools. With non fat LTO makefiles need to be modified to use them.
Note that modern binutils provide plugin auto-load mechanism. Installing the linker plugin into $libdir/bfd-plugins has the same effect as usage of the command wrappers (gcc-ar, gcc-nm and gcc-ranlib).
The default is -fno-fat-lto-objects on targets with linker plugin support.
(原文链接:https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html)
gcc在使用ar处理lto的文件时是需要使用gcc-ar来代替ar的,但为什么有些编译器仍使用ar也可以正确生成lib,那是因为在工具链的$libdir/bfd-plugins路径下包含liblto_plugin.so(liblto_plugin.dll)的动态库来提供给ar,使用插件功能,而有些编译器并没有从libexec路径内拷贝该动态库到$libdir/bfd-plugins路径下。
问题解决
确认了原因,那么解决起来就很容易了,从/gcc/libexec/gcc/riscv-nuclei-elf/9.2.0/liblto_plugin.so拷贝到/gcc/lib/bfd-plugins路径下,再次编译,顺利编译成功,没有任何报错误。