LLVM get constant integer back from Value*
Given llvm::Value* foo
and you know that foo
is actually a ConstantInt
, I believe that the idiomatic LLVM code approach is to use dyn_cast
as follows:
if (llvm::ConstantInt* CI = dyn_cast<llvm::ConstantInt>(foo)) {
// foo indeed is a ConstantInt, we can use CI here
}
else {
// foo was not actually a ConstantInt
}
If you're absolutely sure that foo
is a ConstantInt
and are ready to be hit with an assertion failure if it isn't, you can use cast
instead of dyn_cast
.
P.S. Do note that cast
and dyn_cast
are part of LLVM's own implementation of RTTI. dyn_cast
acts somewhat similarly to the standard C++ dynamic_cast
, though there are differences in implementation and performance (as can be read here).
How to get the exact integer from a Value
The way you outline is more or less correct - there's also a more complete answer in this related question. But that is of course assuming the value is a ConstantInt
.
If you expect some value to be a constant but it isn't, you should make sure you're running one of the constant propagation passes first. If the value is still not a constant there's nothing much you can do, except for maybe writing your own specialized constant propagation pass...
Obfuscating integer constants with an LLVM pass
The problem here is IRBuilder, which performs Constant Folding by default upon creating the new IR instructions.
To solve this issue, I had to create a new volatile (volatile is not obligatory, but I could so I did) variable in IR, perform the "obfuscated" arithmetic operations on it, and replace the operand of the instruction that uses "1337" with the resulting value.
The code is the same as in the question, except for the function obfuscateInt(...), which now looks as follows:
// replValue = ~(originalInt ^ key) -1
Value *obfuscateInt(BasicBlock &BB, Instruction &Inst, Constant *C) {
srand(time(NULL));
int key = std::rand();
int32_t replacedValue = ~(C->getUniqueInteger().getLimitedValue() ^ key);
Constant *replValue = ConstantInt::get(C->getType(), replacedValue),
*keyValue = ConstantInt::get(C->getType(), key);
IRBuilder<> Builder(&Inst);
// allocate enough space on the stack to store a 32-bit value. Var name = "AA"
AllocaInst *varAlloc = Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, "AA");
// Store the key in AA, set "volatile" to true
Builder.CreateStore(keyValue, varAlloc, true);
// read the variable "AA"
LoadInst *loadVar = Builder.CreateLoad(varAlloc, true, "AA");
// use it
Value *repl = Builder.CreateXor(replValue, loadVar);
Value *finValue = Builder.CreateNeg(repl);
return Builder.CreateSub(finValue, Builder.getInt32(1));
}
The generated IR now looks like:
%1 = alloca i32, align 4
%2 = alloca i32, align 4
store i32 0, i32* %1, align 4
store volatile i32 3, i32* %2, align 4
%3 = load volatile i32, i32* %2, align 4
%4 = alloca i32
store volatile i32 525933950, i32* %4
%5 = load volatile i32, i32* %4
%6 = xor i32 -525932616, %5
%7 = sub i32 0, %6
%8 = sub i32 %7, 1
%9 = add nsw i32 %3, %8
store volatile i32 %9, i32* %2, align 4
%10 = load volatile i32, i32* %2, align 4
%11 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([41 x i8], [41 x i8]* @.str, i32 0, i32 0), i32 %10)
%12 = load volatile i32, i32* %2, align 4
ret i32 %12
And the disassembly shows that 1337 doesn't appear anywhere, yet the behaviour of the program is preserved:
0000000000001140 <main>:
1140: 55 push rbp
1141: 48 89 e5 mov rbp,rsp
1144: 48 83 ec 10 sub rsp,0x10
1148: 31 c0 xor eax,eax
114a: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
1151: c7 45 f8 03 00 00 00 mov DWORD PTR [rbp-0x8],0x3
1158: 8b 4d f8 mov ecx,DWORD PTR [rbp-0x8]
115b: c7 45 f4 02 77 c4 31 mov DWORD PTR [rbp-0xc],0x31c47702
1162: 8b 55 f4 mov edx,DWORD PTR [rbp-0xc]
1165: 81 f2 c4 8d 3b ce xor edx,0xce3b8dc4
116b: 29 d0 sub eax,edx
116d: 83 e8 01 sub eax,0x1
1170: 01 c1 add ecx,eax
1172: 89 4d f8 mov DWORD PTR [rbp-0x8],ecx
....
How to create a ConstantInt in LLVM?
Most things in LLVM are created through a static method call instead of directly using a constructor. One reason is that an existing object can be returned instead of creating a new instance.
The static members of ConstantInt have a number of creation methods. You're probably most interested in get (Type *Ty, uint64_t V, bool isSigned=false)
and, if you don't already have an integer type, IntegerType::get (LLVMContext &C, unsigned NumBits)
.
Related Topics
C++ Inheritance via Dominance Warning
C++: How to Check If the Cin Buffer Is Empty
How to Execute a Command and Get Return Code Stdout and Stderr of Command in C++
How to Change an Executable's Properties? (Windows)
Propagate Constness to Data Pointed by Member Variables
Cross-Platform Equivalent to Windows Events
Converting Cv::Mat for Tesseract
Properties File Library for C (Or C++)
Does C++11, 14, 17 or 20 Introduce a Standard Constant for Pi
Template Tricks with Const Char* as a Non-Type Parameter
Portable Branch Prediction Hints
How to Speed Up Floating-Point to Integer Number Conversion
C++ - Hold the Console Window Open
How to Overload a Function That Can Tell a Fixed Array from a Pointer