When laying out symbols in the address space using a linker script, ld
allows to
refer to a specific symbol coming from a static library with the following
syntax:
archive.a:object_file.o(.section.symbol_name)
Using gold
rather than ld
, it seems that such a directive is ignored. The
linking process succeeds. However, when using this instruction to put a specific
symbol at a specific location with gold
and checking the resulting symbol layout
using nm
or having a look at the Map file, the symbol is not in the expected
location.
I made a small test case using a dummy hello world program statically compiled in its entrety with gcc 5.4.0. The C library is musl libc (last commit on the master branch from the official git repository). For binutils, I also use the last commit on the master branch from the official git repository.
I use the linker script to place a specific symbol (.text.exit
) from a static
library (musl C library: libc.a
) at a specific location in the address space
which is: the first position in the .text
section.
My linker script is:
ENTRY(_start)
SECTIONS
{
. = 0x10000;
.text :
{
/* Forcing .text.exit in the first position in .text section */
musl/lib/libc.a:exit.o(.text.exit);
*(.text*);
}
. = 0x8000000;
.data : { *(.data*) }
.rodata : { *(.rodata*) }
.bss : { *(.bss*) }
}
My Makefile:
# Set this to 1 to link with gold, 0 to link with ld
GOLD=1
SRC=test.c
OBJ=test.o
LIBS=musl/lib/crt1.o \
musl/lib/libc.a \
musl/lib/crtn.o
CC=gcc
CFLAGS=-nostdinc -I musl/include -I musl/obj/include
BIN=test
LDFLAGS=-static
SCRIPT=linker-script.x
MAP=map
ifeq ($(GOLD), 1)
LD=binutils-gdb/gold/ld-new
else
LD=binutils-gdb/ld/ld-new
endif
all:
$(CC) $(CFLAGS) -c $(SRC) -o $(OBJ)
$(LD) --output $(BIN) $(LDFLAGS) $(OBJ) $(LIBS) -T $(SCRIPT) \
-Map $(MAP)
clean:
rm -rf $(OBJ) $(BIN) $(MAP)
After compiling and linking I'm checking the map file (obtained using the -Map
ld
/gold
flag) to have a look at the location of .text.exit
. Using ld
as the
linker, it is indeed in the first position of the text section. Using gold
, it
is not (it is present farther in the address space, as if my directive was not
taken into account).
Now, while neither of these work with gold
:
musl/lib/libc.a:exit.o(.text.exit);
musl/lib/libc.a(.text.exit)
This works:
*(.text.exit);
Is that a missing feature in gold
? or am I doing something wrong, maybe there is
another way to refer to a specific symbol of a specific object file in an
archive using gold
?
When laying out symbols in the address space using a linker script, ld allows to refer to a specific symbol coming from a specific object file inside a static library with the following syntax:
archive.a:object_file.o(.section.symbol_name)
That isn't quite what that syntax means. When you see ".section.symbol_name" in the linker script (or in a readelf or objdump list of sections), that is the whole name of the section, and you'll only see sections with names like that if you use the -ffunction-sections option when compiling. Given that your script works with ld, and if you just use the full filename wild card with gold, it looks like your musl libraries were indeed compiled with -ffunction-sections, but that's not something you can always assume is true for system libraries. So the linker isn't really searching for a section named ".text" that defines a symbol named "exit" -- instead, it's simply looking for a section named ".text.exit". Subtle difference, but you should be aware of it.
Now, while neither of these work with gold: musl/lib/libc.a:exit.o(.text.exit); musl/lib/libc.a(.text.exit);
This works: *(.text.exit);
Is that a missing feature in gold? or am I doing something wrong, maybe there is another way to refer to a specific symbol of a specific object file in an archive using gold?
If you look at the resulting -Map output file, I suspect you'll see the name of the object file is written as "musl/lib/libc.a(exit.o)". That's the spelling you need to use in the script, and because of the parentheses, you need to quote it. This:
"musl/lib/libc.a(exit.o)"(.text.exit)
should work. If you want something that will work in both linkers, try something like this:
"musl/lib/libc.a*exit.o*"(.text.exit)
or just
"*exit.o*"(.text.exit)