Weird problems on calling an external function from MCJIT on Windows(mingw)

Hi,
I have a IR file generated by Clang:

; ModuleID = ‘test_load_lib.c’
target datalayout = “e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32”
target triple = “i686-pc-mingw32”

declare i32 @a_outside_func(i32)

define i32 @test_func() {
entry:
%call = call i32 @a_outside_func(i32 15)
ret i32 %call
}

where a_outside_func is a function defined on my code:

extern “C” int a_outside_func(int a)
{
return a + 50;
}

and following code is to get MCJIT work:

#define prt(x) if(x) { cout << x << endl; }

LLVMInitializeAllTargets();
LLVMInitializeAllTargetMCs();
LLVMInitializeAllTargetInfos();
LLVMInitializeAllAsmParsers();
LLVMInitializeAllAsmPrinters();
LLVMInitializeAllDisassemblers(); // just initialize them all…
prt(a_outside_func(50)); // afraid of linker optmize it out

char *err = 0;
LLVMMemoryBufferRef ll_f = 0;
LLVMModuleRef m = 0;
LLVMCreateMemoryBufferWithContentsOfFile(“test_load_lib.ll”,&ll_f,&err); //read .ll
prt(err);
LLVMParseIRInContext(LLVMGetGlobalContext(),ll_f,&m,&err); // ll_f doesnt need freeing
prt(err);
LLVMDumpModule(m);

LLVMLinkInMCJIT();
LLVMExecutionEngineRef ee = 0;
LLVMCreateMCJITCompilerForModule(&ee,m,0,0,&err);
prt(err);
using tf_t = int ();
tf_t f = (tf_t)LLVMGetPointerToGlobal(ee,LLVMGetNamedFunction(m,“test_func”));

At first i got "LLVM ERROR: Incompatible object format! "
But by reading some articles I append LLVMSetTarget(m,“i686-pc-mingw32”); and it’s fixed.
Then I got “LLVM ERROR: Program used external function ‘a_outside_func’ which could not be resolved!”.

I assumed my program didn’t export the symbol properly.Thus,I use nm to check my program’s export and I found “a_outside_func” was renamed to “_a_outside_func”
.
For it I rename the function name in the IR to “_a_outside_func”.But it seemed to make no difference: “LLVM ERROR: Program used external function ‘_a_outside_func’ which could not be resolved!”.

After a day’s wasting I unconsciously packed my external function “a_outside_func” into a shared object,called llvm::sys::DynamicLibrary::LoadLibraryPermanently(“ext_func.so”); at the beginning of the program and named the function “_a_outside_func” in the IR.
OMG IT WORKS THEN?!
So I’d like to ask why llvm cant resolve my external function from the program itself(in fact i dont get such problems on linux)?

Hello

While there is a symbol in the object file, there is nothing like this
in the final executable (well, you can try to export functions from
PE/COFF executable, but this is pretty non-standard technique). This
is the biggest difference wrt linux, where all the visible symbols are
exported by default from the binary.

Most probably, the best way here is to create an explicit mapping
between a GlobalValue which represents your external function and the
address of your function. ExecutionEngine::addGlobalMapping() is your
friend here.

Hello
I quite thank you for your advice,but I have to tell that it made no difference too calling “LLVMAddGlobalMapping(ee,LLVMGetNamedFunction(m,”_a_outside_func"),(void*)(&a_outside_func));".

Are you sure, that LLVMGetNamedFunction(m,"_a_outside_func") does not
return NULL? I believe it should be
LLVMGetNamedFunction(m,"a_outside_func")

oh,I'm sorry to make such a stupid mistake...But I still have to tell the
correct one still didnt make difference...so weird

I’d like to take all my code here to make things easier,they are stil unble to run properly.
cpp code: http://paste.ofcode.org/uNxEMvQTkZyjg2RTwjmXhh

IR code : http://paste.ofcode.org/hhkFUz8weGKSUXXZZnNuEp
Thanks

At some point LLVMAddGlobalMapping was broken/unsupported for MCJIT. It sounds like that is still the case.

There are a couple of ways around this with the C++ interface (either add the symbol using sys::DynamicLibrary::AddSymbol() or create a custom memory manager which provides direct symbol resolution for the local functions you might use), but I don’t think either of these solutions are supported in the C interface.

I don’t think it would take much work to get the global mapping support added back into MCJIT. When this last came up I believe that the other approaches were judged to be better. Your C-interface use case might be sufficient to argue for global mapping support.

-Andy