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