LD_PRELOAD 使用 gcc 或 g++ 编译 .so

LD_PRELOAD compile .so using gcc or g++

我有一个套接字 API 的包装器,我在应用程序之前使用 LD_PRELOAD 预加载了它。但是,当我使用 g++ 编译我的 .so 包装器库时,它不起作用,即,glibc 版本的套接字实现被 picketd 代替。

这是我编译包装器 .so 库(其中之一)的方式:

gcc -Wall -fPIC -shared socket_hooks.c -o socket_hooks.so
or
g++ -Wall -fPIC -shared socket_hooks.c -o socket_hooks.so

这就是我编译和 运行 我的 udp 客户端的方式:

g++ -Wall udp_client.cpp  -o udp_client
LD_PRELOAD=./socket_hooks.so ./udp_client

现在,当我启用调试(导出 LD_DEBUG=all)和 运行 以及使用 gcc(工作版本)编译示例编译的 .so 时,我看到了:

 17278: symbol=socket;  lookup in file=./udp_client [0]
 17278: symbol=socket;  lookup in file=./socket_hooks.so [0]
 17278: binding file ./udp_client [0] to ./socket_hooks.so [0]: normal symbol `socket' [GLIBC_2.2.5]

当我使用 g++ 编译 .so 时,我看到以下内容:

 17285: symbol=socket;  lookup in file=./udp_client [0]
 17285: symbol=socket;  lookup in file=./socket_hooks.so [0]
 17285: symbol=socket;  lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
 17285: binding file ./udp_client [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `socket' [GLIBC_2.2.5]

在这两种情况下都找到了 "socket" 符号,但在后一种情况下它没有被拾取,而是使用了 libc。

你能解释一下这里发生了什么吗?

当您使用 C++ 编译器编译您的模块时,您的符号会被命名以支持函数重载,例如 socket 可能会转换为 _Z10socketiii。这就是运行时加载程序找不到它的原因 - 它正在寻找 socket,而不是 _Z10socketiii

为了禁用名称修改,您必须使用 extern "C" 声明带有 C 链接的函数,可能与 __cplusplus 宏结合使用,以便与 C 编译器保持兼容:

#ifdef __cplusplus
extern "C" {
#endif

int socket(int domain, int type, int protocol);

#ifdef __cplusplus
}
#endif

或者,在每个符号的基础上设置链接:

#ifdef __cplusplus
#define DONT_MANGLE_ME extern "C"
#else
#define DONT_MANGLE_ME
#endif

DONT_MANGLE_ME int socket(int domain, int type, int protocol);