如何自我dlopen一个可执行的二进制文件

我写了一个程序来打开自己

void hello() { printf("hello world\n"); } int main(int argc, char **argv) { char *buf="hello"; void *hndl = dlopen(argv[0], RTLD_LAZY); void (*fptr)(void) = dlsym(hndl, buf); if (fptr != NULL) fptr(); dlclose(hndl); } 

但我得到“segemention故障”的错误我testing了这个程序与.so库,它的工作原理,但不能让它与自己的工作

你需要编码:

  // file ds.c #include <stdio.h> #include <stdlib.h> #include <dlfcn.h> void hello () { printf ("hello world\n"); } int main (int argc, char **argv) { char *buf = "hello"; void *hndl = dlopen (NULL, RTLD_LAZY); if (!hndl) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); exit (EXIT_FAILURE); }; void (*fptr) (void) = dlsym (hndl, buf); if (fptr != NULL) fptr (); else fprintf(stderr, "dlsym %s failed: %s\n", buf, dlerror()); dlclose (hndl); } 

仔细阅读dlopen(3) ,总是检查dlopendlsym函数的成功,并在失败时使用dlerror

并用上面的ds.c文件编译

  gcc -std=c99 -Wall -rdynamic ds.c -o ds -ldl 

不要忘记 – 要获得所有的警告和-rdynamic标志(能够dlsym你自己的符号应该进入动态表)。

在我的Debian / Sid / x86-64系统上(使用gcc版本4.8.2和libc6版本2.17-93提供了我编译的-ldl ,kernel 3.11.6, binutils package 2.23.90提供的ld ),执行./ds给出了预期的输出:

  % ./ds hello world 

乃至:

  % ltrace ./ds __libc_start_main(0x4009b3, 1, 0x7fff1d0088b8, 0x400a50, 0x400ae0 <unfinished ...> dlopen(NULL, 1) = 0x7f1e06c9e1e8 dlsym(0x7f1e06c9e1e8, "hello") = 0x004009a0 puts("hello world"hello world ) = 12 dlclose(0x7f1e06c9e1e8) = 0 +++ exited (status 0) +++ 

除了Basile Starynkevitchs优秀的答案之外,我想指出的是,这不适用于C ++编译器。

首先,你会得到一个警告,因为buf定义为char *已经被弃用了。 你可以改为const char *。

其次,C ++不允许你把dlsym的结果赋值给fptr,因为它拒绝隐式地转换类型。 您必须明确地投入类型

 void (*fptr) (void) = (void (*)())dlsym (hndl, buf); 

要么

 void (*fptr) (void) = reinterpret_cast<void (*)()>(dlsym (hndl, buf)); 

第三,C ++的不同命名方案给函数“hello”赋予不同的名称,所以dlsym不会找到它。 你需要声明为

 extern "C" void hello () {...} 

编译为Basile Starynkevitch说,但用C ++代替C:

 % g++ -Wall -rdynamic ds.cpp -o ds -ldl % ./ds hello world