那个网站有帮人做图的,h5简单网页代码,商家免费入驻平台,第一活动线报网引文 我们在工作中经常会遇到动态库链接的问题#xff0c;因为正常的方式并不能满足我们的场景。常见的问题可以总结如下#xff1a;
系统路径默认路径、usr/lib、/lib 目录#xff0c;不会集成第三方动态库。
同名动态库可能在多个路径中存在。 针对不同的场景#xff0…引文 我们在工作中经常会遇到动态库链接的问题因为正常的方式并不能满足我们的场景。常见的问题可以总结如下
系统路径默认路径、usr/lib、/lib 目录不会集成第三方动态库。
同名动态库可能在多个路径中存在。 针对不同的场景根据链接器的加载逻辑进行相应的处理。
程序的加载流程 根据专栏《程序员的自我修养》中的【程序员的自我修养02】初识ELF文件格式-CSDN博客可知可执行文件的运行流程简述如下
操作系统加载ELF的文件头。以检查文件格式、操作权限等属性。根据文件头中的段表地址定位到各个段内容。将各个段映射到虚拟地址中。查找依赖的动态库并加载。进入文件头中的Entry point address。执行业务代码。 其中链接器查找依赖的动态库并加载这个流程实质很复杂后续我会在《程序员的自我修养》专栏中详细介绍。本文我们只关心链接器如何去找动态库。
问链接器如何知道可执行程序依赖哪些动态库呢
答ELF文件中有一个段.dynamic。这个段里面保存了动态链接器所需要的基本信息比如依赖哪些动态库、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等。我们可以通过readelf -d main命令查看该段内容如下 Dynamic section at offset 0xda8 contains 29 entries: Tag Type Name/Value 0x0000000000000001 (NEEDED) Shared library: [liba.so] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x000000000000000f (RPATH) Library rpath: [/home/yihua/] 0x000000000000000c (INIT) 0x5b8 0x000000000000000d (FINI) 0x794 0x0000000000000019 (INIT_ARRAY) 0x200d98 0x000000000000001b (INIT_ARRAYSZ) 8 (bytes) 0x000000000000001a (FINI_ARRAY) 0x200da0 0x000000000000001c (FINI_ARRAYSZ) 8 (bytes) 0x000000006ffffef5 (GNU_HASH) 0x298 0x0000000000000005 (STRTAB) 0x3f0 0x0000000000000006 (SYMTAB) 0x2d0 0x000000000000000a (STRSZ) 182 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000015 (DEBUG) 0x0 0x0000000000000003 (PLTGOT) 0x200fb8 0x0000000000000002 (PLTRELSZ) 24 (bytes) 0x0000000000000014 (PLTREL) RELA 0x0000000000000017 (JMPREL) 0x5a0 0x0000000000000007 (RELA) 0x4e0 0x0000000000000008 (RELASZ) 192 (bytes) 0x0000000000000009 (RELAENT) 24 (bytes) 0x0000000000000018 (BIND_NOW) 0x000000006ffffffb (FLAGS_1) Flags: NOW PIE 0x000000006ffffffe (VERNEED) 0x4c0 0x000000006fffffff (VERNEEDNUM) 1 0x000000006ffffff0 (VERSYM) 0x4a6 0x000000006ffffff9 (RELACOUNT) 3 0x0000000000000000 (NULL) 0x0 如上可知main 可执行程序依赖 两个动态库 liba.so、libc.so.6。其中黄色字体0x000000000000000f (RPATH) Library rpath: [/home/yihua/]表示链接器查找动态库的路径,其优先级最高。需要我们关注。其它的参数暂不考虑。 查看依赖的动态库还可以通过ldd main命令或objdump -x main | grep NEEDED命令。
知道可执行程序依赖哪些动态库口动态链接器就需要去找这些动态库查找的方式主要有以下四种。
程序指定路径rpath
环境变量LD_LIBRARY_PATH
动态链接器配置文件/etc/ld.so.conf
系统默认路径/lib 、 /usr/lib 其动态链接器加载的顺序分别是rpath -- LD_LIBRARY_PATH -- /etc/ld.so.conf -- /lib 、 /usr/lib。
知道四个方式后我们尝试了解如何使用。本文的示例代码如下 //a.c #includestdio.h int a() { printf(im liba.a\n); } // main.c #includestdlib.h #includestdio.h extern int a(); int main() { a(); return 0; }
编译 C yihuaubuntu:~/test/dynamic$ gcc -FPIC -shared -o liba.so a.c yihuaubuntu:~/test/dynamic$ gcc main.c -o main -L. -la
集成分别将 main 和 liba.so 放入到bin 和lib目录下。 Shell yihuaubuntu:~/test/dynamic$ tree . ├── a.c├── bin│ └── main├── lib│ └── liba.so └── main.c
运行 Shell yihuaubuntu:~/test/dynamic$ ./bin/main./bin/main: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory
如上错误是因为动态链接器没有找到liba.so导致的。可通过以下四种方式修复。
-Wl,-rpath 该方式是通过在编译阶段修改main 可执行程序中的dynamic段达到目的。可查看当前main的dynamic段内容 是没有RPATH参数的。可通过如下编译命令 yihuaubuntu:~/test/dynamic$ gcc -FPIC -shared -o liba.so a.c yihuaubuntu:~/test/dynamic$ gcc main.c -o main -L. -la -Wl,-rpath/home/yihua/test/dynamic/lib
再查看dynamic段内容 运行 拓展 -Wl,-rpath是编译阶段修改可执行程序的rpath参数但是往往我们在工程中是不太确认最终的集成路径的。可以在集成时采用chrpath命令修改可执行程序的rpath参数。如下 yihuaubuntu:~/test/dynamic$ chrpath -r ./lib/ bin/main //修改rpath bin/main: RPATH/home/yihua/ bin/main: new RPATH: ./lib/ yihuaubuntu:~/test/dynamic$ chrpath -l bin/main //查看rpath bin/main: RPATH./lib/
完结撒花~~~
LD_LIBRARY_PATH 环境变量LD_LIBRARY_PATH是我们最最常用的方式大部分情况下我们使用该方式即可。使用方式如下
LD_LIBRARY_PATH$LD_LIBRARY_PATH:/home/yihua//test/dynamic/lib。编译如下 yihuaubuntu:~/test/dynamic$ gcc -FPIC -shared -o liba.so a.c yihuaubuntu:~/test/dynamic$ gcc main.c -o main -L. -la
集成分别将 main 和 liba.so 放入到bin 和lib目录下。
运行 完结撒花~~~
/etc/ld.so.conf 该配置文件是系统动态链接器加载的配置文件。我们可以重新创建一个窗口目的是关闭上述的LD_LIBRARY_PATH环境变量。修改/etc/ld.so.conf文件如下 运行 发现依然没有找到动态库这是为什么呢我们可以通过strace ./bin/main命令查看程序的加载流程。输出如下 yihuaubuntu:~/test/dynamic$ strace ./bin/main execve(./bin/main, [./bin/main], 0x7ffdfd030ae0 /* 26 vars */) 0 brk(NULL) 0x5643c65c3000 access(/etc/ld.so.nohwcap, F_OK) -1 ENOENT (No such file or directory) access(/etc/ld.so.preload, R_OK) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /etc/ld.so.cache, O_RDONLY|O_CLOEXEC) 3 fstat(3, {st_modeS_IFREG|0644, st_size104673, ...}) 0 mmap(NULL, 104673, PROT_READ, MAP_PRIVATE, 3, 0) 0x7ff91b2ed000 close(3) 0 access(/etc/ld.so.nohwcap, F_OK) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/tls/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/tls/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/tls/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/tls/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/tls/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/tls/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/tls/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/tls, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64-linux-gnu/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64-linux-gnu, {st_modeS_IFDIR|0755, st_size16384, ...}) 0 openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/tls/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/tls/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/tls/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/tls/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/tls/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/tls/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/tls/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/tls, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64-linux-gnu/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64-linux-gnu, {st_modeS_IFDIR|0755, st_size81920, ...}) 0 openat(AT_FDCWD, /lib/tls/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/tls/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/tls/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/tls/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/tls/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/tls/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/tls/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/tls, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /lib/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/lib, {st_modeS_IFDIR|0755, st_size4096, ...}) 0 openat(AT_FDCWD, /usr/lib/tls/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/tls/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/tls/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/tls/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/tls/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/tls/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/tls/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/tls, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/haswell/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/haswell/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/haswell/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/haswell, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/x86_64/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib/x86_64, 0x7fffcd77f4e0) -1 ENOENT (No such file or directory) openat(AT_FDCWD, /usr/lib/liba.so, O_RDONLY|O_CLOEXEC) -1 ENOENT (No such file or directory) stat(/usr/lib, {st_modeS_IFDIR|0755, st_size4096, ...}) 0 writev(2, [{iov_base./bin/main, iov_len10}, {iov_base: , iov_len2}, {iov_baseerror while loading shared libra..., iov_len36}, {iov_base: , iov_len2}, {iov_baseliba.so, iov_len7}, {iov_base: , iov_len2}, {iov_basecannot open shared object file, iov_len30}, {iov_base: , iov_len2}, {iov_baseNo such file or directory, iov_len25}, {iov_base\n, iov_len1}], 10./bin/main: error while loading shared libraries: liba.so: cannot open shared object file: No such file or directory ) 117 exit_group(127) ? exited with 127 我们从输出结果可以知道动态链接器只加载/etc/ld.so.cache配置文件并没有加载/etc/ld.so.conf配置文件。因此我们需要通过ldconfig命令更新ld.so.cache文件内容。
如下 完结撒花~~~
系统默认路径 系统默认路径即系统存放动态库的地方一般为/lib、/usr/lib。我们只需要将动态库放到对应的路径下即可。 重新打开一个窗口执行如下命令运行 完结撒花~~~
总结 综上所述我们知道了动态链接库寻找动态库的四种方式其中: 系统默认路径和/etc/ld.so.conf需要系统权限大部分情况是不能进行修改的。若有相应权限可以优先使用该方式。 环境变量LD_LIBRARY_PATH可以解决我们大部分场景比如引文中的第一个场景。但是它并不解决动态库重名的问题。比如引文中的第二个场景。这时我们就可以采用-Wl,-rpath 编译选项或chrpath修改可执行程序的rpath参数。 希望本文能够对您有所帮助还请三连表示支持哦~~~