Linux 动态库 undefined symbol 原因定位与解决方法

2023-05-16

在使用动态库开发部署时,遇到最多的问题可能就是 undefined symbol 了,导致这个出现这个问题的原因有多种多样,快速找到原因,采用对应的方法解决是本文写作的目的。

可能的原因

  1. 依赖库未找到
    这是最常见的原因,一般是没有指定查找目录,或者没有安装到系统查找目录里
  2. 链接的依赖库不一致
    编译的时候使用了高版本,然后不同机器使用时链接的却是低版本,低版本可能缺失某些 api
  3. 符号被隐藏
    如果动态库编译时被默认隐藏,外部代码使用了某个被隐藏的符号。
  4. c++ abi 版本不一致
    最典型的例子就是 gcc 4.x 到 gcc 5.x 版本之间的问题,在 4.x 编辑的动态库,不能在 5.x 中链接使用。

解决方法

  1. 依赖库未找到
  • 使用 ldd -r , 确定系统库中是否存在所依赖的库
  • 执行 ldconfig 命令更新 ld 缓存
  • 执行 ldconfig -p | grep {SO_NAME} 查看是否能找到对应的库
  • 检查 LD_LIBRATY_PATH 是否设置了有效的路径
  1. 链接的库版本不一致
    如果系统中之前有安装过相同的库,或者存在多个库,就需要确定链接的具体是哪个库

有一个特殊场景需要注意下,.so 文件中有个默认 rpath 路径,用于搜索被依赖的库,这个路径优先于系统目录和LD_LIBRARY_PATH。假如 rpath 存在相同名字的 .so 文件,会优先加载这个路径的文件。

在遇到 undefined symbol 问题时,使用 readelf -d | grep rpath 查看:

$ readelf -d libSXVideoEngineJni.so | grep rpath
 0x000000000000000f (RPATH)              Library rpath: 
 [/home/slayer/workspace/SXVideoEngine-Core/Render/cmake-build-
 debug:/home/slayer/workspace/SXVideoEngine-Core/Render/../../SXVideoEngine-Core-Lib/blend2d/linux/lib]

如果存在的路径中有相应的库,可以先重命名文件再测试确认。

关于连接时的顺序可以查看文档: http://man7.org/linux/man-pages/man8/ld.so.8.html

    If a shared object dependency does not contain a slash, then it is
   searched for in the following order:

   o  Using the directories specified in the DT_RPATH dynamic section
      attribute of the binary if present and DT_RUNPATH attribute does
      not exist.  Use of DT_RPATH is deprecated.

   o  Using the environment variable LD_LIBRARY_PATH, unless the
      executable is being run in secure-execution mode (see below), in
      which case this variable is ignored.

   o  Using the directories specified in the DT_RUNPATH dynamic section
      attribute of the binary if present.  Such directories are searched
      only to find those objects required by DT_NEEDED (direct
      dependencies) entries and do not apply to those objects' children,
      which must themselves have their own DT_RUNPATH entries.  This is
      unlike DT_RPATH, which is applied to searches for all children in
      the dependency tree.

   o  From the cache file /etc/ld.so.cache, which contains a compiled
      list of candidate shared objects previously found in the augmented
      library path.  If, however, the binary was linked with the -z
      nodeflib linker option, shared objects in the default paths are
      skipped.  Shared objects installed in hardware capability
      directories (see below) are preferred to other shared objects.

   o  In the default path /lib, and then /usr/lib.  (On some 64-bit
      architectures, the default paths for 64-bit shared objects are
      /lib64, and then /usr/lib64.)  If the binary was linked with the
      -z nodeflib linker option, this step is skipped.

符号被隐藏

第三方已经编译好的库,在引入了对应的头文件,使用了其中的某个方法,最终链接的时候出现 undefined symbol,这种情况有可能是库的开发者并没有导出这个方法的符号。

# 使用 nm 命令查看导出的函数符号, 这里查看 License 相关的函数
$ nm -gDC libSXVideoEngineJni.so | grep -i license
0000000000008110 T __ZN13SXVideoEngine6Public7License10SetLicenseEPKc
0000000000008130 T __ZN13SXVideoEngine6Public7License13LicenseStatusEv
0000000000008190 T __ZN13SXVideoEngine6Public7License19IsVideoCutSupportedEv
0000000000008170 T __ZN13SXVideoEngine6Public7License26IsDynamicTemplateSupportedEv
0000000000008150 T __ZN13SXVideoEngine6Public7License26IsStadardTemplateSupportedEv

# nm 返回的并不是原始函数名,通过 c++filt 获取原始名称
$ c++filt __ZN13SXVideoEngine6Public7License10SetLicenseEPKc
SXVideoEngine::Public::License::SetLicense(char const*)

c++ Abi 版本不一致

Gcc 对 c++ 的新特性是一步一步的增加的,如果实现了新的特性,就可能会修改 c++ 的 abi,并且会升级 glibc 的版本。

Abi 链接最常见的错误是 std::string 和 std::list 的在gcc 4.x 和 gcc 5.x 的不同实现引起的。在gcc 4.x 时,gcc 对标准 string 的实现就放在 std 命名空间下,编译时展开为 std::basic_string 。但是 gcc 5.x 开始,对 string 的实现就放在了 std::__cxx11空间里,编译后展开为 std::__cxx11::basic_string 。这就会导致在 gcc 4.x 编译的动态库,假如有的函数使用了 string 作为参数或者返回值,这时导出的函数参数为 std::basic_string 类型。 无法在 gcc 5.x 下编译连接使用。
错误类似:

undefined symbol:  "std::__cxx11 ***"

这种情况有一个折中办法就是在gcc 5.x 或以上 编译时,增加 -D_GLIBCXX_USE_CXX11_ABI=0 禁用 c++11 abi。
当然最好的做法就是保证编译器大版本基本一致。在新开发的程序如果用到了 c++ 的新特性,升级 gcc 版本和 glibc 是十分必要的。

实用命令总结

  1. ldd 命令,用于查找某个动态库所依赖的库是否存在
# ldd -r <lib/excutable file> 
# 找不到的库会出现 not found
$ ldd -r libSXVideoEngine.so
        linux-vdso.so.1 =>  (0x00007ffc337d2000)
        libz.so.1 => /lib64/libz.so.1 (0x00007f061cf41000)
        libX11.so.6 => /lib64/libX11.so.6 (0x00007f061cc03000)
        libEGL.so.1 => /lib64/libEGL.so.1 (0x00007f061c9ef000)
        libGLESv2.so.2 => /lib64/libGLESv2.so.2 (0x00007f061c7dd000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f061c5c1000)
        libblend2d.so => /home/seeshion/workspace/SXVideoEngine-Core/Render/../../SXVideoEngine-Core-Lib/blend2d/linux/lib/libblend2d.so (0x00007f061c187000)
        libfreeimage.so.3 => /lib/libfreeimage.so.3 (0x00007f061b8ac000)
        libavcodec.so.58 => /lib/libavcodec.so.58 (0x00007f06198b6000)
        libavformat.so.58 => /lib/libavformat.so.58 (0x00007f06193e1000)
        libavutil.so.56 => /lib/libavutil.so.56 (0x00007f06190bd000)
        ...
        
  1. nm 命令,用于读取库被导出的符号
$ nm -gDC libSXVideoEngineJni.so | grep -i license
0000000000008110 T __ZN13SXVideoEngine6Public7License10SetLicenseEPKc
0000000000008130 T __ZN13SXVideoEngine6Public7License13LicenseStatusEv
0000000000008190 T __ZN13SXVideoEngine6Public7License19IsVideoCutSupportedEv
0000000000008170 T __ZN13SXVideoEngine6Public7License26IsDynamicTemplateSupportedEv
0000000000008150 T __ZN13SXVideoEngine6Public7License26IsStadardTemplateSupportedEv

  1. readelf 用于读取 elf 文件的相关信息
$ readelf -d libSXVideoEngineJni.so | grep rpath
 0x000000000000000f (RPATH)              Library rpath: 
 [/home/slayer/workspace/SXVideoEngine-Core/Render/cmake-build-
 debug:/home/slayer/workspace/SXVideoEngine-Core/Render/../../SXVideoEngine-Core-Lib/blend2d/linux/lib]
  1. c++filt 用于获取符号的原始名
$ c++filt __ZN13SXVideoEngine6Public7License10SetLicenseEPKc
SXVideoEngine::Public::License::SetLicense(char const*)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux 动态库 undefined symbol 原因定位与解决方法 的相关文章

  • 使用python把普通图片生成ico图标

    文章目录 xff1a 1 使用在线网站生成ico图标2 使用python的库包PythonMagick生成ico图片2 1 安装PythonMagick2 2 使用PythonMagick生成ico图片代码 1 ico是Iconfile的缩
  • windows上比较好用的截图软件+Gif录制软件+看图软件,建议收藏!

    文章目录 xff1a 1 windows10上比较好用的截图软件1 1 windows10自带的截图方式1 1 1 快捷键win 43 shift 43 s1 1 2 PrintScreen键截图1 1 3 win 43 PrintScre
  • 在Edge浏览器中登录微软账户报错:0x80190001错误

    1 错误可能原因 之所以会出现登录微软账户报错 xff0c 很有可能是因为Clash xff08 你懂得 xff09 2 解决方式 1 下载一个finder xff08 抓包软件 xff09 xff08 参考 xff09 finder官网下
  • 加入bing体验chatGPT大军中来吧,它来了!

    1 第一步 xff1a 加入候选名单 1 首先需要加入候选名单 https www microsoft com zh cn edge form 61 MA13FJ 2 下载最新的Edge浏览器 androd iOS都有试用版本 xff08
  • Qt6 CMake项目导入资源文件Resources 官方最简洁方法

    导入 xff1a https doc qt io qt 6 resources html build system integration 使用 xff1a source 34 qrc images close2x png 34
  • HTTP 系列(三)—— HTTP报文

    什么是 HTTP 报文 HTTP 报文是简单的格式化数据块 xff0c 通俗的说 xff0c 它是用于数据传输的文本字符串 每条报文都包含一条来自客户端的请求或者一条来自服务器的响应 xff0c 它们都由三个部分组成 xff1a 对报文进行
  • GET请求

    什么是GET请求 get请求其实就是通过URL来传递数据 一个标准的URL网址 xff0c 在最后有一个querystring部分 xff0c 表示对页面查询 xff0c 用 来表示这部分 xff0c 内容必须是k 61 v 对个参数用 a
  • nested exception is org.apache.ibatis.exceptions.TooManyResultsException: Expected one result

    文章目录 背景解决 背景 mybaitsPlus this baseMapper selectOne wrapper 查出多个结果 xff0c 抛出了异常 解决 getOne wrapper false ServiceImpl getOne
  • RARP的使用

    大家好呀 xff0c 我是请假君 xff0c 今天又来和大家一起学习数通了 xff0c 今天要分享的知识是RARP的使用 主机只知道自己的硬件地址时 xff0c 可以通过RARP Reverse Address Resolution Pro
  • 5 . 如何用c语言封装寄存器

    前面我们介绍了存储器映射 寄存器和寄存器映射 xff0c 这些都是为使用 C语言封装寄存器做铺垫 我们通过一个实例来对 C 语言封装寄存器进行介绍 实例 xff1a 控制 GPIOC 端口的第 0 管脚输出一个低电平 首先我们需要知道GPI
  • 干货收藏:68道C语言与C++常见面试题

    1 变量的声明和定义有什么区别 变量的定义为变量分配地址和存储空间 变量的声明不分配地址 一个变量可以在多个地方声明 但是只在一个地方定义 加入extern 修饰的是变量的声明 说明此变量将在文件以外或在文件后面部分定义 神级编程网站 堪称
  • 推荐几款好用的手机编程APP!

    各位 很多人现在喜欢用手机写代码 今天小编就带大家盘点几款手机端编程软件 程序员相关的海量资料 点击免费获取 1 C4droid 适用编程语言 C C 适用平台 Android 2 2 软件介绍 付费软件 国内免费 c4droid是款And
  • 精心为学弟学妹整理了60个适合练手的C语言/C++项目,值得收藏!

    前几天写这篇文章 精心为学弟学妹准备的C语言与C 学习路线 书籍 视频推荐和资料 值得收藏 阅读和收藏都挺多 也让我一周涨了3000多粉丝 在这里感谢大家关注支持我 最近很多粉丝朋友私信问一些学习路线的问题以及一些学习资源 一个一个回复有点
  • 如果编程语言是一门武功绝学

    nbsp 学习编程与武功绝学 武侠小说中 各路侠客绿林好汉都是从基本功开始一招一式学起 掌握了足够多的招式后 加之勤学苦练 量变引起质变 会有一天打开任督二脉顿悟出这些招式背后的哲学逻辑 成为一代宗师 在编程的学习过程中 我们何尝不是从一招
  • CSDN粉丝冲3万粉福利放送!C++、Python、数据结构与算法、计算机基础、数据库教程汇总!

    最近有粉丝问我要一些C Python 数据结构与算法 计算机基础 数据库的学习资料 一个一个回复有些慢 索性就写一篇文章吧 声明 此文章中涉及到的内容均来自网络 我看到比较好的才分享给大家 你们可以根据情况选择 程序员必备资源 值得收藏 点
  • C/C++框架和第三方库汇总

    根据读者反馈 xff0c 发现此篇汇总获赞率异常的高 xff0c 为了照顾一下新加入的粉丝 xff0c 故重新发一遍 xff0c 供粉丝查阅温习 值得学习的C语言开源项目 1 Webbench Webbench是一个在linux下使用的非常
  • C/C++动态检测内存错误利器 - ASan

    来自公众号 xff1a 大胖聊编程 作者 xff1a 大胖 ASan xff0c 即Address Sanitizer xff0c 是一个适用于c c 43 43 程序的动态内存错误检测器 xff0c 它由一个编译器检测模块 xff08 L
  • C++之虚函数和虚函数表

    哈喽大家好 最近开始学习计算机基础相关的面试内容 xff0c 比如C 43 43 算法与数据结构 计算机网络 操作系统 设计模式 数据库等 因此把学习时记的笔记分享给大家 xff0c 希望对大家有所帮助 今天分享的是C 43 43 中虚函数
  • 计算机大一新生,想卷却找不到方向,恳请前辈指指路?

    其实 xff0c 大学里面的课程就告诉你应该学什么 xff1f 先推荐三个非常不错的计算机科学学习的 Github 仓库 xff01 希望对大家有帮助 xff01 哭了哭了 xff01 如果我当时上大学的时候有人告诉我这些开源项目就好了 x
  • http cache-control 指令的设置以及意义

    转载地址 https developer mozilla org zh CN docs Web HTTP Headers Cache Control http www cnblogs com yuyii archive 2008 10 16

随机推荐