In my LLVM code, I create extern "C"
wrapper functions for this, and insert LLVM function declarations into the module in order to call them. Then, a good way to make LLVM know about the functions is not to let it use dlopen
and search for the function name in the executing binary (this is a pain in the ass, since the function names need to be in the .dynsym
section, and it is slow too), but to do the mapping manually, using ExecutionEngine::addGlobalMapping.
Just get the llvm::Function*
of that declaration and the address of the function as given in C++ by &functionname
converted to void*
and pass these two things along to LLVM. The JIT executing your stuff will then know where to find the function.
For example, if you wanted to wrap QString
you could create several functions that create, destroy and call functions of such an object
extern "C" void createQString(void *p, char const*v) {
new (p) QString(v); // placement-new
}
extern "C" int32_t countQString(void *p) {
QString *q = static_cast<QString*>(p);
return q->count();
}
extern "C" void destroyQString(void *p) {
QString *q = static_cast<QString*>(p);
q->~QString();
}
And create proper declarations and a mapping. Then you can call
these functions, passing along a memory region suitably aligned and sized for QString
(possibly alloca
'ed) and a i8*
pointing to the C string data for initialization.