LINUX.ORG.RU

Выполение маш. кода


0

0

Кто нибудь знает, что можно почитать на вот такую тему:

маш.код нужно загрузить с помощью программы и выполнить. Например программа работает в определенный момент вызывает функцию, которая загружает машинный код и передает ему управление. После выполнения машинный код возвращает управление.

Сорри за корявое обьяснение проблеммы - прото сам еще плохо ориентируюсь.

Попробую еще вот так задать вопрос: Мне нужно узнать как сделать такой финт:

Создать маш.код не ABI Linux а "чистый" маш код который в определеное место памяти запишет 1. Сделать программу которая загрузит этот маш.код. и передаст ему управление. После завершения распечает значение из памяти. Там должна оказаться 1.

google мне пока не помог :)

anonymous

>google мне пока не помог :)

замени слово маш.код на ассемблер и вперед обратно в гугл

anonymous
()

а скриптовыми языками не обойтись?

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

Нее, Это система времени выполнения (RunTime) пользовательских программ. Ну есть компилятор который делает из исходной программы бинарный код. Этот код загружается на устройтво (Linux или без ОС), там RunTime его вызывает, но это должен быть бинарный код, а не ELF.

anonymous
()

посмотри в исходниках quake3 там есть такой скрипт engine lcc

вроде он как раз из скриптов делал машинный код

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

Мне для примера хватило бы так: x86 (PC) под управлением Linux.

Процесс который загружает из файла бинарный код и прердает ему управление. Никаких системных вызовов в этом коде нет.

Просто запиь 1 в определенный байт в памяти по заданному адресу. По завершению этого кода процесс делает printf() значения лежащего по этому адресу. Я думаю на таком упрощенном примере будет понятен принцип.

Чем сделать такой бинарный код пока не знаю, думаю что на ассемблере, но только скомпилить так(этого я тоже пока не знаю как), чтобы это НЕ был формат исполняемого файла Linux.

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

Ну вот немого навоял. Пример простой но от него можно отталкиваться далее.
brain@broya:~/exempls/asm/lor$ cat lor.c
int add_ab(int a,int b)
{
  return a+b;
}

brain@broya:~/exempls/asm/lor$ gcc -c lor.c
brain@broya:~/exempls/asm/lor$ ld lor.o --oformat=binary -o lor
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048000

"ld lor.o --oformat=binary -o lor"  этим мы создаем "простой" бинарный файл.

brain@broya:~/exempls/asm/lor$ cat main.c
#include <stdio.h>
#include <stdlib.h>

void main()
{
  int a=10,b=99;
  int (* f)(int,int); //Указатель на функцию (которая идет в бинарном файле)
  char buf[15]; //Буфер для бинарного модуля
  FILE *file  = fopen("lor","rb");
  fread(buf,11,1,file); //Читаем бинарный файл созданный ранее

  f = buf;
  printf("c=%d\n",f(a,b));

  exit(0);
}

brain@broya:~/exempls/asm/lor$ gcc main.c -o main
main.c: In function &#8216;main&#8217;:
main.c:13: warning: assignment from incompatible pointer type
main.c:5: warning: return type of &#8216;main&#8217; is not &#8216;int&#8217;
brain@broya:~/exempls/asm/lor$ ./main
c=109

Ну в принципе все.

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

Огромное спасибо! Все действительно настолько просто, что приходит мысль - как сам то не догодался. :)

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

>Огромное спасибо! Все действительно настолько просто, что приходит мысль - как сам то не догодался. :)

Да пожалуста. Самому стало интересно. Пример простой но при увлечение кода в вызываемой функции, могут быть свои подводные камни.

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

>>Огромное спасибо! Все действительно настолько просто, что приходит мысль - как сам то не догодался. :)

>Да пожалуста. Самому стало интересно. Пример простой но при увлечение кода в вызываемой функции

А ты пробовал исполнить загруженный код? Потому что судя по этому:

ld: warning: cannot find entry symbol _start; defaulting to 0000000008048000

он у тебя не исполнится.

2 OP:

Тебе придется (в дополнение к тому, что сказал I3rain) линковать программу так, чтобы она была рассчитана на выполнение с нужного тебе адреса, и грузить ее именно на этот адрес. Или использовать PIC, но с этим свои сложности.

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

>А ты пробовал исполнить загруженный код? Потому что судя по этому:
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048000


Заметь это ругается на "бинарный" модуль там не нужна точка входа.
brain@broya:~/exempls/asm/lor$ ld lor.o --oformat=binary -o lor
ld: warning: cannot find entry symbol _start; defaulting to 0000000008048000

>Тебе придется (в дополнение к тому, что сказал I3rain) линковать программу так, чтобы она была рассчитана на выполнение с нужного тебе адреса, и грузить ее именно на этот адрес. Или использовать PIC, но с этим свои сложности.

Нет не нужно. Если только там явно не вызываются функции и не юзаются глобальные переменные. Но и это можно сделать если передать в функцию указатель на структура с нужными переменными и другими функциями. 
Хотя вариантов много......

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

> А ты пробовал исполнить загруженный код? Потому что судя по этому:
> ld: warning: cannot find entry symbol _start; defaulting to 0000000008048000
> он у тебя не исполнится.

ну как ELF он само-собой не исполнится, но как binary вполне.

foo@ip-230$ objdump --target="binary" -m i386 -D foo

foo:     file format binary

Disassembly of section .data:

00000000 <.data>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 0c                mov    0xc(%ebp),%eax
   6:   03 45 08                add    0x8(%ebp),%eax
   9:   c9                      leave
   a:   c3                      ret

чему тут не исполниться то? внешних ссылок нет.

// wbr

klalafuda ★☆☆
()
Ответ на: комментарий от I3rain

>>Тебе придется (в дополнение к тому, что сказал I3rain) линковать программу так, чтобы она была рассчитана на выполнение с нужного тебе адреса, и грузить ее именно на этот адрес. Или использовать PIC, но с этим свои сложности.

> Нет не нужно. Если только там явно не вызываются функции и не юзаются глобальные переменные.

Другими словами - "если программа является тривиальным учебным примером"?

> Но и это можно сделать если передать в функцию указатель на структура с нужными переменными и другими функциями.

Такая вот извращенная форма PIC.

klalafuda> чему тут не исполниться то?

Здесь - конечно, нечему. Программка слишком тривиальная.

Хотя, не зная точно, что именно нужно анонимному брату... может, для него этого достаточно.

tailgunner ★★★★★
()

Можно при компиляции указать опции -fpic -fPIC. По идее должно создать переносимый код.

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

>можно еще просто для интереса написать загрузчик ELF'ов, динамический линковщик...

Хм, а и вправду нужно попробывать!

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

> Если линкером расположить точку входа в начало, то ABI будет весьма простым :)

ABI такой, какой он есть. При этом совершенно не зависит от адреса точки входа, странно, да?

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

Не совсем понял. Какой такой ABI у куска кода? По моей идее это точка входа, способ передачи входных параметров и выходных. Все это нужно учитывать в любом случае. Но это все не влияет на переносимость кода.

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

>Не совсем понял.

Это очевидно :)

> Какой такой ABI у куска кода?

Шутишь? ABI - это как раз интерфейс куска кода, по определению.

> точка входа, способ передачи входных параметров и выходных.

Всё это часть ABI. Но еще есть GOT и PLT - особенно GOT релевантен к рассматриваемому вопросу ;)

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

Все правильно. GOT будет таскаться вместе с кодом. Пользователя ее положение волновать не должно. Оно по идее вычисляется исходя из текущего значения счетчика комманд и известного смещения. Все остальные смещения в программе берутся из GOT.

Опять же не вижу проблем с переносимостью :)

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

Во всяком случае это все в приложении к ARM. Как это выглядит на других архитектурах не знаю.

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

Насколько я знаю, на i386 для реализации GOT используются выделенные регистры, которые необходимо инициализировать перед вызовом. Вот об этой детали упомянуто не было (и это только из того, что я помню).

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

В ближайшее свободное время поэкспериментирую.

На АРМах у меня всегда все работало как нужно.

Это все еще будет зависеть от того расположена GOT в ОЗУ или ПЗУ.

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

> В ближайшее свободное время поэкспериментирую.

Делом займись. ВАТУ всё так же глючат? :-P

> На АРМах у меня всегда все работало как нужно.

А ты что, всегда пользовался --target=binary, загрузкой через read(2) и mmap(PROT_EXEC)? =8-0

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

ВАТУ работают строго так как было сказано. А то что с тех пор передумали много чего, так меня не предупреждал никто о передумках :) Начальство скажет переделаю.

--target=binary, но никакого read не было. И операционки там не было. Все заливалось прямо во флешку устройства. Естественно в этом случае можно было раместить все по фиксированным адресам и в продакшн пошло именно так, но с PIC я игрался долго...

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

> маш.код нужно загрузить с помощью программы и выполнить.

Вот о чем здесь говорили. И причем здесь твой опыт с единым бинарем, пусть даже собранным с --target=binary?

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

При том, что тот код грузился (бутлоадером, аналог запускающей программы) из флеша в ОЗУ (по разным адресам) и на него передавалось управление. Ситуация аналогична описаной.

Это я все к тому что -fPIC -fpic достаточно для переносимости кода и никакого ABI особо учитывать не нужно, хотя-бы на некоторых архитектурах.

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

> При том, что тот код грузился (бутлоадером, аналог запускающей программы)

Это значит только одну вещь - что такое в принципе возможно. Но в этом никто и не сомневался, речь шла только о том, _как_.

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

Вот так: http://beta.linux.org.ru/jump-message.jsp?msgid=1717427#1717869

Хотя да, я гоню. Записи в GOT все-равно нужно будет кому-то корректировать. И компилятор такой код вряд-ли включит. Это меня ядро сбило. Там для АРМа такая корректировака включена, вот я почему-то и решил что компилятор этот код включит.

alexru ★★★★
()

На самом деле ELF-объекты (без pic'ов/got'ов) грузятся в память и линкуются тривиально. Если заюзать libelf то и грузить не надо - только слинковать. Единственная простыня в этой процедуре - учесть все типы релокаций, но для ia32 их всего 2, помоему. Так что нужно загрузить и слинковать объект, из объекта импортнуть некий my_start() и int i и запустить.

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