[ELF] Delete empty TargetLayout class and rename DefaultLayout to TargetLayout
No functional changes. llvm-svn: 234052
This commit is contained in:
parent
b2e0f7a40f
commit
2181c10b5b
|
@ -28,7 +28,7 @@ public:
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &ctx)
|
ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &ctx)
|
||||||
: SymbolTable<ELFT>(ctx, ".symtab",
|
: SymbolTable<ELFT>(ctx, ".symtab",
|
||||||
DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
|
TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
|
void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
|
||||||
|
|
|
@ -1,998 +0,0 @@
|
||||||
//===- lib/ReaderWriter/ELF/DefaultLayout.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 "Chunk.h"
|
|
||||||
#include "HeaderChunks.h"
|
|
||||||
#include "Layout.h"
|
|
||||||
#include "SectionChunks.h"
|
|
||||||
#include "SegmentChunks.h"
|
|
||||||
#include "lld/Core/Instrumentation.h"
|
|
||||||
#include "lld/Core/STDExtras.h"
|
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
|
||||||
#include "llvm/ADT/DenseMap.h"
|
|
||||||
#include "llvm/ADT/DenseSet.h"
|
|
||||||
#include "llvm/ADT/Hashing.h"
|
|
||||||
#include "llvm/ADT/SmallVector.h"
|
|
||||||
#include "llvm/ADT/StringExtras.h"
|
|
||||||
#include "llvm/ADT/StringMap.h"
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
|
||||||
#include "llvm/Support/Errc.h"
|
|
||||||
#include "llvm/Support/Format.h"
|
|
||||||
#include <map>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace lld {
|
|
||||||
namespace elf {
|
|
||||||
/// \brief The DefaultLayout 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 DefaultLayout
|
|
||||||
/// class
|
|
||||||
template<class ELFT>
|
|
||||||
class DefaultLayout : public Layout {
|
|
||||||
public:
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class AdditionalSegmentHashKey {
|
|
||||||
public:
|
|
||||||
int64_t operator()(const AdditionalSegmentKey &k) const {
|
|
||||||
// k.first = SegmentName
|
|
||||||
// k.second = SegmentFlags
|
|
||||||
return llvm::hash_combine(k.first, k.second);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Output Sections contain the map of Sectionnames 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<AdditionalSegmentKey, Segment<ELFT> *,
|
|
||||||
AdditionalSegmentHashKey> AdditionalSegmentMapT;
|
|
||||||
typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
|
|
||||||
SegmentMapT;
|
|
||||||
|
|
||||||
typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
|
|
||||||
|
|
||||||
typedef llvm::DenseSet<const Atom *> AtomSetT;
|
|
||||||
|
|
||||||
DefaultLayout(ELFLinkingContext &ctx)
|
|
||||||
: _ctx(ctx), _linkerScriptSema(ctx.linkerScriptSema()) {}
|
|
||||||
|
|
||||||
/// \brief Return the section order for a input section
|
|
||||||
SectionOrder getSectionOrder(StringRef name, int32_t contentType,
|
|
||||||
int32_t contentPermissions) override;
|
|
||||||
|
|
||||||
/// \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 Layout::SegmentType getSegmentType(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);
|
|
||||||
|
|
||||||
// Adds an atom to the section
|
|
||||||
ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) override;
|
|
||||||
|
|
||||||
/// \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
|
|
||||||
lld::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();
|
|
||||||
|
|
||||||
/// \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);
|
|
||||||
|
|
||||||
void assignSectionsToSegments() override;
|
|
||||||
|
|
||||||
void assignVirtualAddress() override;
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
const AtomLayout *findAtomLayoutByName(StringRef name) const override {
|
|
||||||
for (auto sec : _sections)
|
|
||||||
if (auto section = dyn_cast<Section<ELFT>>(sec))
|
|
||||||
if (auto *al = section->findAtomLayoutByName(name))
|
|
||||||
return al;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
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() {
|
|
||||||
if (!_dynamicRelocationTable) {
|
|
||||||
_dynamicRelocationTable = std::move(createRelocationTable(
|
|
||||||
_ctx.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
|
|
||||||
ORDER_DYNAMIC_RELOCS));
|
|
||||||
addSection(_dynamicRelocationTable.get());
|
|
||||||
}
|
|
||||||
return _dynamicRelocationTable.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
|
|
||||||
RelocationTable<ELFT> *getPLTRelocationTable() {
|
|
||||||
if (!_pltRelocationTable) {
|
|
||||||
_pltRelocationTable = std::move(createRelocationTable(
|
|
||||||
_ctx.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
|
|
||||||
ORDER_DYNAMIC_PLT_RELOCS));
|
|
||||||
addSection(_pltRelocationTable.get());
|
|
||||||
}
|
|
||||||
return _pltRelocationTable.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t getTLSSize() const {
|
|
||||||
for (const auto &phdr : *_programHeader)
|
|
||||||
if (phdr->p_type == llvm::ELF::PT_TLS)
|
|
||||||
return phdr->p_memsz;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
llvm::BumpPtrAllocator _allocator;
|
|
||||||
SectionMapT _sectionMap;
|
|
||||||
OutputSectionMapT _outputSectionMap;
|
|
||||||
AdditionalSegmentMapT _additionalSegmentMap;
|
|
||||||
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<lld::AtomLayout *> _absoluteAtoms;
|
|
||||||
AtomSetT _referencedDynAtoms;
|
|
||||||
llvm::StringSet<> _copiedDynSymNames;
|
|
||||||
ELFLinkingContext &_ctx;
|
|
||||||
script::Sema &_linkerScriptSema;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
Layout::SectionOrder DefaultLayout<ELFT>::getSectionOrder(
|
|
||||||
StringRef name, int32_t contentType, int32_t contentPermissions) {
|
|
||||||
switch (contentType) {
|
|
||||||
case DefinedAtom::typeResolver:
|
|
||||||
case DefinedAtom::typeCode:
|
|
||||||
return llvm::StringSwitch<Layout::SectionOrder>(name)
|
|
||||||
.StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
|
|
||||||
.StartsWith(".eh_frame", ORDER_EH_FRAME)
|
|
||||||
.StartsWith(".init", ORDER_INIT)
|
|
||||||
.StartsWith(".fini", ORDER_FINI)
|
|
||||||
.StartsWith(".hash", ORDER_HASH)
|
|
||||||
.Default(ORDER_TEXT);
|
|
||||||
|
|
||||||
case DefinedAtom::typeConstant:
|
|
||||||
return ORDER_RODATA;
|
|
||||||
|
|
||||||
case DefinedAtom::typeData:
|
|
||||||
case DefinedAtom::typeDataFast:
|
|
||||||
return llvm::StringSwitch<Layout::SectionOrder>(name)
|
|
||||||
.StartsWith(".init_array", ORDER_INIT_ARRAY)
|
|
||||||
.StartsWith(".fini_array", ORDER_FINI_ARRAY)
|
|
||||||
.StartsWith(".dynamic", ORDER_DYNAMIC)
|
|
||||||
.StartsWith(".ctors", ORDER_CTORS)
|
|
||||||
.StartsWith(".dtors", ORDER_DTORS)
|
|
||||||
.Default(ORDER_DATA);
|
|
||||||
|
|
||||||
case DefinedAtom::typeZeroFill:
|
|
||||||
case DefinedAtom::typeZeroFillFast:
|
|
||||||
return ORDER_BSS;
|
|
||||||
|
|
||||||
case DefinedAtom::typeGOT:
|
|
||||||
return llvm::StringSwitch<Layout::SectionOrder>(name)
|
|
||||||
.StartsWith(".got.plt", ORDER_GOT_PLT)
|
|
||||||
.Default(ORDER_GOT);
|
|
||||||
|
|
||||||
case DefinedAtom::typeStub:
|
|
||||||
return ORDER_PLT;
|
|
||||||
|
|
||||||
case DefinedAtom::typeRONote:
|
|
||||||
return ORDER_RO_NOTE;
|
|
||||||
|
|
||||||
case DefinedAtom::typeRWNote:
|
|
||||||
return ORDER_RW_NOTE;
|
|
||||||
|
|
||||||
case DefinedAtom::typeNoAlloc:
|
|
||||||
return ORDER_NOALLOC;
|
|
||||||
|
|
||||||
case DefinedAtom::typeThreadData:
|
|
||||||
return ORDER_TDATA;
|
|
||||||
case DefinedAtom::typeThreadZeroFill:
|
|
||||||
return ORDER_TBSS;
|
|
||||||
default:
|
|
||||||
// If we get passed in a section push it to OTHER
|
|
||||||
if (contentPermissions == DefinedAtom::perm___)
|
|
||||||
return ORDER_OTHER;
|
|
||||||
|
|
||||||
return ORDER_NOT_DEFINED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief This maps the input sections to the output section names
|
|
||||||
template <class ELFT>
|
|
||||||
StringRef
|
|
||||||
DefaultLayout<ELFT>::getInputSectionName(const DefinedAtom *da) const {
|
|
||||||
if (da->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
|
|
||||||
switch (da->contentType()) {
|
|
||||||
case DefinedAtom::typeCode:
|
|
||||||
return ".text";
|
|
||||||
case DefinedAtom::typeData:
|
|
||||||
return ".data";
|
|
||||||
case DefinedAtom::typeConstant:
|
|
||||||
return ".rodata";
|
|
||||||
case DefinedAtom::typeZeroFill:
|
|
||||||
return ".bss";
|
|
||||||
case DefinedAtom::typeThreadData:
|
|
||||||
return ".tdata";
|
|
||||||
case DefinedAtom::typeThreadZeroFill:
|
|
||||||
return ".tbss";
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return da->customSectionName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief This maps the input sections to the output section names.
|
|
||||||
template <class ELFT>
|
|
||||||
StringRef
|
|
||||||
DefaultLayout<ELFT>::getOutputSectionName(StringRef archivePath,
|
|
||||||
StringRef memberPath,
|
|
||||||
StringRef inputSectionName) const {
|
|
||||||
StringRef outputSectionName;
|
|
||||||
if (_linkerScriptSema.hasLayoutCommands()) {
|
|
||||||
script::Sema::SectionKey key = {archivePath, memberPath, inputSectionName};
|
|
||||||
outputSectionName = _linkerScriptSema.getOutputSection(key);
|
|
||||||
if (!outputSectionName.empty())
|
|
||||||
return outputSectionName;
|
|
||||||
}
|
|
||||||
return llvm::StringSwitch<StringRef>(inputSectionName)
|
|
||||||
.StartsWith(".text", ".text")
|
|
||||||
.StartsWith(".ctors", ".ctors")
|
|
||||||
.StartsWith(".dtors", ".dtors")
|
|
||||||
.StartsWith(".rodata", ".rodata")
|
|
||||||
.StartsWith(".gcc_except_table", ".gcc_except_table")
|
|
||||||
.StartsWith(".data.rel.ro", ".data.rel.ro")
|
|
||||||
.StartsWith(".data.rel.local", ".data.rel.local")
|
|
||||||
.StartsWith(".data", ".data")
|
|
||||||
.StartsWith(".tdata", ".tdata")
|
|
||||||
.StartsWith(".tbss", ".tbss")
|
|
||||||
.StartsWith(".init_array", ".init_array")
|
|
||||||
.StartsWith(".fini_array", ".fini_array")
|
|
||||||
.Default(inputSectionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Gets the segment for a output section
|
|
||||||
template <class ELFT>
|
|
||||||
Layout::SegmentType DefaultLayout<ELFT>::getSegmentType(
|
|
||||||
Section<ELFT> *section) const {
|
|
||||||
|
|
||||||
switch (section->order()) {
|
|
||||||
case ORDER_INTERP:
|
|
||||||
return llvm::ELF::PT_INTERP;
|
|
||||||
|
|
||||||
case ORDER_TEXT:
|
|
||||||
case ORDER_HASH:
|
|
||||||
case ORDER_DYNAMIC_SYMBOLS:
|
|
||||||
case ORDER_DYNAMIC_STRINGS:
|
|
||||||
case ORDER_DYNAMIC_RELOCS:
|
|
||||||
case ORDER_DYNAMIC_PLT_RELOCS:
|
|
||||||
case ORDER_REL:
|
|
||||||
case ORDER_INIT:
|
|
||||||
case ORDER_PLT:
|
|
||||||
case ORDER_FINI:
|
|
||||||
case ORDER_RODATA:
|
|
||||||
case ORDER_EH_FRAME:
|
|
||||||
case ORDER_CTORS:
|
|
||||||
case ORDER_DTORS:
|
|
||||||
return llvm::ELF::PT_LOAD;
|
|
||||||
|
|
||||||
case ORDER_RO_NOTE:
|
|
||||||
case ORDER_RW_NOTE:
|
|
||||||
return llvm::ELF::PT_NOTE;
|
|
||||||
|
|
||||||
case ORDER_DYNAMIC:
|
|
||||||
return llvm::ELF::PT_DYNAMIC;
|
|
||||||
|
|
||||||
case ORDER_EH_FRAMEHDR:
|
|
||||||
return llvm::ELF::PT_GNU_EH_FRAME;
|
|
||||||
|
|
||||||
case ORDER_GOT:
|
|
||||||
case ORDER_GOT_PLT:
|
|
||||||
case ORDER_DATA:
|
|
||||||
case ORDER_BSS:
|
|
||||||
case ORDER_INIT_ARRAY:
|
|
||||||
case ORDER_FINI_ARRAY:
|
|
||||||
return llvm::ELF::PT_LOAD;
|
|
||||||
|
|
||||||
case ORDER_TDATA:
|
|
||||||
case ORDER_TBSS:
|
|
||||||
return llvm::ELF::PT_TLS;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return llvm::ELF::PT_NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
bool DefaultLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) {
|
|
||||||
switch (section->order()) {
|
|
||||||
case ORDER_INTERP:
|
|
||||||
case ORDER_HASH:
|
|
||||||
case ORDER_DYNAMIC_SYMBOLS:
|
|
||||||
case ORDER_DYNAMIC_STRINGS:
|
|
||||||
case ORDER_DYNAMIC_RELOCS:
|
|
||||||
case ORDER_DYNAMIC_PLT_RELOCS:
|
|
||||||
case ORDER_REL:
|
|
||||||
case ORDER_INIT:
|
|
||||||
case ORDER_PLT:
|
|
||||||
case ORDER_TEXT:
|
|
||||||
case ORDER_FINI:
|
|
||||||
case ORDER_RODATA:
|
|
||||||
case ORDER_EH_FRAME:
|
|
||||||
case ORDER_EH_FRAMEHDR:
|
|
||||||
case ORDER_TDATA:
|
|
||||||
case ORDER_TBSS:
|
|
||||||
case ORDER_RO_NOTE:
|
|
||||||
case ORDER_RW_NOTE:
|
|
||||||
case ORDER_DYNAMIC:
|
|
||||||
case ORDER_CTORS:
|
|
||||||
case ORDER_DTORS:
|
|
||||||
case ORDER_GOT:
|
|
||||||
case ORDER_GOT_PLT:
|
|
||||||
case ORDER_DATA:
|
|
||||||
case ORDER_INIT_ARRAY:
|
|
||||||
case ORDER_FINI_ARRAY:
|
|
||||||
case ORDER_BSS:
|
|
||||||
case ORDER_NOALLOC:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return section->hasOutputSegment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
AtomSection<ELFT> *DefaultLayout<ELFT>::createSection(
|
|
||||||
StringRef sectionName, int32_t contentType,
|
|
||||||
DefinedAtom::ContentPermissions permissions, SectionOrder sectionOrder) {
|
|
||||||
return new (_allocator) AtomSection<ELFT>(_ctx, sectionName, contentType,
|
|
||||||
permissions, sectionOrder);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
AtomSection<ELFT> *
|
|
||||||
DefaultLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType,
|
|
||||||
DefinedAtom::ContentPermissions permissions,
|
|
||||||
const DefinedAtom *da) {
|
|
||||||
const SectionKey sectionKey(sectionName, permissions, da->file().path());
|
|
||||||
SectionOrder sectionOrder = getSectionOrder(sectionName, contentType, permissions);
|
|
||||||
auto sec = _sectionMap.find(sectionKey);
|
|
||||||
if (sec != _sectionMap.end())
|
|
||||||
return sec->second;
|
|
||||||
AtomSection<ELFT> *newSec =
|
|
||||||
createSection(sectionName, contentType, permissions, sectionOrder);
|
|
||||||
|
|
||||||
newSec->setOutputSectionName(getOutputSectionName(
|
|
||||||
da->file().archivePath(), da->file().memberPath(), sectionName));
|
|
||||||
newSec->setOrder(sectionOrder);
|
|
||||||
newSec->setArchiveNameOrPath(da->file().archivePath());
|
|
||||||
newSec->setMemberNameOrPath(da->file().memberPath());
|
|
||||||
_sections.push_back(newSec);
|
|
||||||
_sectionMap.insert(std::make_pair(sectionKey, newSec));
|
|
||||||
return newSec;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
ErrorOr<const lld::AtomLayout *>
|
|
||||||
DefaultLayout<ELFT>::addAtom(const Atom *atom) {
|
|
||||||
if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) {
|
|
||||||
// HACK: Ignore undefined atoms. We need to adjust the interface so that
|
|
||||||
// undefined atoms can still be included in the output symbol table for
|
|
||||||
// -noinhibit-exec.
|
|
||||||
if (definedAtom->contentType() == DefinedAtom::typeUnknown)
|
|
||||||
return make_error_code(llvm::errc::invalid_argument);
|
|
||||||
const DefinedAtom::ContentPermissions permissions =
|
|
||||||
definedAtom->permissions();
|
|
||||||
const DefinedAtom::ContentType contentType = definedAtom->contentType();
|
|
||||||
|
|
||||||
StringRef sectionName = getInputSectionName(definedAtom);
|
|
||||||
AtomSection<ELFT> *section =
|
|
||||||
getSection(sectionName, contentType, permissions, definedAtom);
|
|
||||||
|
|
||||||
// Add runtime relocations to the .rela section.
|
|
||||||
for (const auto &reloc : *definedAtom) {
|
|
||||||
bool isLocalReloc = true;
|
|
||||||
if (_ctx.isDynamicRelocation(*reloc)) {
|
|
||||||
getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
|
|
||||||
isLocalReloc = false;
|
|
||||||
} else if (_ctx.isPLTRelocation(*reloc)) {
|
|
||||||
getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
|
|
||||||
isLocalReloc = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!reloc->target())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
//Ignore undefined atoms that are not target of dynamic relocations
|
|
||||||
if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (_ctx.isCopyRelocation(*reloc)) {
|
|
||||||
_copiedDynSymNames.insert(definedAtom->name());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
_referencedDynAtoms.insert(reloc->target());
|
|
||||||
}
|
|
||||||
return section->appendAtom(atom);
|
|
||||||
}
|
|
||||||
|
|
||||||
const AbsoluteAtom *absoluteAtom = cast<AbsoluteAtom>(atom);
|
|
||||||
// Absolute atoms are not part of any section, they are global for the whole
|
|
||||||
// link
|
|
||||||
_absoluteAtoms.push_back(
|
|
||||||
new (_allocator) lld::AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
|
|
||||||
return _absoluteAtoms.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Output sections with the same name into a OutputSection
|
|
||||||
template <class ELFT> void DefaultLayout<ELFT>::createOutputSections() {
|
|
||||||
OutputSection<ELFT> *outputSection;
|
|
||||||
|
|
||||||
for (auto &si : _sections) {
|
|
||||||
Section<ELFT> *section = dyn_cast<Section<ELFT>>(si);
|
|
||||||
if (!section)
|
|
||||||
continue;
|
|
||||||
const std::pair<StringRef, OutputSection<ELFT> *> currentOutputSection(
|
|
||||||
section->outputSectionName(), nullptr);
|
|
||||||
std::pair<typename OutputSectionMapT::iterator, bool> outputSectionInsert(
|
|
||||||
_outputSectionMap.insert(currentOutputSection));
|
|
||||||
if (!outputSectionInsert.second) {
|
|
||||||
outputSection = outputSectionInsert.first->second;
|
|
||||||
} else {
|
|
||||||
outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
|
|
||||||
OutputSection<ELFT>(section->outputSectionName());
|
|
||||||
_outputSections.push_back(outputSection);
|
|
||||||
outputSectionInsert.first->second = outputSection;
|
|
||||||
}
|
|
||||||
outputSection->appendSection(si);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {
|
|
||||||
ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
|
|
||||||
ELFLinkingContext::OutputMagic outputMagic = _ctx.getOutputMagic();
|
|
||||||
// sort the sections by their order as defined by the layout
|
|
||||||
sortInputSections();
|
|
||||||
|
|
||||||
// Create output sections.
|
|
||||||
createOutputSections();
|
|
||||||
|
|
||||||
// Finalize output section layout.
|
|
||||||
finalizeOutputSectionLayout();
|
|
||||||
|
|
||||||
// Set the ordinal after sorting the sections
|
|
||||||
int ordinal = 1;
|
|
||||||
for (auto osi : _outputSections) {
|
|
||||||
osi->setOrdinal(ordinal);
|
|
||||||
for (auto ai : osi->sections()) {
|
|
||||||
ai->setOrdinal(ordinal);
|
|
||||||
}
|
|
||||||
++ordinal;
|
|
||||||
}
|
|
||||||
for (auto osi : _outputSections) {
|
|
||||||
for (auto ai : osi->sections()) {
|
|
||||||
if (auto section = dyn_cast<Section<ELFT> >(ai)) {
|
|
||||||
if (!hasOutputSegment(section))
|
|
||||||
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();
|
|
||||||
|
|
||||||
int64_t lookupSectionFlag = osi->flags();
|
|
||||||
if ((!(lookupSectionFlag & llvm::ELF::SHF_WRITE)) &&
|
|
||||||
(_ctx.mergeRODataToTextSegment()))
|
|
||||||
lookupSectionFlag &= ~llvm::ELF::SHF_EXECINSTR;
|
|
||||||
|
|
||||||
// Merge string sections into Data segment itself
|
|
||||||
lookupSectionFlag &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE);
|
|
||||||
|
|
||||||
// Merge the TLS section into the DATA segment itself
|
|
||||||
lookupSectionFlag &= ~(llvm::ELF::SHF_TLS);
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
|
|
||||||
_segmentMap.insert(currentSegment));
|
|
||||||
if (!segmentInsert.second) {
|
|
||||||
segment = segmentInsert.first->second;
|
|
||||||
} else {
|
|
||||||
segment = new (_allocator)
|
|
||||||
Segment<ELFT>(_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()) {
|
|
||||||
Segment<ELFT> *segment = new (_allocator) ProgramHeaderSegment<ELFT>(_ctx);
|
|
||||||
_segments.push_back(segment);
|
|
||||||
segment->append(_elfHeader);
|
|
||||||
segment->append(_programHeader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ELFT>
|
|
||||||
void
|
|
||||||
DefaultLayout<ELFT>::assignVirtualAddress() {
|
|
||||||
if (_segments.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
|
|
||||||
|
|
||||||
uint64_t baseAddress = _ctx.getBaseAddress();
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// so that AT_PHDR is set correctly by the loader and so they are accessible
|
|
||||||
// at runtime. To do this we simply prepend them to the first loadable Segment
|
|
||||||
// and let the layout logic take care of it.
|
|
||||||
Segment<ELFT> *firstLoadSegment = nullptr;
|
|
||||||
for (auto si : _segments) {
|
|
||||||
if (si->segmentType() == llvm::ELF::PT_LOAD) {
|
|
||||||
firstLoadSegment = si;
|
|
||||||
si->firstSection()->setAlign(si->alignment());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(firstLoadSegment != nullptr && "No loadable segment!");
|
|
||||||
firstLoadSegment->prepend(_programHeader);
|
|
||||||
firstLoadSegment->prepend(_elfHeader);
|
|
||||||
bool newSegmentHeaderAdded = true;
|
|
||||||
bool virtualAddressAssigned = false;
|
|
||||||
bool fileOffsetAssigned = false;
|
|
||||||
while (true) {
|
|
||||||
for (auto si : _segments) {
|
|
||||||
si->finalize();
|
|
||||||
// Don't add PT_NULL segments into the program header
|
|
||||||
if (si->segmentType() != llvm::ELF::PT_NULL)
|
|
||||||
newSegmentHeaderAdded = _programHeader->addSegment(si);
|
|
||||||
}
|
|
||||||
if (!newSegmentHeaderAdded && virtualAddressAssigned)
|
|
||||||
break;
|
|
||||||
uint64_t address = baseAddress;
|
|
||||||
// start assigning virtual addresses
|
|
||||||
for (auto &si : _segments) {
|
|
||||||
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
|
||||||
(si->segmentType() != llvm::ELF::PT_NULL))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (si->segmentType() == llvm::ELF::PT_NULL) {
|
|
||||||
si->assignVirtualAddress(0 /*non loadable*/);
|
|
||||||
} else {
|
|
||||||
if (virtualAddressAssigned && (address != baseAddress) &&
|
|
||||||
(address == si->virtualAddr()))
|
|
||||||
break;
|
|
||||||
si->assignVirtualAddress(address);
|
|
||||||
}
|
|
||||||
address = si->virtualAddr() + si->memSize();
|
|
||||||
}
|
|
||||||
uint64_t baseFileOffset = 0;
|
|
||||||
uint64_t fileoffset = baseFileOffset;
|
|
||||||
for (auto &si : _segments) {
|
|
||||||
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
|
||||||
(si->segmentType() != llvm::ELF::PT_NULL))
|
|
||||||
continue;
|
|
||||||
if (fileOffsetAssigned && (fileoffset != baseFileOffset) &&
|
|
||||||
(fileoffset == si->fileOffset()))
|
|
||||||
break;
|
|
||||||
si->assignFileOffsets(fileoffset);
|
|
||||||
fileoffset = si->fileOffset() + si->fileSize();
|
|
||||||
}
|
|
||||||
virtualAddressAssigned = true;
|
|
||||||
fileOffsetAssigned = true;
|
|
||||||
_programHeader->resetProgramHeaders();
|
|
||||||
}
|
|
||||||
Section<ELFT> *section;
|
|
||||||
// Fix the offsets of all the atoms within a section
|
|
||||||
for (auto &si : _sections) {
|
|
||||||
section = dyn_cast<Section<ELFT>>(si);
|
|
||||||
if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
|
|
||||||
section->assignFileOffsets(section->fileOffset());
|
|
||||||
}
|
|
||||||
// Set the size of the merged Sections
|
|
||||||
for (auto osi : _outputSections) {
|
|
||||||
uint64_t sectionfileoffset = 0;
|
|
||||||
uint64_t startFileOffset = 0;
|
|
||||||
uint64_t sectionsize = 0;
|
|
||||||
bool isFirstSection = true;
|
|
||||||
for (auto si : osi->sections()) {
|
|
||||||
if (isFirstSection) {
|
|
||||||
startFileOffset = si->fileOffset();
|
|
||||||
isFirstSection = false;
|
|
||||||
}
|
|
||||||
sectionfileoffset = si->fileOffset();
|
|
||||||
sectionsize = si->fileSize();
|
|
||||||
}
|
|
||||||
sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
|
|
||||||
osi->setFileOffset(startFileOffset);
|
|
||||||
osi->setSize(sectionsize);
|
|
||||||
}
|
|
||||||
// Set the virtual addr of the merged Sections
|
|
||||||
for (auto osi : _outputSections) {
|
|
||||||
uint64_t sectionstartaddr = 0;
|
|
||||||
uint64_t startaddr = 0;
|
|
||||||
uint64_t sectionsize = 0;
|
|
||||||
bool isFirstSection = true;
|
|
||||||
for (auto si : osi->sections()) {
|
|
||||||
if (isFirstSection) {
|
|
||||||
startaddr = si->virtualAddr();
|
|
||||||
isFirstSection = false;
|
|
||||||
}
|
|
||||||
sectionstartaddr = si->virtualAddr();
|
|
||||||
sectionsize = si->memSize();
|
|
||||||
}
|
|
||||||
sectionsize = (sectionstartaddr - startaddr) + sectionsize;
|
|
||||||
osi->setMemSize(sectionsize);
|
|
||||||
osi->setAddr(startaddr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
void DefaultLayout<ELFT>::assignFileOffsetsForMiscSections() {
|
|
||||||
uint64_t fileoffset = 0;
|
|
||||||
uint64_t size = 0;
|
|
||||||
for (auto si : _segments) {
|
|
||||||
// Don't calculate offsets from non loadable segments
|
|
||||||
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
|
||||||
(si->segmentType() != llvm::ELF::PT_NULL))
|
|
||||||
continue;
|
|
||||||
fileoffset = si->fileOffset();
|
|
||||||
size = si->fileSize();
|
|
||||||
}
|
|
||||||
fileoffset = fileoffset + size;
|
|
||||||
Section<ELFT> *section;
|
|
||||||
for (auto si : _sections) {
|
|
||||||
section = dyn_cast<Section<ELFT>>(si);
|
|
||||||
if (section && DefaultLayout<ELFT>::hasOutputSegment(section))
|
|
||||||
continue;
|
|
||||||
fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment());
|
|
||||||
si->setFileOffset(fileoffset);
|
|
||||||
si->setVirtualAddr(0);
|
|
||||||
fileoffset += si->fileSize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT> void DefaultLayout<ELFT>::sortInputSections() {
|
|
||||||
// First, sort according to default layout's order
|
|
||||||
std::stable_sort(
|
|
||||||
_sections.begin(), _sections.end(),
|
|
||||||
[](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); });
|
|
||||||
|
|
||||||
if (!_linkerScriptSema.hasLayoutCommands())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Sort the sections by their order as defined by the linker script
|
|
||||||
std::stable_sort(this->_sections.begin(), this->_sections.end(),
|
|
||||||
[this](Chunk<ELFT> *A, Chunk<ELFT> *B) {
|
|
||||||
auto *a = dyn_cast<Section<ELFT>>(A);
|
|
||||||
auto *b = dyn_cast<Section<ELFT>>(B);
|
|
||||||
|
|
||||||
if (a == nullptr)
|
|
||||||
return false;
|
|
||||||
if (b == nullptr)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return _linkerScriptSema.less(
|
|
||||||
{a->archivePath(), a->memberPath(),
|
|
||||||
a->inputSectionName()},
|
|
||||||
{b->archivePath(), b->memberPath(),
|
|
||||||
b->inputSectionName()});
|
|
||||||
});
|
|
||||||
// Now try to arrange sections with no mapping rules to sections with
|
|
||||||
// similar content
|
|
||||||
auto p = this->_sections.begin();
|
|
||||||
// Find first section that has no assigned rule id
|
|
||||||
while (p != this->_sections.end()) {
|
|
||||||
auto *sect = dyn_cast<AtomSection<ELFT>>(*p);
|
|
||||||
if (!sect)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (!_linkerScriptSema.hasMapping({sect->archivePath(),
|
|
||||||
sect->memberPath(),
|
|
||||||
sect->inputSectionName()}))
|
|
||||||
break;
|
|
||||||
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
// For all sections that have no assigned rule id, try to move them near a
|
|
||||||
// section with similar contents
|
|
||||||
if (p != this->_sections.begin()) {
|
|
||||||
for (; p != this->_sections.end(); ++p) {
|
|
||||||
auto q = p;
|
|
||||||
--q;
|
|
||||||
while (q != this->_sections.begin() &&
|
|
||||||
(*q)->getContentType() != (*p)->getContentType())
|
|
||||||
--q;
|
|
||||||
if ((*q)->getContentType() != (*p)->getContentType())
|
|
||||||
continue;
|
|
||||||
++q;
|
|
||||||
for (auto i = p; i != q;) {
|
|
||||||
auto next = i--;
|
|
||||||
std::iter_swap(i, next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class ELFT>
|
|
||||||
void DefaultLayout<ELFT>::addExtraChunksToSegment(Segment<ELFT> *segment,
|
|
||||||
StringRef archivePath,
|
|
||||||
StringRef memberPath,
|
|
||||||
StringRef sectionName) {
|
|
||||||
if (!_linkerScriptSema.hasLayoutCommands())
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::vector<const script::SymbolAssignment *> exprs =
|
|
||||||
_linkerScriptSema.getExprs({archivePath, memberPath, sectionName});
|
|
||||||
for (auto expr : exprs) {
|
|
||||||
auto expChunk =
|
|
||||||
new (this->_allocator) ExpressionChunk<ELFT>(this->_ctx, expr);
|
|
||||||
segment->append(expChunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace elf
|
|
||||||
} // end namespace lld
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -116,7 +116,7 @@ template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
|
||||||
OutputELFWriter<ELFT>::createDefaultSections();
|
OutputELFWriter<ELFT>::createDefaultSections();
|
||||||
if (this->_ctx.isDynamic()) {
|
if (this->_ctx.isDynamic()) {
|
||||||
_interpSection.reset(new (this->_alloc) InterpSection<ELFT>(
|
_interpSection.reset(new (this->_alloc) InterpSection<ELFT>(
|
||||||
this->_ctx, ".interp", DefaultLayout<ELFT>::ORDER_INTERP,
|
this->_ctx, ".interp", TargetLayout<ELFT>::ORDER_INTERP,
|
||||||
this->_ctx.getInterpreter()));
|
this->_ctx.getInterpreter()));
|
||||||
this->_layout.addSection(_interpSection.get());
|
this->_layout.addSection(_interpSection.get());
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,8 @@ public:
|
||||||
(contentType == DefinedAtom::typeZeroFillFast))
|
(contentType == DefinedAtom::typeZeroFillFast))
|
||||||
return ORDER_SDATA;
|
return ORDER_SDATA;
|
||||||
|
|
||||||
return DefaultLayout<HexagonELFType>::getSectionOrder(name, contentType,
|
return TargetLayout<HexagonELFType>::getSectionOrder(name, contentType,
|
||||||
contentPermissions);
|
contentPermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Return the appropriate input section name.
|
/// \brief Return the appropriate input section name.
|
||||||
|
@ -53,7 +53,7 @@ public:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return DefaultLayout<HexagonELFType>::getInputSectionName(da);
|
return TargetLayout<HexagonELFType>::getInputSectionName(da);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Gets or creates a section.
|
/// \brief Gets or creates a section.
|
||||||
|
@ -64,7 +64,7 @@ public:
|
||||||
if ((contentType == DefinedAtom::typeDataFast) ||
|
if ((contentType == DefinedAtom::typeDataFast) ||
|
||||||
(contentType == DefinedAtom::typeZeroFillFast))
|
(contentType == DefinedAtom::typeZeroFillFast))
|
||||||
return _sdataSection;
|
return _sdataSection;
|
||||||
return DefaultLayout<HexagonELFType>::createSection(
|
return TargetLayout<HexagonELFType>::createSection(
|
||||||
name, contentType, contentPermissions, sectionOrder);
|
name, contentType, contentPermissions, sectionOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ public:
|
||||||
if (section->order() == ORDER_SDATA)
|
if (section->order() == ORDER_SDATA)
|
||||||
return PT_LOAD;
|
return PT_LOAD;
|
||||||
|
|
||||||
return DefaultLayout<HexagonELFType>::getSegmentType(section);
|
return TargetLayout<HexagonELFType>::getSegmentType(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
Section<HexagonELFType> *getSDataSection() const {
|
Section<HexagonELFType> *getSDataSection() const {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
|
#ifndef LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
|
||||||
#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
|
#define LLD_READER_WRITER_ELF_MIPS_MIPS_DYNAMIC_TABLE_H
|
||||||
|
|
||||||
#include "DefaultLayout.h"
|
#include "TargetLayout.h"
|
||||||
#include "SectionChunks.h"
|
#include "SectionChunks.h"
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
|
@ -23,7 +23,7 @@ public:
|
||||||
MipsDynamicTable(const ELFLinkingContext &ctx,
|
MipsDynamicTable(const ELFLinkingContext &ctx,
|
||||||
MipsTargetLayout<MipsELFType> &layout)
|
MipsTargetLayout<MipsELFType> &layout)
|
||||||
: DynamicTable<MipsELFType>(ctx, layout, ".dynamic",
|
: DynamicTable<MipsELFType>(ctx, layout, ".dynamic",
|
||||||
DefaultLayout<MipsELFType>::ORDER_DYNAMIC),
|
TargetLayout<MipsELFType>::ORDER_DYNAMIC),
|
||||||
_targetLayout(layout) {}
|
_targetLayout(layout) {}
|
||||||
|
|
||||||
void createDefaultEntries() override {
|
void createDefaultEntries() override {
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
return _gotSection;
|
return _gotSection;
|
||||||
if (type == DefinedAtom::typeStub && name == ".plt")
|
if (type == DefinedAtom::typeStub && name == ".plt")
|
||||||
return _pltSection;
|
return _pltSection;
|
||||||
return DefaultLayout<ELFT>::createSection(name, type, permissions, order);
|
return TargetLayout<ELFT>::createSection(name, type, permissions, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief GP offset relative to .got section.
|
/// \brief GP offset relative to .got section.
|
||||||
|
@ -63,10 +63,10 @@ public:
|
||||||
Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType,
|
Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType,
|
||||||
int32_t contentPermissions) override {
|
int32_t contentPermissions) override {
|
||||||
if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
|
if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
|
||||||
return DefaultLayout<ELFT>::ORDER_TEXT;
|
return TargetLayout<ELFT>::ORDER_TEXT;
|
||||||
|
|
||||||
return DefaultLayout<ELFT>::getSectionOrder(name, contentType,
|
return TargetLayout<ELFT>::getSectionOrder(name, contentType,
|
||||||
contentPermissions);
|
contentPermissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -130,7 +130,7 @@ public:
|
||||||
|
|
||||||
MipsSymbolTable(const ELFLinkingContext &ctx)
|
MipsSymbolTable(const ELFLinkingContext &ctx)
|
||||||
: SymbolTable<ELFT>(ctx, ".symtab",
|
: SymbolTable<ELFT>(ctx, ".symtab",
|
||||||
DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
|
TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
|
||||||
|
|
||||||
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
|
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
|
||||||
int64_t addr) override {
|
int64_t addr) override {
|
||||||
|
@ -172,7 +172,7 @@ public:
|
||||||
MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
|
MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
|
||||||
MipsTargetLayout<ELFT> &layout)
|
MipsTargetLayout<ELFT> &layout)
|
||||||
: DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
|
: DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
|
||||||
DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
|
TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
|
||||||
_targetLayout(layout) {}
|
_targetLayout(layout) {}
|
||||||
|
|
||||||
void sortSymbols() override {
|
void sortSymbols() override {
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
|
#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
|
||||||
#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
|
#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
|
||||||
|
|
||||||
#include "DefaultLayout.h"
|
|
||||||
#include "ELFFile.h"
|
#include "ELFFile.h"
|
||||||
#include "TargetLayout.h"
|
#include "TargetLayout.h"
|
||||||
#include "lld/Core/Instrumentation.h"
|
#include "lld/Core/Instrumentation.h"
|
||||||
|
@ -350,7 +349,7 @@ void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
|
||||||
_layout.assignFileOffsetsForMiscSections();
|
_layout.assignFileOffsetsForMiscSections();
|
||||||
for (auto sec : _layout.sections())
|
for (auto sec : _layout.sections())
|
||||||
if (auto section = dyn_cast<Section<ELFT>>(sec))
|
if (auto section = dyn_cast<Section<ELFT>>(sec))
|
||||||
if (!DefaultLayout<ELFT>::hasOutputSegment(section))
|
if (!TargetLayout<ELFT>::hasOutputSegment(section))
|
||||||
_shdrtab->updateSection(section);
|
_shdrtab->updateSection(section);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,11 +397,11 @@ template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
|
||||||
|
|
||||||
_symtab = std::move(this->createSymbolTable());
|
_symtab = std::move(this->createSymbolTable());
|
||||||
_strtab.reset(new (_alloc) StringTable<ELFT>(
|
_strtab.reset(new (_alloc) StringTable<ELFT>(
|
||||||
_ctx, ".strtab", DefaultLayout<ELFT>::ORDER_STRING_TABLE));
|
_ctx, ".strtab", TargetLayout<ELFT>::ORDER_STRING_TABLE));
|
||||||
_shstrtab.reset(new (_alloc) StringTable<ELFT>(
|
_shstrtab.reset(new (_alloc) StringTable<ELFT>(
|
||||||
_ctx, ".shstrtab", DefaultLayout<ELFT>::ORDER_SECTION_STRINGS));
|
_ctx, ".shstrtab", TargetLayout<ELFT>::ORDER_SECTION_STRINGS));
|
||||||
_shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
|
_shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
|
||||||
_ctx, DefaultLayout<ELFT>::ORDER_SECTION_HEADERS));
|
_ctx, TargetLayout<ELFT>::ORDER_SECTION_HEADERS));
|
||||||
_layout.addSection(_symtab.get());
|
_layout.addSection(_symtab.get());
|
||||||
_layout.addSection(_strtab.get());
|
_layout.addSection(_strtab.get());
|
||||||
_layout.addSection(_shstrtab.get());
|
_layout.addSection(_shstrtab.get());
|
||||||
|
@ -416,8 +415,7 @@ template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
|
||||||
if (!section || section->outputSectionName() != ".eh_frame")
|
if (!section || section->outputSectionName() != ".eh_frame")
|
||||||
continue;
|
continue;
|
||||||
_ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
|
_ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
|
||||||
_ctx, ".eh_frame_hdr", _layout,
|
_ctx, ".eh_frame_hdr", _layout, TargetLayout<ELFT>::ORDER_EH_FRAMEHDR));
|
||||||
DefaultLayout<ELFT>::ORDER_EH_FRAMEHDR));
|
|
||||||
_layout.addSection(_ehFrameHeader.get());
|
_layout.addSection(_ehFrameHeader.get());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -425,10 +423,10 @@ template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
|
||||||
if (_ctx.isDynamic()) {
|
if (_ctx.isDynamic()) {
|
||||||
_dynamicTable = std::move(createDynamicTable());
|
_dynamicTable = std::move(createDynamicTable());
|
||||||
_dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
|
_dynamicStringTable.reset(new (_alloc) StringTable<ELFT>(
|
||||||
_ctx, ".dynstr", DefaultLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
|
_ctx, ".dynstr", TargetLayout<ELFT>::ORDER_DYNAMIC_STRINGS, true));
|
||||||
_dynamicSymbolTable = std::move(createDynamicSymbolTable());
|
_dynamicSymbolTable = std::move(createDynamicSymbolTable());
|
||||||
_hashTable.reset(new (_alloc) HashSection<ELFT>(
|
_hashTable.reset(new (_alloc) HashSection<ELFT>(
|
||||||
_ctx, ".hash", DefaultLayout<ELFT>::ORDER_HASH));
|
_ctx, ".hash", TargetLayout<ELFT>::ORDER_HASH));
|
||||||
// Set the hash table in the dynamic symbol table so that the entries in the
|
// Set the hash table in the dynamic symbol table so that the entries in the
|
||||||
// hash table can be created
|
// hash table can be created
|
||||||
_dynamicSymbolTable->setHashTable(_hashTable.get());
|
_dynamicSymbolTable->setHashTable(_hashTable.get());
|
||||||
|
@ -453,7 +451,7 @@ template <class ELFT>
|
||||||
unique_bump_ptr<SymbolTable<ELFT>>
|
unique_bump_ptr<SymbolTable<ELFT>>
|
||||||
OutputELFWriter<ELFT>::createSymbolTable() {
|
OutputELFWriter<ELFT>::createSymbolTable() {
|
||||||
return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>(
|
return unique_bump_ptr<SymbolTable<ELFT>>(new (_alloc) SymbolTable<ELFT>(
|
||||||
this->_ctx, ".symtab", DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE));
|
this->_ctx, ".symtab", TargetLayout<ELFT>::ORDER_SYMBOL_TABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief create dynamic table
|
/// \brief create dynamic table
|
||||||
|
@ -461,7 +459,7 @@ template <class ELFT>
|
||||||
unique_bump_ptr<DynamicTable<ELFT>>
|
unique_bump_ptr<DynamicTable<ELFT>>
|
||||||
OutputELFWriter<ELFT>::createDynamicTable() {
|
OutputELFWriter<ELFT>::createDynamicTable() {
|
||||||
return unique_bump_ptr<DynamicTable<ELFT>>(new (_alloc) DynamicTable<ELFT>(
|
return unique_bump_ptr<DynamicTable<ELFT>>(new (_alloc) DynamicTable<ELFT>(
|
||||||
this->_ctx, _layout, ".dynamic", DefaultLayout<ELFT>::ORDER_DYNAMIC));
|
this->_ctx, _layout, ".dynamic", TargetLayout<ELFT>::ORDER_DYNAMIC));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief create dynamic symbol table
|
/// \brief create dynamic symbol table
|
||||||
|
@ -471,7 +469,7 @@ unique_bump_ptr<DynamicSymbolTable<ELFT>>
|
||||||
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
|
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
|
||||||
new (_alloc)
|
new (_alloc)
|
||||||
DynamicSymbolTable<ELFT>(this->_ctx, _layout, ".dynsym",
|
DynamicSymbolTable<ELFT>(this->_ctx, _layout, ".dynsym",
|
||||||
DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
|
TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class ELFT>
|
template <class ELFT>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
namespace lld {
|
namespace lld {
|
||||||
namespace elf {
|
namespace elf {
|
||||||
|
|
||||||
template <typename ELFT> class DefaultLayout;
|
template <typename ELFT> class TargetLayout;
|
||||||
|
|
||||||
/// \brief A segment can be divided into segment slices
|
/// \brief A segment can be divided into segment slices
|
||||||
/// depending on how the segments can be split
|
/// depending on how the segments can be split
|
||||||
|
@ -527,7 +527,7 @@ template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
|
||||||
// segment. If we see a tbss section, don't add memory size to addr The
|
// 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
|
// fileOffset is automatically taken care of since TBSS section does not
|
||||||
// end up using file size
|
// end up using file size
|
||||||
if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
|
if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS)
|
||||||
curSliceSize = (*si)->memSize();
|
curSliceSize = (*si)->memSize();
|
||||||
} else {
|
} else {
|
||||||
uint64_t curAddr = curSliceAddress + curSliceSize;
|
uint64_t curAddr = curSliceAddress + curSliceSize;
|
||||||
|
@ -610,7 +610,7 @@ template <class ELFT> void Segment<ELFT>::assignVirtualAddress(uint64_t addr) {
|
||||||
// any segment. If we see a tbss section, don't add memory size to addr
|
// 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
|
// The fileOffset is automatically taken care of since TBSS section does
|
||||||
// not end up using file size.
|
// not end up using file size.
|
||||||
if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
|
if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS)
|
||||||
curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
|
curSliceSize = newAddr - curSliceAddress + (*si)->memSize();
|
||||||
else
|
else
|
||||||
curSliceSize = newAddr - curSliceAddress;
|
curSliceSize = newAddr - curSliceAddress;
|
||||||
|
|
|
@ -7,21 +7,988 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#ifndef LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
|
#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
|
||||||
#define LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
|
#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
|
||||||
|
|
||||||
#include "DefaultLayout.h"
|
#include "Atoms.h"
|
||||||
#include "lld/Core/LLVM.h"
|
#include "Chunk.h"
|
||||||
|
#include "HeaderChunks.h"
|
||||||
|
#include "Layout.h"
|
||||||
|
#include "SectionChunks.h"
|
||||||
|
#include "SegmentChunks.h"
|
||||||
|
#include "lld/Core/Instrumentation.h"
|
||||||
|
#include "lld/Core/STDExtras.h"
|
||||||
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/DenseSet.h"
|
||||||
|
#include "llvm/ADT/Hashing.h"
|
||||||
|
#include "llvm/ADT/SmallVector.h"
|
||||||
|
#include "llvm/ADT/StringExtras.h"
|
||||||
|
#include "llvm/ADT/StringMap.h"
|
||||||
|
#include "llvm/ADT/StringRef.h"
|
||||||
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
|
#include "llvm/Support/Errc.h"
|
||||||
|
#include "llvm/Support/Format.h"
|
||||||
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace lld {
|
namespace lld {
|
||||||
namespace elf {
|
namespace elf {
|
||||||
/// \brief The target can override certain functions in the DefaultLayout
|
/// \brief The TargetLayout class is used by the Writer to arrange
|
||||||
/// class so that the order, the name of the section and the segment type could
|
/// sections and segments in the order determined by the target ELF
|
||||||
/// be changed in the final layout
|
/// format. The writer creates a single instance of the TargetLayout
|
||||||
template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> {
|
/// class
|
||||||
|
template<class ELFT>
|
||||||
|
class TargetLayout : public Layout {
|
||||||
public:
|
public:
|
||||||
TargetLayout(ELFLinkingContext &ctx) : DefaultLayout<ELFT>(ctx) {}
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AdditionalSegmentHashKey {
|
||||||
|
public:
|
||||||
|
int64_t operator()(const AdditionalSegmentKey &k) const {
|
||||||
|
// k.first = SegmentName
|
||||||
|
// k.second = SegmentFlags
|
||||||
|
return llvm::hash_combine(k.first, k.second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Output Sections contain the map of Sectionnames 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<AdditionalSegmentKey, Segment<ELFT> *,
|
||||||
|
AdditionalSegmentHashKey> AdditionalSegmentMapT;
|
||||||
|
typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
|
||||||
|
SegmentMapT;
|
||||||
|
|
||||||
|
typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
|
||||||
|
|
||||||
|
typedef llvm::DenseSet<const Atom *> AtomSetT;
|
||||||
|
|
||||||
|
TargetLayout(ELFLinkingContext &ctx)
|
||||||
|
: _ctx(ctx), _linkerScriptSema(ctx.linkerScriptSema()) {}
|
||||||
|
|
||||||
|
/// \brief Return the section order for a input section
|
||||||
|
SectionOrder getSectionOrder(StringRef name, int32_t contentType,
|
||||||
|
int32_t contentPermissions) override;
|
||||||
|
|
||||||
|
/// \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 Layout::SegmentType getSegmentType(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);
|
||||||
|
|
||||||
|
// Adds an atom to the section
|
||||||
|
ErrorOr<const lld::AtomLayout *> addAtom(const Atom *atom) override;
|
||||||
|
|
||||||
|
/// \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
|
||||||
|
lld::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();
|
||||||
|
|
||||||
|
/// \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);
|
||||||
|
|
||||||
|
void assignSectionsToSegments() override;
|
||||||
|
|
||||||
|
void assignVirtualAddress() override;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
const AtomLayout *findAtomLayoutByName(StringRef name) const override {
|
||||||
|
for (auto sec : _sections)
|
||||||
|
if (auto section = dyn_cast<Section<ELFT>>(sec))
|
||||||
|
if (auto *al = section->findAtomLayoutByName(name))
|
||||||
|
return al;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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() {
|
||||||
|
if (!_dynamicRelocationTable) {
|
||||||
|
_dynamicRelocationTable = std::move(createRelocationTable(
|
||||||
|
_ctx.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
|
||||||
|
ORDER_DYNAMIC_RELOCS));
|
||||||
|
addSection(_dynamicRelocationTable.get());
|
||||||
|
}
|
||||||
|
return _dynamicRelocationTable.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get or create the PLT relocation table. Referenced by DT_JMPREL.
|
||||||
|
RelocationTable<ELFT> *getPLTRelocationTable() {
|
||||||
|
if (!_pltRelocationTable) {
|
||||||
|
_pltRelocationTable = std::move(createRelocationTable(
|
||||||
|
_ctx.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
|
||||||
|
ORDER_DYNAMIC_PLT_RELOCS));
|
||||||
|
addSection(_pltRelocationTable.get());
|
||||||
|
}
|
||||||
|
return _pltRelocationTable.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t getTLSSize() const {
|
||||||
|
for (const auto &phdr : *_programHeader)
|
||||||
|
if (phdr->p_type == llvm::ELF::PT_TLS)
|
||||||
|
return phdr->p_memsz;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
llvm::BumpPtrAllocator _allocator;
|
||||||
|
SectionMapT _sectionMap;
|
||||||
|
OutputSectionMapT _outputSectionMap;
|
||||||
|
AdditionalSegmentMapT _additionalSegmentMap;
|
||||||
|
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<lld::AtomLayout *> _absoluteAtoms;
|
||||||
|
AtomSetT _referencedDynAtoms;
|
||||||
|
llvm::StringSet<> _copiedDynSymNames;
|
||||||
|
ELFLinkingContext &_ctx;
|
||||||
|
script::Sema &_linkerScriptSema;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
Layout::SectionOrder
|
||||||
|
TargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType,
|
||||||
|
int32_t contentPermissions) {
|
||||||
|
switch (contentType) {
|
||||||
|
case DefinedAtom::typeResolver:
|
||||||
|
case DefinedAtom::typeCode:
|
||||||
|
return llvm::StringSwitch<Layout::SectionOrder>(name)
|
||||||
|
.StartsWith(".eh_frame_hdr", ORDER_EH_FRAMEHDR)
|
||||||
|
.StartsWith(".eh_frame", ORDER_EH_FRAME)
|
||||||
|
.StartsWith(".init", ORDER_INIT)
|
||||||
|
.StartsWith(".fini", ORDER_FINI)
|
||||||
|
.StartsWith(".hash", ORDER_HASH)
|
||||||
|
.Default(ORDER_TEXT);
|
||||||
|
|
||||||
|
case DefinedAtom::typeConstant:
|
||||||
|
return ORDER_RODATA;
|
||||||
|
|
||||||
|
case DefinedAtom::typeData:
|
||||||
|
case DefinedAtom::typeDataFast:
|
||||||
|
return llvm::StringSwitch<Layout::SectionOrder>(name)
|
||||||
|
.StartsWith(".init_array", ORDER_INIT_ARRAY)
|
||||||
|
.StartsWith(".fini_array", ORDER_FINI_ARRAY)
|
||||||
|
.StartsWith(".dynamic", ORDER_DYNAMIC)
|
||||||
|
.StartsWith(".ctors", ORDER_CTORS)
|
||||||
|
.StartsWith(".dtors", ORDER_DTORS)
|
||||||
|
.Default(ORDER_DATA);
|
||||||
|
|
||||||
|
case DefinedAtom::typeZeroFill:
|
||||||
|
case DefinedAtom::typeZeroFillFast:
|
||||||
|
return ORDER_BSS;
|
||||||
|
|
||||||
|
case DefinedAtom::typeGOT:
|
||||||
|
return llvm::StringSwitch<Layout::SectionOrder>(name)
|
||||||
|
.StartsWith(".got.plt", ORDER_GOT_PLT)
|
||||||
|
.Default(ORDER_GOT);
|
||||||
|
|
||||||
|
case DefinedAtom::typeStub:
|
||||||
|
return ORDER_PLT;
|
||||||
|
|
||||||
|
case DefinedAtom::typeRONote:
|
||||||
|
return ORDER_RO_NOTE;
|
||||||
|
|
||||||
|
case DefinedAtom::typeRWNote:
|
||||||
|
return ORDER_RW_NOTE;
|
||||||
|
|
||||||
|
case DefinedAtom::typeNoAlloc:
|
||||||
|
return ORDER_NOALLOC;
|
||||||
|
|
||||||
|
case DefinedAtom::typeThreadData:
|
||||||
|
return ORDER_TDATA;
|
||||||
|
case DefinedAtom::typeThreadZeroFill:
|
||||||
|
return ORDER_TBSS;
|
||||||
|
default:
|
||||||
|
// If we get passed in a section push it to OTHER
|
||||||
|
if (contentPermissions == DefinedAtom::perm___)
|
||||||
|
return ORDER_OTHER;
|
||||||
|
|
||||||
|
return ORDER_NOT_DEFINED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief This maps the input sections to the output section names
|
||||||
|
template <class ELFT>
|
||||||
|
StringRef TargetLayout<ELFT>::getInputSectionName(const DefinedAtom *da) const {
|
||||||
|
if (da->sectionChoice() == DefinedAtom::sectionBasedOnContent) {
|
||||||
|
switch (da->contentType()) {
|
||||||
|
case DefinedAtom::typeCode:
|
||||||
|
return ".text";
|
||||||
|
case DefinedAtom::typeData:
|
||||||
|
return ".data";
|
||||||
|
case DefinedAtom::typeConstant:
|
||||||
|
return ".rodata";
|
||||||
|
case DefinedAtom::typeZeroFill:
|
||||||
|
return ".bss";
|
||||||
|
case DefinedAtom::typeThreadData:
|
||||||
|
return ".tdata";
|
||||||
|
case DefinedAtom::typeThreadZeroFill:
|
||||||
|
return ".tbss";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return da->customSectionName();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief This maps the input sections to the output section names.
|
||||||
|
template <class ELFT>
|
||||||
|
StringRef
|
||||||
|
TargetLayout<ELFT>::getOutputSectionName(StringRef archivePath,
|
||||||
|
StringRef memberPath,
|
||||||
|
StringRef inputSectionName) const {
|
||||||
|
StringRef outputSectionName;
|
||||||
|
if (_linkerScriptSema.hasLayoutCommands()) {
|
||||||
|
script::Sema::SectionKey key = {archivePath, memberPath, inputSectionName};
|
||||||
|
outputSectionName = _linkerScriptSema.getOutputSection(key);
|
||||||
|
if (!outputSectionName.empty())
|
||||||
|
return outputSectionName;
|
||||||
|
}
|
||||||
|
return llvm::StringSwitch<StringRef>(inputSectionName)
|
||||||
|
.StartsWith(".text", ".text")
|
||||||
|
.StartsWith(".ctors", ".ctors")
|
||||||
|
.StartsWith(".dtors", ".dtors")
|
||||||
|
.StartsWith(".rodata", ".rodata")
|
||||||
|
.StartsWith(".gcc_except_table", ".gcc_except_table")
|
||||||
|
.StartsWith(".data.rel.ro", ".data.rel.ro")
|
||||||
|
.StartsWith(".data.rel.local", ".data.rel.local")
|
||||||
|
.StartsWith(".data", ".data")
|
||||||
|
.StartsWith(".tdata", ".tdata")
|
||||||
|
.StartsWith(".tbss", ".tbss")
|
||||||
|
.StartsWith(".init_array", ".init_array")
|
||||||
|
.StartsWith(".fini_array", ".fini_array")
|
||||||
|
.Default(inputSectionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Gets the segment for a output section
|
||||||
|
template <class ELFT>
|
||||||
|
Layout::SegmentType
|
||||||
|
TargetLayout<ELFT>::getSegmentType(Section<ELFT> *section) const {
|
||||||
|
switch (section->order()) {
|
||||||
|
case ORDER_INTERP:
|
||||||
|
return llvm::ELF::PT_INTERP;
|
||||||
|
|
||||||
|
case ORDER_TEXT:
|
||||||
|
case ORDER_HASH:
|
||||||
|
case ORDER_DYNAMIC_SYMBOLS:
|
||||||
|
case ORDER_DYNAMIC_STRINGS:
|
||||||
|
case ORDER_DYNAMIC_RELOCS:
|
||||||
|
case ORDER_DYNAMIC_PLT_RELOCS:
|
||||||
|
case ORDER_REL:
|
||||||
|
case ORDER_INIT:
|
||||||
|
case ORDER_PLT:
|
||||||
|
case ORDER_FINI:
|
||||||
|
case ORDER_RODATA:
|
||||||
|
case ORDER_EH_FRAME:
|
||||||
|
case ORDER_CTORS:
|
||||||
|
case ORDER_DTORS:
|
||||||
|
return llvm::ELF::PT_LOAD;
|
||||||
|
|
||||||
|
case ORDER_RO_NOTE:
|
||||||
|
case ORDER_RW_NOTE:
|
||||||
|
return llvm::ELF::PT_NOTE;
|
||||||
|
|
||||||
|
case ORDER_DYNAMIC:
|
||||||
|
return llvm::ELF::PT_DYNAMIC;
|
||||||
|
|
||||||
|
case ORDER_EH_FRAMEHDR:
|
||||||
|
return llvm::ELF::PT_GNU_EH_FRAME;
|
||||||
|
|
||||||
|
case ORDER_GOT:
|
||||||
|
case ORDER_GOT_PLT:
|
||||||
|
case ORDER_DATA:
|
||||||
|
case ORDER_BSS:
|
||||||
|
case ORDER_INIT_ARRAY:
|
||||||
|
case ORDER_FINI_ARRAY:
|
||||||
|
return llvm::ELF::PT_LOAD;
|
||||||
|
|
||||||
|
case ORDER_TDATA:
|
||||||
|
case ORDER_TBSS:
|
||||||
|
return llvm::ELF::PT_TLS;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return llvm::ELF::PT_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
bool TargetLayout<ELFT>::hasOutputSegment(Section<ELFT> *section) {
|
||||||
|
switch (section->order()) {
|
||||||
|
case ORDER_INTERP:
|
||||||
|
case ORDER_HASH:
|
||||||
|
case ORDER_DYNAMIC_SYMBOLS:
|
||||||
|
case ORDER_DYNAMIC_STRINGS:
|
||||||
|
case ORDER_DYNAMIC_RELOCS:
|
||||||
|
case ORDER_DYNAMIC_PLT_RELOCS:
|
||||||
|
case ORDER_REL:
|
||||||
|
case ORDER_INIT:
|
||||||
|
case ORDER_PLT:
|
||||||
|
case ORDER_TEXT:
|
||||||
|
case ORDER_FINI:
|
||||||
|
case ORDER_RODATA:
|
||||||
|
case ORDER_EH_FRAME:
|
||||||
|
case ORDER_EH_FRAMEHDR:
|
||||||
|
case ORDER_TDATA:
|
||||||
|
case ORDER_TBSS:
|
||||||
|
case ORDER_RO_NOTE:
|
||||||
|
case ORDER_RW_NOTE:
|
||||||
|
case ORDER_DYNAMIC:
|
||||||
|
case ORDER_CTORS:
|
||||||
|
case ORDER_DTORS:
|
||||||
|
case ORDER_GOT:
|
||||||
|
case ORDER_GOT_PLT:
|
||||||
|
case ORDER_DATA:
|
||||||
|
case ORDER_INIT_ARRAY:
|
||||||
|
case ORDER_FINI_ARRAY:
|
||||||
|
case ORDER_BSS:
|
||||||
|
case ORDER_NOALLOC:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return section->hasOutputSegment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
AtomSection<ELFT> *
|
||||||
|
TargetLayout<ELFT>::createSection(StringRef sectionName, int32_t contentType,
|
||||||
|
DefinedAtom::ContentPermissions permissions,
|
||||||
|
SectionOrder sectionOrder) {
|
||||||
|
return new (_allocator) AtomSection<ELFT>(_ctx, sectionName, contentType,
|
||||||
|
permissions, sectionOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
AtomSection<ELFT> *
|
||||||
|
TargetLayout<ELFT>::getSection(StringRef sectionName, int32_t contentType,
|
||||||
|
DefinedAtom::ContentPermissions permissions,
|
||||||
|
const DefinedAtom *da) {
|
||||||
|
const SectionKey sectionKey(sectionName, permissions, da->file().path());
|
||||||
|
SectionOrder sectionOrder = getSectionOrder(sectionName, contentType, permissions);
|
||||||
|
auto sec = _sectionMap.find(sectionKey);
|
||||||
|
if (sec != _sectionMap.end())
|
||||||
|
return sec->second;
|
||||||
|
AtomSection<ELFT> *newSec =
|
||||||
|
createSection(sectionName, contentType, permissions, sectionOrder);
|
||||||
|
|
||||||
|
newSec->setOutputSectionName(getOutputSectionName(
|
||||||
|
da->file().archivePath(), da->file().memberPath(), sectionName));
|
||||||
|
newSec->setOrder(sectionOrder);
|
||||||
|
newSec->setArchiveNameOrPath(da->file().archivePath());
|
||||||
|
newSec->setMemberNameOrPath(da->file().memberPath());
|
||||||
|
_sections.push_back(newSec);
|
||||||
|
_sectionMap.insert(std::make_pair(sectionKey, newSec));
|
||||||
|
return newSec;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
ErrorOr<const lld::AtomLayout *> TargetLayout<ELFT>::addAtom(const Atom *atom) {
|
||||||
|
if (const DefinedAtom *definedAtom = dyn_cast<DefinedAtom>(atom)) {
|
||||||
|
// HACK: Ignore undefined atoms. We need to adjust the interface so that
|
||||||
|
// undefined atoms can still be included in the output symbol table for
|
||||||
|
// -noinhibit-exec.
|
||||||
|
if (definedAtom->contentType() == DefinedAtom::typeUnknown)
|
||||||
|
return make_error_code(llvm::errc::invalid_argument);
|
||||||
|
const DefinedAtom::ContentPermissions permissions =
|
||||||
|
definedAtom->permissions();
|
||||||
|
const DefinedAtom::ContentType contentType = definedAtom->contentType();
|
||||||
|
|
||||||
|
StringRef sectionName = getInputSectionName(definedAtom);
|
||||||
|
AtomSection<ELFT> *section =
|
||||||
|
getSection(sectionName, contentType, permissions, definedAtom);
|
||||||
|
|
||||||
|
// Add runtime relocations to the .rela section.
|
||||||
|
for (const auto &reloc : *definedAtom) {
|
||||||
|
bool isLocalReloc = true;
|
||||||
|
if (_ctx.isDynamicRelocation(*reloc)) {
|
||||||
|
getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
|
||||||
|
isLocalReloc = false;
|
||||||
|
} else if (_ctx.isPLTRelocation(*reloc)) {
|
||||||
|
getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
|
||||||
|
isLocalReloc = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!reloc->target())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Ignore undefined atoms that are not target of dynamic relocations
|
||||||
|
if (isa<UndefinedAtom>(reloc->target()) && isLocalReloc)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (_ctx.isCopyRelocation(*reloc)) {
|
||||||
|
_copiedDynSymNames.insert(definedAtom->name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_referencedDynAtoms.insert(reloc->target());
|
||||||
|
}
|
||||||
|
return section->appendAtom(atom);
|
||||||
|
}
|
||||||
|
|
||||||
|
const AbsoluteAtom *absoluteAtom = cast<AbsoluteAtom>(atom);
|
||||||
|
// Absolute atoms are not part of any section, they are global for the whole
|
||||||
|
// link
|
||||||
|
_absoluteAtoms.push_back(
|
||||||
|
new (_allocator) lld::AtomLayout(absoluteAtom, 0, absoluteAtom->value()));
|
||||||
|
return _absoluteAtoms.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Output sections with the same name into a OutputSection
|
||||||
|
template <class ELFT> void TargetLayout<ELFT>::createOutputSections() {
|
||||||
|
OutputSection<ELFT> *outputSection;
|
||||||
|
|
||||||
|
for (auto &si : _sections) {
|
||||||
|
Section<ELFT> *section = dyn_cast<Section<ELFT>>(si);
|
||||||
|
if (!section)
|
||||||
|
continue;
|
||||||
|
const std::pair<StringRef, OutputSection<ELFT> *> currentOutputSection(
|
||||||
|
section->outputSectionName(), nullptr);
|
||||||
|
std::pair<typename OutputSectionMapT::iterator, bool> outputSectionInsert(
|
||||||
|
_outputSectionMap.insert(currentOutputSection));
|
||||||
|
if (!outputSectionInsert.second) {
|
||||||
|
outputSection = outputSectionInsert.first->second;
|
||||||
|
} else {
|
||||||
|
outputSection = new (_allocator.Allocate<OutputSection<ELFT>>())
|
||||||
|
OutputSection<ELFT>(section->outputSectionName());
|
||||||
|
_outputSections.push_back(outputSection);
|
||||||
|
outputSectionInsert.first->second = outputSection;
|
||||||
|
}
|
||||||
|
outputSection->appendSection(si);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Create output sections.
|
||||||
|
createOutputSections();
|
||||||
|
|
||||||
|
// Finalize output section layout.
|
||||||
|
finalizeOutputSectionLayout();
|
||||||
|
|
||||||
|
// Set the ordinal after sorting the sections
|
||||||
|
int ordinal = 1;
|
||||||
|
for (auto osi : _outputSections) {
|
||||||
|
osi->setOrdinal(ordinal);
|
||||||
|
for (auto ai : osi->sections()) {
|
||||||
|
ai->setOrdinal(ordinal);
|
||||||
|
}
|
||||||
|
++ordinal;
|
||||||
|
}
|
||||||
|
for (auto osi : _outputSections) {
|
||||||
|
for (auto ai : osi->sections()) {
|
||||||
|
if (auto section = dyn_cast<Section<ELFT> >(ai)) {
|
||||||
|
if (!hasOutputSegment(section))
|
||||||
|
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();
|
||||||
|
|
||||||
|
int64_t lookupSectionFlag = osi->flags();
|
||||||
|
if ((!(lookupSectionFlag & llvm::ELF::SHF_WRITE)) &&
|
||||||
|
(_ctx.mergeRODataToTextSegment()))
|
||||||
|
lookupSectionFlag &= ~llvm::ELF::SHF_EXECINSTR;
|
||||||
|
|
||||||
|
// Merge string sections into Data segment itself
|
||||||
|
lookupSectionFlag &= ~(llvm::ELF::SHF_STRINGS | llvm::ELF::SHF_MERGE);
|
||||||
|
|
||||||
|
// Merge the TLS section into the DATA segment itself
|
||||||
|
lookupSectionFlag &= ~(llvm::ELF::SHF_TLS);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
std::pair<typename SegmentMapT::iterator, bool> segmentInsert(
|
||||||
|
_segmentMap.insert(currentSegment));
|
||||||
|
if (!segmentInsert.second) {
|
||||||
|
segment = segmentInsert.first->second;
|
||||||
|
} else {
|
||||||
|
segment = new (_allocator)
|
||||||
|
Segment<ELFT>(_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()) {
|
||||||
|
Segment<ELFT> *segment = new (_allocator) ProgramHeaderSegment<ELFT>(_ctx);
|
||||||
|
_segments.push_back(segment);
|
||||||
|
segment->append(_elfHeader);
|
||||||
|
segment->append(_programHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT> void TargetLayout<ELFT>::assignVirtualAddress() {
|
||||||
|
if (_segments.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
|
||||||
|
|
||||||
|
uint64_t baseAddress = _ctx.getBaseAddress();
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// so that AT_PHDR is set correctly by the loader and so they are accessible
|
||||||
|
// at runtime. To do this we simply prepend them to the first loadable Segment
|
||||||
|
// and let the layout logic take care of it.
|
||||||
|
Segment<ELFT> *firstLoadSegment = nullptr;
|
||||||
|
for (auto si : _segments) {
|
||||||
|
if (si->segmentType() == llvm::ELF::PT_LOAD) {
|
||||||
|
firstLoadSegment = si;
|
||||||
|
si->firstSection()->setAlign(si->alignment());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(firstLoadSegment != nullptr && "No loadable segment!");
|
||||||
|
firstLoadSegment->prepend(_programHeader);
|
||||||
|
firstLoadSegment->prepend(_elfHeader);
|
||||||
|
bool newSegmentHeaderAdded = true;
|
||||||
|
bool virtualAddressAssigned = false;
|
||||||
|
bool fileOffsetAssigned = false;
|
||||||
|
while (true) {
|
||||||
|
for (auto si : _segments) {
|
||||||
|
si->finalize();
|
||||||
|
// Don't add PT_NULL segments into the program header
|
||||||
|
if (si->segmentType() != llvm::ELF::PT_NULL)
|
||||||
|
newSegmentHeaderAdded = _programHeader->addSegment(si);
|
||||||
|
}
|
||||||
|
if (!newSegmentHeaderAdded && virtualAddressAssigned)
|
||||||
|
break;
|
||||||
|
uint64_t address = baseAddress;
|
||||||
|
// start assigning virtual addresses
|
||||||
|
for (auto &si : _segments) {
|
||||||
|
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
||||||
|
(si->segmentType() != llvm::ELF::PT_NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (si->segmentType() == llvm::ELF::PT_NULL) {
|
||||||
|
si->assignVirtualAddress(0 /*non loadable*/);
|
||||||
|
} else {
|
||||||
|
if (virtualAddressAssigned && (address != baseAddress) &&
|
||||||
|
(address == si->virtualAddr()))
|
||||||
|
break;
|
||||||
|
si->assignVirtualAddress(address);
|
||||||
|
}
|
||||||
|
address = si->virtualAddr() + si->memSize();
|
||||||
|
}
|
||||||
|
uint64_t baseFileOffset = 0;
|
||||||
|
uint64_t fileoffset = baseFileOffset;
|
||||||
|
for (auto &si : _segments) {
|
||||||
|
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
||||||
|
(si->segmentType() != llvm::ELF::PT_NULL))
|
||||||
|
continue;
|
||||||
|
if (fileOffsetAssigned && (fileoffset != baseFileOffset) &&
|
||||||
|
(fileoffset == si->fileOffset()))
|
||||||
|
break;
|
||||||
|
si->assignFileOffsets(fileoffset);
|
||||||
|
fileoffset = si->fileOffset() + si->fileSize();
|
||||||
|
}
|
||||||
|
virtualAddressAssigned = true;
|
||||||
|
fileOffsetAssigned = true;
|
||||||
|
_programHeader->resetProgramHeaders();
|
||||||
|
}
|
||||||
|
Section<ELFT> *section;
|
||||||
|
// Fix the offsets of all the atoms within a section
|
||||||
|
for (auto &si : _sections) {
|
||||||
|
section = dyn_cast<Section<ELFT>>(si);
|
||||||
|
if (section && TargetLayout<ELFT>::hasOutputSegment(section))
|
||||||
|
section->assignFileOffsets(section->fileOffset());
|
||||||
|
}
|
||||||
|
// Set the size of the merged Sections
|
||||||
|
for (auto osi : _outputSections) {
|
||||||
|
uint64_t sectionfileoffset = 0;
|
||||||
|
uint64_t startFileOffset = 0;
|
||||||
|
uint64_t sectionsize = 0;
|
||||||
|
bool isFirstSection = true;
|
||||||
|
for (auto si : osi->sections()) {
|
||||||
|
if (isFirstSection) {
|
||||||
|
startFileOffset = si->fileOffset();
|
||||||
|
isFirstSection = false;
|
||||||
|
}
|
||||||
|
sectionfileoffset = si->fileOffset();
|
||||||
|
sectionsize = si->fileSize();
|
||||||
|
}
|
||||||
|
sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
|
||||||
|
osi->setFileOffset(startFileOffset);
|
||||||
|
osi->setSize(sectionsize);
|
||||||
|
}
|
||||||
|
// Set the virtual addr of the merged Sections
|
||||||
|
for (auto osi : _outputSections) {
|
||||||
|
uint64_t sectionstartaddr = 0;
|
||||||
|
uint64_t startaddr = 0;
|
||||||
|
uint64_t sectionsize = 0;
|
||||||
|
bool isFirstSection = true;
|
||||||
|
for (auto si : osi->sections()) {
|
||||||
|
if (isFirstSection) {
|
||||||
|
startaddr = si->virtualAddr();
|
||||||
|
isFirstSection = false;
|
||||||
|
}
|
||||||
|
sectionstartaddr = si->virtualAddr();
|
||||||
|
sectionsize = si->memSize();
|
||||||
|
}
|
||||||
|
sectionsize = (sectionstartaddr - startaddr) + sectionsize;
|
||||||
|
osi->setMemSize(sectionsize);
|
||||||
|
osi->setAddr(startaddr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
void TargetLayout<ELFT>::assignFileOffsetsForMiscSections() {
|
||||||
|
uint64_t fileoffset = 0;
|
||||||
|
uint64_t size = 0;
|
||||||
|
for (auto si : _segments) {
|
||||||
|
// Don't calculate offsets from non loadable segments
|
||||||
|
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
||||||
|
(si->segmentType() != llvm::ELF::PT_NULL))
|
||||||
|
continue;
|
||||||
|
fileoffset = si->fileOffset();
|
||||||
|
size = si->fileSize();
|
||||||
|
}
|
||||||
|
fileoffset = fileoffset + size;
|
||||||
|
Section<ELFT> *section;
|
||||||
|
for (auto si : _sections) {
|
||||||
|
section = dyn_cast<Section<ELFT>>(si);
|
||||||
|
if (section && TargetLayout<ELFT>::hasOutputSegment(section))
|
||||||
|
continue;
|
||||||
|
fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment());
|
||||||
|
si->setFileOffset(fileoffset);
|
||||||
|
si->setVirtualAddr(0);
|
||||||
|
fileoffset += si->fileSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT> void TargetLayout<ELFT>::sortInputSections() {
|
||||||
|
// First, sort according to default layout's order
|
||||||
|
std::stable_sort(
|
||||||
|
_sections.begin(), _sections.end(),
|
||||||
|
[](Chunk<ELFT> *A, Chunk<ELFT> *B) { return A->order() < B->order(); });
|
||||||
|
|
||||||
|
if (!_linkerScriptSema.hasLayoutCommands())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Sort the sections by their order as defined by the linker script
|
||||||
|
std::stable_sort(this->_sections.begin(), this->_sections.end(),
|
||||||
|
[this](Chunk<ELFT> *A, Chunk<ELFT> *B) {
|
||||||
|
auto *a = dyn_cast<Section<ELFT>>(A);
|
||||||
|
auto *b = dyn_cast<Section<ELFT>>(B);
|
||||||
|
|
||||||
|
if (a == nullptr)
|
||||||
|
return false;
|
||||||
|
if (b == nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return _linkerScriptSema.less(
|
||||||
|
{a->archivePath(), a->memberPath(),
|
||||||
|
a->inputSectionName()},
|
||||||
|
{b->archivePath(), b->memberPath(),
|
||||||
|
b->inputSectionName()});
|
||||||
|
});
|
||||||
|
// Now try to arrange sections with no mapping rules to sections with
|
||||||
|
// similar content
|
||||||
|
auto p = this->_sections.begin();
|
||||||
|
// Find first section that has no assigned rule id
|
||||||
|
while (p != this->_sections.end()) {
|
||||||
|
auto *sect = dyn_cast<AtomSection<ELFT>>(*p);
|
||||||
|
if (!sect)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!_linkerScriptSema.hasMapping({sect->archivePath(),
|
||||||
|
sect->memberPath(),
|
||||||
|
sect->inputSectionName()}))
|
||||||
|
break;
|
||||||
|
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
// For all sections that have no assigned rule id, try to move them near a
|
||||||
|
// section with similar contents
|
||||||
|
if (p != this->_sections.begin()) {
|
||||||
|
for (; p != this->_sections.end(); ++p) {
|
||||||
|
auto q = p;
|
||||||
|
--q;
|
||||||
|
while (q != this->_sections.begin() &&
|
||||||
|
(*q)->getContentType() != (*p)->getContentType())
|
||||||
|
--q;
|
||||||
|
if ((*q)->getContentType() != (*p)->getContentType())
|
||||||
|
continue;
|
||||||
|
++q;
|
||||||
|
for (auto i = p; i != q;) {
|
||||||
|
auto next = i--;
|
||||||
|
std::iter_swap(i, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ELFT>
|
||||||
|
void TargetLayout<ELFT>::addExtraChunksToSegment(Segment<ELFT> *segment,
|
||||||
|
StringRef archivePath,
|
||||||
|
StringRef memberPath,
|
||||||
|
StringRef sectionName) {
|
||||||
|
if (!_linkerScriptSema.hasLayoutCommands())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::vector<const script::SymbolAssignment *> exprs =
|
||||||
|
_linkerScriptSema.getExprs({archivePath, memberPath, sectionName});
|
||||||
|
for (auto expr : exprs) {
|
||||||
|
auto expChunk =
|
||||||
|
new (this->_allocator) ExpressionChunk<ELFT>(this->_ctx, expr);
|
||||||
|
segment->append(expChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // end namespace elf
|
} // end namespace elf
|
||||||
} // end namespace lld
|
} // end namespace lld
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue