What I am trying to do is quite simple. When I start the mongoose server, I want to create an additional thread to do some extra work. To do this, I think I need to LD_PRELOAD the __libc_start_main of the server.
/* 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;
}
However, I have no idea how to write the Makefile for this. Can someone give me any help? Is there anything I need to pay attention to?
The answer to your question about makefiles is that you want to write something like:
CFLAGS ?= -Wall -Wextra
all: mylib.so
mylib.so: mylib.o
gcc -o $@ -shared $(CFLAGS) $(LDFLAGS) $^
Which uses an implicit rule to generate the .o files required by your shared object. (You'll also need -fPIC in CFLAGS for x86_64 and probably -pthread as well for good measure, with -ldl in LDFLAGS).
The crux of your problem can be simplified substantially. To create an extra thread in an LD_PRELOADed library early during initialization you can simply do:
static void start_my_thread() __attribute__((constructor));
static void start_my_thread() {
// Call pthread_create here and then return
}
Which uses the gcc __attribute__ extension to register the function to be called automatically during loading of the library (i.e. before main() gets hit).
As a further aside, even if you wanted to do it the way you've shown you can simplify it substantially, by using the pseudo library handle RTLD_NEXT to find the next occurrence of a symbol, after the current library.
So when you wrote:
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");
That can just be written as:
orig_func = (orig_func_type) dlsym(RTLD_NEXT, "__libc_start_main");
Which also lets multiple LD_PRELOAD libraries interpose on the same functions together by chaining them.
And even if you really did want to call dlopen on libc explicitly for some reason (despite RTLD_NEXT/RTLD_DEFAULT) I'd recommend adding RTLD_NOLOAD into the flags you use to open it with so you don't end up with a weird bug on some obscure configuration of having two different copies of libc open!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With