动态库的起始地址是什么意思?
What does start address mean for dynamic library?
我刚刚发现共享库也有 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
可执行文件的含义很清楚,但共享对象的含义是什么?
就像在程序中一样,共享库的起始地址(a.k.a 入口点地址)只是
.text
段的起始地址,包含所有可执行文件
代码。
这里也有一个玩具共享库来说明:
foo.c
#include <stdio.h>
void foo(void)
{
printf(__func__);
}
编译并link:
$ gcc -Wall -Wextra -fPIC -c foo.c
$ gcc -shared -o libfoo.so foo.o -Wl,-Map=libfoo.map
我们看看它的起始地址:
$ 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
当我们 linked SO 时,我们请求了一个 linker 地图文件,libfoo.map
。这是
该地图文件的 .text
部分:
.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)
根据objdump
,它从地址 0x530 开始。它是 0xf2 字节长。从五个
linker 加载的文件:
/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
crti.o
的输入 .text
部分为空,贡献了 0 个字节。
然后 crtbeginS.o
贡献了 0xda 字节,但没有符号。然后foo.o
在地址 0x60a 贡献了 0x18 个字节,包括符号 foo
。然后
crtendS.o
和 crtn.o
各贡献了 0 个字节。 0xda + 0x18 = 0xf2。 (这
.text
部分为空的文件将对
其他输出部分,未显示)。
因此,在库的起始地址我们找到代码 crtbeginS.o
,
这是 C 运行时初始化代码 - 共享库版本 -
用于查找全局构造函数(即任何 C++ 的构造函数
全局对象或 C 函数限定
__attribute((constructor))
)。参见 this question and answer。
综上,共享库的起始地址输入那个库的贡献
到动态 linked.
程序的运行时初始化
我刚刚发现共享库也有 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
可执行文件的含义很清楚,但共享对象的含义是什么?
就像在程序中一样,共享库的起始地址(a.k.a 入口点地址)只是
.text
段的起始地址,包含所有可执行文件
代码。
这里也有一个玩具共享库来说明:
foo.c
#include <stdio.h>
void foo(void)
{
printf(__func__);
}
编译并link:
$ gcc -Wall -Wextra -fPIC -c foo.c
$ gcc -shared -o libfoo.so foo.o -Wl,-Map=libfoo.map
我们看看它的起始地址:
$ 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
当我们 linked SO 时,我们请求了一个 linker 地图文件,libfoo.map
。这是
该地图文件的 .text
部分:
.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)
根据objdump
,它从地址 0x530 开始。它是 0xf2 字节长。从五个
linker 加载的文件:
/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
crti.o
的输入 .text
部分为空,贡献了 0 个字节。
然后 crtbeginS.o
贡献了 0xda 字节,但没有符号。然后foo.o
在地址 0x60a 贡献了 0x18 个字节,包括符号 foo
。然后
crtendS.o
和 crtn.o
各贡献了 0 个字节。 0xda + 0x18 = 0xf2。 (这
.text
部分为空的文件将对
其他输出部分,未显示)。
因此,在库的起始地址我们找到代码 crtbeginS.o
,
这是 C 运行时初始化代码 - 共享库版本 -
用于查找全局构造函数(即任何 C++ 的构造函数
全局对象或 C 函数限定
__attribute((constructor))
)。参见 this question and answer。
综上,共享库的起始地址输入那个库的贡献 到动态 linked.
程序的运行时初始化