Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with AddGlobalMapping usage #22

Closed
rflechner opened this issue Jul 24, 2015 · 5 comments
Closed

Problem with AddGlobalMapping usage #22

rflechner opened this issue Jul 24, 2015 · 5 comments

Comments

@rflechner
Copy link

Hi,

I would like to call a C# function from LLVM bytecode.

To understand the mecanism, I created a "Display" function and I tried to use AddGlobalMapping.

But I have a problem with function resolution at runtime.

My program outputs:

; ModuleID = 'LLVMSharpIntro'
target triple = "i686-pc-windows-msvc-elf"

; Function Attrs: nounwind
declare void @display() #0

define i32 @sum(i32, i32) {
entry:
  %tmp = add i32 %0, %1
  call void @display()
  ret i32 %tmp
}

attributes #0 = { nounwind }
LLVM ERROR: Program used external function 'display' which could not be resolved!

My small program is:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using LLVMSharp;

namespace ConsoleApplication1
{
    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int Add(int a, int b);

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void DisplayDelegate();

        public static void Display()
        {
            Console.WriteLine("coucou");
        }

        private static void Main(string[] args)
        {
            LLVMBool False = new LLVMBool(0);
            //LLVMModuleRef mod = LLVM.ModuleCreateWithName("LLVMSharpIntro");
            LLVMModuleRef mod = LLVM.ModuleCreateWithNameInContext("LLVMSharpIntro", LLVM.GetGlobalContext());

            LLVMExecutionEngineRef engine;
            IntPtr error;
            LLVM.LinkInMCJIT();
            LLVM.InitializeX86Target();
            LLVM.InitializeX86TargetInfo();
            LLVM.InitializeX86TargetMC();
            LLVM.InitializeX86AsmPrinter();

            var platform = Environment.OSVersion.Platform;
            if (platform == PlatformID.Win32NT) // On Windows, LLVM currently (3.6) does not support PE/COFF
            {
                LLVM.SetTarget(mod, Marshal.PtrToStringAnsi(LLVM.GetDefaultTargetTriple()) + "-elf");
            }


            var options = new LLVMMCJITCompilerOptions();
            var optionsSize = (4 * sizeof(int)) + IntPtr.Size; // LLVMMCJITCompilerOptions has 4 ints and a pointer

            LLVM.InitializeMCJITCompilerOptions(out options, optionsSize);
            LLVM.CreateMCJITCompilerForModule(out engine, mod, out options, optionsSize, out error);
            //LLVM.CreateExecutionEngine(out engine, mod, out error);

            LLVMBuilderRef builder = LLVM.CreateBuilder();

            /* display */
            LLVMTypeRef[] no_param_types = { LLVM.VoidType() };
            LLVMTypeRef voidType = LLVM.FunctionType(LLVM.VoidType(), new LLVMTypeRef[0], false);
            var display = LLVM.AddFunction(mod, "display", voidType);
            display.SetLinkage(LLVMLinkage.LLVMExternalLinkage);
            /* end display */

            DisplayDelegate dd = Display;
            var p1 = Marshal.GetFunctionPointerForDelegate(dd);
            var mock = LLVM.GetNamedFunction(mod, "display");
            LLVM.AddGlobalMapping(engine, mock, p1);
            LLVM.SetFunctionCallConv(mock, (uint)LLVMCallConv.LLVMCCallConv);
            LLVM.AddFunctionAttr(mock, LLVMAttribute.LLVMNoUnwindAttribute);

            /* sum */
            LLVMTypeRef[] param_types = { LLVM.Int32Type(), LLVM.Int32Type() };
            LLVMTypeRef ret_type = LLVM.FunctionType(LLVM.Int32Type(), out param_types[0], 2, False);
            LLVMValueRef sum = LLVM.AddFunction(mod, "sum", ret_type);
            var entry = LLVM.AppendBasicBlock(sum, "entry");
            LLVM.PositionBuilderAtEnd(builder, entry);
            LLVMValueRef tmp = LLVM.BuildAdd(builder, LLVM.GetParam(sum, 0), LLVM.GetParam(sum, 1), "tmp");
            LLVMValueRef result1 = new LLVMValueRef();
            var toCall = LLVM.GetNamedFunction(mod, "display");
            LLVM.BuildCall(builder, toCall, new LLVMValueRef[0], "");
            LLVM.BuildRet(builder, tmp);
            /* end sum */

            LLVM.VerifyModule(mod, LLVMVerifierFailureAction.LLVMAbortProcessAction, out error);
            LLVM.DisposeMessage(error);

            LLVM.DumpModule(mod);

            var addMethod = (Add)Marshal.GetDelegateForFunctionPointer(LLVM.GetPointerToGlobal(engine, sum), typeof(Add));
            int result = addMethod(10, 10);

            Console.WriteLine("Result of sum is: " + result);

            if (LLVM.WriteBitcodeToFile(mod, "sum.bc") != 0)
                Console.WriteLine("error writing bitcode to file, skipping");

            LLVM.DisposeBuilder(builder);
            LLVM.DisposeExecutionEngine(engine);
            Console.ReadKey();
        }

    }
}

Did I missed something ?

Thank you.

Romain.

@mjsabby
Copy link
Contributor

mjsabby commented Jul 24, 2015

Calling into managed code is not as straight forward as you'd like. I've pasted a working example that calls into a static delegate sort of like you wanted.

The interesting function is ReversePInvoke -- you'll have to keep changing this depending on your parameters. I've logged issue #23 to make it automatic in LLVMSharp -- I have all the code, it's in a private repo for another project, but it makes more sense to put it here since it'll be useful to more number of people.

Anyway, here it is.

namespace LLVMSharpIntroForReversePInvoke
{
    using System;
    using System.Runtime.InteropServices;
    using LLVMSharp;

    class Program
    {
        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate int Add(int a, int b);

        [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
        public delegate void PrintSumDelegate(int a, int b, int sum);

        [AllowReversePInvokeCalls]
        public static void PrintSum(int a, int b, int sum)
        {
            Console.WriteLine("Sum for {0}+{1} is: {2}", a, b, sum);
        }

        private static LLVMValueRef ReversePInvoke(LLVMBuilderRef builder, LLVMTypeRef callTargetTypeRef, LLVMValueRef delegateAddressParameter, out LLVMValueRef args, uint numArgs)
        {
            var ptrType = LLVM.PointerType(callTargetTypeRef, 0);
            var delegateAddress = LLVM.BuildAlloca(builder, LLVM.Int64Type(), "delegate.value");
            var alloca = LLVM.BuildAlloca(builder, ptrType, "delegate.addr");
            LLVM.BuildStore(builder, delegateAddressParameter, delegateAddress);
            LLVM.BuildStore(builder, LLVM.BuildIntToPtr(builder, LLVM.BuildLoad(builder, delegateAddress, "delegate.addr.load"), ptrType, "delegate.funcptr"), alloca);
            return LLVM.BuildCall(builder, LLVM.BuildLoad(builder, alloca, "delegate"), out args, numArgs, string.Empty);
        }

        static void Main(string[] args)
        {
            LLVMBool False = new LLVMBool(0);
            LLVMBool True = new LLVMBool(1);
            LLVMModuleRef mod = LLVM.ModuleCreateWithName("LLVMSharpIntro");

            LLVMTypeRef[] param_types = { LLVM.Int32Type(), LLVM.Int32Type() };
            LLVMTypeRef ret_type = LLVM.FunctionType(LLVM.Int32Type(), out param_types[0], 2, False);
            LLVMValueRef sum = LLVM.AddFunction(mod, "sum", ret_type);

            LLVMBasicBlockRef entry = LLVM.AppendBasicBlock(sum, "entry");

            LLVMBuilderRef builder = LLVM.CreateBuilder();
            LLVM.PositionBuilderAtEnd(builder, entry);

            var sumValue = LLVM.BuildAdd(builder, LLVM.GetParam(sum, 0), LLVM.GetParam(sum, 1), "tmp");

            LLVMTypeRef[] argTypesToPrintSum = new LLVMTypeRef[3];
            argTypesToPrintSum[0] = LLVM.Int32Type();
            argTypesToPrintSum[1] = LLVM.Int32Type();
            argTypesToPrintSum[2] = LLVM.Int32Type();

            LLVMValueRef[] argsToPrintSum = new LLVMValueRef[3];
            argsToPrintSum[0] = LLVM.GetParam(sum, 0);
            argsToPrintSum[1] = LLVM.GetParam(sum, 1);
            argsToPrintSum[2] = sumValue;

            var callTargetType = LLVM.FunctionType(LLVM.VoidType(), out argTypesToPrintSum[0], 3, False);
            ReversePInvoke(builder, callTargetType, LLVM.ConstInt(LLVM.Int64Type(), (ulong)Marshal.GetFunctionPointerForDelegate(new PrintSumDelegate(PrintSum)).ToInt64(), True), out argsToPrintSum[0], 3);

            LLVM.BuildRet(builder, sumValue);
            LLVM.DumpModule(mod);

            IntPtr error;
            LLVM.VerifyModule(mod, LLVMVerifierFailureAction.LLVMAbortProcessAction, out error);
            LLVM.DisposeMessage(error);

            LLVMExecutionEngineRef engine;

            LLVM.LinkInMCJIT();
            LLVM.InitializeX86Target();
            LLVM.InitializeX86TargetInfo();
            LLVM.InitializeX86TargetMC();
            LLVM.InitializeX86AsmPrinter();

            var platform = Environment.OSVersion.Platform;
            if (platform == PlatformID.Win32NT) // On Windows, LLVM currently (3.6) does not support PE/COFF
            {
                LLVM.SetTarget(mod, Marshal.PtrToStringAnsi(LLVM.GetDefaultTargetTriple()) + "-elf");
            }

            var options = new LLVMMCJITCompilerOptions();
            var optionsSize = (4 * sizeof(int)) + IntPtr.Size; // LLVMMCJITCompilerOptions has 4 ints and a pointer

            LLVM.InitializeMCJITCompilerOptions(out options, optionsSize);
            LLVM.CreateMCJITCompilerForModule(out engine, mod, out options, optionsSize, out error);

            var addMethod = (Add)Marshal.GetDelegateForFunctionPointer(LLVM.GetPointerToGlobal(engine, sum), typeof(Add));
            int result = addMethod(10, 10);

            Console.WriteLine("Result of sum is: " + result);

            if (LLVM.WriteBitcodeToFile(mod, "sum.bc") != 0)
            {
                Console.WriteLine("error writing bitcode to file, skipping");
            }

            LLVM.DumpModule(mod);

            LLVM.DisposeBuilder(builder);
            LLVM.DisposeExecutionEngine(engine);
            Console.ReadKey();
        }
    }
}

@mjsabby
Copy link
Contributor

mjsabby commented Jul 25, 2015

@rflechner I think your issue is likely resolved at this point. I'm going to close this issue in a day.

@rflechner
Copy link
Author

yes, everything works.
that's great !

thanks a lot for your help.

@mjsabby
Copy link
Contributor

mjsabby commented Jul 25, 2015

Np.

@mjsabby mjsabby closed this as completed Jul 25, 2015
@paganaye
Copy link

paganaye commented Apr 7, 2021

For those who try this today the signature has changed a bit
I managed to make it work with this code:

` static LLVMBool False = new LLVMBool(0);
static LLVMBool True = new LLVMBool(1);

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void PrintSumDelegate(int a, int b, int sum);

    [AllowReversePInvokeCalls]
    public static void PrintSum(int a, int b, int sum)
    {
        Console.WriteLine("Sum for {0}+{1} is: {2}", a, b, sum);
    }

    private static LLVMValueRef ReversePInvoke(LLVMBuilderRef builder, LLVMTypeRef callTargetTypeRef, LLVMValueRef delegateAddressParameter, LLVMValueRef[] args)
    {
        var ptrType = LLVM.PointerType(callTargetTypeRef, 0);
        var delegateAddress = LLVM.BuildAlloca(builder, LLVM.Int64Type(), "delegate.value");
        var alloca = LLVM.BuildAlloca(builder, ptrType, "delegate.addr");
        LLVM.BuildStore(builder, delegateAddressParameter, delegateAddress);
        LLVM.BuildStore(builder, LLVM.BuildIntToPtr(builder, LLVM.BuildLoad(builder, delegateAddress, "delegate.addr.load"), ptrType, "delegate.funcptr"), alloca);
        return LLVM.BuildCall(builder, LLVM.BuildLoad(builder, alloca, "delegate"), args, string.Empty);
    }

        var sumValue = LLVM.BuildAdd(builder, LLVM.GetParam(sum, 0), LLVM.GetParam(sum, 1), "tmp");

        LLVMTypeRef[] argTypesToPrintSum = new LLVMTypeRef[3];
        argTypesToPrintSum[0] = LLVM.Int32Type();
        argTypesToPrintSum[1] = LLVM.Int32Type();
        argTypesToPrintSum[2] = LLVM.Int32Type();

        LLVMValueRef[] argsToPrintSum = new LLVMValueRef[3];
        argsToPrintSum[0] = LLVM.GetParam(sum, 0);
        argsToPrintSum[1] = LLVM.GetParam(sum, 1);
        argsToPrintSum[2] = sumValue;

        var callTargetType = LLVM.FunctionType(LLVM.VoidType(), argTypesToPrintSum, False);
        ReversePInvoke(builder, callTargetType, LLVM.ConstInt(LLVM.Int64Type(), (ulong)Marshal.GetFunctionPointerForDelegate(new PrintSumDelegate(PrintSum)).ToInt64(), True), argsToPrintSum);

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants