背景
使用gcc8.2编译a.out,机器安装默认的版本为gcc3.4。使用ldd打印so依赖列表,此时libstdc++.so位于/usr/lib64目录下
打印程序运行时加载的so库列表,显示加载的是/home/xxx/gcc-8.2/lib/目录下的libstdc++.so
使用默认版本编译的程序,运行时加载的时/usr/lib64目录下的libstdc++库
此时的环境变量LD_LIBRARY_PATH未设值
分析()
对比两个进程ldd的结果,可以看到ld-linux-x86-64.so.2是不一样的。加载器的路径是gcc写入到二进制文件中的,可以通过命令strings查看这个路径。修改gcc的spec文件可以重新指定加载器路径。
使用strings 查看两个ld-linux-x86-64.so的内容,可以看到内置的加载路径信息
环境中/opt/comiler/gcc-8.2其实指向/home/xxx/gcc-8.2的符号链接
动态库查找顺序
编译时,ld-linux.so查找共享库的顺序:
- ld-linux.so由gcc的spec文件中所设定
- gcc --print-search-dirs所打印出的路径,主要是libgcc_s.so等库。可以通过GCC_EXEC_PREFIX来设定
- LIBRARY_PATH环境变量中所设定的路径,或编译的命令行中指定的-L/usr/local/lib
- binutils中的ld所设定的缺省搜索路径顺序,编译binutils时指定。(可以通过“ld --verbose | grep SEARCH”来查看)
- 二进制程序的搜索路径顺序为PATH环境变量中所设定。一般/usr/local/bin高于/usr/bin
- 编译时的头文件的搜索路径顺序,与library的查找顺序类似。一般/usr/local/include高于/usr/include
运行时,ld-linux.so查找共享库的顺序:
- ld-linux.so在可执行的目标文件中被指定,可用readelf命令查看
- 在ld-linux.so内置的lib路径下查找(猜的)
- 在缺省/usr/lib和lib中搜索;当glibc安装到/usr/local下时,它查找/usr/local/lib
- LD_LIBRARY_PATH环境变量中所设定的路径
- /etc/ld.so.conf(或/usr/local/etc/ld.so.conf)中所指定的路径,由ldconfig生成二进制的ld.so.cache中
查看最终运行时加载的库
ld-linux.so加载器其实是个可执行程序,使用--list选项可以得到与ldd类似的结果,不过这个输出更加接近运行时的结果(还可以通过修改环境变量改变)。