Можно ли загрузить функцию в выделенную память и запустить ее оттуда? - PullRequest
4 голосов
/ 26 августа 2010

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

Что-то вроде:

memcpy(shared_memory_address, &func, &func + sizeof(func));

Я понимаю, что вы не можете принять размер функции, но это было то, что пришло мне в голову.

Ответы [ 7 ]

4 голосов
/ 26 августа 2010

Теоретически, поскольку функции - это просто последовательность байт-кода где-то в памяти, вы можете скопировать блок памяти функции и вызвать (перейти в нее). Хотя c ++ абстрагирует эту возможность, как вы заметили, мы на самом деле не можем знать размер функции (хотя мы можем получить указатель на нее).

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

4 голосов
/ 26 августа 2010

Это было весело.
Но похоже, что вы можете. Хотя я бы НИКОГДА не сделал бы это:

Скомпилировано на lenovo: T61p под управлением Windows 7: с использованием g ++ 4.3.4

Я хотел бы отметить, что некоторые типы аппаратного обеспечения будут препятствовать этому, поскольку вы можете выполнять код только из определенной области памяти (программной области), которая помечена в файле карты памяти аппаратного обеспечения как только для чтения (для предотвращения самоизменения кода).

Обратите внимание, что тип функции очень ограничен:

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

  • Вызов функции или метода.
  • Передать указатель (или ссылку)
    • Ни один объект, содержащий указатель или ссылку, не будет работать.
  • Используйте глобалы.
  • Вы можете передать указатель на метод:
    • Но объект, на котором он используется, должен передаваться по значению.

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

Глупый Пример

#include <vector>
#include <iostream>
#include <string.h>

int func(int x)
{
    return x+1;
}

typedef int (*FUNC)(int);


int main()
{
    std::vector<char>   buffer(5000);

    ::memcpy(&buffer[0],reinterpret_cast<char*>(&func),5000);

    FUNC func   = reinterpret_cast<FUNC>(&buffer[0]);

    int result  = (*func)(5);

    std::cout << result << std::endl;

}
2 голосов
/ 26 августа 2010

В последний раз, когда я пытался это сделать, я столкнулся с дорожным блоком: определением количества байтов в функции.Задача состоит в том, чтобы использовать адрес функции, копировать байты в память (при условии, что код скомпилирован как независимый от позиции код, PIC).

Более независимый от платформы метод - это просмотреть документацию вашего компилятора, чтобы узнать, существует ли #pragma, опция компилятора или ключевое слово, которое позволяет вам указать адрес функции или сегмент для загрузки во время загрузки.

Кроме того, выполните поиск по группам встроенных систем, поскольку это популярный метод: загрузите код, который программирует флэш-память в ОЗУ, выполните функцию в ОЗУ, а затем перезагрузите систему.

Надеюсь, что это поможет.

Редактировать:
Предложение: создать сегмент данных или кода, используя файл на языке ассемблера или инструкции для компоновщика (вскрипт сборки).Поместите свою функцию в отдельный файл кода.Скажите компилятору и компоновщику скомпилировать эту функцию в новый сегмент кода.Могут быть специфичные для компилятора операторы, чтобы получить начальный адрес и размер сегмента.Кроме того, операционная система может загружать сегмент по заданному для вас адресу.

Также посмотрите библиотеки DLL или общие библиотеки, которые можно загрузить во время выполнения, с помощью операционной системы.

1 голос
/ 26 августа 2010

Да.Подобный метод используется генераторами кода Just-In-Time, такими как Java VM.Фактически, вы могли бы почти сказать, что загрузчик и компоновщик операционной системы делает это для вас, поскольку он загружает динамические библиотеки в ваш процесс.

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

1 голос
/ 26 августа 2010

Если вы попытаетесь сделать это, вы можете столкнуться с проблемами при запуске кода из памяти, которая не должна содержать исполняемый код.См. Эту статью Википедии для получения дополнительной информации: http://en.wikipedia.org/wiki/Executable_space_protection

0 голосов
/ 26 августа 2010

Если вы генерируете байты кода и внедряете его в процесс, это называется Генерация кода времени выполнения (RTCG) .Вы можете посмотреть некоторые примеры .

Современные ядра не позволят этому работать с непривилегированного уровня, поэтому вы должны войти в правильный режим или кольцо первый.Чтобы найти размер кода, вы должны (конечно) подсчитать байты функции, в которой находится сегмент кода, до последнего кода возврата.

Драйверы графики Afaik иногда использовали RTCG при создании кода для растровых операций на лету (проблема зависит).

0 голосов
/ 26 августа 2010

Вы можете разумно предположить, что это абсолютно невозможно в Linux, Windows или более сложных встроенных операционных системах.

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

Конечно, существует четко определенный механизм предоставления библиотек кода для нескольких процессов, предоставляемый динамической библиотечной системой Linux и Windows. Вероятно, не так гибко, как хотелось бы. : -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...