blob: 8212df0c39024f1338d614c9c356066101ae3279 [file] [log] [blame] [edit]
//===- AllocateDataSegment.cpp - Create a template for the data segment ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Code sandboxed with MinSFI cannot access the memory containing its data
// segment directly because it is located outside its address subspace. To
// this end, this pass collates all of the global variables in the module
// into an exported global struct named "__sfi_data_segment" and a corresponding
// global integer holding the overall size. The runtime is expected to link
// against these variables and to initialize the memory region of the sandbox
// by copying the data segment template into a fixed address inside the region.
//
// This pass assumes that the base of the memory region of the sandbox is
// aligned to at least 2^29 bytes (=512MB), which is the maximum global variable
// alignment supported by LLVM.
//
//===----------------------------------------------------------------------===//
#include "llvm/Pass.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Module.h"
#include "llvm/Transforms/MinSFI.h"
using namespace llvm;
static const char ExternalSymName_DataSegment[] = "__sfi_data_segment";
static const char ExternalSymName_DataSegmentSize[] = "__sfi_data_segment_size";
static const uint32_t DataSegmentBaseAddress = 0x10000;
namespace {
class AllocateDataSegment : public ModulePass {
public:
static char ID;
AllocateDataSegment() : ModulePass(ID) {
initializeAllocateDataSegmentPass(*PassRegistry::getPassRegistry());
}
virtual bool runOnModule(Module &M);
};
} // namespace
static inline uint32_t getPadding(uint32_t Offset, const GlobalVariable *GV,
const DataLayout &DL) {
uint32_t Alignment = DL.getPreferredAlignment(GV);
if (Alignment <= 1)
return 0;
else
return OffsetToAlignment(Offset, Alignment);
}
bool AllocateDataSegment::runOnModule(Module &M) {
DataLayout DL(&M);
Type *I8 = Type::getInt8Ty(M.getContext());
Type *I32 = Type::getInt32Ty(M.getContext());
Type *IntPtrType = DL.getIntPtrType(M.getContext());
// First, we do a pass over the global variables, in which we compute
// the amount of required padding between them and consequently their
// addresses relative to the memory base of the sandbox. References to each
// global are then replaced with direct memory pointers.
uint32_t VarOffset = 0;
DenseMap<GlobalVariable*, uint32_t> VarPadding;
for (Module::global_iterator GV = M.global_begin(), E = M.global_end();
GV != E; ++GV) {
assert(GV->hasInitializer());
uint32_t Padding = getPadding(VarOffset, GV, DL);
VarPadding[GV] = Padding;
VarOffset += Padding;
GV->replaceAllUsesWith(
ConstantExpr::getIntToPtr(
ConstantInt::get(IntPtrType,
DataSegmentBaseAddress + VarOffset),
GV->getType()));
VarOffset += DL.getTypeStoreSize(GV->getType()->getPointerElementType());
}
// Using the offsets computed above, we prepare the layout and the contents
// of the desired data structure. After the type and initializer of each
// global is copied, the global is not needed any more and it is erased.
SmallVector<Type*, 10> TemplateLayout;
SmallVector<Constant*, 10> TemplateData;
for (Module::global_iterator It = M.global_begin(), E = M.global_end();
It != E; ) {
GlobalVariable *GV = It++;
uint32_t Padding = VarPadding[GV];
if (Padding > 0) {
Type *PaddingType = ArrayType::get(I8, Padding);
TemplateLayout.push_back(PaddingType);
TemplateData.push_back(ConstantAggregateZero::get(PaddingType));
}
TemplateLayout.push_back(GV->getType()->getPointerElementType());
TemplateData.push_back(GV->getInitializer());
GV->eraseFromParent();
}
// Finally, we create the struct and size global variables.
StructType *TemplateType =
StructType::create(M.getContext(), ExternalSymName_DataSegment);
TemplateType->setBody(TemplateLayout, /*isPacked=*/true);
Constant *Template = ConstantStruct::get(TemplateType, TemplateData);
new GlobalVariable(M, Template->getType(), /*isConstant=*/true,
GlobalVariable::ExternalLinkage, Template,
ExternalSymName_DataSegment);
Constant *TemplateSize =
ConstantInt::get(I32, DL.getTypeAllocSize(TemplateType));
new GlobalVariable(M, TemplateSize->getType(), /*isConstant=*/true,
GlobalVariable::ExternalLinkage, TemplateSize,
ExternalSymName_DataSegmentSize);
return true;
}
char AllocateDataSegment::ID = 0;
INITIALIZE_PASS(AllocateDataSegment, "minsfi-allocate-data-segment",
"Create a template for the data segment", false, false)
ModulePass *llvm::createAllocateDataSegmentPass() {
return new AllocateDataSegment();
}