【问题标题】:How does calling a function from a shared library work?从共享库调用函数是如何工作的?
【发布时间】:2020-02-22 14:55:47
【问题描述】:

当您在运行前加载共享库,并将它提供的符号(即函数)添加到全局偏移表中。

当你调用它提供的函数时会发生什么?因为你已经编译了你的代码,所以函数必须已经指向某个地方。

【问题讨论】:

  • 共享库中的函数是在链接时加载的,而不是在运行时加载的。链接器将函数名称替换为偏移值。设置最终地址的加载时间,因此当代码运行时,它所看到的只是跳转/调用的地址

标签: linux c c++ shared-libraries linker


【解决方案1】:

假设您有一个项目hello,其中包含以下文件:

  • main.cpp
  • function.cpp
  • class.cpp

现在您想使用g++ 构建项目。构建过程将如下所示:

----------------      -------      --------------        -------------
| function.cpp | ---> | g++ | ---> | function.o |        | libstdc++ |
----------------      -------      --------------        -------------
                                                 \      /
------------          -------      ----------     ------      ---------
| main.cpp | -------> | g++ | ---> | main.o | --> | ld | ---> | hello |
------------          -------      ----------     ------      ---------
                                                 /
-------------         -------      -----------  /
| class.cpp | ------> | g++ | ---> | class.o | /
-------------         -------      -----------

这里的g++ 是一个编译器,它将你的源文件一个一个地编译成一个目标文件。它只检查语法错误、未定义的函数或变量。尽管cpp(C 预处理器)在编译器之前执行,但这是另一个主题。编译完所有源文件后,ld(即链接器)会将您的目标文件链接到一个可执行文件中。现在,假设 main.cpp 调用名为 hello-function 的函数,在 function.cpp 中实现,并使用 std::cout,定义 libstdc++(C++ 标准库)。当代码有效时,编译器将main.cpp 编译为目标文件。当所有目标文件通过链接器时,它将读取这些对象并找到引用的函数和变量。如果您不将 function.o (其中包含 hello-function 实现)传递给链接器,您将收到一条错误消息 undefined reference 。现在,假设main.cpp 调用了一个外部库中可用的函数。如果您没有为链接器指定库,它将显示 undefined reference 。 当没有错误时,链接器将所有目标文件链接到一个可执行文件中,并放入有关生成的可执行文件所依赖的共享库的信息。

在你的程序编译链接后,你就可以执行程序了。当您执行它时,您的操作系统(在本例中为 Linux)将可执行文件加载到内存中。之后,它读取文件并确定它需要哪些库,如果尚未加载,则加载它们。然后它执行程序,当它找到对外部库的引用时,它会将引用转换为实际内存位置并调用它。程序完成执行后,您的操作系统会释放未使用的内存并卸载所有未使用的库。

此外,如果您的程序链接到的共享库的版本与您的程序在链接阶段链接的版本不同,您可能会收到“segmentation fault”。

【讨论】:

    猜你喜欢
    • 2011-02-02
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 2021-03-22
    • 2016-10-18
    • 1970-01-01
    相关资源
    最近更新 更多