本文介绍了LD_PRELOAD __libc_start_main的Makefile的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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;
}

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

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?

推荐答案

关于makefile的问题的答案是,您想要编写类似以下内容的文件:

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) $^

使用隐式规则来生成共享对象所需的.o文件. (对于x86_64,您还需要CFLAGS中的-fPIC,为了更好地使用它,可能还需要-pthread,而在LDFLAGS中则需要-ldl.)

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).

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

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
}

使用gcc __attribute__扩展名注册要在加载库期间(即在main()被命中之前)自动调用的功能.

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).

此外,即使您想要按照显示的方式进行操作,也可以使用伪库句柄RTLD_NEXT查找当前库之后的下一个出现的符号,从而对其进行实质性的简化.

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.

所以当你写的时候:

  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库插入到同一函数中.

Which also lets multiple LD_PRELOAD libraries interpose on the same functions together by chaining them.

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

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!

这篇关于LD_PRELOAD __libc_start_main的Makefile的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-29 08:30