r212125 - MS ABI: Reference MSVC RTTI from the VFTable
Timur Iskhodzhanov
timurrrr at google.com
Tue Jul 8 05:28:19 PDT 2014
I'm trying to understand how to fix the ASan/Windows breakage wrt vftables.
Here's what David told me on the r212138 thread:
2014-07-08 4:39 GMT+04:00 David Majnemer <david.majnemer at gmail.com>:
> ASAN replaces one internal global with another. Because the new symbol
> isn't in a Comdat, it's alias isn't either. This makes the alias a
> strong definition.
After rethinking this a bit, I'm puzzled.
Not only we need to correctly link no-rtti with rtti-enabled TUs but we
should also handle asan vs no-asan TUs.
ASan increases the size of globals by adding redzones.
It looks like an internal GV for a vftable in a (asan enabled, no-rtti)
configuration will be *larger* than the same vftable in a
(no-asan,rtti-enabled) configuration and the linking process will cause bad
result.
That said, I think we have to disable instrumentation of vftables on
Windows as long as we want to support mixing rtti- with no-rtti TUs or asan
with no-asan TUs.
Are we on the same page here?
If we agree that we can't add redzones to vftables, we should
adjust AddressSanitizerModule::ShouldInstrumentGlobal(GV) to handle this.
The problem is that those GVs are unnamed.
Is there a condition that's only true for the internal vftable GVs so I can
write an "if()"?
I think "if (G->hasComdat() && G->getLinkage() == InternalLinkage)" is a
too wide condition.
Or can we name these internal GVs somehow to make them easy to filter out?
E.g. "\02?_7blah"?
2014-07-02 0:30 GMT+04:00 David Majnemer <david.majnemer at gmail.com>:
> Author: majnemer
> Date: Tue Jul 1 15:30:31 2014
> New Revision: 212125
>
> URL: http://llvm.org/viewvc/llvm-project?rev=212125&view=rev
> Log:
> MS ABI: Reference MSVC RTTI from the VFTable
>
> The pointer for a class's RTTI data comes right before the VFTable but
> has no name. To be properly compatible with this, we do the following:
> * Create a single GlobalVariable which holds the contents of the VFTable
> _and_ the pointer to the RTTI data.
> * Create a GlobalAlias, with appropriate linkage/visibility, that points
> just after the RTTI data pointer. This ensures that the VFTable
> symbol will always refer to VFTable data.
> * Create a Comdat with a "Largest" SelectionKind and stick the private
> GlobalVariable in it. By transitivity, the GlobalAlias will be a
> member of the Comdat group. Using "Largest" ensures that foreign
> definitions without an RTTI data pointer will _not_ be chosen in the
> final linked image.
>
> Whether or not we emit RTTI data depends on several things:
> * The -fno-rtti flag implies that we should never not emit a pointer to
> RTTI data before the VFTable.
> * __declspec(dllimport) brings in the VFTable from a remote DLL. Use an
> available_externally GlobalVariable to provide a local definition of
> the VFTable. This means that we won't have any available_externally
> definitions of things like complete object locators. This is
> acceptable because they are never directly referenced.
>
> To my knowledge, this completes the implementation of MSVC RTTI code
> generation.
>
> Further semantic work should be done to properly support /GR-.
>
> Modified:
> cfe/trunk/lib/AST/VTableBuilder.cpp
> cfe/trunk/lib/CodeGen/CGVTables.cpp
> cfe/trunk/lib/CodeGen/CGVTables.h
> cfe/trunk/lib/CodeGen/CodeGenModule.h
> cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> cfe/trunk/lib/CodeGen/MicrosoftRTTI.cpp
> cfe/trunk/test/CodeGenCXX/dllexport.cpp
>
> Modified: cfe/trunk/lib/AST/VTableBuilder.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/VTableBuilder.cpp?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/VTableBuilder.cpp (original)
> +++ cfe/trunk/lib/AST/VTableBuilder.cpp Tue Jul 1 15:30:31 2014
> @@ -2574,6 +2574,12 @@ public:
>
> MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)),
> WhichVFPtr(*Which),
> Overriders(MostDerivedClass, CharUnits(), MostDerivedClass) {
> + // Only include the RTTI component if we know that we will provide a
> + // definition of the vftable.
> + if (Context.getLangOpts().RTTI &&
> + !MostDerivedClass->hasAttr<DLLImportAttr>())
> + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass));
> +
> LayoutVFTable();
>
> if (Context.getLangOpts().DumpVTableLayouts)
> @@ -2915,7 +2921,8 @@ void VFTableBuilder::AddMethods(BaseSubo
> // it requires return adjustment. Insert the method info for this
> method.
> unsigned VBIndex =
> LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase)
> : 0;
> - MethodInfo MI(VBIndex, Components.size());
> + MethodInfo MI(VBIndex, Context.getLangOpts().RTTI ? Components.size()
> - 1
> + :
> Components.size());
>
> assert(!MethodInfoMap.count(MD) &&
> "Should not have method info for this method yet!");
>
> Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGVTables.cpp Tue Jul 1 15:30:31 2014
> @@ -431,12 +431,10 @@ void CodeGenVTables::EmitThunks(GlobalDe
> emitThunk(GD, (*ThunkInfoVector)[I], /*ForVTable=*/false);
> }
>
> -llvm::Constant *
> -CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD,
> - const VTableComponent *Components,
> - unsigned NumComponents,
> - const VTableLayout::VTableThunkTy
> *VTableThunks,
> - unsigned NumVTableThunks) {
> +llvm::Constant *CodeGenVTables::CreateVTableInitializer(
> + const CXXRecordDecl *RD, const VTableComponent *Components,
> + unsigned NumComponents, const VTableLayout::VTableThunkTy
> *VTableThunks,
> + unsigned NumVTableThunks, llvm::Constant *RTTI) {
> SmallVector<llvm::Constant *, 64> Inits;
>
> llvm::Type *Int8PtrTy = CGM.Int8PtrTy;
> @@ -444,9 +442,6 @@ CodeGenVTables::CreateVTableInitializer(
> llvm::Type *PtrDiffTy =
> CGM.getTypes().ConvertType(CGM.getContext().getPointerDiffType());
>
> - QualType ClassType = CGM.getContext().getTagDeclType(RD);
> - llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(ClassType);
> -
> unsigned NextVTableThunkIndex = 0;
>
> llvm::Constant *PureVirtualFn = nullptr, *DeletedVirtualFn = nullptr;
> @@ -594,13 +589,14 @@ CodeGenVTables::GenerateConstructionVTab
> // V-tables are always unnamed_addr.
> VTable->setUnnamedAddr(true);
>
> + llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor(
> + CGM.getContext().getTagDeclType(Base.getBase()));
> +
> // Create and set the initializer.
> - llvm::Constant *Init =
> - CreateVTableInitializer(Base.getBase(),
> - VTLayout->vtable_component_begin(),
> - VTLayout->getNumVTableComponents(),
> - VTLayout->vtable_thunk_begin(),
> - VTLayout->getNumVTableThunks());
> + llvm::Constant *Init = CreateVTableInitializer(
> + Base.getBase(), VTLayout->vtable_component_begin(),
> + VTLayout->getNumVTableComponents(), VTLayout->vtable_thunk_begin(),
> + VTLayout->getNumVTableThunks(), RTTI);
> VTable->setInitializer(Init);
>
> return VTable;
>
> Modified: cfe/trunk/lib/CodeGen/CGVTables.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.h?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGVTables.h (original)
> +++ cfe/trunk/lib/CodeGen/CGVTables.h Tue Jul 1 15:30:31 2014
> @@ -61,11 +61,10 @@ public:
> /// decl.
> /// \param Components - The vtable components; this is really an array
> of
> /// VTableComponents.
> - llvm::Constant *CreateVTableInitializer(const CXXRecordDecl *RD,
> - const VTableComponent
> *Components,
> - unsigned NumComponents,
> - const VTableLayout::VTableThunkTy
> *VTableThunks,
> - unsigned NumVTableThunks);
> + llvm::Constant *CreateVTableInitializer(
> + const CXXRecordDecl *RD, const VTableComponent *Components,
> + unsigned NumComponents, const VTableLayout::VTableThunkTy
> *VTableThunks,
> + unsigned NumVTableThunks, llvm::Constant *RTTI);
>
> CodeGenVTables(CodeGenModule &CGM);
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Tue Jul 1 15:30:31 2014
> @@ -750,8 +750,8 @@ public:
> /// \brief Gets or a creats a Microsoft TypeDescriptor.
> llvm::Constant *getMSTypeDescriptor(QualType Ty);
> /// \brief Gets or a creats a Microsoft CompleteObjectLocator.
> - llvm::GlobalVariable *getMSCompleteObjectLocator(const CXXRecordDecl
> *RD,
> - const VPtrInfo *Info);
> + llvm::Constant *getMSCompleteObjectLocator(const CXXRecordDecl *RD,
> + const VPtrInfo *Info);
>
> /// Gets the address of a block which requires no captures.
> llvm::Constant *GetAddrOfGlobalBlock(const BlockExpr *BE, const char *);
>
> Modified: cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/ItaniumCXXABI.cpp Tue Jul 1 15:30:31 2014
> @@ -1182,11 +1182,13 @@ void ItaniumCXXABI::emitVTableDefinition
> ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
> const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
> llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
> + llvm::Constant *RTTI =
> + CGM.GetAddrOfRTTIDescriptor(CGM.getContext().getTagDeclType(RD));
>
> // Create and set the initializer.
> llvm::Constant *Init = CGVT.CreateVTableInitializer(
> RD, VTLayout.vtable_component_begin(),
> VTLayout.getNumVTableComponents(),
> - VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks());
> + VTLayout.vtable_thunk_begin(), VTLayout.getNumVTableThunks(), RTTI);
> VTable->setInitializer(Init);
>
> // Set the correct linkage.
>
> Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Tue Jul 1 15:30:31 2014
> @@ -403,9 +403,11 @@ public:
>
> private:
> typedef std::pair<const CXXRecordDecl *, CharUnits> VFTableIdTy;
> - typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *>
> VFTablesMapTy;
> + typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalVariable *>
> VTablesMapTy;
> + typedef llvm::DenseMap<VFTableIdTy, llvm::GlobalValue *> VFTablesMapTy;
> /// \brief All the vftables that have been referenced.
> VFTablesMapTy VFTablesMap;
> + VTablesMapTy VTablesMap;
>
> /// \brief This set holds the record decls we've deferred vtable
> emission for.
> llvm::SmallPtrSet<const CXXRecordDecl *, 4> DeferredVFTables;
> @@ -1051,26 +1053,22 @@ void MicrosoftCXXABI::emitVTableDefiniti
> const CXXRecordDecl *RD) {
> MicrosoftVTableContext &VFTContext = CGM.getMicrosoftVTableContext();
> VPtrInfoVector VFPtrs = VFTContext.getVFPtrOffsets(RD);
> - llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);
>
> for (VPtrInfo *Info : VFPtrs) {
> llvm::GlobalVariable *VTable = getAddrOfVTable(RD,
> Info->FullOffsetInMDC);
> if (VTable->hasInitializer())
> continue;
> - if (getContext().getLangOpts().RTTI)
> - CGM.getMSCompleteObjectLocator(RD, Info);
> +
> + llvm::Constant *RTTI = CGM.getMSCompleteObjectLocator(RD, Info);
>
> const VTableLayout &VTLayout =
> VFTContext.getVFTableLayout(RD, Info->FullOffsetInMDC);
> llvm::Constant *Init = CGVT.CreateVTableInitializer(
> RD, VTLayout.vtable_component_begin(),
> VTLayout.getNumVTableComponents(), VTLayout.vtable_thunk_begin(),
> - VTLayout.getNumVTableThunks());
> - VTable->setInitializer(Init);
> -
> - VTable->setLinkage(Linkage);
> + VTLayout.getNumVTableThunks(), RTTI);
>
> - CGM.setGlobalVisibility(VTable, RD);
> + VTable->setInitializer(Init);
> }
> }
>
> @@ -1079,8 +1077,9 @@ llvm::Value *MicrosoftCXXABI::getVTableA
> const CXXRecordDecl *NearestVBase, bool &NeedsVirtualOffset) {
> NeedsVirtualOffset = (NearestVBase != nullptr);
>
> - llvm::Value *VTableAddressPoint =
> - getAddrOfVTable(VTableClass, Base.getBaseOffset());
> + (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
> + VFTableIdTy ID(VTableClass, Base.getBaseOffset());
> + llvm::GlobalValue *VTableAddressPoint = VFTablesMap[ID];
> if (!VTableAddressPoint) {
> assert(Base.getBase()->getNumVBases() &&
>
> !CGM.getContext().getASTRecordLayout(Base.getBase()).hasOwnVFPtr());
> @@ -1097,9 +1096,11 @@ static void mangleVFTableName(MicrosoftM
>
> llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr(
> BaseSubobject Base, const CXXRecordDecl *VTableClass) {
> - llvm::Constant *VTable = getAddrOfVTable(VTableClass,
> Base.getBaseOffset());
> - assert(VTable && "Couldn't find a vftable for the given base?");
> - return VTable;
> + (void)getAddrOfVTable(VTableClass, Base.getBaseOffset());
> + VFTableIdTy ID(VTableClass, Base.getBaseOffset());
> + llvm::GlobalValue *VFTable = VFTablesMap[ID];
> + assert(VFTable && "Couldn't find a vftable for the given base?");
> + return VFTable;
> }
>
> llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const
> CXXRecordDecl *RD,
> @@ -1108,9 +1109,9 @@ llvm::GlobalVariable *MicrosoftCXXABI::g
> // shouldn't be used in the given record type. We want to cache this
> result in
> // VFTablesMap, thus a simple zero check is not sufficient.
> VFTableIdTy ID(RD, VPtrOffset);
> - VFTablesMapTy::iterator I;
> + VTablesMapTy::iterator I;
> bool Inserted;
> - std::tie(I, Inserted) = VFTablesMap.insert(std::make_pair(ID, nullptr));
> + std::tie(I, Inserted) = VTablesMap.insert(std::make_pair(ID, nullptr));
> if (!Inserted)
> return I->second;
>
> @@ -1140,21 +1141,73 @@ llvm::GlobalVariable *MicrosoftCXXABI::g
> for (size_t J = 0, F = VFPtrs.size(); J != F; ++J) {
> if (VFPtrs[J]->FullOffsetInMDC != VPtrOffset)
> continue;
> + SmallString<256> VFTableName;
> + mangleVFTableName(getMangleContext(), RD, VFPtrs[J], VFTableName);
> + StringRef VTableName = VFTableName;
>
> - llvm::ArrayType *ArrayType = llvm::ArrayType::get(
> - CGM.Int8PtrTy,
> + uint64_t NumVTableSlots =
> VTContext.getVFTableLayout(RD, VFPtrs[J]->FullOffsetInMDC)
> - .getNumVTableComponents());
> + .getNumVTableComponents();
> + llvm::GlobalValue::LinkageTypes VTableLinkage =
> + llvm::GlobalValue::ExternalLinkage;
> + llvm::ArrayType *VTableType =
> + llvm::ArrayType::get(CGM.Int8PtrTy, NumVTableSlots);
> + if (getContext().getLangOpts().RTTI) {
> + VTableLinkage = llvm::GlobalValue::PrivateLinkage;
> + VTableName = "";
> + }
>
> - SmallString<256> Name;
> - mangleVFTableName(getMangleContext(), RD, VFPtrs[J], Name);
> - VTable = CGM.CreateOrReplaceCXXRuntimeVariable(
> - Name.str(), ArrayType, llvm::GlobalValue::ExternalLinkage);
> - VTable->setUnnamedAddr(true);
> - if (RD->hasAttr<DLLImportAttr>())
> -
> VTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
> - else if (RD->hasAttr<DLLExportAttr>())
> -
> VTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
> + VTable = CGM.getModule().getNamedGlobal(VFTableName);
> + if (!VTable) {
> + llvm::GlobalValue *VFTable = VTable = new llvm::GlobalVariable(
> + CGM.getModule(), VTableType, /*isConstant=*/true, VTableLinkage,
> + /*Initializer=*/nullptr, VTableName);
> + VTable->setUnnamedAddr(true);
> + if (getContext().getLangOpts().RTTI &&
> !RD->hasAttr<DLLImportAttr>()) {
> + llvm::Value *GEPIndices[] = {llvm::ConstantInt::get(CGM.IntTy, 0),
> + llvm::ConstantInt::get(CGM.IntTy,
> 1)};
> + llvm::Constant *VTableGEP =
> + llvm::ConstantExpr::getInBoundsGetElementPtr(VTable,
> GEPIndices);
> + VFTable = llvm::GlobalAlias::create(
> +
> cast<llvm::SequentialType>(VTableGEP->getType())->getElementType(),
> + /*AddressSpace=*/0, llvm::GlobalValue::ExternalLinkage,
> + VFTableName.str(), VTableGEP, &CGM.getModule());
> + } else {
> + VTable->setName(VFTableName.str());
> + }
> +
> + VFTable->setUnnamedAddr(true);
> + if (RD->hasAttr<DLLImportAttr>())
> +
> VFTable->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
> + else if (RD->hasAttr<DLLExportAttr>())
> +
> VFTable->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass);
> +
> + llvm::GlobalValue::LinkageTypes VFTableLinkage =
> CGM.getVTableLinkage(RD);
> + if (VFTable != VTable) {
> + if
> (llvm::GlobalValue::isAvailableExternallyLinkage(VFTableLinkage)) {
> + // AvailableExternally implies that we grabbed the data from
> another
> + // executable. No need to stick the alias in a Comdat.
> + } else if (llvm::GlobalValue::isLocalLinkage(VFTableLinkage)) {
> + // If it's local, it means that the virtual function table
> can't be
> + // referenced in another translation unit. No need to stick the
> alias
> + // in a Comdat.
> + } else if (llvm::GlobalValue::isWeakODRLinkage(VFTableLinkage) ||
> +
> llvm::GlobalValue::isLinkOnceODRLinkage(VFTableLinkage)) {
> + // The alias is going to be dropped into a Comdat, no need to
> make it
> + // weak.
> + VFTableLinkage = llvm::GlobalValue::ExternalLinkage;
> + llvm::Comdat *C =
> + CGM.getModule().getOrInsertComdat(VFTable->getName());
> + C->setSelectionKind(llvm::Comdat::Largest);
> + VTable->setComdat(C);
> + } else {
> + llvm_unreachable("unexpected linkage for vftable!");
> + }
> + }
> + VFTable->setLinkage(VFTableLinkage);
> + CGM.setGlobalVisibility(VFTable, RD);
> + VFTablesMap[ID] = VFTable;
> + }
> break;
> }
>
>
> Modified: cfe/trunk/lib/CodeGen/MicrosoftRTTI.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftRTTI.cpp?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/MicrosoftRTTI.cpp (original)
> +++ cfe/trunk/lib/CodeGen/MicrosoftRTTI.cpp Tue Jul 1 15:30:31 2014
> @@ -505,8 +505,10 @@ llvm::Constant *CodeGenModule::getMSType
> Int8PtrTy);
> }
>
> -llvm::GlobalVariable *
> +llvm::Constant *
> CodeGenModule::getMSCompleteObjectLocator(const CXXRecordDecl *RD,
> const VPtrInfo *Info) {
> + if (!getLangOpts().RTTI)
> + return llvm::Constant::getNullValue(Int8PtrTy);
> return MSRTTIBuilder(*this, RD).getCompleteObjectLocator(Info);
> }
>
> Modified: cfe/trunk/test/CodeGenCXX/dllexport.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/dllexport.cpp?rev=212125&r1=212124&r2=212125&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGenCXX/dllexport.cpp (original)
> +++ cfe/trunk/test/CodeGenCXX/dllexport.cpp Tue Jul 1 15:30:31 2014
> @@ -24,6 +24,9 @@ struct External { int v; };
> #define INSTVAR(var) template int var;
> #define INST(func) template void func();
>
> +// The vftable for struct W is comdat largest because we have RTTI.
> +// M32-DAG: $"\01??_7W@@6B@" = comdat largest
> +
>
>
> //===----------------------------------------------------------------------===//
> // Globals
> @@ -518,7 +521,8 @@ struct __declspec(dllexport) W { virtual
> // Copy ctor:
> // M32-DAG: define weak_odr dllexport x86_thiscallcc %struct.W* @"\01??0W@
> @QAE at ABU0@@Z"
> // vftable:
> -// M32-DAG: @"\01??_7W@@6B@" = weak_odr dllexport unnamed_addr constant
> [1 x i8*] [i8* bitcast (void (%struct.W*)* @"\01?foo at W@@UAEXXZ" to i8*)]
> +// M32-DAG: [[W_VTABLE:@.*]] = private unnamed_addr constant [2 x i8*]
> [i8* bitcast (%MSRTTICompleteObjectLocator* @"\01??_R4W@@6B@" to i8*),
> i8* bitcast (void (%struct.W*)* @"\01?foo at W@@UAEXXZ" to i8*)], comdat
> $"\01??_7W@@6B@"
> +// M32-DAG: @"\01??_7W@@6B@" = dllexport unnamed_addr alias
> getelementptr inbounds ([2 x i8*]* [[W_VTABLE]], i32 0, i32 1), comdat
> $"\01??_7W@@6B@"
> // G32-DAG: @_ZTV1W = weak_odr dllexport unnamed_addr constant [3 x i8*]
> [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI1W to i8*), i8* bitcast (void
> (%struct.W*)* @_ZN1W3fooEv to i8*)]
>
> struct __declspec(dllexport) X : public virtual W {};
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140708/5e9d4e0c/attachment.html>
More information about the cfe-commits
mailing list