diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -185,12 +185,16 @@ (R.getVersion() >= VersionTuple(major, minor)); } + StringRef SymbolPrefix() { + return CGM.getTriple().isOSBinFormatCOFF() ? "_" : "._"; + } + std::string SymbolForProtocol(StringRef Name) { - return (StringRef("._OBJC_PROTOCOL_") + Name).str(); + return (SymbolPrefix() + "OBJC_PROTOCOL_" + Name).str(); } std::string SymbolForProtocolRef(StringRef Name) { - return (StringRef("._OBJC_REF_PROTOCOL_") + Name).str(); + return (SymbolPrefix() + "OBJC_REF_PROTOCOL_" + Name).str(); } @@ -906,12 +910,15 @@ ConstantStringSection }; static const char *const SectionsBaseNames[8]; + static const char *const PECOFFSectionsBaseNames[8]; template std::string sectionName() { - std::string name(SectionsBaseNames[K]); - if (CGM.getTriple().isOSBinFormatCOFF()) + if (CGM.getTriple().isOSBinFormatCOFF()) { + std::string name(PECOFFSectionsBaseNames[K]); name += "$m"; - return name; + return name; + } + return SectionsBaseNames[K]; } /// The GCC ABI superclass message lookup function. Takes a pointer to a /// structure describing the receiver and the class, and a selector as @@ -932,15 +939,19 @@ bool EmittedClass = false; /// Generate the name of a symbol for a reference to a class. Accesses to /// classes should be indirected via this. + + typedef std::pair> EarlyInitPair; + std::vector EarlyInitList; + std::string SymbolForClassRef(StringRef Name, bool isWeak) { if (isWeak) - return (StringRef("._OBJC_WEAK_REF_CLASS_") + Name).str(); + return (SymbolPrefix() + "OBJC_WEAK_REF_CLASS_" + Name).str(); else - return (StringRef("._OBJC_REF_CLASS_") + Name).str(); + return (SymbolPrefix() + "OBJC_REF_CLASS_" + Name).str(); } /// Generate the name of a class symbol. std::string SymbolForClass(StringRef Name) { - return (StringRef("._OBJC_CLASS_") + Name).str(); + return (SymbolPrefix() + "OBJC_CLASS_" + Name).str(); } void CallRuntimeFunction(CGBuilderTy &B, StringRef FunctionName, ArrayRef Args) { @@ -994,10 +1005,13 @@ llvm::Constant *isa = TheModule.getNamedGlobal(Sym); - if (!isa) + if (!isa) { isa = new llvm::GlobalVariable(TheModule, IdTy, /* isConstant */false, llvm::GlobalValue::ExternalLinkage, nullptr, Sym); - else if (isa->getType() != PtrToIdTy) + if (CGM.getTriple().isOSBinFormatCOFF()) { + cast(isa)->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + } + } else if (isa->getType() != PtrToIdTy) isa = llvm::ConstantExpr::getBitCast(isa, PtrToIdTy); // struct @@ -1012,7 +1026,11 @@ ConstantInitBuilder Builder(CGM); auto Fields = Builder.beginStruct(); - Fields.add(isa); + if (!CGM.getTriple().isOSBinFormatCOFF()) { + Fields.add(isa); + } else { + Fields.addNullPointer(PtrTy); + } // For now, all non-ASCII strings are represented as UTF-16. As such, the // number of bytes is simply double the number of UTF-16 codepoints. In // ASCII strings, the number of bytes is equal to the number of non-ASCII @@ -1083,6 +1101,10 @@ ObjCStrGV->setComdat(TheModule.getOrInsertComdat(StringName)); ObjCStrGV->setVisibility(llvm::GlobalValue::HiddenVisibility); } + if (CGM.getTriple().isOSBinFormatCOFF()) { + std::pair v{ObjCStrGV, 0}; + EarlyInitList.emplace_back(Sym, v); + } llvm::Constant *ObjCStr = llvm::ConstantExpr::getBitCast(ObjCStrGV, IdTy); ObjCStrings[Str] = ObjCStr; ConstantStrings.push_back(ObjCStr); @@ -1196,6 +1218,26 @@ ClassSymbol->setInitializer(new llvm::GlobalVariable(TheModule, Int8Ty, false, llvm::GlobalValue::ExternalWeakLinkage, nullptr, SymbolForClass(Name))); + else { + if (CGM.getTriple().isOSBinFormatCOFF()) { + IdentifierInfo &II = CGM.getContext().Idents.get(Name); + TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); + DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); + + const ObjCInterfaceDecl *OID = nullptr; + for (const auto &Result : DC->lookup(&II)) + if ((OID = dyn_cast(Result))) + break; + + auto Storage = llvm::GlobalValue::DefaultStorageClass; + if (OID->hasAttr()) + Storage = llvm::GlobalValue::DLLImportStorageClass; + else if (OID->hasAttr()) + Storage = llvm::GlobalValue::DLLExportStorageClass; + + cast(ClassSymbol)->setDLLStorageClass(Storage); + } + } assert(ClassSymbol->getName() == SymbolName); return ClassSymbol; } @@ -1448,7 +1490,7 @@ Sym->setSection((Section + SecSuffix).str()); Sym->setComdat(TheModule.getOrInsertComdat((Prefix + Section).str())); - Sym->setAlignment(1); + Sym->setAlignment(CGM.getPointerAlign().getQuantity()); return Sym; }; return { Sym("__start_", "$a"), Sym("__stop", "$z") }; @@ -1483,11 +1525,19 @@ ConstantInitBuilder builder(CGM); auto InitStructBuilder = builder.beginStruct(); InitStructBuilder.addInt(Int64Ty, 0); - for (auto *s : SectionsBaseNames) { - auto bounds = GetSectionBounds(s); - InitStructBuilder.add(bounds.first); - InitStructBuilder.add(bounds.second); - }; + if (CGM.getTriple().isOSBinFormatCOFF()) { + for (auto *s : PECOFFSectionsBaseNames) { + auto bounds = GetSectionBounds(s); + InitStructBuilder.add(bounds.first); + InitStructBuilder.add(bounds.second); + } + } else { + for (auto *s : SectionsBaseNames) { + auto bounds = GetSectionBounds(s); + InitStructBuilder.add(bounds.first); + InitStructBuilder.add(bounds.second); + } + } auto *InitStruct = InitStructBuilder.finishAndCreateGlobal(".objc_init", CGM.getPointerAlign(), false, llvm::GlobalValue::LinkOnceODRLinkage); InitStruct->setVisibility(llvm::GlobalValue::HiddenVisibility); @@ -1577,6 +1627,29 @@ ConstantStrings.clear(); Categories.clear(); Classes.clear(); + + if (EarlyInitList.size() > 0) { + auto *Init = llvm::Function::Create(llvm::FunctionType::get(CGM.VoidTy, + {}), llvm::GlobalValue::InternalLinkage, ".objc_early_init", + &CGM.getModule()); + llvm::IRBuilder<> b(llvm::BasicBlock::Create(CGM.getLLVMContext(), "entry", + Init)); + for (const auto &lateInit : EarlyInitList) { + auto *global = TheModule.getGlobalVariable(lateInit.first); + if (global) { + b.CreateAlignedStore(global, + b.CreateStructGEP(lateInit.second.first, lateInit.second.second), CGM.getPointerAlign().getQuantity()); + } + } + b.CreateRetVoid(); + // We can't use the normal LLVM global initialisation array, because we + // need to specify that this runs early in library initialisation. + auto *InitVar = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), + /*isConstant*/true, llvm::GlobalValue::InternalLinkage, + Init, ".objc_early_init_ptr"); + InitVar->setSection(".CRT$XCLb"); + CGM.addUsedGlobal(InitVar); + } return nullptr; } /// In the v2 ABI, ivar offset variables use the type encoding in their name @@ -1608,6 +1681,7 @@ } void GenerateClass(const ObjCImplementationDecl *OID) override { ASTContext &Context = CGM.getContext(); + bool IsCOFF = CGM.getTriple().isOSBinFormatCOFF(); // Get the class name ObjCInterfaceDecl *classDecl = @@ -1666,8 +1740,8 @@ // struct objc_property_list *properties metaclassFields.add(GeneratePropertyList(OID, classDecl, /*isClassProperty*/true)); - auto *metaclass = metaclassFields.finishAndCreateGlobal("._OBJC_METACLASS_" - + className, CGM.getPointerAlign()); + auto *metaclass = metaclassFields.finishAndCreateGlobal(SymbolPrefix() + + "OBJC_METACLASS_" + className, CGM.getPointerAlign()); auto classFields = builder.beginStruct(); // struct objc_class *isa; @@ -1676,15 +1750,28 @@ // Get the superclass name. const ObjCInterfaceDecl * SuperClassDecl = OID->getClassInterface()->getSuperClass(); + llvm::Constant *SuperClass = nullptr; if (SuperClassDecl) { auto SuperClassName = SymbolForClass(SuperClassDecl->getNameAsString()); - llvm::Constant *SuperClass = TheModule.getNamedGlobal(SuperClassName); + SuperClass = TheModule.getNamedGlobal(SuperClassName); if (!SuperClass) { SuperClass = new llvm::GlobalVariable(TheModule, PtrTy, false, llvm::GlobalValue::ExternalLinkage, nullptr, SuperClassName); + if (IsCOFF) { + auto Storage = llvm::GlobalValue::DefaultStorageClass; + if (SuperClassDecl->hasAttr()) + Storage = llvm::GlobalValue::DLLImportStorageClass; + else if (SuperClassDecl->hasAttr()) + Storage = llvm::GlobalValue::DLLExportStorageClass; + + cast(SuperClass)->setDLLStorageClass(Storage); + } } - classFields.add(llvm::ConstantExpr::getBitCast(SuperClass, PtrTy)); + if (!IsCOFF) + classFields.add(llvm::ConstantExpr::getBitCast(SuperClass, PtrTy)); + else + classFields.addNullPointer(PtrTy); } else classFields.addNullPointer(PtrTy); // const char *name; @@ -1832,19 +1919,24 @@ classFields.finishAndCreateGlobal(SymbolForClass(className), CGM.getPointerAlign(), false, llvm::GlobalValue::ExternalLinkage); - if (CGM.getTriple().isOSBinFormatCOFF()) { - auto Storage = llvm::GlobalValue::DefaultStorageClass; - if (OID->getClassInterface()->hasAttr()) - Storage = llvm::GlobalValue::DLLImportStorageClass; - else if (OID->getClassInterface()->hasAttr()) - Storage = llvm::GlobalValue::DLLExportStorageClass; - cast(classStruct)->setDLLStorageClass(Storage); - } - auto *classRefSymbol = GetClassVar(className); classRefSymbol->setSection(sectionName()); classRefSymbol->setInitializer(llvm::ConstantExpr::getBitCast(classStruct, IdTy)); + if (IsCOFF) { + // we can't import a class struct. + if (OID->getClassInterface()->hasAttr()) { + cast(classStruct)->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + cast(classRefSymbol)->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); + } + + if (SuperClass) { + std::pair v{classStruct, 1}; + EarlyInitList.emplace_back(SuperClass->getName(), std::move(v)); + } + + } + // Resolve the class aliases, if they exist. // FIXME: Class pointer aliases shouldn't exist! @@ -1872,7 +1964,7 @@ auto classInitRef = new llvm::GlobalVariable(TheModule, classStruct->getType(), false, llvm::GlobalValue::ExternalLinkage, - classStruct, "._OBJC_INIT_CLASS_" + className); + classStruct, SymbolPrefix() + "OBJC_INIT_CLASS_" + className); classInitRef->setSection(sectionName()); CGM.addUsedGlobal(classInitRef); @@ -1909,6 +2001,18 @@ "__objc_constant_string" }; +const char *const CGObjCGNUstep2::PECOFFSectionsBaseNames[8] = +{ +".objcrt$SEL", +".objcrt$CLS", +".objcrt$CLR", +".objcrt$CAT", +".objcrt$PCL", +".objcrt$PCR", +".objcrt$CAL", +".objcrt$STR" +}; + /// Support for the ObjFW runtime. class CGObjCObjFW: public CGObjCGNU { protected: