From cdc1246750163de49a4357444f47aaef9ffc6323 Mon Sep 17 00:00:00 2001 From: Denis Protivensky Date: Thu, 23 Jul 2015 10:34:30 +0000 Subject: [PATCH] [ELF] Apply segments from linker scripts Put sections to segments according to linker scripts if available. Rework the code of TargetLayout::assignSectionsToSegments so it operates on the given list of segments, which can be either read from linker scripts or constructed as before. Handle NONE segments defined in linker scripts by putting corresponding sections to PT_NULL segment. Consider flags set for segments through linker scripts. Differential Revision: http://reviews.llvm.org/D10918 llvm-svn: 243002 --- lld/include/lld/ReaderWriter/LinkerScript.h | 6 +- .../ReaderWriter/ELF/ARM/ARMTargetHandler.h | 2 +- .../ELF/Hexagon/HexagonTargetHandler.h | 2 +- .../ELF/Mips/MipsTargetLayout.cpp | 2 +- .../ReaderWriter/ELF/Mips/MipsTargetLayout.h | 2 +- lld/lib/ReaderWriter/ELF/SectionChunks.h | 4 + lld/lib/ReaderWriter/ELF/SegmentChunks.cpp | 36 ++++- lld/lib/ReaderWriter/ELF/SegmentChunks.h | 4 + lld/lib/ReaderWriter/ELF/TargetLayout.cpp | 139 ++++++++++-------- lld/lib/ReaderWriter/ELF/TargetLayout.h | 63 ++++---- lld/lib/ReaderWriter/LinkerScript.cpp | 16 +- lld/test/elf/linkerscript/phdrs-all-none.test | 26 ++++ .../elf/linkerscript/phdrs-different.test | 45 ++++++ lld/test/elf/linkerscript/phdrs-flags.test | 46 ++++++ lld/test/elf/linkerscript/phdrs-one-none.test | 36 +++++ .../elf/linkerscript/phdrs-same-flags.test | 35 +++++ lld/test/elf/linkerscript/phdrs-same.test | 36 +++++ 17 files changed, 395 insertions(+), 105 deletions(-) create mode 100644 lld/test/elf/linkerscript/phdrs-all-none.test create mode 100644 lld/test/elf/linkerscript/phdrs-different.test create mode 100644 lld/test/elf/linkerscript/phdrs-flags.test create mode 100644 lld/test/elf/linkerscript/phdrs-one-none.test create mode 100644 lld/test/elf/linkerscript/phdrs-same-flags.test create mode 100644 lld/test/elf/linkerscript/phdrs-same.test diff --git a/lld/include/lld/ReaderWriter/LinkerScript.h b/lld/include/lld/ReaderWriter/LinkerScript.h index b2ac0487d2b8..d9d46a414d75 100644 --- a/lld/include/lld/ReaderWriter/LinkerScript.h +++ b/lld/include/lld/ReaderWriter/LinkerScript.h @@ -817,12 +817,12 @@ public: _includePHDRs(includePHDRs), _at(at), _flags(flags) {} StringRef name() const { return _name; } + uint64_t type() const { return _type; } + uint64_t flags() const { return _flags; } + bool isNone() const; void dump(raw_ostream &os) const; - /// Special header that discards output sections assigned to it. - static const PHDR *NONE; - private: StringRef _name; uint64_t _type; diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h index e6e774980cd1..0352e81a1f61 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -89,7 +89,7 @@ public: inputSectionName)); } - SegmentType getSegmentType(Section *section) const override { + SegmentType getSegmentType(const Section *section) const override { switch (section->order()) { case ORDER_ARM_EXIDX: return llvm::ELF::PT_ARM_EXIDX; diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h index 2ff19ad61c48..b1366bed09ea 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h @@ -79,7 +79,7 @@ public: /// \brief get the segment type for the section thats defined by the target TargetLayout::SegmentType - getSegmentType(Section *section) const override { + getSegmentType(const Section *section) const override { if (section->order() == ORDER_SDATA) return PT_LOAD; return TargetLayout::getSegmentType(section); diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp index cb06d5d21ce4..710f8320a8b9 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp @@ -33,7 +33,7 @@ AtomSection *MipsTargetLayout::createSection( template typename TargetLayout::SegmentType -MipsTargetLayout::getSegmentType(Section *section) const { +MipsTargetLayout::getSegmentType(const Section *section) const { switch (section->order()) { case ORDER_MIPS_REGINFO: return _abiInfo.hasMipsAbiSection() ? llvm::ELF::PT_LOAD diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h index c8a8985108e7..08855438d20e 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h @@ -38,7 +38,7 @@ public: typename TargetLayout::SectionOrder order) override; typename TargetLayout::SegmentType - getSegmentType(Section *section) const override; + getSegmentType(const Section *section) const override; /// \brief GP offset relative to .got section. uint64_t getGPOffset() const { return 0x7FF0; } diff --git a/lld/lib/ReaderWriter/ELF/SectionChunks.h b/lld/lib/ReaderWriter/ELF/SectionChunks.h index 3e84a04a774f..546779970407 100644 --- a/lld/lib/ReaderWriter/ELF/SectionChunks.h +++ b/lld/lib/ReaderWriter/ELF/SectionChunks.h @@ -85,6 +85,10 @@ public: return nullptr; } + const OutputSection *getOutputSection() const { + return _outputSection; + } + void setOutputSection(OutputSection *os, bool isFirst = false) { _outputSection = os; _isFirstSectionInOutputSection = isFirst; diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.cpp b/lld/lib/ReaderWriter/ELF/SegmentChunks.cpp index 60a0b164042a..cc6998d7ae48 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.cpp +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.cpp @@ -23,7 +23,7 @@ template Segment::Segment(const ELFLinkingContext &ctx, StringRef name, const typename TargetLayout::SegmentType type) : Chunk(name, Chunk::Kind::ELFSegment, ctx), _segmentType(type), - _flags(0), _atomflags(0) { + _flags(0), _atomflags(0), _segmentFlags(false) { this->_alignment = 1; this->_fsize = 0; _outputMagic = ctx.getOutputMagic(); @@ -46,17 +46,37 @@ static DefinedAtom::ContentPermissions toAtomPerms(uint64_t flags) { } } +// This function actually is used, but not in all instantiations of Segment. +LLVM_ATTRIBUTE_UNUSED +static DefinedAtom::ContentPermissions toAtomPermsSegment(uint64_t flags) { + switch (flags & (llvm::ELF::PF_R | llvm::ELF::PF_W | llvm::ELF::PF_X)) { + case llvm::ELF::PF_R | llvm::ELF::PF_W | llvm::ELF::PF_X: + return DefinedAtom::permRWX; + case llvm::ELF::PF_R | llvm::ELF::PF_X: + return DefinedAtom::permR_X; + case llvm::ELF::PF_R: + return DefinedAtom::permR__; + case llvm::ELF::PF_R | llvm::ELF::PF_W: + return DefinedAtom::permRW_; + default: + return DefinedAtom::permUnknown; + } +} + template void Segment::append(Chunk *chunk) { _sections.push_back(chunk); Section *section = dyn_cast>(chunk); if (!section) return; + if (this->_alignment < section->alignment()) + this->_alignment = section->alignment(); + + if (_segmentFlags) + return; if (_flags < section->getFlags()) _flags |= section->getFlags(); if (_atomflags < toAtomPerms(_flags)) _atomflags = toAtomPerms(_flags); - if (this->_alignment < section->alignment()) - this->_alignment = section->alignment(); } template @@ -389,6 +409,9 @@ void Segment::write(ELFWriter *writer, TargetLayout &layout, } template int64_t Segment::flags() const { + if (_segmentFlags) + return (int64_t)_flags; + int64_t fl = 0; if (_flags & llvm::ELF::SHF_ALLOC) fl |= llvm::ELF::PF_R; @@ -399,6 +422,13 @@ template int64_t Segment::flags() const { return fl; } +template void Segment::setSegmentFlags(uint64_t flags) { + assert(!_segmentFlags && !_flags && "Flags has already been set"); + _segmentFlags = true; + _flags = flags; + _atomflags = toAtomPermsSegment(flags); +} + template void Segment::finalize() { // We want to finalize the segment values for now only for non loadable // segments, since those values are not set in the Layout diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index 2882cdbbf944..2138a783bdab 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -139,6 +139,9 @@ public: int64_t flags() const; + // Set segment flags directly. + void setSegmentFlags(uint64_t flags); + /// Prepend a generic chunk to the segment. void prepend(Chunk *c) { _sections.insert(_sections.begin(), c); @@ -188,6 +191,7 @@ protected: typename TargetLayout::SegmentType _segmentType; uint64_t _flags; int64_t _atomflags; + bool _segmentFlags; llvm::BumpPtrAllocator _segmentAllocate; }; diff --git a/lld/lib/ReaderWriter/ELF/TargetLayout.cpp b/lld/lib/ReaderWriter/ELF/TargetLayout.cpp index c0dae207bd6e..ada63fbe3810 100644 --- a/lld/lib/ReaderWriter/ELF/TargetLayout.cpp +++ b/lld/lib/ReaderWriter/ELF/TargetLayout.cpp @@ -133,7 +133,7 @@ TargetLayout::getOutputSectionName(StringRef archivePath, /// \brief Gets the segment for a output section template typename TargetLayout::SegmentType -TargetLayout::getSegmentType(Section *section) const { +TargetLayout::getSegmentType(const Section *section) const { switch (section->order()) { case ORDER_INTERP: return llvm::ELF::PT_INTERP; @@ -320,7 +320,6 @@ template void TargetLayout::createOutputSections() { } else { outputSection = new (_allocator.Allocate>()) OutputSection(section->outputSectionName()); - checkOutputSectionSegment(outputSection); _outputSections.push_back(outputSection); outputSectionInsert.first->second = outputSection; } @@ -328,15 +327,66 @@ template void TargetLayout::createOutputSections() { } } -// Check that output section has proper segment set template -void TargetLayout::checkOutputSectionSegment( - const OutputSection *sec) { +std::vector +TargetLayout::getCustomSegments(const OutputSection *sec) const { std::vector phdrs; if (_linkerScriptSema.getPHDRsForOutputSection(sec->name(), phdrs)) { llvm::report_fatal_error( "Linker script has wrong segments set for output sections"); } + return phdrs; +} + +template +std::vector +TargetLayout::getCustomSegments(const Section *section) const { + auto sec = section->getOutputSection(); + assert(sec && "Output section should be already set for input section"); + return getCustomSegments(sec); +} + +template +std::vector::SegmentKey> +TargetLayout::getSegmentsForSection(const OutputSection *os, + const Section *sec) const { + std::vector segKeys; + auto phdrs = getCustomSegments(os); + if (!phdrs.empty()) { + if (phdrs.size() == 1 && phdrs[0]->isNone()) { + segKeys.emplace_back("NONE", llvm::ELF::PT_NULL, 0, false); + return segKeys; + } + + for (auto phdr : phdrs) { + segKeys.emplace_back(phdr->name(), phdr->type(), phdr->flags(), true); + } + return segKeys; + } + + uint64_t flags = getLookupSectionFlags(os); + int64_t segmentType = getSegmentType(sec); + StringRef segmentName = sec->segmentKindToStr(); + + // We need a separate segment for sections that don't have + // the segment type to be PT_LOAD + if (segmentType != llvm::ELF::PT_LOAD) + segKeys.emplace_back(segmentName, segmentType, flags, false); + + if (segmentType == llvm::ELF::PT_NULL) + return segKeys; + + // If the output magic is set to OutputMagic::NMAGIC or + // OutputMagic::OMAGIC, Place the data alongside text in one single + // segment + ELFLinkingContext::OutputMagic outputMagic = _ctx.getOutputMagic(); + if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC || + outputMagic == ELFLinkingContext::OutputMagic::OMAGIC) + flags = + llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_WRITE; + + segKeys.emplace_back("LOAD", llvm::ELF::PT_LOAD, flags, false); + return segKeys; } template @@ -356,7 +406,6 @@ TargetLayout::getLookupSectionFlags(const OutputSection *os) const { template void TargetLayout::assignSectionsToSegments() { ScopedTask task(getDefaultDomain(), "assignSectionsToSegments"); - ELFLinkingContext::OutputMagic outputMagic = _ctx.getOutputMagic(); // sort the sections by their order as defined by the layout sortInputSections(); @@ -381,66 +430,40 @@ template void TargetLayout::assignSectionsToSegments() { continue; osi->setLoadableSection(section->isLoadableSection()); - - // Get the segment type for the section - int64_t segmentType = getSegmentType(section); - osi->setHasSegment(); - section->setSegmentType(segmentType); - StringRef segmentName = section->segmentKindToStr(); - uint64_t lookupSectionFlag = getLookupSectionFlags(osi); + auto segKeys = getSegmentsForSection(osi, section); + assert(!segKeys.empty() && "Must always be at least one segment"); + section->setSegmentType(segKeys[0]._type); - Segment *segment; - // We need a separate segment for sections that don't have - // the segment type to be PT_LOAD - if (segmentType != llvm::ELF::PT_LOAD) { - const AdditionalSegmentKey key(segmentType, lookupSectionFlag); - const std::pair *> - additionalSegment(key, nullptr); - std::pair - additionalSegmentInsert( - _additionalSegmentMap.insert(additionalSegment)); - if (!additionalSegmentInsert.second) { - segment = additionalSegmentInsert.first->second; + for (auto key : segKeys) { + // Try to find non-load (real) segment type if possible + if (key._type != llvm::ELF::PT_LOAD) + section->setSegmentType(key._type); + + const std::pair *> currentSegment(key, + nullptr); + std::pair segmentInsert( + _segmentMap.insert(currentSegment)); + Segment *segment; + if (!segmentInsert.second) { + segment = segmentInsert.first->second; } else { - segment = - new (_allocator) Segment(_ctx, segmentName, segmentType); - additionalSegmentInsert.first->second = segment; + segment = new (_allocator) Segment(_ctx, key._name, key._type); + if (key._segmentFlags) + segment->setSegmentFlags(key._flags); + segmentInsert.first->second = segment; _segments.push_back(segment); } + if (key._type == llvm::ELF::PT_LOAD) { + // Insert chunks with linker script expressions that occur at this + // point, just before appending a new input section + addExtraChunksToSegment(segment, section->archivePath(), + section->memberPath(), + section->inputSectionName()); + } segment->append(section); } - if (segmentType == llvm::ELF::PT_NULL) - continue; - - // If the output magic is set to OutputMagic::NMAGIC or - // OutputMagic::OMAGIC, Place the data alongside text in one single - // segment - if (outputMagic == ELFLinkingContext::OutputMagic::NMAGIC || - outputMagic == ELFLinkingContext::OutputMagic::OMAGIC) - lookupSectionFlag = llvm::ELF::SHF_EXECINSTR | llvm::ELF::SHF_ALLOC | - llvm::ELF::SHF_WRITE; - - // Use the flags of the merged Section for the segment - const SegmentKey key("PT_LOAD", lookupSectionFlag); - const std::pair *> currentSegment(key, nullptr); - std::pair segmentInsert( - _segmentMap.insert(currentSegment)); - if (!segmentInsert.second) { - segment = segmentInsert.first->second; - } else { - segment = - new (_allocator) Segment(_ctx, "PT_LOAD", llvm::ELF::PT_LOAD); - segmentInsert.first->second = segment; - _segments.push_back(segment); - } - // Insert chunks with linker script expressions that occur at this - // point, just before appending a new input section - addExtraChunksToSegment(segment, section->archivePath(), - section->memberPath(), - section->inputSectionName()); - segment->append(section); } } if (_ctx.isDynamic() && !_ctx.isDynamicLibrary()) { diff --git a/lld/lib/ReaderWriter/ELF/TargetLayout.h b/lld/lib/ReaderWriter/ELF/TargetLayout.h index f35bf0311466..e77212146fd9 100644 --- a/lld/lib/ReaderWriter/ELF/TargetLayout.h +++ b/lld/lib/ReaderWriter/ELF/TargetLayout.h @@ -106,36 +106,31 @@ public: typedef typename std::vector *>::iterator ChunkIter; typedef typename std::vector *>::iterator SegmentIter; - // 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 std::pair AdditionalSegmentKey; - // The segments are created using - // SegmentName, Segment flags - typedef std::pair SegmentKey; + // Properties used during segment creation + struct SegmentKey { + SegmentKey(StringRef name, int64_t type, uint64_t flags, bool segFlags) + : _name(name), _type(type), _flags(flags), + _segmentFlags(segFlags && flags != 0) {} + StringRef _name = ""; + int64_t _type = 0; + uint64_t _flags = 0; + bool _segmentFlags = false; + }; - // HashKey for the Segment - class SegmentHashKey { - public: - int64_t operator() (const SegmentKey &k) const { - // k.first = SegmentName - // k.second = SegmentFlags - return llvm::hash_combine(k.first, k.second); + struct SegmentKeyHash { + int64_t operator()(const SegmentKey &k) const { + return llvm::hash_combine(k._name, k._type, k._flags); } }; - class AdditionalSegmentHashKey { - public: - int64_t operator()(const AdditionalSegmentKey &k) const { - // k.first = SegmentName - // k.second = SegmentFlags - return llvm::hash_combine(k.first, k.second); + struct SegmentKeyEq { + bool operator()(const SegmentKey &lhs, const SegmentKey &rhs) const { + return ((lhs._name == rhs._name) && (lhs._type == rhs._type) && + (lhs._flags == rhs._flags)); } }; - // Output Sections contain the map of Sectionnames to a vector of sections, + // Output Sections contain the map of Section names to a vector of sections, // that have been merged to form a single section typedef llvm::StringMap *> OutputSectionMapT; typedef @@ -143,10 +138,8 @@ public: typedef std::unordered_map *, SectionKeyHash, SectionKeyEq> SectionMapT; - typedef std::unordered_map *, - AdditionalSegmentHashKey> AdditionalSegmentMapT; - typedef std::unordered_map *, SegmentHashKey> - SegmentMapT; + typedef std::unordered_map *, SegmentKeyHash, + SegmentKeyEq> SegmentMapT; typedef typename std::vector::iterator AbsoluteAtomIterT; @@ -177,7 +170,7 @@ public: const DefinedAtom *da); /// \brief Gets the segment for a output section - virtual SegmentType getSegmentType(Section *section) const; + virtual SegmentType getSegmentType(const Section *section) const; /// \brief Returns true/false depending on whether the section has a Output // segment or not @@ -209,8 +202,17 @@ public: // Output sections with the same name into a OutputSection void createOutputSections(); - // Check that output section has proper segment set - void checkOutputSectionSegment(const OutputSection *sec); + // Query for custom segments of the given section + std::vector + getCustomSegments(const Section *section) const; + + // Query for custom segments of the given output section + std::vector + getCustomSegments(const OutputSection *sec) const; + + // Query for segments based on output and input sections + std::vector getSegmentsForSection(const OutputSection *os, + const Section *sec) const; /// \brief Sort the sections by their order as defined by the layout, /// preparing all sections to be assigned to a segment. @@ -312,7 +314,6 @@ protected: llvm::BumpPtrAllocator _allocator; SectionMapT _sectionMap; OutputSectionMapT _outputSectionMap; - AdditionalSegmentMapT _additionalSegmentMap; SegmentMapT _segmentMap; std::vector *> _sections; std::vector *> _segments; diff --git a/lld/lib/ReaderWriter/LinkerScript.cpp b/lld/lib/ReaderWriter/LinkerScript.cpp index 79a367d15bf1..858fa7812ec8 100644 --- a/lld/lib/ReaderWriter/LinkerScript.cpp +++ b/lld/lib/ReaderWriter/LinkerScript.cpp @@ -937,6 +937,13 @@ void OutputSectionDescription::dump(raw_ostream &os) const { } } +// Special header that discards output sections assigned to it. +static const PHDR PHDR_NONE("NONE", 0, false, false, nullptr, 0); + +bool PHDR::isNone() const { + return this == &PHDR_NONE; +} + void PHDR::dump(raw_ostream &os) const { os << _name << " " << _type; if (_includeFileHdr) @@ -953,9 +960,6 @@ void PHDR::dump(raw_ostream &os) const { os << ";\n"; } -static PHDR none("NONE", 0, false, false, NULL, 0); -const PHDR *PHDR::NONE = &none; - void PHDRS::dump(raw_ostream &os) const { os << "PHDRS\n{\n"; for (auto &&phdr : _phdrs) { @@ -2736,11 +2740,11 @@ std::error_code Sema::buildSectionToPHDR() { // Add NONE header to the map provided there's no user-defined // header with the same name. - if (!_sectionToPHDR.count(PHDR::NONE->name())) - phdrs[PHDR::NONE->name()] = PHDR::NONE; + if (!_sectionToPHDR.count(PHDR_NONE.name())) + phdrs[PHDR_NONE.name()] = &PHDR_NONE; // Match output sections to available headers. - llvm::SmallVector phdrsCur, phdrsLast { PHDR::NONE }; + llvm::SmallVector phdrsCur, phdrsLast { &PHDR_NONE }; for (const Command *cmd : _layoutCommands) { auto osd = dyn_cast(cmd); if (!osd || osd->isDiscarded()) diff --git a/lld/test/elf/linkerscript/phdrs-all-none.test b/lld/test/elf/linkerscript/phdrs-all-none.test new file mode 100644 index 000000000000..199fee5c9eab --- /dev/null +++ b/lld/test/elf/linkerscript/phdrs-all-none.test @@ -0,0 +1,26 @@ +/* +Test when all segments are marked as NONE. + +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o + +RUN: lld -flavor gnu -target x86_64 -T %s %t.o -static -o %t1 +RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix NONE-ALL-PHDRS %s +*/ + +ENTRY(_start) + +PHDRS +{ + text PT_LOAD; +} + +SECTIONS +{ + .text : { *(.text) } :NONE + .data : { *(.data) } +} + +/* +NONE-ALL-PHDRS: .text {{[0-9a-f]+}} 0000000000000000 +NONE-ALL-PHDRS: .data {{[0-9a-f]+}} 000000000000002c +*/ diff --git a/lld/test/elf/linkerscript/phdrs-different.test b/lld/test/elf/linkerscript/phdrs-different.test new file mode 100644 index 000000000000..c9a04e2a935e --- /dev/null +++ b/lld/test/elf/linkerscript/phdrs-different.test @@ -0,0 +1,45 @@ +/* +Test sections put to different segments. + +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o + +RUN: lld -flavor gnu -target x86_64 -T %s %t.o -static -o %t1 +RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix DIFF-PHDRS-SECS %s +RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix DIFF-PHDRS-HDRS %s +*/ + +ENTRY(_start) + +PHDRS +{ + text PT_LOAD; + data PT_LOAD; +} + +SECTIONS +{ + .text : { *(.text) } :text + .data : { *(.data) } :data +} + +/* +DIFF-PHDRS-SECS: .text {{[0-9a-f]+}} 00000000004000e8 +DIFF-PHDRS-SECS: .data {{[0-9a-f]+}} 0000000000401000 + +DIFF-PHDRS-HDRS: ProgramHeader { +DIFF-PHDRS-HDRS: Type: PT_LOAD (0x1) +DIFF-PHDRS-HDRS: VirtualAddress: 0x400000 +DIFF-PHDRS-HDRS: Flags [ (0x5) +DIFF-PHDRS-HDRS: PF_R (0x4) +DIFF-PHDRS-HDRS: PF_X (0x1) +DIFF-PHDRS-HDRS: ] +DIFF-PHDRS-HDRS: } +DIFF-PHDRS-HDRS: ProgramHeader { +DIFF-PHDRS-HDRS: Type: PT_LOAD (0x1) +DIFF-PHDRS-HDRS: VirtualAddress: 0x401000 +DIFF-PHDRS-HDRS: Flags [ (0x6) +DIFF-PHDRS-HDRS: PF_R (0x4) +DIFF-PHDRS-HDRS: PF_W (0x2) +DIFF-PHDRS-HDRS: ] +DIFF-PHDRS-HDRS: } +*/ diff --git a/lld/test/elf/linkerscript/phdrs-flags.test b/lld/test/elf/linkerscript/phdrs-flags.test new file mode 100644 index 000000000000..d6011bd989c5 --- /dev/null +++ b/lld/test/elf/linkerscript/phdrs-flags.test @@ -0,0 +1,46 @@ +/* +Test sections put to different segments with FLAGS attribute set. + +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o + +RUN: lld -flavor gnu -target x86_64 -T %s %t.o -static -o %t1 +RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix FLAGS-PHDRS-SECS %s +RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix FLAGS-PHDRS-HDRS %s +*/ + +ENTRY(_start) + +PHDRS +{ + text PT_LOAD FLAGS(0x5); + data PT_LOAD FLAGS(0x7); +} + +SECTIONS +{ + .text : { *(.text) } :text + .data : { *(.data) } :data +} + +/* +FLAGS-PHDRS-SECS: .text {{[0-9a-f]+}} 0000000000401000 +FLAGS-PHDRS-SECS: .data {{[0-9a-f]+}} 00000000004000e8 + +FLAGS-PHDRS-HDRS: ProgramHeader { +FLAGS-PHDRS-HDRS: Type: PT_LOAD (0x1) +FLAGS-PHDRS-HDRS: VirtualAddress: 0x400000 +FLAGS-PHDRS-HDRS: Flags [ (0x7) +FLAGS-PHDRS-HDRS: PF_R (0x4) +FLAGS-PHDRS-HDRS: PF_W (0x2) +FLAGS-PHDRS-HDRS: PF_X (0x1) +FLAGS-PHDRS-HDRS: ] +FLAGS-PHDRS-HDRS: } +FLAGS-PHDRS-HDRS: ProgramHeader { +FLAGS-PHDRS-HDRS: Type: PT_LOAD (0x1) +FLAGS-PHDRS-HDRS: VirtualAddress: 0x401000 +FLAGS-PHDRS-HDRS: Flags [ (0x5) +FLAGS-PHDRS-HDRS: PF_R (0x4) +FLAGS-PHDRS-HDRS: PF_X (0x1) +FLAGS-PHDRS-HDRS: ] +FLAGS-PHDRS-HDRS: } +*/ diff --git a/lld/test/elf/linkerscript/phdrs-one-none.test b/lld/test/elf/linkerscript/phdrs-one-none.test new file mode 100644 index 000000000000..ebd9c8602a6e --- /dev/null +++ b/lld/test/elf/linkerscript/phdrs-one-none.test @@ -0,0 +1,36 @@ +/* +Test when one segment is marked as NONE. + +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o + +RUN: lld -flavor gnu -target x86_64 -T %s %t.o -static -o %t1 +RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix NONE-PHDRS-SECS %s +RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix NONE-PHDRS-HDRS %s +*/ + +ENTRY(_start) + +PHDRS +{ + text PT_LOAD; +} + +SECTIONS +{ + .text : { *(.text) } :text + .data : { *(.data) } :NONE +} + +/* +NONE-PHDRS-SECS: .text {{[0-9a-f]+}} 00000000004000b0 +NONE-PHDRS-SECS: .data {{[0-9a-f]+}} 0000000000000000 + +NONE-PHDRS-HDRS: ProgramHeader { +NONE-PHDRS-HDRS: Type: PT_LOAD (0x1) +NONE-PHDRS-HDRS: VirtualAddress: 0x400000 +NONE-PHDRS-HDRS: Flags [ (0x5) +NONE-PHDRS-HDRS: PF_R (0x4) +NONE-PHDRS-HDRS: PF_X (0x1) +NONE-PHDRS-HDRS: ] +NONE-PHDRS-HDRS: } +*/ diff --git a/lld/test/elf/linkerscript/phdrs-same-flags.test b/lld/test/elf/linkerscript/phdrs-same-flags.test new file mode 100644 index 000000000000..64b6828242f1 --- /dev/null +++ b/lld/test/elf/linkerscript/phdrs-same-flags.test @@ -0,0 +1,35 @@ +/* +Test sections put to same segment with FLAGS attribute set. + +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o + +RUN: lld -flavor gnu -target x86_64 -T %s %t.o -static -o %t1 +RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix FLAGS-PHDRS-SECS %s +RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix FLAGS-PHDRS-HDRS %s +*/ + +ENTRY(_start) + +PHDRS +{ + text PT_LOAD FLAGS(0x4); +} + +SECTIONS +{ + .text : { *(.text) } :text + .data : { *(.data) } +} + +/* +FLAGS-PHDRS-SECS: .text {{[0-9a-f]+}} 00000000004000b0 +FLAGS-PHDRS-SECS: .data {{[0-9a-f]+}} 00000000004000dc + +FLAGS-PHDRS-HDRS: ProgramHeader { +FLAGS-PHDRS-HDRS: Type: PT_LOAD (0x1) +FLAGS-PHDRS-HDRS: VirtualAddress: 0x400000 +FLAGS-PHDRS-HDRS: Flags [ (0x4) +FLAGS-PHDRS-HDRS: PF_R (0x4) +FLAGS-PHDRS-HDRS: ] +FLAGS-PHDRS-HDRS: } +*/ diff --git a/lld/test/elf/linkerscript/phdrs-same.test b/lld/test/elf/linkerscript/phdrs-same.test new file mode 100644 index 000000000000..11620e0d45b6 --- /dev/null +++ b/lld/test/elf/linkerscript/phdrs-same.test @@ -0,0 +1,36 @@ +/* +Test sections put to same segment. + +RUN: yaml2obj -format=elf %p/Inputs/simple.o.yaml -o=%t.o + +RUN: lld -flavor gnu -target x86_64 -T %s %t.o -static -o %t1 +RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix SAME-PHDRS-SECS %s +RUN: llvm-readobj -program-headers %t1 | FileCheck -check-prefix SAME-PHDRS-HDRS %s +*/ + +ENTRY(_start) + +PHDRS +{ + text PT_LOAD; +} + +SECTIONS +{ + .text : { *(.text) } :text + .data : { *(.data) } +} + +/* +SAME-PHDRS-SECS: .text {{[0-9a-f]+}} 00000000004000b0 +SAME-PHDRS-SECS: .data {{[0-9a-f]+}} 00000000004000dc + +SAME-PHDRS-HDRS: ProgramHeader { +SAME-PHDRS-HDRS: Type: PT_LOAD (0x1) +SAME-PHDRS-HDRS: VirtualAddress: 0x400000 +SAME-PHDRS-HDRS: Flags [ (0x5) +SAME-PHDRS-HDRS: PF_R (0x4) +SAME-PHDRS-HDRS: PF_X (0x1) +SAME-PHDRS-HDRS: ] +SAME-PHDRS-HDRS: } +*/