Description
I am an LLVM beginner and trying to transform LLVM C++ API to LLVMSharp in my project (suffering from C++ and CMake)
So I am implementing a HelloWorld example with LLVMSharp for learning, but there are some things wrong
I create a console program with .NET 7 by Visual Studio 2022 Preview
I install LLVMSharp and libLLVM by NuGet, and add <RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == ''">$(NETCoreSdkRuntimeIdentifier)</RuntimeIdentifier>
into csproj to solve DllNotFoundException
(#157 (comment))
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RuntimeIdentifier Condition="'$(RuntimeIdentifier)' == ''">$(NETCoreSdkRuntimeIdentifier)</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="libLLVM" Version="15.0.0" />
<PackageReference Include="LLVMSharp" Version="5.0.0" />
</ItemGroup>
</Project>
With abstruct some utilities function like CreateExtern
, DeclarePuts
, CreateFunction
, CreateMain
...
I create the following program:
using LLVMSharp;
LLVMValueRef CreateExtern(
LLVMModuleRef module,
string name,
LLVMTypeRef returnType,
LLVMTypeRef[] parameters,
bool isVarArg = false
)
{
var functionType = LLVM.FunctionType(returnType, parameters, isVarArg);
return LLVM.AddFunction(module, name, functionType);
}
LLVMValueRef DeclarePuts(LLVMModuleRef module)
{
LLVMTypeRef returnType = LLVM.Int32Type();
LLVMTypeRef[] parameters = { LLVM.PointerType(LLVM.Int8Type(), 0) };
return CreateExtern(module, "puts", returnType, parameters);
}
(LLVMValueRef, LLVMBuilderRef) CreateFunction(
LLVMModuleRef module,
string name,
LLVMTypeRef returnType,
LLVMTypeRef[] parameters,
bool isVarArgs = false
)
{
var funcType = LLVM.FunctionType(returnType, parameters, isVarArgs);
var func = LLVM.AddFunction(module, name, funcType);
var entry = LLVM.AppendBasicBlock(func, "entry");
var builder = LLVM.CreateBuilder();
LLVM.PositionBuilderAtEnd(builder, entry);
return (func, builder);
}
(LLVMValueRef, LLVMBuilderRef) CreateMain(LLVMModuleRef module)
{
return CreateFunction(module, "main", LLVM.Int32Type(), Array.Empty<LLVMTypeRef>());
}
void RunMain(LLVMModuleRef module)
{
LLVM.LinkInMCJIT();
LLVM.InitializeX86TargetMC();
LLVM.InitializeX86Target();
LLVM.InitializeX86TargetInfo();
LLVM.InitializeX86AsmParser();
LLVM.InitializeX86AsmPrinter();
LLVM.CreateExecutionEngineForModule(out var engine, module, out var _);
var main = LLVM.GetNamedFunction(module, "main");
LLVM.RunFunction(engine, main, Array.Empty<LLVMGenericValueRef>());
}
var context = LLVM.ContextCreate();
var module = LLVM.ModuleCreateWithNameInContext("Hello World", context);
var funcPuts = DeclarePuts(module);
var (_, builder_main) = CreateMain(module);
var constInt0 = LLVM.ConstInt(LLVM.Int32Type(), 0, true);
var constStr = LLVM.BuildGlobalStringPtr(builder_main, "Hello World!", "");
var parameters = new LLVMValueRef[] { constStr };
LLVM.BuildCall(builder_main, funcPuts, parameters, "");
LLVM.BuildRet(builder_main, constInt0);
LLVM.DumpModule(module);
RunMain(module);
Program crashes in LLVM.BuildCall(builder_main, funcPuts, parameters, "");
, and the console output:
Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:
--------------------------------
at LLVMSharp.LLVM.BuildCall(LLVMSharp.LLVMBuilderRef, LLVMSharp.LLVMValueRef, LLVMSharp.LLVMValueRef ByRef, UInt32, System.String)
--------------------------------
at LLVMSharp.LLVM.BuildCall(LLVMSharp.LLVMBuilderRef, LLVMSharp.LLVMValueRef, LLVMSharp.LLVMValueRef[], System.String)
at LearnLLVMSharp.Program.Main(System.String[])
By LLVM.DumpModule(module);
, the halfway result before the crash is as follows:
; ModuleID = 'Hello World'
source_filename = "Hello World"
@0 = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1
declare i32 @puts(ptr %0)
define i32 @main() {
entry:
}