forked from OSchip/llvm-project
872 lines
28 KiB
C++
872 lines
28 KiB
C++
//===- 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 "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/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 <memory>
|
|
#include <tuple>
|
|
#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)
|
|
: _name(name), _perm(perm) {
|
|
}
|
|
|
|
// Data members
|
|
StringRef _name;
|
|
DefinedAtom::ContentPermissions _perm;
|
|
};
|
|
|
|
struct SectionKeyHash {
|
|
int64_t operator()(const SectionKey &k) const {
|
|
return llvm::hash_combine(k._name, k._perm);
|
|
}
|
|
};
|
|
|
|
struct SectionKeyEq {
|
|
bool operator()(const SectionKey &lhs, const SectionKey &rhs) const {
|
|
return ((lhs._name == rhs._name) && (lhs._perm == rhs._perm));
|
|
}
|
|
};
|
|
|
|
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() (int64_t segmentType, int64_t segmentFlag) const {
|
|
// k.first = SegmentName
|
|
// k.second = SegmentFlags
|
|
return llvm::hash_combine(segmentType, segmentFlag);
|
|
}
|
|
};
|
|
|
|
|
|
// Merged Sections contain the map of Sectionnames to a vector of sections,
|
|
// that have been merged to form a single section
|
|
typedef std::map<StringRef, MergedSections<ELFT> *> MergedSectionMapT;
|
|
typedef typename std::vector<MergedSections<ELFT> *>::iterator
|
|
MergedSectionIter;
|
|
|
|
typedef std::unordered_map<SectionKey, AtomSection<ELFT> *, SectionKeyHash,
|
|
SectionKeyEq> SectionMapT;
|
|
typedef std::map<AdditionalSegmentKey, Segment<ELFT> *> AdditionalSegmentMapT;
|
|
typedef std::unordered_map<SegmentKey, Segment<ELFT> *, SegmentHashKey>
|
|
SegmentMapT;
|
|
|
|
/// \brief find a absolute atom pair given a absolute atom name
|
|
struct FindByName {
|
|
const std::string _name;
|
|
FindByName(StringRef name) : _name(name) {}
|
|
bool operator()(const lld::AtomLayout *j) { return j->_atom->name() == _name; }
|
|
};
|
|
|
|
typedef typename std::vector<lld::AtomLayout *>::iterator AbsoluteAtomIterT;
|
|
|
|
DefaultLayout(const ELFLinkingContext &context) : _context(context) {}
|
|
|
|
/// \brief Return the section order for a input section
|
|
SectionOrder getSectionOrder(StringRef name, int32_t contentType,
|
|
int32_t contentPermissions) override;
|
|
|
|
/// \brief This maps the input sections to the output section names
|
|
virtual StringRef getSectionName(const DefinedAtom *da) const;
|
|
|
|
/// \brief Gets or creates a section.
|
|
AtomSection<ELFT> *getSection(
|
|
StringRef name, int32_t contentType,
|
|
DefinedAtom::ContentPermissions contentPermissions);
|
|
|
|
/// \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.
|
|
MergedSections<ELFT> *findOutputSection(StringRef name) {
|
|
auto iter = _mergedSectionMap.find(name);
|
|
if (iter == _mergedSectionMap.end())
|
|
return nullptr;
|
|
return iter->second;
|
|
}
|
|
|
|
/// \brief find a absolute atom given a name
|
|
AbsoluteAtomIterT findAbsoluteAtom(StringRef name) {
|
|
return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
|
|
FindByName(name));
|
|
}
|
|
|
|
// Merge sections with the same name into a MergedSections
|
|
void mergeSimilarSections();
|
|
|
|
void assignSectionsToSegments() override;
|
|
|
|
void assignVirtualAddress() override;
|
|
|
|
void assignOffsetsForMiscSections();
|
|
|
|
void assignFileOffsets() override;
|
|
|
|
/// Inline functions
|
|
inline range<AbsoluteAtomIterT> absoluteAtoms() { return _absoluteAtoms; }
|
|
|
|
inline void addSection(Chunk<ELFT> *c) {
|
|
_sections.push_back(c);
|
|
}
|
|
|
|
inline void finalize() {
|
|
ScopedTask task(getDefaultDomain(), "Finalize layout");
|
|
for (auto &si : _sections)
|
|
si->finalize();
|
|
}
|
|
|
|
inline void doPreFlight() {
|
|
for (auto &si : _sections)
|
|
si->doPreFlight();
|
|
}
|
|
|
|
inline bool findAtomAddrByName(StringRef name, uint64_t &addr) override {
|
|
for (auto sec : _sections)
|
|
if (auto section = dyn_cast<Section<ELFT> >(sec))
|
|
if (section->findAtomAddrByName(name, addr))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
inline void setHeader(ELFHeader<ELFT> *elfHeader) { _elfHeader = elfHeader; }
|
|
|
|
inline void setProgramHeader(ProgramHeader<ELFT> *p) {
|
|
_programHeader = p;
|
|
}
|
|
|
|
inline range<MergedSectionIter> mergedSections() { return _mergedSections; }
|
|
|
|
inline range<ChunkIter> sections() { return _sections; }
|
|
|
|
inline range<SegmentIter> segments() { return _segments; }
|
|
|
|
inline ELFHeader<ELFT> *getHeader() { return _elfHeader; }
|
|
|
|
inline ProgramHeader<ELFT> *getProgramHeader() {
|
|
return _programHeader;
|
|
}
|
|
|
|
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.reset(new (_allocator) RelocationTable<ELFT>(
|
|
_context, _context.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.reset(new (_allocator) RelocationTable<ELFT>(
|
|
_context, _context.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;
|
|
}
|
|
|
|
protected:
|
|
/// \brief Allocate a new section.
|
|
virtual AtomSection<ELFT> *createSection(
|
|
StringRef name, int32_t contentType,
|
|
DefinedAtom::ContentPermissions contentPermissions,
|
|
SectionOrder sectionOrder);
|
|
|
|
protected:
|
|
llvm::BumpPtrAllocator _allocator;
|
|
SectionMapT _sectionMap;
|
|
MergedSectionMapT _mergedSectionMap;
|
|
AdditionalSegmentMapT _additionalSegmentMap;
|
|
SegmentMapT _segmentMap;
|
|
std::vector<Chunk<ELFT> *> _sections;
|
|
std::vector<Segment<ELFT> *> _segments;
|
|
std::vector<MergedSections<ELFT> *> _mergedSections;
|
|
ELFHeader<ELFT> *_elfHeader;
|
|
ProgramHeader<ELFT> *_programHeader;
|
|
LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _dynamicRelocationTable;
|
|
LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _pltRelocationTable;
|
|
std::vector<lld::AtomLayout *> _absoluteAtoms;
|
|
const ELFLinkingContext &_context;
|
|
};
|
|
|
|
/// \brief Handle linker scripts. TargetLayouts would derive
|
|
/// from this class to override some of the functionalities.
|
|
template<class ELFT>
|
|
class ScriptLayout: public DefaultLayout<ELFT> {
|
|
public:
|
|
ScriptLayout(const ELFLinkingContext &context)
|
|
: DefaultLayout<ELFT>(context)
|
|
{}
|
|
};
|
|
|
|
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)
|
|
.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>::getSectionName(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 llvm::StringSwitch<StringRef>(da->customSectionName())
|
|
.StartsWith(".text", ".text")
|
|
.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(da->customSectionName());
|
|
}
|
|
|
|
/// \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:
|
|
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_CTORS:
|
|
case ORDER_DTORS:
|
|
return llvm::ELF::PT_GNU_RELRO;
|
|
|
|
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>(_context, sectionName, contentType,
|
|
permissions, sectionOrder);
|
|
}
|
|
|
|
template <class ELFT>
|
|
AtomSection<ELFT> *DefaultLayout<ELFT>::getSection(
|
|
StringRef sectionName, int32_t contentType,
|
|
DefinedAtom::ContentPermissions permissions) {
|
|
const SectionKey sectionKey(sectionName, permissions);
|
|
auto sec = _sectionMap.find(sectionKey);
|
|
if (sec != _sectionMap.end())
|
|
return sec->second;
|
|
SectionOrder sectionOrder =
|
|
getSectionOrder(sectionName, contentType, permissions);
|
|
AtomSection<ELFT> *newSec =
|
|
createSection(sectionName, contentType, permissions, sectionOrder);
|
|
newSec->setOrder(sectionOrder);
|
|
_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 = getSectionName(definedAtom);
|
|
AtomSection<ELFT> *section =
|
|
getSection(sectionName, contentType, permissions);
|
|
// Add runtime relocations to the .rela section.
|
|
for (const auto &reloc : *definedAtom)
|
|
if (_context.isDynamicRelocation(*definedAtom, *reloc))
|
|
getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
|
|
else if (_context.isPLTRelocation(*definedAtom, *reloc))
|
|
getPLTRelocationTable()->addRelocation(*definedAtom, *reloc);
|
|
return section->appendAtom(atom);
|
|
} else if (const AbsoluteAtom *absoluteAtom = dyn_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();
|
|
} else {
|
|
llvm_unreachable("Only absolute / defined atoms can be added here");
|
|
}
|
|
}
|
|
|
|
/// Merge sections with the same name into a MergedSections
|
|
template<class ELFT>
|
|
void
|
|
DefaultLayout<ELFT>::mergeSimilarSections() {
|
|
MergedSections<ELFT> *mergedSection;
|
|
|
|
for (auto &si : _sections) {
|
|
const std::pair<StringRef, MergedSections<ELFT> *>
|
|
currentMergedSections(si->name(), nullptr);
|
|
std::pair<typename MergedSectionMapT::iterator, bool>
|
|
mergedSectionInsert
|
|
(_mergedSectionMap.insert(currentMergedSections));
|
|
if (!mergedSectionInsert.second) {
|
|
mergedSection = mergedSectionInsert.first->second;
|
|
} else {
|
|
mergedSection = new (_allocator.Allocate<MergedSections<ELFT>>())
|
|
MergedSections<ELFT>(si->name());
|
|
_mergedSections.push_back(mergedSection);
|
|
mergedSectionInsert.first->second = mergedSection;
|
|
}
|
|
mergedSection->appendSection(si);
|
|
}
|
|
}
|
|
|
|
template <class ELFT> void DefaultLayout<ELFT>::assignSectionsToSegments() {
|
|
ScopedTask task(getDefaultDomain(), "assignSectionsToSegments");
|
|
ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();
|
|
// TODO: Do we want to give a chance for the targetHandlers
|
|
// to sort segments in an arbitrary order?
|
|
// sort the sections by their order as defined by the layout
|
|
std::stable_sort(_sections.begin(), _sections.end(),
|
|
[](Chunk<ELFT> *A, Chunk<ELFT> *B) {
|
|
return A->order() < B->order();
|
|
});
|
|
// Merge all sections
|
|
mergeSimilarSections();
|
|
// Set the ordinal after sorting the sections
|
|
int ordinal = 1;
|
|
for (auto msi : _mergedSections) {
|
|
msi->setOrdinal(ordinal);
|
|
for (auto ai : msi->sections()) {
|
|
ai->setOrdinal(ordinal);
|
|
}
|
|
++ordinal;
|
|
}
|
|
for (auto msi : _mergedSections) {
|
|
for (auto ai : msi->sections()) {
|
|
if (auto section = dyn_cast<Section<ELFT> >(ai)) {
|
|
if (!hasOutputSegment(section))
|
|
continue;
|
|
|
|
msi->setLoadableSection(section->isLoadableSection());
|
|
|
|
// Get the segment type for the section
|
|
int64_t segmentType = getSegmentType(section);
|
|
|
|
msi->setHasSegment();
|
|
section->setSegmentType(segmentType);
|
|
StringRef segmentName = section->segmentKindToStr();
|
|
|
|
int64_t lookupSectionFlag = msi->flags();
|
|
if (!(lookupSectionFlag & llvm::ELF::SHF_WRITE))
|
|
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>(_context, 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>(_context, "PT_LOAD",
|
|
llvm::ELF::PT_LOAD);
|
|
segmentInsert.first->second = segment;
|
|
_segments.push_back(segment);
|
|
}
|
|
segment->append(section);
|
|
}
|
|
}
|
|
}
|
|
if (_context.isDynamic() && !_context.isDynamicLibrary()) {
|
|
Segment<ELFT> *segment =
|
|
new (_allocator) ProgramHeaderSegment<ELFT>(_context);
|
|
_segments.push_back(segment);
|
|
segment->append(_elfHeader);
|
|
segment->append(_programHeader);
|
|
}
|
|
}
|
|
|
|
template <class ELFT> void DefaultLayout<ELFT>::assignFileOffsets() {
|
|
// TODO: Do we want to give a chance for the targetHandlers
|
|
// to sort segments in an arbitrary order?
|
|
std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
|
|
int ordinal = 0;
|
|
// Compute the number of segments that might be needed, so that the
|
|
// size of the program header can be computed
|
|
uint64_t offset = 0;
|
|
for (auto si : _segments) {
|
|
si->setOrdinal(++ordinal);
|
|
// Don't assign offsets for segments that are not loadable
|
|
if (si->segmentType() != llvm::ELF::PT_LOAD)
|
|
continue;
|
|
si->assignOffsets(offset);
|
|
offset += si->fileSize();
|
|
}
|
|
}
|
|
|
|
template<class ELFT>
|
|
void
|
|
DefaultLayout<ELFT>::assignVirtualAddress() {
|
|
if (_segments.empty())
|
|
return;
|
|
|
|
uint64_t virtualAddress = _context.getBaseAddress();
|
|
ELFLinkingContext::OutputMagic outputMagic = _context.getOutputMagic();
|
|
|
|
// 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->align2());
|
|
break;
|
|
}
|
|
}
|
|
firstLoadSegment->prepend(_programHeader);
|
|
firstLoadSegment->prepend(_elfHeader);
|
|
bool newSegmentHeaderAdded = true;
|
|
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)
|
|
break;
|
|
uint64_t fileoffset = 0;
|
|
uint64_t address = virtualAddress;
|
|
// Fix the offsets after adding the program header
|
|
for (auto &si : _segments) {
|
|
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
|
(si->segmentType() != llvm::ELF::PT_NULL))
|
|
continue;
|
|
// Align the segment to a page boundary only if the output mode is
|
|
// not OutputMagic::NMAGIC/OutputMagic::OMAGIC
|
|
if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
|
|
outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
|
|
fileoffset =
|
|
llvm::RoundUpToAlignment(fileoffset, _context.getPageSize());
|
|
si->assignOffsets(fileoffset);
|
|
fileoffset = si->fileOffset() + si->fileSize();
|
|
}
|
|
// 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) {
|
|
// Handle Non allocatable sections.
|
|
uint64_t nonLoadableAddr = 0;
|
|
si->setVAddr(nonLoadableAddr);
|
|
si->assignVirtualAddress(nonLoadableAddr);
|
|
} else {
|
|
si->setVAddr(virtualAddress);
|
|
// The first segment has the virtualAddress set to the base address as
|
|
// we have added the file header and the program header don't align the
|
|
// first segment to the pagesize
|
|
si->assignVirtualAddress(address);
|
|
si->setMemSize(address - virtualAddress);
|
|
if (outputMagic != ELFLinkingContext::OutputMagic::NMAGIC &&
|
|
outputMagic != ELFLinkingContext::OutputMagic::OMAGIC)
|
|
virtualAddress =
|
|
llvm::RoundUpToAlignment(address, _context.getPageSize());
|
|
}
|
|
}
|
|
_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->assignOffsets(section->fileOffset());
|
|
}
|
|
// Set the size of the merged Sections
|
|
for (auto msi : _mergedSections) {
|
|
uint64_t sectionfileoffset = 0;
|
|
uint64_t startFileOffset = 0;
|
|
uint64_t sectionsize = 0;
|
|
bool isFirstSection = true;
|
|
for (auto si : msi->sections()) {
|
|
if (isFirstSection) {
|
|
startFileOffset = si->fileOffset();
|
|
isFirstSection = false;
|
|
}
|
|
sectionfileoffset = si->fileOffset();
|
|
sectionsize = si->fileSize();
|
|
}
|
|
sectionsize = (sectionfileoffset - startFileOffset) + sectionsize;
|
|
msi->setFileOffset(startFileOffset);
|
|
msi->setSize(sectionsize);
|
|
}
|
|
// Set the virtual addr of the merged Sections
|
|
for (auto msi : _mergedSections) {
|
|
uint64_t sectionstartaddr = 0;
|
|
uint64_t startaddr = 0;
|
|
uint64_t sectionsize = 0;
|
|
bool isFirstSection = true;
|
|
for (auto si : msi->sections()) {
|
|
if (isFirstSection) {
|
|
startaddr = si->virtualAddr();
|
|
isFirstSection = false;
|
|
}
|
|
sectionstartaddr = si->virtualAddr();
|
|
sectionsize = si->memSize();
|
|
}
|
|
sectionsize = (sectionstartaddr - startaddr) + sectionsize;
|
|
msi->setMemSize(sectionsize);
|
|
msi->setAddr(startaddr);
|
|
}
|
|
}
|
|
|
|
template<class ELFT>
|
|
void
|
|
DefaultLayout<ELFT>::assignOffsetsForMiscSections() {
|
|
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->align2());
|
|
si->setFileOffset(fileoffset);
|
|
si->setVAddr(0);
|
|
fileoffset += si->fileSize();
|
|
}
|
|
}
|
|
} // end namespace elf
|
|
} // end namespace lld
|
|
|
|
#endif
|