创建动态链接库
编译并使用动态链接库
-
创建共享库源文件
math.c:int add(int a, int b) { return a + b; } -
创建共享库头文件
math.h:int add(int a, int b); -
编译动态链接库:
gcc -shared -fPIC math.c -o libmath.so-shared:共享对象(shared object),是 Linux 下对动态库的另一种称谓-fPIC:Position Independent Code,
-
编辑主程序源文件
main.c:#include <stdio.h> #include "math.h" int main() { printf("add(1, 2) returned %d\n", add(1, 2)) } -
编译主程序:
gcc main.c -lmath -L. -o main-lmath:-l选项用来指定动态链接库,这里指定了math库(前缀lib和后缀.so被省略)-L.:-L选项用来指定查找动态链接库的位置,这里指定了当前目录.
-
执行主程序:
LD_LIBRARY_PATH="$(pwd)" ./mainLD_LIBRARY_PATH:指定运行程序时查找动态链接库的路径
查看内存映射情况
可以在主程序中加一个死循环让程序保持运行:
#include <stdio.h>
#include "math.h"
int main() {
printf("add(1, 2) returned %d\n", add(1, 2))
}
然后在后台启动程序:
./main >/dev/null &
查看内存映射:
$ cat /proc/1863281/maps
556d6ef54000-556d6ef55000 r--p 00000000 103:03 137297963 /home/user/main
556d6ef55000-556d6ef56000 r-xp 00001000 103:03 137297963 /home/user/main
556d6ef56000-556d6ef57000 r--p 00002000 103:03 137297963 /home/user/main
556d6ef57000-556d6ef58000 r--p 00002000 103:03 137297963 /home/user/main
556d6ef58000-556d6ef59000 rw-p 00003000 103:03 137297963 /home/user/main
556da1a35000-556da1a56000 rw-p 00000000 00:00 0 [heap]
7f88057a4000-7f88057a7000 rw-p 00000000 00:00 0
7f88057a7000-7f88057cf000 r--p 00000000 103:02 23604638 /usr/lib/x86_64-linux-gnu/libc.so.6
7f88057cf000-7f8805964000 r-xp 00028000 103:02 23604638 /usr/lib/x86_64-linux-gnu/libc.so.6
7f8805964000-7f88059bc000 r--p 001bd000 103:02 23604638 /usr/lib/x86_64-linux-gnu/libc.so.6
7f88059bc000-7f88059bd000 ---p 00215000 103:02 23604638 /usr/lib/x86_64-linux-gnu/libc.so.6
7f88059bd000-7f88059c1000 r--p 00215000 103:02 23604638 /usr/lib/x86_64-linux-gnu/libc.so.6
7f88059c1000-7f88059c3000 rw-p 00219000 103:02 23604638 /usr/lib/x86_64-linux-gnu/libc.so.6
7f88059c3000-7f88059d0000 rw-p 00000000 00:00 0
7f88059e3000-7f88059e4000 r--p 00000000 103:03 137297952 /home/user/libmath.so
7f88059e4000-7f88059e5000 r-xp 00001000 103:03 137297952 /home/user/libmath.so
7f88059e5000-7f88059e6000 r--p 00002000 103:03 137297952 /home/user/libmath.so
7f88059e6000-7f88059e7000 r--p 00002000 103:03 137297952 /home/user/libmath.so
7f88059e7000-7f88059e8000 rw-p 00003000 103:03 137297952 /home/user/libmath.so
7f88059e8000-7f88059ea000 rw-p 00000000 00:00 0
7f88059ea000-7f88059ec000 r--p 00000000 103:02 23604552 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f88059ec000-7f8805a16000 r-xp 00002000 103:02 23604552 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8805a16000-7f8805a21000 r--p 0002c000 103:02 23604552 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8805a22000-7f8805a24000 r--p 00037000 103:02 23604552 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7f8805a24000-7f8805a26000 rw-p 00039000 103:02 23604552 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
7ffdbe414000-7ffdbe435000 rw-p 00000000 00:00 0 [stack]
7ffdbe5ee000-7ffdbe5f2000 r--p 00000000 00:00 0 [vvar]
7ffdbe5f2000-7ffdbe5f4000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
可以看到程序加载了 libc.so.6,libmath.so 以及 ld-linux-x86-64.so.2 三个共享链接库。
另外,你会注意到 libc.so.6 和 ld-linux-x86-64.so.2 后面都有一个数字,这个数字是 ABI(Application Binary Interface)的主版本号。当 ABI 发生不兼容的变化时,这个主版本号就会增加。目前主流 Linux 系统使用的都是版本 6。
libc.so.6 实际上是一个符号链接,指向具体的实现文件:
libc.so.6 -> libc-2.31.so
这里的 2.31 是实际的库文件版本号,而 6 是 ABI 版本号。
全局偏移表
为了使用动态链接库,程序中要用到库函数的地方在一开始是一个空指针。当库载入内存中后,库函数的地址会被写入全局偏移表(Global Offset Table, GOT)。我们可以在库文件的 Section 部分找到 GOT:
$ readelf -S ./libmath.so
There are 25 section headers, starting at offset 0x34d8:
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .note.gnu.pr[...] NOTE 00000000000002a8 000002a8
0000000000000020 0000000000000000 A 0 0 8
[ 2] .note.gnu.bu[...] NOTE 00000000000002c8 000002c8
0000000000000024 0000000000000000 A 0 0 4
[ 3] .gnu.hash GNU_HASH 00000000000002f0 000002f0
0000000000000024 0000000000000000 A 4 0 8
[ 4] .dynsym DYNSYM 0000000000000318 00000318
0000000000000090 0000000000000018 A 5 1 8
[ 5] .dynstr STRTAB 00000000000003a8 000003a8
0000000000000059 0000000000000000 A 0 0 1
[ 6] .rela.dyn RELA 0000000000000408 00000408
00000000000000a8 0000000000000018 A 4 0 8
[ 7] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[ 8] .plt PROGBITS 0000000000001020 00001020
0000000000000010 0000000000000010 AX 0 0 16
[ 9] .plt.got PROGBITS 0000000000001030 00001030
0000000000000010 0000000000000010 AX 0 0 16
[10] .text PROGBITS 0000000000001040 00001040
00000000000000d1 0000000000000000 AX 0 0 16
[11] .fini PROGBITS 0000000000001114 00001114
000000000000000d 0000000000000000 AX 0 0 4
[12] .eh_frame_hdr PROGBITS 0000000000002000 00002000
0000000000000024 0000000000000000 A 0 0 4
[13] .eh_frame PROGBITS 0000000000002028 00002028
000000000000007c 0000000000000000 A 0 0 8
[14] .init_array INIT_ARRAY 0000000000003e80 00002e80
0000000000000008 0000000000000008 WA 0 0 8
[15] .fini_array FINI_ARRAY 0000000000003e88 00002e88
0000000000000008 0000000000000008 WA 0 0 8
[16] .dynamic DYNAMIC 0000000000003e90 00002e90
0000000000000150 0000000000000010 WA 5 0 8
[17] .got PROGBITS 0000000000003fe0 00002fe0
0000000000000020 0000000000000008 WA 0 0 8
[18] .got.plt PROGBITS 0000000000004000 00003000
0000000000000018 0000000000000008 WA 0 0 8
[19] .data PROGBITS 0000000000004018 00003018
0000000000000008 0000000000000000 WA 0 0 8
[20] .bss NOBITS 0000000000004020 00003020
0000000000000008 0000000000000000 WA 0 0 1
[21] .comment PROGBITS 0000000000000000 00003020
000000000000002b 0000000000000001 MS 0 0 1
[22] .symtab SYMTAB 0000000000000000 00003050
0000000000000258 0000000000000018 23 20 8
[23] .strtab STRTAB 0000000000000000 000032a8
0000000000000159 0000000000000000 0 0 1
[24] .shstrtab STRTAB 0000000000000000 00003401
00000000000000d6 0000000000000000 0 0 1
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
L (link order), O (extra OS processing required), G (group), T (TLS),
C (compressed), x (unknown), o (OS specific), E (exclude),
D (mbind), l (large), p (processor specific)
采用这种方法实现的动态链接库也叫做地址无关代码(Position Independent Code, PIC)

浙公网安备 33010602011771号