Read section headers upfront.
authorRafael Espindola <rafael.espindola@gmail.com>
Wed, 26 Oct 2016 00:54:03 +0000 (00:54 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Wed, 26 Oct 2016 00:54:03 +0000 (00:54 +0000)
Instead of storing a pointer, store the members we need.

The reason for doing this is that it makes it far easier to create
synthetic sections. It also avoids reading data from files multiple
times., which might help with cross endian linking and host
architectures with slow unaligned access.

There are obvious compacting opportunities, but this already has mixed
results even on native x86_64 linking.

There is also the possibility of better refactoring the code for
handling common symbols, but this already shows that a custom class is
not necessary.

llvm-svn: 285148

lld/ELF/InputSection.cpp
lld/ELF/InputSection.h
lld/ELF/LinkerScript.cpp
lld/ELF/OutputSections.cpp
lld/ELF/Symbols.cpp
lld/ELF/Writer.cpp

index 81f3cea..d407be4 100644 (file)
@@ -33,28 +33,31 @@ template <class ELFT>
 static ArrayRef<uint8_t> getSectionContents(elf::ObjectFile<ELFT> *File,
                                             const typename ELFT::Shdr *Hdr) {
   if (!File || Hdr->sh_type == SHT_NOBITS)
-    return {};
+    return makeArrayRef<uint8_t>(nullptr, Hdr->sh_size);
   return check(File->getObj().getSectionContents(Hdr));
 }
 
 // ELF supports ZLIB-compressed section. Returns true if the section
 // is compressed.
 template <class ELFT>
-static bool isCompressed(const typename ELFT::Shdr *Hdr, StringRef Name) {
-  return (Hdr->sh_flags & SHF_COMPRESSED) || Name.startswith(".zdebug");
+static bool isCompressed(typename ELFT::uint Flags, StringRef Name) {
+  return (Flags & SHF_COMPRESSED) || Name.startswith(".zdebug");
 }
 
 template <class ELFT>
 InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
-                                         const Elf_Shdr *Hdr, StringRef Name,
+                                         uintX_t Flags, uint32_t Type,
+                                         uintX_t Entsize, uint32_t Link,
+                                         uint32_t Info, uintX_t Addralign,
+                                         ArrayRef<uint8_t> Data, StringRef Name,
                                          Kind SectionKind)
-    : InputSectionData(SectionKind, Name, getSectionContents(File, Hdr),
-                       isCompressed<ELFT>(Hdr, Name),
-                       !Config->GcSections || !(Hdr->sh_flags & SHF_ALLOC)),
-      Header(Hdr), File(File), Repl(this) {
+    : InputSectionData(SectionKind, Name, Data, isCompressed<ELFT>(Flags, Name),
+                       !Config->GcSections || !(Flags & SHF_ALLOC)),
+      File(File), Flags(Flags), Entsize(Entsize), Type(Type), Link(Link),
+      Info(Info), Repl(this) {
   // The ELF spec states that a value of 0 means the section has
   // no alignment constraits.
-  uint64_t V = std::max<uint64_t>(Hdr->sh_addralign, 1);
+  uint64_t V = std::max<uint64_t>(Addralign, 1);
   if (!isPowerOf2_64(V))
     fatal(getFilename(File) + ": section sh_addralign is not a power of 2");
 
@@ -66,11 +69,19 @@ InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
   Alignment = V;
 }
 
+template <class ELFT>
+InputSectionBase<ELFT>::InputSectionBase(elf::ObjectFile<ELFT> *File,
+                                         const Elf_Shdr *Hdr, StringRef Name,
+                                         Kind SectionKind)
+    : InputSectionBase(File, Hdr->sh_flags, Hdr->sh_type, Hdr->sh_entsize,
+                       Hdr->sh_link, Hdr->sh_info, Hdr->sh_addralign,
+                       getSectionContents(File, Hdr), Name, SectionKind) {}
+
 template <class ELFT> size_t InputSectionBase<ELFT>::getSize() const {
   if (auto *D = dyn_cast<InputSection<ELFT>>(this))
     if (D->getThunksSize() > 0)
       return D->getThunkOff() + D->getThunksSize();
-  return Header->sh_size;
+  return Data.size();
 }
 
 // Returns a string for an error message.
@@ -177,6 +188,13 @@ InputSectionBase<ELFT> *InputSectionBase<ELFT>::getLinkOrderDep() const {
 }
 
 template <class ELFT>
+InputSection<ELFT>::InputSection(uintX_t Flags, uint32_t Type,
+                                 uintX_t Addralign, ArrayRef<uint8_t> Data)
+    : InputSectionBase<ELFT>(nullptr, Flags, Type,
+                             /*Entsize*/ 0, /*Link*/ 0, /*Info*/ 0, Addralign,
+                             Data, "", Base::Regular) {}
+
+template <class ELFT>
 InputSection<ELFT>::InputSection(elf::ObjectFile<ELFT> *F,
                                  const Elf_Shdr *Header, StringRef Name)
     : InputSectionBase<ELFT>(F, Header, Name, Base::Regular) {}
@@ -198,7 +216,7 @@ template <class ELFT> void InputSection<ELFT>::addThunk(const Thunk<ELFT> *T) {
 }
 
 template <class ELFT> uint64_t InputSection<ELFT>::getThunkOff() const {
-  return this->Header->sh_size;
+  return this->Data.size();
 }
 
 template <class ELFT> uint64_t InputSection<ELFT>::getThunksSize() const {
@@ -458,15 +476,14 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd) {
 template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
   if (this->getType() == SHT_NOBITS)
     return;
-  ELFFile<ELFT> &EObj = this->File->getObj();
 
   // If -r is given, then an InputSection may be a relocation section.
   if (this->getType() == SHT_RELA) {
-    copyRelocations(Buf + OutSecOff, EObj.relas(this->Header));
+    copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rela>());
     return;
   }
   if (this->getType() == SHT_REL) {
-    copyRelocations(Buf + OutSecOff, EObj.rels(this->Header));
+    copyRelocations(Buf + OutSecOff, this->template getDataAs<Elf_Rel>());
     return;
   }
 
@@ -804,27 +821,28 @@ bool MipsAbiFlagsInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
 }
 
 template <class ELFT>
-CommonInputSection<ELFT>::CommonInputSection(std::vector<DefinedCommon *> Syms)
-    : InputSection<ELFT>(nullptr, &Hdr, "") {
-  Hdr.sh_size = 0;
-  Hdr.sh_type = SHT_NOBITS;
-  Hdr.sh_flags = SHF_ALLOC | SHF_WRITE;
-  this->Live = true;
-
+InputSection<ELFT> InputSection<ELFT>::createCommonInputSection(
+    std::vector<DefinedCommon *> Syms) {
   // Sort the common symbols by alignment as an heuristic to pack them better.
   std::stable_sort(Syms.begin(), Syms.end(),
                    [](const DefinedCommon *A, const DefinedCommon *B) {
                      return A->Alignment > B->Alignment;
                    });
 
+  size_t Size = 0;
+  uintX_t Alignment = 1;
   for (DefinedCommon *Sym : Syms) {
-    this->Alignment = std::max<uintX_t>(this->Alignment, Sym->Alignment);
-    Hdr.sh_size = alignTo(Hdr.sh_size, Sym->Alignment);
+    Alignment = std::max<uintX_t>(Alignment, Sym->Alignment);
+    Size = alignTo(Size, Sym->Alignment);
 
     // Compute symbol offset relative to beginning of input section.
-    Sym->Offset = Hdr.sh_size;
-    Hdr.sh_size += Sym->Size;
+    Sym->Offset = Size;
+    Size += Sym->Size;
   }
+  ArrayRef<uint8_t> Data = makeArrayRef<uint8_t>(nullptr, Size);
+  InputSection Ret(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Data);
+  Ret.Live = true;
+  return Ret;
 }
 
 template class elf::InputSectionBase<ELF32LE>;
@@ -861,8 +879,3 @@ template class elf::MipsAbiFlagsInputSection<ELF32LE>;
 template class elf::MipsAbiFlagsInputSection<ELF32BE>;
 template class elf::MipsAbiFlagsInputSection<ELF64LE>;
 template class elf::MipsAbiFlagsInputSection<ELF64BE>;
-
-template class elf::CommonInputSection<ELF32LE>;
-template class elf::CommonInputSection<ELF32BE>;
-template class elf::CommonInputSection<ELF64LE>;
-template class elf::CommonInputSection<ELF64BE>;
index 3ff3531..40ae21e 100644 (file)
@@ -60,6 +60,12 @@ public:
   StringRef Name;
   ArrayRef<uint8_t> Data;
 
+  template <typename T> llvm::ArrayRef<T> getDataAs() const {
+    size_t S = Data.size();
+    assert(S % sizeof(T) == 0);
+    return llvm::makeArrayRef<T>((const T *)Data.data(), S / sizeof(T));
+  }
+
   // If a section is compressed, this has the uncompressed section data.
   std::unique_ptr<uint8_t[]> UncompressedData;
 
@@ -75,11 +81,17 @@ protected:
   typedef typename ELFT::Shdr Elf_Shdr;
   typedef typename ELFT::Sym Elf_Sym;
   typedef typename ELFT::uint uintX_t;
-  const Elf_Shdr *Header;
 
   // The file this section is from.
   ObjectFile<ELFT> *File;
 
+  // These corresponds to the fields in Elf_Shdr.
+  uintX_t Flags;
+  uintX_t Entsize;
+  uint32_t Type;
+  uint32_t Link;
+  uint32_t Info;
+
 public:
   InputSectionBase()
       : InputSectionData(Regular, "", ArrayRef<uint8_t>(), false, false),
@@ -87,6 +99,10 @@ public:
 
   InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
                    StringRef Name, Kind SectionKind);
+  InputSectionBase(ObjectFile<ELFT> *File, uintX_t Flags, uint32_t Type,
+                   uintX_t Entsize, uint32_t Link, uint32_t Info,
+                   uintX_t Addralign, ArrayRef<uint8_t> Data, StringRef Name,
+                   Kind SectionKind);
   OutputSectionBase<ELFT> *OutSec = nullptr;
 
   // This pointer points to the "real" instance of this instance.
@@ -101,11 +117,11 @@ public:
 
   static InputSectionBase<ELFT> Discarded;
 
-  uintX_t getFlags() const { return Header->sh_flags; }
-  uint32_t getType() const { return Header->sh_type; }
-  uintX_t getEntsize() const { return Header->sh_entsize; }
-  uint32_t getLink() const { return Header->sh_link; }
-  uint32_t getInfo() const { return Header->sh_info; }
+  uintX_t getFlags() const { return Flags; }
+  uint32_t getType() const { return Type; }
+  uintX_t getEntsize() const { return Entsize; }
+  uint32_t getLink() const { return Link; }
+  uint32_t getInfo() const { return Info; }
   ObjectFile<ELFT> *getFile() const { return File; }
   uintX_t getOffset(const DefinedRegular<ELFT> &Sym) const;
   InputSectionBase *getLinkOrderDep() const;
@@ -225,6 +241,8 @@ template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
   typedef typename ELFT::uint uintX_t;
 
 public:
+  InputSection(uintX_t Flags, uint32_t Type, uintX_t Addralign,
+               ArrayRef<uint8_t> Data);
   InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header, StringRef Name);
 
   // Write this section to a mmap'ed file, assuming Buf is pointing to
@@ -259,6 +277,14 @@ public:
   template <class RelTy>
   void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
 
+  // Common symbols don't belong to any section. But it is easier for us
+  // to handle them as if they belong to some input section. So we defined
+  // this section that "contains" all common symbols.
+  static InputSection<ELFT> *CommonInputSection;
+
+  static InputSection<ELFT>
+  createCommonInputSection(std::vector<DefinedCommon *> Syms);
+
 private:
   template <class RelTy>
   void copyRelocations(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
@@ -272,6 +298,9 @@ private:
   llvm::TinyPtrVector<const Thunk<ELFT> *> Thunks;
 };
 
+template <class ELFT>
+InputSection<ELFT> *InputSection<ELFT>::CommonInputSection;
+
 // MIPS .reginfo section provides information on the registers used by the code
 // in the object file. Linker should collect this information and write a single
 // .reginfo section in the output file. The output section contains a union of
@@ -314,26 +343,6 @@ public:
   const llvm::object::Elf_Mips_ABIFlags<ELFT> *Flags = nullptr;
 };
 
-// Common symbols don't belong to any section. But it is easier for us
-// to handle them as if they belong to some input section. So we defined
-// this class. CommonInputSection is a virtual singleton class that
-// "contains" all common symbols.
-template <class ELFT> class CommonInputSection : public InputSection<ELFT> {
-  typedef typename ELFT::uint uintX_t;
-
-public:
-  CommonInputSection(std::vector<DefinedCommon *> Syms);
-
-  // The singleton instance of this class.
-  static CommonInputSection<ELFT> *X;
-
-private:
-  static typename ELFT::Shdr Hdr;
-};
-
-template <class ELFT> CommonInputSection<ELFT> *CommonInputSection<ELFT>::X;
-template <class ELFT> typename ELFT::Shdr CommonInputSection<ELFT>::Hdr;
-
 } // namespace elf
 } // namespace lld
 
index 5fd49eb..ed6dd69 100644 (file)
@@ -184,7 +184,7 @@ void LinkerScript<ELFT>::computeInputSections(InputSectionDescription *I) {
         if (!isDiscarded(S) && !S->OutSec && Pat.SectionRe.match(S->Name))
           I->Sections.push_back(S);
       if (Pat.SectionRe.match("COMMON"))
-        I->Sections.push_back(CommonInputSection<ELFT>::X);
+        I->Sections.push_back(InputSection<ELFT>::CommonInputSection);
     }
 
     // Sort sections as instructed by SORT-family commands and --sort-section
index e38de2e..0bbd4ed 100644 (file)
@@ -1565,7 +1565,7 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
     break;
   }
   case SymbolBody::DefinedCommonKind:
-    return CommonInputSection<ELFT>::X->OutSec;
+    return InputSection<ELFT>::CommonInputSection->OutSec;
   case SymbolBody::SharedKind:
     if (cast<SharedSymbol<ELFT>>(Sym)->needsCopy())
       return Out<ELFT>::Bss;
index 707143e..f59132a 100644 (file)
@@ -69,8 +69,8 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
     return VA;
   }
   case SymbolBody::DefinedCommonKind:
-    return CommonInputSection<ELFT>::X->OutSec->getVA() +
-           CommonInputSection<ELFT>::X->OutSecOff +
+    return InputSection<ELFT>::CommonInputSection->OutSec->getVA() +
+           InputSection<ELFT>::CommonInputSection->OutSecOff +
            cast<DefinedCommon>(Body).Offset;
   case SymbolBody::SharedKind: {
     auto &SS = cast<SharedSymbol<ELFT>>(Body);
index 037d4d9..7d54c15 100644 (file)
@@ -261,8 +261,9 @@ template <class ELFT> void Writer<ELFT>::run() {
   if (Target->NeedsThunks)
     forEachRelSec(createThunks<ELFT>);
 
-  CommonInputSection<ELFT> Common(getCommonSymbols<ELFT>());
-  CommonInputSection<ELFT>::X = &Common;
+  InputSection<ELFT> Common =
+      InputSection<ELFT>::createCommonInputSection(getCommonSymbols<ELFT>());
+  InputSection<ELFT>::CommonInputSection = &Common;
 
   Script<ELFT>::X->OutputSections = &OutputSections;
   if (ScriptConfig->HasSections) {
@@ -825,8 +826,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
 
   // If linker script processor hasn't added common symbol section yet,
   // then add it to .bss now.
-  if (!CommonInputSection<ELFT>::X->OutSec) {
-    Out<ELFT>::Bss->addSection(CommonInputSection<ELFT>::X);
+  if (!InputSection<ELFT>::CommonInputSection->OutSec) {
+    Out<ELFT>::Bss->addSection(InputSection<ELFT>::CommonInputSection);
     Out<ELFT>::Bss->assignOffsets();
   }