system()函数未从LD_PRELOAD'ed库中调用。
system()函数未从LD_PRELOAD'ed库中调用。
我正在尝试在Linux上使用LD_PRELOAD
来包装对system
函数的调用,以便对参数进行一些预处理。这是我的system.cpp
代码:
#define _GNU_SOURCE #include#include #include typedef int (*orig_system_type)(const char *command); int system(const char *command) { std::string new_cmd = std::string("set -f;") + command; // 下一行仅用于调试 std::cout << new_cmd << std::endl; orig_system_type orig_system; orig_system = (orig_system_type)dlsym(RTLD_NEXT,"system"); return orig_system(new_cmd.c_str()); }
我使用以下命令编译它:
g++ -shared -fPIC -ldl -o libsystem.so system.cpp
这将生成.so对象。然后,我使用以下命令运行程序:
$ LD_PRELOAD=/path/to/libsystem.so ./myprogram
我没有收到任何错误消息,但似乎我的system
函数没有被调用。通过运行LD_DEBUG=libs
,我可以看到我的.so被加载了,但是我的system
函数没有被调用,而是调用了标准库中的函数。
我需要在代码或编译中做出哪些更改才能使它工作?
问题的出现原因是system()函数没有从LD_PRELOAD的库中调用。解决方法有两种:
方法一:在构造函数/初始化函数中保存“orig_system”指针,这样可以避免每次调用dlsym。代码如下:
extern "C" { typedef int (*orig_system_type)(const char *command); static orig_system_type orig_system; static void myInit() __attribute__((constructor)); void myInit() { orig_system = (orig_system_type)dlsym(RTLD_NEXT,"system"); } int system(const char *command) { std::string new_cmd = std::string("set -f;") + command; // next line is for debuggin only std::cout << new_cmd << std::endl; return orig_system(new_cmd.c_str()); } }
方法二:使用GNU ld的--wrap选项。首先在编译共享库时使用-Wl,--wrap system选项。然后在代码中编写如下内容:
extern "C" { void* __real_system(const char* command); void* __wrap_system(const char* command) { std::string new_cmd = std::string("set -f;") + command; // next line is for debuggin only std::cout << new_cmd << std::endl; return __real_system(new_cmd.c_str()); } }
以上是解决问题的两种方法。
问题出现的原因是驱动程序是用C++编写的,而不是C,因此名称修饰(name mangling)导致系统无法正确调用system函数。解决方法是在驱动程序中使用extern "C"来指定system函数以C语言方式进行链接,以避免名称修饰问题。
修改后的驱动程序代码如下:
#include <cstdlib> extern "C" { int system(const char* command); } int main() { system("find -name *.cpp"); }
然后使用env LD_PRELOAD=$PWD/libsystem.so ./a.out
运行程序,即可正常输出结果:
set -f;find -name *.cpp ./system.cpp ./test.cpp