Adding function call in LLVM IR using IRBuilder causes assertion error

Hi,

I'm trying to add function calls in the LLVM IR using the IRBuilder class. I've read both tutorials about functions but I still get assertion errors. I allocate memory for all function arguments and pass them as explained in the tutorial.

My code is (this function is supposed to add a call to f in bb at pos):
void addCallSite(Function *f, BasicBlock *bb, BasicBlock::iterator pos) {
  std::vector<Value*> args;
  IRBuilder<> builder(bb,pos);
  for(Function::arg_iterator argit = f->arg_begin();argit!=f->arg_end();argit++){
      AllocaInst* allocInst = builder.CreateAlloca(argit->getType());
      args.push_back(allocInst);
  }
  builder.CreateCall(f,args.begin(),args.end());
}

This seems to work for functions without parameters (eg. int foo()), but once a function has a parameter I get the following assertion error:
<llvmpath>/lib/VMCore/Instructions.cpp:297: void llvm::CallInst::init(llvm::Value*, llvm::Value* const*, unsigned int): Assertion `(i >= FTy->getNumParams() || FTy->getParamType(i) == Params[i]->getType()) && "Calling a function with a bad signature!"' failed.

I've checked everything I can think of and it all seems correct to me ... Any help would be greatly appreciated!

Thanks in advance,

Marc Claesen

CreateAlloca(Type) returns an object of type Type*, the memory that
can hold an object of type Type. You probably don't want to be
creating allocas just before calling the function since 1) if that
call winds up in a loop they'll grow your stack frame without bound,
and 2) the memory they point to is initially uninitialized. Where did
the tutorial tell you to do that?

In general, when I hit one of those assertions, I gdb to it, use "p
f->dump()" to see the types of the function's arguments, and use "p
Params[i]->dump()" to see the parameter with the bad type.

CreateAlloca(Type) returns an object of type Type*, the memory that
can hold an object of type Type. You probably don't want to be
creating allocas just before calling the function since 1) if that
call winds up in a loop they'll grow your stack frame without bound,
and 2) the memory they point to is initially uninitialized. Where did
the tutorial tell you to do that?

I used CreateAllocA(Type) because I assumed that was the correct way to create a variable of a given type.

What I'm trying to do is create new variables of the types required by a function and then call the function, so it's quite simple ... I just don't know how to initialise correctly by the looks of it. What function should I use if not CreateAllocA(Type)?

Thanks in advance,

Marc

Jeffrey Yasskin wrote:

Marc Claesen <claesenm@gmail.com> writes:

I'm trying to add function calls in the LLVM IR using the IRBuilder
class. I've read both tutorials about functions but I still get
assertion errors. I allocate memory for all function arguments and pass
them as explained in the tutorial.

My code is (this function is supposed to add a call to f in bb at pos):
void addCallSite(Function *f, BasicBlock *bb, BasicBlock::iterator pos) {
  std::vector<Value*> args;
  IRBuilder<> builder(bb,pos);
  for(Function::arg_iterator argit =
f->arg_begin();argit!=f->arg_end();argit++){
      AllocaInst* allocInst = builder.CreateAlloca(argit->getType());
      args.push_back(allocInst);
  }
  builder.CreateCall(f,args.begin(),args.end());
}

This seems to work for functions without parameters (eg. int foo()), but
once a function has a parameter I get the following assertion error:
<llvmpath>/lib/VMCore/Instructions.cpp:297: void
llvm::CallInst::init(llvm::Value*, llvm::Value* const*, unsigned int):
Assertion `(i >= FTy->getNumParams() || FTy->getParamType(i) ==
Params[i]->getType()) && "Calling a function with a bad signature!"' failed.

CreateAlloca(someType) returns an AllocaInst* which has type
someType*. So if your function takes a parameter of type int, with this
chunk of code

       AllocaInst* allocInst = builder.CreateAlloca(argit->getType());
       args.push_back(allocInst);

you are passing an int*. This triggers the assert.

For now, forget about the allocas.

Another issue is that I don't see in your code the _values_ you want to
pass to the called function. Apparently you already have the function
declaration (Function *f) but you are creating a call to that function,
and you need the actual arguments (not the argument types):

inf foo(int); // declaration. you already have this elsewhere.

foo(10); // call. you need the value (10) to pass to the function.

[Please use Reply to All for sending your message to the ml too]

Marc Claesen <claesenm@gmail.com> writes:

Another issue is that I don't see in your code the _values_ you want to
pass to the called function. Apparently you already have the function
declaration (Function *f) but you are creating a call to that function,
and you need the actual arguments (not the argument types):

That's exactly the problem. I'm trying to initialise values of the
appropriate types as required by a given function and pass those. What
I'm looking for is the appropriate instructions to initialise a
variable of a given type to it's type's default value. I realise this
program will generate useless function calls but it's part of a binary
obfuscation chain.

In LLVM there is no such a thing as a type default value. Maybe that
concept exists on your language.

Creating allocas is not the solution, as the alloca is just
uninitialized space on the stack.

Suppossing that the function parameters simple enough, like integral or
floating point types, and the "default value" is zero, something like
this will do (untested):

  std::vector<Value*> args;
  IRBuilder<> builder(bb,pos);
  for(Function::arg_iterator argit =
      f->arg_begin();argit!=f->arg_end();
      argit++)
  {
      Value *arg = Constant::getNullValue(argit->getType());
      args.push_back(arg);
  }
  builder.CreateCall(f,args.begin(),args.end());

If your arguments are something more fancy, you have more work ahead
(for following the platform/language ABI, etc).