gpt4 book ai didi

c++ - LD_PRELOAD 的 Makefile __libc_start_main

转载 作者:太空狗 更新时间:2023-10-29 21:16:19 24 4
gpt4 key购买 nike

我想做的很简单。当我启动 Mongoose 服务器时,我想创建一个额外的线程来做一些额外的工作。为此,我认为我需要 LD_PRELOAD 服务器的 __libc_start_main

/* This is spec_hooks.cpp */
typedef int (*main_type)(int, char**, char**);

struct arg_type
{
char **argv;
int (*main_func) (int, char **, char **);
};

main_type saved_init_func = NULL;
void tern_init_func(int argc, char **argv, char **env){
dprintf("%04d: __tern_init_func() called.\n", (int) pthread_self());
if(saved_init_func)
saved_init_func(argc, argv, env);
__tern_prog_begin(); //create a new thread in this function
}

extern "C" int my_main(int argc, char **pt, char **aa)
{
int ret;
arg_type *args = (arg_type*)pt;
dprintf("%04d: __libc_start_main() called.\n", (int) pthread_self());
ret = args->main_func(argc, args->argv, aa);
return ret;
}

extern "C" int __libc_start_main(
void *func_ptr,
int argc,
char* argv[],
void (*init_func)(void),
void (*fini_func)(void),
void (*rtld_fini_func)(void),
void *stack_end)
{
typedef void (*fnptr_type)(void);
typedef int (*orig_func_type)(void *, int, char *[], fnptr_type,
fnptr_type, fnptr_type, void*);
orig_func_type orig_func;
arg_type args;

void * handle;
int ret;

// Get lib path.
Dl_info dli;
dladdr((void *)dlsym, &dli);
std::string libPath = dli.dli_fname;
libPath = dli.dli_fname;
size_t lastSlash = libPath.find_last_of("/");
libPath = libPath.substr(0, lastSlash);
libPath += "/libc.so.6";
libPath = "/lib/x86_64-linux-gnu/libc.so.6";

if(!(handle=dlopen(libPath.c_str(), RTLD_LAZY))) {
puts("dlopen error");
abort();
}

orig_func = (orig_func_type) dlsym(handle, "__libc_start_main");

if(dlerror()) {
puts("dlerror");
abort();
}

dlclose(handle);

dprintf("%04d: __libc_start_main is hooked.\n", (int) pthread_self());

args.argv = argv;
args.main_func = (main_type)func_ptr;
saved_init_func = (main_type)init_func;

saved_fini_func = (fini_type)rtld_fini_func;
ret = orig_func((void*)my_main, argc, (char**)(&args),
(fnptr_type)tern_init_func, (fnptr_type)fini_func,
rtld_fini_func, stack_end);
return ret;
}

但是,我不知道如何为此编写 Makefile。有人可以帮我吗?有什么需要注意的吗?

最佳答案

你关于 makefile 的问题的答案是你想写这样的东西:

CFLAGS ?= -Wall -Wextra

all: mylib.so

mylib.so: mylib.o
gcc -o $@ -shared $(CFLAGS) $(LDFLAGS) $^

它使用隐式规则生成共享对象所需的 .o 文件。 (对于 x86_64,您还需要在 CFLAGS 中使用 -fPIC,并且可能还需要 -pthread,以便在 LDFLAGS 中使用 -ldl)。


问题的关键可以大大简化。要在初始化期间尽早在 LD_PRELOADed 库中创建一个额外的线程,您可以简单地执行以下操作:

static void start_my_thread() __attribute__((constructor));

static void start_my_thread() {
// Call pthread_create here and then return
}

它使用 gcc __attribute__ 扩展来注册在库加载期间自动调用的函数(即在 main() 被命中之前)。


此外,即使您想按照展示的方式进行操作,也可以通过使用伪库句柄 RTLD_NEXT 来查找下一次出现的符号,从而大大简化它,在当前库之后。

所以当你写的时候:

  Dl_info dli;
dladdr((void *)dlsym, &dli);
std::string libPath = dli.dli_fname;
libPath = dli.dli_fname;
size_t lastSlash = libPath.find_last_of("/");
libPath = libPath.substr(0, lastSlash);
libPath += "/libc.so.6";
libPath = "/lib/x86_64-linux-gnu/libc.so.6";

if(!(handle=dlopen(libPath.c_str(), RTLD_LAZY))) {
puts("dlopen error");
abort();
}

orig_func = (orig_func_type) dlsym(handle, "__libc_start_main");

可以这样写:

orig_func = (orig_func_type) dlsym(RTLD_NEXT, "__libc_start_main");

这还允许多个 LD_PRELOAD 库通过链接将它们插入到相同的函数中。


即使出于某种原因(尽管有 RTLD_NEXT/RTLD_DEFAULT)您确实确实想在 libc 上显式调用 dlopen,我还是建议将 RTLD_NOLOAD 添加到您用来打开它的标志中,这样您在打开两个不同的 libc 拷贝的一些晦涩的配置上,最终出现了一个奇怪的错误!

关于c++ - LD_PRELOAD 的 Makefile __libc_start_main,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35390437/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com