静态库中的LTO和替代stdlib函数

问题描述

我有一个嵌入式平台,它在静态库中引入了自己的stdlib函数,例如mallocprintf。我需要使用LTO编译该库。不幸的是,在这种组合中(-flto + -nostdlib +与来自.a的stdlib替换链接),链接程序找不到函数

我准备了可以在大多数Unix机器上运行的MWE,但是由于它包含多个文件,因此我将其放入存储库中: https://github.com/stefanct/lto_static_libs

包含的makefile允许打开和关闭某些功能以进行测试:

  • nostdlib=y:将-nostdlib添加链接阶段
  • nolto=y:禁用LTO
  • libfunc=y:启用对库中非标准函数调用(您将在末尾看到原因!)

要点是要有一个包含标准功能的模块,例如:

int puts(const char *s) {
  return 2;
}

使用-flto将其编译为目标文件,使用gcc-ar将其放入静态库中,并最终在与应用程序链接时使用它。

在我的设置中(从源代码构建的GCC 11分支和从Debian Buster构建的GNU ld 2.31.1),我得到以下结果:

未设置任何选项:确定-库中的printf被标准函数覆盖(?):

$ make -B 
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects     -c -o libtest.o libtest.c
lto-dump -list libtest.o
Type   Visibility  Size  Name
function  default     4  lib_func  
function  default     4  puts  
function  default     4  printf  

gcc-nm libtest.o
00000000 T lib_func
00000000 T printf
00000000 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects     -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects   -o exe main.o -L. -ltest 

$ ./exe 
hurga

没有stdlib,也没有LTO:好-链接可以正常工作(ish-运行segfaults,但是我猜这是可以预期的,可以与-nodefaultlibs一起解决,但是我不在乎)

$ make -B nostdlib=y nolto=y
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter     -c -o libtest.o libtest.c
gcc-nm libtest.o
0000000000000074 T lib_func
0000000000000000 T printf
0000000000000065 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter     -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter   -o exe main.o -L. -ltest -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000

没有stdlib,但启用了LTO:突然找不到看跌期权。 但是,正如您所看到的,放入库中的目标文件包含的功能就很好(甚至gcc-mn libtest.a显示了同样的功能)。 我想解决这种情况。为什么会这样?

$ make -B nostdlib=y 
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects     -c -o libtest.o libtest.c
lto-dump -list libtest.o
Type   Visibility  Size  Name
function  default     4  lib_func  
function  default     4  puts  
function  default     4  printf  

gcc-nm libtest.o
00000000 T lib_func
00000000 T printf
00000000 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects     -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects   -o exe main.o -L. -ltest -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000
/usr/bin/ld: /tmp/cczvyrrg.ltrans0.ltrans.o: in function `main':
<artificial>:(.text+0xe): undefined reference to `puts'
collect2: error: ld returned 1 exit status
make: *** [makefile:39: exe] Error 1

有趣的是,如果我们在同一库中调用一个不相关(非标准)的函数,事情又会开始起作用!?

$ make -B nostdlib=y libfunc=y
Using GCC 11.0.0
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects  -D LIB_FUNC   -c -o libtest.o libtest.c
lto-dump -list libtest.o
Type   Visibility  Size  Name
function  default     4  lib_func  
function  default     4  puts  
function  default     4  printf  

gcc-nm libtest.o
00000000 T lib_func
00000000 T printf
00000000 T puts
rm -f libtest.a
gcc-ar -cvq libtest.a libtest.o
a - libtest.o
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects  -D LIB_FUNC   -c -o main.o main.c
gcc -Wall -Wextra -Wno-unused-parameter -flto -ffat-lto-objects  -D LIB_FUNC -o exe main.o -L. -ltest -nostdlib
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000401000

我在binutils / ld中看到错误了吗?这是上游固定的吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)