LINUX.ORG.RU

Запуск самосгенерированного кода на Си в Linux


1

1

Пытаюсь запустить функцию, помещенную в динамическую память, но всегда получаю Segmentation fault.

Первый вариант: загружаю код из bin-файла:

int main(int argc, char *argv[])
{
FILE *bytecode;
if((bytecode = fopen("jit_me.bin", "r")) == NULL)
{ fprintf(stderr,"Error opening file\n"); exit(1); }
char *p;
void (*f)() = p = malloc(50);
int c,i=0;
while((c = getc(bytecode)) != EOF) {*(p+i)=(char) c; i++;}
fclose(bytecode);
printf("Here we go...\n");
(*(f))();
}

Второй вариант: копирую готовую функцию в память и запускаю:

void temp()
{
printf("Hello");
}

int main(int argc, char *argv[])
{
char *p,*old;
old = (void (*)()) temp;
void (*f)() = p = malloc(20);
int i=0;
for(i=0;i<10;i++) {*(p+i)=(char) *(old+i); i++;}
printf("Here we go...\n");
(*(f))();
}

Всегда печатает фразу "Here we go..." (прямо перед запуском функции) и вылетает. Что делать, чтобы он заработал?

★★

Есть такая функиция (syscall) mprotect(), он определяет атрибуты области памяти (точнее страницы) --- может ли она быть выполнимой. Поэтому нужно выделять память по границе странице, а потом говорить mprotect(paddr, size, PROT_READ|PROT_EXEC);

mky ★★★★★
()

Каким образом был получен jit_me.bin ?

И еще, почему ты решил (во втором примере), что размер

void temp() { printf("Hello"); }

составляет 20 байт, расположенных в памяти через байт? А за это надо убивать, чтобы больше не мучал Си:

for(i=0;i<10;i++) {*(p+i)=(char) *(old+i); i++;}

mky ★★★★★
()

#include <string.h>
int a=0;
void temp()
{
a++;
// printf("Hello");
 }

  int main(int argc, char *argv[])
  {
   char *p,*old;
    old = (void (*)()) temp;
     void (*f)() = p = malloc(200);
      int i=0;
      // for(i=0;i<100;i++) {*(p+i)=(char) *(old+i); i++;}
      memcpy(p,old,30);
        printf("Here we go...\n");
        printf("%d",a);
         (*(f))();
         printf("%d",a);
         }
Вызывать внешнии функции нельзя, тк у тебя адреса меняются. Потом ты не правильно копировал данные.

krum
()
Ответ на: комментарий от krum

Вот это работает:)
#include <string.h>
int a=0;
void myputs(){
puts("Test");

}
void (*mp)() = myputs;
void temp()
{
a++;
  (*(mp))();
//myputs();
 }

  int main(int argc, char *argv[])
  {
   char *p,*old;
    old = (void (*)()) temp;
     void (*f)() = p = malloc(200);
      int i=0;
      // for(i=0;i<100;i++) {*(p+i)=(char) *(old+i); i++;}
      memcpy(p,old,100);
        printf("Here we go...\n");
        printf("%d",a);
         (*(f))();
         printf("%d",a);
         }

krum
()
Ответ на: комментарий от krum

Хм, а не проще этот код кидать в библиотеку, а затем dlopen() и тд? Так тебе придётся написать фактически линкер:)

krum
()
Ответ на: комментарий от dilmah

>PIC рулит

Кем? gcc -g test_.c -fpic -o test_
./test_
Here we go...
Segmentation fault
 cat test_.c
#include <string.h>
int a=0;
void myputs(){
puts("Test");

}
void (*mp)() = myputs;
void temp()
{
a++;
//  (*(mp))();
myputs();
 }

  int main(int argc, char *argv[])
  {
   char *p,*old;
    old = (void (*)()) temp;
     void (*f)() = p = malloc(200);
      int i=0;
      // for(i=0;i<100;i++) {*(p+i)=(char) *(old+i); i++;}
      memcpy(p,old,100);
        printf("Here we go...\n");
        printf("%d",a);
         (*(f))();
         printf("%d",a);
         }


krum
()

а мож тебе надо посмотретьсырцы ld.so?

я почти уверен что если твоя ф-я будет вызывать какую нибуть другую то ты её никогда не заставиш работать ;-) по крайней мере без заимствования коди из ld.so...

да и без pic/PIC лучше не пытатся решить задачу...

cvv ★★★★★
()
Ответ на: комментарий от ero-sennin

> А может, тебе пора переходить на Лисп? ;)

Ему пора переходить в 3-тий класс

anonymous
()
Ответ на: комментарий от mky

>Каким образом был получен jit_me.bin ?

Написал на асме:
SECTION .text
mov eax,1
mov ebx,0
int 0x80
и скомпилил командой nasm -f bin jit_me.asm

>И еще, почему ты решил что размер составляет 20 байт

Прикинул с запасом =)

ЗЫ: А в коде bin'а нет обращений к памяти, так что ничего не смещается. Он просто корректно завершает программу с помощью прерывания 0x80.

xTERM ★★
() автор топика
Ответ на: комментарий от xTERM

>и скомпилил командой nasm -f bin jit_me.asm

А код не пробовл смотреть (дизассемблировать)?
$ objdump --target="binary" -m i386 -D jit_me.bin

Если jit_me.bin равен 14 байт, то все понятно, 
он должен быть равен 12 байт. 
В общем, если в начало jit_me.asm добавит BITS 32, то должно наступить щастье :)) 
Хотя по хорошему, вместо malloc/read нужно делать mmap() c 
PROT_EXEC и MAP_PRIVATE.

#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    int fd;
    char *p;
    void (*f)(void);

    if( (fd = open("jit_me.bin", O_RDONLY)) != -1 ) { 
        if ( (p = malloc(50)) != NULL && read(fd, p, 50) > 0 ) {
            f = (void *)p;
            f(); 
        }
    }
    return 10;
}

mky ★★★★★
()
Ответ на: комментарий от generatorglukoff

> надеюсь ret поставил?

После выхода через системный вызов? :)

mv ★★★★★
()
Ответ на: комментарий от krum

> // for(i=0;i<100;i++) {*(p+i)=(char) *(old+i); i++;}

> memcpy(p,old,100);

А в чем, собственно говоря, разница между циклом и memcpy?

xTERM ★★
() автор топика
Ответ на: комментарий от xTERM

Вот серс memcpy:

void *memcpy(void *dst, const void *src, size_t n)
{
void *ret = dst;

while (n--)
{
*(char *)dst = *(char *)src;
dst = (char *) dst + 1;
src = (char *) src + 1;
}

return ret;
}

Не вижу особой разницы.

xTERM ★★
() автор топика
Ответ на: комментарий от xTERM

>> // for(i=0;i<100;i++) {*(p+i)=(char) *(old+i); i++;}

>> memcpy(p,old,100);

>А в чем, собственно говоря, разница между циклом и memcpy?

Ты действительно не видишь ошибки в своем коде или прикалываешься? ДВОЙНОЕ ИНКРЕМЕНТИРОВАНИЕ.

В случае оптимизации gcc заменяет библиотечную memcpy на inline функцию.

mky ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.