[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