[lld] r250737 - Add support for merging the contents of SHF_MERGE sections.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 19 14:00:02 PDT 2015


Author: rafael
Date: Mon Oct 19 16:00:02 2015
New Revision: 250737

URL: http://llvm.org/viewvc/llvm-project?rev=250737&view=rev
Log:
Add support for merging the contents of SHF_MERGE sections.

For now SHF_STRINGS are not supported.

Added:
    lld/trunk/test/elf2/Inputs/merge.s
    lld/trunk/test/elf2/merge-invalid-size.s
    lld/trunk/test/elf2/merge-shared.s
    lld/trunk/test/elf2/merge.s
    lld/trunk/test/elf2/relocation-in-merge.s
    lld/trunk/test/elf2/relocation-past-merge-end.s
    lld/trunk/test/elf2/writable-merge.s
Modified:
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/OutputSections.cpp
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Mon Oct 19 16:00:02 2015
@@ -150,16 +150,28 @@ void elf2::ObjectFile<ELFT>::initializeS
       uint32_t RelocatedSectionIndex = Sec.sh_info;
       if (RelocatedSectionIndex >= Size)
         error("Invalid relocated section index");
-      InputSection<ELFT> *RelocatedSection = Sections[RelocatedSectionIndex];
+      InputSectionBase<ELFT> *RelocatedSection =
+          Sections[RelocatedSectionIndex];
       if (!RelocatedSection)
         error("Unsupported relocation reference");
-      RelocatedSection->RelocSections.push_back(&Sec);
+      if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection))
+        S->RelocSections.push_back(&Sec);
+      else
+        error("Relocations pointing to SHF_MERGE are not supported");
       break;
     }
-    default:
-      Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec);
+    default: {
+      uintX_t Flags = Sec.sh_flags;
+      if (Flags & SHF_MERGE && !(Flags & SHF_STRINGS)) {
+        if (Flags & SHF_WRITE)
+          error("Writable SHF_MERGE sections are not supported");
+        Sections[I] = new (this->Alloc) MergeInputSection<ELFT>(this, &Sec);
+      } else {
+        Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec);
+      }
       break;
     }
+    }
   }
 }
 
@@ -173,7 +185,7 @@ template <class ELFT> void elf2::ObjectF
 }
 
 template <class ELFT>
-InputSection<ELFT> *
+InputSectionBase<ELFT> *
 elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
   uint32_t Index = Sym.st_shndx;
   if (Index == ELF::SHN_XINDEX)
@@ -209,7 +221,7 @@ SymbolBody *elf2::ObjectFile<ELFT>::crea
   case STB_GLOBAL:
   case STB_WEAK:
   case STB_GNU_UNIQUE: {
-    InputSection<ELFT> *Sec = getSection(*Sym);
+    InputSectionBase<ELFT> *Sec = getSection(*Sym);
     if (Sec == &InputSection<ELFT>::Discarded)
       return new (this->Alloc) Undefined<ELFT>(Name, *Sym);
     return new (this->Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sec);

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Mon Oct 19 16:00:02 2015
@@ -94,6 +94,7 @@ template <class ELFT> class ObjectFile :
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
 
   typedef llvm::support::detail::packed_endian_specific_integral<
       uint32_t, ELFT::TargetEndianness, 2> GroupEntryType;
@@ -110,8 +111,8 @@ public:
   explicit ObjectFile(MemoryBufferRef M);
   void parse(llvm::DenseSet<StringRef> &Comdats);
 
-  ArrayRef<InputSection<ELFT> *> getSections() const { return Sections; }
-  InputSection<ELFT> *getSection(const Elf_Sym &Sym) const;
+  ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
+  InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
 
   SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
     uint32_t FirstNonLocal = this->Symtab->sh_info;
@@ -132,7 +133,7 @@ private:
   SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
 
   // List of all sections defined by this file.
-  std::vector<InputSection<ELFT> *> Sections;
+  std::vector<InputSectionBase<ELFT> *> Sections;
 
   ArrayRef<Elf_Word> SymtabSHNDX;
 

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Mon Oct 19 16:00:02 2015
@@ -22,8 +22,41 @@ using namespace lld;
 using namespace lld::elf2;
 
 template <class ELFT>
+InputSectionBase<ELFT>::InputSectionBase(ObjectFile<ELFT> *File,
+                                         const Elf_Shdr *Header,
+                                         Kind SectionKind)
+    : Header(Header), File(File), SectionKind(SectionKind) {}
+
+template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
+  ErrorOr<StringRef> Name = File->getObj().getSectionName(this->Header);
+  error(Name);
+  return *Name;
+}
+
+template <class ELFT>
+ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
+  ErrorOr<ArrayRef<uint8_t>> Ret =
+      this->File->getObj().getSectionContents(this->Header);
+  error(Ret);
+  return *Ret;
+}
+
+template <class ELFT>
+typename ELFFile<ELFT>::uintX_t
+InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) const {
+  if (auto *S = dyn_cast<InputSection<ELFT>>(this))
+    return S->OutSecOff + Sym.st_value;
+  return cast<MergeInputSection<ELFT>>(this)->getOffset(Sym.st_value);
+}
+
+template <class ELFT>
 InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
-    : File(F), Header(Header) {}
+    : InputSectionBase<ELFT>(F, Header, Base::Regular) {}
+
+template <class ELFT>
+bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == Base::Regular;
+}
 
 template <class ELFT>
 template <bool isRela>
@@ -65,35 +98,63 @@ void InputSection<ELFT>::relocate(
 }
 
 template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
-  if (Header->sh_type == SHT_NOBITS)
+  if (this->Header->sh_type == SHT_NOBITS)
     return;
   // Copy section contents from source object file to output file.
-  ArrayRef<uint8_t> Data = *File->getObj().getSectionContents(Header);
+  ArrayRef<uint8_t> Data = this->getSectionData();
   memcpy(Buf + OutSecOff, Data.data(), Data.size());
 
-  ELFFile<ELFT> &EObj = File->getObj();
+  ELFFile<ELFT> &EObj = this->File->getObj();
   uint8_t *Base = Buf + OutSecOff;
-  uintX_t BaseAddr = OutSec->getVA() + OutSecOff;
+  uintX_t BaseAddr = this->OutSec->getVA() + OutSecOff;
   // Iterate over all relocation sections that apply to this section.
   for (const Elf_Shdr *RelSec : RelocSections) {
     if (RelSec->sh_type == SHT_RELA)
-      relocate(Base, Base + Data.size(), EObj.relas(RelSec), *File, BaseAddr);
+      relocate(Base, Base + Data.size(), EObj.relas(RelSec), *this->File,
+               BaseAddr);
     else
-      relocate(Base, Base + Data.size(), EObj.rels(RelSec), *File, BaseAddr);
+      relocate(Base, Base + Data.size(), EObj.rels(RelSec), *this->File,
+               BaseAddr);
   }
 }
 
-template <class ELFT> StringRef InputSection<ELFT>::getSectionName() const {
-  ErrorOr<StringRef> Name = File->getObj().getSectionName(Header);
-  error(Name);
-  return *Name;
+template <class ELFT>
+MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F,
+                                           const Elf_Shdr *Header)
+    : InputSectionBase<ELFT>(F, Header, Base::Merge) {}
+
+template <class ELFT>
+bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+  return S->SectionKind == Base::Merge;
+}
+
+// FIXME: Optimize this by keeping an offset for each element.
+template <class ELFT>
+typename MergeInputSection<ELFT>::uintX_t
+MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+  ArrayRef<uint8_t> Data = this->getSectionData();
+  uintX_t EntSize = this->Header->sh_entsize;
+  if (Offset + EntSize > Data.size())
+    error("Entry is past the end of the section");
+  Data = Data.slice(Offset, EntSize);
+  return static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Data);
 }
 
 namespace lld {
 namespace elf2 {
+template class InputSectionBase<object::ELF32LE>;
+template class InputSectionBase<object::ELF32BE>;
+template class InputSectionBase<object::ELF64LE>;
+template class InputSectionBase<object::ELF64BE>;
+
 template class InputSection<object::ELF32LE>;
 template class InputSection<object::ELF32BE>;
 template class InputSection<object::ELF64LE>;
 template class InputSection<object::ELF64BE>;
+
+template class MergeInputSection<object::ELF32LE>;
+template class MergeInputSection<object::ELF32BE>;
+template class MergeInputSection<object::ELF64LE>;
+template class MergeInputSection<object::ELF64BE>;
 }
 }

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Mon Oct 19 16:00:02 2015
@@ -21,22 +21,28 @@ template <class ELFT> class OutputSectio
 template <class ELFT> class OutputSectionBase;
 
 // This corresponds to a section of an input file.
-template <class ELFT> class InputSection {
+template <class ELFT> class InputSectionBase {
+protected:
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
-  typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
-  typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+  const Elf_Shdr *Header;
+
+  // The file this section is from.
+  ObjectFile<ELFT> *File;
 
 public:
-  InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+  enum Kind { Regular, Merge };
+  Kind SectionKind;
+
+  InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+                   Kind SectionKind);
+  OutputSectionBase<ELFT> *OutSec = nullptr;
 
   // Returns the size of this section (even if this is a common or BSS.)
   size_t getSize() const { return Header->sh_size; }
 
-  // Write this section to a mmap'ed file, assuming Buf is pointing to
-  // beginning of the output section.
-  void writeTo(uint8_t *Buf);
+  static InputSectionBase<ELFT> Discarded;
 
   StringRef getSectionName() const;
   const Elf_Shdr *getSectionHdr() const { return Header; }
@@ -49,15 +55,52 @@ public:
     return std::max<uintX_t>(Header->sh_addralign, 1);
   }
 
+  uintX_t getOffset(const Elf_Sym &Sym) const;
+  ArrayRef<uint8_t> getSectionData() const;
+};
+
+template <class ELFT>
+InputSectionBase<ELFT>
+    InputSectionBase<ELFT>::Discarded(nullptr, nullptr,
+                                      InputSectionBase<ELFT>::Regular);
+
+// This corresponds to a SHF_MERGE section of an input file.
+template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
+  typedef InputSectionBase<ELFT> Base;
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+
+public:
+  MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+  static bool classof(const InputSectionBase<ELFT> *S);
+  uintX_t getOffset(uintX_t Offset) const;
+};
+
+// This corresponds to a non SHF_MERGE section of an input file.
+template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
+  typedef InputSectionBase<ELFT> Base;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+  typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+
+public:
+  InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+
+  // Write this section to a mmap'ed file, assuming Buf is pointing to
+  // beginning of the output section.
+  void writeTo(uint8_t *Buf);
+
   // Relocation sections that refer to this one.
   SmallVector<const Elf_Shdr *, 1> RelocSections;
 
   // The offset from beginning of the output sections this section was assigned
   // to. The writer sets a value.
   uint64_t OutSecOff = 0;
-  OutputSectionBase<ELFT> *OutSec = nullptr;
 
-  static InputSection<ELFT> Discarded;
+  static bool classof(const InputSectionBase<ELFT> *S);
 
 private:
   template <bool isRela>
@@ -65,16 +108,8 @@ private:
                 llvm::iterator_range<
                     const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
                 const ObjectFile<ELFT> &File, uintX_t BaseAddr);
-
-  // The file this section is from.
-  ObjectFile<ELFT> *File;
-
-  const Elf_Shdr *Header;
 };
 
-template <class ELFT>
-InputSection<ELFT> InputSection<ELFT>::Discarded(nullptr, nullptr);
-
 } // namespace elf2
 } // namespace lld
 

Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Mon Oct 19 16:00:02 2015
@@ -408,8 +408,8 @@ typename ELFFile<ELFT>::uintX_t lld::elf
     return cast<DefinedAbsolute<ELFT>>(S).Sym.st_value;
   case SymbolBody::DefinedRegularKind: {
     const auto &DR = cast<DefinedRegular<ELFT>>(S);
-    const InputSection<ELFT> &SC = DR.Section;
-    return SC.OutSec->getVA() + SC.OutSecOff + DR.Sym.st_value;
+    const InputSectionBase<ELFT> &SC = DR.Section;
+    return SC.OutSec->getVA() + SC.getOffset(DR.Sym);
   }
   case SymbolBody::DefinedCommonKind:
     return Out<ELFT>::Bss->getVA() + cast<DefinedCommon<ELFT>>(S).OffsetInBSS;
@@ -449,11 +449,22 @@ lld::elf2::getLocalRelTarget(const Objec
   // the group are not allowed. Unfortunately .eh_frame breaks that rule
   // and must be treated specially. For now we just replace the symbol with
   // 0.
-  InputSection<ELFT> *Section = File.getSection(*Sym);
+  InputSectionBase<ELFT> *Section = File.getSection(*Sym);
   if (Section == &InputSection<ELFT>::Discarded)
     return Addend;
 
-  return Section->OutSec->getVA() + Section->OutSecOff + Sym->st_value + Addend;
+  uintX_t VA = Section->OutSec->getVA();
+  if (isa<InputSection<ELFT>>(Section))
+    return VA + Section->getOffset(*Sym) + Addend;
+
+  uintX_t Offset = Sym->st_value;
+  if (Sym->getType() == STT_SECTION) {
+    Offset += Addend;
+    Addend = Offset % Section->getSectionHdr()->sh_entsize;
+    Offset -= Addend;
+  }
+  return VA + cast<MergeInputSection<ELFT>>(Section)->getOffset(Offset) +
+         Addend;
 }
 
 // Returns true if a symbol can be replaced at load-time by a symbol
@@ -500,6 +511,44 @@ template <class ELFT> void OutputSection
 }
 
 template <class ELFT>
+MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t sh_type,
+                                             uintX_t sh_flags)
+    : OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {}
+
+template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+  for (const std::pair<ArrayRef<uint8_t>, uintX_t> &P : Offsets) {
+    ArrayRef<uint8_t> Data = P.first;
+    memcpy(Buf, Data.data(), Data.size());
+    Buf += Data.size();
+  }
+}
+
+template <class ELFT>
+void MergeOutputSection<ELFT>::addSection(MergeInputSection<ELFT> *S) {
+  S->OutSec = this;
+  uint32_t Align = S->getAlign();
+  if (Align > this->Header.sh_addralign)
+    this->Header.sh_addralign = Align;
+
+  uintX_t Off = this->Header.sh_size;
+  ArrayRef<uint8_t> Data = S->getSectionData();
+  uintX_t EntSize = S->getSectionHdr()->sh_entsize;
+  if (Data.size() % EntSize)
+    error("SHF_MERGE section size must be a multiple of sh_entsize");
+  for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) {
+    auto P = Offsets.insert(std::make_pair(Data.slice(I, EntSize), Off));
+    if (P.second)
+      Off += EntSize;
+  }
+  this->Header.sh_size = Off;
+}
+
+template <class ELFT>
+unsigned MergeOutputSection<ELFT>::getOffset(ArrayRef<uint8_t> Val) {
+  return Offsets.find(Val)->second;
+}
+
+template <class ELFT>
 StringTableSection<ELFT>::StringTableSection(bool Dynamic)
     : OutputSectionBase<ELFT>(Dynamic ? ".dynstr" : ".strtab",
                               llvm::ELF::SHT_STRTAB,
@@ -611,13 +660,15 @@ void SymbolTableSection<ELFT>::writeLoca
       ESym->st_name = StrTabSec.getFileOff(SymName);
       ESym->st_size = Sym.st_size;
       ESym->setBindingAndType(Sym.getBinding(), Sym.getType());
-      uintX_t VA = Sym.st_value;
+      uintX_t VA = 0;
       if (Sym.st_shndx == SHN_ABS) {
         ESym->st_shndx = SHN_ABS;
+        VA = Sym.st_value;
       } else {
-        const InputSection<ELFT> *Sec = File->getSection(Sym);
-        ESym->st_shndx = Sec->OutSec->SectionIndex;
-        VA += Sec->OutSec->getVA() + Sec->OutSecOff;
+        const InputSectionBase<ELFT> *Section = File->getSection(Sym);
+        const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
+        ESym->st_shndx = OutSec->SectionIndex;
+        VA += OutSec->getVA() + Section->getOffset(Sym);
       }
       ESym->st_value = VA;
     }
@@ -644,7 +695,7 @@ void SymbolTableSection<ELFT>::writeGlob
     ESym->st_name = StrTabSec.getFileOff(Name);
 
     const OutputSectionBase<ELFT> *OutSec = nullptr;
-    const InputSection<ELFT> *Section = nullptr;
+    const InputSectionBase<ELFT> *Section = nullptr;
 
     switch (Body->kind()) {
     case SymbolBody::DefinedSyntheticKind:
@@ -740,6 +791,11 @@ template class OutputSection<ELF32BE>;
 template class OutputSection<ELF64LE>;
 template class OutputSection<ELF64BE>;
 
+template class MergeOutputSection<ELF32LE>;
+template class MergeOutputSection<ELF32BE>;
+template class MergeOutputSection<ELF64LE>;
+template class MergeOutputSection<ELF64BE>;
+
 template class StringTableSection<ELF32LE>;
 template class StringTableSection<ELF32BE>;
 template class StringTableSection<ELF64LE>;
@@ -758,19 +814,29 @@ template ELFFile<ELF64BE>::uintX_t getSy
 template ELFFile<ELF32LE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF32LE> &,
                   const ELFFile<ELF32LE>::Elf_Rel &);
-
 template ELFFile<ELF32BE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF32BE> &,
                   const ELFFile<ELF32BE>::Elf_Rel &);
-
 template ELFFile<ELF64LE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF64LE> &,
                   const ELFFile<ELF64LE>::Elf_Rel &);
-
 template ELFFile<ELF64BE>::uintX_t
 getLocalRelTarget(const ObjectFile<ELF64BE> &,
                   const ELFFile<ELF64BE>::Elf_Rel &);
 
+template ELFFile<ELF32LE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF32LE> &,
+                  const ELFFile<ELF32LE>::Elf_Rela &);
+template ELFFile<ELF32BE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF32BE> &,
+                  const ELFFile<ELF32BE>::Elf_Rela &);
+template ELFFile<ELF64LE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF64LE> &,
+                  const ELFFile<ELF64LE>::Elf_Rela &);
+template ELFFile<ELF64BE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF64BE> &,
+                  const ELFFile<ELF64BE>::Elf_Rela &);
+
 template bool includeInSymtab<ELF32LE>(const SymbolBody &);
 template bool includeInSymtab<ELF32BE>(const SymbolBody &);
 template bool includeInSymtab<ELF64LE>(const SymbolBody &);

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Mon Oct 19 16:00:02 2015
@@ -12,6 +12,7 @@
 
 #include "lld/Core/LLVM.h"
 
+#include "llvm/ADT/MapVector.h"
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Object/ELF.h"
 
@@ -27,6 +28,7 @@ template <class ELFT> class SymbolTable;
 template <class ELFT> class SymbolTableSection;
 template <class ELFT> class StringTableSection;
 template <class ELFT> class InputSection;
+template <class ELFT> class MergeInputSection;
 template <class ELFT> class OutputSection;
 template <class ELFT> class ObjectFile;
 template <class ELFT> class DefinedRegular;
@@ -204,6 +206,23 @@ private:
 };
 
 template <class ELFT>
+class MergeOutputSection final : public OutputSectionBase<ELFT> {
+  typedef typename OutputSectionBase<ELFT>::uintX_t uintX_t;
+
+public:
+  MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+  void addSection(MergeInputSection<ELFT> *S);
+  void writeTo(uint8_t *Buf) override;
+
+  unsigned getOffset(ArrayRef<uint8_t> Val);
+
+private:
+  // This map is used to find if we already have an entry for a given value and,
+  // if so, at what offset it is.
+  llvm::MapVector<ArrayRef<uint8_t>, uintX_t> Offsets;
+};
+
+template <class ELFT>
 class InterpSection final : public OutputSectionBase<ELFT> {
 public:
   InterpSection();

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon Oct 19 16:00:02 2015
@@ -217,14 +217,15 @@ template <class ELFT> class DefinedRegul
   typedef typename Base::Elf_Sym Elf_Sym;
 
 public:
-  DefinedRegular(StringRef N, const Elf_Sym &Sym, InputSection<ELFT> &Section)
+  DefinedRegular(StringRef N, const Elf_Sym &Sym,
+                 InputSectionBase<ELFT> &Section)
       : Defined<ELFT>(Base::DefinedRegularKind, N, Sym), Section(Section) {}
 
   static bool classof(const SymbolBody *S) {
     return S->kind() == Base::DefinedRegularKind;
   }
 
-  const InputSection<ELFT> &Section;
+  const InputSectionBase<ELFT> &Section;
 };
 
 template <class ELFT> class DefinedSynthetic : public Defined<ELFT> {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Oct 19 16:00:02 2015
@@ -71,6 +71,7 @@ private:
   std::unique_ptr<llvm::FileOutputBuffer> Buffer;
 
   SpecificBumpPtrAllocator<OutputSection<ELFT>> SecAlloc;
+  SpecificBumpPtrAllocator<MergeOutputSection<ELFT>> MSecAlloc;
   BumpPtrAllocator Alloc;
   std::vector<OutputSectionBase<ELFT> *> OutputSections;
   unsigned getNumSections() const { return OutputSections.size() + 1; }
@@ -135,24 +136,27 @@ template <bool Is64Bits> struct SectionK
   StringRef Name;
   uint32_t Type;
   uintX_t Flags;
+  uintX_t EntSize;
 };
 }
 namespace llvm {
 template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
   static SectionKey<Is64Bits> getEmptyKey() {
-    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
+    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0,
+                                0};
   }
   static SectionKey<Is64Bits> getTombstoneKey() {
     return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
-                                0};
+                                0, 0};
   }
   static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
-    return hash_combine(Val.Name, Val.Type, Val.Flags);
+    return hash_combine(Val.Name, Val.Type, Val.Flags, Val.EntSize);
   }
   static bool isEqual(const SectionKey<Is64Bits> &LHS,
                       const SectionKey<Is64Bits> &RHS) {
     return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
-           LHS.Type == RHS.Type && LHS.Flags == RHS.Flags;
+           LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
+           LHS.EntSize == RHS.EntSize;
   }
 };
 }
@@ -390,39 +394,52 @@ template <class ELFT> void Writer<ELFT>:
   if (needsInterpSection())
     OutputSections.push_back(Out<ELFT>::Interp);
 
-  SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
+  SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map;
 
   OutputSections.push_back(Out<ELFT>::Bss);
   Map[{Out<ELFT>::Bss->getName(), Out<ELFT>::Bss->getType(),
-       Out<ELFT>::Bss->getFlags()}] = Out<ELFT>::Bss;
+       Out<ELFT>::Bss->getFlags(), 0}] = Out<ELFT>::Bss;
 
   std::vector<OutputSectionBase<ELFT> *> RegularSections;
 
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
-    for (InputSection<ELFT> *C : F->getSections()) {
+    for (InputSectionBase<ELFT> *C : F->getSections()) {
       if (!C || C == &InputSection<ELFT>::Discarded)
         continue;
       const Elf_Shdr *H = C->getSectionHdr();
       uintX_t OutFlags = H->sh_flags & ~SHF_GROUP;
+      // For SHF_MERGE we create different output sections for each sh_entsize.
+      // This makes each output section simple and keeps a single level
+      // mapping from input to output.
+      auto *IS = dyn_cast<InputSection<ELFT>>(C);
+      uintX_t EntSize = IS ? 0 : H->sh_entsize;
       SectionKey<ELFT::Is64Bits> Key{getOutputName(C->getSectionName()),
-                                     H->sh_type, OutFlags};
-      OutputSection<ELFT> *&Sec = Map[Key];
+                                     H->sh_type, OutFlags, EntSize};
+      OutputSectionBase<ELFT> *&Sec = Map[Key];
       if (!Sec) {
-        Sec = new (SecAlloc.Allocate())
-            OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+        if (IS)
+          Sec = new (SecAlloc.Allocate())
+              OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+        else
+          Sec = new (MSecAlloc.Allocate())
+              MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
         OutputSections.push_back(Sec);
         RegularSections.push_back(Sec);
       }
-      Sec->addSection(C);
+      if (IS)
+        static_cast<OutputSection<ELFT> *>(Sec)->addSection(IS);
+      else
+        static_cast<MergeOutputSection<ELFT> *>(Sec)
+            ->addSection(cast<MergeInputSection<ELFT>>(C));
     }
   }
 
-  Out<ELFT>::Dynamic->PreInitArraySec =
-      Map.lookup({".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC});
+  Out<ELFT>::Dynamic->PreInitArraySec = Map.lookup(
+      {".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
   Out<ELFT>::Dynamic->InitArraySec =
-      Map.lookup({".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC});
+      Map.lookup({".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
   Out<ELFT>::Dynamic->FiniArraySec =
-      Map.lookup({".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC});
+      Map.lookup({".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
 
   auto AddStartEnd = [&](StringRef Start, StringRef End,
                          OutputSectionBase<ELFT> *OS) {
@@ -455,9 +472,10 @@ template <class ELFT> void Writer<ELFT>:
   // Scan relocations. This must be done after every symbol is declared so that
   // we can correctly decide if a dynamic relocation is needed.
   for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles())
-    for (InputSection<ELFT> *S : F->getSections())
-      if (S && S != &InputSection<ELFT>::Discarded)
-        scanRelocs(*S);
+    for (InputSectionBase<ELFT> *B : F->getSections())
+      if (auto *S = dyn_cast_or_null<InputSection<ELFT>>(B))
+        if (S != &InputSection<ELFT>::Discarded)
+          scanRelocs(*S);
 
   // FIXME: Try to avoid the extra walk over all global symbols.
   std::vector<DefinedCommon<ELFT> *> CommonSymbols;
@@ -516,7 +534,7 @@ template <class ELFT> void Writer<ELFT>:
   // If we have a .opd section (used under PPC64 for function descriptors),
   // store a pointer to it here so that we can use it later when processing
   // relocations.
-  Out<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC});
+  Out<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0});
 }
 
 static bool isAlpha(char C) {

Added: lld/trunk/test/elf2/Inputs/merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/Inputs/merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/Inputs/merge.s (added)
+++ lld/trunk/test/elf2/Inputs/merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,6 @@
+        .section        .mysec,"aM", at progbits,4
+        .align  4
+        .long   0x42
+
+        .text
+        movl .mysec, %eax

Added: lld/trunk/test/elf2/merge-invalid-size.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/merge-invalid-size.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/merge-invalid-size.s (added)
+++ lld/trunk/test/elf2/merge-invalid-size.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: SHF_MERGE section size must be a multiple of sh_entsize
+
+        .section	.foo,"aM", at progbits,4
+        .short 42

Added: lld/trunk/test/elf2/merge-shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/merge-shared.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/merge-shared.s (added)
+++ lld/trunk/test/elf2/merge-shared.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld2 %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+	.section	foo,"aM", at progbits,4
+        .long 42
+        .long 42
+
+        .text
+        .quad foo + 6
+
+
+// CHECK:      Name: foo (20)
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x158
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x{{.*}} R_X86_64_RELATIVE - 0x15A
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]

Added: lld/trunk/test/elf2/merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/merge.s (added)
+++ lld/trunk/test/elf2/merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,109 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/merge.s -o %t2.o
+// RUN: ld.lld2 %t.o %t2.o -o %t
+// RUN: llvm-readobj -s -section-data -t %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+        .section        .mysec,"aM", at progbits,4
+        .align  4
+        .global foo
+        .hidden foo
+        .long   0x10
+foo:
+        .long   0x42
+bar:
+        .long   0x42
+zed:
+        .long   0x42
+
+// CHECK:      Name: .mysec
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT:    Flags [
+// CHECK-NEXT:      SHF_ALLOC
+// CHECK-NEXT:      SHF_MERGE
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x100E8
+// CHECK-NEXT:    Offset: 0xE8
+// CHECK-NEXT:    Size: 8
+// CHECK-NEXT:    Link: 0
+// CHECK-NEXT:    Info: 0
+// CHECK-NEXT:    AddressAlignment: 4
+// CHECK-NEXT:    EntrySize: 0
+// CHECK-NEXT:    SectionData (
+// CHECK-NEXT:      0000: 10000000 42000000
+// CHECK-NEXT:    )
+
+
+// Address of the constant 0x10 = 0x100E8 = 65768
+// Address of the constant 0x42 = 0x100EC = 65772
+
+// CHECK:      Symbols [
+
+// CHECK:        Name: bar
+// CHECK-NEXT:   Value: 0x100EC
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Loca
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .mysec
+
+// CHECK:        Name: zed
+// CHECK-NEXT:   Value: 0x100EC
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 0
+// CHECK-NEXT:   Section: .mysec
+
+// CHECK:        Name: foo
+// CHECK-NEXT:   Value: 0x100EC
+// CHECK-NEXT:   Size: 0
+// CHECK-NEXT:   Binding: Local
+// CHECK-NEXT:   Type: None
+// CHECK-NEXT:   Other: 2
+// CHECK-NEXT:   Section: .mysec
+
+ // CHECK: ]
+
+        .text
+        .globl  _start
+_start:
+// DISASM:      Disassembly of section .text:
+// DISASM-NEXT: _start:
+
+        movl .mysec, %eax
+// addr(0x10) = 65768
+// DISASM-NEXT:   movl    65768, %eax
+
+        movl .mysec+7, %eax
+// addr(0x42) + 3 = 65772 + 3 = 65775
+// DISASM-NEXT:   movl    65775, %eax
+
+        movl .mysec+8, %eax
+// addr(0x42) = 65772
+// DISASM-NEXT:   movl    65772, %eax
+
+        movl bar+7, %eax
+// addr(0x42) + 7 = 65772 + 7 = 65779
+// DISASM-NEXT:   movl    65779, %eax
+
+        movl bar+8, %eax
+// addr(0x42) + 8 = 65772 + 8 = 65780
+// DISASM-NEXT:   movl    65780, %eax
+
+        movl foo, %eax
+// addr(0x42) = 65772
+// DISASM-NEXT:   movl    65772, %eax
+
+        movl foo+7, %eax
+// addr(0x42) + 7 =  = 65772 + 7 = 65779
+// DISASM-NEXT:   movl    65779, %eax
+
+        movl foo+8, %eax
+// addr(0x42) + 8 =  = 65772 + 8 = 65780
+// DISASM-NEXT:   movl    65780, %eax
+
+//  From the other file:  movl .mysec, %eax
+// addr(0x42) = 65772
+// DISASM-NEXT:   movl    65772, %eax

Added: lld/trunk/test/elf2/relocation-in-merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation-in-merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/relocation-in-merge.s (added)
+++ lld/trunk/test/elf2/relocation-in-merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: Relocations pointing to SHF_MERGE are not supported
+
+        .section	.foo,"aM", at progbits,4
+        .long bar

Added: lld/trunk/test/elf2/relocation-past-merge-end.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation-past-merge-end.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/relocation-past-merge-end.s (added)
+++ lld/trunk/test/elf2/relocation-past-merge-end.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t.so -shared 2>&1 | FileCheck %s
+// CHECK: Entry is past the end of the section
+
+        .long .foo + 1
+        .section	.foo,"aM", at progbits,4

Added: lld/trunk/test/elf2/writable-merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/writable-merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/writable-merge.s (added)
+++ lld/trunk/test/elf2/writable-merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,6 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: Writable SHF_MERGE sections are not supported
+
+        .section	.foo,"awM", at progbits,4




More information about the llvm-commits mailing list