I have had great luck in the last couple of months getting llvm to do cool stuff with directly linked modules using llvm-as and llvm-ld. Now, I would like to get some of the same functionality working through an ExecutionEngine; however, I am having trouble making functions call across module boundaries. I know from previous discussions on this list that what I am attempting should be easy. I would really appreciate it if someone more knowledgeable could take a look at the trivial failing test I've hooked up and tell me what obvious thing I've missed, or at least what I should try next. ;;;; bar.ll define i32 @bar( i32 %a ) { %out = mul i32 %a, 2 ret i32 %out } ;;;; ;;;; foo.ll declare i32 @bar( i32 ) define i32 @main( i32 %argc, i8** %argv ) { %out = call i32 @bar( i32 4 ) ret i32 %out } ;;;; //// test.cpp #include <string> #include <vector> #include <llvm/Support/MemoryBuffer.h> #include <llvm/Bitcode/ReaderWriter.h> #include <llvm/ModuleProvider.h> #include <llvm/ExecutionEngine/ExecutionEngine.h> int main( int argc, char** argv ) { std::string error; llvm::MemoryBuffer *foo_buffer, *bar_buffer; llvm::ModuleProvider *foo_provider, *bar_provider; foo_buffer = llvm::MemoryBuffer::getFile( "foo.bc", &error ); foo_provider = llvm::getBitcodeModuleProvider(foo_buffer,&err); bar_buffer = llvm::MemoryBuffer::getFile( "bar.bc", &error ); bar_provider = llvm::getBitcodeModuleProvider(bar_buffer,&err); llvm::ExecutionEngine *engine; engine = llvm::ExecutionEngine::create( foo_provider ); engine->addModuleProvider( bar_provider ); std::vector<std::string> args; args.push_back( "foo.ll" ); llvm::Function *fn_main = engine->FindFunctionNamed( "main" ); int rv = engine->runFunctionAsMain( fn_main, args, environ ); return rv; } //// #### Makefile AS=/home/terrence/programming/OSS-rcs/llvm/Debug/bin/llvm-as LD=/home/terrence/programming/OSS-rcs/llvm/Debug/bin/llvm-ld CC=g++ LLVM_CONFIG=/home/terrence/programming/OSS-rcs/llvm/Debug/bin/llvm-config LLVM_CXXFLAGS=`${LLVM_CONFIG} --cxxflags` LLVM_LDFLAGS=`${LLVM_CONFIG} --ldflags` LLVM_LIBS=`${LLVM_CONFIG} --libs` lower: ${AS} -f -o=foo.bc foo.ll ${AS} -f -o=bar.bc bar.ll link: lower ${LD} -native -o=linked foo.bc bar.bc test: lower ${CC} -o test.o -c ${LLVM_CXXFLAGS} test.cpp ${CC} -o test test.o ${LLVM_LDFLAGS} ${LLVM_LIBS} #### Example Interactive session: : make link llvm-as -f -o=foo.bc foo.ll llvm-as -f -o=bar.bc bar.ll llvm-ld -native -o=linked foo.bc bar.bc : ./linked : echo $? 8 : make test llvm-as -f -o=foo.bc foo.ll llvm-as -f -o=bar.bc bar.ll g++ -o test.o -c `llvm-config --cxxflags` test.cpp g++ -o test test.o `llvm-config --ldflags` `llvm-config --libs` : ./test ERROR: Program used external function 'bar' which could not be resolved! fish: Job 1, “./test” terminated by signal SIGABRT (Abort) The backtrace from the abort is: #0 0x00007f25d700f535 in raise () from /lib/libc.so.6 #1 0x00007f25d70109e0 in abort () from /lib/libc.so.6 #2 0x000000000056486e in llvm::JIT::getPointerToNamedFunction (this=0x2d4bb80, Name=@0x7fffe030e6e0, AbortOnFailure=true) at Intercept.cpp:142 #3 0x00000000005651a9 in llvm::JIT::getPointerToFunction (this=0x2d4bb80, F=0x2d45dd0) at JIT.cpp:538 #4 0x000000000056d3c5 in getFunctionStub (this=0x2d5a8b0, F=0x2d45dd0) at JITEmitter.cpp:181 #5 0x000000000056d79a in getPointerToGlobal (this=0x2d5a820, V=0x2d45dd0, Reference=0x7f25d605e01a, DoesntNeedStub=false) at JITEmitter.cpp:632 #6 0x000000000056daba in finishFunction (this=0x2d5a820, F=@0x2d76b00) at JITEmitter.cpp:924 #7 0x00000000006989ff in runOnMachineFunction (this=0x2d74900, MF=@0x2d76b00) at X86CodeEmitter.cpp:118 #8 0x000000000043d1dd in llvm::MachineFunctionPass::runOnFunction (this=0x2d74900, F=@0x2d46120) at /home/terrence/programming/OSS-rcs/llvm/include/llvm/CodeGen/MachineFunctionPass.h:42 #9 0x0000000000ca95b1 in llvm::FPPassManager::runOnFunction (this=0x2d4c250, F=@0x2d46120) at PassManager.cpp:1323 #10 0x0000000000ca9b30 in llvm::FunctionPassManagerImpl::run (this=0x2d4bcb0, F=@0x2d46120) at PassManager.cpp:1281 #11 0x0000000000ca9c9a in llvm::FunctionPassManager::run (this=0x2d4bc70, F=@0x2d46120) at PassManager.cpp:1226 #12 0x0000000000564ec5 in llvm::JIT::runJITOnFunctionUnlocked (this=0x2d4bb80, F=0x2d46120, locked=@0x7fffe030eb60) at JIT.cpp:488 #13 0x00000000005651f1 in llvm::JIT::getPointerToFunction (this=0x2d4bb80, F=0x2d46120) at JIT.cpp:543 #14 0x00000000005653e0 in llvm::JIT::runFunction (this=0x2d4bb80, F=0x2d46120, ArgValues=@0x7fffe030efa0) at JIT.cpp:319 #15 0x000000000055c037 in llvm::ExecutionEngine::runFunctionAsMain (this=0x2d4bb80, Fn=0x2d46120, argv=@0x7fffe030f0c0, envp=0x7fffe030f248) at ExecutionEngine.cpp:375 #16 0x000000000041d77e in main (argc=1, argv=0x7fffe030f238) at test.cpp:25 I have tested this with a debug build of svn revision 64627 and 65938 with a full `make clean`, `svn up`, and `make`. GCC version is 4.2.2 on x86_64-pc-linux-gnu. If I invert the loading order of the foo and bar modules in test.cpp (e.g. creating the ExecutionEngine with bar_provider and adding foo_provider secondarily) I get exactly the same results, so it can find @main just fine. Thoughts? - Terrence