我有一个套接字API的包装器,我使用LD_PRELOAD在我的应用程序之前预加载。但是,当我使用g ++编译我的.so包装器库时,它不起作用,即替代了套接字实现的glibc版本。
这是我编译包装器.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
现在当我启用debug(export 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。
你能解释一下这里发生了什么吗?
答案 0 :(得分:1)
使用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);