library
static library
Introduction
Create archive file (*.a):
$ cc -c -o foo.o foo.c $ cc -c -o bar.o bar.c $ ar ruv libfoo.a foo.o bar.o
Inside the archive file:
$ ar tv libfoo.a
Link:
$ cc -o baz baz.o -lfoo
可执行文件会包含静态链接库的object file的副本,因此执行时不需要该静态链接库。
ar Usage
打包(类似tar):
# ar options: # r: 加入新文件或取代现有文件 # c: libhoge.a不存在时不显示警告 # u: 根据时间戳保留最新文件 # s: 仿照ranlib为打包的文件建立索引 $ ar rcus libhoge.a foo.o bar.o baz.o
浏览打包文件:
# t: 列出打包内容 # v: 显示详细资讯 $ ar tv libhoge.a
解开打包文件:
$ ar xv libhoge.a
shared library
Introduction
Create shared library:
# PIC = Position Independent Code $ cc -fPIC -c -o foo.o foo.c $ cc -fPIC -c -o bar.o bar.c $ cc -shared -W1,-soname,libfoo.so.0 -o libfoo.so foo.o bar.o
Link:
$ cc -o baz baz.o -lfoo
链接时只会把共享链接库的SONAME登记在可执行文件的NEEDED中,可执行文件在被执行时,动态链接器ld.so会根据NEEDED来找到必要的共享链接库(库文件必须存在!)。
Search "NEEDED"
# use objdump $ objdump -p /bin/ls | grep -C1 NEEDED Dynamic Section: NEEDED libcap.so.2 NEEDED libacl.so.1 NEEDED libc.so.6 INIT 0x0000000000402180 # or use readelf $ readelf -d /bin/ls | grep -C1 NEEDED Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [libcap.so.2] 0x0000000000000001 (NEEDED) Shared library: [libacl.so.1] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000c (INIT) 0x402180
Dependencies
ldd
可执行文件:
$ ldd /bin/ls linux-vdso.so.1 (0x00007fff995fe000) libcap.so.2 => /usr/lib/libcap.so.2 (0x00007f678d4a3000) libacl.so.1 => /usr/lib/libacl.so.1 (0x00007f678d29a000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f678cef0000) libattr.so.1 => /usr/lib/libattr.so.1 (0x00007f678cceb000) /lib64/ld-linux-x86-64.so.2 (0x00007f678d6a7000)
共享链接库:
$ ldd /lib/librt.so.1 linux-vdso.so.1 (0x00007fff649fe000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007f65e810e000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f65e7d64000) /usr/lib/ld-linux-x86-64.so.2 (0x00007f65e832b000)
LD_TRACE_LOADED_OBJECTS
可执行文件:
$ LD_TRACE_LOADED_OBJECTS=1 /bin/ls linux-vdso.so.1 (0x00007ffff5bfe000) libcap.so.2 => /usr/lib/libcap.so.2 (0x00007f93c5df5000) libacl.so.1 => /usr/lib/libacl.so.1 (0x00007f93c5bec000) libc.so.6 => /usr/lib/libc.so.6 (0x00007f93c5842000) libattr.so.1 => /usr/lib/libattr.so.1 (0x00007f93c563d000) /lib64/ld-linux-x86-64.so.2 (0x00007f93c5ff9000)
共享链接库:
$ LD_TRACE_LOADED_OBJECTS=1 /lib/librt.so.1 linux-vdso.so.1 (0x00007fff781fe000) libpthread.so.0 => /usr/lib/libpthread.so.0 (0x00007fd3708ce000) libc.so.6 => /usr/lib/libc.so.6 (0x00007fd370524000) /usr/lib/ld-linux-x86-64.so.2 (0x00007fd370aeb000)
NOTE: 与Binary Hacks所说不同,无需加ELF解释器动态链接库/lib/ld-linux.so.2
$ LD_TRACE_LOADED_OBJECTS=1 /lib/ld-linux.so.2 /lib/librt.so.1
PIC
$ gcc -fpic $ gcc -fPIC
-fpic可以产生的GOT (Global Offset Table)大小受到处理器的限制,而-fPIC则任何处理器通用(在x86下二者相同)。
PIC vs non-PIC
- PIC版的function call经由PLT (Procedure Linkage Table)。
- 两者的共享链接库,用readelf查看可以发现:non-PIC版需要TEXTREL(text之内需要重定位),且RELCOUNT(定位数量)比PIC版多。(若要使PIC版的RELCOUNT变为0,需要在执行gcc时指定-nostartfiles。)
- non-PIC版执行时需要花更多时间重定位。
- non-PIC版在载入text segment之内需要重定位的page时会引发copy on write,进而使它无法和其他process共用text segment,丧失使用shared library的优势。
- non-PIC的共享链接库的代码段.text比PIC版小,但重定位需要的.rel.dyn占了很大空间。