Index: lld/ELF/InputFiles.cpp =================================================================== --- lld/ELF/InputFiles.cpp +++ lld/ELF/InputFiles.cpp @@ -605,24 +605,17 @@ StringRef signature = getShtGroupSignature(objSections, sec); this->sections[i] = &InputSection::discarded; - ArrayRef entries = CHECK(obj.template getSectionContentsAsArray(sec), this); if (entries.empty()) fatal(toString(this) + ": empty SHT_GROUP"); - // The first word of a SHT_GROUP section contains flags. Currently, - // the standard defines only "GRP_COMDAT" flag for the COMDAT group. - // An group with the empty flag doesn't define anything; such sections - // are just skipped. - if (entries[0] == 0) - continue; - - if (entries[0] != GRP_COMDAT) + Elf_Word flag = entries[0]; + if (flag && flag != GRP_COMDAT) fatal(toString(this) + ": unsupported SHT_GROUP format"); bool isNew = - ignoreComdats || + (flag & GRP_COMDAT) == 0 || ignoreComdats || symtab->comdatGroups.try_emplace(CachedHashStringRef(signature), this) .second; if (isNew) { Index: lld/test/ELF/gc-sections-group-debug.s =================================================================== --- lld/test/ELF/gc-sections-group-debug.s +++ lld/test/ELF/gc-sections-group-debug.s @@ -8,5 +8,5 @@ # CHECK: Name: .debug_types -.section .debug_types,"G",@progbits,abcd,comdat +.section .debug_types,"G",@progbits,abcd .quad .debug_types Index: lld/test/ELF/gc-sections-group.s =================================================================== --- lld/test/ELF/gc-sections-group.s +++ lld/test/ELF/gc-sections-group.s @@ -34,19 +34,19 @@ .globl anote_foo, foo, bss_foo, note_foo -.section .myanote.foo,"aG",@note,foo,comdat +.section .myanote.foo,"aG",@note,foo anote_foo: .byte 0 -.section .mytext.foo,"axG",@progbits,foo,comdat +.section .mytext.foo,"axG",@progbits,foo foo: .byte 0 -.section .mybss.foo,"awG",@nobits,foo,comdat +.section .mybss.foo,"awG",@nobits,foo bss_foo: .byte 0 -.section .mynote.foo,"G",@note,foo,comdat +.section .mynote.foo,"G",@note,foo note_foo: .byte 0 Index: llvm/include/llvm/IR/GlobalObject.h =================================================================== --- llvm/include/llvm/IR/GlobalObject.h +++ llvm/include/llvm/IR/GlobalObject.h @@ -55,6 +55,7 @@ enum { LastAlignmentBit = 4, HasSectionHashEntryBit, + HasGroupHashEntryBit, GlobalObjectBits, }; @@ -121,6 +122,19 @@ /// appropriate default object file section. void setSection(StringRef S); + /// Check if this global has a group. + bool hasGroup() const { + return getGlobalValueSubClassData() & (1 << HasGroupHashEntryBit); + } + + /// Get the group of this global if it has one. + StringRef getGroup() const { + return hasGroup() ? getGroupImpl() : StringRef(); + } + + /// Change the group for this global. + void setGroup(StringRef G); + bool hasComdat() const { return getComdat() != nullptr; } const Comdat *getComdat() const { return ObjComdat; } Comdat *getComdat() { return ObjComdat; } @@ -166,6 +180,7 @@ } StringRef getSectionImpl() const; + StringRef getGroupImpl() const; }; } // end namespace llvm Index: llvm/include/llvm/MC/MCContext.h =================================================================== --- llvm/include/llvm/MC/MCContext.h +++ llvm/include/llvm/MC/MCContext.h @@ -310,7 +310,7 @@ MCSectionELF *createELFSectionImpl(StringRef Section, unsigned Type, unsigned Flags, SectionKind K, unsigned EntrySize, - const MCSymbolELF *Group, + const MCSymbolELF *Group, bool IsComdat, unsigned UniqueID, const MCSymbolELF *LinkedToSym); @@ -487,19 +487,21 @@ MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - const Twine &Group) { - return getELFSection(Section, Type, Flags, EntrySize, Group, + const Twine &Group, bool IsComdat = true) { + return getELFSection(Section, Type, Flags, EntrySize, Group, IsComdat, MCSection::NonUniqueID, nullptr); } MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - const Twine &Group, unsigned UniqueID, + const Twine &Group, bool IsComdat, + unsigned UniqueID, const MCSymbolELF *LinkedToSym); MCSectionELF *getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - const MCSymbolELF *Group, unsigned UniqueID, + const MCSymbolELF *Group, bool IsComdat, + unsigned UniqueID, const MCSymbolELF *LinkedToSym); /// Get a section with the provided group identifier. This section is @@ -517,7 +519,8 @@ void renameELFSection(MCSectionELF *Section, StringRef Name); - MCSectionELF *createELFGroupSection(const MCSymbolELF *Group); + MCSectionELF *createELFGroupSection(const MCSymbolELF *Group, + bool IsComdat); void recordELFMergeableSectionInfo(StringRef SectionName, unsigned Flags, unsigned UniqueID, unsigned EntrySize); Index: llvm/include/llvm/MC/MCSectionELF.h =================================================================== --- llvm/include/llvm/MC/MCSectionELF.h +++ llvm/include/llvm/MC/MCSectionELF.h @@ -13,6 +13,7 @@ #ifndef LLVM_MC_MCSECTIONELF_H #define LLVM_MC_MCSECTIONELF_H +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbolELF.h" @@ -38,7 +39,7 @@ /// fixed-sized entries 'EntrySize' will be 0. unsigned EntrySize; - const MCSymbolELF *Group; + const PointerIntPair Group; /// Used by SHF_LINK_ORDER. If non-null, the sh_link field will be set to the /// section header index of the section where LinkedToSym is defined. @@ -49,13 +50,14 @@ // The storage of Name is owned by MCContext's ELFUniquingMap. MCSectionELF(StringRef Name, unsigned type, unsigned flags, SectionKind K, - unsigned entrySize, const MCSymbolELF *group, unsigned UniqueID, - MCSymbol *Begin, const MCSymbolELF *LinkedToSym) + unsigned entrySize, const MCSymbolELF *group, bool IsComdat, + unsigned UniqueID, MCSymbol *Begin, + const MCSymbolELF *LinkedToSym) : MCSection(SV_ELF, Name, K, Begin), Type(type), Flags(flags), - UniqueID(UniqueID), EntrySize(entrySize), Group(group), + UniqueID(UniqueID), EntrySize(entrySize), Group(group, IsComdat), LinkedToSym(LinkedToSym) { - if (Group) - Group->setIsSignature(); + if (Group.getPointer()) + Group.getPointer()->setIsSignature(); } // TODO Delete after we stop supporting generation of GNU-style .zdebug_* @@ -71,7 +73,8 @@ unsigned getFlags() const { return Flags; } unsigned getEntrySize() const { return EntrySize; } void setFlags(unsigned F) { Flags = F; } - const MCSymbolELF *getGroup() const { return Group; } + const MCSymbolELF *getGroup() const { return Group.getPointer(); } + bool isComdat() const { return Group.getInt(); } void PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T, raw_ostream &OS, Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -571,6 +571,7 @@ KEYWORD(align); KEYWORD(addrspace); KEYWORD(section); + KEYWORD(group); KEYWORD(partition); KEYWORD(alias); KEYWORD(ifunc); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -1185,6 +1185,11 @@ GV->setSection(Lex.getStrVal()); if (parseToken(lltok::StringConstant, "expected global section string")) return true; + } else if (Lex.getKind() == lltok::kw_group) { + Lex.Lex(); + GV->setGroup(Lex.getStrVal()); + if (parseToken(lltok::StringConstant, "expected section group string")) + return true; } else if (Lex.getKind() == lltok::kw_partition) { Lex.Lex(); GV->setPartition(Lex.getStrVal()); @@ -5713,6 +5718,7 @@ std::vector FwdRefAttrGrps; LocTy BuiltinLoc; std::string Section; + std::string Group; std::string Partition; MaybeAlign Alignment; std::string GC; @@ -5729,6 +5735,7 @@ parseFnAttributeValuePairs(FuncAttrs, FwdRefAttrGrps, false, BuiltinLoc) || (EatIfPresent(lltok::kw_section) && parseStringConstant(Section)) || + (EatIfPresent(lltok::kw_group) && parseStringConstant(Group)) || (EatIfPresent(lltok::kw_partition) && parseStringConstant(Partition)) || parseOptionalComdat(FunctionName, C) || parseOptionalAlignment(Alignment) || @@ -5833,6 +5840,7 @@ Fn->setUnnamedAddr(UnnamedAddr); Fn->setAlignment(MaybeAlign(Alignment)); Fn->setSection(Section); + Fn->setGroup(Group); Fn->setPartition(Partition); Fn->setComdat(C); Fn->setPersonalityFn(PersonalityFn); Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -115,6 +115,7 @@ kw_align, kw_addrspace, kw_section, + kw_group, kw_partition, kw_alias, kw_ifunc, Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -3262,6 +3262,10 @@ if (Record.size() > 15) NewGV->setPartition(StringRef(Strtab.data() + Record[14], Record[15])); + // Check whether we have enough values to read a section group name. + if (Record.size() > 17) + NewGV->setGroup(StringRef(Strtab.data() + Record[16], Record[17])); + return Error::success(); } @@ -3383,6 +3387,10 @@ if (Record.size() > 18) Func->setPartition(StringRef(Strtab.data() + Record[17], Record[18])); + // Check whether we have enough values to read a section group name. + if (Record.size() > 20) + Func->setGroup(StringRef(Strtab.data() + Record[19], Record[20])); + Type *FullTy = PointerType::get(FullFTy, AddrSpace); assert(Func->getType() == flattenPointerTypes(FullTy) && "Incorrect fully specified type provided for Function"); Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1327,7 +1327,8 @@ GV.hasComdat() || GV.hasAttributes() || GV.isDSOLocal() || - GV.hasPartition()) { + GV.hasPartition() || + GV.hasGroup()) { Vals.push_back(getEncodedVisibility(GV)); Vals.push_back(getEncodedThreadLocalMode(GV)); Vals.push_back(getEncodedUnnamedAddr(GV)); @@ -1341,6 +1342,8 @@ Vals.push_back(GV.isDSOLocal()); Vals.push_back(addToStrtab(GV.getPartition())); Vals.push_back(GV.getPartition().size()); + Vals.push_back(addToStrtab(GV.getGroup())); + Vals.push_back(GV.getGroup().size()); } else { AbbrevToUse = SimpleGVarAbbrev; } Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1831,7 +1831,7 @@ OutStreamer->SwitchSection( OutContext.getELFSection(".llvm_sympart", ELF::SHT_LLVM_SYMPART, 0, 0, - "", ++UniqueID, nullptr)); + "", false, ++UniqueID, nullptr)); OutStreamer->emitBytes(GV.getPartition()); OutStreamer->emitZeros(1); OutStreamer->emitValue( @@ -3378,13 +3378,13 @@ GroupName = F.getComdat()->getName(); } InstMap = OutContext.getELFSection("xray_instr_map", ELF::SHT_PROGBITS, - Flags, 0, GroupName, + Flags, 0, GroupName, F.hasComdat(), MCSection::NonUniqueID, LinkedToSym); if (!TM.Options.XRayOmitFunctionIndex) FnSledIndex = OutContext.getELFSection( "xray_fn_idx", ELF::SHT_PROGBITS, Flags | ELF::SHF_WRITE, 0, - GroupName, MCSection::NonUniqueID, LinkedToSym); + GroupName, F.hasComdat(), MCSection::NonUniqueID, LinkedToSym); } else if (MF->getSubtarget().getTargetTriple().isOSBinFormatMachO()) { InstMap = OutContext.getMachOSection("__DATA", "xray_instr_map", 0, SectionKind::getReadOnlyWithRel()); @@ -3480,7 +3480,7 @@ } OutStreamer->SwitchSection(OutContext.getELFSection( "__patchable_function_entries", ELF::SHT_PROGBITS, Flags, 0, GroupName, - MCSection::NonUniqueID, LinkedToSym)); + F.hasComdat(), MCSection::NonUniqueID, LinkedToSym)); emitAlignment(Align(PointerSize)); OutStreamer->emitSymbolValue(CurrentPatchableFunctionEntrySym, PointerSize); } Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -669,9 +669,14 @@ Kind = getELFKindForNamedSection(SectionName, Kind); StringRef Group = ""; + bool IsComdat = false; unsigned Flags = getELFSectionFlags(Kind); - if (const Comdat *C = getELFComdat(GO)) { + if (GO->hasGroup()) { + Group = GO->getGroup(); + Flags |= ELF::SHF_GROUP; + } else if (const Comdat *C = getELFComdat(GO)) { Group = C->getName(); + IsComdat = true; Flags |= ELF::SHF_GROUP; } @@ -730,8 +735,8 @@ } MCSectionELF *Section = getContext().getELFSection( - SectionName, getELFSectionType(SectionName, Kind), Flags, - EntrySize, Group, UniqueID, LinkedToSym); + SectionName, getELFSectionType(SectionName, Kind), Flags, EntrySize, + Group, IsComdat, UniqueID, LinkedToSym); // 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->getLinkedToSymbol() == LinkedToSym && @@ -763,9 +768,14 @@ unsigned *NextUniqueID, const MCSymbolELF *AssociatedSymbol) { StringRef Group = ""; - if (const Comdat *C = getELFComdat(GO)) { + bool IsComdat = false; + if (GO->hasGroup()) { + Group = GO->getGroup(); + Flags |= ELF::SHF_GROUP; + } else if (const Comdat *C = getELFComdat(GO)) { Flags |= ELF::SHF_GROUP; Group = C->getName(); + IsComdat = true; } // Get the section entry size based on the kind. @@ -788,7 +798,8 @@ if (Kind.isExecuteOnly()) UniqueID = 0; return Ctx.getELFSection(Name, getELFSectionType(Name, Kind), Flags, - EntrySize, Group, UniqueID, AssociatedSymbol); + EntrySize, Group, IsComdat, UniqueID, + AssociatedSymbol); } MCSection *TargetLoweringObjectFileELF::SelectSectionForGlobal( @@ -804,6 +815,7 @@ else EmitUniqueSection = TM.getDataSections(); } + EmitUniqueSection |= GO->hasGroup(); EmitUniqueSection |= GO->hasComdat(); const MCSymbolELF *LinkedToSym = getLinkedToSymbol(GO, TM); @@ -844,18 +856,23 @@ const auto *LSDA = cast(LSDASection); unsigned Flags = LSDA->getFlags(); - StringRef Group; - if (F.hasComdat()) { + StringRef Group = ""; + bool IsComdat = false; + if (F.hasGroup()) { + Group = F.getGroup(); + Flags |= ELF::SHF_GROUP; + } else if (F.hasComdat()) { Group = F.getComdat()->getName(); Flags |= ELF::SHF_GROUP; + IsComdat = true; } // Append the function name as the suffix like GCC, assuming // -funique-section-names applies to .gcc_except_table sections. if (TM.getUniqueSectionNames()) - return getContext().getELFSection(LSDA->getName() + "." + F.getName(), - LSDA->getType(), Flags, 0, Group, - MCSection::NonUniqueID, nullptr); + return getContext().getELFSection( + LSDA->getName() + "." + F.getName(), LSDA->getType(), Flags, 0, Group, + IsComdat, MCSection::NonUniqueID, nullptr); // Allocate a unique ID if function sections && (integrated assembler or GNU // as>=2.35). Note we could use SHF_LINK_ORDER to facilitate --gc-sections but @@ -868,7 +885,7 @@ ? NextUniqueID++ : MCSection::NonUniqueID; return getContext().getELFSection(LSDA->getName(), LSDA->getType(), Flags, 0, - Group, ID, nullptr); + Group, F.hasComdat(), ID, nullptr); } bool TargetLoweringObjectFileELF::shouldPutJumpTableInFunctionSection( @@ -934,8 +951,8 @@ GroupName = F.getComdat()->getName().str(); } return getContext().getELFSection(Name, ELF::SHT_PROGBITS, Flags, - 0 /* Entry Size */, GroupName, UniqueID, - nullptr); + 0 /* Entry Size */, GroupName, + F.hasComdat(), UniqueID, nullptr); } static MCSectionELF *getStaticStructorSection(MCContext &Ctx, bool UseInitArray, Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -3557,6 +3557,11 @@ printEscapedString(GV->getPartition(), Out); Out << '"'; } + if (GV->hasGroup()) { + Out << ", group \""; + printEscapedString(GV->getGroup(), Out); + Out << '"'; + } maybePrintComdat(Out, *GV); if (GV->getAlignment()) Index: llvm/lib/IR/Globals.cpp =================================================================== --- llvm/lib/IR/Globals.cpp +++ llvm/lib/IR/Globals.cpp @@ -225,6 +225,27 @@ setGlobalObjectFlag(HasSectionHashEntryBit, !S.empty()); } +StringRef GlobalObject::getGroupImpl() const { + assert(hasGroup()); + return getContext().pImpl->GlobalObjectGroups[this]; +} + +void GlobalObject::setGroup(StringRef G) { + // Do nothing if we're clearing the group and it is already empty. + if (!hasGroup() && G.empty()) + return; + + // Get or create a stable group name string and put it in the table in the + // context. + if (!G.empty()) + G = getContext().pImpl->Saver.save(G); + getContext().pImpl->GlobalObjectGroups[this] = G; + + // Update the HasGroupHashEntryBit. Setting the group to the empty string + // means this global no longer has a group. + setGlobalObjectFlag(HasGroupHashEntryBit, !G.empty()); +} + bool GlobalValue::isDeclaration() const { // Globals are definitions if they have an initializer. if (const GlobalVariable *GV = dyn_cast(this)) Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -1453,6 +1453,9 @@ /// Collection of per-GlobalObject sections used in this context. DenseMap GlobalObjectSections; + /// Collection of per-GlobalObject groups used in this context. + DenseMap GlobalObjectGroups; + /// Collection of per-GlobalValue partitions used in this context. DenseMap GlobalValuePartitions; Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -584,9 +584,13 @@ Assert(!GV.isDeclaration() || GV.hasValidDeclarationLinkage(), "Global is external, but doesn't have external or weak linkage!", &GV); - if (const GlobalObject *GO = dyn_cast(&GV)) + if (const GlobalObject *GO = dyn_cast(&GV)) { + Assert(!(GO->hasGroup() && GO->hasComdat()), + "cannot have both a group and be in a comdat!", GO); + Assert(GO->getAlignment() <= Value::MaximumAlignment, "huge alignment values are unsupported", GO); + } Assert(!GV.hasAppendingLinkage() || isa(GV), "Only global variables can have appending linkage!", &GV); Index: llvm/lib/MC/ELFObjectWriter.cpp =================================================================== --- llvm/lib/MC/ELFObjectWriter.cpp +++ llvm/lib/MC/ELFObjectWriter.cpp @@ -1114,7 +1114,8 @@ Asm.registerSymbol(*SignatureSymbol); unsigned &GroupIdx = RevGroupMap[SignatureSymbol]; if (!GroupIdx) { - MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol); + MCSectionELF *Group = + Ctx.createELFGroupSection(SignatureSymbol, Section.isComdat()); GroupIdx = addToSectionTable(Group); Group->setAlignment(Align(4)); Groups.push_back(Group); @@ -1151,7 +1152,7 @@ const MCSymbol *SignatureSymbol = Group->getGroup(); assert(SignatureSymbol); - write(uint32_t(ELF::GRP_COMDAT)); + write(uint32_t(Group->isComdat() ? ELF::GRP_COMDAT : 0)); for (const MCSectionELF *Member : GroupMembers[SignatureSymbol]) { uint32_t SecIndex = SectionIndexMap.lookup(Member); write(SecIndex); Index: llvm/lib/MC/MCContext.cpp =================================================================== --- llvm/lib/MC/MCContext.cpp +++ llvm/lib/MC/MCContext.cpp @@ -419,7 +419,7 @@ unsigned Flags, SectionKind K, unsigned EntrySize, const MCSymbolELF *Group, - unsigned UniqueID, + bool Comdat, unsigned UniqueID, const MCSymbolELF *LinkedToSym) { MCSymbolELF *R; MCSymbol *&Sym = Symbols[Section]; @@ -439,8 +439,9 @@ R->setBinding(ELF::STB_LOCAL); R->setType(ELF::STT_SECTION); - auto *Ret = new (ELFAllocator.Allocate()) MCSectionELF( - Section, Type, Flags, K, EntrySize, Group, UniqueID, R, LinkedToSym); + auto *Ret = new (ELFAllocator.Allocate()) + MCSectionELF(Section, Type, Flags, K, EntrySize, Group, Comdat, UniqueID, + R, LinkedToSym); auto *F = new MCDataFragment(); Ret->getFragmentList().insert(Ret->begin(), F); @@ -461,7 +462,7 @@ return createELFSectionImpl( I->getKey(), Type, Flags, SectionKind::getReadOnly(), EntrySize, Group, - true, cast(RelInfoSection->getBeginSymbol())); + true, true, cast(RelInfoSection->getBeginSymbol())); } MCSectionELF *MCContext::getELFNamedSection(const Twine &Prefix, @@ -473,20 +474,21 @@ MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, - const Twine &Group, unsigned UniqueID, + const Twine &Group, bool IsComdat, + unsigned UniqueID, const MCSymbolELF *LinkedToSym) { MCSymbolELF *GroupSym = nullptr; if (!Group.isTriviallyEmpty() && !Group.str().empty()) GroupSym = cast(getOrCreateSymbol(Group)); - return getELFSection(Section, Type, Flags, EntrySize, GroupSym, UniqueID, - LinkedToSym); + return getELFSection(Section, Type, Flags, EntrySize, GroupSym, IsComdat, + UniqueID, LinkedToSym); } MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type, unsigned Flags, unsigned EntrySize, const MCSymbolELF *GroupSym, - unsigned UniqueID, + bool IsComdat, unsigned UniqueID, const MCSymbolELF *LinkedToSym) { StringRef Group = ""; if (GroupSym) @@ -513,7 +515,7 @@ MCSectionELF *Result = createELFSectionImpl(CachedName, Type, Flags, Kind, EntrySize, GroupSym, - UniqueID, LinkedToSym); + IsComdat, UniqueID, LinkedToSym); Entry.second = Result; recordELFMergeableSectionInfo(Result->getName(), Result->getFlags(), @@ -522,9 +524,10 @@ return Result; } -MCSectionELF *MCContext::createELFGroupSection(const MCSymbolELF *Group) { +MCSectionELF *MCContext::createELFGroupSection(const MCSymbolELF *Group, + bool IsComdat) { return createELFSectionImpl(".group", ELF::SHT_GROUP, 0, - SectionKind::getReadOnly(), 4, Group, + SectionKind::getReadOnly(), 4, Group, IsComdat, MCSection::NonUniqueID, nullptr); } Index: llvm/lib/MC/MCObjectFileInfo.cpp =================================================================== --- llvm/lib/MC/MCObjectFileInfo.cpp +++ llvm/lib/MC/MCObjectFileInfo.cpp @@ -1006,7 +1006,7 @@ } return Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, Flags, 0, - GroupName, ElfSec.getUniqueID(), + GroupName, true, ElfSec.getUniqueID(), cast(TextSec.getBeginSymbol())); } @@ -1026,7 +1026,7 @@ // Use the text section's begin symbol and unique ID to create a separate // .llvm_bb_addr_map section associated with every unique text section. return Ctx->getELFSection(".llvm_bb_addr_map", ELF::SHT_LLVM_BB_ADDR_MAP, - Flags, 0, GroupName, ElfSec.getUniqueID(), + Flags, 0, GroupName, true, ElfSec.getUniqueID(), cast(TextSec.getBeginSymbol())); } Index: llvm/lib/MC/MCParser/ELFAsmParser.cpp =================================================================== --- llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -157,7 +157,7 @@ unsigned parseSunStyleSectionFlags(); bool maybeParseSectionType(StringRef &TypeName); bool parseMergeSize(int64_t &Size); - bool parseGroup(StringRef &GroupName); + bool parseGroup(StringRef &GroupName, bool &IsComdat); bool parseLinkedToSym(MCSymbolELF *&LinkedToSym); bool maybeParseUniqueID(int64_t &UniqueID); }; @@ -421,7 +421,7 @@ return false; } -bool ELFAsmParser::parseGroup(StringRef &GroupName) { +bool ELFAsmParser::parseGroup(StringRef &GroupName, bool &IsComdat) { MCAsmLexer &L = getLexer(); if (L.isNot(AsmToken::Comma)) return TokError("expected group name"); @@ -439,6 +439,7 @@ return TokError("invalid linkage"); if (Linkage != "comdat") return TokError("Linkage must be 'comdat'"); + IsComdat = true; } return false; } @@ -499,6 +500,7 @@ StringRef TypeName; int64_t Size = 0; StringRef GroupName; + bool IsComdat = false; unsigned Flags = 0; unsigned extraFlags = 0; const MCExpr *Subsection = nullptr; @@ -571,7 +573,7 @@ if (parseMergeSize(Size)) return true; if (Group) - if (parseGroup(GroupName)) + if (parseGroup(GroupName, IsComdat)) return true; if (Flags & ELF::SHF_LINK_ORDER) if (parseLinkedToSym(LinkedToSym)) @@ -637,12 +639,14 @@ cast_or_null(CurrentSection.first)) if (const MCSymbol *Group = Section->getGroup()) { GroupName = Group->getName(); + IsComdat = Section->isComdat(); Flags |= ELF::SHF_GROUP; } } - MCSectionELF *Section = getContext().getELFSection( - SectionName, Type, Flags, Size, GroupName, UniqueID, LinkedToSym); + MCSectionELF *Section = + getContext().getELFSection(SectionName, Type, Flags, Size, GroupName, + IsComdat, UniqueID, LinkedToSym); getStreamer().SwitchSection(Section, Subsection); // x86-64 psABI names SHT_X86_64_UNWIND as the canonical type for .eh_frame, // but GNU as emits SHT_PROGBITS .eh_frame for .cfi_* directives. Don't error Index: llvm/lib/MC/MCSectionELF.cpp =================================================================== --- llvm/lib/MC/MCSectionELF.cpp +++ llvm/lib/MC/MCSectionELF.cpp @@ -169,8 +169,9 @@ if (Flags & ELF::SHF_GROUP) { OS << ","; - printName(OS, Group->getName()); - OS << ",comdat"; + printName(OS, Group.getPointer()->getName()); + if (isComdat()) + OS << ",comdat"; } if (Flags & ELF::SHF_LINK_ORDER) { Index: llvm/lib/Target/ARM/ARMTargetObjectFile.cpp =================================================================== --- llvm/lib/Target/ARM/ARMTargetObjectFile.cpp +++ llvm/lib/Target/ARM/ARMTargetObjectFile.cpp @@ -49,7 +49,8 @@ // Since we cannot modify flags for an existing section, we create a new // section with the right flags, and use 0 as the unique ID for // execute-only text - TextSection = Ctx.getELFSection(".text", Type, Flags, 0, "", 0U, nullptr); + TextSection = + Ctx.getELFSection(".text", Type, Flags, 0, "", false, 0U, nullptr); } } Index: llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp =================================================================== --- llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp +++ llvm/lib/Target/ARM/MCTargetDesc/ARMELFStreamer.cpp @@ -1203,7 +1203,7 @@ if (Group) Flags |= ELF::SHF_GROUP; MCSectionELF *EHSection = getContext().getELFSection( - EHSecName, Type, Flags, 0, Group, FnSection.getUniqueID(), + EHSecName, Type, Flags, 0, Group, false, FnSection.getUniqueID(), static_cast(FnSection.getBeginSymbol())); assert(EHSection && "Failed to get the required EH section"); Index: llvm/test/Bitcode/compatibility.ll =================================================================== --- llvm/test/Bitcode/compatibility.ll +++ llvm/test/Bitcode/compatibility.ll @@ -160,6 +160,10 @@ @g.section = global i32 0, section "_DATA" ; CHECK: @g.section = global i32 0, section "_DATA" +; Global Variables -- group +@g.group = global i32 0, group "group" +; CHECK: @g.group = global i32 0, group "group" + ; Global Variables -- partition @g.partition = global i32 0, partition "part" ; CHECK: @g.partition = global i32 0, partition "part" Index: llvm/test/CodeGen/X86/group.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/group.ll @@ -0,0 +1,18 @@ +; RUN: llc < %s -mtriple=x86_64-unknown-linux | FileCheck %s + +; CHECK: .section .text.f1,"axG",@progbits,group1 +; CHECK: .section .text.f2,"axG",@progbits,group2 +; CHECK-NOT: .section .text.f3,"axG",@progbits,group3 +; CHECK: .section .bss.g1,"aGw",@nobits,group4 + +define void @f1() group "group1" { + unreachable +} + +define hidden void @f2() group "group2" { + unreachable +} + +declare void @f3() group "group3" + +@g1 = global i32 0, group "group4"