g++链接动态库写foo.so和./foo.so为何前者运行报加载错误?
差异原因分析
链接阶段对两种参数的处理差异
当你给链接器传入**不带路径的foo.so时,链接器会将其判定为「按名称搜索的共享库」,最终只会将纯文件名foo.so写入可执行文件的DT_NEEDED元数据字段,不会保留任何路径信息。
当你传入带相对路径的./foo.so**时,链接器会将其判定为「指定路径的共享库文件」,会将完整的相对路径字符串./foo.so写入DT_NEEDED字段。运行时动态链接器的搜索逻辑差异
动态链接器加载可执行文件时,会读取DT_NEEDED字段的内容来查找依赖:- 如果字段内容是纯文件名
foo.so,动态链接器只会按优先级搜索系统默认路径:/lib、/usr/lib、LD_LIBRARY_PATH环境变量指定的路径、ldconfig缓存路径。当前工作目录默认不在搜索列表中,因此会抛出找不到库的错误。 - 如果字段内容是带路径的
./foo.so,动态链接器会直接按照路径(相对路径是相对于执行a.out时的当前工作目录)查找文件,此时foo.so和a.out在同一目录下,因此能正常找到。
- 如果字段内容是纯文件名
你可以通过readelf -d a.out | grep NEEDED命令查看两种编译方式生成的可执行文件的依赖字段差异,就能直观看到不同。
注意:用
./foo.so的方式只适合你在和foo.so同目录下运行a.out的场景,如果你切换到其他目录执行a.out,相对路径会基于你当前的工作目录计算,依然会找不到库。如果需要更稳定的同目录依赖查找,可以在链接时加参数-Wl,-rpath='$ORIGIN',指定动态链接器优先在a.out自身所在的目录查找共享库。
内容的提问来源于stack exchange,提问作者Tiina
相关产品推荐
相关产品推荐

