[lld] r234934 - ELF: Split SegmentChunks.h to SegmentChunks.{h,cpp}.

Rui Ueyama ruiu at google.com
Tue Apr 14 13:12:50 PDT 2015


Author: ruiu
Date: Tue Apr 14 15:12:50 2015
New Revision: 234934

URL: http://llvm.org/viewvc/llvm-project?rev=234934&view=rev
Log:
ELF: Split SegmentChunks.h to SegmentChunks.{h,cpp}.

Added:
    lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp
      - copied, changed from r234932, lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h
Modified:
    lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt
    lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h

Modified: lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt?rev=234934&r1=234933&r2=234934&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt (original)
+++ lld/trunk/lib/ReaderWriter/ELF/CMakeLists.txt Tue Apr 14 15:12:50 2015
@@ -7,6 +7,7 @@ add_llvm_library(lldELF
   OutputELFWriter.cpp
   Reader.cpp
   SectionChunks.cpp
+  SegmentChunks.cpp
   TargetLayout.cpp
   Writer.cpp
   LINK_LIBS

Copied: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp (from r234932, lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h)
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp?p2=lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp&p1=lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h&r1=234932&r2=234934&rev=234934&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp Tue Apr 14 15:12:50 2015
@@ -7,310 +7,17 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
-#define LLD_READER_WRITER_ELF_SEGMENT_CHUNKS_H
-
-#include "Chunk.h"
-#include "SectionChunks.h"
-#include "Writer.h"
-#include "lld/Core/range.h"
-#include "lld/Core/Writer.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/ELF.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include <memory>
+#include "SegmentChunks.h"
+#include "TargetLayout.h"
 
 namespace lld {
 namespace elf {
 
-template <typename ELFT> class TargetLayout;
-
-/// \brief A segment can be divided into segment slices
-///        depending on how the segments can be split
-template<class ELFT>
-class SegmentSlice {
-public:
-  typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
-
-  /// Set the start of the slice.
-  void setStart(int32_t s) { _startSection = s; }
-
-  // Set the segment slice start and end iterators. This is used to walk through
-  // the sections that are part of the Segment slice
-  void setSections(range<SectionIter> sections) { _sections = sections; }
-
-  // Return the fileOffset of the slice
-  uint64_t fileOffset() const { return _offset; }
-  void setFileOffset(uint64_t offset) { _offset = offset; }
-
-  // Return the size of the slice
-  uint64_t fileSize() const { return _fsize; }
-  void setFileSize(uint64_t filesz) { _fsize = filesz; }
-
-  // Return the start of the slice
-  int32_t startSection() const { return _startSection; }
-
-  // Return the start address of the slice
-  uint64_t virtualAddr() const { return _addr; }
-
-  // Return the memory size of the slice
-  uint64_t memSize() const { return _memSize; }
-
-  // Return the alignment of the slice
-  uint64_t alignment() const { return _alignment; }
-
-  void setMemSize(uint64_t memsz) { _memSize = memsz; }
-
-  void setVirtualAddr(uint64_t addr) { _addr = addr; }
-
-  void setAlign(uint64_t align) { _alignment = align; }
-
-  static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b) {
-    return a->startSection() < b->startSection();
-  }
-
-  range<SectionIter> sections() { return _sections; }
-
-private:
-  range<SectionIter> _sections;
-  int32_t _startSection;
-  uint64_t _addr;
-  uint64_t _offset;
-  uint64_t _alignment;
-  uint64_t _fsize;
-  uint64_t _memSize;
-};
-
-/// \brief A segment contains a set of sections, that have similar properties
-//  the sections are already separated based on different flags and properties
-//  the segment is just a way to concatenate sections to segments
-template<class ELFT>
-class Segment : public Chunk<ELFT> {
-public:
-  typedef typename std::vector<SegmentSlice<ELFT> *>::iterator SliceIter;
-  typedef typename std::vector<Chunk<ELFT> *>::iterator SectionIter;
-
-  Segment(const ELFLinkingContext &ctx, StringRef name,
-          const typename TargetLayout<ELFT>::SegmentType type);
-
-  /// \brief the Order of segments that appear in the output file
-  enum SegmentOrder {
-    permUnknown,
-    permRWX,
-    permRX,
-    permR,
-    permRWL,
-    permRW,
-    permNonAccess
-  };
-
-  /// append a section to a segment
-  virtual void append(Chunk<ELFT> *chunk);
-
-  /// Sort segments depending on the property
-  /// If we have a Program Header segment, it should appear first
-  /// If we have a INTERP segment, that should appear after the Program Header
-  /// All Loadable segments appear next in this order
-  /// All Read Write Execute segments follow
-  /// All Read Execute segments appear next
-  /// All Read only segments appear first
-  /// All Write execute segments follow
-  static bool compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb);
-
-  /// \brief Start assigning file offset to the segment chunks The fileoffset
-  /// needs to be page at the start of the segment and in addition the
-  /// fileoffset needs to be aligned to the max section alignment within the
-  /// segment. This is required so that the ELF property p_poffset % p_align =
-  /// p_vaddr mod p_align holds true.
-  /// The algorithm starts off by assigning the startOffset thats passed in as
-  /// parameter to the first section in the segment, if the difference between
-  /// the newly computed offset is greater than a page, then we create a segment
-  /// slice, as it would be a waste of virtual memory just to be filled with
-  /// zeroes
-  void assignFileOffsets(uint64_t startOffset);
-
-  /// \brief Assign virtual addresses to the slices
-  void assignVirtualAddress(uint64_t addr);
-
-  // Write the Segment
-  void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
-             llvm::FileOutputBuffer &buffer);
-
-  int64_t flags() const;
-
-  /// Prepend a generic chunk to the segment.
-  void prepend(Chunk<ELFT> *c) {
-    _sections.insert(_sections.begin(), c);
-  }
-
-  /// Finalize the segment before assigning File Offsets / Virtual addresses
-
-  /// Finalize the segment, before we want to write the segment header
-  /// information
-  void finalize() {
-    // We want to finalize the segment values for now only for non loadable
-    // segments, since those values are not set in the Layout
-    if (_segmentType == llvm::ELF::PT_LOAD)
-      return;
-    // The size is the difference of the
-    // last section to the first section, especially for TLS because
-    // the TLS segment contains both .tdata/.tbss
-    this->setFileOffset(_sections.front()->fileOffset());
-    this->setVirtualAddr(_sections.front()->virtualAddr());
-    size_t startFileOffset = _sections.front()->fileOffset();
-    size_t startAddr = _sections.front()->virtualAddr();
-    for (auto ai : _sections) {
-      this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
-      this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
-    }
-  }
-
-  // For LLVM RTTI
-  static bool classof(const Chunk<ELFT> *c) {
-    return c->kind() == Chunk<ELFT>::Kind::ELFSegment;
-  }
-
-  // Getters
-  int32_t sectionCount() const { return _sections.size(); }
-
-  /// \brief, this function returns the type of segment (PT_*)
-  typename TargetLayout<ELFT>::SegmentType segmentType() {
-    return _segmentType;
-  }
-
-  /// \brief return the segment type depending on the content,
-  /// If the content corresponds to Code, this will return Segment::Code
-  /// If the content corresponds to Data, this will return Segment::Data
-  /// If the content corresponds to TLS, this will return Segment::TLS
-  virtual int getContentType() const {
-    int64_t fl = flags();
-    switch (_segmentType) {
-    case llvm::ELF::PT_LOAD: {
-      if (fl && llvm::ELF::PF_X)
-        return Chunk<ELFT>::ContentType::Code;
-      if (fl && llvm::ELF::PF_W)
-        return Chunk<ELFT>::ContentType::Data;
-    }
-    case llvm::ELF::PT_TLS:
-      return Chunk<ELFT>::ContentType::TLS;
-    case llvm::ELF::PT_NOTE:
-      return Chunk<ELFT>::ContentType::Note;
-    default:
-      return Chunk<ELFT>::ContentType::Unknown;
-    }
-  }
-
-  int pageSize() const { return this->_ctx.getPageSize(); }
-
-  int rawflags() const { return _atomflags; }
-
-  int64_t atomflags() const {
-    switch (_atomflags) {
-    case DefinedAtom::permUnknown:
-      return permUnknown;
-    case DefinedAtom::permRWX:
-      return permRWX;
-    case DefinedAtom::permR_X:
-      return permRX;
-    case DefinedAtom::permR__:
-      return permR;
-    case DefinedAtom::permRW_L:
-      return permRWL;
-    case DefinedAtom::permRW_:
-      return permRW;
-    case DefinedAtom::perm___:
-    default:
-      return permNonAccess;
-    }
-  }
-
-  int64_t numSlices() const { return _segmentSlices.size(); }
-
-  range<SliceIter> slices() { return _segmentSlices; }
-
-  Chunk<ELFT> *firstSection() { return _sections[0]; }
-
-private:
-
-  /// \brief Check if the chunk needs to be aligned
-  bool needAlign(Chunk<ELFT> *chunk) const {
-    if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
-        _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
-      return true;
-    return false;
-  }
-
-  // Cached value of outputMagic
-  ELFLinkingContext::OutputMagic _outputMagic;
-
-protected:
-  /// \brief Section or some other chunk type.
-  std::vector<Chunk<ELFT> *> _sections;
-  std::vector<SegmentSlice<ELFT> *> _segmentSlices;
-  typename TargetLayout<ELFT>::SegmentType _segmentType;
-  uint64_t _flags;
-  int64_t _atomflags;
-  llvm::BumpPtrAllocator _segmentAllocate;
-};
-
-/// This chunk represents a linker script expression that needs to be calculated
-/// at the time the virtual addresses for the parent segment are being assigned.
-template <class ELFT> class ExpressionChunk : public Chunk<ELFT> {
-public:
-  ExpressionChunk(ELFLinkingContext &ctx, const script::SymbolAssignment *expr)
-      : Chunk<ELFT>(StringRef(), Chunk<ELFT>::Kind::Expression, ctx),
-        _expr(expr), _linkerScriptSema(ctx.linkerScriptSema()) {
-    this->_alignment = 1;
-  }
-
-  static bool classof(const Chunk<ELFT> *c) {
-    return c->kind() == Chunk<ELFT>::Kind::Expression;
-  }
-
-  int getContentType() const override {
-    return Chunk<ELFT>::ContentType::Unknown;
-  }
-
-  void write(ELFWriter *, TargetLayout<ELFT> &,
-             llvm::FileOutputBuffer &) override {}
-
-  std::error_code evalExpr(uint64_t &curPos) {
-    return _linkerScriptSema.evalExpr(_expr, curPos);
-  }
-
-private:
-  const script::SymbolAssignment *_expr;
-  script::Sema &_linkerScriptSema;
-};
-
-/// \brief A Program Header segment contains a set of chunks instead of sections
-/// The segment doesn't contain any slice
-template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {
-public:
-  ProgramHeaderSegment(const ELFLinkingContext &ctx)
-      : Segment<ELFT>(ctx, "PHDR", llvm::ELF::PT_PHDR) {
-    this->_alignment = 8;
-    this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
-  }
-
-  /// Finalize the segment, before we want to write the segment header
-  /// information
-  void finalize() {
-    // If the segment is of type Program Header, then the values fileOffset
-    // and the fileSize need to be picked up from the last section, the first
-    // section points to the ELF header and the second chunk points to the
-    // actual program headers
-    this->setFileOffset(this->_sections.back()->fileOffset());
-    this->setVirtualAddr(this->_sections.back()->virtualAddr());
-    this->_fsize = this->_sections.back()->fileSize();
-    this->_msize = this->_sections.back()->memSize();
-  }
-};
+template <class ELFT>
+bool SegmentSlice<ELFT>::compare_slices(SegmentSlice<ELFT> *a,
+                                        SegmentSlice<ELFT> *b) {
+  return a->startSection() < b->startSection();
+}
 
 template <class ELFT>
 Segment<ELFT>::Segment(const ELFLinkingContext &ctx, StringRef name,
@@ -504,7 +211,8 @@ template <class ELFT> void Segment<ELFT>
         isDataPageAlignedForNMagic = true;
       }
       // align the startOffset to the section alignment
-      uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
+      uint64_t newAddr =
+          llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
       // Handle linker script expressions, which *may update newAddr* if the
       // expression assigns to "."
       if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
@@ -569,11 +277,11 @@ template <class ELFT> void Segment<ELFT>
         auto sliceIter =
             std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
                          [startSection](SegmentSlice<ELFT> *s) -> bool {
-              return s->startSection() == startSection;
-            });
+                           return s->startSection() == startSection;
+                         });
         if (sliceIter == _segmentSlices.end()) {
           slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
-            SegmentSlice<ELFT>();
+              SegmentSlice<ELFT>();
           _segmentSlices.push_back(slice);
         } else {
           slice = (*sliceIter);
@@ -622,11 +330,11 @@ template <class ELFT> void Segment<ELFT>
   }
   auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
                                 [startSection](SegmentSlice<ELFT> *s) -> bool {
-    return s->startSection() == startSection;
-  });
+                                  return s->startSection() == startSection;
+                                });
   if (sliceIter == _segmentSlices.end()) {
     slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
-      SegmentSlice<ELFT>();
+        SegmentSlice<ELFT>();
     _segmentSlices.push_back(slice);
   } else {
     slice = (*sliceIter);
@@ -653,9 +361,7 @@ void Segment<ELFT>::write(ELFWriter *wri
       section->write(writer, layout, buffer);
 }
 
-template<class ELFT>
-int64_t
-Segment<ELFT>::flags() const {
+template <class ELFT> int64_t Segment<ELFT>::flags() const {
   int64_t fl = 0;
   if (_flags & llvm::ELF::SHF_ALLOC)
     fl |= llvm::ELF::PF_R;
@@ -665,7 +371,92 @@ Segment<ELFT>::flags() const {
     fl |= llvm::ELF::PF_X;
   return fl;
 }
+
+template <class ELFT> void Segment<ELFT>::finalize() {
+  // We want to finalize the segment values for now only for non loadable
+  // segments, since those values are not set in the Layout
+  if (_segmentType == llvm::ELF::PT_LOAD)
+    return;
+  // The size is the difference of the
+  // last section to the first section, especially for TLS because
+  // the TLS segment contains both .tdata/.tbss
+  this->setFileOffset(_sections.front()->fileOffset());
+  this->setVirtualAddr(_sections.front()->virtualAddr());
+  size_t startFileOffset = _sections.front()->fileOffset();
+  size_t startAddr = _sections.front()->virtualAddr();
+  for (auto ai : _sections) {
+    this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
+    this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
+  }
+}
+
+template <class ELFT> int Segment<ELFT>::getContentType() const {
+  int64_t fl = flags();
+  switch (_segmentType) {
+  case llvm::ELF::PT_LOAD: {
+    if (fl && llvm::ELF::PF_X)
+      return Chunk<ELFT>::ContentType::Code;
+    if (fl && llvm::ELF::PF_W)
+      return Chunk<ELFT>::ContentType::Data;
+  }
+  case llvm::ELF::PT_TLS:
+    return Chunk<ELFT>::ContentType::TLS;
+  case llvm::ELF::PT_NOTE:
+    return Chunk<ELFT>::ContentType::Note;
+  default:
+    return Chunk<ELFT>::ContentType::Unknown;
+  }
+}
+
+template <class ELFT> int64_t Segment<ELFT>::atomflags() const {
+  switch (_atomflags) {
+  case DefinedAtom::permUnknown:
+    return permUnknown;
+  case DefinedAtom::permRWX:
+    return permRWX;
+  case DefinedAtom::permR_X:
+    return permRX;
+  case DefinedAtom::permR__:
+    return permR;
+  case DefinedAtom::permRW_L:
+    return permRWL;
+  case DefinedAtom::permRW_:
+    return permRW;
+  case DefinedAtom::perm___:
+  default:
+    return permNonAccess;
+  }
+}
+
+/// \brief Check if the chunk needs to be aligned
+template <class ELFT> bool Segment<ELFT>::needAlign(Chunk<ELFT> *chunk) const {
+  if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
+      _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
+    return true;
+  return false;
+}
+
+template <class ELFT> void ProgramHeaderSegment<ELFT>::finalize() {
+  // If the segment is of type Program Header, then the values fileOffset
+  // and the fileSize need to be picked up from the last section, the first
+  // section points to the ELF header and the second chunk points to the
+  // actual program headers
+  this->setFileOffset(this->_sections.back()->fileOffset());
+  this->setVirtualAddr(this->_sections.back()->virtualAddr());
+  this->_fsize = this->_sections.back()->fileSize();
+  this->_msize = this->_sections.back()->memSize();
+}
+
+#define INSTANTIATE(klass)        \
+  template class klass<ELF32LE>;  \
+  template class klass<ELF32BE>;  \
+  template class klass<ELF64LE>;  \
+  template class klass<ELF64BE>;
+
+INSTANTIATE(ExpressionChunk);
+INSTANTIATE(ProgramHeaderSegment);
+INSTANTIATE(Segment);
+INSTANTIATE(SegmentSlice);
+
 } // end namespace elf
 } // end namespace lld
-
-#endif

Modified: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h?rev=234934&r1=234933&r2=234934&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h Tue Apr 14 15:12:50 2015
@@ -15,11 +15,9 @@
 #include "Writer.h"
 #include "lld/Core/range.h"
 #include "lld/Core/Writer.h"
-#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Object/ELF.h"
 #include "llvm/Support/Allocator.h"
-#include "llvm/Support/Debug.h"
 #include "llvm/Support/ELF.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FileOutputBuffer.h"
@@ -70,9 +68,7 @@ public:
 
   void setAlign(uint64_t align) { _alignment = align; }
 
-  static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b) {
-    return a->startSection() < b->startSection();
-  }
+  static bool compare_slices(SegmentSlice<ELFT> *a, SegmentSlice<ELFT> *b);
 
   range<SectionIter> sections() { return _sections; }
 
@@ -148,27 +144,9 @@ public:
     _sections.insert(_sections.begin(), c);
   }
 
-  /// Finalize the segment before assigning File Offsets / Virtual addresses
-
   /// Finalize the segment, before we want to write the segment header
   /// information
-  void finalize() {
-    // We want to finalize the segment values for now only for non loadable
-    // segments, since those values are not set in the Layout
-    if (_segmentType == llvm::ELF::PT_LOAD)
-      return;
-    // The size is the difference of the
-    // last section to the first section, especially for TLS because
-    // the TLS segment contains both .tdata/.tbss
-    this->setFileOffset(_sections.front()->fileOffset());
-    this->setVirtualAddr(_sections.front()->virtualAddr());
-    size_t startFileOffset = _sections.front()->fileOffset();
-    size_t startAddr = _sections.front()->virtualAddr();
-    for (auto ai : _sections) {
-      this->_fsize = ai->fileOffset() + ai->fileSize() - startFileOffset;
-      this->_msize = ai->virtualAddr() + ai->memSize() - startAddr;
-    }
-  }
+  void finalize();
 
   // For LLVM RTTI
   static bool classof(const Chunk<ELFT> *c) {
@@ -187,63 +165,18 @@ public:
   /// If the content corresponds to Code, this will return Segment::Code
   /// If the content corresponds to Data, this will return Segment::Data
   /// If the content corresponds to TLS, this will return Segment::TLS
-  virtual int getContentType() const {
-    int64_t fl = flags();
-    switch (_segmentType) {
-    case llvm::ELF::PT_LOAD: {
-      if (fl && llvm::ELF::PF_X)
-        return Chunk<ELFT>::ContentType::Code;
-      if (fl && llvm::ELF::PF_W)
-        return Chunk<ELFT>::ContentType::Data;
-    }
-    case llvm::ELF::PT_TLS:
-      return Chunk<ELFT>::ContentType::TLS;
-    case llvm::ELF::PT_NOTE:
-      return Chunk<ELFT>::ContentType::Note;
-    default:
-      return Chunk<ELFT>::ContentType::Unknown;
-    }
-  }
+  virtual int getContentType() const;
 
   int pageSize() const { return this->_ctx.getPageSize(); }
-
   int rawflags() const { return _atomflags; }
-
-  int64_t atomflags() const {
-    switch (_atomflags) {
-    case DefinedAtom::permUnknown:
-      return permUnknown;
-    case DefinedAtom::permRWX:
-      return permRWX;
-    case DefinedAtom::permR_X:
-      return permRX;
-    case DefinedAtom::permR__:
-      return permR;
-    case DefinedAtom::permRW_L:
-      return permRWL;
-    case DefinedAtom::permRW_:
-      return permRW;
-    case DefinedAtom::perm___:
-    default:
-      return permNonAccess;
-    }
-  }
-
+  int64_t atomflags() const;
   int64_t numSlices() const { return _segmentSlices.size(); }
-
   range<SliceIter> slices() { return _segmentSlices; }
-
   Chunk<ELFT> *firstSection() { return _sections[0]; }
 
 private:
-
   /// \brief Check if the chunk needs to be aligned
-  bool needAlign(Chunk<ELFT> *chunk) const {
-    if (chunk->getContentType() == Chunk<ELFT>::ContentType::Data &&
-        _outputMagic == ELFLinkingContext::OutputMagic::NMAGIC)
-      return true;
-    return false;
-  }
+  bool needAlign(Chunk<ELFT> *chunk) const;
 
   // Cached value of outputMagic
   ELFLinkingContext::OutputMagic _outputMagic;
@@ -300,371 +233,9 @@ public:
 
   /// Finalize the segment, before we want to write the segment header
   /// information
-  void finalize() {
-    // If the segment is of type Program Header, then the values fileOffset
-    // and the fileSize need to be picked up from the last section, the first
-    // section points to the ELF header and the second chunk points to the
-    // actual program headers
-    this->setFileOffset(this->_sections.back()->fileOffset());
-    this->setVirtualAddr(this->_sections.back()->virtualAddr());
-    this->_fsize = this->_sections.back()->fileSize();
-    this->_msize = this->_sections.back()->memSize();
-  }
+  void finalize();
 };
 
-template <class ELFT>
-Segment<ELFT>::Segment(const ELFLinkingContext &ctx, StringRef name,
-                       const typename TargetLayout<ELFT>::SegmentType type)
-    : Chunk<ELFT>(name, Chunk<ELFT>::Kind::ELFSegment, ctx), _segmentType(type),
-      _flags(0), _atomflags(0) {
-  this->_alignment = 1;
-  this->_fsize = 0;
-  _outputMagic = ctx.getOutputMagic();
-}
-
-// This function actually is used, but not in all instantiations of Segment.
-LLVM_ATTRIBUTE_UNUSED
-static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) {
-  switch (flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)) {
-  case SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR:
-    return DefinedAtom::permRWX;
-  case SHF_ALLOC | SHF_EXECINSTR:
-    return DefinedAtom::permR_X;
-  case SHF_ALLOC:
-    return DefinedAtom::permR__;
-  case SHF_ALLOC | SHF_WRITE:
-    return DefinedAtom::permRW_;
-  default:
-    return DefinedAtom::permUnknown;
-  }
-}
-
-template <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) {
-  _sections.push_back(chunk);
-  Section<ELFT> *section = dyn_cast<Section<ELFT>>(chunk);
-  if (!section)
-    return;
-  if (_flags < section->getFlags())
-    _flags |= section->getFlags();
-  if (_atomflags < toAtomPerms(_flags))
-    _atomflags = toAtomPerms(_flags);
-  if (this->_alignment < section->alignment())
-    this->_alignment = section->alignment();
-}
-
-template <class ELFT>
-bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
-  int64_t type1 = sega->segmentType();
-  int64_t type2 = segb->segmentType();
-
-  if (type1 == type2)
-    return sega->atomflags() < segb->atomflags();
-
-  // The single PT_PHDR segment is required to precede any loadable
-  // segment.  We simply make it always first.
-  if (type1 == llvm::ELF::PT_PHDR)
-    return true;
-  if (type2 == llvm::ELF::PT_PHDR)
-    return false;
-
-  // The single PT_INTERP segment is required to precede any loadable
-  // segment.  We simply make it always second.
-  if (type1 == llvm::ELF::PT_INTERP)
-    return true;
-  if (type2 == llvm::ELF::PT_INTERP)
-    return false;
-
-  // We then put PT_LOAD segments before any other segments.
-  if (type1 == llvm::ELF::PT_LOAD)
-    return true;
-  if (type2 == llvm::ELF::PT_LOAD)
-    return false;
-
-  // We put the PT_GNU_RELRO segment last, because that is where the
-  // dynamic linker expects to find it
-  if (type1 == llvm::ELF::PT_GNU_RELRO)
-    return false;
-  if (type2 == llvm::ELF::PT_GNU_RELRO)
-    return true;
-
-  // We put the PT_TLS segment last except for the PT_GNU_RELRO
-  // segment, because that is where the dynamic linker expects to find
-  if (type1 == llvm::ELF::PT_TLS)
-    return false;
-  if (type2 == llvm::ELF::PT_TLS)
-    return true;
-
-  // Otherwise compare the types to establish an arbitrary ordering.
-  // FIXME: Should figure out if we should just make all other types compare
-  // equal, but if so, we should probably do the same for atom flags and change
-  // users of this to use stable_sort.
-  return type1 < type2;
-}
-
-template <class ELFT>
-void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
-  uint64_t fileOffset = startOffset;
-  uint64_t curSliceFileOffset = fileOffset;
-  bool isDataPageAlignedForNMagic = false;
-  bool alignSegments = this->_ctx.alignSegments();
-  uint64_t p_align = this->_ctx.getPageSize();
-  uint64_t lastVirtualAddress = 0;
-
-  this->setFileOffset(startOffset);
-  for (auto &slice : slices()) {
-    bool isFirstSection = true;
-    for (auto section : slice->sections()) {
-      // Handle linker script expressions, which may change the offset
-      if (!isFirstSection)
-        if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(section))
-          fileOffset += expr->virtualAddr() - lastVirtualAddress;
-      // Align fileoffset to the alignment of the section.
-      fileOffset = llvm::RoundUpToAlignment(fileOffset, section->alignment());
-      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
-      // to a page boundary
-      if (isFirstSection &&
-          _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
-          _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC) {
-        // Align to a page only if the output is not
-        // OutputMagic::NMAGIC/OutputMagic::OMAGIC
-        if (alignSegments)
-          fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align);
-        else {
-          // Align according to ELF spec.
-          // in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
-          uint64_t virtualAddress = slice->virtualAddr();
-          Section<ELFT> *sect = dyn_cast<Section<ELFT>>(section);
-          if (sect && sect->isLoadableSection() &&
-              ((virtualAddress & (p_align - 1)) !=
-               (fileOffset & (p_align - 1))))
-            fileOffset = llvm::RoundUpToAlignment(fileOffset, p_align) +
-                         (virtualAddress % p_align);
-        }
-      } else if (!isDataPageAlignedForNMagic && needAlign(section)) {
-        fileOffset =
-            llvm::RoundUpToAlignment(fileOffset, this->_ctx.getPageSize());
-        isDataPageAlignedForNMagic = true;
-      }
-      if (isFirstSection) {
-        slice->setFileOffset(fileOffset);
-        isFirstSection = false;
-        curSliceFileOffset = fileOffset;
-      }
-      section->setFileOffset(fileOffset);
-      fileOffset += section->fileSize();
-      lastVirtualAddress = section->virtualAddr() + section->memSize();
-    }
-    slice->setFileSize(fileOffset - curSliceFileOffset);
-  }
-  this->setFileSize(fileOffset - startOffset);
-}
-
-/// \brief Assign virtual addresses to the slices
-template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
-  int startSection = 0;
-  int currSection = 0;
-  SectionIter startSectionIter;
-
-  // slice align is set to the max alignment of the chunks that are
-  // contained in the slice
-  uint64_t sliceAlign = 0;
-  // Current slice size
-  uint64_t curSliceSize = 0;
-  // Current Slice File Offset
-  uint64_t curSliceAddress = 0;
-
-  startSectionIter = _sections.begin();
-  startSection = 0;
-  bool isFirstSection = true;
-  bool isDataPageAlignedForNMagic = false;
-  uint64_t startAddr = addr;
-  SegmentSlice<ELFT> *slice = nullptr;
-  uint64_t tlsStartAddr = 0;
-  bool alignSegments = this->_ctx.alignSegments();
-  StringRef prevOutputSectionName = StringRef();
-
-  for (auto si = _sections.begin(); si != _sections.end(); ++si) {
-    // If this is first section in the segment, page align the section start
-    // address. The linker needs to align the data section to a page boundary
-    // only if NMAGIC is set.
-    if (isFirstSection) {
-      isFirstSection = false;
-      if (alignSegments &&
-          _outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
-          _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
-        // Align to a page only if the output is not
-        // OutputMagic::NMAGIC/OutputMagic::OMAGIC
-        startAddr =
-            llvm::RoundUpToAlignment(startAddr, this->_ctx.getPageSize());
-      else if (!isDataPageAlignedForNMagic && needAlign(*si)) {
-        // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
-        // Data to a page boundary.
-        startAddr =
-            llvm::RoundUpToAlignment(startAddr, this->_ctx.getPageSize());
-        isDataPageAlignedForNMagic = true;
-      }
-      // align the startOffset to the section alignment
-      uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->alignment());
-      // Handle linker script expressions, which *may update newAddr* if the
-      // expression assigns to "."
-      if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
-        expr->evalExpr(newAddr);
-      curSliceAddress = newAddr;
-      sliceAlign = (*si)->alignment();
-      (*si)->setVirtualAddr(curSliceAddress);
-
-      // Handle TLS.
-      if (auto section = dyn_cast<Section<ELFT>>(*si)) {
-        if (section->getSegmentType() == llvm::ELF::PT_TLS) {
-          tlsStartAddr =
-              llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
-          section->assignVirtualAddress(tlsStartAddr);
-          tlsStartAddr += (*si)->memSize();
-        } else {
-          section->assignVirtualAddress(newAddr);
-        }
-      }
-      // TBSS section is special in that it doesn't contribute to memory of any
-      // segment. If we see a tbss section, don't add memory size to addr The
-      // fileOffset is automatically taken care of since TBSS section does not
-      // end up using file size
-      if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS)
-        curSliceSize = (*si)->memSize();
-    } else {
-      uint64_t curAddr = curSliceAddress + curSliceSize;
-      if (!isDataPageAlignedForNMagic && needAlign(*si)) {
-        // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
-        // Data
-        // to a page boundary
-        curAddr = llvm::RoundUpToAlignment(curAddr, this->_ctx.getPageSize());
-        isDataPageAlignedForNMagic = true;
-      }
-      uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->alignment());
-      // Handle linker script expressions, which *may update newAddr* if the
-      // expression assigns to "."
-      if (auto expr = dyn_cast<ExpressionChunk<ELFT>>(*si))
-        expr->evalExpr(newAddr);
-      Section<ELFT> *sec = dyn_cast<Section<ELFT>>(*si);
-      StringRef curOutputSectionName;
-      if (sec)
-        curOutputSectionName = sec->outputSectionName();
-      else {
-        // If this is a linker script expression, propagate the name of the
-        // previous section instead
-        if (isa<ExpressionChunk<ELFT>>(*si))
-          curOutputSectionName = prevOutputSectionName;
-        else
-          curOutputSectionName = (*si)->name();
-      }
-      bool autoCreateSlice = true;
-      if (curOutputSectionName == prevOutputSectionName)
-        autoCreateSlice = false;
-      // If the newAddress computed is more than a page away, let's create
-      // a separate segment, so that memory is not used up while running.
-      // Dont create a slice, if the new section falls in the same output
-      // section as the previous section.
-      if (autoCreateSlice && ((newAddr - curAddr) > this->_ctx.getPageSize()) &&
-          (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
-           _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) {
-        auto sliceIter =
-            std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
-                         [startSection](SegmentSlice<ELFT> *s) -> bool {
-              return s->startSection() == startSection;
-            });
-        if (sliceIter == _segmentSlices.end()) {
-          slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
-            SegmentSlice<ELFT>();
-          _segmentSlices.push_back(slice);
-        } else {
-          slice = (*sliceIter);
-        }
-        slice->setStart(startSection);
-        slice->setSections(make_range(startSectionIter, si));
-        slice->setMemSize(curSliceSize);
-        slice->setAlign(sliceAlign);
-        slice->setVirtualAddr(curSliceAddress);
-        // Start new slice
-        curSliceAddress = newAddr;
-        (*si)->setVirtualAddr(curSliceAddress);
-        startSectionIter = si;
-        startSection = currSection;
-        if (auto section = dyn_cast<Section<ELFT>>(*si))
-          section->assignVirtualAddress(newAddr);
-        curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
-        sliceAlign = (*si)->alignment();
-      } else {
-        if (sliceAlign < (*si)->alignment())
-          sliceAlign = (*si)->alignment();
-        (*si)->setVirtualAddr(newAddr);
-        // Handle TLS.
-        if (auto section = dyn_cast<Section<ELFT>>(*si)) {
-          if (section->getSegmentType() == llvm::ELF::PT_TLS) {
-            tlsStartAddr =
-                llvm::RoundUpToAlignment(tlsStartAddr, (*si)->alignment());
-            section->assignVirtualAddress(tlsStartAddr);
-            tlsStartAddr += (*si)->memSize();
-          } else {
-            section->assignVirtualAddress(newAddr);
-          }
-        }
-        // TBSS section is special in that it doesn't contribute to memory of
-        // any segment. If we see a tbss section, don't add memory size to addr
-        // The fileOffset is automatically taken care of since TBSS section does
-        // not end up using file size.
-        if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS)
-          curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
-        else
-          curSliceSize = newAddr - curSliceAddress;
-      }
-      prevOutputSectionName = curOutputSectionName;
-    }
-    currSection++;
-  }
-  auto sliceIter = std::find_if(_segmentSlices.begin(), _segmentSlices.end(),
-                                [startSection](SegmentSlice<ELFT> *s) -> bool {
-    return s->startSection() == startSection;
-  });
-  if (sliceIter == _segmentSlices.end()) {
-    slice = new (_segmentAllocate.Allocate<SegmentSlice<ELFT>>())
-      SegmentSlice<ELFT>();
-    _segmentSlices.push_back(slice);
-  } else {
-    slice = (*sliceIter);
-  }
-  slice->setStart(startSection);
-  slice->setVirtualAddr(curSliceAddress);
-  slice->setMemSize(curSliceSize);
-  slice->setSections(make_range(startSectionIter, _sections.end()));
-  slice->setAlign(sliceAlign);
-
-  // Set the segment memory size and the virtual address.
-  this->setMemSize(curSliceAddress - startAddr + curSliceSize);
-  this->setVirtualAddr(curSliceAddress);
-  std::stable_sort(_segmentSlices.begin(), _segmentSlices.end(),
-                   SegmentSlice<ELFT>::compare_slices);
-}
-
-// Write the Segment
-template <class ELFT>
-void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
-                          llvm::FileOutputBuffer &buffer) {
-  for (auto slice : slices())
-    for (auto section : slice->sections())
-      section->write(writer, layout, buffer);
-}
-
-template<class ELFT>
-int64_t
-Segment<ELFT>::flags() const {
-  int64_t fl = 0;
-  if (_flags & llvm::ELF::SHF_ALLOC)
-    fl |= llvm::ELF::PF_R;
-  if (_flags & llvm::ELF::SHF_WRITE)
-    fl |= llvm::ELF::PF_W;
-  if (_flags & llvm::ELF::SHF_EXECINSTR)
-    fl |= llvm::ELF::PF_X;
-  return fl;
-}
 } // end namespace elf
 } // end namespace lld
 





More information about the llvm-commits mailing list