How to get the address of a global variable in LLVM?

Let x be the address of a global variable g in a program at run-time. LLVM IR produces a store instruction as shown below:

store i32 30, i32* @g, align 4

I am writing an LLVM pass which will instrument the program such that x is passed to an instrumentation function func(int addr) at run-time. I can insert a call to func using IRBuilder successfully. What I am not being able to do is to insert instrumentation to collect x.

if (StoreInst *store_inst = dyn_cast(&I)) {

Value* po = store_inst->getPointerOperand();
if(isa(po)) {
errs() << "store [pointer]: " << *po << ‘\n’;

Constant *instrument_func = F.getParent()->getOrInsertFunction(“func”, Type::getVoidTy(Ctx), Type::getInt32Ty(Ctx), NULL);

IRBuilder<> builder(&I);
builder.SetInsertPoint(&B, ++builder.GetInsertPoint());

Value* args[] = {po};
builder.CreateCall(instrument_func, args);
}
}

The result of running opt is :

Call parameter type does not match function signature!
i32* @a
i32 call void bitcast (void (i64)* @func to void (i32))(i32 @a)
LLVM ERROR: Broken function found, compilation aborted!

Let `x` be the address of a global variable `g` in a program at
run-time. LLVM IR produces a store instruction as shown below:

    store i32 30, i32* @g, align 4

I am writing an LLVM pass which will instrument the program such that
`x` is passed to an instrumentation function `func(int addr)` at
run-time. I can insert a call to `func` using `IRBuilder` successfully.
What I am not being able to do is to insert instrumentation to collect `x`.

    if (StoreInst *store_inst = dyn_cast<StoreInst>(&I)) {

                        Value* po = store_inst->getPointerOperand();
                        if(isa<GlobalVariable>(po)) {
                            errs() << "store [pointer]: " << *po << '\n';

                            Constant *instrument_func =
F.getParent()->getOrInsertFunction("func", Type::getVoidTy(Ctx),
Type::getInt32Ty(Ctx), NULL);

                            IRBuilder<> builder(&I);
                            builder.SetInsertPoint(&B,
++builder.GetInsertPoint());

                            Value* args = {po};
                            builder.CreateCall(instrument_func, args);
                        }
                    }

The result of running `opt` is :

    Call parameter type does not match function signature!
    i32* @a
     i32 call void bitcast (void (i64)* @func to void (i32)*)(i32* @a)
    LLVM ERROR: Broken function found, compilation aborted!

You need a load instruction since your function takes an i32, not an i32*.... A global's value in llvm is its address, not the numeric data it contains.

Jon

I suspect he actually wants to make his function take an "i8*" and
bitcast his pointer to that type before calling it. [*]

Tim.

[*] Keeping it as an i32/i64 and using ptrtoint instead of bitcast
would also work, but be less portable and elegant.

I am a little confused. Can anyone explain me in short? The definition of func is as below:

void func(int var_addr) {
printf("[instr]: Global variable at address 0x%x\n", var_addr);
}

I want to insert a call to func just before the store instruction with the address x of global variable g as parameter.

I am a little confused. Can anyone explain me in short? The definition
of `func` is as below:

   void func(int var_addr) {
printf("[instr]: Global variable at address 0x%x\n", var_addr);
   }

I want to insert a call to `func` just before the store instruction with
the address `x` of global variable `g` as parameter.

Tim is saying that your function should be:

   void func(void *var_addr) ...

and that in llvm you want to refer to it with type `void func(i8*)`.

I only suggested the load because I was confused about what you wanted (assumed you wanted the value, because of what you had picked for the function signature).

Jon

Your error is because the function you create is "void @func(i32)" but
you're trying to pass it an i32* (the address of the global). This
mismatch is spotted by LLVM's verifier and it quits.

So you have to make them match up somehow. IMO the best way to do this
would be to instead create "void @func(i8*)" (as Joel explained) and
then use IRBuilder::CreateBitCast on "po" to convert it from an i32*
to an i8*. Then you can pass that result to @func instead of "po".

Incidentally, the "i32 call void bitcast (void (i64)* @func to void
(i32)*)(i32* @a)" line in the output suggests you're being
inconsistent about how you call getOrCreateFunction for @func
elsewhere in your code: the first time it's told to expect an i64 so
when you getOrCreateFunction a second time LLVM "helpfully" inserts a
constant bitcast of its own. This is almost certainly not a good idea.

Tim.

Thank you so much to you both. I got it working.