Короче говоря, у меня есть массив целых чисел, который представляет секцию .text двоичного файла ELF с одной функцией. Я хочу выполнить эту функцию. Я выполнил эту команду до попытки выполнить команду:
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";
но он все еще segfaults, когда я пытаюсь запустить его:
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
ELF объектный файл содержит перемещение информация, и очень вероятно, его .text
раздел содержит код для перемещения, поэтому код не будет работать как есть. Использовать objdump
а также readelf
команды, чтобы исследовать это. Если вы действительно хотите загрузить его так, как вы это делаете, вам следует обработать информацию о перемещении, которая является сложной, специфичной для процессора и утомительной. Если вы действительно хотите потратить недели на это, изучите x86-64 ABI. Но используя dlopen
из .so
затем dlsym
намного проще (потому что dlopen
делает переезд после того, как mmap
сегменты от t.so
), увидеть ниже.
X86-64 ABI раньше был на http://x86-64.org/documentation/abi.pdf но этот сайт не работает сегодня
Что такое getFunc
? Как вы делаете перемещение внутри вашего t.o
? Почему ты не можешь иметь t.so
общий объект (например, скомпилированный с gcc -Wall -fPIC -O -shared t.c -o t.so
) затем загрузите его, используя dlopen (3) а также 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
(это обычно приводит к незначительной утечке адресного пространства процесса; см. файл /proc/1234/maps
для процесса pid 1234), особенно если вы этого не сделаете dlopen
большое количество общих объектов.
Если t.so
плагин вызывает функции из вашей основной программы, вы хотите, чтобы эта основная программа была связана с -rdynamic
возможность ld
или же gcc
Если t.so
был скомпилирован из какого-то источника C ++, он должен объявить
extern "C" int myfunc(int,int);
потому что название искажения сделано g++
мой manydl.c Программа показывает, что вы можете сделать много сотен тысяч dlopen
-с в процессе Linux. Он работает путем генерации «случайного» кода на C, компилируя его в несколько .so
, а также dlopen
что .so
файл, а затем повторяя это много раз.
Если вы не хотите бремя компиляции .c
или же .cc
код в .so
плагин, вы могли бы рассмотреть оперативную генерацию кода в памяти, используя LLVM, asmjit, libjit, GNU молнии так далее…
Вам не хватает переезда. Двоичный файл не содержит абсолютных адресов, но смещений.
Когда двоичный файл загружен, ОС перемещает указатели функций (и все другие символы), добавляя адрес выделенного сегмента к смещениям в двоичном файле.