2009-04-16 78 views
5

我已经使用windows主机上使用RVDS编译器的* .o目标代码文件(C源代码)创建了共享库(* .so)。如何从共享库中导出符号

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

代替创建共享库,如果我使用相同的源文件创建一个静态库,然后链接到应用程序,然后执行该应用程序,它可以正常工作。

所以我的问题是: -

  1. 我是否需要使用一些结构,从而使得它工作正常出口(出口到应用功能)符号或其它任何标志,明确地说,在我的源文件链接时与应用程序?需要什么,我该怎么做?

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

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

谢谢。

回答

11

这是它如何在Linux上工作:

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

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

3)静态链接在链接时执行(即在编译之后)。实际地址在组件中被替换,并且它们是直接调用。

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

0

你知道坠机原因吗?

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

+0

@Jonathan:我没有使用dlopen加载共享库()调用。 – goldenmean 2009-05-25 11:53:20

3
  1. 你并不需要与gcc出口的符号,因为它出口的所有符号默认;但是,RVDS可能会也可能不会这样做。检查您的RVDS编译器文档(尝试将其配置为'Relocatable ELF'输出?)

  2. 在Linux共享库必须是可重定位的,作为基地址是在运行时确定的。生成与位置无关的代码是理想的,因为它减少移居库所需要的工时量。如果你的库没有重定位它崩溃(换句话说,不从你的目标文件进行动态库之前剥离重定位信息)。在选择基地址并重新定位内部参考之后,符号在运行时解析为地址。

  3. 对于静态库,所有符号,搬迁,和负载分配地址的情况发生在编译时。

我唯一的猜测就是不知何故,编译器发出的代码在运行时不可重定位。对我来说,如何在不破坏静态库的情况下实现这个目标是个谜,尽管如此...

如果您直接从RVDS生成静态库和共享库,那么一个选择是尝试将该静态库到共享库:

gcc -shared -o libfoo.so libfoo.a 

如果这会有所帮助,那么RVDS的共享库连接体(或它的配置)很可能打破。