[llvm-dev] Fwd: I cannot change value of global variable in LLVM IR using IRBuilder

539 views
Skip to first unread message

Emma Luciano via llvm-dev

unread,
Jun 3, 2020, 4:35:37 AM6/3/20
to llvm...@lists.llvm.org

Hi Everyone,

I'm quite new to LLVM and I want to update value of global variable in LLVM IR. I created new global variable in ModulePass:

bool runOnModule(llvm::Module &M) {
    IRBuilder<> Builder(M.getContext());
    Instruction *I = &*inst_begin(M.getFunction("main"));
    Builder.SetInsertPoint(I);
    M.getOrInsertGlobal("globalKey", Builder.getInt64Ty());
    GlobalVariable* gVar = M.getNamedGlobal("globalKey");
    gVar->setLinkage(GlobalValue::InternalLinkage);
    gVar->setAlignment(Align(8));
    gVar->setInitializer(Builder.getInt64(0));
    gVar->setConstant(false);

    for (Function &F : M.functions()) {
        InstructionVisitor visitor(DL, getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(F));
        for (Instruction &I : instructions(F)) {
            visitor.visit(I);
        }
    }
    return true;
}

Later in InstructionVisitor I try to update it like that:

IRBuilder<> Builder(I->getContext());
Builder.SetInsertPoint(I->getNextNode());

GlobalVariable* key = I->getModule()->getNamedGlobal("globalKey");

if (key) {
    LoadInst* load = Builder.CreateLoad(key);
    Value* inc = Builder.CreateAdd(load, Builder.getInt64(1));
    StoreInst* store = Builder.CreateStore(inc, key);
}

I print that global variable during execution of instrumented code. I access it's value by key->getOperand(0), but it's unchanged. I'm using ORC JIT based on this tutorial: https://llvm.org/docs/tutorial/BuildingAJIT2.html and I run ModulePass from optimizeModule function from this tutorial.

In IR it looks like that:

  %2 = load i64, i64* @globalKey
  %3 = add i64 %2, 1
  store i64 %3, i64* @globalKey

I tried updating value of global variable, which was present in source code that I'm instrumenting. It didn't work either.

I created corresponding stackoverflow topic: https://stackoverflow.com/questions/62142574/how-can-i-update-global-variable-value-in-llvm-ir-using-irbuilder?fbclid=IwAR2X7uGhUjm_SN2UcxWYqaRQW2-cs6iPbMx2_tbKubeyYUkZ_pS6rkFfY9I

I will be really grateful for help.

Regards,

Emma Luciano

Eli Friedman via llvm-dev

unread,
Jun 3, 2020, 5:21:28 AM6/3/20
to Emma Luciano, llvm...@lists.llvm.org

Suppose I have the following program:

 

$ cat test.c

int a = 0;

int main() { a = 1; };

 

Then I compile and run it:

$ clang test.c

$ ./a.out

 

Then I print the contents of test.c again:

 

$ cat test.c

int a = 0;

int main() { a = 1; }

 

Why does it say “int a = 0;”?  The program set it to 1, no?

 

As far as I can tell, this is equivalent to your question… except it’s less obvious because the “source code” is an LLVM IR module in memory.

 

Maybe you’re looking for ExecutionSession::lookup?  The same way the tutorial computes the address of “main”, you can compute the runtime address of any other externally visible symbol.

 

See also https://llvm.org/docs/ORCv2.html , https://www.youtube.com/watch?v=hILdR8XRvdQ .

 

-Eli

Emma Luciano via llvm-dev

unread,
Jun 3, 2020, 5:53:21 AM6/3/20
to Eli Friedman, llvm...@lists.llvm.org
I don't think it's the same problem as you described. By printing I meant calling printf function and passing my global variable as one of the arguments.

My code:

Instruction* InstructionVisitor::incrementGlobalKey(Instruction* I) {

IRBuilder<> Builder(I->getContext());
Builder.SetInsertPoint(I->getNextNode());

GlobalVariable* key = I->getModule()->getNamedGlobal("globalKey");

if (key) {
LoadInst* load = Builder.CreateLoad(key);
Value* inc = Builder.CreateAdd(load, Builder.getInt64(1));
StoreInst* store = Builder.CreateStore(inc, key);
return store;
}
return I;
}

Instruction* InstructionVisitor::print(Instruction* I, const char* text, Value* arg1, Value* arg2, Value* arg3, Value* arg4) {
Function* printfFn = I->getModule()->getFunction("printf");
if (printfFn) {
IRBuilder<> Builder(I->getContext());
Builder.SetInsertPoint(I->getNextNode());
Value* convertedText = Builder.CreateGlobalStringPtr(text);

std::vector <Value *> params;
params.push_back(convertedText);
if (arg1)
params.push_back(arg1);
if (arg2)
params.push_back(arg2);
if (arg3)
params.push_back(arg3);
if (arg4)
params.push_back(arg4);

return Builder.CreateCall(printfFn, params);
}
return I;
}

void InstructionVisitor::visitCallInst(CallInst &CI) {
if (isAllocationFn(&CI, &TLI)) {
Value* allocatedAddress = &CI;
Instruction* I = &CI;
Value* allocatedSize = I->getOperand(0);
Instruction* next = incrementGlobalKey(I);

GlobalVariable* key = I->getModule()->getNamedGlobal("globalKey");
const char* message = "Allocated address: 0x%p, size: %d, key: %lld\n";
print(next, message, allocatedAddress, allocatedSize, key->getOperand(0));
}
}

Code that I'm executing (source code) is:
int main()
{
char* buffer;
int size = 101;
buffer = new char[size];
printf("CHECK address: 0x%p, size: %d\n", buffer, size);
TestClass* test = new TestClass(1, 2);
printf("(CHECK address: 0x%p, size: %llu\n", test, sizeof(TestClass));

delete buffer;
delete test;
}

And program output after instrumentation:

Allocated address: 0x000001CD326C1B20, size: 101, key: 0
CHECK address: 0x000001CD326C1B20, size: 101
Allocated address: 0x000001CD326C1B90, size: 8, key: 0
CHECK address: 0x000001CD326C1B90, size: 8

Regards,
Emma Luciano

David Blaikie via llvm-dev

unread,
Jun 3, 2020, 2:56:39 PM6/3/20
to Emma Luciano, llvm...@lists.llvm.org
I'm with Eli on this "GlobalVariable" is not the actual global
variable in memory - it's the IR representation of the global variable
before it is compiled to machine code & allocated in the running
process - it always has the same value/isn't affected by the execution
of loads and stores at runtime.

> _______________________________________________
> LLVM Developers mailing list
> llvm...@lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
_______________________________________________
LLVM Developers mailing list
llvm...@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev

Johannes Doerfert via llvm-dev

unread,
Jun 3, 2020, 4:18:50 PM6/3/20
to David Blaikie, Emma Luciano, llvm...@lists.llvm.org

Right.


Maybe I can put this a bit differently:

A `llvm::GlobalVariable` is *not* the source variable but a pointer to the storage location of the source variable.

This is the same for an `llvm::AllocaInst` that represents a local variable.

Using a source variable means reading the `llvm::GlobalVariable` (or `llvm::AllocaInst`) that models the memory allocated for the source variable.

Changing the variable corresponds to a write.


Hope this helps :)

Emma Luciano via llvm-dev

unread,
Jun 4, 2020, 4:05:08 AM6/4/20
to Johannes Doerfert, David Blaikie, Eli Friedman, llvm...@lists.llvm.org
Hi,

I understood that I have been incrementing that global variable the whole time, but printing wrong stuff. I added missing load of global variable and now I am passing the loaded value to printf function.
Code looks like this and works fine:
Instruction* InstructionVisitor::getGlobalValue(Instruction* I, StringRef Name) {

    IRBuilder<> Builder(I->getContext());
    Builder.SetInsertPoint(I->getNextNode());

    GlobalVariable* key = I->getModule()->getNamedGlobal(Name);

    if (key) {
        LoadInst* load = Builder.CreateLoad(key);

        return load;
    }
    return nullptr;

}

void InstructionVisitor::visitCallInst(CallInst &CI) {
    if (isAllocationFn(&CI, &TLI)) {
        Value* allocatedAddress = &CI;
        Instruction* I = &CI;
        Value* allocatedSize = I->getOperand(0);

        Instruction* next = incrementGlobalKey(I, allocatedAddress, allocatedSize);
        Instruction* loadKey = getGlobalValue(next, "globalKey");


        const char* message = "Allocated address: 0x%p, size: %d, key: %lld\n";

        next = print(loadKey, message, allocatedAddress, allocatedSize, loadKey);
    }
}

Thank you,
Emma Luciano
Reply all
Reply to author
Forward
0 new messages