【问题标题】:Undefined reference to error when .so libraries are involved while building the executable在构建可执行文件时涉及 .so 库时对错误的未定义引用
【发布时间】:2020-05-10 18:08:35
【问题描述】:

我有一个.so 库,在构建它时我没有收到任何未定义的引用错误。 但是现在我正在使用.so 文件构建一个可执行文件,我可以在链接阶段看到未定义的引用错误,如下所示:

xy.so:对 `MICRO_TO_NANO_ULL' 的未定义引用

我参考了thisthis,但无法真正理解动态链接。

同样阅读here 会导致更多混乱:

动态链接是通过放置可共享的名称来完成的 可执行映像中的库。与图书馆的实际链接 在映像运行之前,例程不会发生,当两个 可执行文件和库被放置在内存中。一个优势 动态链接是多个程序可以共享一个副本 图书馆。

我的问题是:

  • 不动态链接意味着当我使用启动可执行文件时 ./executable_name 然后如果链接器无法找到 .so 它应该崩溃的可执行文件依赖于哪个文件?

  • 如果所有外部实体引用都是 在构建时解决?是动态链接器执行的某种预检查吗?别的 动态链接器可以利用 LD_LIBRARY_PATH 获取额外的库来解决未定义的问题 符号。

【问题讨论】:

  • 投票支持关闭问题的人 - 请发布一个链接,以便我阅读相关内容,我将自己删除该问题。
  • 您确实应该发布您观察到的链接器错误。
  • @YugSingh “请编辑问题以将其限制为具有足够详细信息的特定问题,以确定适当的答案。避免一次提出多个不同的问题。请参阅如何提问页面以帮助澄清此问题。” -- “需要专注”的密切原因
  • @S.S.Anne 我觉得这些问题是相关的,并且在尝试理解动态链接时发生在我身上。这就是为什么我将它们作为同一问题的一部分发布。感谢您的建议。
  • @Ctx 我添加了链接器错误。感谢您的建议。

标签: c gcc ld dynamic-linking .so


【解决方案1】:

动态链接是否意味着当我使用 ./executable_name 启动可执行文件时,如果链接器无法找到可执行文件所依赖的 .so 文件,它应该会崩溃吗?

不,链接器将退出并显示“没有这样的文件或目录”消息。

想象一下:

  • 您的可执行文件在某处存储了它需要的共享库列表。
  • 链接器,把它当成一个普通的程序吧。
  • 链接器打开您的可执行文件。
  • 链接器读取此列表。对于每个文件。
    • 它试图在链接器路径中找到该文件。
    • 如果找到文件,它会“加载”它。
    • 如果找不到文件,它会从open() 调用中获取errnoNo Such file or directory。然后打印一条找不到库的消息并终止您的可执行文件。
  • 运行可执行文件时,链接器会动态搜索共享库中的符号。
    • 当它找不到符号时,它会打印一些消息并且可执行文件终止。

例如,您可以设置LD_DEBUG=all 来检查链接器在做什么。您还可以检查strace 下的可执行文件,以查看所有open 调用。

如果所有外部实体引用都已解决,那么动态链接实际上是什么? 建筑?

动态链接是当您运行可执行文件时,链接器会加载每个共享库。

在构建时,您的编译器会检查您在程序中使用的所有符号是否存在于共享库中。这只是为了安全。例如,您可以使用 ex 禁用此检查。 --unresolved-symbols=ignore-in-shared-libs.

它是由动态链接器执行的某种预检查吗?

是的。

其他动态链接器可以利用 LD_LIBRARY_PATH 来获取其他库来解析未定义的符号。

LD_LIBRARY_PATH 只是一个逗号分隔的路径列表,用于搜索共享库。 LD_LIBRARY_PATH 中的路径仅在标准路径之前处理。就这样。它没有“额外的库”,它有额外的路径来搜索库 - 库保持不变。

【讨论】:

  • 您在顶部描述的是未找到 动态链接器本身 的情况。如果仅找不到共享库或单个符号,则错误消息会有所不同。
  • 不应该像上一段中提到的When building, your compiler is kind enough to check for you, that all symbols that you use in your program exist in shared libraries. 那样对Is it some sort of pre-check performed by dynamic linker? 的答案是吗?在这个问题中,我仍然指的是我们在构建可执行文件时遇到的未定义引用错误。
【解决方案2】:

在您编译共享库时,似乎缺少 #define。这个错误

xy.so:对 `MICRO_TO_NANO_ULL' 的未定义引用

意思是像

#define MICRO_TO_NANO_ULL(sec) ((unsigned long long)sec * 1000)

应该存在,但不存在。

然后编译器假定它是一个外部函数并为它创建一个(未定义的)符号,而它应该在编译时由预处理器宏解析。

如果您包含正确的文件(宏名称为 grep)或在源文件顶部放置适当的定义,则链接器错误应该会消失。

【讨论】:

    【解决方案3】:

    动态链接不是意味着当我使用./executable_name 启动可执行文件时,如果链接器无法找到可执行文件所依赖的.so 文件,它应该崩溃吗?

    是的。如果.so 文件在运行时不存在。

    如果在构建时解析了所有外部实体引用,那么动态链接究竟是什么?是动态链接器执行的某种预检查吗?其他动态链接器可以利用LD_LIBRARY_PATH 获取额外的库来解析未定义的符号。

    它允许升级库并让应用程序仍然能够使用该库,它通过加载一个库副本而不是在每个使用它的应用程序中加载一个副本来减少内存使用量。

    链接器只是创建对这些符号的引用,以便以后可以使用底层变量或函数。它不会将变量和函数直接链接到可执行文件中。

    动态链接器不会拉入任何库,除非在可执行文件中指定了这些库(或扩展为可执行文件所依赖的任何库)。如果您为LD_LIBRARY_PATH 目录提供的.so 文件的版本与可执行文件所需的版本完全不同,则可执行文件可能会崩溃。


    在您的情况下,似乎没有找到所需的宏定义并且编译器正在使用隐式声明规则。您可以通过使用 -pedantic -pedantic-errors 编译代码轻松解决此问题(假设您使用的是 GCC)。

    【讨论】:

    • If the linker wouldn't require the symbols to link then the dynamic linker would just fail at run-time and there's no point in that, as then software would build correctly and not run correctly. 如果链接器需要在构建时 链接符号,则它不是动态链接。如果我错了,请纠正我。
    • 这是强制链接器创建对应用程序中使用的符号的引用还是可以绕过?询问它的原因是因为在运行时动态链接器可以利用LD_LIBRARY_PATH 来搜索符号。正如您在答案中提到的,可以更改参考。
    • @YugSingh 必填项。程序正确构建然后在运行时失败是很愚蠢的。 LD_LIBRARY_PATH 搜索 .so 文件。引用不能更改,只能更改底层函数或变量。
    【解决方案4】:

    动态链接不意味着当我使用启动可执行文件时 ./executable_name 然后如果链接器无法找到 .so 文件 它应该崩溃取决于哪个可执行文件?

    它会崩溃。崩溃的时间确实取决于您从 .so 文件调用某个导出函数的方式。 您可以使用 dlopen dlysm 和 co 自己通过函数指针检索所有导出的函数。在这种情况下,程序会在第一次调用时崩溃,以防找不到导出的方法。

    如果可执行文件只是从共享对象(它的标头的一部分)调用导出的方法,动态链接器会使用要在其可执行文件中调用的方法的信息(参见第二个答案)并在找不到的情况下崩溃lib 或符号不匹配。

    如果在构建时解析了所有外部实体引用,那么动态链接实际上是什么?是动态链接器执行的某种预检查吗?其他动态链接器可以利用 LD_LIBRARY_PATH 来获取额外的库来解析未定义的符号。

    您需要区分实际链接和动态链接。从实际链接开始: 在链接静态库的情况下,实际链接将复制方法中的所有代码,以使用它在可执行文件/库中调用。 链接动态库时,您不会复制代码,而是复制符号。符号包含指向动态库中实际代码的偏移量或其他信息。如果可执行文件确实调用了动态库未导出的方法,则它在实际链接部分已经失败。

    现在,当启动您的可执行文件时,操作系统会在某个时候尝试将共享对象加载到代码实际驻留的内存中。如果找不到它或者它是不可复制的(即:可执行文件链接到使用不同导出的库),它可能仍会在运行时失败。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-13
      • 2013-04-09
      • 2021-11-06
      相关资源
      最近更新 更多