Linux 如何自行打开可执行二进制文件

Linux 如何自行打开可执行二进制文件,linux,gcc,arm,Linux,Gcc,Arm,我写了一个程序来打开它自己 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); } 但我得到了“分段错误”错误 我用一

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

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库测试了这个程序,它可以工作,但不能自己工作

您需要编写代码:

  // 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);
  }    
不要忘记使用
-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) +++
%ltrace./ds
__libc_start_main(0x4009b3、0x7fff1d0088b8、0x400a50、0x400ae0
dlopen(NULL,1)=0x7f1e06c9e1e8
dlsym(0x7f1e06c9e1e8,“你好”)=0x004009a0
放置(“hello world”hello world
)                            = 12
dlclose(0x7f1e06c9e1e8)=0
+++已退出(状态0)+++

除了BaselStaynkviChChices的优秀答案之外,我想指出,这在C++编译器上是不起作用的。

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

第二,C++不允许你把DLSEM的结果分配给FPTR,因为它拒绝隐式转换类型。

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

编译为Basile Starynkevitch所说,但用C++代替C:< /P>

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

可能重复但无法使其自身工作…;只是好奇,你期望发生什么?@artless noise:hello world!好的,我明白了。但是,使用
dlopen
加载的过程将尝试使用可执行文件填充地址空间,但此可执行文件已经加载。此概念适用于
dlsym()
,但您不能使用
dlopen()
。可执行文件是进程空间的根。这就是为什么我们成功编译了
execv
fork
等,但输出退出时不打印“hello world!”
dlerror
在我更新的代码中是什么意思?您是否编译并链接了
-rdynamic
?我在我的Debian/Sid系统上测试了它,它正常工作!我使用了您提到的所有标志和代码,没有任何更改。但是程序存在时没有任何错误或输出!您是否像我刚才那样添加了检查和
dlerror
?同时尝试
ltrace
strace
您的程序。不要使用GCC 4.4,它是一个古老的不受支持的编译器。尝试升级到GCC 4.8.2
void (*fptr) (void) = reinterpret_cast<void (*)()>(dlsym (hndl, buf));
extern "C" void hello () {...}
% g++ -Wall -rdynamic ds.cpp -o ds -ldl
% ./ds
hello world