【问题标题】:How to export symbols from a shared library如何从共享库中导出符号
【发布时间】:2009-04-16 13:40:57
【问题描述】:

我使用 Windows 主机上的 RVDS 编译器使用 *.o 目标代码文件(C 源代码)创建了一个共享库 (*.so)。

我将这个共享对象与一个应用程序(在 Linux 主机上使用gcc 用于 ARM 目标)链接并获得一个可执行文件,该可执行文件在运行时会产生分段错误。 (我知道我必须调试它!)

如果我不是创建共享库,而是创建一个具有相同源文件的静态库,然后与应用程序链接,然后执行应用程序,它会按预期工作。

所以我的问题是:

  1. 我是否需要在我的源文件中使用某些结构明确地导出符号(导出到应用程序的函数)或任何其他符号,以便在与应用程序链接时能够正常工作?需要什么?我该怎么做?

  2. 共享库是如何工作的?即,函数将被加载和运行的地址,将在创建库时在库中给出。应用程序(main())如何解析要执行库函数的地址?

  3. 静态库是如何工作的,即在静态库的情况下,这个地址规范和解析是如何发生的?

【问题讨论】:

    标签: linux shared-libraries arm cross-compiling rvds


    【解决方案1】:

    这就是它在 linux 上的工作方式:

    1) 不,你不需要做任何事情。但是,您可以使用 gcc -fvisibility 命令行参数限制导出变量,并使用可见性属性显式标记导出的条目。

    2) 可执行文件将有一个它导入的所有函数的表(这些都是具有默认可见性的函数)。加载器/链接器将在运行之前选择一个地址来加载库并填充此表,对这些函数的调用是间接调用。 (请注意,这也适用于共享对象)

    3) 静态链接在链接时执行(在您编译之后)。实际地址在程序集中被替换,它们是直接调用。

    注意:有一种叫做 PIC(位置无关代码)的东西。 AFAIK,这处理对同一共享对象中的数据/函数的引用,因此链接器在加载库时不需要覆盖库的一半代码,因为代码不会对其进行任何绝对引用自己的数据。你可以尝试一下。

    【讨论】:

      【解决方案2】:
      1. 你不需要用gcc导出符号,因为它默认导出所有符号;但是,RVDS 可能会也可能不会这样做。检查您的 RVDS 编译器文档(尝试将其配置为 'Relocatable ELF' 输出?)

      2. Linux 上的共享库必须是可重定位的,因为基地址是在运行时确定的。生成与位置无关的代码是理想的,因为它减少了重新定位库所需的工作量。如果您的库不可重定位,它崩溃(换句话说,在创建动态库之前不要从目标文件中删除重定位信息)。选择基地址并重新定位内部引用后,符号会在运行时解析为地址。

      3. 对于静态库,所有符号解析、重定位和加载地址分配都在编译时发生。

      我唯一的猜测是,编译器输出的代码在运行时是不可重定位的。不过,在不破坏静态库的情况下如何实现这对我来说是个谜……

      如果您直接从 RVDS 生成静态库和共享库,一种选择是尝试将该静态库转换为共享库:

      gcc -shared -o libfoo.so libfoo.a
      

      如果这有帮助,那么 RVDS 的共享库链接器(或其配置)可能已损坏。

      【讨论】:

        【解决方案3】:

        你知道崩溃的原因吗?

        如果您正在动态加载共享库(例如通过dlopen()),一种可能性是您假设库加载正常,而实际上没有加载,然后尝试通过空指针执行函数。

        【讨论】:

        • @Jonathan:我没有使用 dlopen() 调用加载共享库。
        • 好的 - 我没有主意了。我比较熟悉 Unix/Linux;我可能会在那里提供更多帮助。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-03-22
        • 2012-03-27
        • 1970-01-01
        • 2013-11-30
        • 1970-01-01
        • 2010-11-17
        相关资源
        最近更新 更多