📜 ⬆️ ⬇️

[C # /. NET] Generate machine code using LLVM

In this topic, I will show how to generate and execute machine code using the Low Level Virtual Machine without much difficulty using the example of a function that calculates the answer to the main question of life, the universe and all that.

And for the work we need

Precompiled versions of LLVM as a Windows DLL. CodePlex
They need to be copied to the appropriate system folders or to the folders where the executable file of your test project will be located.

Binding code written in C #.
Mercurial: https://hg01.codeplex.com/codeblock
Source Codeplex Code
')
Actually from the source code, you only need the LLVM project, which, respectively, lies in the LLVM folder. Please note that the project was created in Visual Studio 2010 and is aimed at .NET 4.0, but from the same .cs files you can also assemble a binding for the old version of .NET.

Getting Started


Create a new C # console project, add the LLVM project to the solution. From your project, make a link to LLVM.

Add a link to the corresponding namespace in the Program.cs header (this is the default name for the source file):
using LLVM;
using Type = LLVM.Type;

Now you can start working with LLVM.

Initializing the target platform and creating common elements


Declare static context variables of type Context, module of type Module and engine of type ExecutionEngine.
static Context context;
static Module module;
static ExecutionEngine engine;

What the context is for at this stage is not important, so we simply use the global context LLVM.
A module in LLVM is a kind of library equivalent. It may contain descriptions of the function and static variables. In this case, the definitions of functions are not required to lie in the same module, i.e. It may have unresolved links.
Execution engine - is responsible for the execution of the generated code directly during the execution of the program. It can be an interpreter or a compiler.

Next is the initialization of the necessary structures for the system in which the LLVM is running, as well as the actual initialization of the specified objects:
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" );

Return 42


delegate int IntFunc();

private static void Function42()
{
Console .Write( "creating ret42..." );
// ret42 int(void)
var rettype = IntegerType.GetInt32(context);
var intfunc = new FunctionType(rettype);
var ret42 = module.CreateFunction( "ret42" , intfunc);
// .NET, stdcall
ret42.CallingConvention = CallingConvention.StdCallX86;

// .
//
var block = new Block( "ret42root" , context, ret42);
// - 42
var c42 = rettype.Constant(42, true );
//
//
var instructions = new InstructionBuilder(context, block);
// ,
instructions.Return(c42);
Console .WriteLine( "OK" );

Console .Write( "compiling ret42..." );
// - ,
// , LLVM
// , - -
// - ( { i32 i32 } 32- int)
var wrapper = engine.CreateWrapper(ret42, context, module);
// .NET- . LLVM
var fun = engine.GetDelegate<IntFunc>(wrapper);
Console .WriteLine( "OK" );

Console .Write( "executing..." );
Console .WriteLine(func());
}


* This source code was highlighted with Source Code Highlighter .

Source: https://habr.com/ru/post/92070/


All Articles