What does start address mean for dynamic library?

2

I just discovered that shared libraries also have got start address:

objdump -f /usr/lib/libTH.so

/usr/lib/libTH.so:     file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000026e60

It is clear what it does mean for executable, but what is it for shared objects?

dynamic
shared-libraries

1 Answer

3

Just as in a program, the start address (a.k.a entry point address) of a shared library is simply the start address of the .text segment, containing all the executable code.

Here's a toy shared library too illustrate:

foo.c

#include <stdio.h>

void foo(void)
{
    printf(__func__);
}

Compile and link:

$ gcc -Wall -Wextra -fPIC -c foo.c
$ gcc -shared -o libfoo.so foo.o -Wl,-Map=libfoo.map

Let's see its start address:

$ objdump -f libfoo.so 

libfoo.so:     file format elf64-x86-64
architecture: i386:x86-64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000000530

We requested a linker map file, libfoo.map, when we linked the SO. Here's the .text section from that map file:

.text           0x0000000000000530       0xf2
 *(.text.unlikely .text.*_unlikely .text.unlikely.*)
 *(.text.exit .text.exit.*)
 *(.text.startup .text.startup.*)
 *(.text.hot .text.hot.*)
 *(.text .stub .text.* .gnu.linkonce.t.*)
 .text          0x0000000000000530        0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
 .text          0x0000000000000530       0xda /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
 .text          0x000000000000060a       0x18 foo.o
                0x000000000000060a                foo
 .text          0x0000000000000622        0x0 /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
 .text          0x0000000000000622        0x0 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o
 *(.gnu.warning)

As per objdump, it starts at address 0x530. It is 0xf2 bytes long. From the five files that the linker loaded:

 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crti.o
 /usr/lib/gcc/x86_64-linux-gnu/7/crtbeginS.o
 foo.o
 /usr/lib/gcc/x86_64-linux-gnu/7/crtendS.o
 /usr/lib/gcc/x86_64-linux-gnu/7/../../../x86_64-linux-gnu/crtn.o

The input .text section of crti.o was empty and contributed 0 bytes. Then crtbeginS.o contributed 0xda bytes, but no symbols. Then foo.o contributed 0x18 bytes at address 0x60a, including the symbol foo. Then crtendS.o and crtn.o each contributed 0 bytes. 0xda + 0x18 = 0xf2. (The files that had empty .text sections will have contributed something to other output sections, not shown).

So, at the start address of the library we find the code crtbeginS.o, which is C runtime initialization code - the shared library version - for finding global constructor functions (i.e. constructors of any C++ global objects or C functions qualified with __attribute((constructor))). See this question and answer.

In summary, the start address of the shared library enters that library's contribution to the runtime initialization of the program with which it is dynamically linked.

answered on Stack Overflow Feb 4, 2018 by Mike Kinghan

User contributions licensed under CC BY-SA 3.0