How do I manually add single symbols to LLIT?

Hello!

I am trying to implement basic functions for my language like printing to the standard output. I was wondering how I can add the functions to the LLJIT. I read about linking Dynamic Libraries in the docs. Can you tell me how to do it easily? In the official llvm tutorial using KaleidoscopeJIT, you can just mark a function extern and it will be callable from the IR. Can I do something similar here?

When I mark a function extern I register it in the Module, but the JIT can’t find the symbol. Is there some more configuration that needs to be done?

Thanks in advance!

To make a C++ function easily findable, you need to mark the C++ definition extern "C", that C bit is important because it disables name mangling (otherwise you’d need to look up void foo() as _ZN3fooEv). Is that what you tried?

Also, I’m not really an expert on the JIT (it could abstract this away) but even with that some systems (Darwin & Windows, I think) add an underscore to the beginning of any global. So you might need to lookup _foo instead of foo.

Thanks for the response!
That is exactly what I do! I define the function like this in my code:

extern "C" double printString(int8_t* str){
    llvm::outs() << *str;
    return 0;
}

The JIT-Error I get is the following, which means that it automatically adds an underscore to the global, as I look up for “printString”, not “_printString”:

JIT session error: Symbols not found: [ _printString ]

I also tried adding a underscore in the definition, but that doesn’t change the issue.
I probably have to add the symbol manually, but I don’t see how to do that if the function is not in a dynamic library, which for the moment is too complicated for me.

I found that introspecting the current binary to find symbol can be fragile. The more robust way to make function available is to be explicit about it (it also allow to expose static/internal functions with arbitrary symbol name).
Here is an example: llvm-project/Invoke.cpp at main · llvm/llvm-project · GitHub (there is some indirection as it is using the mlir::ExecutionEngine API, but it just forwards to the LLVM Orc machinery anyway.

Thanks for the reply!

I looked through the LLJIT docs and can’t find a way to add these symbols manually, that’s why I am asking in the first place… The easiest way after all is probably to just compile the core functions of the language into a dylib and add them like that.

The code I pointed you to (mlir::ExecutionEngine) is just wrapping LLJIT, if you follow the code you’ll get to:


void ExecutionEngine::registerSymbols(
    llvm::function_ref<SymbolMap(MangleAndInterner)> symbolMap) {
  auto &mainJitDylib = jit->getMainJITDylib();
  cantFail(mainJitDylib.define(
      absoluteSymbols(symbolMap(llvm::orc::MangleAndInterner(
          mainJitDylib.getExecutionSession(), jit->getDataLayout())))));
}

Where jit is std::unique_ptr<llvm::orc::LLJIT> jit;

1 Like