Как хранить и вызывать скомпилированную функцию в C / C ++? - PullRequest
5 голосов
/ 20 июля 2009

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

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

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

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

Редактировать 2: дальнейшее уточнение:

С указателем на функцию:

  1. Загрузить указатель из & struct + offsetof (pointer)
  2. Перейти к местоположению, содержащемуся в указателе

С буфером, содержащим машинный код:

  1. Перейти к & struct + offsetof (buffer)

Второй шаг меньше.

Ответы [ 12 ]

0 голосов
/ 20 июля 2009

Если вас интересует только C ++, рассмотрите возможность использования «функциональных объектов» - определите класс с одним методом, содержащим логику вашей функции, и перегрузите оператор () класса, чтобы вызвать метод. Затем объявив экземпляр вашего класса:

Foo Foo;

... вы можете сделать это:

rtn_type result = foo( /* arg list */);

Синтаксически это похоже на сохранение вашей функции в переменной.

0 голосов
/ 20 июля 2009

Звучит как работа для нескольких хороших операторов goto и встроенной сборки.

Просто будьте осторожны.

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