Функция system() не вызывается из библиотеки LD_PRELOAD
Я пытаюсь использовать LD_PRELOAD
на Linux, чтобы обернуть звонки system
функция, чтобы добавить некоторую предварительную обработку к аргументу. Вот мой system.cpp
:
#define _GNU_SOURCE
#include <dlfcn.h>
#include <string>
#include <iostream>
typedef int (*orig_system_type)(const char *command);
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;
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
функция не вызывается, а вызывается функция из стандартной библиотеки.
Что мне нужно изменить в коде / сборке, чтобы заставить его работать?
3 ответа
Тебе нужно
extern "C" int system ...
потому что он вызывается функцией C. Версия C++ имеет искаженное имя, поэтому она не распознается.
Возможно, вы захотите сохранить указатель "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());
}
}
(этот код не проверен, но я использовал эту технику в прошлом).
Альтернативой может быть использование опции --wrap GNU ld.
Если вы компилируете свою общую библиотеку с
-Wl,- система обертывания
тогда в своем коде ты пишешь
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());
}
}
(Обратите внимание, что я никогда не использовал это).
Код должен работать отлично. Предполагая, что программа драйвера выглядит примерно так:
#include <cstdlib>
int main() {
system("find -name *.cpp");
}
затем env LD_PRELOAD=$PWD/libsystem.so ./a.out
дает мне этот вывод:
set -f;find -name *.cpp
./system.cpp
./test.cpp
Это показывает, что не только появляется ваш оператор отладки, но и что глобус отключен для этой команды.