如何从共享库中导出符号

时间:2009-04-16 13:40:58

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

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

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

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

所以我的问题是:

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

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

  3. 静态库是如何工作的,即静态库如何解决规范和解决问题?

3 个答案:

答案 0 :(得分:12)

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

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

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

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

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

答案 1 :(得分:3)

  1. 您无需使用gcc导出符号,因为它默认导出所有符号;然而,RVDS可能会也可能不会这样做。检查您的RVDS编译器文档(尝试将其配置为“Relocatable ELF”输出?)

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

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

  4. 我唯一的猜测是,不知何故,编译器推出的代码在运行时无法重定位。对我来说,如果不破坏静态库,如何发生这种情况仍然是一个谜,但是......

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

    gcc -shared -o libfoo.so libfoo.a
    

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

答案 2 :(得分:0)

你知道发生撞车的原因吗?

如果您动态加载共享库(例如,通过dlopen()),一种可能性是假设库没有加载,然后尝试通过空指针执行函数。< / p>