<span>动态库libXXX.so ldd命令</span>
##############
ldd查看程序依赖的依赖库:
[root@xxx ~]# ldd /usr/bin/mydumper /usr/bin/mydumper: /lib64/libc.so.6: version `GLIBC_2.28' not found (required by /usr/bin/mydumper) linux-vdso.so.1 => (0x00007ffe68d8c000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f39616aa000) libz.so.1 => /lib64/libz.so.1 (0x00007f3961494000) libm.so.6 => /lib64/libm.so.6 (0x00007f3961191000) librt.so.1 => /lib64/librt.so.1 (0x00007f3960f89000) libssl.so.1.1 => not found libcrypto.so.1.1 => not found libdl.so.2 => /lib64/libdl.so.2 (0x00007f3960d84000) libglib-2.0.so.0 => /lib64/libglib-2.0.so.0 (0x00007f3960a4d000) libgthread-2.0.so.0 => /lib64/libgthread-2.0.so.0 (0x00007f396084a000) libgio-2.0.so.0 => /lib64/libgio-2.0.so.0 (0x00007f39604ca000) libgobject-2.0.so.0 => /lib64/libgobject-2.0.so.0 (0x00007f396027a000) libpcre.so.1 => /lib64/libpcre.so.1 (0x00007f3960018000) libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f395fd11000) libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f395fafb000) libc.so.6 => /lib64/libc.so.6 (0x00007f395f739000) /lib64/ld-linux-x86-64.so.2 (0x000055d14c110000) libffi.so.6 => /lib64/libffi.so.6 (0x00007f395f531000) libgmodule-2.0.so.0 => /lib64/libgmodule-2.0.so.0 (0x00007f395f32d000) libselinux.so.1 => /lib64/libselinux.so.1 (0x00007f395f105000) libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f395eeeb000) [root@tj1-using-glc-db01 ~]# mydumper --version mydumper: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory
ldd原理和含义:
第一列:程序需要依赖什么库
第二列: 系统提供的与程序需要的库所对应的库
第三列:库加载的开始地址
通过上面的信息,我们可以得到以下几个信息: 通过对比第一列和第二列,我们可以分析程序需要依赖的库和系统实际提供的,是否相匹配
通过观察第三列,我们可以知道在当前的库中的符号在对应的进程的地址空间中的开始位置
如果依赖的某个库找不到,通过这个命令可以迅速定位问题所在; 原理: ldd不是个可执行程式,而只是个shell脚本; ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。ld-linux.so模块会先于executable模块程式工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执行模块的dependency。
1、动态库的概念。动态链接库与普通的程序相比而言,没有main函数,是一系列函数的实现。通过shared和fPIC编译参数生产so动态链接库文件。程序在调用库函数时,只需要连接上这个库即可。
2、动态库的优点。可以实现进程之间的资源共享。就是说,某个程序的在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。这样的模式虽然会带来一些“动态链接”额外的开销,却大大的节省了系统的内存资源。C的标准库就是动态链接库,也就是说系统中所有运行的程序共享着同一个C标准库的代码段。将一些程序升级变得简单。用户只需要升级动态链接库,而无需重新编译链接其他原有的代码就可以完成整个程序的升级。Windows 就是一个很好的例子。甚至可以真正坐到链接载入完全由程序员在程序代码中控制。 程序员在编写程序的时候,可以明确的指明什么时候或者什么情况下,链接载入哪个动态链接库函数。你可以有一个相当大的软件,但每次运行的时候,由于不同的操作需求,只有一小部分程序被载入内存。所有的函数本着“有需求才调入”的原则,于是大大节省了系统资源。比如现在的软件通常都能打开若干种不同类型的文件,这些读写操作通常都用动态链接库来实现。在一次运行当中,一般只有一种类型的文件将会被打开。所以直到程序知道文件的类型以后再载入相应的读写函数,而不是一开始就将所有的读写函数都载入,然后才发觉在整个程序中根本没有用到它们。编译时查找的是静态库或动态库,而运行时查找的只是动态库。gcc参数-L指定编译时的链接路径,-Wl,-rpath指定运行时链接路径。编译时使用环境变量LIBRARY_PATH指定库的路径,运行时使用环境变量LD_LIBRARY_PATH或/etc/ld.so.conf指定库的路径。编译时用的链接器是ld,而运行时用的链接器是/lib/ld-linux.so.2。编译时与运行时都会查找默认路径:/lib /usr/lib。编译时还有一个默认路径:/usr/local/lib,而运行时不会默认找查该路径。
3、动态库的创建。例如下面实现一个简单的整数四则运输的动态链接库,定义的caculate.h和caculate.c两个文件,生产libcac.so动态链接库。
定义库的头文件如下:
库中函数的实现如下:
4、动态库的使用方法之一。编写一个测试程序main.c调用此动态链接库的函数。编译生产可执行文件main如下:gcc main.c -o main -L ./ -lcac (其中-L指明动态链接库的路径,-l后是链接库的名称,省略lib)。
然后直接运行出现如下图,找不到动态库,说明这是运行时,命令main程序动态加载libcac.so库时没有找到,那么要么是系统不存在该文件,要么是存在该文件但是不在动态库的查找路径中。
解决办法。因为该动态库是老子亲手建立的,浪门可能不存在呢!所以只可能是可执行程序main没有找到动态库位置,因此设置动态库运行时。运行时使用的环境变量是LD_LIBRARY_PATH指定库的路径。如下图,问题得到解决。
5、动态库的使用方法之二。linux提供dlopen、dlsym、dlerror和dlcolose函数获取动态链接库的函数。通过这个四个函数可以实现一个插件程序,方便程序的扩展和维护。函数格式如下所示。
dlopen()是一个强大的库函数。该函数将打开一个新库,并把它装入内存。该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的。写个测试程序调用上面生产libcac.so库如下所示。
同样需要设置动态库查找路径。
当然如果在编译时就指定运行时的动态链接库路径也是可以的。如下图就是。
6、动态库一般都会加上版本号作为后缀。动态库命名规范。
7、可执行程序在执行的时候如何定位共享库(动态库)文件 。
8、查看一个可执行程序依赖的共享库。获取某个命令执行时需要依赖哪些动态库,如果有依赖库找不到,那么程序会无法正常运行。
# ldd 命令的绝对路径
9、动态库中的函数名查找。
10、动态库的升级。
10、