Files
clang-p2996/lld/lib/ReaderWriter/ELF/TargetLayout.h
Denis Protivensky cdc1246750 [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
2015-07-23 10:34:30 +00:00

336 lines
11 KiB
C++

//===- lib/ReaderWriter/ELF/TargetLayout.h --------------------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
#include "Atoms.h"
#include "HeaderChunks.h"
#include "SectionChunks.h"
#include "SegmentChunks.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include <unordered_map>
namespace lld {
namespace elf {
/// \brief The TargetLayout class is used by the Writer to arrange
/// sections and segments in the order determined by the target ELF
/// format. The writer creates a single instance of the TargetLayout
/// class
template <class ELFT> class TargetLayout {
public:
typedef uint32_t SectionOrder;
typedef uint32_t SegmentType;
// The order in which the sections appear in the output file
// If its determined, that the layout needs to change
// just changing the order of enumerations would essentially
// change the layout in the output file
// Change the enumerations so that Target can override and stick
// a section anywhere it wants to
enum DefaultSectionOrder {
ORDER_NOT_DEFINED = 0,
ORDER_INTERP = 10,
ORDER_RO_NOTE = 15,
ORDER_HASH = 30,
ORDER_DYNAMIC_SYMBOLS = 40,
ORDER_DYNAMIC_STRINGS = 50,
ORDER_DYNAMIC_RELOCS = 52,
ORDER_DYNAMIC_PLT_RELOCS = 54,
ORDER_INIT = 60,
ORDER_PLT = 70,
ORDER_TEXT = 80,
ORDER_FINI = 90,
ORDER_REL = 95,
ORDER_RODATA = 100,
ORDER_EH_FRAME = 110,
ORDER_EH_FRAMEHDR = 120,
ORDER_TDATA = 124,
ORDER_TBSS = 128,
ORDER_CTORS = 130,
ORDER_DTORS = 140,
ORDER_INIT_ARRAY = 150,
ORDER_FINI_ARRAY = 160,
ORDER_DYNAMIC = 170,
ORDER_GOT = 180,
ORDER_GOT_PLT = 190,
ORDER_DATA = 200,
ORDER_RW_NOTE = 205,
ORDER_BSS = 210,
ORDER_NOALLOC = 215,
ORDER_OTHER = 220,
ORDER_SECTION_STRINGS = 230,
ORDER_SYMBOL_TABLE = 240,
ORDER_STRING_TABLE = 250,
ORDER_SECTION_HEADERS = 260
};
public:
// The Key used for creating Sections
// The sections are created using
// SectionName, contentPermissions
struct SectionKey {
SectionKey(StringRef name, DefinedAtom::ContentPermissions perm,
StringRef path)
: _name(name), _perm(perm), _path(path) {}
// Data members
StringRef _name;
DefinedAtom::ContentPermissions _perm;
StringRef _path;
};
struct SectionKeyHash {
int64_t operator()(const SectionKey &k) const {
return llvm::hash_combine(k._name, k._perm, k._path);
}
};
struct SectionKeyEq {
bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {
return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm) &&
(lhs._path == rhs._path));
}
};
typedef typename std::vector<Chunk<ELFT> *>::iterator ChunkIter;
typedef typename std::vector<Segment<ELFT> *>::iterator SegmentIter;
// 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);
}
};
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 Section names to a vector of sections,
// that have been merged to form a single section
typedef llvm::StringMap<OutputSection<ELFT> *> OutputSectionMapT;
typedef
typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter;
typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
SectionKeyEq> SectionMapT;
typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentKeyHash,
SegmentKeyEq> SegmentMapT;
typedef typename std::vector<AtomLayout *>::iterator AbsoluteAtomIterT;
typedef llvm::DenseSet<const Atom *> AtomSetT;
TargetLayout(ELFLinkingContext &ctx)
: _ctx(ctx), _linkerScriptSema(ctx.linkerScriptSema()) {}
virtual ~TargetLayout() = default;
/// \brief Return the section order for a input section
virtual SectionOrder getSectionOrder(StringRef name, int32_t contentType,
int32_t contentPermissions);
/// \brief Return the name of the input section by decoding the input
/// sectionChoice.
virtual StringRef getInputSectionName(const DefinedAtom *da) const;
/// \brief Return the name of the output section from the input section.
virtual StringRef getOutputSectionName(StringRef archivePath,
StringRef memberPath,
StringRef inputSectionName) const;
/// \brief Gets or creates a section.
AtomSection<ELFT> *
getSection(StringRef name, int32_t contentType,
DefinedAtom::ContentPermissions contentPermissions,
const DefinedAtom *da);
/// \brief Gets the segment for a output section
virtual SegmentType getSegmentType(const Section<ELFT> *section) const;
/// \brief Returns true/false depending on whether the section has a Output
// segment or not
static bool hasOutputSegment(Section<ELFT> *section);
/// \brief Append the Atom to the layout and create appropriate sections.
/// \returns A reference to the atom layout or an error. The atom layout will
/// be updated as linking progresses.
virtual ErrorOr<const AtomLayout *> addAtom(const Atom *atom);
/// \brief Find an output Section given a section name.
OutputSection<ELFT> *findOutputSection(StringRef name) {
auto iter = _outputSectionMap.find(name);
if (iter == _outputSectionMap.end())
return nullptr;
return iter->second;
}
/// \brief find a absolute atom given a name
AtomLayout *findAbsoluteAtom(StringRef name) {
auto iter = std::find_if(
_absoluteAtoms.begin(), _absoluteAtoms.end(),
[=](const AtomLayout *a) { return a->_atom->name() == name; });
if (iter == _absoluteAtoms.end())
return nullptr;
return *iter;
}
// Output sections with the same name into a OutputSection
void createOutputSections();
// 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.
virtual void sortInputSections();
/// \brief Add extra chunks to a segment just before including the input
/// section given by <archivePath, memberPath, sectionName>. This
/// is used to add linker script expressions before each section.
virtual void addExtraChunksToSegment(Segment<ELFT> *segment,
StringRef archivePath,
StringRef memberPath,
StringRef sectionName);
/// \brief associates a section to a segment
virtual void assignSectionsToSegments();
/// \brief associates a virtual address to the segment, section, and the atom
virtual void assignVirtualAddress();
void assignFileOffsetsForMiscSections();
range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
void addSection(Chunk<ELFT> *c) { _sections.push_back(c); }
void finalize() {
ScopedTask task(getDefaultDomain(), "Finalize layout");
for (auto &si : _sections)
si->finalize();
}
void doPreFlight() {
for (auto &si : _sections)
si->doPreFlight();
}
/// \brief find the Atom in the current layout
virtual const AtomLayout *findAtomLayoutByName(StringRef name) const;
void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; }
void setProgramHeader(ProgramHeader<ELFT> *p) {
_programHeader = p;
}
range<OutputSectionIter> outputSections() { return _outputSections; }
range<ChunkIter> sections() { return _sections; }
range<SegmentIter> segments() { return _segments; }
ELFHeader<ELFT> *getHeader() { return _elfHeader; }
bool hasDynamicRelocationTable() const { return !!_dynamicRelocationTable; }
bool hasPLTRelocationTable() const { return !!_pltRelocationTable; }
/// \brief Get or create the dynamic relocation table. All relocations in this
/// table are processed at startup.
RelocationTable<ELFT> *getDynamicRelocationTable();
/// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
RelocationTable<ELFT> *getPLTRelocationTable();
uint64_t getTLSSize() const;
bool isReferencedByDefinedAtom(const Atom *a) const {
return _referencedDynAtoms.count(a);
}
bool isCopied(const SharedLibraryAtom *sla) const {
return _copiedDynSymNames.count(sla->name());
}
protected:
/// \brief TargetLayouts may use these functions to reorder the input sections
/// in a order defined by their ABI.
virtual void finalizeOutputSectionLayout() {}
/// \brief Allocate a new section.
virtual AtomSection<ELFT> *createSection(
StringRef name, int32_t contentType,
DefinedAtom::ContentPermissions contentPermissions,
SectionOrder sectionOrder);
/// \brief Create a new relocation table.
virtual unique_bump_ptr<RelocationTable<ELFT>>
createRelocationTable(StringRef name, int32_t order) {
return unique_bump_ptr<RelocationTable<ELFT>>(
new (_allocator) RelocationTable<ELFT>(_ctx, name, order));
}
virtual uint64_t getLookupSectionFlags(const OutputSection<ELFT> *os) const;
/// \brief Sort segements stored in the _segments
virtual void sortSegments();
protected:
llvm::BumpPtrAllocator _allocator;
SectionMapT _sectionMap;
OutputSectionMapT _outputSectionMap;
SegmentMapT _segmentMap;
std::vector<Chunk<ELFT> *> _sections;
std::vector<Segment<ELFT> *> _segments;
std::vector<OutputSection<ELFT> *> _outputSections;
ELFHeader<ELFT> *_elfHeader;
ProgramHeader<ELFT> *_programHeader;
unique_bump_ptr<RelocationTable<ELFT>> _dynamicRelocationTable;
unique_bump_ptr<RelocationTable<ELFT>> _pltRelocationTable;
std::vector<AtomLayout *> _absoluteAtoms;
AtomSetT _referencedDynAtoms;
llvm::StringSet<> _copiedDynSymNames;
ELFLinkingContext &_ctx;
script::Sema &_linkerScriptSema;
};
} // end namespace elf
} // end namespace lld
#endif