IRBuilder constraints


I need to control IRBuilder(or manage IR building with other means) very strictly. The problem is in the realm of ConstInt/GlobalVariable handling, more precisely:

LLVM converts llvm::ConstantInt values to GlobalVariable addresses ad-hoc if I store a constant in a GlobalVariable, and it appears to me, that I can do nothing about it. Consider the following, shortened code:

0x18: r2 = memread(0x4000)
0x1C: r3 = memread(0x4004)
0x20: r4 = add(r2, r3)

Gets translated to:
%v0_18 = load i32, i32* inttoptr (i32 16384 to i32*), align 16384
%v0_20 = load i32, i32* inttoptr (i32 16388 to i32*), align 4
%v2_24 = add i32 %v0_20, %v0_18
which is absolutely fine, however, in another binary:

0x800004: r2 = memread(0x4000)
0x800008: r3 = memread(0x4004)
0x80000C: r6 = 0x4020
0x800010: r1 = logic_shift_right(r6, 3)
0x800014: r4 = add(r2, r3)

Gets translated to:

@global_var_4020.3 = global i32 0
@global_var_4000.4 = local_unnamed_addr global i32 0
@global_var_4004.5 = local_unnamed_addr global i32 0

%v0_800004 = load i32, i32* @global_var_4400.1, align 4
%v0_800008 = load i32, i32* @global_var_4404.2, align 4
%v0_800010 = lshr (i32 ptrtoint (i32* @global_var_4020.3 to i32), i32 3)
%v2_800014 = add i32 %v0_800008, %v0_800004

The funny thing, as you can see, is that now the address range is nowhere near 0x4000(just like in the previous example). But LLVM uses global variables, which happen to have the correct addresses. Even more strange is, that for a bit shifting operation a global variable address is used as operand.

The IRBuilder code for the memread instruction is the following for both cases(simplified version):

int constVal = param1;
llvm::IRBuilder<>& irb;
llvm::Value* op1 = llvm::ConstantInt::getSigned(irb.getInt32Ty(), constVal);
auto* pt = llvm::PointerType::get(op1->getType(), 0);
auto* addr = irb.CreateIntToPtr(op1, pt);
auto* loaded = irb.CreateLoad(addr);
irb.CreateStore(loaded, module->getNamedGlobal(regname));

I cannot get LLVM to leave an llvm::Value as ConstantInt in every case, if I pass it to IRBuilder for processing(for example through a globalvariable storing instruction).
Do you know how I can tell IRBuilder, or any other part of LLVM, to leave a supplied or retrieved llvm::Value as const?

Best regards,


How sure are you that it's the IRBuilder doing this? It looks
completely unsound to me in the general case (there's nothing tying
the new globals to their original address), and I've never seen
anything similar.

But it looks very plausibly like what you'd get if you triggered a
completely different part of some decompiler tool to decide that your
accesses are generic enough to be modelled as globals in LLVM.



You are right Tim, it’s converted later on, outside LLVM in a symbolic tree analysis phase.
Thank you.