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

好奇:

参考以下代码

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()函数的函数指针保持为静态变量也是错误的吗?我不知道动态链接到底是如何工作的,恐怕函数地址可能会在运行时在内存中移动。手册页说dlsym()带有RTLD_NEXT句柄函数是一个昂贵的计算,所以我只想懒惰地评估一次。

注意:我正在Linux发行版上对此进行编译,并且涉及Linux动态链接器,因此我将继续在Linux上对其进行标记。

代词

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

命令行上的库和对象顺序确实很重要。通常,如果库A调用库B,则应在命令行中将B放在A之后。通常,所有库都应放在所有目标文件之后。这样的几个SO问答中对此进行了广泛讨论

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章