diff options
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Chunk.h | 11 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/DefaultLayout.h | 76 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/HeaderChunks.h | 8 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/Layout.h | 2 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/OutputELFWriter.h | 3 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/SectionChunks.h | 11 | ||||
| -rw-r--r-- | lld/lib/ReaderWriter/ELF/SegmentChunks.h | 288 | ||||
| -rw-r--r-- | lld/test/elf/phdr.test | 4 |
8 files changed, 191 insertions, 212 deletions
diff --git a/lld/lib/ReaderWriter/ELF/Chunk.h b/lld/lib/ReaderWriter/ELF/Chunk.h index 8bf66d3b960..4e495811028 100644 --- a/lld/lib/ReaderWriter/ELF/Chunk.h +++ b/lld/lib/ReaderWriter/ELF/Chunk.h @@ -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; } diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h index 2cfba915a13..57b28e4d550 100644 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ b/lld/lib/ReaderWriter/ELF/DefaultLayout.h @@ -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<ELFT>::assignSectionsToSegments() { } } -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>::assignVirtualAddress() { 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>::assignVirtualAddress() { 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>::assignVirtualAddress() { 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>::assignVirtualAddress() { 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>::assignVirtualAddress() { } } -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>::assignOffsetsForMiscSections() { continue; fileoffset = llvm::RoundUpToAlignment(fileoffset, si->align2()); si->setFileOffset(fileoffset); - si->setVAddr(0); + si->setVirtualAddr(0); fileoffset += si->fileSize(); } } diff --git a/lld/lib/ReaderWriter/ELF/HeaderChunks.h b/lld/lib/ReaderWriter/ELF/HeaderChunks.h index b32ef6c7d33..5a83ee56b50 100644 --- a/lld/lib/ReaderWriter/ELF/HeaderChunks.h +++ b/lld/lib/ReaderWriter/ELF/HeaderChunks.h @@ -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); diff --git a/lld/lib/ReaderWriter/ELF/Layout.h b/lld/lib/ReaderWriter/ELF/Layout.h index 4fb97140749..bb8cffe701d 100644 --- a/lld/lib/ReaderWriter/ELF/Layout.h +++ b/lld/lib/ReaderWriter/ELF/Layout.h @@ -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() {} diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h index 9eab2cfcabc..7eb9bd9500a 100644 --- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h +++ b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h @@ -265,7 +265,7 @@ void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() { 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>::buildOutput(const File &file) { // 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 diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 026b78dd37d..244382eb09d 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -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; } diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index c9be23517ac..0f07e7d504e 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -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(Segment<ELFT> *sega, Segment<ELFT> *segb) { 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>::assignOffsets(uint64_t startOffset) { 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>::assignOffsets(uint64_t startOffset) { 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 diff --git a/lld/test/elf/phdr.test b/lld/test/elf/phdr.test index 9122bd0dd58..3f626aa1179 100644 --- a/lld/test/elf/phdr.test +++ b/lld/test/elf/phdr.test @@ -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) |

