创建一个共享对象C,它依赖于静态库B,它本身又依赖于静态库A 目标问题

问题描述

目标

我想创建一个共享库 libsquare.so,它静态链接libmul.a,而 libadd.a 本身静态链接libmul.a

情况

我通过将 libadd.a 链接libsquare.so 来创建它。 然后我通过链接刚刚创建的 libmul.a 来创建 libmul.a

add 具有 add 函数代码

问题

当我将它链接到共享对象并查看符号表时,*UND* 符号仍然存在,但未定义 (.text),而不是在 {{1} } 部分。

我有一个 MWE here on Github 演示它。

这里是objdump -t libsquare.so的一部分

libsquare.so:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000         *UND*  0000000000000000              add
0000000000001119 g     F .text  000000000000001c              square
0000000000001135 g     F .text  000000000000003b              mul
... // some symbols omitted here... See repo for entire table

这里是整个objdump -t libmul.a

mul.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 mul.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g     F .text  000000000000003b mul
0000000000000000         *UND*  0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000         *UND*  0000000000000000 add


In nested archive libadd.a:

add.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 add.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g     F .text  0000000000000014 add

本质上运行的命令是:

cc -fPIC -rdynamic -o add.o -c add.c
cc -fPIC -rdynamic -o mul.o -c mul.c
cc -fPIC -rdynamic -o square.o -c square.c
ar rcs libadd.a add.o
ranlib libadd.a
ar rcs libmul.a mul.o libadd.a
ranlib libmul.a
gcc -shared -Wl,-soname=square -o libsquare.so square.o libmul.a 
cc -fPIC -rdynamic -o test-w-lib.o -c test-w-lib.c
cc -o test-w-lib libsquare.so test-w-lib.o -ldl 
/usr/bin/ld: libsquare.so: undefined reference to `add'
collect2: error: ld returned 1 exit status

解决方法

没关系,我找到了解决方案。

开个玩笑:)

问题是我的 ar 命令。通过 libmul.a 创建 ar rcs libmul.a mul.o libadd.a 时,它会创建一个名为 libmul.a 的存档,其中包含 mul.olibadd.a,如下所示:

libmul.a
├── mul.o
└── libadd.a
    └── add.o

另见objdump:

$ objdump libmul.a -t
In archive libmul.a:

mul.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 mul.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g     F .text  000000000000003b mul
0000000000000000         *UND*  0000000000000000 _GLOBAL_OFFSET_TABLE_
0000000000000000         *UND*  0000000000000000 add


In nested archive libadd.a:

add.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 add.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 g     F .text  0000000000000014 add

当最终将 libmul.a 链接为 gcc use-lib-mul.c libmul.a 时,这也会失败。 (因此整体问题与共享对象无关 - 部分)。

解决方案

如注释和 here 中所述,必须从依赖库 libadd.a 中解压对象以创建另一个库 libmul.a

所以要正确生成libmul.a

libmul.a: mul.o libadd.a
    rm -rf libadd; mkdir libadd; cd libadd; ar x ../libadd.a
    ar rcs ${@} ${<} ./libadd/*.o
    ranlib ${@}

这会产生:

libmul.a
├── mul.o
└── add.o

最后,正确生成libsquare.so

libsquare.so: square.o libmul.a
    rm -rf libmul;  mkdir libmul; cd libmul; ar x ../libmul.a
    $(CC) -shared -Wl,-soname=square -o ${@} ${<} libmul/*.o

然后在 .text 部分包含所有必需的符号,并且符号的所有长度 >0 0x140x1c0x3b 分别为:

$ objdump libsquare.so -t

libsquare.so:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000              square.c
0000000000000000 l    df *ABS*  0000000000000000              add.c
0000000000000000 l    df *ABS*  0000000000000000              mul.c
0000000000001135 g     F .text  0000000000000014              add
0000000000001119 g     F .text  000000000000001c              square
0000000000001149 g     F .text  000000000000003b              mul
...