Linux程序动态库加载优化
作者:zhanhailiang 日期:2014-10-26
linux程序动态库加载流程简介
linux从程序(program或对象)变成进程(process或进程),简单说来需要经过三步:
-
fork进程,在内核创建进程相关内核项,加载进程可执行文件;
-
查找依赖的.so,逐一加载映射虚拟地址;
-
初始化程序变量;
如下例通过strace查看pwd命令执行过程:
[root@~/wade/codeReview/learningc]# strace pwd execve("/bin/pwd", ["pwd"], [/* 24 vars */]) = 0 brk(0) = 0x1c77000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb011000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=29690, ...}) = 0 mmap(NULL, 29690, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f06eb009000 close(3) = 0 open("/lib64/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\356\1\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1921096, ...}) = 0 mmap(NULL, 3750152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f06eaa5f000 mprotect(0x7f06eabe9000, 2097152, PROT_NONE) = 0 mmap(0x7f06eade9000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18a000) = 0x7f06eade9000 mmap(0x7f06eadee000, 18696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f06eadee000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb008000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb007000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb006000 arch_prctl(ARCH_SET_FS, 0x7f06eb007700) = 0 mprotect(0x7f06eade9000, 16384, PROT_READ) = 0 mprotect(0x7f06eb012000, 4096, PROT_READ) = 0 munmap(0x7f06eb009000, 29690) = 0 brk(0) = 0x1c77000 brk(0x1c98000) = 0x1c98000 open("/usr/lib/locale/locale-archive", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=99158576, ...}) = 0 mmap(NULL, 99158576, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f06e4bce000 close(3) = 0 getcwd("/root/wade/codeReview/learningc", 4096) = 32 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f06eb010000 write(1, "/root/wade/codeReview/learningc\n", 32/root/wade/codeReview/learningc ) = 32 close(1) = 0 munmap(0x7f06eb010000, 4096) = 0 close(2) = 0 exit_group(0) = ?
由此可见,如果只加载必须的动态库对程序性能有很重要的意义。
最佳实践
1. 程序test.c:
#include <stdio.h> #include <stdlib.h> #include <string.h> main () { printf ("1"); exit (0); }
2. 编译test.c
[root@~/wade/codeReview/learningc/16]# gcc -lm -lpthread -o test test.c
3. 通过ldd test命令查看程序运行时需要加载哪些动态库:
[root@~/wade/codeReview/learningc/16]# ldd test linux-vdso.so.1 => (0x00007fff6b5ff000) libm.so.6 => /lib64/libm.so.6 (0x00007f394cefa000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f394ccdd000) libc.so.6 => /lib64/libc.so.6 (0x00007f394c948000) /lib64/ld-linux-x86-64.so.2 (0x00007f394d187000)
4. 通过ldd -u test命令查看程序加载了哪些不必要的动态库:
[root@~/wade/codeReview/learningc/16]# ldd -u test Unused direct dependencies: /lib64/libm.so.6 /lib64/libpthread.so.0
5. 通过-Wl,–as-needed编译选项只加载必须的动态库:
[root@~/wade/codeReview/learningc/16]# gcc -Wl,--as-needed -lm -o test test.c [root@~/wade/codeReview/learningc/16]# ldd test linux-vdso.so.1 => (0x00007fffdf5ff000) libc.so.6 => /lib64/libc.so.6 (0x00007f5d862cd000) /lib64/ld-linux-x86-64.so.2 (0x00007f5d8666a000)
参考文章:
-
linux下so动态库一些不为人知的秘密(上):http://blog.chinaunix.net/uid-27105712-id-3313293.html
-
linux下so动态库一些不为人知的秘密(中):http://blog.chinaunix.net/uid-27105712-id-3313327.html
-
linux下so动态库一些不为人知的秘密(中二):http://blog.chinaunix.net/uid-27105712-id-3317666.html
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。