Как стать автором
Обновить

Комментарии 12

Неужели автор ничего не слышал о Cling - ROOT ?

Cling — интерактивный интерпретатор C++, построенный на базе библиотек LLVM и Clang. Его преимущества перед стандартными интерпретаторами заключаются в том, что он имеет командную строку и использует JIT-компилятор для компиляции.

Есть ли английская версия этого поста?
Xочу переслать его своим коллегам из Cling/ROOT
Они могли бы дать наиболее профессиональную рецензию этому труду.

Ссылки на исходные материалы на английском я привел в конце статьи.

Мне требуется не отдельная утилита с JIT компилятором C/C++, а API для компиляции и выполнения кода в рамках собственного приложения. Но все равно большое спасибо за наводку на Cling-ROOT, я действительно про него ничего не слышал.

Для динамической компиляции в своём движке я юзал RuntimeCompiledCPlusPlus. Автор обещает поддержу clang MSVC и gcc. Работает она просто, трекает файлы и при измерении даёт возможность запустить процесс рекомпиляции, а затем делает свап dll' ок. Все опции компиляции можно передать в инициализации. Штука рабочая, почему о ней так мало говорят - не знаю

Спасибо! Хотя это немного не то, что мне требуется, но тоже прикольная вещь!

А как под капотом реализована загрузка и исполнение кода? Ведь на любом современном компьютере/ОС нельзя запустить на исполнение произвольный адрес в памяти, скомпилированный код изначально должен быть загружен именно как программный код. Единственный известный мне механизм подгрузки кода во время выполнения приложения — это загрузка динамической библиотеки с диска, но здесь наверняка реализовано как-то по-другому, без промежуточного файла (.so / .dll).

Да, реализована, причем тут механизм немного другой. Сперва из скомпилированного и оптимизированного модуля создается среда JIT выполнения для текущей платформы

llvm::EngineBuilder builder(std::move(module));
...
auto executionEngine = builder.create();

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

AddFunc add = reinterpret_cast<AddFunc> (executionEngine->getFunctionAddress("nv_add"));
...
int res = add(40, 2);

В Windows можно пометить кусок памяти как исполнимый через VirtualProtect с флагом PAGE_EXECUTE_READ, в Linux и MacOS - через mprotect с флагом PROT_EXEC. Грузить динамическую библиотеку для этого не нужно.

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

В комментарии, на который я отвечал, есть фраза "Ведь на любом современном компьютере/ОС нельзя запустить на исполнение произвольный адрес в памяти". На что я парировал, что можно, и перечислил API, которое для этого нужно.

В таком контексте ваш комментарий действительно актуальный.

Спасибо!
Зарегистрируйтесь на Хабре, чтобы оставить комментарий