From: Shankar Easwaran Date: Wed, 27 Feb 2013 20:24:47 +0000 (+0000) Subject: [lld][ELF] Order segments X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=d4ac74ffccb52c11305094da159ef73b612df5f2;p=platform%2Fupstream%2Fllvm.git [lld][ELF] Order segments llvm-svn: 176207 --- diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h index 48c97a4..93c23f3 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ b/lld/lib/ReaderWriter/ELF/DefaultLayout.h @@ -110,15 +110,15 @@ public: }; typedef typename std::vector *>::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 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 *> MergedSectionMapT; - typedef typename std::vector< - MergedSections *>::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 *> MergedSectionMapT; + typedef typename std::vector *>::iterator + MergedSectionIter; + typedef std::unordered_map *, SectionKeyHash, SectionKeyEq> SectionMapT; - typedef std::unordered_map *, - SegmentHashKey> SegmentMapT; + typedef std::map *> AdditionalSegmentMapT; + typedef std::unordered_map *, 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 *> _sections; std::vector *> _segments; @@ -547,24 +555,50 @@ template void DefaultLayout::assignSectionsToSegments() { } for (auto msi : _mergedSections) { for (auto ai : msi->sections()) { - if (auto section = dyn_cast>(ai)) { + if (auto section = dyn_cast >(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 *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 *> + additionalSegment(segmentType, nullptr); + std::pair + additionalSegmentInsert( + _additionalSegmentMap.insert(additionalSegment)); + if (!additionalSegmentInsert.second) { + segment = additionalSegmentInsert.first->second; + } else { + segment = new (_allocator) + Segment(_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 *> currentSegment(key, nullptr); - std::pair - segmentInsert(_segmentMap.insert(currentSegment)); - Segment *segment; + std::pair segmentInsert( + _segmentMap.insert(currentSegment)); if (!segmentInsert.second) { segment = segmentInsert.first->second; } else { segment = new (_allocator) - Segment(_targetInfo, segmentName, getSegmentType(section)); + Segment(_targetInfo, "PT_LOAD", llvm::ELF::PT_LOAD); segmentInsert.first->second = segment; _segments.push_back(segment); } @@ -572,6 +606,13 @@ template void DefaultLayout::assignSectionsToSegments() { } } } + if (_targetInfo.isDynamic()) { + Segment *segment = + new (_allocator) ProgramHeaderSegment(_targetInfo); + _segments.push_back(segment); + segment->append(_header); + segment->append(_programHeader); + } } template void DefaultLayout::assignFileOffsets() { @@ -584,12 +625,14 @@ template void DefaultLayout::assignFileOffsets() { 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 void DefaultLayout::assignVirtualAddress() { @@ -597,36 +640,48 @@ DefaultLayout::assignVirtualAddress() { 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 *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::assignOffsetsForMiscSections() { 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(); } diff --git a/lld/lib/ReaderWriter/ELF/HeaderChunks.h b/lld/lib/ReaderWriter/ELF/HeaderChunks.h index 3682b23..561d3f1 100644 --- a/lld/lib/ReaderWriter/ELF/HeaderChunks.h +++ b/lld/lib/ReaderWriter/ELF/HeaderChunks.h @@ -119,30 +119,7 @@ public: bool addSegment(Segment *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 bool ProgramHeader::addSegment(Segment *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; diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 68ea093..a01c482 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -41,6 +41,7 @@ namespace lld { namespace elf { template class MergedSections; using namespace llvm::ELF; +template class Segment; /// \brief An ELF section. template class Section : public Chunk { @@ -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 StringRef Section::segmentKindToStr() const { 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(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(); diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index fb772dd..c75a065 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -122,7 +122,11 @@ public: }; /// append a section to a segment - void append(Section *section); + virtual void append(Section *chunk); + + /// append a chunk to a segment, this function + /// is used by the ProgramHeader segment + virtual void append(Chunk *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 *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 ProgramHeaderSegment : public Segment { +public: + ProgramHeaderSegment(const ELFTargetInfo &ti) + : Segment(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 *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 *> _sections; +}; + template Segment::Segment(const ELFTargetInfo &ti, StringRef name, const Layout::SegmentType type) @@ -270,7 +322,48 @@ template void Segment::append(Section *section) { template bool Segment::compareSegments(Segment *sega, Segment *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 void Segment::assignOffsets(uint64_t startOffset) { @@ -367,10 +460,7 @@ template void Segment::assignOffsets(uint64_t startOffset) { /// \brief Assign virtual addresses to the slices template void Segment::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 void Segment::assignVirtualAddress(uint64_t &addr) { 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 *currentSection = llvm::dyn_cast >(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; diff --git a/lld/test/elf/dynamic-segorder.test b/lld/test/elf/dynamic-segorder.test new file mode 100644 index 0000000..a9dd439 --- /dev/null +++ b/lld/test/elf/dynamic-segorder.test @@ -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-