将静态库链接到动态库时删除死代码

J. *_*Lui 6 c gcc shared-libraries static-libraries dead-code

假设我有以下文件:

libmy_static_lib.c:

#include <stdio.h>
void func1(void){
    printf("func1() called from a static library\n");
}
void unused_func1(void){
    printf("printing from the unused function1\n");
}
void unused_func2(void){
    printf("printing from unused function2\n");
}
Run Code Online (Sandbox Code Playgroud)

libmy_static_lib.h:

void func(void);
void unused_func1(void);
void unused_func2(void);
Run Code Online (Sandbox Code Playgroud)

my_prog.c:

#include "libmy_static_lib.h"
#include <stdio.h>
void func_in_my_prog()
{
    printf("in my prog\n");
    func1();

}
Run Code Online (Sandbox Code Playgroud)

这是我链接库的方式:

# build the static library libmy_static_lib.a
gcc -fPIC -c -fdata-sections --function-sections -c libmy_static_lib.c -o libmy_static_lib.o
ar rcs libmy_static_lib.a libmy_static_lib.o

# build libmy_static_lib.a into a new shared library
gcc -fPIC -c ./my_prog.c -o ./my_prog.o
gcc -Wl,--gc-sections -shared -m64 -o libmy_shared_lib.so ./my_prog.o -L. -l:libmy_static_lib.a
Run Code Online (Sandbox Code Playgroud)

libmy_static_lib.c中有两个未使用的函数,我认为从这篇文章中可以看出

gcc fdata-sections --function-sections
Run Code Online (Sandbox Code Playgroud)

应该为每个函数创建一个符号,并且

gcc -Wl,--gc-sections
Run Code Online (Sandbox Code Playgroud)

应该在链接时删除未使用的符号

但是当我跑步的时候

nm libmy_shared_lib.so
Run Code Online (Sandbox Code Playgroud)

它显示这两个未使用的函数也链接到共享库中.

有关如何让gcc自动删除未使用的功能的任何建议?

编辑:如果我将静态库直接链接到可执行文件,我可以使用上面的gcc选项来删除未使用的函数.但是,如果我将静态库链接到共享库,它不会删除未使用的函数.

Flo*_*mer 5

您可以使用版本脚本结合-ffunction-sections和来标记入口点--gc-sections

例如,考虑这个 C 文件 ( example.c):

int
foo (void)
{
  return 17;
}

int
bar (void)
{
  return 251;
}
Run Code Online (Sandbox Code Playgroud)

而这个版本的脚本,叫做version.script

{
  global: foo;
  local: *;
};
Run Code Online (Sandbox Code Playgroud)

像这样编译和链接源:

gcc -Wl,--gc-sections -shared -ffunction-sections -Wl,--version-script=version.script example.c
Run Code Online (Sandbox Code Playgroud)

如果查看 的输出objdump -d --reloc a.out,您会注意到 onlyfoo包含在共享对象中,而不包含bar

以这种方式删除函数时,链接器将考虑间接依赖关系。例如,如果你foo变成这样:

void *
foo (void)
{
  extern int bar (void);
  return bar;
}
Run Code Online (Sandbox Code Playgroud)

链接器将会把两者foobar到共享对象,因为两者都需要,即使只bar用于出口。

(显然,这不适用于所有平台,但 ELF 支持这一点。)