[LLVMdev] Cross-Module Function Calls

Terrence Cole terrence at zettabytestorage.com
Sun Mar 8 17:57:13 PDT 2009


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





More information about the llvm-dev mailing list