0

Goal

I want to create a shared library libsquare.so which is statically linked to libmul.a which itself is statically linked to libadd.a

Situation

I create libmul.a by linking libadd.a to it. Then I create libsquare.so by linking in the just created libmul.a.

libmul.a has the code for the add-function.

Problem

When I link it to into a shared object, and looking into the symbol table, the add-symbol is still there, but undefined (*UND*), rather than in the .text section.

I have a MWE here on Github demonstrating it.

Here a part of the 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

Here the entire 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

In essence the commands run are:

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
Joel
  • 1,725
  • 3
  • 16
  • 34
  • Just `gcc -shared -Wl,-soname=square -o libsquare.so square.o mul.o add.o`. `which is statically linked` If you want them to be _contained_ within the library, then unpack static libraries and link with object files. – KamilCuk Apr 21 '21 at 07:18
  • What do you mean by _contained_? Suppose, I don't have access to `add.o`, its a different project with its own dependencies and I only get the `libadd.o`. – Joel Apr 21 '21 at 07:24
  • 1
    By contained I mean that the shared library will include in it all the code inside it. What do you mean by "statically linked"? Static linking means just compilation. Unpack static libraries and extract object files from them. Then compile with the object files. A static library is just list a "zip" of .o files, nothing more nothing less. || Or use `--whole-archive` which does the same as including all object files on compilation line. Does https://stackoverflow.com/questions/2649735/how-to-link-static-library-into-dynamic-library-in-gcc answer your question? – KamilCuk Apr 21 '21 at 07:46
  • 1
    And this answer mentions unpacking https://stackoverflow.com/questions/8808691/can-i-build-a-shared-library-by-linking-static-libraries . Does it answer your question? What research did you do before asking your question? – KamilCuk Apr 21 '21 at 07:50
  • You add all static libraries to the command to build the shared library, like `gcc -shared -Wl,-soname=square -o libsquare.so square.o libmul.a libadd.a`. – the busybee Apr 21 '21 at 09:48
  • 1
    "*libmul.a has the code for the add-function.*": how did you figure? It's wrong. Simply use `gcc -shared -Wl,-soname=square -o libsquare.so square.o libmul.a libadd.a` – CristiFati Apr 21 '21 at 10:03
  • @CristiFati `objdump -D libmul.a` shows the assembly of `add.c`, hence I thought that the libmul.a has everything it needs. @KamilCuk Thanks. was not aware, that I could unpack `libmul.a` to get `mul.o` again. I was thoroughly reading documentation of `gcc` and `ld` (not `ar` unfortunately) to understand how the linking works. But since I was mislead by my objdump of `llbmul,a` I didn't search for 'create a static lib depending on another static lib` which ultimately was the problem. Cheers to both of you. – Joel Apr 22 '21 at 00:42

1 Answers1

0

Never mind, I found a solution.

Just kidding :)

The problem is my ar commands. When creating the libmul.a via ar rcs libmul.a mul.o libadd.a it creates an archive called libmul.a with mul.o and libadd.a in it like so:

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

see also the 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

When then eventually linking libmul.a like gcc use-lib-mul.c libmul.a than this fails as well. (Thus the overall problem has nothing to do with the shared object - part).

Solution

As written in the comments and here, one must unpack the objects from dependency lib libadd.a to create another lib libmul.a.

So to correctly generate libmul.a:

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

This creates:

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

And finally, to correctly generate 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

which then has all the required symbols in the .text section and the symbols have all lengths >0 0x14, 0x1c and 0x3b resp.:

$ 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
...
Joel
  • 1,725
  • 3
  • 16
  • 34