Function - replaceAllUsesWith

Hello LLVM-World,

currently I play around with a „llvm::Module” and an external function defined there “puts”. Normally this function gets resolved in the JIT-Process but I wonder about two things:

Hi Björn,

Can I resolve the function already in this step? I used “replaceAllUsesWith” and passed a “llvm::ConstantInt” to the function. But this didn’t worked.

In general it's good to tell us why something didn't work (error
messages, assertions etc). In this case I'd guess it's because the
types don't match up: you probably have to wrap your int in a
ConstantExpr::getPointerCast to the same type you're replacing.

What might happen if I have two modules and use “replaceAllUsesWith” on a function of Module A, passing a function of Module B.

Nothing good. You have to copy the function (and its dependencies)
into the new module yourself. CloneFunction will probably be helpful
there, or maybe just linking the modules together.

Cheers.

Tim.

I’m not sure if I followed correctly, but you can’t replace a function declaration with a constant int. The value for the function will be used (mostly) as an argument to the call instruction, which won’t really be able to operate on an int. It isn’t clear to me what you’re trying to do exactly, replace the call to puts with an indirect call to the pointer value that correspond to puts in your current process? You would need to at least cast this pointer value to the right type, and use an indirect call.

Best,

Hello LLVM-World,

currently I play around with a „llvm::Module” and an external function defined there “puts”. Normally this function gets resolved in the JIT-Process but I wonder about two things:

  1. Can I resolve the function already in this step? I used “replaceAllUsesWith” and passed a “llvm::ConstantInt” to the function. But this didn’t worked.

I'm not sure if I followed correctly, but you can't replace a function declaration with a constant int. The value for the function will be used (mostly) as an argument to the call instruction, which won't really be able to operate on an int. It isn't clear to me what you're trying to do exactly, replace the call to puts with an indirect call to the pointer value that correspond to puts in your current process? You would need to at least cast this pointer value to the right type, and use an indirect call.

Hey Mehdi,

I simply try overloading “puts” with a custom address before I start the JIT process. I want to replace the call to “puts” with my own address. For a test purpose I tried this now:
              mainModue->getFunction("puts")->replaceAllUsesWith(
                     llvm::ConstantExpr::getPointerCast(
                           llvm::ConstantInt::get(llvm::IntegerType::get(context, 64), 0xF),
                           mainModue->getFunction("puts")->getType()
                     )
              );
This code will crash the application though. I know that 0xF is not a correct address and that there can be stuff optimized, but currently I just want to ‘see’ that “puts” was overloaded with 0xF.

Kind greetings
Björn

Best,

Hi Björn

What does the IR code look like when you dump your module?
llvm::outs() << mainModule;

I guess for the external function “puts” it will have a declaration like this:
declare i32 @puts(i8*)

When loading your module in the JIT, RuntimeDyld will resolve it to an actual address. This lookup is done by name and it happens in a stage called external symbol resolution. You should be able to inspect how this works by setting a breakpoint here:
Hope it helps. Stefan

Hey Stefan,

The function looks like this:
“; Function Attrs: nounwind

declare i32 @puts(i8* nocapture readonly) local_unnamed_addr #2

I wondered if I can do the external symbol resolution without using the JIT and RuntimeDyld (for now). For me it sounds like something that could be possible…

Kind greetings

Björn

I'm virtually certain it is. I think lldb does it, in fact. You
mentioned the pointercast didn't work, but didn't give any details on
how or what actually crashed. Do you have more you can tell us?

Also, hopefully you're using a build of LLVM with assertions enabled,
that'll catch errors much earlier.

Cheers.

Tim.

Hey Tim,

Sadly I have currently only a release build of LLVM7 with no assertions turned on... So I just know that the line of code I posted is crashing.
No output, no anything....just...Crash...

Kind greetings
Björn

Sadly I have currently only a release build of LLVM7 with no assertions turned on...

That's definitely the first thing you should fix. Preferably a debug
build too. The only reason you should ever be debugging against a
release build of LLVM is if you have a Heisenbug that doesn't happen
otherwise. It's a horrible experience.

So I just know that the line of code I posted is crashing.
No output, no anything....just...Crash...

Even a release build can give you a backtrace if you attach a
debugger, though as I've said I wouldn't normally bother.

Cheers.

Tim.

I could actually track down the cause of the problem:

mainModue->getFunction("puts")->replaceAllUsesWith(
llvm::ConstantExpr::getPointerCast(
llvm::ConstantInt::get(llvm::IntegerType::get(context, 64), 0xF),
mainModue->getFunction("puts")->getType()
)
);
The problem is the line where I receive the type of the function "puts", it will crash the application - when used as the parameter for "getPointerCast". I generated a new type, then the function didn't crashed anymore.
Is there a way to copy the value? I want to ensure to use the correct type...

Kind greetings
Björn

I don't think copying is the issue, you're just passing pointers
within a single Context around by the looks of it.

I have just noticed the getPointerCast actually only does ptrtoint but
you want inttoptr, without assertions it's possible that's doing bad
things in a non-obvious way. It should certainly be getIntToPtr
anyway.

Cheers.

Tim.

What does that mean for my code and the idea?
I'm a really unexperienced LLVM user...

You should definitely change getPointerCast to getIntToPtr (the
interface looks otherwise identical). It may solve your problems, or
it may not.

You should also build LLVM with assertions and probably debug mode, as
I said before. The output when that crashes is 100x more useful to
people trying to help you than anything you'll get from a release
build.

Cheers.

Tim.

Hey Tim,

Using "getIntToPtr" worked fine! Thank you!

Kind greetings
Björn