См. ответ, который я только что отправил на этот вопрос. Вы можете использовать библиотеку callback(3)
для генерации новых функций во время выполнения. Он не соответствует стандартам, поскольку включает в себя множество уродливых хаков, специфичных для платформы, но он работает на большом количестве систем.
Библиотека заботится о выделении памяти, проверяя, является ли память исполняемой, и, при необходимости, очищая кэш команд, чтобы гарантировать, что динамически генерируемый код (т. Е. Замыкание) является исполняемым. По сути, он генерирует заглушки кода, которые могут выглядеть следующим образом на x86:
pop %ecx
push $THUNK
push %ecx
jmp $function
THUNK:
.long $parameter
А затем возвращает адрес первой инструкции. Эта заглушка сохраняет адрес возврата в ECX (пустой регистр в соглашении о вызовах x86), помещает дополнительный параметр в стек (указатель на thunk), а затем повторно отправляет адрес возврата. Затем он переходит к фактической функции. Это приводит к тому, что функция обманывается, думая, что у нее есть дополнительный параметр, который является скрытым контекстом замыкания.
На самом деле все сложнее (фактическая функция, вызываемая в конце заглушки, __vacall_r
, а не сама функция, а __vacall_r()
обрабатывает больше деталей реализации), но это основной принцип.