Skip to content

Commit

Permalink
MS ABI: Implement x86_64 RTTI
Browse files Browse the repository at this point in the history
Summary:
The RTTI scheme for x86_64 is largely the same as the one for i386.

Differences are largely limited to avoiding load-time relocations by
replacing pointers to RTTI metadata with the difference of that data
relative to the load address of the module.

Interestingly, this precludes the possibility of successfully using RTTI
data from another DLL.  The ImageBase reference is always relative to
the current DLL.

Differential Revision: http://reviews.llvm.org/D4148

llvm-svn: 211041
  • Loading branch information
majnemer committed Jun 16, 2014
1 parent a5360c4 commit 4c2a042
Show file tree
Hide file tree
Showing 2 changed files with 202 additions and 18 deletions.
99 changes: 81 additions & 18 deletions clang/lib/CodeGen/MicrosoftRTTI.cpp
Expand Up @@ -51,6 +51,43 @@ using namespace CodeGen;
// vbtable. The names of the BaseClassDescriptors have all of their fields
// mangled into them so they can be aggressively deduplicated by the linker.

static bool isImageRelative(CodeGenModule &CGM) {
return CGM.getTarget().getPointerWidth(/*AddressSpace=*/0) == 64;
}

static llvm::Type *getImageRelativeType(CodeGenModule &CGM,
llvm::Type *PtrType) {
if (!isImageRelative(CGM))
return PtrType;
return CGM.IntTy;
}

static llvm::GlobalVariable *getImageBase(CodeGenModule &CGM) {
StringRef Name = "__ImageBase";
if (llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(Name))
return GV;

return new llvm::GlobalVariable(CGM.getModule(), CGM.Int8Ty,
/*isConstant=*/true,
llvm::GlobalValue::ExternalLinkage,
/*Initializer=*/nullptr, Name);
}

static llvm::Constant *getImageRelativeConstant(CodeGenModule &CGM,
llvm::Constant *PtrVal) {
if (!isImageRelative(CGM))
return PtrVal;

llvm::Constant *ImageBaseAsInt =
llvm::ConstantExpr::getPtrToInt(getImageBase(CGM), CGM.IntPtrTy);
llvm::Constant *PtrValAsInt =
llvm::ConstantExpr::getPtrToInt(PtrVal, CGM.IntPtrTy);
llvm::Constant *Diff =
llvm::ConstantExpr::getSub(PtrValAsInt, ImageBaseAsInt,
/*HasNUW=*/true, /*HasNSW=*/true);
return llvm::ConstantExpr::getTrunc(Diff, CGM.IntTy);
}

// 5 routines for constructing the llvm types for MS RTTI structs.
static llvm::StructType *getClassHierarchyDescriptorType(CodeGenModule &CGM);

Expand All @@ -72,13 +109,15 @@ static llvm::StructType *getBaseClassDescriptorType(CodeGenModule &CGM) {
if (auto Type = CGM.getModule().getTypeByName(Name))
return Type;
llvm::Type *FieldTypes[] = {
CGM.Int8PtrTy,
getImageRelativeType(CGM, CGM.Int8PtrTy),
CGM.IntTy,
CGM.IntTy,
CGM.IntTy,
CGM.IntTy,
CGM.IntTy,
getClassHierarchyDescriptorType(CGM)->getPointerTo()};
getImageRelativeType(
CGM, getClassHierarchyDescriptorType(CGM)->getPointerTo()),
};
return llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, Name);
}

Expand All @@ -92,7 +131,10 @@ static llvm::StructType *getClassHierarchyDescriptorType(CodeGenModule &CGM) {
CGM.IntTy,
CGM.IntTy,
CGM.IntTy,
getBaseClassDescriptorType(CGM)->getPointerTo()->getPointerTo()};
getImageRelativeType(
CGM,
getBaseClassDescriptorType(CGM)->getPointerTo()->getPointerTo()),
};
Type->setBody(FieldTypes);
return Type;
}
Expand All @@ -101,13 +143,21 @@ static llvm::StructType *getCompleteObjectLocatorType(CodeGenModule &CGM) {
static const char Name[] = "MSRTTICompleteObjectLocator";
if (auto Type = CGM.getModule().getTypeByName(Name))
return Type;
llvm::StructType *Type = llvm::StructType::create(CGM.getLLVMContext(), Name);
llvm::Type *FieldTypes[] = {
CGM.IntTy,
CGM.IntTy,
CGM.IntTy,
CGM.Int8PtrTy,
getClassHierarchyDescriptorType(CGM)->getPointerTo() };
return llvm::StructType::create(CGM.getLLVMContext(), FieldTypes, Name);
getImageRelativeType(CGM, CGM.Int8PtrTy),
getImageRelativeType(
CGM, getClassHierarchyDescriptorType(CGM)->getPointerTo()),
getImageRelativeType(CGM, Type),
};
llvm::ArrayRef<llvm::Type *> FieldTypesRef(
std::begin(FieldTypes),
isImageRelative(CGM) ? std::end(FieldTypes) : std::end(FieldTypes) - 1);
Type->setBody(FieldTypesRef);
return Type;
}

static llvm::GlobalVariable *getTypeInfoVTable(CodeGenModule &CGM) {
Expand Down Expand Up @@ -288,9 +338,11 @@ llvm::GlobalVariable *MSRTTIBuilder::getClassHierarchyDescriptor() {
llvm::ConstantInt::get(CGM.IntTy, 0), // Unknown
llvm::ConstantInt::get(CGM.IntTy, Flags),
llvm::ConstantInt::get(CGM.IntTy, Classes.size()),
llvm::ConstantExpr::getInBoundsGetElementPtr(
getBaseClassArray(Classes),
llvm::ArrayRef<llvm::Value *>(GEPIndices))};
getImageRelativeConstant(CGM,
llvm::ConstantExpr::getInBoundsGetElementPtr(
getBaseClassArray(Classes),
llvm::ArrayRef<llvm::Value *>(GEPIndices))),
};
CHD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
return CHD;
}
Expand All @@ -308,16 +360,18 @@ MSRTTIBuilder::getBaseClassArray(SmallVectorImpl<MSRTTIClass> &Classes) {
// mode) bytes of padding. We provide a pointer sized amount of padding by
// adding +1 to Classes.size(). The sections have pointer alignment and are
// marked pick-any so it shouldn't matter.
auto PtrType = getBaseClassDescriptorType(CGM)->getPointerTo();
auto PtrType = getImageRelativeType(
CGM, getBaseClassDescriptorType(CGM)->getPointerTo());
auto ArrayType = llvm::ArrayType::get(PtrType, Classes.size() + 1);
auto BCA = new llvm::GlobalVariable(Module, ArrayType,
/*Constant=*/true, Linkage, /*Initializer=*/nullptr, MangledName.c_str());

// Initialize the BaseClassArray.
SmallVector<llvm::Constant *, 8> BaseClassArrayData;
for (MSRTTIClass &Class : Classes)
BaseClassArrayData.push_back(getBaseClassDescriptor(Class));
BaseClassArrayData.push_back(llvm::ConstantPointerNull::get(PtrType));
BaseClassArrayData.push_back(
getImageRelativeConstant(CGM, getBaseClassDescriptor(Class)));
BaseClassArrayData.push_back(llvm::Constant::getNullValue(PtrType));
BCA->setInitializer(llvm::ConstantArray::get(ArrayType, BaseClassArrayData));
return BCA;
}
Expand Down Expand Up @@ -354,13 +408,16 @@ MSRTTIBuilder::getBaseClassDescriptor(const MSRTTIClass &Class) {

// Initialize the BaseClassDescriptor.
llvm::Constant *Fields[] = {
CGM.getMSTypeDescriptor(Context.getTypeDeclType(Class.RD)),
getImageRelativeConstant(
CGM, CGM.getMSTypeDescriptor(Context.getTypeDeclType(Class.RD))),
llvm::ConstantInt::get(CGM.IntTy, Class.NumBases),
llvm::ConstantInt::get(CGM.IntTy, Class.OffsetInVBase),
llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset),
llvm::ConstantInt::get(CGM.IntTy, OffsetInVBTable),
llvm::ConstantInt::get(CGM.IntTy, Class.Flags),
MSRTTIBuilder(CGM, Class.RD).getClassHierarchyDescriptor()};
getImageRelativeConstant(
CGM, MSRTTIBuilder(CGM, Class.RD).getClassHierarchyDescriptor()),
};
BCD->setInitializer(llvm::ConstantStruct::get(Type, Fields));
return BCD;
}
Expand Down Expand Up @@ -395,12 +452,18 @@ MSRTTIBuilder::getCompleteObjectLocator(const VPtrInfo *Info) {

// Initialize the CompleteObjectLocator.
llvm::Constant *Fields[] = {
llvm::ConstantInt::get(CGM.IntTy, 0), // IsDeltaEncoded
llvm::ConstantInt::get(CGM.IntTy, isImageRelative(CGM)),
llvm::ConstantInt::get(CGM.IntTy, OffsetToTop),
llvm::ConstantInt::get(CGM.IntTy, VFPtrOffset),
CGM.getMSTypeDescriptor(Context.getTypeDeclType(RD)),
getClassHierarchyDescriptor()};
COL->setInitializer(llvm::ConstantStruct::get(Type, Fields));
getImageRelativeConstant(
CGM, CGM.getMSTypeDescriptor(Context.getTypeDeclType(RD))),
getImageRelativeConstant(CGM, getClassHierarchyDescriptor()),
getImageRelativeConstant(CGM, COL),
};
llvm::ArrayRef<llvm::Constant *> FieldsRef(Fields);
if (!isImageRelative(CGM))
FieldsRef = FieldsRef.slice(0, FieldsRef.size() - 1);
COL->setInitializer(llvm::ConstantStruct::get(Type, FieldsRef));
return COL;
}

Expand Down

0 comments on commit 4c2a042

Please sign in to comment.