Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function pointer as Argument to call

Tags:

llvm

I am trying to create a call to a function foo that receives a function pointer (with signature void bar(void)) as argument. From This post I got the basic Idea to accomplish this. First I register the Foo function. Bar is actually a function that has been compiled by LLVM so there is no registration neccessary.

FunctionType* BarType =  FunctionType::get(Type::getVoidTy(getGlobalContext()), false);

Type* FooType[1];
FooType[0] = static_cast<Type*>(BarType)->getPointerTo();
ArrayRef<Type*> FooTypeARef(FooType, 1);

FunctionType* signature = FunctionType::get(Type::getInt32Ty(getGlobalContext()), FooTypeARef, false);
Function* func = Function::Create(signature, Function::ExternalLinkage, "Foo", TheModule);
LLVM_ExecutionEngine()->addGlobalMapping(func, const_cast<void*>(&Foo));

This is how the actual call is inserted (Case I)

std::vector<Value*> ArgsV_Foo;
Function *FooFun= LLVM_Module()->getFunction("Foo");
Function* BarFun = LLVM_Module()->getFunction("Bar");

ArgsV_Foo.push_back( BarFun );

LLVM_Builder()->CreateCall(FooFun, ArgsV, "calltmp")

However, this aborts inside CreateCall with the reason "Calling a function with a bad signature". I am not sure if the line ArgsV_Foo.push_back( BarFun ) is correct.

A different approach that seems possible to me is to use ExecutionEngine to get a pointer to Bar, but I do not understand how to convert the resulting function pointer to a llvm::Value* (Case II)

std::vector<Value*> ArgsV_Foo;
Function *FooFun= LLVM_Module()->getFunction("Foo");
Function* BarFun = LLVM_Module()->getFunction("Bar");

void* BarFunPtr = LLVM_ExecutionEngine()->getPointerToFunction(BarFun);
Value* val = ??
ArgsV_FEFork.push_back(val);

LLVM_Builder()->CreateCall(FooFun, ArgsV, "calltmp")

Maybe someone has an idea how to accomplish the second case or confirm that the assignment in the first case is correct (and the problem sits elsewhere).

like image 455
antipattern Avatar asked Mar 19 '26 06:03

antipattern


1 Answers

Regarding the 1st case:

I'm not quite sure what's going on there. Why do you upcast BarType, for example? In any case, an easy way to check it out would be to call ->dump() on all the types involved and check out for yourself what the differences are.

Also, avoid using static_cast on LLVM objects - there are more canonical ways to cast.

To solve the 2nd case:

  1. Cast the function pointer (BarFunPtr) to an integer.
  2. Create a constant integer in LLVM using the result of (1) as the value. Remember - anything that you compute outside the JITted code is a constant as far as that code is concerned.
  3. Cast the constant integer from (2) to a pointer via inttoptr. The pointer's type should be a function pointer matching bar's type.
  4. Use the result of (3) as the call target.

Regarding ArrayRefs

Finally, just FYI, there are easier ways to create ArrayRef instances.... In particular you might be interested in its implicit single-element constructor :-)

like image 182
Oak Avatar answered Mar 24 '26 22:03

Oak