c++ - 关于编译和链接 C++ 文件时的 -ldl 标志

标签 c++ linux c++11 dynamic-linking

引用以下代码

test_linker.cpp

int main() {

    srand(time(0));
    for (int i = 0; i < 10; ++i) {
        cout << rand() % 10 << endl;
    }

    return 0;
}

urandom.cpp

#include <iostream>
using std::cout;
using std::endl;
#include <dlfcn.h>

int rand() throw() {

    // get the original rand() function
    static auto original_rand = (decltype(&rand)) dlsym(RTLD_NEXT,"rand");

    cout << "Call made to rand()" << endl;
    return original_rand();
}

当我尝试使用以下命令编译代码时

g++ -std=c++11 -Wall -Werror -Wextra -Wvla -pedantic -O3 urandom.cpp -c
g++ -std=c++11 -Wall -O3 test_linker.cpp urandom.o -ldl

一切正常,但是当我将 -ldl 标志移动到文件之前时,链接器会抛出一条错误消息说

urandom.cpp:(.text+0xaf): undefined reference to `dlsym'

问题 1 有人可以解释为什么会发生这种情况吗?我通常不关心编译命令中标志的顺序。

问题 2 另外,将指向原始 rand() 函数的函数指针保持为静态变量是否错误?我不知道动态链接究竟是如何工作的,我担心函数地址可能会在运行时在内存中移动。手册页说带有 RTLD_NEXT 句柄的 dlsym() 函数是一项昂贵的计算,所以我只想懒惰地评估一次。

注意:我在 Linux 发行版上编译它并且涉及 Linux 动态链接器,所以我将继续并用 Linux 标记它。

最佳答案

-ldl 是链接器的库名称。它告诉链接器查找并链接名为 libdl.so(或有时为 libdl.a)的文件。它与在命令行的相同位置放置相关库的完整路径具有相同的效果。

命令行上的库和对象顺序很重要。通常,如果库 A 调用库 B,则在命令行中 B 应放在 A 之后。所有库通常都应该在所有目标文件之后。这在几个 SO 问题和答案中被广泛涵盖,例如 this one .

至于第二个问题,不,一个函数的地址在运行时不会改变,除非你dlopen一个共享库,然后卸载它,然后dlopen再次。在您的情况下,由于您没有 dlopen 库,因此将函数地址保存在静态变量中是安全的。当然,如果您运行多个线程,则需要以某种方式确保线程安全(将其互斥,或使用线程本地存储)。

关于c++ - 关于编译和链接 C++ 文件时的 -ldl 标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35324324/

相关文章:

c++ - 由于哪个版本的 GCC 支持 C++14?

linux - `!:-` 是做什么的?

c++ - 将类型名称和值与模板包扩展混合

c++ - 合并两个具有重叠键的 unordered_maps

c++ - 错误 : passing ‘const string {aka const std::__cxx11::basic_string<char>}’ as ‘this’ argument

C++ 如何避免 dynamic_casting?

c++ - 默认初始化 boost::optional

c++ - 在另一个文件中引用 C++ 结构对象?

linux - 如何在ansible中使用yum模块禁用所有存储库?

linux - 重置 bash 历史搜索位置