The AtomSections were improperly merging sections from various input files. This patch fixes the problem, with an updated test that was provided by Simon. Thanks to Simon Atanasyan for catching this issue. llvm-svn: 222982
884 lines
29 KiB
C++
884 lines
29 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 "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)
|
|
: _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);
|
|
}
|
|
};
|
|
|
|
// Output Sections contain the map of Sectionnames to a vector of sections,
|
|
// that have been merged to form a single section
|
|
typedef std::map<StringRef, OutputSection<ELFT> *> OutputSectionMapT;
|
|
typedef
|
|
typename std::vector<OutputSection<ELFT> *>::iterator OutputSectionIter;
|
|
|
|
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;
|
|
|
|
typedef llvm::DenseSet<const Atom *> AtomSetT;
|
|
|
|
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 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 inputSectionName) 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.
|
|
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
|
|
AbsoluteAtomIterT findAbsoluteAtom(StringRef name) {
|
|
return std::find_if(_absoluteAtoms.begin(), _absoluteAtoms.end(),
|
|
FindByName(name));
|
|
}
|
|
|
|
// Output sections with the same name into a OutputSection
|
|
void createOutputSections();
|
|
|
|
void assignSectionsToSegments() override;
|
|
|
|
void assignVirtualAddress() override;
|
|
|
|
void assignFileOffsetsForMiscSections();
|
|
|
|
/// 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<OutputSectionIter> outputSections() { return _outputSections; }
|
|
|
|
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;
|
|
}
|
|
|
|
bool isReferencedByDefinedAtom(const Atom *a) const {
|
|
return _referencedDynAtoms.count(a);
|
|
}
|
|
|
|
bool isCopied(const SharedLibraryAtom *sla) const {
|
|
return _copiedDynSymNames.count(sla->name());
|
|
}
|
|
|
|
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;
|
|
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;
|
|
LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _dynamicRelocationTable;
|
|
LLD_UNIQUE_BUMP_PTR(RelocationTable<ELFT>) _pltRelocationTable;
|
|
std::vector<lld::AtomLayout *> _absoluteAtoms;
|
|
AtomSetT _referencedDynAtoms;
|
|
llvm::StringSet<> _copiedDynSymNames;
|
|
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)
|
|
.StartsWith(".dynamic", ORDER_DYNAMIC)
|
|
.StartsWith(".got.plt", ORDER_GOT_PLT)
|
|
.StartsWith(".got", ORDER_GOT)
|
|
.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 inputSectionName) const {
|
|
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>(_context, sectionName, contentType,
|
|
permissions, sectionOrder);
|
|
}
|
|
|
|
template <class ELFT>
|
|
AtomSection<ELFT> *DefaultLayout<ELFT>::getSection(
|
|
StringRef sectionName, int32_t contentType,
|
|
DefinedAtom::ContentPermissions permissions) {
|
|
// FIXME: We really need the file path here in the SectionKey, when that
|
|
// is available, replace the sectionKey that has outputSectionName to the
|
|
// inputSectionName.
|
|
StringRef outputSectionName = getOutputSectionName(sectionName);
|
|
const SectionKey sectionKey(outputSectionName, 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->setOutputSectionName(outputSectionName);
|
|
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 = getInputSectionName(definedAtom);
|
|
AtomSection<ELFT> *section =
|
|
getSection(sectionName, contentType, permissions);
|
|
|
|
// Add runtime relocations to the .rela section.
|
|
for (const auto &reloc : *definedAtom) {
|
|
bool isLocalReloc = true;
|
|
if (_context.isDynamicRelocation(*definedAtom, *reloc)) {
|
|
getDynamicRelocationTable()->addRelocation(*definedAtom, *reloc);
|
|
isLocalReloc = false;
|
|
} else if (_context.isPLTRelocation(*definedAtom, *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 (_context.isCopyRelocation(*reloc)) {
|
|
_copiedDynSymNames.insert(definedAtom->name());
|
|
continue;
|
|
}
|
|
|
|
_referencedDynAtoms.insert(reloc->target());
|
|
}
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
/// 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 = _context.getOutputMagic();
|
|
// 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();
|
|
});
|
|
// Create output sections.
|
|
createOutputSections();
|
|
// 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)) &&
|
|
(_context.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>(_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>::assignVirtualAddress() {
|
|
if (_segments.empty())
|
|
return;
|
|
|
|
std::sort(_segments.begin(), _segments.end(), Segment<ELFT>::compareSegments);
|
|
|
|
uint64_t virtualAddress = _context.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;
|
|
}
|
|
}
|
|
firstLoadSegment->prepend(_programHeader);
|
|
firstLoadSegment->prepend(_elfHeader);
|
|
bool newSegmentHeaderAdded = true;
|
|
bool virtualAddressAssigned = 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;
|
|
virtualAddressAssigned = true;
|
|
uint64_t address = virtualAddress;
|
|
// 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 {
|
|
si->assignVirtualAddress(address);
|
|
}
|
|
address = si->virtualAddr() + si->memSize();
|
|
}
|
|
uint64_t fileoffset = 0;
|
|
for (auto &si : _segments) {
|
|
if ((si->segmentType() != llvm::ELF::PT_LOAD) &&
|
|
(si->segmentType() != llvm::ELF::PT_NULL))
|
|
continue;
|
|
si->assignFileOffsets(fileoffset);
|
|
fileoffset = si->fileOffset() + si->fileSize();
|
|
}
|
|
_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();
|
|
}
|
|
}
|
|
} // end namespace elf
|
|
} // end namespace lld
|
|
|
|
#endif
|