[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
This commit is contained in:
Denis Protivensky 2015-07-23 10:34:30 +00:00
parent ffcc7663a2
commit cdc1246750
17 changed files with 395 additions and 105 deletions

View File

@ -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;

View File

@ -89,7 +89,7 @@ public:
inputSectionName));
}
SegmentType getSegmentType(Section<ELF32LE> *section) const override {
SegmentType getSegmentType(const Section<ELF32LE> *section) const override {
switch (section->order()) {
case ORDER_ARM_EXIDX:
return llvm::ELF::PT_ARM_EXIDX;

View File

@ -79,7 +79,7 @@ public:
/// \brief get the segment type for the section thats defined by the target
TargetLayout::SegmentType
getSegmentType(Section<ELF32LE> *section) const override {
getSegmentType(const Section<ELF32LE> *section) const override {
if (section->order() == ORDER_SDATA)
return PT_LOAD;
return TargetLayout::getSegmentType(section);

View File

@ -33,7 +33,7 @@ AtomSection<ELFT> *MipsTargetLayout<ELFT>::createSection(
template <class ELFT>
typename TargetLayout<ELFT>::SegmentType
MipsTargetLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
MipsTargetLayout<ELFT>::getSegmentType(const Section<ELFT> *section) const {
switch (section->order()) {
case ORDER_MIPS_REGINFO:
return _abiInfo.hasMipsAbiSection() ? llvm::ELF::PT_LOAD

View File

@ -38,7 +38,7 @@ public:
typename TargetLayout<ELFT>::SectionOrder order) override;
typename TargetLayout<ELFT>::SegmentType
getSegmentType(Section<ELFT> *section) const override;
getSegmentType(const Section<ELFT> *section) const override;
/// \brief GP offset relative to .got section.
uint64_t getGPOffset() const { return 0x7FF0; }

View File

@ -85,6 +85,10 @@ public:
return nullptr;
}
const OutputSection<ELFT> *getOutputSection() const {
return _outputSection;
}
void setOutputSection(OutputSection<ELFT> *os, bool isFirst = false) {
_outputSection = os;
_isFirstSectionInOutputSection = isFirst;

View File

@ -23,7 +23,7 @@ template <class ELFT>
Segment<ELFT>::Segment(const ELFLinkingContext &ctx, StringRef name,
const typename TargetLayout<ELFT>::SegmentType type)
: Chunk<ELFT>(name, Chunk<ELFT>::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 <class ELFT> void Segment<ELFT>::append(Chunk<ELFT> *chunk) {
_sections.push_back(chunk);
Section<ELFT> *section = dyn_cast<Section<ELFT>>(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 <class ELFT>
@ -389,6 +409,9 @@ void Segment<ELFT>::write(ELFWriter *writer, TargetLayout<ELFT> &layout,
}
template <class ELFT> int64_t Segment<ELFT>::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 <class ELFT> int64_t Segment<ELFT>::flags() const {
return fl;
}
template <class ELFT> void Segment<ELFT>::setSegmentFlags(uint64_t flags) {
assert(!_segmentFlags && !_flags && "Flags has already been set");
_segmentFlags = true;
_flags = flags;
_atomflags = toAtomPermsSegment(flags);
}
template <class ELFT> void Segment<ELFT>::finalize() {
// We want to finalize the segment values for now only for non loadable
// segments, since those values are not set in the Layout

View File

@ -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<ELFT> *c) {
_sections.insert(_sections.begin(), c);
@ -188,6 +191,7 @@ protected:
typename TargetLayout<ELFT>::SegmentType _segmentType;
uint64_t _flags;
int64_t _atomflags;
bool _segmentFlags;
llvm::BumpPtrAllocator _segmentAllocate;
};

View File

@ -133,7 +133,7 @@ TargetLayout<ELFT>::getOutputSectionName(StringRef archivePath,
/// \brief Gets the segment for a output section
template <class ELFT>
typename TargetLayout<ELFT>::SegmentType
TargetLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
TargetLayout<ELFT>::getSegmentType(const Section<ELFT> *section) const {
switch (section->order()) {
case ORDER_INTERP:
return llvm::ELF::PT_INTERP;
@ -320,7 +320,6 @@ template <class ELFT> void TargetLayout<ELFT>::createOutputSections() {
} else {
outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
OutputSection<ELFT>(section->outputSectionName());
checkOutputSectionSegment(outputSection);
_outputSections.push_back(outputSection);
outputSectionInsert.first->second = outputSection;
}
@ -328,15 +327,66 @@ template <class ELFT> void TargetLayout<ELFT>::createOutputSections() {
}
}
// Check that output section has proper segment set
template <class ELFT>
void TargetLayout<ELFT>::checkOutputSectionSegment(
const OutputSection<ELFT> *sec) {
std::vector<const script::PHDR *>
TargetLayout<ELFT>::getCustomSegments(const OutputSection<ELFT> *sec) const {
std::vector<const script::PHDR *> phdrs;
if (_linkerScriptSema.getPHDRsForOutputSection(sec->name(), phdrs)) {
llvm::report_fatal_error(
"Linker script has wrong segments set for output sections");
}
return phdrs;
}
template <class ELFT>
std::vector<const script::PHDR *>
TargetLayout<ELFT>::getCustomSegments(const Section<ELFT> *section) const {
auto sec = section->getOutputSection();
assert(sec && "Output section should be already set for input section");
return getCustomSegments(sec);
}
template <class ELFT>
std::vector<typename TargetLayout<ELFT>::SegmentKey>
TargetLayout<ELFT>::getSegmentsForSection(const OutputSection<ELFT> *os,
const Section<ELFT> *sec) const {
std::vector<SegmentKey> 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 <class ELFT>
@ -356,7 +406,6 @@ TargetLayout<ELFT>::getLookupSectionFlags(const OutputSection<ELFT> *os) const {
template <class ELFT> void TargetLayout<ELFT>::assignSectionsToSegments() {
ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
ELFLinkingContext::OutputMagic outputMagic = _ctx.getOutputMagic();
// sort the sections by their order as defined by the layout
sortInputSections();
@ -381,68 +430,42 @@ template <class ELFT> void TargetLayout<ELFT>::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<ELFT> *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<AdditionalSegmentKey, Segment<ELFT> *>
additionalSegment(key, nullptr);
std::pair<typename AdditionalSegmentMapT::iterator, bool>
additionalSegmentInsert(
_additionalSegmentMap.insert(additionalSegment));
if (!additionalSegmentInsert.second) {
segment = additionalSegmentInsert.first->second;
} else {
segment =
new (_allocator) Segment<ELFT>(_ctx, segmentName, segmentType);
additionalSegmentInsert.first->second = segment;
_segments.push_back(segment);
}
segment->append(section);
}
if (segmentType == llvm::ELF::PT_NULL)
continue;
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);
// 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<SegmentKey, Segment<ELFT> *> currentSegment(key, nullptr);
const std::pair<SegmentKey, Segment<ELFT> *> currentSegment(key,
nullptr);
std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
_segmentMap.insert(currentSegment));
Segment<ELFT> *segment;
if (!segmentInsert.second) {
segment = segmentInsert.first->second;
} else {
segment =
new (_allocator) Segment<ELFT>(_ctx, "PT_LOAD", llvm::ELF::PT_LOAD);
segment = new (_allocator) Segment<ELFT>(_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 (_ctx.isDynamic() && !_ctx.isDynamicLibrary()) {
Segment<ELFT> *segment = new (_allocator) ProgramHeaderSegment<ELFT>(_ctx);
_segments.push_back(segment);

View File

@ -106,32 +106,27 @@ public:
typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
typedef typename std::vector<Segment<ELFT> *>::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<int64_t, int64_t> AdditionalSegmentKey;
// The segments are created using
// SegmentName, Segment flags
typedef std::pair<StringRef, int64_t> 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:
struct SegmentKeyHash {
int64_t operator()(const SegmentKey &k) const {
// k.first = SegmentName
// k.second = SegmentFlags
return llvm::hash_combine(k.first, k.second);
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));
}
};
@ -143,10 +138,8 @@ public:
typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
SectionKeyEq> SectionMapT;
typedef std::unordered_map<AdditionalSegmentKey, Segment<ELFT> *,
AdditionalSegmentHashKey> AdditionalSegmentMapT;
typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
SegmentMapT;
typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentKeyHash,
SegmentKeyEq> SegmentMapT;
typedef typename std::vector<AtomLayout *>::iterator AbsoluteAtomIterT;
@ -177,7 +170,7 @@ public:
const DefinedAtom *da);
/// \brief Gets the segment for a output section
virtual SegmentType getSegmentType(Section<ELFT> *section) const;
virtual SegmentType getSegmentType(const Section<ELFT> *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<ELFT> *sec);
// Query for custom segments of the given section
std::vector<const script::PHDR *>
getCustomSegments(const Section<ELFT> *section) const;
// Query for custom segments of the given output section
std::vector<const script::PHDR *>
getCustomSegments(const OutputSection<ELFT> *sec) const;
// Query for segments based on output and input sections
std::vector<SegmentKey> getSegmentsForSection(const OutputSection<ELFT> *os,
const Section<ELFT> *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<Chunk<ELFT> *> _sections;
std::vector<Segment<ELFT> *> _segments;

View File

@ -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<const PHDR *, 2> phdrsCur, phdrsLast { PHDR::NONE };
llvm::SmallVector<const PHDR *, 2> phdrsCur, phdrsLast { &PHDR_NONE };
for (const Command *cmd : _layoutCommands) {
auto osd = dyn_cast<OutputSectionDescription>(cmd);
if (!osd || osd->isDiscarded())

View File

@ -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
*/

View File

@ -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: }
*/

View File

@ -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: }
*/

View File

@ -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: }
*/

View File

@ -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: }
*/

View File

@ -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: }
*/