OLD | NEW |
(Empty) | |
| 1 //===- AllocateDataSegment.cpp - Create a template for the data segment ---===// |
| 2 // |
| 3 // The LLVM Compiler Infrastructure |
| 4 // |
| 5 // This file is distributed under the University of Illinois Open Source |
| 6 // License. See LICENSE.TXT for details. |
| 7 // |
| 8 //===----------------------------------------------------------------------===// |
| 9 // |
| 10 // Code sandboxed with MinSFI cannot access the memory containing its data |
| 11 // segment directly because it is located outside its address subspace. To |
| 12 // this end, this pass collates all of the global variables in the module |
| 13 // into an exported global struct named "__sfi_data_segment" and a corresponding |
| 14 // global integer holding the overall size. The runtime is expected to link |
| 15 // against these variables and to initialize the memory region of the sandbox |
| 16 // by copying the data segment template into a fixed address inside the region. |
| 17 // |
| 18 // This pass assumes that the base of the memory region of the sandbox is |
| 19 // aligned to at least 2^29 bytes (=512MB), which is the maximum global variable |
| 20 // alignment supported by LLVM. |
| 21 // |
| 22 //===----------------------------------------------------------------------===// |
| 23 |
| 24 #include "llvm/Pass.h" |
| 25 #include "llvm/IR/Constants.h" |
| 26 #include "llvm/IR/DataLayout.h" |
| 27 #include "llvm/IR/Module.h" |
| 28 #include "llvm/Transforms/MinSFI.h" |
| 29 |
| 30 using namespace llvm; |
| 31 |
| 32 static const char ExternalSymName_DataSegment[] = "__sfi_data_segment"; |
| 33 static const char ExternalSymName_DataSegmentSize[] = "__sfi_data_segment_size"; |
| 34 |
| 35 static const uint32_t DataSegmentBaseAddress = 0x10000; |
| 36 |
| 37 namespace { |
| 38 class AllocateDataSegment : public ModulePass { |
| 39 public: |
| 40 static char ID; |
| 41 AllocateDataSegment() : ModulePass(ID) { |
| 42 initializeAllocateDataSegmentPass(*PassRegistry::getPassRegistry()); |
| 43 } |
| 44 |
| 45 virtual bool runOnModule(Module &M); |
| 46 }; |
| 47 } // namespace |
| 48 |
| 49 static inline uint32_t getPadding(uint32_t Offset, const GlobalVariable *GV, |
| 50 const DataLayout &DL) { |
| 51 uint32_t Alignment = DL.getPreferredAlignment(GV); |
| 52 if (Alignment <= 1) |
| 53 return 0; |
| 54 else |
| 55 return OffsetToAlignment(Offset, Alignment); |
| 56 } |
| 57 |
| 58 bool AllocateDataSegment::runOnModule(Module &M) { |
| 59 DataLayout DL(&M); |
| 60 Type *I8 = Type::getInt8Ty(M.getContext()); |
| 61 Type *I32 = Type::getInt32Ty(M.getContext()); |
| 62 Type *IntPtrType = DL.getIntPtrType(M.getContext()); |
| 63 |
| 64 // First, we do a pass over the global variables, in which we compute |
| 65 // the amount of required padding between them and consequently their |
| 66 // addresses relative to the memory base of the sandbox. References to each |
| 67 // global are then replaced with direct memory pointers. |
| 68 uint32_t VarOffset = 0; |
| 69 DenseMap<GlobalVariable*, uint32_t> VarPadding; |
| 70 for (Module::global_iterator GV = M.global_begin(), E = M.global_end(); |
| 71 GV != E; ++GV) { |
| 72 assert(GV->hasInitializer()); |
| 73 |
| 74 uint32_t Padding = getPadding(VarOffset, GV, DL); |
| 75 VarPadding[GV] = Padding; |
| 76 VarOffset += Padding; |
| 77 |
| 78 GV->replaceAllUsesWith( |
| 79 ConstantExpr::getIntToPtr( |
| 80 ConstantInt::get(IntPtrType, |
| 81 DataSegmentBaseAddress + VarOffset), |
| 82 GV->getType())); |
| 83 |
| 84 VarOffset += DL.getTypeStoreSize(GV->getType()->getPointerElementType()); |
| 85 } |
| 86 |
| 87 // Using the offsets computed above, we prepare the layout and the contents |
| 88 // of the desired data structure. After the type and initializer of each |
| 89 // global is copied, the global is not needed any more and it is erased. |
| 90 SmallVector<Type*, 10> TemplateLayout; |
| 91 SmallVector<Constant*, 10> TemplateData; |
| 92 for (Module::global_iterator It = M.global_begin(), E = M.global_end(); |
| 93 It != E; ) { |
| 94 GlobalVariable *GV = It++; |
| 95 |
| 96 uint32_t Padding = VarPadding[GV]; |
| 97 if (Padding > 0) { |
| 98 Type *PaddingType = ArrayType::get(I8, Padding); |
| 99 TemplateLayout.push_back(PaddingType); |
| 100 TemplateData.push_back(ConstantAggregateZero::get(PaddingType)); |
| 101 } |
| 102 |
| 103 TemplateLayout.push_back(GV->getType()->getPointerElementType()); |
| 104 TemplateData.push_back(GV->getInitializer()); |
| 105 |
| 106 GV->eraseFromParent(); |
| 107 } |
| 108 |
| 109 // Finally, we create the struct and size global variables. |
| 110 StructType *TemplateType = |
| 111 StructType::create(M.getContext(), ExternalSymName_DataSegment); |
| 112 TemplateType->setBody(TemplateLayout, /*isPacked=*/true); |
| 113 |
| 114 Constant *Template = ConstantStruct::get(TemplateType, TemplateData); |
| 115 new GlobalVariable(M, Template->getType(), /*isConstant=*/true, |
| 116 GlobalVariable::ExternalLinkage, Template, |
| 117 ExternalSymName_DataSegment); |
| 118 |
| 119 Constant *TemplateSize = |
| 120 ConstantInt::get(I32, DL.getTypeAllocSize(TemplateType)); |
| 121 new GlobalVariable(M, TemplateSize->getType(), /*isConstant=*/true, |
| 122 GlobalVariable::ExternalLinkage, TemplateSize, |
| 123 ExternalSymName_DataSegmentSize); |
| 124 |
| 125 return true; |
| 126 } |
| 127 |
| 128 char AllocateDataSegment::ID = 0; |
| 129 INITIALIZE_PASS(AllocateDataSegment, "minsfi-allocate-data-segment", |
| 130 "Create a template for the data segment", false, false) |
| 131 |
| 132 ModulePass *llvm::createAllocateDataSegmentPass() { |
| 133 return new AllocateDataSegment(); |
| 134 } |
OLD | NEW |