长话短说,我有一个整数数组,它代表一个函数的ELF二进制文件的.text部分。我想执行这个功能。我在尝试执行命令之前运行了此命令:
mprotect(function, sHeader.sh_size, PROT_EXEC | PROT_READ | PROT_WRITE);
认为它可以解决权限问题,但是当我尝试运行它时仍然会出现段错误:
int (*fp)(int, int) = (int (*)(int, int))getFunc("t.o");
int a = 2;
int b = 3;
cout << fp(a, b) << "\n";
但是当我尝试运行它时仍然会出现段错误:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000603010 in ?? ()
有什么我错过的吗?
我试图执行的函数的objdump:
0000000000000000 <mult>:
mult():
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: 89 7d fc mov %edi,-0x4(%rbp)
7: 89 75 f8 mov %esi,-0x8(%rbp)
a: 8b 45 fc mov -0x4(%rbp),%eax
d: 0f af 45 f8 imul -0x8(%rbp),%eax
11: 5d pop %rbp
12: c3 retq
答案 0 :(得分:3)
ELF目标文件包含relocation信息,很可能其.text
部分包含要重定位的代码,因此代码不会按原样运行。使用objdump
和readelf
命令进行探索。如果你真的想以你的方式加载它,你应该处理重定位信息,这是复杂的,处理器特定的,乏味的。如果你真的想花几周的时间来研究这个问题,请研究x86-64 ABI。但是使用dlopen
的{{1}}然后.so
要简单得多(因为dlsym
在dlopen
来自mmap
的段后进行重定位),见下文。
x86-64 ABI曾经在http://x86-64.org/documentation/abi.pdf上,但该网站今天不起作用
什么是t.so
?你如何在getFunc
内进行搬迁?为什么你不能拥有t.o
共享对象(例如使用t.so
编译),然后使用dlopen(3)和gcc -Wall -fPIC -O -shared t.c -o t.so
加载它,例如
dlsym(3)
一旦typedef int functionsig_t (int, int);
void* dlh = dlopen("./t.so", RTLD_NOW);
if (!dlh) {
fprintf(stderr, "dlopen t.so failed with %s\n", dlerror());
exit(EXIT_FAILURE);
};
functionsig_t* fp = (functionsig_t*) dlsym(dlh, "myfunc");
if (!fp) {
fprintf(stderr, "dlsym myfunc failed with %s\n", dlerror());
exit(EXIT_FAILURE),
}
// now you can call fp
int res = (*fp) (1,2);
返回并且使用fp
中的任何函数都不存在调用堆栈帧,您可t.so
dlclose(dlh);
来自munmap
的段。您可以避免调用t.so
(这通常会导致进程地址空间无关紧要;请参阅文件dlclose
以获取pid 1234的进程),尤其是如果您没有/proc/1234/maps
很多共享对象。
如果dlopen
插件调用主程序中的函数,您希望该主程序与t.so
选项-rdynamic
或ld
如果已从某些C ++源代码编译gcc
,则应声明
t.so
由 extern "C" int myfunc(int,int);
我的manydl.c程序显示您可以在Linux进程中执行数十万个g++
- s。它的工作原理是生成“随机”C代码,将其编译为dlopen
和.so
- dlopen
文件,然后重复多次。
如果您不希望将.so
或.c
代码编译成.cc
插件,您可以考虑使用{生成内存即时代码生成{3}},LLVM,asmjit,libjit等...
答案 1 :(得分:2)
您缺少搬迁。二进制文件不包含绝对地址,而是包含偏移量。
当加载二进制文件时,OS通过将分配的段地址添加到二进制文件中的偏移量来重定位函数指针(以及所有其他符号)。