Monday, August 02, 2010

[C#/.NET] Генерируем машинный код с помощью LLVM

В этом топике я покажу, как без особых трудов сгенерировать и выполнить машинный код с помощью Low Level Virtual Machine на примере функции, вычисляющей ответ на главный вопрос жизни, вселенной и всего такого.
А для работы нам понадобятся
Предварительно скомпилированные версии LLVM в виде Windows DLL. CodePlex
Их нужно скопировать в соответствующие системные папки или в папки, где будет лежать исполняемый файл Вашего тестового проекта.
Исходный код биндинга, написанный на C#.
Mercurial: https://hg01.codeplex.com/codeblock
Исходный код на Codeplex
Собственно из исходного кода понадобится только проект LLVM, лежащий, соответсвтенно, в папке LLVM. Обратите внимание, проект создан в Visual Studio 2010 и нацелен на .NET 4.0, но из тех же .cs файлов можно собрать биндинг и для старой версии .NET
Приступаем к работе
Создайте новый консольный проект C#, добавьте в решение проект LLVM. Из своего проекта сделайте ссылку на LLVM.
Добавьте в заголовок Program.cs (так по умолчанию называется файл исходного кода) ссылку на соответствующее пространство имён:
using LLVM;
using Type = LLVM.Type;
Теперь можно начинать работу с LLVM.
Инициализация целевой платформы и создание общих элементов
Объявите статические переменные context типа Context, module типа Module и engine типа ExecutionEngine.
static Context context;
static Module module;
static ExecutionEngine engine;
Для чего нужен контекст на данном этапе не важно, поэтому мы просто пользуемся глобальным контекстом LLVM.
Модуль в LLVM — это некий аналог библиотеки. Он может содержать описания функции и статических переменных. При этом определения функций не обязаны лежать в том же модуле, т.е. он может иметь неразрешённые ссылки.
Execution engine — ответственнен за выполнение сгенерированного кода прямо во время исполнения программы. Может быть интерпретатором, либо компилятором.
Далее — инициализация необходимых структур для системы, в которой запущен LLVM, а также — собственно инициализация указанных объектов:
Console.Write("initializing native target...");
Target.InitializeNative();
Console.WriteLine("OK");
Console.Write("reading global context...");
context = Context.Global;
Console.WriteLine("OK");
Console.Write("creating module...");
module = new Module("test", context);
Console.WriteLine("OK");
Console.Write("creating execution engine...");
engine = new ExecutionEngine(module);
Console.WriteLine("OK");
Read more: Habrahabr.ru