Linux 如何从共享库导出符号

Linux 如何从共享库导出符号,linux,shared-libraries,arm,cross-compiling,rvds,Linux,Shared Libraries,Arm,Cross Compiling,Rvds,我在Windows主机上使用RVDS编译器,使用对象代码文件(C源代码)创建了一个共享库(*.so) 我将这个共享对象与一个应用程序链接(在Linux主机上为ARM目标使用gcc)并获得一个可执行文件,该文件在运行时会生成分段错误。(我知道我必须调试它!) 与创建共享库不同的是,如果我创建一个具有相同源文件的静态库,然后链接应用程序,然后执行应用程序,那么它就可以正常工作 因此,我的问题是: 我是否需要在源文件中使用一些构造明确地导出符号(导出到应用程序的函数)或任何其他符号,以便在与应用程序链

我在Windows主机上使用RVDS编译器,使用对象代码文件(C源代码)创建了一个共享库(
*.so

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

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

因此,我的问题是:

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

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

  • 静态库是如何工作的,即在静态库的情况下,该地址规范和解析是如何发生的


  • 以下是它在linux上的工作方式:

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

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

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


    注意:有一个叫做PIC(位置独立代码)的东西。顺便说一句,这涉及到对同一共享对象中的数据/函数的引用,因此链接器在加载库时不需要覆盖库的一半代码,因为代码不会对自己的数据进行任何绝对引用。你可以试试看。

    你知道车祸的原因吗

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

  • 您不需要使用
    gcc
    导出符号,因为默认情况下它会导出所有符号;然而,差饷物业估价署可能会,也可能不会这样做。检查您的RVDS编译器文档(尝试将其配置为“”输出?)

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

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

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

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

    gcc -shared -o libfoo.so libfoo.a
    

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

    @Jonathan:我没有使用dlopen()调用加载共享库。好的-我没有主意了。我更熟悉Unix/Linux;我可能会在那里得到更多帮助。