[ELF] Delete empty TargetLayout class and rename DefaultLayout to TargetLayout

No functional changes.

llvm-svn: 234052
This commit is contained in:
Simon Atanasyan 2015-04-03 21:01:07 +00:00
parent b2e0f7a40f
commit 2181c10b5b
9 changed files with 1004 additions and 1037 deletions

View File

@ -28,7 +28,7 @@ public:
template <class ELFT>
ARMSymbolTable<ELFT>::ARMSymbolTable(const ELFLinkingContext &ctx)
: SymbolTable<ELFT>(ctx, ".symtab",
DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
template <class ELFT>
void ARMSymbolTable<ELFT>::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,

View File

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

View File

@ -116,7 +116,7 @@ template <class ELFT> void ExecutableWriter<ELFT>::createDefaultSections() {
OutputELFWriter<ELFT>::createDefaultSections();
if (this->_ctx.isDynamic()) {
_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->_layout.addSection(_interpSection.get());
}

View File

@ -40,8 +40,8 @@ public:
(contentType == DefinedAtom::typeZeroFillFast))
return ORDER_SDATA;
return DefaultLayout<HexagonELFType>::getSectionOrder(name, contentType,
contentPermissions);
return TargetLayout<HexagonELFType>::getSectionOrder(name, contentType,
contentPermissions);
}
/// \brief Return the appropriate input section name.
@ -53,7 +53,7 @@ public:
default:
break;
}
return DefaultLayout<HexagonELFType>::getInputSectionName(da);
return TargetLayout<HexagonELFType>::getInputSectionName(da);
}
/// \brief Gets or creates a section.
@ -64,7 +64,7 @@ public:
if ((contentType == DefinedAtom::typeDataFast) ||
(contentType == DefinedAtom::typeZeroFillFast))
return _sdataSection;
return DefaultLayout<HexagonELFType>::createSection(
return TargetLayout<HexagonELFType>::createSection(
name, contentType, contentPermissions, sectionOrder);
}
@ -74,7 +74,7 @@ public:
if (section->order() == ORDER_SDATA)
return PT_LOAD;
return DefaultLayout<HexagonELFType>::getSegmentType(section);
return TargetLayout<HexagonELFType>::getSegmentType(section);
}
Section<HexagonELFType> *getSDataSection() const {

View File

@ -9,7 +9,7 @@
#ifndef 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"
namespace lld {
@ -23,7 +23,7 @@ public:
MipsDynamicTable(const ELFLinkingContext &ctx,
MipsTargetLayout<MipsELFType> &layout)
: DynamicTable<MipsELFType>(ctx, layout, ".dynamic",
DefaultLayout<MipsELFType>::ORDER_DYNAMIC),
TargetLayout<MipsELFType>::ORDER_DYNAMIC),
_targetLayout(layout) {}
void createDefaultEntries() override {

View File

@ -39,7 +39,7 @@ public:
return _gotSection;
if (type == DefinedAtom::typeStub && name == ".plt")
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.
@ -63,10 +63,10 @@ public:
Layout::SectionOrder getSectionOrder(StringRef name, int32_t contentType,
int32_t contentPermissions) override {
if ((contentType == DefinedAtom::typeStub) && (name.startswith(".text")))
return DefaultLayout<ELFT>::ORDER_TEXT;
return TargetLayout<ELFT>::ORDER_TEXT;
return DefaultLayout<ELFT>::getSectionOrder(name, contentType,
contentPermissions);
return TargetLayout<ELFT>::getSectionOrder(name, contentType,
contentPermissions);
}
protected:
@ -130,7 +130,7 @@ public:
MipsSymbolTable(const ELFLinkingContext &ctx)
: SymbolTable<ELFT>(ctx, ".symtab",
DefaultLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
TargetLayout<ELFT>::ORDER_SYMBOL_TABLE) {}
void addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da,
int64_t addr) override {
@ -172,7 +172,7 @@ public:
MipsDynamicSymbolTable(const ELFLinkingContext &ctx,
MipsTargetLayout<ELFT> &layout)
: DynamicSymbolTable<ELFT>(ctx, layout, ".dynsym",
DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS),
_targetLayout(layout) {}
void sortSymbols() override {

View File

@ -9,7 +9,6 @@
#ifndef LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
#define LLD_READER_WRITER_ELF_OUTPUT_WRITER_H
#include "DefaultLayout.h"
#include "ELFFile.h"
#include "TargetLayout.h"
#include "lld/Core/Instrumentation.h"
@ -350,7 +349,7 @@ void OutputELFWriter<ELFT>::assignSectionsWithNoSegments() {
_layout.assignFileOffsetsForMiscSections();
for (auto sec : _layout.sections())
if (auto section = dyn_cast<Section<ELFT>>(sec))
if (!DefaultLayout<ELFT>::hasOutputSegment(section))
if (!TargetLayout<ELFT>::hasOutputSegment(section))
_shdrtab->updateSection(section);
}
@ -398,11 +397,11 @@ template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
_symtab = std::move(this->createSymbolTable());
_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>(
_ctx, ".shstrtab", DefaultLayout<ELFT>::ORDER_SECTION_STRINGS));
_ctx, ".shstrtab", TargetLayout<ELFT>::ORDER_SECTION_STRINGS));
_shdrtab.reset(new (_alloc) SectionHeader<ELFT>(
_ctx, DefaultLayout<ELFT>::ORDER_SECTION_HEADERS));
_ctx, TargetLayout<ELFT>::ORDER_SECTION_HEADERS));
_layout.addSection(_symtab.get());
_layout.addSection(_strtab.get());
_layout.addSection(_shstrtab.get());
@ -416,8 +415,7 @@ template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
if (!section || section->outputSectionName() != ".eh_frame")
continue;
_ehFrameHeader.reset(new (_alloc) EHFrameHeader<ELFT>(
_ctx, ".eh_frame_hdr", _layout,
DefaultLayout<ELFT>::ORDER_EH_FRAMEHDR));
_ctx, ".eh_frame_hdr", _layout, TargetLayout<ELFT>::ORDER_EH_FRAMEHDR));
_layout.addSection(_ehFrameHeader.get());
break;
}
@ -425,10 +423,10 @@ template <class ELFT> void OutputELFWriter<ELFT>::createDefaultSections() {
if (_ctx.isDynamic()) {
_dynamicTable = std::move(createDynamicTable());
_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());
_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
// hash table can be created
_dynamicSymbolTable->setHashTable(_hashTable.get());
@ -453,7 +451,7 @@ template <class ELFT>
unique_bump_ptr<SymbolTable<ELFT>>
OutputELFWriter<ELFT>::createSymbolTable() {
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
@ -461,7 +459,7 @@ template <class ELFT>
unique_bump_ptr<DynamicTable<ELFT>>
OutputELFWriter<ELFT>::createDynamicTable() {
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
@ -471,7 +469,7 @@ unique_bump_ptr<DynamicSymbolTable<ELFT>>
return unique_bump_ptr<DynamicSymbolTable<ELFT>>(
new (_alloc)
DynamicSymbolTable<ELFT>(this->_ctx, _layout, ".dynsym",
DefaultLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
TargetLayout<ELFT>::ORDER_DYNAMIC_SYMBOLS));
}
template <class ELFT>

View File

@ -29,7 +29,7 @@
namespace lld {
namespace elf {
template <typename ELFT> class DefaultLayout;
template <typename ELFT> class TargetLayout;
/// \brief A segment can be divided into segment slices
/// 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
// fileOffset is automatically taken care of since TBSS section does not
// end up using file size
if ((*si)->order() != DefaultLayout<ELFT>::ORDER_TBSS)
if ((*si)->order() != TargetLayout<ELFT>::ORDER_TBSS)
curSliceSize = (*si)->memSize();
} else {
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
// The fileOffset is automatically taken care of since TBSS section does
// 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();
else
curSliceSize = newAddr - curSliceAddress;

View File

@ -7,21 +7,988 @@
//
//===----------------------------------------------------------------------===//
#ifndef LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
#define LLD_READER_WRITER_ELF_TARGET_LAYOUT_H
#ifndef LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
#define LLD_READER_WRITER_ELF_DEFAULT_LAYOUT_H
#include "DefaultLayout.h"
#include "lld/Core/LLVM.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 target can override certain functions in the DefaultLayout
/// class so that the order, the name of the section and the segment type could
/// be changed in the final layout
template <class ELFT> class TargetLayout : public DefaultLayout<ELFT> {
/// \brief The TargetLayout class is used by the Writer to arrange
/// sections and segments in the order determined by the target ELF
/// format. The writer creates a single instance of the TargetLayout
/// class
template<class ELFT>
class TargetLayout : public Layout {
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 lld