Skip to content

HelloWorld example implementation #199

Closed
@CWKSC

Description

@CWKSC

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:
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions