[lld] r221233 - [ELF] Fix program headers.

Shankar Easwaran shankarke at gmail.com
Mon Nov 3 19:57:05 PST 2014


Author: shankare
Date: Mon Nov  3 21:57:04 2014
New Revision: 221233

URL: http://llvm.org/viewvc/llvm-project?rev=221233&view=rev
Log:
[ELF] Fix program headers.

The ELF writer creates a invalid binary for few cases with large filesize and
memory size for segments. This patch addresses the functionality and updates the
test. This patch also cleans up parts of the ELF writer for future enhancements
to support Linker scripts.

Modified:
    lld/trunk/lib/ReaderWriter/ELF/Chunk.h
    lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
    lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h
    lld/trunk/lib/ReaderWriter/ELF/Layout.h
    lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
    lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
    lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h
    lld/trunk/test/elf/phdr.test

Modified: lld/trunk/lib/ReaderWriter/ELF/Chunk.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Chunk.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Chunk.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Chunk.h Mon Nov  3 21:57:04 2014
@@ -52,9 +52,10 @@ public:
   StringRef name() const { return _name; }
   // Kind of chunk
   Kind kind() const { return _kind; }
-  uint64_t        fileSize() const { return _fsize; }
-  void            setAlign(uint64_t align) { _align2 = align; }
-  uint64_t        align2() const { return _align2; }
+  virtual uint64_t fileSize() const { return _fsize; }
+  virtual void setFileSize(uint64_t sz) { _fsize = sz; }
+  virtual void setAlign(uint64_t align) { _align2 = align; }
+  virtual uint64_t align2() const { return _align2; }
 
   // The ordinal value of the chunk
   uint64_t            ordinal() const { return _ordinal;}
@@ -66,8 +67,8 @@ public:
   uint64_t            fileOffset() const { return _fileoffset; }
   void               setFileOffset(uint64_t offset) { _fileoffset = offset; }
   // Output start address of the chunk
-  void               setVAddr(uint64_t start) { _start = start; }
-  uint64_t            virtualAddr() const { return _start; }
+  virtual void setVirtualAddr(uint64_t start) { _start = start; }
+  virtual uint64_t virtualAddr() const { return _start; }
   // Memory size of the chunk
   uint64_t memSize() const { return _msize; }
   void setMemSize(uint64_t msize) { _msize = msize; }

Modified: lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h Mon Nov  3 21:57:04 2014
@@ -215,9 +215,7 @@ public:
 
   void assignVirtualAddress() override;
 
-  void assignOffsetsForMiscSections();
-
-  void assignFileOffsets() override;
+  void assignFileOffsetsForMiscSections();
 
   /// Inline functions
   inline range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
@@ -734,32 +732,15 @@ template <class ELFT> void DefaultLayout
   }
 }
 
-template <class ELFT> void DefaultLayout<ELFT>::assignFileOffsets() {
-  // TODO: Do we want to give a chance for the targetHandlers
-  // to sort segments in an arbitrary order?
-  std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
-  int ordinal = 0;
-  // Compute the number of segments that might be needed, so that the
-  // size of the program header can be computed
-  uint64_t offset = 0;
-  for (auto si : _segments) {
-    si->setOrdinal(++ordinal);
-    // Don't assign offsets for segments that are not loadable
-    if (si->segmentType() != llvm::ELF::PT_LOAD)
-      continue;
-    si->assignOffsets(offset);
-    offset += si->fileSize();
-  }
-}
-
 template<class ELFT>
 void
 DefaultLayout<ELFT>::assignVirtualAddress() {
   if (_segments.empty())
     return;
 
+  std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
+
   uint64_t virtualAddress = _context.getBaseAddress();
-  ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();
 
   // HACK: This is a super dirty hack. The elf header and program header are
   // not part of a section, but we need them to be loaded at the base address
@@ -777,6 +758,7 @@ DefaultLayout<ELFT>::assignVirtualAddres
   firstLoadSegment->prepend(_programHeader);
   firstLoadSegment->prepend(_elfHeader);
   bool newSegmentHeaderAdded = true;
+  bool virtualAddressAssigned = false;
   while (true) {
     for (auto si : _segments) {
       si->finalize();
@@ -784,24 +766,10 @@ DefaultLayout<ELFT>::assignVirtualAddres
       if (si->segmentType() != llvm::ELF::PT_NULL)
         newSegmentHeaderAdded = _programHeader->addSegment(si);
     }
-    if (!newSegmentHeaderAdded)
+    if (!newSegmentHeaderAdded && virtualAddressAssigned)
       break;
-    uint64_t fileoffset = 0;
+    virtualAddressAssigned = true;
     uint64_t address = virtualAddress;
-    // Fix the offsets after adding the program header
-    for (auto &si : _segments) {
-      if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
-          (si->segmentType() != llvm::ELF::PT_NULL))
-        continue;
-      // Align the segment to a page boundary only if the output mode is
-      // not OutputMagic::NMAGIC/OutputMagic::OMAGIC
-      if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
-          outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
-        fileoffset =
-            llvm::RoundUpToAlignment(fileoffset, _context.getPageSize());
-      si->assignOffsets(fileoffset);
-      fileoffset = si->fileOffset() + si->fileSize();
-    }
     // start assigning virtual addresses
     for (auto &si : _segments) {
       if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
@@ -809,22 +777,19 @@ DefaultLayout<ELFT>::assignVirtualAddres
         continue;
 
       if (si->segmentType() == llvm::ELF::PT_NULL) {
-        // Handle Non allocatable sections.
-        uint64_t nonLoadableAddr = 0;
-        si->setVAddr(nonLoadableAddr);
-        si->assignVirtualAddress(nonLoadableAddr);
+        si->assignVirtualAddress(0 /*non loadable*/);
       } else {
-        si->setVAddr(virtualAddress);
-        // The first segment has the virtualAddress set to the base address as
-        // we have added the file header and the program header don't align the
-        // first segment to the pagesize
         si->assignVirtualAddress(address);
-        si->setMemSize(address - virtualAddress);
-        if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
-            outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
-          virtualAddress =
-              llvm::RoundUpToAlignment(address, _context.getPageSize());
       }
+      address = si->virtualAddr() + si->memSize();
+    }
+    uint64_t fileoffset = 0;
+    for (auto &si : _segments) {
+      if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
+          (si->segmentType() != llvm::ELF::PT_NULL))
+        continue;
+      si->assignFileOffsets(fileoffset);
+      fileoffset = si->fileOffset() + si->fileSize();
     }
     _programHeader->resetProgramHeaders();
   }
@@ -833,7 +798,7 @@ DefaultLayout<ELFT>::assignVirtualAddres
   for (auto &si : _sections) {
     section = dyn_cast<Section<ELFT>>(si);
     if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
-      section->assignOffsets(section->fileOffset());
+      section->assignFileOffsets(section->fileOffset());
   }
   // Set the size of the merged Sections
   for (auto msi : _mergedSections) {
@@ -873,9 +838,8 @@ DefaultLayout<ELFT>::assignVirtualAddres
   }
 }
 
-template<class ELFT>
-void
-DefaultLayout<ELFT>::assignOffsetsForMiscSections() {
+template <class ELFT>
+void DefaultLayout<ELFT>::assignFileOffsetsForMiscSections() {
   uint64_t fileoffset = 0;
   uint64_t size = 0;
   for (auto si : _segments) {
@@ -894,7 +858,7 @@ DefaultLayout<ELFT>::assignOffsetsForMis
       continue;
     fileoffset = llvm::RoundUpToAlignment(fileoffset, si->align2());
     si->setFileOffset(fileoffset);
-    si->setVAddr(0);
+    si->setVirtualAddr(0);
     fileoffset += si->fileSize();
   }
 }

Modified: lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h Mon Nov  3 21:57:04 2014
@@ -43,7 +43,7 @@ public:
   void e_shentsize(uint16_t shentsize) { _eh.e_shentsize = shentsize; }
   void e_shnum(uint16_t shnum)         { _eh.e_shnum = shnum; }
   void e_shstrndx(uint16_t shstrndx)   { _eh.e_shstrndx = shstrndx; }
-  uint64_t  fileSize()                 { return sizeof (Elf_Ehdr); }
+  uint64_t fileSize() const { return sizeof(Elf_Ehdr); }
 
   static inline bool classof(const Chunk<ELFT> *c) {
     return c->Kind() == Chunk<ELFT>::Kind::ELFHeader;
@@ -125,9 +125,7 @@ public:
 
   void resetProgramHeaders() { _phi = _ph.begin(); }
 
-  uint64_t  fileSize() {
-    return sizeof(Elf_Phdr) * _ph.size();
-  }
+  uint64_t fileSize() const { return sizeof(Elf_Phdr) * _ph.size(); }
 
   static inline bool classof(const Chunk<ELFT> *c) {
     return c->Kind() == Chunk<ELFT>::Kind::ProgramHeader;
@@ -271,7 +269,7 @@ public:
 
   void finalize() {}
 
-  inline uint64_t fileSize() { return sizeof(Elf_Shdr) * _sectionInfo.size(); }
+  uint64_t fileSize() const { return sizeof(Elf_Shdr) * _sectionInfo.size(); }
 
   inline uint64_t entsize() {
     return sizeof(Elf_Shdr);

Modified: lld/trunk/lib/ReaderWriter/ELF/Layout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Layout.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Layout.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Layout.h Mon Nov  3 21:57:04 2014
@@ -47,8 +47,6 @@ public:
   virtual void assignSectionsToSegments() = 0;
   /// associates a virtual address to the segment, section, and the atom
   virtual void assignVirtualAddress() = 0;
-  /// associates a file offset to the segment, section and the atom
-  virtual void assignFileOffsets() = 0;
 
 public:
   Layout() {}

Modified: lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/OutputELFWriter.h Mon Nov  3 21:57:04 2014
@@ -265,7 +265,7 @@ void OutputELFWriter<ELFT>::assignSectio
     if (!mergedSec->hasSegment())
       _shdrtab->appendSection(mergedSec);
   }
-  _layout.assignOffsetsForMiscSections();
+  _layout.assignFileOffsetsForMiscSections();
   for (auto sec : _layout.sections())
     if (auto section = dyn_cast<Section<ELFT>>(sec))
       if (!DefaultLayout<ELFT>::hasOutputSegment(section))
@@ -377,7 +377,6 @@ std::error_code OutputELFWriter<ELFT>::b
   // contained in them, in anyway the targets may want
   _layout.doPreFlight();
 
-  _layout.assignFileOffsets();
   _layout.assignVirtualAddress();
 
   // Finalize the default value of symbols that the linker adds

Modified: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h Mon Nov  3 21:57:04 2014
@@ -59,11 +59,10 @@ public:
   virtual bool isLoadableSection() const { return false; }
 
   /// \brief Assign file offsets starting at offset.
-  virtual void assignOffsets(uint64_t offset) {}
+  virtual void assignFileOffsets(uint64_t offset) {}
 
-  /// \brief Assign virtual addresses starting at addr. Addr is modified to be
-  /// the next available virtual address.
-  virtual void assignVirtualAddress(uint64_t &addr) {}
+  /// \brief Assign virtual addresses starting at addr.
+  virtual void assignVirtualAddress(uint64_t addr) {}
 
   uint64_t getFlags() const { return _flags; }
   uint64_t getEntSize() const { return _entSize; }
@@ -195,7 +194,7 @@ public:
   /// \brief Set the virtual address of each Atom in the Section. This
   /// routine gets called after the linker fixes up the virtual address
   /// of the section
-  virtual void assignVirtualAddress(uint64_t &addr) {
+  virtual void assignVirtualAddress(uint64_t addr) {
     for (auto &ai : _atoms) {
       ai->_virtualAddr = addr + ai->_fileOffset;
     }
@@ -203,7 +202,7 @@ public:
 
   /// \brief Set the file offset of each Atom in the section. This routine
   /// gets called after the linker fixes up the section offset
-  virtual void assignOffsets(uint64_t offset) {
+  virtual void assignFileOffsets(uint64_t offset) {
     for (auto &ai : _atoms) {
       ai->_fileOffset = offset + ai->_fileOffset;
     }

Modified: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h Mon Nov  3 21:57:04 2014
@@ -41,14 +41,8 @@ public:
 
   SegmentSlice() { }
 
-  /// Set the segment slice so that it begins at the offset specified
-  /// by file offset and set the start of the slice to be s and the end
-  /// of the slice to be e
-  void set(uint64_t fileoffset, int32_t s, int e) {
-    _startSection = s;
-    _endSection = e + 1;
-    _offset = fileoffset;
-  }
+  /// 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
@@ -59,8 +53,12 @@ public:
   // Return the fileOffset of the slice
   inline uint64_t fileOffset() const { return _offset; }
 
+  void setFileOffset(uint64_t offset) { _offset = offset; }
+
   // Return the size of the slice
-  inline uint64_t fileSize() const { return _size; }
+  inline uint64_t fileSize() const { return _fsize; }
+
+  void setFileSize(uint64_t filesz) { _fsize = filesz; }
 
   // Return the start of the slice
   inline int32_t startSection() const { return _startSection; }
@@ -74,11 +72,9 @@ public:
   // Return the alignment of the slice
   inline uint64_t align2() const { return _align2; }
 
-  inline void setSize(uint64_t sz) { _size = sz; }
-
   inline void setMemSize(uint64_t memsz) { _memSize = memsz; }
 
-  inline void setVAddr(uint64_t addr) { _addr = addr; }
+  inline void setVirtualAddr(uint64_t addr) { _addr = addr; }
 
   inline void setAlign(uint64_t align) { _align2 = align; }
 
@@ -91,13 +87,12 @@ public:
   }
 
 private:
-  int32_t _startSection;
-  int32_t _endSection;
   range<SectionIter> _sections;
+  int32_t _startSection;
   uint64_t _addr;
   uint64_t _offset;
-  uint64_t _size;
   uint64_t _align2;
+  uint64_t _fsize;
   uint64_t _memSize;
 };
 
@@ -151,10 +146,10 @@ public:
   /// 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 assignOffsets(uint64_t startOffset);
+  void assignFileOffsets(uint64_t startOffset);
 
   /// \brief Assign virtual addresses to the slices
-  void assignVirtualAddress(uint64_t &addr);
+  void assignVirtualAddress(uint64_t addr);
 
   // Write the Segment
   void write(ELFWriter *writer, TargetLayout<ELFT> &layout,
@@ -181,7 +176,7 @@ public:
     // last section to the first section, especially for TLS because
     // the TLS segment contains both .tdata/.tbss
     this->setFileOffset(_sections.front()->fileOffset());
-    this->setVAddr(_sections.front()->virtualAddr());
+    this->setVirtualAddr(_sections.front()->virtualAddr());
     size_t startFileOffset = _sections.front()->fileOffset();
     size_t startAddr = _sections.front()->virtualAddr();
     for (auto ai : _sections) {
@@ -260,16 +255,6 @@ public:
 
   inline range<SliceIter> slices() { return _segmentSlices; }
 
-  // These two accessors are still needed for a call to std::stable_sort.
-  // Consider adding wrappers for two iterator algorithms.
-  inline SliceIter slices_begin() {
-    return _segmentSlices.begin();
-  }
-
-  inline SliceIter slices_end() {
-    return _segmentSlices.end();
-  }
-
   Chunk<ELFT> *firstSection() { return _sections[0]; }
 
 private:
@@ -316,7 +301,7 @@ public:
     // section points to the ELF header and the second chunk points to the
     // actual program headers
     this->setFileOffset(_sections.back()->fileOffset());
-    this->setVAddr(_sections.back()->virtualAddr());
+    this->setVirtualAddr(_sections.back()->virtualAddr());
     this->_fsize = _sections.back()->fileSize();
     this->_msize = _sections.back()->memSize();
   }
@@ -409,58 +394,132 @@ bool Segment<ELFT>::compareSegments(Segm
   return false;
 }
 
-template <class ELFT> void Segment<ELFT>::assignOffsets(uint64_t startOffset) {
+template <class ELFT>
+void Segment<ELFT>::assignFileOffsets(uint64_t startOffset) {
+  uint64_t fileOffset = startOffset;
+  uint64_t curSliceFileOffset = fileOffset;
+  bool isDataPageAlignedForNMagic = false;
+
+  this->setFileOffset(startOffset);
+  for (auto &slice : slices()) {
+    // Align to the slice alignment
+    fileOffset = llvm::RoundUpToAlignment(fileOffset, slice->align2());
+
+    bool isFirstSection = true;
+
+    for (auto section : slice->sections()) {
+      // 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
+        fileOffset =
+            llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
+      }
+      if (!isDataPageAlignedForNMagic && needAlign(section)) {
+        fileOffset =
+            llvm::RoundUpToAlignment(fileOffset, this->_context.getPageSize());
+        isDataPageAlignedForNMagic = true;
+      }
+      // Align the section address
+      fileOffset = llvm::RoundUpToAlignment(fileOffset, section->align2());
+
+      if (isFirstSection) {
+        slice->setFileOffset(fileOffset);
+        isFirstSection = false;
+        curSliceFileOffset = fileOffset;
+      }
+      section->setFileOffset(fileOffset);
+      fileOffset += section->fileSize();
+    }
+    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, endSectionIter;
+  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 curSliceFileOffset = 0;
+  uint64_t curSliceAddress = 0;
 
   startSectionIter = _sections.begin();
-  endSectionIter = _sections.end();
   startSection = 0;
   bool isFirstSection = true;
   bool isDataPageAlignedForNMagic = false;
+  uint64_t startAddr = addr;
+  SegmentSlice<ELFT> *slice = nullptr;
+  uint64_t tlsStartAddr = 0;
+
   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) {
-      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
-      // to a page boundary
-      if (!isDataPageAlignedForNMagic && needAlign(*si)) {
-        startOffset =
-            llvm::RoundUpToAlignment(startOffset, this->_context.getPageSize());
+      isFirstSection = false;
+      if (_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->_context.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->_context.getPageSize());
         isDataPageAlignedForNMagic = true;
       }
       // align the startOffset to the section alignment
-      uint64_t newOffset =
-        llvm::RoundUpToAlignment(startOffset, (*si)->align2());
-      curSliceFileOffset = newOffset;
+      uint64_t newAddr = llvm::RoundUpToAlignment(startAddr, (*si)->align2());
+      curSliceAddress = newAddr;
       sliceAlign = (*si)->align2();
-      this->setFileOffset(startOffset);
-      (*si)->setFileOffset(newOffset);
-      curSliceSize = (*si)->fileSize();
-      isFirstSection = false;
+      (*si)->setVirtualAddr(curSliceAddress);
+
+      // Handle TLS.
+      if (auto section = dyn_cast<AtomSection<ELFT>>(*si)) {
+        if (section->getSegmentType() == llvm::ELF::PT_TLS) {
+          tlsStartAddr =
+              llvm::RoundUpToAlignment(tlsStartAddr, (*si)->align2());
+          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() != DefaultLayout<ELFT>::ORDER_TBSS)
+        curSliceSize = (*si)->memSize();
     } else {
-      uint64_t curOffset = curSliceFileOffset + curSliceSize;
-      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
-      // to a page boundary
+      uint64_t curAddr = curSliceAddress + curSliceSize;
       if (!isDataPageAlignedForNMagic && needAlign(*si)) {
-        curOffset =
-            llvm::RoundUpToAlignment(curOffset, this->_context.getPageSize());
+        // If the linker outputmagic is set to OutputMagic::NMAGIC, align the
+        // Data
+        // to a page boundary
+        curAddr =
+            llvm::RoundUpToAlignment(curAddr, this->_context.getPageSize());
         isDataPageAlignedForNMagic = true;
       }
-      uint64_t newOffset = llvm::RoundUpToAlignment(curOffset, (*si)->align2());
-      SegmentSlice<ELFT> *slice = nullptr;
-      // If the newOffset computed is more than a page away, let's create
+      uint64_t newAddr = llvm::RoundUpToAlignment(curAddr, (*si)->align2());
+      // 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
-      if (((newOffset - curOffset) > this->_context.getPageSize()) &&
+      if (((newAddr - curAddr) > this->_context.getPageSize()) &&
           (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
            _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)) {
-
+        slice = nullptr;
         // TODO: use std::find here
         for (auto s : slices()) {
           if (s->startSection() == startSection) {
@@ -473,30 +532,48 @@ template <class ELFT> void Segment<ELFT>
             SegmentSlice<ELFT>();
           _segmentSlices.push_back(slice);
         }
-        slice->set(curSliceFileOffset, startSection, currSection);
-        slice->setSections(make_range(startSectionIter, endSectionIter));
-        slice->setSize(curSliceSize);
+        slice->setStart(startSection);
+        slice->setSections(make_range(startSectionIter, si));
+        slice->setMemSize(curSliceSize);
         slice->setAlign(sliceAlign);
-        uint64_t newPageOffset =
-            llvm::RoundUpToAlignment(curOffset, this->_context.getPageSize());
-        newOffset = llvm::RoundUpToAlignment(newPageOffset, (*si)->align2());
-        curSliceFileOffset = newOffset;
-        startSectionIter = endSectionIter;
+        slice->setVirtualAddr(curSliceAddress);
+        // Start new slice
+        curSliceAddress = newAddr;
+        (*si)->setVirtualAddr(curSliceAddress);
+        startSectionIter = si;
         startSection = currSection;
-        (*si)->setFileOffset(curSliceFileOffset);
-        curSliceSize = newOffset - curSliceFileOffset + (*si)->fileSize();
+        if (auto section = dyn_cast<AtomSection<ELFT>>(*si))
+          section->assignVirtualAddress(newAddr);
+        curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
         sliceAlign = (*si)->align2();
       } else {
         if (sliceAlign < (*si)->align2())
           sliceAlign = (*si)->align2();
-        (*si)->setFileOffset(newOffset);
-        curSliceSize = newOffset - curSliceFileOffset + (*si)->fileSize();
+        (*si)->setVirtualAddr(newAddr);
+        // Handle TLS.
+        if (auto section = dyn_cast<AtomSection<ELFT>>(*si)) {
+          if (section->getSegmentType() == llvm::ELF::PT_TLS) {
+            tlsStartAddr =
+                llvm::RoundUpToAlignment(tlsStartAddr, (*si)->align2());
+            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() != DefaultLayout<ELFT>::ORDER_TBSS)
+          curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
+        else
+          curSliceSize = newAddr - curSliceAddress;
       }
     }
     currSection++;
-    endSectionIter = si;
   }
-  SegmentSlice<ELFT> *slice = nullptr;
+  slice = nullptr;
   for (auto s : slices()) {
     // TODO: add std::find
     if (s->startSection() == startSection) {
@@ -509,74 +586,17 @@ template <class ELFT> void Segment<ELFT>
       SegmentSlice<ELFT>();
     _segmentSlices.push_back(slice);
   }
-  slice->set(curSliceFileOffset, startSection, currSection);
+  slice->setStart(startSection);
+  slice->setVirtualAddr(curSliceAddress);
+  slice->setMemSize(curSliceSize);
   slice->setSections(make_range(startSectionIter, _sections.end()));
-  slice->setSize(curSliceSize);
   slice->setAlign(sliceAlign);
-  this->_fsize = curSliceFileOffset - startOffset + curSliceSize;
-  std::stable_sort(slices_begin(), slices_end(),
-                   SegmentSlice<ELFT>::compare_slices);
-}
 
-/// \brief Assign virtual addresses to the slices
-template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t &addr) {
-  bool isTLSSegment = false;
-  bool isDataPageAlignedForNMagic = false;
-  uint64_t tlsStartAddr = 0;
-
-  for (auto slice : slices()) {
-    // Align to a page only if the output is not
-    // OutputMagic::NMAGIC/OutputMagic::OMAGIC
-    if (_outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
-        _outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
-      addr = llvm::RoundUpToAlignment(addr, this->_context.getPageSize());
-
-    // Align to the slice alignment
-    addr = llvm::RoundUpToAlignment(addr, slice->align2());
-
-    bool virtualAddressSet = false;
-    for (auto section : slice->sections()) {
-      // If the linker outputmagic is set to OutputMagic::NMAGIC, align the Data
-      // to a page boundary
-      if (!isDataPageAlignedForNMagic && needAlign(section)) {
-        addr = llvm::RoundUpToAlignment(addr, this->_context.getPageSize());
-        isDataPageAlignedForNMagic = true;
-      }
-      // Align the section address
-      addr = llvm::RoundUpToAlignment(addr, section->align2());
-      // Check if the segment is of type TLS
-      // The sections that belong to the TLS segment have their
-      // virtual addresses that are relative To TP
-      Section<ELFT> *currentSection = dyn_cast<Section<ELFT> >(section);
-      if (currentSection)
-        isTLSSegment = (currentSection->getSegmentType() == llvm::ELF::PT_TLS);
-
-      tlsStartAddr = (isTLSSegment)
-                     ? llvm::RoundUpToAlignment(tlsStartAddr, section->align2())
-                     : 0;
-      if (!virtualAddressSet) {
-        slice->setVAddr(addr);
-        virtualAddressSet = true;
-      }
-      section->setVAddr(addr);
-      if (auto s = dyn_cast<Section<ELFT> >(section)) {
-        if (isTLSSegment)
-          s->assignVirtualAddress(tlsStartAddr);
-        else
-          s->assignVirtualAddress(addr);
-      }
-      if (isTLSSegment)
-        tlsStartAddr += section->memSize();
-      section->setMemSize(addr + section->memSize() - section->virtualAddr());
-      // 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 (section->order() != DefaultLayout<ELFT>::ORDER_TBSS)
-        addr += section->memSize();
-    }
-    slice->setMemSize(addr - slice->virtualAddr());
-  }
+  // 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

Modified: lld/trunk/test/elf/phdr.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/phdr.test?rev=221233&r1=221232&r2=221233&view=diff
==============================================================================
--- lld/trunk/test/elf/phdr.test (original)
+++ lld/trunk/test/elf/phdr.test Mon Nov  3 21:57:04 2014
@@ -50,7 +50,7 @@ I386-NEXT:     Offset: 0x1000
 I386-NEXT:     VirtualAddress: 0x1000
 I386-NEXT:     PhysicalAddress: 0x1000
 I386-NEXT:     FileSize: 260
-I386-NEXT:     MemSize: 4
+I386-NEXT:     MemSize: 260
 I386-NEXT:     Flags [ (0x6)
 I386-NEXT:       PF_R (0x4)
 I386-NEXT:       PF_W (0x2)
@@ -63,7 +63,7 @@ I386-NEXT:     Offset: 0x4000
 I386-NEXT:     VirtualAddress: 0x4000
 I386-NEXT:     PhysicalAddress: 0x4000
 I386-NEXT:     FileSize: 4
-I386-NEXT:     MemSize: 16392
+I386-NEXT:     MemSize: 8
 I386-NEXT:     Flags [ (0x6)
 I386-NEXT:       PF_R (0x4)
 I386-NEXT:       PF_W (0x2)





More information about the llvm-commits mailing list