Index: src/IceTargetLoweringX8632.cpp |
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp |
index d36ad1695191b49e77d7ad516c33d80eacfbf890..eb6afca1ecc552807b41855d43a902b92cdde4e6 100644 |
--- a/src/IceTargetLoweringX8632.cpp |
+++ b/src/IceTargetLoweringX8632.cpp |
@@ -136,6 +136,8 @@ const uint32_t X86_LOG2_OF_MIN_STACK_SLOT_SIZE = 2; |
const uint32_t X86_LOG2_OF_MAX_STACK_SLOT_SIZE = 4; |
// The number of different NOP instructions |
const uint32_t X86_NUM_NOP_VARIANTS = 5; |
+// Randomize integer immediates at least 2 bytes in size. |
+const uint64_t X86_INT_IMMEDIATE_RANDOMIZATION_THRESHOLD = 0xffff; |
// Value and Alignment are in bytes. Return Value adjusted to the next |
// highest multiple of Alignment. |
@@ -151,6 +153,17 @@ uint32_t applyStackAlignment(uint32_t Value) { |
return applyAlignment(Value, X86_STACK_ALIGNMENT_BYTES); |
} |
+// This gives a name to the immediate so it can be identified as a |
+// constant pool entry. |
+IceString nameImmediate(Constant *Immediate) { |
+ bool IsRelocatable = llvm::isa<ConstantRelocatable>(Immediate); |
+ IceString Name; |
+ llvm::raw_string_ostream NameBuf(Name); |
+ NameBuf << (IsRelocatable ? "L$__reloc" : "L$") << Immediate->getType() << "$" |
+ << Immediate->getPoolEntryID(); |
+ return NameBuf.str(); |
+} |
+ |
// Instruction set options |
namespace cl = ::llvm::cl; |
cl::opt<TargetX8632::X86InstructionSet> CLInstructionSet( |
@@ -162,6 +175,51 @@ cl::opt<TargetX8632::X86InstructionSet> CLInstructionSet( |
clEnumValN(TargetX8632::SSE4_1, "sse4.1", |
"Enable SSE 4.1 instructions"), clEnumValEnd)); |
+enum RandomizeImmediates { |
+ Randomize_None, |
+ Randomize_ConstantBlinding, |
+ Randomize_ConstantPooling |
+}; |
+ |
+cl::opt<RandomizeImmediates> CLRandomizeImmediates( |
+ "randomize-immediates", |
+ cl::desc("Randomize the representation of immediates"), |
+ cl::init(Randomize_None), |
+ cl::values(clEnumValN(Randomize_None, "none", "Don't randomize (default)"), |
+ clEnumValN(Randomize_ConstantBlinding, "constant-blinding", |
+ "Use constant blinding"), |
+ clEnumValN(Randomize_ConstantPooling, "constant-pooling", |
+ "Use constant pooling"), |
+ clEnumValEnd)); |
+ |
+bool immediateShouldBeRandomized(Operand *Immediate) { |
+ if (!CLRandomizeImmediates) |
+ return false; |
+ if (ConstantInteger *ConstInt = |
+ llvm::dyn_cast_or_null<ConstantInteger>(Immediate)) { |
+ // i64 should have been split at this point. |
+ assert(ConstInt->getType() != IceType_i64); |
+ return ConstInt->getType() == IceType_i32 && |
+ (ConstInt->getValue() + |
+ X86_INT_IMMEDIATE_RANDOMIZATION_THRESHOLD / 2) >= |
+ X86_INT_IMMEDIATE_RANDOMIZATION_THRESHOLD; |
+ } |
+ return false; |
+} |
+ |
+// Return a string representation of the type that is suitable for use |
+// in an identifier. |
+IceString typeIdentString(const Type Ty) { |
+ IceString Str; |
+ llvm::raw_string_ostream BaseOS(Str); |
+ if (isVectorType(Ty)) { |
+ BaseOS << "v" << typeNumElements(Ty) << typeElementType(Ty); |
+ } else { |
+ BaseOS << Ty; |
+ } |
+ return BaseOS.str(); |
+} |
+ |
// In some cases, there are x-macros tables for both high-level and |
// low-level instructions/operands that use the same enum key value. |
// The tables are kept separate to maintain a proper separation |
@@ -263,7 +321,8 @@ TargetX8632::TargetX8632(Cfg *Func) |
: TargetLowering(Func), InstructionSet(CLInstructionSet), |
IsEbpBasedFrame(false), NeedsStackAlignment(false), FrameSizeLocals(0), |
SpillAreaSizeBytes(0), NextLabelNumber(0), ComputedLiveRanges(false), |
- PhysicalRegisters(VarList(Reg_NUM)) { |
+ PhysicalRegisters(VarList(Reg_NUM)), |
+ ConstantBlindingCookieInitialized(false), ConstantBlindingCookie(0) { |
// TODO: Don't initialize IntegerRegisters and friends every time. |
// Instead, initialize in some sort of static initializer for the |
// class. |
@@ -983,9 +1042,41 @@ template <typename T> void TargetX8632::emitConstantPool() const { |
} |
} |
+void TargetX8632::emitPooledImmediates() const { |
+ Ostream &Str = Ctx->getStrEmit(); |
+ SizeT Align = typeWidthInBytesOnStack(IceType_i32); |
+ // TODO: Determine the right directives to place here. |
+ Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",@progbits," << Align |
+ << "\n"; |
+ Str << "\t.align\t" << Align << "\n"; |
+ ConstantList PooledImmediates = Ctx->getImmediatePool(); |
+ for (ConstantList::const_iterator I = PooledImmediates.begin(), |
+ E = PooledImmediates.end(); |
+ I != E; ++I) { |
+ Constant *Value = *I; |
+ IceString Name = nameImmediate(Value); |
+ Str << Name << ":\n"; |
+ if (ConstantInteger *Int = llvm::dyn_cast<ConstantInteger>(Value)) { |
+ assert(Int->getType() == IceType_i32); |
+ char buf[30]; |
+ int CharsPrinted = snprintf(buf, llvm::array_lengthof(buf), "0x%x", |
+ (uint32_t)Int->getValue()); |
+ assert(CharsPrinted >= 0 && |
+ (size_t)CharsPrinted < llvm::array_lengthof(buf)); |
+ Str << "\t.long\t" << buf << "\n"; |
+ } else if (ConstantRelocatable *Reloc = |
+ llvm::dyn_cast<ConstantRelocatable>(Value)) { |
+ Str << "\t.long\t"; |
+ Reloc->emit(Ctx); |
+ Str << "\n"; |
+ } |
+ } |
+} |
+ |
void TargetX8632::emitConstants() const { |
emitConstantPool<PoolTypeConverter<float> >(); |
emitConstantPool<PoolTypeConverter<double> >(); |
+ emitPooledImmediates(); |
// No need to emit constants from the int pool since (for x86) they |
// are embedded as immediates in the instructions. |
@@ -3808,8 +3899,9 @@ void TargetX8632::lowerSelect(const InstSelect *Inst) { |
_mov(DestLo, SrcLoRI); |
_mov(DestHi, SrcHiRI); |
} else { |
- _cmp(ConditionRMI, Zero); |
+ // Call legalize() before _cmp, since legalize() may modify flags. |
SrcT = legalize(SrcT, Legal_Reg | Legal_Imm, true); |
+ _cmp(ConditionRMI, Zero); |
_mov(Dest, SrcT); |
_br(InstX8632Br::Br_ne, Label); |
Context.insert(InstFakeUse::create(Func, Dest)); |
@@ -4027,6 +4119,49 @@ Variable *TargetX8632::copyToReg(Operand *Src, int32_t RegNum) { |
return Reg; |
} |
+// Insert code to randomize the representation of the immediate. Return |
+// a register that holds the (derandomized) value of the immediate. |
+// WARNING: Constant blinding overwrites the flags register. |
+Variable *TargetX8632::randomizeImmediate(Constant *Immediate) { |
+ assert(llvm::isa<ConstantInteger>(Immediate) || |
+ llvm::isa<ConstantRelocatable>(Immediate)); |
+ |
+ if (CLRandomizeImmediates == Randomize_None) |
+ return legalizeToVar(Immediate); |
+ |
+ Variable *Dest = makeReg(Immediate->getType()); |
+ |
+ if (CLRandomizeImmediates == Randomize_ConstantPooling) { |
+ const Type Ty = Immediate->getType(); |
+ const int64_t Offset = 0; |
+ const IceString Name = nameImmediate(Immediate); |
+ const bool SuppressMangling = true; |
+ Ctx->addConstantPooledImmediate(Name, Immediate); |
+ Constant *Sym = Ctx->getConstantSym(Ty, Offset, Name, SuppressMangling); |
+ // LEAHACK: Once a proper assembler is used, change this to be |
+ // mov Dest, [Sym]. |
+ _mov(Dest, OperandX8632Mem::create(Func, Ty, NULL, Sym)); |
+ } else { |
+ assert(CLRandomizeImmediates == Randomize_ConstantBlinding); |
+ // Mask integer immediates with a random XOR key. |
+ ConstantInteger *IntegerImmediate = llvm::cast<ConstantInteger>(Immediate); |
+ assert(IntegerImmediate->getType() != IceType_i64); |
+ uint64_t Value = IntegerImmediate->getValue(); |
+ if (!ConstantBlindingCookieInitialized) { |
+ RandomNumberGeneratorWrapper RNG(Ctx->getRNG()); |
+ ConstantBlindingCookie = |
+ RNG.next((uint64_t)std::numeric_limits<uint32_t>::max() + 1); |
+ ConstantBlindingCookieInitialized = true; |
+ } |
+ uint32_t Mask1 = ConstantBlindingCookie; |
+ uint32_t Mask2 = Mask1 ^ Value; |
+ _mov(Dest, Ctx->getConstantInt(IceType_i32, Mask1)); |
+ _xor(Dest, Ctx->getConstantInt(IceType_i32, Mask2)); |
+ } |
+ |
+ return Dest; |
+} |
+ |
Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
bool AllowOverlap, int32_t RegNum) { |
// Assert that a physical register is allowed. To date, all calls |
@@ -4044,6 +4179,7 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
// that the Base and Index components are in physical registers. |
Variable *Base = Mem->getBase(); |
Variable *Index = Mem->getIndex(); |
+ Constant *Offset = Mem->getOffset(); |
Variable *RegBase = NULL; |
Variable *RegIndex = NULL; |
if (Base) { |
@@ -4052,10 +4188,22 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
if (Index) { |
RegIndex = legalizeToVar(Index, true); |
} |
+ |
+ if (immediateShouldBeRandomized(Offset)) { |
+ // lea new_base [base + randomize(offset)] |
+ Variable *RegOffset = randomizeImmediate(Offset); |
+ OperandX8632Mem *NewBaseAddr = OperandX8632Mem::create( |
+ Func, Mem->getType(), RegBase, NULL, RegOffset, 0); |
+ Variable *NewBase = makeReg(IceType_i32); |
+ _lea(NewBase, NewBaseAddr); |
+ RegBase = NewBase; |
+ Offset = NULL; |
+ } |
+ |
if (Base != RegBase || Index != RegIndex) { |
- From = OperandX8632Mem::create( |
- Func, Mem->getType(), RegBase, Mem->getOffset(), RegIndex, |
- Mem->getShift(), Mem->getSegmentRegister()); |
+ From = OperandX8632Mem::create(Func, Mem->getType(), RegBase, Offset, |
+ RegIndex, Mem->getShift(), |
+ Mem->getSegmentRegister()); |
} |
if (!(Allowed & Legal_Mem)) { |
@@ -4082,6 +4230,11 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed, |
} |
// There should be no constants of vector type (other than undef). |
assert(!isVectorType(From->getType())); |
+ |
+ if (immediateShouldBeRandomized(From)) { |
+ return randomizeImmediate(llvm::cast<Constant>(From)); |
+ } |
+ |
bool NeedsReg = false; |
if (!(Allowed & Legal_Imm)) |
// Immediate specifically not allowed |