[lld] r230194 - [ELF] Add .gnu.linkonce support.

Shankar Easwaran shankare at codeaurora.org
Sun Feb 22 16:04:50 PST 2015


Author: shankare
Date: Sun Feb 22 18:04:49 2015
New Revision: 230194

URL: http://llvm.org/viewvc/llvm-project?rev=230194&view=rev
Log:
[ELF] Add .gnu.linkonce support.

When the GNU linker sees two input sections with the same name, and the name
starts with ".gnu.linkonce.", the linker will only keep one copy and discard the
other. Any section whose name starts with “.gnu.linkonce.” is a COMDAT section.

Some architectures like Hexagon use this section to store floating point constants,
that need be deduped.

This patch adds gnu.linkonce functionality to the ELFReader.

Added:
    lld/trunk/test/elf/gnulinkonce/
    lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test
    lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-undef.test
    lld/trunk/test/elf/gnulinkonce/gnulinkonce.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/Atoms.h
    lld/trunk/lib/ReaderWriter/ELF/ELFFile.h
    lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
    lld/trunk/lib/ReaderWriter/ELF/TODO.txt

Modified: lld/trunk/lib/ReaderWriter/ELF/Atoms.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Atoms.h?rev=230194&r1=230193&r2=230194&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Atoms.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Atoms.h Sun Feb 22 18:04:49 2015
@@ -179,14 +179,16 @@ public:
   uint64_t size() const override {
     // Common symbols are not allocated in object files,
     // so use st_size to tell how many bytes are required.
-    if ((_symbol->getType() == llvm::ELF::STT_COMMON) ||
-        _symbol->st_shndx == llvm::ELF::SHN_COMMON)
+    if (_symbol && (_symbol->getType() == llvm::ELF::STT_COMMON ||
+                    _symbol->st_shndx == llvm::ELF::SHN_COMMON))
       return (uint64_t) _symbol->st_size;
 
     return _contentData.size();
   }
 
   Scope scope() const override {
+    if (!_symbol)
+      return scopeGlobal;
     if (_symbol->getVisibility() == llvm::ELF::STV_HIDDEN)
       return scopeLinkageUnit;
     else if (_symbol->getBinding() != llvm::ELF::STB_LOCAL)
@@ -199,6 +201,9 @@ public:
   Interposable interposable() const override { return interposeNo; }
 
   Merge merge() const override {
+    if (!_symbol)
+      return mergeNo;
+
     if (_symbol->getBinding() == llvm::ELF::STB_WEAK)
       return mergeAsWeak;
 
@@ -216,6 +221,9 @@ public:
     ContentType ret = typeUnknown;
     uint64_t flags = _section->sh_flags;
 
+    if (!_symbol && _sectionName.startswith(".gnu.linkonce"))
+      return typeGnuLinkOnce;
+
     if (!(flags & llvm::ELF::SHF_ALLOC))
       return _contentType = typeNoAlloc;
 
@@ -286,6 +294,9 @@ public:
   }
 
   Alignment alignment() const override {
+    if (!_symbol)
+      return Alignment(0);
+
     // Obtain proper value of st_value field.
     const auto symValue = getSymbolValue(_symbol);
 
@@ -323,7 +334,7 @@ public:
 
   StringRef customSectionName() const override {
     if ((contentType() == typeZeroFill) ||
-        (_symbol->st_shndx == llvm::ELF::SHN_COMMON))
+        (_symbol && _symbol->st_shndx == llvm::ELF::SHN_COMMON))
       return ".bss";
     return _sectionName;
   }

Modified: lld/trunk/lib/ReaderWriter/ELF/ELFFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/ELFFile.h?rev=230194&r1=230193&r2=230194&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/ELFFile.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/ELFFile.h Sun Feb 22 18:04:49 2015
@@ -168,8 +168,23 @@ public:
     return _absoluteAtoms;
   }
 
-  Atom *findAtom(const Elf_Sym *symbol) {
-    return _symbolToAtomMapping.lookup(symbol);
+  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);
+    if (targetAtom->definition() != Atom::definitionRegular)
+      return targetAtom;
+    if ((llvm::dyn_cast<DefinedAtom>(targetAtom))->scope() ==
+        DefinedAtom::scopeTranslationUnit)
+      return targetAtom;
+    if (!redirectReferenceUsingUndefAtom(sourceSymbol, targetSymbol))
+      return targetAtom;
+    auto undefForGroupchild = _undefAtomsForgroupChild.find(targetAtom->name());
+    if (undefForGroupchild != _undefAtomsForgroupChild.end())
+      return undefForGroupchild->getValue();
+    auto undefGroupChildAtom =
+        new (_readerStorage) SimpleUndefinedAtom(*this, targetAtom->name());
+    _undefinedAtoms._atoms.push_back(undefGroupChildAtom);
+    return (_undefAtomsForgroupChild[targetAtom->name()] = undefGroupChildAtom);
   }
 
 protected:
@@ -258,6 +273,12 @@ protected:
     return shdr && (shdr->sh_type == llvm::ELF::SHT_PROGBITS) && syms.empty();
   }
 
+  /// Handle creation of atoms for .gnu.linkonce sections.
+  std::error_code handleGnuLinkOnceSection(
+      StringRef sectionName,
+      llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+      const Elf_Shdr *shdr);
+
   /// Process the Undefined symbol and create an atom for it.
   ErrorOr<ELFUndefinedAtom<ELFT> *>
   handleUndefinedSymbol(StringRef symName, const Elf_Sym *sym) {
@@ -286,6 +307,11 @@ protected:
            symbol->st_shndx == llvm::ELF::SHN_COMMON;
   }
 
+  /// Returns true if the section is a gnulinkonce section.
+  bool isGnuLinkOnceSection(StringRef sectionName) const {
+    return sectionName.startswith(".gnu.linkonce");
+  }
+
   /// 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 {
@@ -333,6 +359,10 @@ protected:
     return mergeAtom;
   }
 
+  /// Does the atom need to be redirected using a separate undefined atom ?
+  bool redirectReferenceUsingUndefAtom(const Elf_Sym *sourceSymbol,
+                                       const Elf_Sym *targetSymbol) const;
+
   llvm::BumpPtrAllocator _readerStorage;
   std::unique_ptr<llvm::object::ELFFile<ELFT> > _objFile;
   atom_collection_vector<DefinedAtom> _definedAtoms;
@@ -350,6 +380,11 @@ protected:
   std::unordered_map<StringRef, range<Elf_Rel_Iter>> _relocationReferences;
   std::vector<ELFReference<ELFT> *> _references;
   llvm::DenseMap<const Elf_Sym *, Atom *> _symbolToAtomMapping;
+  // Group child atoms have a pair corresponding to the signature and the
+  // section header of the section that was used for generating the signature.
+  llvm::DenseMap<const Elf_Sym *, std::pair<StringRef, const Elf_Shdr *>>
+      _groupChild;
+  llvm::StringMap<Atom *> _undefAtomsForgroupChild;
 
   /// \brief Atoms that are created for a section that has the merge property
   /// set
@@ -623,6 +658,11 @@ std::error_code ELFFile<ELFT>::createSym
 }
 
 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;
   for (auto &i : _sectionSymbols) {
     const Elf_Shdr *section = i.first;
     std::vector<Elf_Sym_Iter> &symbols = i.second;
@@ -641,11 +681,21 @@ template <class ELFT> std::error_code EL
     if (std::error_code ec = sectionContents.getError())
       return ec;
 
+    bool addAtoms = true;
+
+    if (isGnuLinkOnceSection(*sectionName)) {
+      groupSections.insert(std::make_pair(section, *sectionName));
+      addAtoms = false;
+    }
+
     if (handleSectionWithNoSymbols(section, symbols)) {
       ELFDefinedAtom<ELFT> *newAtom =
           createSectionAtom(section, *sectionName, *sectionContents);
-      _definedAtoms._atoms.push_back(newAtom);
       newAtom->setOrdinal(++_ordinal);
+      if (addAtoms)
+        _definedAtoms._atoms.push_back(newAtom);
+      else
+        atomsForSection[*sectionName].push_back(newAtom);
       continue;
     }
 
@@ -693,8 +743,11 @@ template <class ELFT> std::error_code EL
           auto definedMergeAtom = handleDefinedSymbol(
               symbolName, *sectionName, &**si, section, symbolData,
               _references.size(), _references.size(), _references);
-          _definedAtoms._atoms.push_back(*definedMergeAtom);
           (*definedMergeAtom)->setOrdinal(++_ordinal);
+          if (addAtoms)
+            _definedAtoms._atoms.push_back(*definedMergeAtom);
+          else
+            atomsForSection[*sectionName].push_back(*definedMergeAtom);
         }
         continue;
       }
@@ -740,19 +793,60 @@ template <class ELFT> std::error_code EL
       // is a weak atom.
       previousAtom = anonAtom ? anonAtom : newAtom;
 
-      _definedAtoms._atoms.push_back(newAtom);
+      if (addAtoms)
+        _definedAtoms._atoms.push_back(newAtom);
+      else
+        atomsForSection[*sectionName].push_back(newAtom);
+
       _symbolToAtomMapping.insert(std::make_pair(&*symbol, newAtom));
       if (anonAtom) {
         anonAtom->setOrdinal(++_ordinal);
-        _definedAtoms._atoms.push_back(anonAtom);
+        if (addAtoms)
+          _definedAtoms._atoms.push_back(anonAtom);
+        else
+          atomsForSection[*sectionName].push_back(anonAtom);
       }
     }
   }
 
+  // Iterate over all the group sections to create parent atoms pointing to
+  // group-child atoms.
+  for (auto &sect : groupSections) {
+    StringRef signature = sect.second;
+    if (isGnuLinkOnceSection(signature))
+      handleGnuLinkOnceSection(signature, atomsForSection, sect.first);
+  }
+
   updateReferences();
   return std::error_code();
 }
 
+template <class ELFT>
+std::error_code ELFFile<ELFT>::handleGnuLinkOnceSection(
+    StringRef signature,
+    llvm::StringMap<std::vector<ELFDefinedAtom<ELFT> *>> &atomsForSection,
+    const Elf_Shdr *shdr) {
+  unsigned int referenceStart = _references.size();
+  std::vector<ELFReference<ELFT> *> refs;
+  for (auto ha : atomsForSection[signature]) {
+    _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[signature].clear();
+  // Create a gnu linkonce atom.
+  auto gnuLinkOnceAtom = handleDefinedSymbol(
+      signature, signature, nullptr, shdr, ArrayRef<uint8_t>(), referenceStart,
+      _references.size(), _references);
+  (*gnuLinkOnceAtom)->setOrdinal(++_ordinal);
+  _definedAtoms._atoms.push_back(*gnuLinkOnceAtom);
+  for (auto reference : refs)
+    (*gnuLinkOnceAtom)->addReference(reference);
+  return std::error_code();
+}
+
 template <class ELFT> std::error_code ELFFile<ELFT>::createAtomsFromContext() {
   if (!_useWrap)
     return std::error_code();
@@ -882,7 +976,7 @@ template <class ELFT> void ELFFile<ELFT>
       // If the atom is not in mergeable string section, the target atom is
       // simply that atom.
       if (!isMergeableStringSection(shdr)) {
-        ri->setTarget(findAtom(symbol));
+        ri->setTarget(findAtom(ri->symbol(), symbol));
         continue;
       }
       updateReferenceForMergeStringAccess(ri, symbol, shdr);
@@ -954,6 +1048,24 @@ void ELFFile<ELFT>::createEdge(ELFDefine
   from->addReference(reference);
 }
 
+/// Does the atom need to be redirected using a separate undefined atom ?
+template <class ELFT>
+bool ELFFile<ELFT>::redirectReferenceUsingUndefAtom(
+    const Elf_Sym *sourceSymbol, const Elf_Sym *targetSymbol) const {
+  auto groupChild = _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())
+    return false;
+
+  if (sourceSymbol->st_shndx != targetSymbol->st_shndx) {
+    return true;
+  }
+
+  return false;
+}
+
 } // end namespace elf
 } // end namespace lld
 

Modified: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h?rev=230194&r1=230193&r2=230194&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h Sun Feb 22 18:04:49 2015
@@ -361,6 +361,9 @@ const lld::AtomLayout &AtomSection<ELFT>
     _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.");

Modified: lld/trunk/lib/ReaderWriter/ELF/TODO.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/TODO.txt?rev=230194&r1=230193&r2=230194&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/TODO.txt (original)
+++ lld/trunk/lib/ReaderWriter/ELF/TODO.txt Sun Feb 22 18:04:49 2015
@@ -14,6 +14,4 @@ lib/ReaderWriter/ELF
 
 - Section Groups.
 
-- Gnu linkonce sections.
-
 - Fix section flags as they appear in input (update content permissions)

Added: lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test?rev=230194&view=auto
==============================================================================
--- lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test (added)
+++ lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-discarded-reference.test Sun Feb 22 18:04:49 2015
@@ -0,0 +1,147 @@
+# Tests that the linker is able to read .gnu.linkonce sections and link them
+# appropriately. The testcase has been created by using the following source
+# code.
+# TODO: This test should produce a discarded reference error message which it
+# doesnot currently.
+# linkoncea.s
+#        .section .gnu.linkonce.d.dummy,"aw"
+#bar:
+#        .long    0
+# linkonceb.s
+#        .section .gnu.linkonce.d.dummy,"aw"
+#foo:
+#        .long    0
+#        .section .blah, "aw"
+#        .long    foo
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.linkonce1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.linkonce1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGNULINKONCE < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGNULINKONCESECTIONS
+#CHECKGNULINKONCE: - name:            .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE:   scope:           global
+#CHECKGNULINKONCE:   type:            gnu-linkonce
+#CHECKGNULINKONCE:   section-choice:  custom-required
+#CHECKGNULINKONCE:   section-name:    .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE:   permissions:     rw-
+#CHECKGNULINKONCE:   references:
+#CHECKGNULINKONCE:     - kind:            group-child
+#CHECKGNULINKONCE:       offset:          0
+#CHECKGNULINKONCE:       target:          bar
+#CHECKGNULINKONCESECTIONS:   Section {
+#CHECKGNULINKONCESECTIONS:     Name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCESECTIONS:     Type: SHT_PROGBITS
+#CHECKGNULINKONCESECTIONS:     Flags [ (0x3)
+#CHECKGNULINKONCESECTIONS:       SHF_ALLOC (0x2)
+#CHECKGNULINKONCESECTIONS:       SHF_WRITE (0x1)
+#CHECKGNULINKONCESECTIONS:     ]
+#CHECKGNULINKONCESECTIONS:     Size: 4
+#CHECKGNULINKONCESECTIONS:   }
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  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:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .gnu.linkonce.d.dummy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .gnu.linkonce.d.dummy
+      Type:            STT_SECTION
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            bar
+      Section:         .gnu.linkonce.d.dummy
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  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:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .gnu.linkonce.d.dummy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+  - Name:            .blah
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+  - Name:            .rela.blah
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .blah
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          foo
+        Type:            R_X86_64_32
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .gnu.linkonce.d.dummy
+      Type:            STT_SECTION
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            foo
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            .blah
+      Type:            STT_SECTION
+      Section:         .blah
+...

Added: lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-undef.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-undef.test?rev=230194&view=auto
==============================================================================
--- lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-undef.test (added)
+++ lld/trunk/test/elf/gnulinkonce/gnulinkonce-report-undef.test Sun Feb 22 18:04:49 2015
@@ -0,0 +1,129 @@
+# Tests that the linker is able to read .gnu.linkonce sections and link them
+# appropriately. The testcase has been created by using the following source
+# code. This test checks that the linker produces an undefined error.
+# linkoncea.s
+#        .section .gnu.linkonce.d.dummy,"aw"
+#bar:
+#        .long    0
+# linkonceb.s
+#        .section .gnu.linkonce.d.dummy,"aw"
+#        .global foo
+#foo:
+#        .long    0
+#        .section .blah, "aw"
+#        .long    foo
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.linkonce1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.linkonce1b.o
+#RUN: not lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN:  --output-filetype=yaml -o %t2.out.yaml 2>&1 | FileCheck \
+#RUN: -check-prefix=UNDEFS %s
+#RUN: not lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: -o %t2.out 2>&1 | FileCheck -check-prefix=UNDEFS %s
+#UNDEFS: Undefined symbol: {{.*}} foo
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  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:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .gnu.linkonce.d.dummy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .gnu.linkonce.d.dummy
+      Type:            STT_SECTION
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            bar
+      Section:         .gnu.linkonce.d.dummy
+...
+---
+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:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .gnu.linkonce.d.dummy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+  - Name:            .blah
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+  - Name:            .rela.blah
+    Type:            SHT_RELA
+    Link:            .symtab
+    AddressAlign:    0x0000000000000008
+    Info:            .blah
+    Relocations:
+      - Offset:          0x0000000000000000
+        Symbol:          foo
+        Type:            R_X86_64_32
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .gnu.linkonce.d.dummy
+      Type:            STT_SECTION
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            .blah
+      Type:            STT_SECTION
+      Section:         .blah
+  Global:
+    - Name:            foo
+      Section:         .gnu.linkonce.d.dummy
+...

Added: lld/trunk/test/elf/gnulinkonce/gnulinkonce.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/gnulinkonce/gnulinkonce.test?rev=230194&view=auto
==============================================================================
--- lld/trunk/test/elf/gnulinkonce/gnulinkonce.test (added)
+++ lld/trunk/test/elf/gnulinkonce/gnulinkonce.test Sun Feb 22 18:04:49 2015
@@ -0,0 +1,151 @@
+# Tests that the linker is able to read .gnu.linkonce sections and link them
+# appropriately. The testcase has been created by using the following source
+# code
+# linkonce1a.s
+# ------------
+#        .section .gnu.linkonce.d.dummy,"aw"
+#bar:
+#        .long    0
+# linkonce1b.s
+# ------------
+#    .globl main
+#    .globl start
+#    .globl _start
+#    .globl __start
+#    .text
+#main:
+#start:
+#_start:
+#__start:
+#    .long    0
+#
+#        .section .gnu.linkonce.d.dummy,"aw"
+#foo:
+#        .long    0
+#RUN: yaml2obj -format=elf -docnum 1 %s -o %t.linkonce1a.o
+#RUN: yaml2obj -format=elf -docnum 2 %s -o %t.linkonce1b.o
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec --output-filetype=yaml -o %t2.out.yaml
+#RUN: lld -flavor gnu -target x86_64 %t.linkonce1a.o %t.linkonce1b.o \
+#RUN: --noinhibit-exec -o %t2.out
+#RUN: FileCheck %s -check-prefix=CHECKGNULINKONCE < %t2.out.yaml
+#RUN: llvm-readobj -sections %t2.out | FileCheck %s -check-prefix=CHECKGNULINKONCESECTIONS
+#CHECKGNULINKONCE: - name:            .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE:   scope:           global
+#CHECKGNULINKONCE:   type:            gnu-linkonce
+#CHECKGNULINKONCE:   section-choice:  custom-required
+#CHECKGNULINKONCE:   section-name:    .gnu.linkonce.d.dummy
+#CHECKGNULINKONCE:   permissions:     rw-
+#CHECKGNULINKONCE:   references:
+#CHECKGNULINKONCE:     - kind:            group-child
+#CHECKGNULINKONCE:       offset:          0
+#CHECKGNULINKONCE:       target:          bar
+#CHECKGNULINKONCE:     - kind:            group-child
+#CHECKGNULINKONCE:       offset:          0
+#CHECKGNULINKONCESECTIONS:   Section {
+#CHECKGNULINKONCESECTIONS:     Name: .gnu.linkonce.d.dummy
+#CHECKGNULINKONCESECTIONS:     Type: SHT_PROGBITS
+#CHECKGNULINKONCESECTIONS:     Flags [ (0x3)
+#CHECKGNULINKONCESECTIONS:       SHF_ALLOC (0x2)
+#CHECKGNULINKONCESECTIONS:       SHF_WRITE (0x1)
+#CHECKGNULINKONCESECTIONS:     ]
+#CHECKGNULINKONCESECTIONS:     Size: 4
+#CHECKGNULINKONCESECTIONS:   }
+---
+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:         ''
+  - Name:            .bss
+    Type:            SHT_NOBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000004
+    Content:         ''
+  - Name:            .gnu.linkonce.d.dummy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+Symbols:
+  Local:
+    - Name:            bar
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .gnu.linkonce.d.dummy
+      Type:            STT_SECTION
+      Section:         .gnu.linkonce.d.dummy
+...
+---
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         '00000000'
+  - 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:            .gnu.linkonce.d.dummy
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_WRITE, SHF_ALLOC ]
+    AddressAlign:    0x0000000000000001
+    Content:         '00000000'
+Symbols:
+  Local:
+    - Name:            .text
+      Type:            STT_SECTION
+      Section:         .text
+    - Name:            .data
+      Type:            STT_SECTION
+      Section:         .data
+    - Name:            .bss
+      Type:            STT_SECTION
+      Section:         .bss
+    - Name:            .gnu.linkonce.d.dummy
+      Type:            STT_SECTION
+      Section:         .gnu.linkonce.d.dummy
+    - Name:            foo
+      Section:         .gnu.linkonce.d.dummy
+  Global:
+    - Name:            main
+      Section:         .text
+    - Name:            start
+      Section:         .text
+    - Name:            _start
+      Section:         .text
+    - Name:            __start
+      Section:         .text
+...






More information about the llvm-commits mailing list