[lld] r176207 - [lld][ELF] Order segments

Shankar Easwaran shankare at codeaurora.org
Wed Feb 27 12:24:47 PST 2013


Author: shankare
Date: Wed Feb 27 14:24:47 2013
New Revision: 176207

URL: http://llvm.org/viewvc/llvm-project?rev=176207&view=rev
Log:
[lld][ELF] Order segments

Added:
    lld/trunk/test/elf/dynamic-segorder.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
    lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h
    lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
    lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h

Modified: lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h?rev=176207&r1=176206&r2=176207&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/DefaultLayout.h Wed Feb 27 14:24:47 2013
@@ -110,15 +110,15 @@ public:
   };
 
   typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
-  // The key used for Segments
+  // The additional segments are used to figure out 
+  // if there is a segment by that type already created
+  // For example : PT_TLS, we have two sections .tdata/.tbss 
+  // that are part of PT_TLS, we need to create this additional 
+  // segment only once
+  typedef int64_t AdditionalSegmentKey;
   // The segments are created using
   // SegmentName, Segment flags
   typedef std::pair<StringRef, int64_t> SegmentKey;
-  // Merged Sections contain the map of Sectionnames to a vector of sections,
-  // that have been merged to form a single section
-  typedef std::map<StringRef, MergedSections<ELFT> *> MergedSectionMapT;
-  typedef typename std::vector<
-      MergedSections<ELFT> *>::iterator MergedSectionIter;
 
   // HashKey for the Segment
   class SegmentHashKey {
@@ -130,10 +130,17 @@ public:
     }
   };
 
+  // Merged Sections contain the map of Sectionnames to a vector of sections,
+  // that have been merged to form a single section
+  typedef std::map<StringRef, MergedSections<ELFT> *> MergedSectionMapT;
+  typedef typename std::vector<MergedSections<ELFT> *>::iterator
+  MergedSectionIter;
+
   typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
                              SectionKeyEq> SectionMapT;
-  typedef std::unordered_map<SegmentKey, Segment<ELFT> *,
-                             SegmentHashKey> SegmentMapT;
+  typedef std::map<AdditionalSegmentKey, Segment<ELFT> *> AdditionalSegmentMapT;
+  typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
+  SegmentMapT;
 
   /// \brief find a absolute atom pair given a absolute atom name
   struct FindByName {
@@ -284,6 +291,7 @@ private:
   llvm::BumpPtrAllocator _allocator;
   SectionMapT _sectionMap;
   MergedSectionMapT _mergedSectionMap;
+  AdditionalSegmentMapT _additionalSegmentMap;
   SegmentMapT _segmentMap;
   std::vector<Chunk<ELFT> *> _sections;
   std::vector<Segment<ELFT> *> _segments;
@@ -547,24 +555,50 @@ template <class ELFT> void DefaultLayout
   }
   for (auto msi : _mergedSections) {
     for (auto ai : msi->sections()) {
-      if (auto section = dyn_cast<Section<ELFT>>(ai)) {
+      if (auto section = dyn_cast<Section<ELFT> >(ai)) {
         if (!hasOutputSegment(section))
           continue;
+
+        // Get the segment type for the section
+        int64_t segmentType = getSegmentType(section);
+
         msi->setHasSegment();
-        section->setSegment(getSegmentType(section));
+        section->setSegmentType(segmentType);
         StringRef segmentName = section->segmentKindToStr();
+
+        int64_t sectionFlag = msi->flags();
+
+        Segment<ELFT> *segment;
+        // We need a seperate segment for sections that dont have 
+        // the segment type to be PT_LOAD
+        if (segmentType != llvm::ELF::PT_LOAD) {
+          const std::pair<AdditionalSegmentKey, Segment<ELFT> *>
+          additionalSegment(segmentType, nullptr);
+          std::pair<typename AdditionalSegmentMapT::iterator, bool>
+          additionalSegmentInsert(
+              _additionalSegmentMap.insert(additionalSegment));
+          if (!additionalSegmentInsert.second) {
+            segment = additionalSegmentInsert.first->second;
+          } else {
+            segment = new (_allocator)
+                Segment<ELFT>(_targetInfo, segmentName, segmentType);
+            additionalSegmentInsert.first->second = segment;
+            _segments.push_back(segment);
+          }
+          segment->append(section);
+        }
+
         // Use the flags of the merged Section for the segment
-        const SegmentKey key(segmentName, msi->flags());
+        const SegmentKey key("PT_LOAD", sectionFlag);
         const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key,
                                                                     nullptr);
-        std::pair<typename SegmentMapT::iterator, bool>
-                            segmentInsert(_segmentMap.insert(currentSegment));
-        Segment<ELFT> *segment;
+        std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
+            _segmentMap.insert(currentSegment));
         if (!segmentInsert.second) {
           segment = segmentInsert.first->second;
         } else {
           segment = new (_allocator)
-              Segment<ELFT>(_targetInfo, segmentName, getSegmentType(section));
+              Segment<ELFT>(_targetInfo, "PT_LOAD", llvm::ELF::PT_LOAD);
           segmentInsert.first->second = segment;
           _segments.push_back(segment);
         }
@@ -572,6 +606,13 @@ template <class ELFT> void DefaultLayout
       }
     }
   }
+  if (_targetInfo.isDynamic()) {
+    Segment<ELFT> *segment =
+        new (_allocator) ProgramHeaderSegment<ELFT>(_targetInfo);
+    _segments.push_back(segment);
+    segment->append(_header);
+    segment->append(_programHeader);
+  }
 }
 
 template <class ELFT> void DefaultLayout<ELFT>::assignFileOffsets() {
@@ -584,12 +625,14 @@ template <class ELFT> void DefaultLayout
   uint64_t offset = 0;
   for (auto si : _segments) {
     si->setOrdinal(++ordinal);
+    // Dont 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() {
@@ -597,36 +640,48 @@ DefaultLayout<ELFT>::assignVirtualAddres
     return;
   
   uint64_t virtualAddress = _targetInfo.getBaseAddress();
-  
+
   // 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
   // so that AT_PHDR is set correctly by the loader and so they are accessible
-  // at runtime. To do this we simply prepend them to the first Segment and
-  // let the layout logic take care of it.
-  _segments[0]->prepend(_programHeader);
-  _segments[0]->prepend(_header);
-  
+  // at runtime. To do this we simply prepend them to the first loadable Segment 
+  // and let the layout logic take care of it.
+  Segment<ELFT> *firstLoadSegment = nullptr;
+  for (auto si : _segments) {
+    if (si->segmentType() == llvm::ELF::PT_LOAD) {
+      firstLoadSegment = si;
+      break;
+    }
+  }
+  firstLoadSegment->prepend(_programHeader);
+  firstLoadSegment->prepend(_header);
+
   bool newSegmentHeaderAdded = true;
   while (true) {
     for (auto si : _segments) {
+      si->finalize();
       newSegmentHeaderAdded = _programHeader->addSegment(si);
     }
-    if (_targetInfo.isDynamic() && _programHeader->addPHDR())
-      newSegmentHeaderAdded = true;
     if (!newSegmentHeaderAdded)
       break;
     uint64_t fileoffset = 0;
     uint64_t address = virtualAddress;
     // Fix the offsets after adding the program header
     for (auto &si : _segments) {
+      // Dont assign offsets for non loadable segments
+      if (si->segmentType() != llvm::ELF::PT_LOAD)
+        continue;
       // Align the segment to a page boundary
-      fileoffset = llvm::RoundUpToAlignment(fileoffset,
-                                            _targetInfo.getPageSize());
+      fileoffset =
+          llvm::RoundUpToAlignment(fileoffset, _targetInfo.getPageSize());
       si->assignOffsets(fileoffset);
       fileoffset = si->fileOffset() + si->fileSize();
     }
     // start assigning virtual addresses
     for (auto si = _segments.begin(); si != _segments.end(); ++si) {
+      // Dont assign addresses for non loadable segments
+      if ((*si)->segmentType() != llvm::ELF::PT_LOAD)
+        continue;
       (*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 dont align the
@@ -689,6 +744,9 @@ DefaultLayout<ELFT>::assignOffsetsForMis
   uint64_t fileoffset = 0;
   uint64_t size = 0;
   for (auto si : _segments) {
+    // Dont calculate offsets from non loadable segments
+    if (si->segmentType() != llvm::ELF::PT_LOAD)
+      continue;
     fileoffset = si->fileOffset();
     size = 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=176207&r1=176206&r2=176207&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/HeaderChunks.h Wed Feb 27 14:24:47 2013
@@ -119,30 +119,7 @@ public:
 
   bool addSegment(Segment<ELFT> *segment);
 
-  bool addPHDR() {
-    bool allocatedNew = false;
-    auto phdr = allocateProgramHeader();
-    if (phdr.second)
-      allocatedNew = true;
-
-    this->_fsize = fileSize();
-    this->_msize = this->_fsize;
-
-    phdr.first->p_type = llvm::ELF::PT_PHDR;
-    phdr.first->p_offset = this->fileOffset();
-    phdr.first->p_vaddr = this->virtualAddr();
-    phdr.first->p_paddr = this->virtualAddr();
-    phdr.first->p_filesz = this->fileSize();
-    phdr.first->p_memsz = this->memSize();
-    phdr.first->p_flags = llvm::ELF::PF_R;
-    phdr.first->p_align = 8;
-
-    return allocatedNew;
-  }
-
-  void resetProgramHeaders() {
-    _phi = _ph.begin();
-  }
+  void resetProgramHeaders() { _phi = _ph.begin(); }
 
   uint64_t  fileSize() {
     return sizeof(Elf_Phdr) * _ph.size();
@@ -203,23 +180,28 @@ private:
 template <class ELFT>
 bool ProgramHeader<ELFT>::addSegment(Segment<ELFT> *segment) {
   bool allocatedNew = false;
+  // For segments that are not a loadable segment, we
+  // just pick the values directly from the segment as there
+  // wouldnt be any slices within that
+  if (segment->segmentType() != llvm::ELF::PT_LOAD) {
+    auto phdr = allocateProgramHeader();
+    if (phdr.second)
+      allocatedNew = true;
+    phdr.first->p_type = segment->segmentType();
+    phdr.first->p_offset = segment->fileOffset();
+    phdr.first->p_vaddr = segment->virtualAddr();
+    phdr.first->p_paddr = segment->virtualAddr();
+    phdr.first->p_filesz = segment->fileSize();
+    phdr.first->p_memsz = segment->memSize();
+    phdr.first->p_flags = segment->flags();
+    phdr.first->p_align = segment->align2();
+    this->_fsize = fileSize();
+    this->_msize = this->_fsize;
+    return allocatedNew;
+  }
+  // For all other segments, use the slice
+  // to derive program headers
   for (auto slice : segment->slices()) {
-    // If we have a TLS segment, emit a LOAD first.
-    if (segment->segmentType() == llvm::ELF::PT_TLS ||
-        segment->segmentType() == llvm::ELF::PT_DYNAMIC ||
-        segment->segmentType() == llvm::ELF::PT_INTERP) {
-      auto phdr = allocateProgramHeader();
-      if (phdr.second)
-        allocatedNew = true;
-      phdr.first->p_type = llvm::ELF::PT_LOAD;
-      phdr.first->p_offset = slice->fileOffset();
-      phdr.first->p_vaddr = slice->virtualAddr();
-      phdr.first->p_paddr = slice->virtualAddr();
-      phdr.first->p_filesz = slice->fileSize();
-      phdr.first->p_memsz = slice->memSize();
-      phdr.first->p_flags = segment->flags();
-      phdr.first->p_align = segment->pageSize();
-    }
     auto phdr = allocateProgramHeader();
     if (phdr.second)
       allocatedNew = true;

Modified: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h?rev=176207&r1=176206&r2=176207&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h Wed Feb 27 14:24:47 2013
@@ -41,6 +41,7 @@ namespace lld {
 namespace elf {
 template <class> class MergedSections;
 using namespace llvm::ELF;
+template <class ELFT> class Segment;
 
 /// \brief An ELF section.
 template <class ELFT> class Section : public Chunk<ELFT> {
@@ -87,7 +88,7 @@ public:
   }
 
   /// \brief Records the segmentType, that this section belongs to
-  void setSegment(const Layout::SegmentType segmentType) {
+  void setSegmentType(const Layout::SegmentType segmentType) {
     this->_segmentType = segmentType;
   }
 
@@ -329,6 +330,8 @@ template <class ELFT> StringRef Section<
     return "NOTE";
   case llvm::ELF::PT_NULL:
     return "NULL";
+  case llvm::ELF::PT_TLS:
+    return "TLS";
   default:
     return "UNKNOWN";
   }
@@ -807,7 +810,7 @@ public:
       Elf_Rela *r = reinterpret_cast<Elf_Rela *>(dest);
       uint32_t index =
           _symbolTable ? _symbolTable->getSymbolTableIndex(rel.second->target())
-                       : STN_UNDEF;
+                       : (uint32_t) STN_UNDEF;
       r->setSymbolAndType(index, rel.second->kind());
       r->r_offset =
           writer->addressOfAtom(rel.first) + rel.second->offsetInAtom();

Modified: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h?rev=176207&r1=176206&r2=176207&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h Wed Feb 27 14:24:47 2013
@@ -122,7 +122,11 @@ public:
   };
 
   /// append a section to a segment
-  void append(Section<ELFT> *section);
+  virtual void append(Section<ELFT> *chunk);
+
+  /// append a chunk to a segment, this function
+  /// is used by the ProgramHeader segment
+  virtual void append(Chunk<ELFT> *chunk) {}
 
   /// Sort segments depending on the property
   /// If we have a Program Header segment, it should appear first
@@ -159,11 +163,28 @@ public:
     _sections.insert(_sections.begin(), c);
   }
 
-  // Finalize the segment before assigning File Offsets / Virtual addresses
+  /// Finalize the segment before assigning File Offsets / Virtual addresses
   inline void doPreFlight() {}
 
-  // Finalize the segment, before we want to write to the output file
-  inline void finalize() {}
+  /// Finalize the segment, before we want to write the segment header
+  /// information
+  inline 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->setVAddr(_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 inline bool classof(const Chunk<ELFT> *c) {
@@ -232,6 +253,37 @@ protected:
   llvm::BumpPtrAllocator _segmentAllocate;
 };
 
+/// \brief A Program Header segment contains a set of chunks instead of sections
+/// The segment doesnot contain any slice
+template <class ELFT> class ProgramHeaderSegment : public Segment<ELFT> {
+public:
+  ProgramHeaderSegment(const ELFTargetInfo &ti)
+      : Segment<ELFT>(ti, "PHDR", llvm::ELF::PT_PHDR) {
+    this->_align2 = 8;
+    this->_flags = (llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR);
+  }
+
+  /// append a section to a segment
+  void append(Chunk<ELFT> *chunk) { _sections.push_back(chunk); }
+
+  /// Finalize the segment, before we want to write the segment header
+  /// information
+  inline 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(_sections.back()->fileOffset());
+    this->setVAddr(_sections.back()->virtualAddr());
+    this->_fsize = _sections.back()->fileSize();
+    this->_msize = _sections.back()->memSize();
+  }
+
+protected:
+  /// \brief Section or some other chunk type.
+  std::vector<Chunk<ELFT> *> _sections;
+};
+
 template <class ELFT>
 Segment<ELFT>::Segment(const ELFTargetInfo &ti, StringRef name,
                        const Layout::SegmentType type)
@@ -270,7 +322,48 @@ template <class ELFT> void Segment<ELFT>
 
 template <class ELFT>
 bool Segment<ELFT>::compareSegments(Segment<ELFT> *sega, Segment<ELFT> *segb) {
-  return sega->atomflags() < segb->atomflags();
+  int64_t type1 = sega->segmentType();
+  int64_t type2 = segb->segmentType();
+
+  // 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 && type2 != llvm::ELF::PT_LOAD)
+    return true;
+  if (type2 == llvm::ELF::PT_LOAD && type1 != llvm::ELF::PT_LOAD)
+    return false;
+
+  // 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 && type2 != llvm::ELF::PT_TLS &&
+      type2 != llvm::ELF::PT_GNU_RELRO)
+    return false;
+  if (type2 == llvm::ELF::PT_TLS && type1 != llvm::ELF::PT_TLS &&
+      type1 != llvm::ELF::PT_GNU_RELRO)
+    return true;
+
+  // 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 && type2 != llvm::ELF::PT_GNU_RELRO)
+    return false;
+  if (type2 == llvm::ELF::PT_GNU_RELRO && type1 != llvm::ELF::PT_GNU_RELRO)
+    return true;
+
+  if (type1 == type2)
+    return sega->atomflags() < segb->atomflags();
+  return false;
 }
 
 template <class ELFT> void Segment<ELFT>::assignOffsets(uint64_t startOffset) {
@@ -367,10 +460,7 @@ template <class ELFT> void Segment<ELFT>
 
 /// \brief Assign virtual addresses to the slices
 template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t &addr) {
-  // 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
-  bool isTLSSegment = (segmentType() == llvm::ELF::PT_TLS);
+  bool isTLSSegment = false;
   uint64_t tlsStartAddr = 0;
 
   for (auto slice : slices()) {
@@ -383,8 +473,16 @@ template <class ELFT> void Segment<ELFT>
     for (auto section : slice->sections()) {
       // Align the section address
       addr = llvm::RoundUpToAlignment(addr, section->align2());
-      tlsStartAddr = (isTLSSegment) ?
-                    llvm::RoundUpToAlignment(tlsStartAddr, section->align2()):0;
+      // 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 = llvm::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;

Added: lld/trunk/test/elf/dynamic-segorder.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/dynamic-segorder.test?rev=176207&view=auto
==============================================================================
--- lld/trunk/test/elf/dynamic-segorder.test (added)
+++ lld/trunk/test/elf/dynamic-segorder.test Wed Feb 27 14:24:47 2013
@@ -0,0 +1,19 @@
+RUN: lld -core -target x86_64-linux %p/Inputs/tls.x86-64 \
+RUN:   %p/Inputs/shared.so-x86-64 -output=%t -entry=main \
+RUN:   -output-type=dynamic
+RUN: llvm-objdump -p %t | FileCheck %s
+
+CHECK: PHDR
+CHECK: flags r-x
+CHECK: INTERP
+CHECK: flags r--
+CHECK: LOAD
+CHECK: flags r-x
+CHECK: LOAD
+CHECK: flags r--
+CHECK: LOAD
+CHECK: flags rw-
+CHECK: DYNAMIC
+CHECK: flags r--
+CHECK: TLS
+CHECK: flags rw-





More information about the llvm-commits mailing list