还有一些类似 GCC_ 前缀
或者 GLIBC_PRIVATE 的版本符号,这样的富豪标记分别用于GCC编译器和GLIC内部
它提醒共享库的使用者,最好不要使用它们,因为不是对外公开的
给共享库加上版本
gcc -shared -fPIC foo.c -Xlinker --version-script libfoo.ver -o libfoo.so
VERS_1.2 {
global:
foo;
local:
*;
};
编译命令
gcc -shared -fPIC foo.c -Xlinker --version-script libfoo.ver -o libfoo.so
再编译一个main程序
gcc p1.c ./libfoo.so -o main
如果将这个main程序拿到其他机器上运行,找到的版本库比当前的低,就会运行报错
共享库的路径
/lib 存放系统最关键和基础的共享库
/usr/lib 存放一些非系统运行时所需要的关键性共享库
/user/local/lib 存放一些第三方应用程序的库
共享库的查找方式
先看ELF文件中定义的 .dynamic信息,如果共享库是绝对路径,就去绝对路径下找
否则就去指定的路径下找
动态链接器会在 /lib,/user/lib,/etc/ld.so.conf配置文件指定的目录中查找共享库
ldconfig程序是为共享库目录下的各个共享库创建,删除或更新相应的SO-NAME
/etc/ld.so.cache是将相应的SO-NAME收集起来,建立一个缓存
动态链接器会在这个缓存文件中查找,如果找不到还会遍历 /lib,/usr/lib这两个目录
环境变量
LD_LIBRARY_PATH
也可以直接运行动态链接器来启动程序
/lib/ld-linux.so.2 -library-path /home/user /bin/ls
LD_PRELOAD,其优先级比 LD_LIBRARY_PATH还要高
可以通过这种功能,覆盖系统函数,达到库打桩的目的
LD_DEBUG,打开动态链接器的调试功能
LD_DEBUG=files ./p1 的运行结果
25551:
25551: file=./libfoo.so [0]; needed by ./p1 [0]
25551: file=./libfoo.so [0]; generating link map
25551: dynamic: 0x00007f93099ebdf8 base: 0x00007f93097eb000 size: 0x0000000000201040
25551: entry: 0x00007f93097eb5d0 phdr: 0x00007f93097eb040 phnum: 7
25551:
25551:
25551: file=libc.so.6 [0]; needed by ./p1 [0]
25551: file=libc.so.6 [0]; generating link map
25551: dynamic: 0x00007f93097e3b80 base: 0x00007f9309428000 size: 0x00000000003c21c0
25551: entry: 0x00007f9309449d10 phdr: 0x00007f9309428040 phnum: 10
25551:
25551:
25551: calling init: /lib64/libc.so.6
25551:
25551:
25551: calling init: ./libfoo.so
25551:
25551:
25551: initialize program: ./p1
25551:
25551:
25551: transferring control: ./p1
25551:
printf from lib.so 1
LD_DEBUG支持的其他参数
共享库的构造函数,析构函数
在函数前加上一些声明即可,这种是GCC对C和C++的扩展,在其他编译器上这种语法不通用
#include
int main() {
printf("hehe\n");
}
void __attribute__((constructor)) init_func() {
printf("init...\n");
}
void __attribute__((destructor)) finit_func() {
printf("destroy...\n");
}