[ELF] Add section group/COMDAT support.
authorShankar Easwaran <shankare@codeaurora.org>
Mon, 23 Feb 2015 00:30:00 +0000 (00:30 +0000)
committerShankar Easwaran <shankare@codeaurora.org>
Mon, 23 Feb 2015 00:30:00 +0000 (00:30 +0000)
SHF_GROUP: Group Member Sections
----------------------------------
A section which is part of a group, and is to be retained or discarded with the
group as a whole, is identified by a new section header attribute: SHF_GROUP
This section is a member (perhaps the only one) of a group of sections, and the
linker should retain or discard all or none of the members. This section must be
referenced in a SHT_GROUP section. This attribute flag may be set in any section
header, and no other modification or indication is made in the grouped sections.
All additional information is contained in the associated SHT_GROUP section.

SHT_GROUP: Section Group Definition
-------------------------------------
Represents a group section.

The section group's sh_link field identifies a symbol table section, and its
sh_info field the index of a symbol in that section. The name of that symbol is
treated as the identifier of the section group.

More information: https://mentorembedded.github.io/cxx-abi/abi/prop-72-comdat.html

Added a lot of extensive tests, that tests functionality.

llvm-svn: 230195

15 files changed:
lld/lib/ReaderWriter/ELF/Atoms.h
lld/lib/ReaderWriter/ELF/DefaultLayout.h
lld/lib/ReaderWriter/ELF/ELFFile.h
lld/lib/ReaderWriter/ELF/Hexagon/HexagonSectionChunks.h
lld/lib/ReaderWriter/ELF/Layout.h
lld/lib/ReaderWriter/ELF/Mips/MipsSectionChunks.h
lld/lib/ReaderWriter/ELF/OutputELFWriter.h
lld/lib/ReaderWriter/ELF/SectionChunks.h
lld/test/elf/sectionGroups/sectiongroup-new-members.test [new file with mode: 0644]
lld/test/elf/sectionGroups/sectiongroup-simple.test [new file with mode: 0644]
lld/test/elf/sectionGroups/sectiongroup-undef-member-other.test [new file with mode: 0644]
lld/test/elf/sectionGroups/sectiongroup-undef-member.test [new file with mode: 0644]
lld/test/elf/sectionGroups/sectiongroup-with-globalsymbols.test [new file with mode: 0644]
lld/test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test [new file with mode: 0644]
lld/test/elf/sectionGroups/sectiongroup-with-undef-signature.test [new file with mode: 0644]

index b80c469..929ca22 100644 (file)
@@ -221,6 +221,9 @@ public:
     ContentType ret = typeUnknown;
     uint64_t flags = _section->sh_flags;
 
+    if (_section->sh_type == llvm::ELF::SHT_GROUP)
+      return typeGroupComdat;
+
     if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
       return typeGnuLinkOnce;
 
index 59259c7..32a4825 100644 (file)
@@ -196,7 +196,7 @@ public:
   static bool hasOutputSegment(Section<ELFT> *section);
 
   // Adds an atom to the section
-  ErrorOr<const lld::AtomLayout &> addAtom(const Atom *atom) override;
+  ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) override;
 
   /// \brief Find an output Section given a section name.
   OutputSection<ELFT> *findOutputSection(StringRef name) {
@@ -553,7 +553,8 @@ DefaultLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType,
 }
 
 template <class ELFT>
-ErrorOr<const lld::AtomLayout &> DefaultLayout<ELFT>::addAtom(const Atom *atom) {
+ErrorOr<const lld::AtomLayout *>
+DefaultLayout<ELFT>::addAtom(const Atom *atom) {
   if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) {
     // HACK: Ignore undefined atoms. We need to adjust the interface so that
     // undefined atoms can still be included in the output symbol table for
@@ -600,7 +601,7 @@ ErrorOr<const lld::AtomLayout &> DefaultLayout<ELFT>::addAtom(const Atom *atom)
     // link
     _absoluteAtoms.push_back(new (_allocator)
         lld::AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
-    return *_absoluteAtoms.back();
+    return _absoluteAtoms.back();
   } else {
     llvm_unreachable("Only absolute / defined atoms can be added here");
   }
index 6d1ac49..606f6df 100644 (file)
@@ -50,6 +50,7 @@ template <class ELFT> class ELFFile : public File {
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Iter Elf_Sym_Iter;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela_Iter Elf_Rela_Iter;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel_Iter Elf_Rel_Iter;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
 
   // A Map is used to hold the atoms that have been divided up
   // after reading the section that contains Merge String attributes
@@ -171,6 +172,7 @@ public:
   Atom *findAtom(const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) {
     // All references to atoms inside a group are through undefined atoms.
     Atom *targetAtom = _symbolToAtomMapping.lookup(targetSymbol);
+    StringRef targetSymbolName = targetAtom->name();
     if (targetAtom->definition() != Atom::definitionRegular)
       return targetAtom;
     if ((llvm::dyn_cast<DefinedAtom>(targetAtom))->scope() ==
@@ -178,13 +180,13 @@ public:
       return targetAtom;
     if (!redirectReferenceUsingUndefAtom(sourceSymbol, targetSymbol))
       return targetAtom;
-    auto undefForGroupchild = _undefAtomsForgroupChild.find(targetAtom->name());
+    auto undefForGroupchild = _undefAtomsForgroupChild.find(targetSymbolName);
     if (undefForGroupchild != _undefAtomsForgroupChild.end())
       return undefForGroupchild->getValue();
     auto undefGroupChildAtom =
-        new (_readerStorage) SimpleUndefinedAtom(*this, targetAtom->name());
+        new (_readerStorage) SimpleUndefinedAtom(*this, targetSymbolName);
     _undefinedAtoms._atoms.push_back(undefGroupChildAtom);
-    return (_undefAtomsForgroupChild[targetAtom->name()] = undefGroupChildAtom);
+    return (_undefAtomsForgroupChild[targetSymbolName] = undefGroupChildAtom);
   }
 
 protected:
@@ -279,6 +281,13 @@ protected:
       llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
       const Elf_Shdr *shdr);
 
+  // Handle Section groups/COMDAT scetions.
+  std::error_code handleSectionGroup(
+      StringRef signature, StringRef groupSectionName,
+      llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+      llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
+      const Elf_Shdr *shdr);
+
   /// Process the Undefined symbol and create an atom for it.
   ErrorOr<ELFUndefinedAtom<ELFT> *>
   handleUndefinedSymbol(StringRef symName, const Elf_Sym *sym) {
@@ -312,6 +321,16 @@ protected:
     return sectionName.startswith(".gnu.linkonce");
   }
 
+  /// Returns true if the section is a COMDAT group section.
+  bool isGroupSection(const Elf_Shdr *shdr) const {
+    return (shdr->sh_type == llvm::ELF::SHT_GROUP);
+  }
+
+  /// Returns true if the section is a member of some group.
+  bool isSectionMemberOfGroup(const Elf_Shdr *shdr) const {
+    return (shdr->sh_flags & llvm::ELF::SHF_GROUP);
+  }
+
   /// Returns correct st_value for the symbol depending on the architecture.
   /// For most architectures it's just a regular st_value with no changes.
   virtual uint64_t getSymbolValue(const Elf_Sym *symbol) const {
@@ -661,8 +680,12 @@ template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() {
   // Holds all the atoms that are part of the section. They are the targets of
   // the kindGroupChild reference.
   llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> atomsForSection;
-  // group sections have a mapping of the section header to the signature.
-  llvm::DenseMap<const Elf_Shdr *, StringRef> groupSections;
+  // group sections have a mapping of the section header to the
+  // signature/section.
+  llvm::DenseMap<const Elf_Shdr *, std::pair<StringRef, StringRef>>
+      groupSections;
+  // Contains a list of comdat sections for a group.
+  llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> comdatSections;
   for (auto &i : _sectionSymbols) {
     const Elf_Shdr *section = i.first;
     std::vector<Elf_Sym_Iter> &symbols = i.second;
@@ -683,11 +706,49 @@ template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() {
 
     bool addAtoms = true;
 
+    // A section of type SHT_GROUP defines a grouping of sections. The name of a
+    // symbol from one of the containing object's symbol tables provides a
+    // signature
+    // for the section group. The section header of the SHT_GROUP section
+    // specifies
+    // the identifying symbol entry, as described : the sh_link member contains
+    // the section header index of the symbol table section that contains the
+    // entry.
+    // The sh_info member contains the symbol table index of the identifying
+    // entry.
+    // The sh_flags member of the section header contains 0. The name of the
+    // section
+    // (sh_name) is not specified.
+    if (isGroupSection(section)) {
+      const Elf_Word *groupMembers =
+          reinterpret_cast<const Elf_Word *>(sectionContents->data());
+      const long count = (section->sh_size) / sizeof(Elf_Word);
+      for (int i = 1; i < count; i++) {
+        const Elf_Shdr *sHdr = _objFile->getSection(groupMembers[i]);
+        ErrorOr<StringRef> sectionName = _objFile->getSectionName(sHdr);
+        if (std::error_code ec = sectionName.getError())
+          return ec;
+        comdatSections[section].push_back(*sectionName);
+      }
+      const Elf_Sym *symbol = _objFile->getSymbol(section->sh_info);
+      const Elf_Shdr *symtab = _objFile->getSection(section->sh_link);
+      ErrorOr<StringRef> symbolName = _objFile->getSymbolName(symtab, symbol);
+      if (std::error_code ec = symbolName.getError())
+        return ec;
+      groupSections.insert(
+          std::make_pair(section, std::make_pair(*symbolName, *sectionName)));
+      continue;
+    }
+
     if (isGnuLinkOnceSection(*sectionName)) {
-      groupSections.insert(std::make_pair(section, *sectionName));
+      groupSections.insert(
+          std::make_pair(section, std::make_pair(*sectionName, *sectionName)));
       addAtoms = false;
     }
 
+    if (isSectionMemberOfGroup(section))
+      addAtoms = false;
+
     if (handleSectionWithNoSymbols(section, symbols)) {
       ELFDefinedAtom<ELFT> *newAtom =
           createSectionAtom(section, *sectionName, *sectionContents);
@@ -812,9 +873,13 @@ template <class ELFT> std::error_code ELFFile<ELFT>::createAtoms() {
   // Iterate over all the group sections to create parent atoms pointing to
   // group-child atoms.
   for (auto &sect : groupSections) {
-    StringRef signature = sect.second;
+    StringRef signature = sect.second.first;
+    StringRef groupSectionName = sect.second.second;
     if (isGnuLinkOnceSection(signature))
       handleGnuLinkOnceSection(signature, atomsForSection, sect.first);
+    else if (isGroupSection(sect.first))
+      handleSectionGroup(signature, groupSectionName, atomsForSection,
+                         comdatSections, sect.first);
   }
 
   updateReferences();
@@ -847,6 +912,36 @@ std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection(
   return std::error_code();
 }
 
+template <class ELFT>
+std::error_code ELFFile<ELFT>::handleSectionGroup(
+    StringRef signature, StringRef groupSectionName,
+    llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+    llvm::DenseMap<const Elf_Shdr *, std::vector<StringRef>> &comdatSections,
+    const Elf_Shdr *shdr) {
+  unsigned int referenceStart = _references.size();
+  std::vector<ELFReference<ELFT> *> refs;
+  auto sectionNamesInGroup = comdatSections[shdr];
+  for (auto sectionName : sectionNamesInGroup) {
+    for (auto ha : atomsForSection[sectionName]) {
+      _groupChild[ha->symbol()] = std::make_pair(signature, shdr);
+      ELFReference<ELFT> *ref = new (_readerStorage)
+          ELFReference<ELFT>(lld::Reference::kindGroupChild);
+      ref->setTarget(ha);
+      refs.push_back(ref);
+    }
+    atomsForSection[sectionName].clear();
+  }
+  // Create a gnu linkonce atom.
+  auto sectionGroupAtom = handleDefinedSymbol(
+      signature, groupSectionName, nullptr, shdr, ArrayRef<uint8_t>(),
+      referenceStart, _references.size(), _references);
+  (*sectionGroupAtom)->setOrdinal(++_ordinal);
+  _definedAtoms._atoms.push_back(*sectionGroupAtom);
+  for (auto reference : refs)
+    (*sectionGroupAtom)->addReference(reference);
+  return std::error_code();
+}
+
 template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() {
   if (!_useWrap)
     return std::error_code();
@@ -1052,18 +1147,27 @@ void ELFFile<ELFT>::createEdge(ELFDefinedAtom<ELFT> *from,
 template <class ELFT>
 bool ELFFile<ELFT>::redirectReferenceUsingUndefAtom(
     const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) const {
-  auto groupChild = _groupChild.find(targetSymbol);
+  auto groupChildTarget = _groupChild.find(targetSymbol);
 
   // If the reference is not to a group child atom, there is no need to redirect
-  // using a undefined atom.
-  if (groupChild == _groupChild.end())
+  // using a undefined atom. Its also not needed if the source and target are
+  // from the same section.
+  if ((groupChildTarget == _groupChild.end()) ||
+      (sourceSymbol->st_shndx == targetSymbol->st_shndx))
     return false;
 
-  if (sourceSymbol->st_shndx != targetSymbol->st_shndx) {
+  auto groupChildSource = _groupChild.find(sourceSymbol);
+
+  // If the source symbol is not in a group, use a undefined symbol too.
+  if (groupChildSource == _groupChild.end())
     return true;
-  }
 
-  return false;
+  // If the source and child are from the same group, we dont need the
+  // relocation to go through a undefined symbol.
+  if (groupChildSource->second.second == groupChildTarget->second.second)
+    return false;
+
+  return true;
 }
 
 } // end namespace elf
index a276a72..5b3fbbb 100644 (file)
@@ -35,7 +35,7 @@ public:
   /// \brief Does this section have an output segment.
   virtual bool hasOutputSegment() { return true; }
 
-  const lld::AtomLayout &appendAtom(const Atom *atom) {
+  const lld::AtomLayout *appendAtom(const Atom *atom) {
     const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
     DefinedAtom::Alignment atomAlign = definedAtom->alignment();
     uint64_t alignment = 1u << atomAlign.powerOf2;
@@ -44,7 +44,7 @@ public:
     // std::max doesn't support uint64_t
     if (this->_alignment < alignment)
       this->_alignment = alignment;
-    return *(this->_atoms.back());
+    return (this->_atoms.back());
   }
 
 }; // SDataSection
index bbb43ef..826cf50 100644 (file)
@@ -40,7 +40,7 @@ public:
   /// \brief Append the Atom to the layout and create appropriate sections.
   /// \returns A reference to the atom layout or an error. The atom layout will
   /// be updated as linking progresses.
-  virtual ErrorOr<const lld::AtomLayout &> addAtom(const Atom *atom) = 0;
+  virtual ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) = 0;
   /// find the Atom in the current layout
   virtual const AtomLayout *findAtomLayoutByName(StringRef name) const = 0;
   /// associates a section to a segment
index 43ba958..3d1c262 100644 (file)
@@ -49,7 +49,7 @@ public:
     return ia == _posMap.end() && ib != _posMap.end();
   }
 
-  const lld::AtomLayout &appendAtom(const Atom *atom) override {
+  const lld::AtomLayout *appendAtom(const Atom *atom) override {
     const DefinedAtom *da = dyn_cast<DefinedAtom>(atom);
 
     for (const auto &r : *da) {
@@ -105,8 +105,8 @@ public:
     return it != _pltLayoutMap.end() ? it->second : nullptr;
   }
 
-  const lld::AtomLayout &appendAtom(const Atom *atom) override {
-    const auto &layout = AtomSection<ELFType>::appendAtom(atom);
+  const lld::AtomLayout *appendAtom(const Atom *atom) override {
+    const auto *layout = AtomSection<ELFType>::appendAtom(atom);
 
     const DefinedAtom *da = cast<DefinedAtom>(atom);
 
@@ -115,7 +115,7 @@ public:
         continue;
       assert(r->kindArch() == Reference::KindArch::Mips);
       if (r->kindValue() == LLD_R_MIPS_STO_PLT) {
-        _pltLayoutMap[r->target()] = &layout;
+        _pltLayoutMap[r->target()] = layout;
         break;
       }
     }
index a857caa..caa5112 100644 (file)
@@ -162,6 +162,13 @@ template <class ELFT>
 void OutputELFWriter<ELFT>::buildChunks(const File &file) {
   ScopedTask task(getDefaultDomain(), "buildChunks");
   for (const DefinedAtom *definedAtom : file.defined()) {
+    DefinedAtom::ContentType contentType = definedAtom->contentType();
+    // Dont add COMDAT group atoms and GNU linkonce atoms, as they are used for
+    // symbol resolution.
+    // TODO: handle partial linking.
+    if (contentType == DefinedAtom::typeGroupComdat ||
+        contentType == DefinedAtom::typeGnuLinkOnce)
+      continue;
     _layout.addAtom(definedAtom);
   }
   for (const AbsoluteAtom *absoluteAtom : file.absolute())
index e7d8587..a9e9cb7 100644 (file)
@@ -218,7 +218,7 @@ public:
   // \brief Append an atom to a Section. The atom gets pushed into a vector
   // contains the atom, the atom file offset, the atom virtual address
   // the atom file offset is aligned appropriately as set by the Reader
-  virtual const lld::AtomLayout &appendAtom(const Atom *atom);
+  virtual const lld::AtomLayout *appendAtom(const Atom *atom);
 
   /// \brief Set the virtual address of each Atom in the Section. This
   /// routine gets called after the linker fixes up the virtual address
@@ -318,7 +318,7 @@ uint64_t AtomSection<ELFT>::alignOffset(uint64_t offset,
 // contains the atom, the atom file offset, the atom virtual address
 // the atom file offset is aligned appropriately as set by the Reader
 template <class ELFT>
-const lld::AtomLayout &AtomSection<ELFT>::appendAtom(const Atom *atom) {
+const lld::AtomLayout *AtomSection<ELFT>::appendAtom(const Atom *atom) {
   const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
 
   DefinedAtom::Alignment atomAlign = definedAtom->alignment();
@@ -361,9 +361,6 @@ const lld::AtomLayout &AtomSection<ELFT>::appendAtom(const Atom *atom) {
     _atoms.push_back(new (_alloc) lld::AtomLayout(atom, mOffset, 0));
     this->_msize = mOffset + definedAtom->size();
     break;
-  case DefinedAtom::typeGnuLinkOnce:
-    // Discard gnu linkonce atoms as they are just used to identify signature.
-    break;
   default:
     llvm::dbgs() << definedAtom->contentType() << "\n";
     llvm_unreachable("Uexpected content type.");
@@ -373,7 +370,9 @@ const lld::AtomLayout &AtomSection<ELFT>::appendAtom(const Atom *atom) {
   if (this->_alignment < alignment)
     this->_alignment = alignment;
 
-  return *_atoms.back();
+  if (_atoms.size())
+    return _atoms.back();
+  return nullptr;
 }
 
 /// \brief convert the segment type to a String for diagnostics
diff --git a/lld/test/elf/sectionGroups/sectiongroup-new-members.test b/lld/test/elf/sectionGroups/sectiongroup-new-members.test
new file mode 100644 (file)
index 0000000..d270c5f
--- /dev/null
@@ -0,0 +1,153 @@
+# Checks that the linker picks the first group in the output file when the file
+# have some members dont appear in the first group.
+# 1a.s
+# ------
+#
+#    .section .text,"axG",%progbits,foo_group,comdat
+#    .weak foo
+#foo:
+#    .word 0
+# 1b.s
+# -----
+#    .section .text,"axG",%progbits,foo_group,comdat
+#    .global foo
+#    .global bar
+#foo:
+#    .word 0
+#bar:
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols  %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP:  - name:            foo
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    merge:           as-weak
+#CHECKGROUP:    section-name:    .text
+#CHECKGROUP:  - name:            foo_group
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    type:            group-comdat
+#CHECKGROUP:    section-choice:  custom-required
+#CHECKGROUP:    section-name:    .group
+#CHECKGROUP:    permissions:     ---
+#CHECKGROUP:    references:
+#CHECKGROUP:      - kind:            group-child
+#CHECKGROUP:        offset:          0
+#CHECKGROUP:        target:          foo
+#CHECKGROUPSECTIONS:  Section {
+#CHECKGROUPSECTIONS:    Name: .text
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [ (0x6)
+#CHECKGROUPSECTIONS:      SHF_ALLOC (0x2)
+#CHECKGROUPSECTIONS:      SHF_EXECINSTR (0x4)
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 2
+#CHECKGROUPSECTIONS:    AddressAlignment: 1
+#CHECKGROUPSECTIONS:  }
+#CHECKSYMBOLS:   Name: foo
+#CHECKSYMBOLS:   Type: Function
+#CHECKSYMBOLS:   Section: .text
+#CHECKSYMBOLS-NOT:   Name: bar
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            foo_group
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .text
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0000'
+Symbols:
+  Local:
+    - Name:            foo_group
+      Section:         .group
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+  Weak:
+    - Name:            foo
+      Section:         .text
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            foo_group
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .text
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0000'
+Symbols:
+  Local:
+    - Name:            foo_group
+      Section:         .group
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+  Global:
+    - Name:            bar
+      Section:         .text
+      Value:           0x0000000000000002
+    - Name:            foo
+      Section:         .text
+...
diff --git a/lld/test/elf/sectionGroups/sectiongroup-simple.test b/lld/test/elf/sectionGroups/sectiongroup-simple.test
new file mode 100644 (file)
index 0000000..25be603
--- /dev/null
@@ -0,0 +1,146 @@
+# Checks that the linker picks the first group in the output file when the file
+# have some members dont appear in the first group.
+# 1a.s
+# ------
+#    .section .text,"axG",%progbits,foo_group,comdat
+#    .weak foo
+#foo:
+#    .word 0
+# 1b.s
+# -----
+#    .section .text,"axG",%progbits,foo_group,comdat
+#    .global bar
+#bar:
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP:  - name:            foo
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    merge:           as-weak
+#CHECKGROUP:    section-name:    .text
+#CHECKGROUP:  - name:            foo_group
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    type:            group-comdat
+#CHECKGROUP:    section-choice:  custom-required
+#CHECKGROUP:    section-name:    .group
+#CHECKGROUP:    permissions:     ---
+#CHECKGROUP:    references:
+#CHECKGROUP:      - kind:            group-child
+#CHECKGROUP:        offset:          0
+#CHECKGROUP:        target:          foo
+#CHECKGROUPSECTIONS:  Section {
+#CHECKGROUPSECTIONS:    Name: .text
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [ (0x6)
+#CHECKGROUPSECTIONS:      SHF_ALLOC (0x2)
+#CHECKGROUPSECTIONS:      SHF_EXECINSTR (0x4)
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 2
+#CHECKGROUPSECTIONS:    AddressAlignment: 1
+#CHECKGROUPSECTIONS:  }
+#CHECKSYMBOLS:   Name: foo
+#CHECKSYMBOLS:   Type: Function
+#CHECKSYMBOLS:   Section: .text
+
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            foo_group
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .text
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0000'
+Symbols:
+  Local:
+    - Name:            foo_group
+      Section:         .group
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+  Weak:
+    - Name:            foo
+      Section:         .text
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            foo_group
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .text
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+Symbols:
+  Local:
+    - Name:            foo_group
+      Section:         .group
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+  Global:
+    - Name:            bar
+      Section:         .text
+...
diff --git a/lld/test/elf/sectionGroups/sectiongroup-undef-member-other.test b/lld/test/elf/sectionGroups/sectiongroup-undef-member-other.test
new file mode 100644 (file)
index 0000000..78a5f27
--- /dev/null
@@ -0,0 +1,158 @@
+# Tests that linker throws an error for an undefined symbol in the section
+# group, which is the same as the signature in the next input file.
+# comdat1.s
+# ------------
+# .section .foo,"axG",@progbits,g1,comdat
+# .word g1
+#comdat2.s
+#-----------
+#  .global g1
+#  .section .bar,"axG",@progbits,g1,comdat
+#g2:
+#   nop
+#  .section .car,"axG",@progbits,g1,comdat
+#g3:
+#   nop
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out 2>&1 | FileCheck %s
+#CHECK: Undefined symbol: {{.*}} g1
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+      - SectionOrType:   .rela.foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0000'
+  - Name:            .rela.foo
+    Type:            SHT_RELA
+    Flags:           [ SHF_GROUP ]
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .foo
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          g1
+        Type:            R_X86_64_16
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+    - Name:            .group
+      Type:            STT_SECTION
+      Section:         .group
+  Global:
+    - Name:            g1
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .bar
+      - SectionOrType:   .car
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bar
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '90'
+  - Name:            .car
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '90'
+Symbols:
+  Local:
+    - Name:            g2
+      Section:         .bar
+    - Name:            g3
+      Section:         .car
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .bar
+      Type:            STT_SECTION
+      Section:         .bar
+    - Name:            .car
+      Type:            STT_SECTION
+      Section:         .car
+    - Name:            .group
+      Type:            STT_SECTION
+      Section:         .group
+  Global:
+    - Name:            g1
+      Section:         .group
+...
diff --git a/lld/test/elf/sectionGroups/sectiongroup-undef-member.test b/lld/test/elf/sectionGroups/sectiongroup-undef-member.test
new file mode 100644 (file)
index 0000000..2f6804d
--- /dev/null
@@ -0,0 +1,144 @@
+# Tests that linker throws an error for an undefined symbol in the section
+# group.
+#
+#comdata.s
+#------------
+#  .section .foo,"axG",@progbits,g1,comdat
+#  .word g1
+#
+#comdatb.s
+#------------
+#  .global g1
+#  .section .foo,"axG",@progbits,g1,comdat
+#g1:
+#  nop
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.group1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.group1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.group1a.o %t.group1b.o \
+#RUN: --noinhibit-exec -o %t2.out 2>&1 | FileCheck %s
+#CHECK: Undefined symbol: {{.*}} g1
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+      - SectionOrType:   .rela.foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0000'
+  - Name:            .rela.foo
+    Type:            SHT_RELA
+    Flags:           [ SHF_GROUP ]
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .foo
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          g1
+        Type:            R_X86_64_16
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+    - Name:            .group
+      Type:            STT_SECTION
+      Section:         .group
+  Global:
+    - Name:            g1
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '90'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+    - Name:            .group
+      Type:            STT_SECTION
+      Section:         .group
+  Global:
+    - Name:            g1
+      Section:         .foo
+...
diff --git a/lld/test/elf/sectionGroups/sectiongroup-with-globalsymbols.test b/lld/test/elf/sectionGroups/sectiongroup-with-globalsymbols.test
new file mode 100644 (file)
index 0000000..0a28e3c
--- /dev/null
@@ -0,0 +1,253 @@
+# This tests that comdat weak symbol can be overridden by a global symbol.
+# comdat1.s
+#------------------------
+#      .weak g1
+#        .section .foo,"axG",@progbits,g1,comdat
+#g1:
+#        nop
+#        .global g2
+#g2:
+#        nop
+#!
+#
+#comdat2.s << \!
+#-----------------
+#      .global g1
+#        .section .foo,"axG",@progbits,g1,comdat
+#g1:
+#        nop
+#        .global g2
+#g2:
+#        nop
+#
+#cat > g1.c << \!
+#int g1() {
+#  return 0;
+#}
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.comdat1.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.comdat2.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.g1.o
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP:  - name:            g2
+#CHECKGROUP:    content:         [ 90 ]
+#CHECKGROUP:    section-choice:  custom-required
+#CHECKGROUP:    section-name:    .foo
+#CHECKGROUP:  - name:            g1
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    content:         [ 55, 48, 89, E5, 31, C0, 5D, C3 ]
+#CHECKGROUP:    alignment:       2^4
+#CHECKGROUP:    section-name:    .text
+#CHECKGROUPSECTIONS:    Name: .text
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [
+#CHECKGROUPSECTIONS:      SHF_ALLOC
+#CHECKGROUPSECTIONS:      SHF_EXECINSTR
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 8
+#CHECKGROUPSECTIONS:    Name: .foo
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [
+#CHECKGROUPSECTIONS:      SHF_ALLOC
+#CHECKGROUPSECTIONS:      SHF_EXECINSTR
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 2
+#CHECKSYMBOLS:    Name: g2
+#CHECKSYMBOLS:    Section: .foo
+#CHECKSYMBOLS:    Name: g1
+#CHECKSYMBOLS:    Section: .text
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '9090'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+  Global:
+    - Name:            g2
+      Section:         .foo
+      Value:           0x0000000000000001
+  Weak:
+    - Name:            g1
+      Section:         .foo
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '9090'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+  Global:
+    - Name:            g1
+      Section:         .foo
+    - Name:            g2
+      Section:         .foo
+      Value:           0x0000000000000001
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         554889E531C05DC3
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         00636C616E672076657273696F6E20332E372E3020287472756E6B203232393535372920286C6C766D2F7472756E6B203232393536332900
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    AddressAlign:    0x0000000000000008
+    Content:         1400000000000000037A5200017810011B0C0708900100001C0000001C000000000000000800000000410E108602430D0600000000000000
+  - Name:            .rela.eh_frame
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .eh_frame
+    Relocations:
+      - Offset:          0x0000000000000020
+        Symbol:          .text
+        Type:            R_X86_64_PC32
+Symbols:
+  Local:
+    - Name:            g1.c
+      Type:            STT_FILE
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .comment
+      Type:            STT_SECTION
+      Section:         .comment
+    - Name:            .note.GNU-stack
+      Type:            STT_SECTION
+      Section:         .note.GNU-stack
+    - Name:            .eh_frame
+      Type:            STT_SECTION
+      Section:         .eh_frame
+  Global:
+    - Name:            g1
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x0000000000000008
+...
diff --git a/lld/test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test b/lld/test/elf/sectionGroups/sectiongroup-with-undef-external-reference.test
new file mode 100644 (file)
index 0000000..a90034a
--- /dev/null
@@ -0,0 +1,239 @@
+# This tests that comdat undef symbol is overridden by a global symbol.
+# comdat1.s
+#------------------------
+#        .global g1
+#        .section .foo,"axG",@progbits,g1,comdat
+#g1:
+#      .word 5
+#
+#comdat2.s << \!
+#-----------------
+#      .global g1
+#        .section .foo,"axG",@progbits,g1,comdat
+#g1:
+#        nop
+#
+#g1.c
+#-----------
+#extern int g1;
+#int fn() { return g1;}
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.comdat1.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.comdat2.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.g1.o
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP:  - name:            g1
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    content:         [ 05, 00 ]
+#CHECKGROUP:    section-name:    .foo
+#CHECKGROUPSECTIONS:  Section {
+#CHECKGROUPSECTIONS:    Name: .foo
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [
+#CHECKGROUPSECTIONS:      SHF_ALLOC
+#CHECKGROUPSECTIONS:      SHF_EXECINSTR
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 2
+#CHECKGROUPSECTIONS:  }
+#CHECKSYMBOLS:    Name: g1
+#CHECKSYMBOLS:    Section: .foo
+#CHECKSYMBOLS:    Name: fn
+#CHECKSYMBOLS:    Section: .text
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0500'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+  Global:
+    - Name:            g1
+      Section:         .foo
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '90'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+  Global:
+    - Name:            g1
+      Section:         .foo
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000010
+    Content:         554889E58B0425000000005DC3
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .text
+    Relocations:
+      - Offset:          0x0000000000000007
+        Symbol:          g1
+        Type:            R_X86_64_32S
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         00636C616E672076657273696F6E20332E372E3020287472756E6B203232393535372920286C6C766D2F7472756E6B203232393536332900
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+  - Name:            .eh_frame
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC ]
+    AddressAlign:    0x0000000000000008
+    Content:         1400000000000000037A5200017810011B0C0708900100001C0000001C000000000000000D00000000410E108602430D0600000000000000
+  - Name:            .rela.eh_frame
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .eh_frame
+    Relocations:
+      - Offset:          0x0000000000000020
+        Symbol:          .text
+        Type:            R_X86_64_PC32
+Symbols:
+  Local:
+    - Name:            global-g1.c
+      Type:            STT_FILE
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .comment
+      Type:            STT_SECTION
+      Section:         .comment
+    - Name:            .note.GNU-stack
+      Type:            STT_SECTION
+      Section:         .note.GNU-stack
+    - Name:            .eh_frame
+      Type:            STT_SECTION
+      Section:         .eh_frame
+  Global:
+    - Name:            fn
+      Type:            STT_FUNC
+      Section:         .text
+      Size:            0x000000000000000D
+    - Name:            g1
+...
diff --git a/lld/test/elf/sectionGroups/sectiongroup-with-undef-signature.test b/lld/test/elf/sectionGroups/sectiongroup-with-undef-signature.test
new file mode 100644 (file)
index 0000000..11cb5de
--- /dev/null
@@ -0,0 +1,222 @@
+# This tests that comdat undef symbol is overridden by a global symbol.
+# comdat1.s
+#------------------------
+# .section .foo,"axG",@progbits,g1,comdat
+# word g1
+#
+#comdat2.s << \!
+#-----------------
+#    .global g1
+#    .section .foo,"axG",@progbits,g1,comdat
+#g1:
+#        nop
+#
+#global-g1.c
+#-----------
+#int g1=10;
+#
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.comdat1.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.comdat2.o
+#RUN: yaml2obj -format=elf -docnum 3 %s -o %t.g1.o
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.comdat1.o %t.comdat2.o \
+#RUN: %t.g1.o --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGROUP < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGROUPSECTIONS
+#RUN: llvm-readobj -symbols %t2.out | FileCheck %s -check-prefix=CHECKSYMBOLS
+#CHECKGROUP:  - name:            g1
+#CHECKGROUP:    scope:           global
+#CHECKGROUP:    content:         [ 0A, 00, 00, 00 ]
+#CHECKGROUP:    section-name:    .data
+#CHECKGROUPSECTIONS:    Name: .foo
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [
+#CHECKGROUPSECTIONS:      SHF_ALLOC
+#CHECKGROUPSECTIONS:      SHF_EXECINSTR
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 2
+#CHECKGROUPSECTIONS:    Name: .data
+#CHECKGROUPSECTIONS:    Type: SHT_PROGBITS
+#CHECKGROUPSECTIONS:    Flags [
+#CHECKGROUPSECTIONS:      SHF_ALLOC
+#CHECKGROUPSECTIONS:      SHF_WRITE
+#CHECKGROUPSECTIONS:    ]
+#CHECKGROUPSECTIONS:    Size: 4
+#CHECKSYMBOLS:    Name: g1
+#CHECKSYMBOLS:    Section: .data
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+      - SectionOrType:   .rela.foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '0000'
+  - Name:            .rela.foo
+    Type:            SHT_RELA
+    Flags:           [ SHF_GROUP ]
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .foo
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          g1
+        Type:            R_X86_64_16
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+  Global:
+    - Name:            g1
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .group
+    Type:            SHT_GROUP
+    Link:            .symtab
+    AddressAlign:    0x0000000000000004
+    Info:            g1
+    Members:
+      - SectionOrType:   GRP_COMDAT
+      - SectionOrType:   .foo
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .foo
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+    AddressAlign:    0x0000000000000001
+    Content:         '90'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .foo
+      Type:            STT_SECTION
+      Section:         .foo
+  Global:
+    - Name:            g1
+      Section:         .foo
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .data
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         0A000000
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .comment
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_MERGE, SHF_STRINGS ]
+    AddressAlign:    0x0000000000000001
+    Content:         00636C616E672076657273696F6E20332E372E3020287472756E6B203232393535372920286C6C766D2F7472756E6B203232393536332900
+  - Name:            .note.GNU-stack
+    Type:            SHT_PROGBITS
+    AddressAlign:    0x0000000000000001
+    Content:         ''
+Symbols:
+  Local:
+    - Name:            global-g1.c
+      Type:            STT_FILE
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .comment
+      Type:            STT_SECTION
+      Section:         .comment
+    - Name:            .note.GNU-stack
+      Type:            STT_SECTION
+      Section:         .note.GNU-stack
+  Global:
+    - Name:            g1
+      Type:            STT_OBJECT
+      Section:         .data
+      Size:            0x0000000000000004
+...