0

I need to put data to a separate object section in a static library. I would expect it gets linked into the main binary that uses the library, however it disappears after linking. See a reproducer below:

lib.c

static int keep_somewhere __attribute__((used, section("mySection"))) = 0xdeadbeef;

main.c

#include <stdio.h>

static int keep_in_main __attribute__((used, section("fromMain"))) = 0xdeadbeef;

int main(void) {
    printf("test done\n");
    return 0;
}

Makefile

report: main main-simple
    size -A -d lib.a
    size -A -d main
    size -A -d main-simple

main: lib.a main.c
    gcc -L. -l:lib.a main.c -o main

main-simple: lib.o main.c
    gcc lib.o main.c -o main-simple

lib.o: lib.c
    gcc -c lib.c

lib.a: lib.o
    ar rcs lib.a lib.o

clean:
    rm lib.a lib.o main

.PHONY: clean report

Run make and observe the report.

Size of lib.a shows mySection just fine:

$ size -A -d lib.a
lib.o   (ex lib.a):
section              size   addr
...
mySection               4      0
...
Total 

So does the main-simple binary created without the archive step:

size -A -d main-simple
main-simple  :
section                 size      addr
...
mySection                  4   4210724
fromMain                   4   4210728
...
Total                   8387

However the main binary does not. Notice the fromMain section does appear:

$ size -A -d main
main  :
section                 size      addr
.interp                   28   4195096
.note.gnu.property        64   4195128
.note.gnu.build-id        36   4195192
.note.ABI-tag             32   4195228
.gnu.hash                 28   4195264
.dynsym                   96   4195296
.dynstr                   72   4195392
.gnu.version               8   4195464
.gnu.version_r            48   4195472
.rela.dyn                 48   4195520
.rela.plt                 24   4195568
.init                     27   4198400
.plt                      32   4198432
.text                    251   4198464
.fini                     13   4198716
.rodata                   26   4202496
.eh_frame_hdr             44   4202524
.eh_frame                140   4202568
.init_array                8   4210192
.fini_array                8   4210200
.dynamic                 464   4210208
.got                      16   4210672
.got.plt                  32   4210688
.data                      4   4210720
fromMain                   4   4210724
.bss                       8   4210728
.comment                  46         0
.gnu.build.attributes   6780   4218928
Total                   8387

Just for reference, this was tested using gcc (GCC) 11.2.1 20210728 (Red Hat 11.2.1-1)

Edit 24th of Nov 2021:

For the sake of the used/unused symbol argument, I updated main.c to show that this works when the same pattern is used in the main compile unit.

I also added a simpler case where lib.o is linked directly and not as a library.

MarSik
  • 211
  • 1
  • 2
  • 7

1 Answers1

2

lib.c is being linked into a static library lib.a, and you never use the symbol keep_somewhere in main.c. The linker by default will not include unused symbols in static libraries into the executable, which is why neither the symbol nor the custom section appear in the executable.

To fix this, you can surround the -l:lib.a argument with -Wl,-whole-archive and -Wl,-no-whole-archive like this:

gcc -L. -Wl,-whole-archive -l:lib.a -Wl,-no-whole-archive main.c -o main

This forces the linker to include the entire archive into the executable, including the unused symbols, which should make your custom section appear.

xnsc
  • 126
  • 1
  • 6
  • You are not taking into account the __attribute__(used) I intentionally placed on the symbol. See https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#Common-Variable-Attributes which says: "This attribute, attached to a variable with static storage, means that the variable must be emitted even if it appears that the variable is not referenced. " – MarSik Nov 24 '21 at 06:00
  • 1
    @MarSik The section should be in lib.o, but when linking through lib.a, the linker has no reason to pull lib.o in because lib.o doesn't have any needed symbols (it doesn't have any visible symbols). – Petr Skocik Nov 24 '21 at 06:45
  • Oh, right, that is it. I would have assumed the attribute forces that, but apparently not. This is obviously not the whole issue I am playing with, now I need to find out if -whole-archive plays nicely with -flto and -Os. – MarSik Nov 24 '21 at 07:25
  • @xnsc May I kindly ask you to look into my most recent question https://stackoverflow.com/questions/70216528/gcc-linker-duplicate-and-missing-symbols-when-cross-compiling-to-arm ? It seems you know a lot more about symbol resolution during linking than I do. – Vroomfondel Dec 03 '21 at 16:50