Wiki

by yszheda

View project onGitHub

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占了很大空间。