Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -5101,6 +5101,25 @@ See :doc:`TypeMetadata`. +'``associated``' Metadata +^^^^^^^^^^^^^^^^^^^ + +The ``associated`` metadata may be attached to a global object +declaration with a single argument that references another global object. + +This metadata prevents discarding of the global object in linker GC +unless the referenced object is also discarded. All IR transforms must +preserve this metadata. + +It does not have any effect on non-ELF targets. + +Example: + +.. code-block:: llvm + @a = global i32 1 + @b = internal global i32 2, !associated !0 + !0 = !{i32* @a} + Module Flags Metadata ===================== Index: include/llvm/IR/LLVMContext.h =================================================================== --- include/llvm/IR/LLVMContext.h +++ include/llvm/IR/LLVMContext.h @@ -78,6 +78,7 @@ MD_type = 19, // "type" MD_section_prefix = 20, // "section_prefix" MD_absolute_symbol = 21, // "absolute_symbol" + MD_associated = 22, // "associated" }; /// Known operand bundle tag IDs, which always have the same value. All Index: include/llvm/MC/MCContext.h =================================================================== --- include/llvm/MC/MCContext.h +++ include/llvm/MC/MCContext.h @@ -241,7 +241,7 @@ unsigned EntrySize, const MCSymbolELF *Group, unsigned UniqueID, - const MCSectionELF *Associated); + const MCSymbolELF *Associated); public: explicit MCContext(const MCAsmInfo *MAI, const MCRegisterInfo *MRI, @@ -372,12 +372,12 @@ MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const Twine &Group, unsigned UniqueID, - const MCSectionELF *Associated); + const MCSymbolELF *Associated); MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, unsigned UniqueID, - const MCSectionELF *Associated); + const MCSymbolELF *Associated); /// Get a section with the provided group identifier. This section is /// named by concatenating \p Prefix with '.' then \p Suffix. The \p Type @@ -390,7 +390,7 @@ MCSectionELF *createELFRelSection(const Twine &Name, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, - const MCSectionELF *Associated); + const MCSectionELF *RelInfoSection); void renameELFSection(MCSectionELF *Section, StringRef Name); Index: include/llvm/MC/MCSectionELF.h =================================================================== --- include/llvm/MC/MCSectionELF.h +++ include/llvm/MC/MCSectionELF.h @@ -45,18 +45,21 @@ const MCSymbolELF *Group; - /// Depending on the type of the section this is sh_link or sh_info. - const MCSectionELF *Associated; + /// sh_link for REL and RELA sections. + const MCSectionELF *RelInfoSection; + + /// sh_info for SHF_LINK_ORDER (can be null). + const MCSymbol *AssociatedSymbol; private: friend class MCContext; MCSectionELF(StringRef Section, unsigned type, unsigned flags, SectionKind K, unsigned entrySize, const MCSymbolELF *group, unsigned UniqueID, - MCSymbol *Begin, const MCSectionELF *Associated) + MCSymbol *Begin, const MCSymbolELF *AssociatedSymbol) : MCSection(SV_ELF, K, Begin), SectionName(Section), Type(type), Flags(flags), UniqueID(UniqueID), EntrySize(entrySize), Group(group), - Associated(Associated) { + RelInfoSection(nullptr), AssociatedSymbol(AssociatedSymbol) { if (Group) Group->setIsSignature(); } @@ -86,7 +89,10 @@ bool isUnique() const { return UniqueID != ~0U; } unsigned getUniqueID() const { return UniqueID; } - const MCSectionELF *getAssociatedSection() const { return Associated; } + const MCSectionELF *getRelInfoSection() const { return RelInfoSection; } + void setRelInfoSection(const MCSectionELF* S) { RelInfoSection = S; } + + const MCSymbol *getAssociatedSymbol() const { return AssociatedSymbol; } static bool classof(const MCSection *S) { return S->getVariant() == SV_ELF; Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -211,6 +211,15 @@ return C; } +static const MCSymbolELF *getAssociatedSymbol(MDNode *MD, const TargetMachine &TM) { + auto *VM = dyn_cast(MD->getOperand(0)); + if (!VM) + report_fatal_error("MD_associated operand is not ValueAsMetadata"); + + GlobalObject *GO = dyn_cast(VM->getValue()); + return dyn_cast(TM.getSymbol(GO)); +} + MCSection *TargetLoweringObjectFileELF::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { StringRef SectionName = GO->getSection(); @@ -224,9 +233,24 @@ Group = C->getName(); Flags |= ELF::SHF_GROUP; } - return getContext().getELFSection(SectionName, - getELFSectionType(SectionName, Kind), Flags, - /*EntrySize=*/0, Group); + + // A section can have at most one associated section. Put each global with + // MD_associated in a unique section. + unsigned UniqueID = MCContext::GenericSectionID; + const MCSymbolELF *AssociatedSymbol = nullptr; + if (MDNode *MD = GO->getMetadata(LLVMContext::MD_associated)) { + UniqueID = NextUniqueID++; + Flags |= ELF::SHF_LINK_ORDER; + AssociatedSymbol = getAssociatedSymbol(MD, TM); + } + + MCSectionELF *Section = getContext().getELFSection( + SectionName, getELFSectionType(SectionName, Kind), Flags, + /*EntrySize=*/0, Group, UniqueID, AssociatedSymbol); + // Make sure that we did not get some other section with incompatible sh_link. + // This should not be possible due to UniqueID code above. + assert(Section->getAssociatedSymbol() == AssociatedSymbol); + return Section; } /// Return the section prefix name used by options FunctionsSections and @@ -248,11 +272,10 @@ return ".data.rel.ro"; } -static MCSectionELF * -selectELFSectionForGlobal(MCContext &Ctx, const GlobalObject *GO, - SectionKind Kind, Mangler &Mang, - const TargetMachine &TM, bool EmitUniqueSection, - unsigned Flags, unsigned *NextUniqueID) { +static MCSectionELF *selectELFSectionForGlobal( + MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, + const TargetMachine &TM, bool EmitUniqueSection, unsigned Flags, + unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) { unsigned EntrySize = 0; if (Kind.isMergeableCString()) { if (Kind.isMergeable2ByteCString()) { @@ -319,7 +342,7 @@ if (Kind.isExecuteOnly()) UniqueID = 0; return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags, - EntrySize, Group, UniqueID); + EntrySize, Group, UniqueID, AssociatedSymbol); } MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal( @@ -337,8 +360,20 @@ } EmitUniqueSection |= GO->hasComdat(); - return selectELFSectionForGlobal(getContext(), GO, Kind, getMangler(), TM, - EmitUniqueSection, Flags, &NextUniqueID); + const MCSymbolELF *AssociatedSymbol = nullptr; + if (MDNode *MD = GO->getMetadata(LLVMContext::MD_associated)) { + EmitUniqueSection = true; + Flags |= ELF::SHF_LINK_ORDER; + AssociatedSymbol = getAssociatedSymbol(MD, TM); + } + + EmitUniqueSection |= GO->getMetadata(LLVMContext::MD_associated) != nullptr; + + MCSectionELF *Section = selectELFSectionForGlobal( + getContext(), GO, Kind, getMangler(), TM, EmitUniqueSection, Flags, + &NextUniqueID, AssociatedSymbol); + assert(Section->getAssociatedSymbol() == AssociatedSymbol); + return Section; } MCSection *TargetLoweringObjectFileELF::getSectionForJumpTable( @@ -351,8 +386,9 @@ return ReadOnlySection; return selectELFSectionForGlobal(getContext(), &F, SectionKind::getReadOnly(), - getMangler(), TM, EmitUniqueSection, ELF::SHF_ALLOC, - &NextUniqueID); + getMangler(), TM, EmitUniqueSection, + ELF::SHF_ALLOC, &NextUniqueID, + /* AssociatedSymbol */ nullptr); } bool TargetLoweringObjectFileELF::shouldPutJumpTableInFunctionSection( Index: lib/IR/LLVMContext.cpp =================================================================== --- lib/IR/LLVMContext.cpp +++ lib/IR/LLVMContext.cpp @@ -58,6 +58,7 @@ {MD_type, "type"}, {MD_section_prefix, "section_prefix"}, {MD_absolute_symbol, "absolute_symbol"}, + {MD_associated, "associated"}, }; for (auto &MDKind : MDKinds) { Index: lib/MC/ELFObjectWriter.cpp =================================================================== --- lib/MC/ELFObjectWriter.cpp +++ lib/MC/ELFObjectWriter.cpp @@ -1153,7 +1153,7 @@ case ELF::SHT_RELA: { sh_link = SymbolTableIndex; assert(sh_link && ".symtab not found"); - const MCSectionELF *InfoSection = Section.getAssociatedSection(); + const MCSectionELF *InfoSection = Section.getRelInfoSection(); sh_info = SectionIndexMap.lookup(InfoSection); break; } @@ -1174,8 +1174,12 @@ break; } - if (Section.getFlags() & ELF::SHF_LINK_ORDER) - sh_link = SectionIndexMap.lookup(Section.getAssociatedSection()); + if (Section.getFlags() & ELF::SHF_LINK_ORDER) { + const MCSymbol *Sym = Section.getAssociatedSymbol(); + assert(Sym && Sym->isInSection()); + const MCSectionELF *Sec = dyn_cast(&Sym->getSection()); + sh_link = SectionIndexMap.lookup(Sec); + } WriteSecHdrEntry(StrTabBuilder.getOffset(Section.getSectionName()), Section.getType(), Section.getFlags(), 0, Offset, Size, @@ -1299,7 +1303,7 @@ // Remember the offset into the file for this section. uint64_t SecStart = getStream().tell(); - writeRelocations(Asm, *RelSection->getAssociatedSection()); + writeRelocations(Asm, *RelSection->getRelInfoSection()); uint64_t SecEnd = getStream().tell(); SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd); Index: lib/MC/MCContext.cpp =================================================================== --- lib/MC/MCContext.cpp +++ lib/MC/MCContext.cpp @@ -312,7 +312,7 @@ unsigned EntrySize, const MCSymbolELF *Group, unsigned UniqueID, - const MCSectionELF *Associated) { + const MCSymbolELF *Associated) { MCSymbolELF *R; MCSymbol *&Sym = Symbols[Section]; if (Sym && Sym->isUndefined()) { @@ -341,15 +341,17 @@ MCSectionELF *MCContext::createELFRelSection(const Twine &Name, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *Group, - const MCSectionELF *Associated) { + const MCSectionELF *RelInfoSection) { StringMap::iterator I; bool Inserted; std::tie(I, Inserted) = ELFRelSecNames.insert(std::make_pair(Name.str(), true)); - return createELFSectionImpl(I->getKey(), Type, Flags, - SectionKind::getReadOnly(), EntrySize, Group, - true, Associated); + MCSectionELF *Section = + createELFSectionImpl(I->getKey(), Type, Flags, SectionKind::getReadOnly(), + EntrySize, Group, true, nullptr); + Section->setRelInfoSection(RelInfoSection); + return Section; } MCSectionELF *MCContext::getELFNamedSection(const Twine &Prefix, @@ -362,7 +364,7 @@ MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const Twine &Group, unsigned UniqueID, - const MCSectionELF *Associated) { + const MCSymbolELF *Associated) { MCSymbolELF *GroupSym = nullptr; if (!Group.isTriviallyEmpty() && !Group.str().empty()) GroupSym = cast(getOrCreateSymbol(Group)); @@ -375,7 +377,7 @@ unsigned Flags, unsigned EntrySize, const MCSymbolELF *GroupSym, unsigned UniqueID, - const MCSectionELF *Associated) { + const MCSymbolELF *Associated) { StringRef Group = ""; if (GroupSym) Group = GroupSym->getName(); Index: lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- lib/MC/MCParser/ELFAsmParser.cpp +++ lib/MC/MCParser/ELFAsmParser.cpp @@ -157,7 +157,7 @@ bool maybeParseSectionType(StringRef &TypeName); bool parseMergeSize(int64_t &Size); bool parseGroup(StringRef &GroupName); - bool parseMetadataSym(MCSectionELF *&Associated); + bool parseMetadataSym(MCSymbolELF *&Associated); bool maybeParseUniqueID(int64_t &UniqueID); }; @@ -429,7 +429,7 @@ return false; } -bool ELFAsmParser::parseMetadataSym(MCSectionELF *&Associated) { +bool ELFAsmParser::parseMetadataSym(MCSymbolELF *&Associated) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) return TokError("expected metadata symbol"); @@ -437,10 +437,9 @@ StringRef Name; if (getParser().parseIdentifier(Name)) return true; - MCSymbol *Sym = getContext().lookupSymbol(Name); - if (!Sym || !Sym->isInSection()) + Associated = dyn_cast_or_null(getContext().lookupSymbol(Name)); + if (!Associated || !Associated->isInSection()) return TokError("symbol is not in a section: " + Name); - Associated = cast(&Sym->getSection()); return false; } @@ -479,7 +478,7 @@ const MCExpr *Subsection = nullptr; bool UseLastGroup = false; StringRef UniqueStr; - MCSectionELF *Associated = nullptr; + MCSymbolELF *Associated = nullptr; int64_t UniqueID = ~0; // Set the defaults first. @@ -594,8 +593,9 @@ } } - MCSection *ELFSection = getContext().getELFSection( - SectionName, Type, Flags, Size, GroupName, UniqueID, Associated); + MCSection *ELFSection = + getContext().getELFSection(SectionName, Type, Flags, Size, GroupName, + UniqueID, Associated); getStreamer().SwitchSection(ELFSection, Subsection); if (getContext().getGenDwarfForAssembly()) { Index: lib/MC/MCSectionELF.cpp =================================================================== --- lib/MC/MCSectionELF.cpp +++ lib/MC/MCSectionELF.cpp @@ -102,6 +102,8 @@ OS << 'S'; if (Flags & ELF::SHF_TLS) OS << 'T'; + if (Flags & ELF::SHF_LINK_ORDER) + OS << 'm'; // If there are target-specific flags, print them. Triple::ArchType Arch = T.getArch(); @@ -152,6 +154,11 @@ OS << ",comdat"; } + if (Flags & ELF::SHF_LINK_ORDER && AssociatedSymbol) { + OS << ","; + printName(OS, AssociatedSymbol->getName()); + } + if (isUnique()) OS << ",unique," << UniqueID; Index: lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -1139,7 +1139,8 @@ if (Group) Flags |= ELF::SHF_GROUP; MCSectionELF *EHSection = getContext().getELFSection( - EHSecName, Type, Flags, 0, Group, FnSection.getUniqueID(), &FnSection); + EHSecName, Type, Flags, 0, Group, FnSection.getUniqueID(), + dyn_cast(&Fn)); assert(EHSection && "Failed to get the required EH section"); Index: test/CodeGen/X86/elf-associated.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/elf-associated.ll @@ -0,0 +1,34 @@ +; RUN: llc -data-sections=1 -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s +; RUN: llc -data-sections=0 -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s + +@a = global i32 1 +@b = global i32 2, !associated !0 +!0 = !{i32* @a} +; CHECK-DAG: .section .data.b,"awm",@progbits,a + +; Loop is OK. Also, normally -data-sections=0 would place @c and @d in the same section. !associated prevents that. +@c = global i32 2, !associated !2 +@d = global i32 2, !associated !1 +!1 = !{i32* @c} +!2 = !{i32* @d} +; CHECK-DAG: .section .data.c,"awm",@progbits,d +; CHECK-DAG: .section .data.d,"awm",@progbits,c + +; BSS is OK. +@e = global i32 0 +@f = global i32 0, !associated !3 +@g = global i32 1, !associated !3 +!3 = !{i32* @e} +; CHECK-DAG: .section .bss.f,"awm",@nobits,e +; CHECK-DAG: .section .data.g,"awm",@progbits,e + +; Explicit sections. +@h = global i32 1, section "aaa" +@i = global i32 1, section "bbb", !associated !4 +@j = global i32 1, section "bbb", !associated !4 +@k = global i32 1, !associated !4 +!4 = !{i32* @h} +; CHECK-DAG: .section aaa,"aw",@progbits +; CHECK-DAG: .section bbb,"awm",@progbits,h,unique,1 +; CHECK-DAG: .section bbb,"awm",@progbits,h,unique,2 +; CHECK-DAG: .section .data.k,"awm",@progbits,h Index: test/ThinLTO/X86/lazyload_metadata.ll =================================================================== --- test/ThinLTO/X86/lazyload_metadata.ll +++ test/ThinLTO/X86/lazyload_metadata.ll @@ -10,13 +10,13 @@ ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \ ; RUN: -o /dev/null -stats \ ; RUN: 2>&1 | FileCheck %s -check-prefix=LAZY -; LAZY: 49 bitcode-reader - Number of Metadata records loaded +; LAZY: 51 bitcode-reader - Number of Metadata records loaded ; LAZY: 2 bitcode-reader - Number of MDStrings loaded ; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \ ; RUN: -o /dev/null -disable-ondemand-mds-loading -stats \ ; RUN: 2>&1 | FileCheck %s -check-prefix=NOTLAZY -; NOTLAZY: 58 bitcode-reader - Number of Metadata records loaded +; NOTLAZY: 60 bitcode-reader - Number of Metadata records loaded ; NOTLAZY: 7 bitcode-reader - Number of MDStrings loaded @@ -55,4 +55,4 @@ !6 = !{!9} !7 = !{!"7"} !8 = !{!"8"} -!9 = !{!6} \ No newline at end of file +!9 = !{!6}