如何从共享库中导出符号

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

我把这个共享对象与一个应用程序(在Linux主机上使用gcc for arm target)连接起来,并获得一个可执行文件,在运行时产生分段错误(我知道我必须debugging它!

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

所以我的问题是:

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

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

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

谢谢。

这是如何工作在Linux上:

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

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

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

注:有一个叫做PIC(位置独立码)的东西。 AFAIK,这涉及到在同一个共享对象中的数据/函数的引用,所以当加载库时,链接器不需要覆盖库的一半代码,而代码并没有对其进行任何绝对引用自己的数据。 你可以试着去尝试一下。

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

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

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

我唯一的猜测就是,不知何故,编译器发出的代码在运行时不可重定位。 这对我来说是一个谜,如果没有打破静态库,

如果您直接从RVDS生成静态库和共享库,则可以尝试将该静态库转换为共享库:

 gcc -shared -o libfoo.so libfoo.a 

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

你知道坠机的原因吗?

如果你动态地加载共享库(例如,通过dlopen() ),一种可能性是你假设库在没有的时候加载了OK,然后试图通过空指针来执行函数。