Add support for merging the contents of SHF_MERGE sections.
For now SHF_STRINGS are not supported.
llvm-svn: 250737
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 0ab85e4..55ecfef 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -22,8 +22,41 @@
 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 @@
 }
 
 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>;
 }
 }