Index: lld/trunk/include/lld/ReaderWriter/LinkerScript.h =================================================================== --- lld/trunk/include/lld/ReaderWriter/LinkerScript.h +++ lld/trunk/include/lld/ReaderWriter/LinkerScript.h @@ -817,12 +817,12 @@ _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; Index: lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h +++ lld/trunk/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -89,7 +89,7 @@ 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; Index: lld/trunk/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h +++ lld/trunk/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h @@ -79,7 +79,7 @@ /// \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); Index: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h +++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.h @@ -38,7 +38,7 @@ 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; } Index: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp +++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsTargetLayout.cpp @@ -33,7 +33,7 @@ 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 Index: lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h +++ lld/trunk/lib/ReaderWriter/ELF/SectionChunks.h @@ -85,6 +85,10 @@ return nullptr; } + const OutputSection *getOutputSection() const { + return _outputSection; + } + void setOutputSection(OutputSection *os, bool isFirst = false) { _outputSection = os; _isFirstSectionInOutputSection = isFirst; Index: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h +++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.h @@ -139,6 +139,9 @@ 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 @@ typename TargetLayout::SegmentType _segmentType; uint64_t _flags; int64_t _atomflags; + bool _segmentFlags; llvm::BumpPtrAllocator _segmentAllocate; }; Index: lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp +++ lld/trunk/lib/ReaderWriter/ELF/SegmentChunks.cpp @@ -23,7 +23,7 @@ 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 @@ } } +// 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 @@ } 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 @@ 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 Index: lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h +++ lld/trunk/lib/ReaderWriter/ELF/TargetLayout.h @@ -106,36 +106,31 @@ 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; - - // 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); + // 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; + }; + + 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 @@ 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 @@ 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 @@ // 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 @@ llvm::BumpPtrAllocator _allocator; SectionMapT _sectionMap; OutputSectionMapT _outputSectionMap; - AdditionalSegmentMapT _additionalSegmentMap; SegmentMapT _segmentMap; std::vector *> _sections; std::vector *> _segments; Index: lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp +++ lld/trunk/lib/ReaderWriter/ELF/TargetLayout.cpp @@ -133,7 +133,7 @@ /// \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 @@ } else { outputSection = new (_allocator.Allocate>()) OutputSection(section->outputSectionName()); - checkOutputSectionSegment(outputSection); _outputSections.push_back(outputSection); outputSectionInsert.first->second = outputSection; } @@ -328,15 +327,66 @@ } } -// 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 @@ 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 @@ 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); - - 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; + auto segKeys = getSegmentsForSection(osi, section); + assert(!segKeys.empty() && "Must always be at least one segment"); + section->setSegmentType(segKeys[0]._type); + + 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()) { Index: lld/trunk/lib/ReaderWriter/LinkerScript.cpp =================================================================== --- lld/trunk/lib/ReaderWriter/LinkerScript.cpp +++ lld/trunk/lib/ReaderWriter/LinkerScript.cpp @@ -937,6 +937,13 @@ } } +// 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 @@ 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 @@ // 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()) Index: lld/trunk/test/elf/linkerscript/phdrs-all-none.test =================================================================== --- lld/trunk/test/elf/linkerscript/phdrs-all-none.test +++ lld/trunk/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 +*/ Index: lld/trunk/test/elf/linkerscript/phdrs-different.test =================================================================== --- lld/trunk/test/elf/linkerscript/phdrs-different.test +++ lld/trunk/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: } +*/ Index: lld/trunk/test/elf/linkerscript/phdrs-flags.test =================================================================== --- lld/trunk/test/elf/linkerscript/phdrs-flags.test +++ lld/trunk/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: } +*/ Index: lld/trunk/test/elf/linkerscript/phdrs-one-none.test =================================================================== --- lld/trunk/test/elf/linkerscript/phdrs-one-none.test +++ lld/trunk/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: } +*/ Index: lld/trunk/test/elf/linkerscript/phdrs-same-flags.test =================================================================== --- lld/trunk/test/elf/linkerscript/phdrs-same-flags.test +++ lld/trunk/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: } +*/ Index: lld/trunk/test/elf/linkerscript/phdrs-same.test =================================================================== --- lld/trunk/test/elf/linkerscript/phdrs-same.test +++ lld/trunk/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: } +*/