4

我写了一个程序来 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);
}

但我收到“分段错误”错误我用 .so 库测试了这个程序,它可以工作,但不能让它自己工作

4

2 回答 2

13

你需要编码:

  // 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),始终检查那里的dlopen&dlsym函数是否成功,并dlerror在失败时使用。

并编译上面的ds.c文件

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

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

在我的 Debian/Sid/x86-64 系统上(gcc版本 4.8.2 和libc6版本 2.17-93 提供-ldl由我编译的内核 3.11.6,binutils包 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) +++
于 2013-10-31T20:27:03.603 回答
4

除了 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
于 2017-07-17T12:54:05.803 回答