From 2181c10b5bf6435c90d0118bf36a88dc0ae3113e Mon Sep 17 00:00:00 2001 From: Simon Atanasyan Date: Fri, 3 Apr 2015 21:01:07 +0000 Subject: [PATCH] [ELF] Delete empty TargetLayout class and rename DefaultLayout to TargetLayout No functional changes. llvm-svn: 234052 --- lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h | 2 +- lld/lib/ReaderWriter/ELF/DefaultLayout.h | 998 ------------------ lld/lib/ReaderWriter/ELF/ExecutableWriter.h | 2 +- .../ELF/Hexagon/HexagonTargetHandler.h | 10 +- .../ReaderWriter/ELF/Mips/MipsDynamicTable.h | 4 +- .../ReaderWriter/ELF/Mips/MipsTargetHandler.h | 12 +- lld/lib/ReaderWriter/ELF/OutputELFWriter.h | 22 +- lld/lib/ReaderWriter/ELF/SegmentChunks.h | 6 +- lld/lib/ReaderWriter/ELF/TargetLayout.h | 985 ++++++++++++++++- 9 files changed, 1004 insertions(+), 1037 deletions(-) delete mode 100644 lld/lib/ReaderWriter/ELF/DefaultLayout.h diff --git a/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h b/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h index 0655c7fe4376..b0cc49b02d05 100644 --- a/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h +++ b/lld/lib/ReaderWriter/ELF/ARM/ARMSymbolTable.h @@ -28,7 +28,7 @@ public: template ARMSymbolTable::ARMSymbolTable(const ELFLinkingContext &ctx) : SymbolTable(ctx, ".symtab", - DefaultLayout::ORDER_SYMBOL_TABLE) {} + TargetLayout::ORDER_SYMBOL_TABLE) {} template void ARMSymbolTable::addDefinedAtom(Elf_Sym &sym, const DefinedAtom *da, diff --git a/lld/lib/ReaderWriter/ELF/DefaultLayout.h b/lld/lib/ReaderWriter/ELF/DefaultLayout.h deleted file mode 100644 index 63f537b807ab..000000000000 --- a/lld/lib/ReaderWriter/ELF/DefaultLayout.h +++ /dev/null @@ -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 -#include - -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 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 *>::iterator ChunkIter; - typedef typename std::vector *>::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 AdditionalSegmentKey; - // The segments are created using - // SegmentName, Segment flags - typedef std::pair 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 *> OutputSectionMapT; - typedef - typename std::vector *>::iterator OutputSectionIter; - - typedef std::unordered_map *, SectionKeyHash, - SectionKeyEq> SectionMapT; - typedef std::unordered_map *, - AdditionalSegmentHashKey> AdditionalSegmentMapT; - typedef std::unordered_map *, SegmentHashKey> - SegmentMapT; - - typedef typename std::vector::iterator AbsoluteAtomIterT; - - typedef llvm::DenseSet 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 * - 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 *section) const; - - /// \brief Returns true/false depending on whether the section has a Output - // segment or not - static bool hasOutputSegment(Section *section); - - // Adds an atom to the section - ErrorOr addAtom(const Atom *atom) override; - - /// \brief Find an output Section given a section name. - OutputSection *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 . This - /// is used to add linker script expressions before each section. - virtual void addExtraChunksToSegment(Segment *segment, - StringRef archivePath, - StringRef memberPath, - StringRef sectionName); - - void assignSectionsToSegments() override; - - void assignVirtualAddress() override; - - void assignFileOffsetsForMiscSections(); - - range absoluteAtoms() { return _absoluteAtoms; } - - void addSection(Chunk *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>(sec)) - if (auto *al = section->findAtomLayoutByName(name)) - return al; - return nullptr; - } - - void setHeader(ELFHeader *elfHeader) { _elfHeader = elfHeader; } - - void setProgramHeader(ProgramHeader *p) { - _programHeader = p; - } - - range outputSections() { return _outputSections; } - - range sections() { return _sections; } - - range segments() { return _segments; } - - ELFHeader *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 *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 *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 *createSection( - StringRef name, int32_t contentType, - DefinedAtom::ContentPermissions contentPermissions, - SectionOrder sectionOrder); - - /// \brief Create a new relocation table. - virtual unique_bump_ptr> - createRelocationTable(StringRef name, int32_t order) { - return unique_bump_ptr>( - new (_allocator) RelocationTable(_ctx, name, order)); - } - -protected: - llvm::BumpPtrAllocator _allocator; - SectionMapT _sectionMap; - OutputSectionMapT _outputSectionMap; - AdditionalSegmentMapT _additionalSegmentMap; - SegmentMapT _segmentMap; - std::vector *> _sections; - std::vector *> _segments; - std::vector *> _outputSections; - ELFHeader *_elfHeader; - ProgramHeader *_programHeader; - unique_bump_ptr> _dynamicRelocationTable; - unique_bump_ptr> _pltRelocationTable; - std::vector _absoluteAtoms; - AtomSetT _referencedDynAtoms; - llvm::StringSet<> _copiedDynSymNames; - ELFLinkingContext &_ctx; - script::Sema &_linkerScriptSema; -}; - -template -Layout::SectionOrder DefaultLayout::getSectionOrder( - StringRef name, int32_t contentType, int32_t contentPermissions) { - switch (contentType) { - case DefinedAtom::typeResolver: - case DefinedAtom::typeCode: - return llvm::StringSwitch(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(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(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 -StringRef -DefaultLayout::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 -StringRef -DefaultLayout::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(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 -Layout::SegmentType DefaultLayout::getSegmentType( - Section *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 -bool DefaultLayout::hasOutputSegment(Section *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 -AtomSection *DefaultLayout::createSection( - StringRef sectionName, int32_t contentType, - DefinedAtom::ContentPermissions permissions, SectionOrder sectionOrder) { - return new (_allocator) AtomSection(_ctx, sectionName, contentType, - permissions, sectionOrder); -} - -template -AtomSection * -DefaultLayout::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 *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 -ErrorOr -DefaultLayout::addAtom(const Atom *atom) { - if (const DefinedAtom *definedAtom = dyn_cast(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 *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(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(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 void DefaultLayout::createOutputSections() { - OutputSection *outputSection; - - for (auto &si : _sections) { - Section *section = dyn_cast>(si); - if (!section) - continue; - const std::pair *> currentOutputSection( - section->outputSectionName(), nullptr); - std::pair outputSectionInsert( - _outputSectionMap.insert(currentOutputSection)); - if (!outputSectionInsert.second) { - outputSection = outputSectionInsert.first->second; - } else { - outputSection = new (_allocator.Allocate>()) - OutputSection(section->outputSectionName()); - _outputSections.push_back(outputSection); - outputSectionInsert.first->second = outputSection; - } - outputSection->appendSection(si); - } -} - -template void DefaultLayout::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 >(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 *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 *> - additionalSegment(key, nullptr); - std::pair - additionalSegmentInsert( - _additionalSegmentMap.insert(additionalSegment)); - if (!additionalSegmentInsert.second) { - segment = additionalSegmentInsert.first->second; - } else { - segment = - new (_allocator) Segment(_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 *> currentSegment(key, - nullptr); - std::pair segmentInsert( - _segmentMap.insert(currentSegment)); - if (!segmentInsert.second) { - segment = segmentInsert.first->second; - } else { - segment = new (_allocator) - Segment(_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 *segment = new (_allocator) ProgramHeaderSegment(_ctx); - _segments.push_back(segment); - segment->append(_elfHeader); - segment->append(_programHeader); - } -} - -template -void -DefaultLayout::assignVirtualAddress() { - if (_segments.empty()) - return; - - std::sort(_segments.begin(), _segments.end(), Segment::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 *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 *section; - // Fix the offsets of all the atoms within a section - for (auto &si : _sections) { - section = dyn_cast>(si); - if (section && DefaultLayout::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 -void DefaultLayout::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 *section; - for (auto si : _sections) { - section = dyn_cast>(si); - if (section && DefaultLayout::hasOutputSegment(section)) - continue; - fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment()); - si->setFileOffset(fileoffset); - si->setVirtualAddr(0); - fileoffset += si->fileSize(); - } -} - -template void DefaultLayout::sortInputSections() { - // First, sort according to default layout's order - std::stable_sort( - _sections.begin(), _sections.end(), - [](Chunk *A, Chunk *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 *A, Chunk *B) { - auto *a = dyn_cast>(A); - auto *b = dyn_cast>(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>(*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 -void DefaultLayout::addExtraChunksToSegment(Segment *segment, - StringRef archivePath, - StringRef memberPath, - StringRef sectionName) { - if (!_linkerScriptSema.hasLayoutCommands()) - return; - - std::vector exprs = - _linkerScriptSema.getExprs({archivePath, memberPath, sectionName}); - for (auto expr : exprs) { - auto expChunk = - new (this->_allocator) ExpressionChunk(this->_ctx, expr); - segment->append(expChunk); - } -} - -} // end namespace elf -} // end namespace lld - -#endif diff --git a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h index b281b09c9c27..6fe5baabb3df 100644 --- a/lld/lib/ReaderWriter/ELF/ExecutableWriter.h +++ b/lld/lib/ReaderWriter/ELF/ExecutableWriter.h @@ -116,7 +116,7 @@ template void ExecutableWriter::createDefaultSections() { OutputELFWriter::createDefaultSections(); if (this->_ctx.isDynamic()) { _interpSection.reset(new (this->_alloc) InterpSection( - this->_ctx, ".interp", DefaultLayout::ORDER_INTERP, + this->_ctx, ".interp", TargetLayout::ORDER_INTERP, this->_ctx.getInterpreter())); this->_layout.addSection(_interpSection.get()); } diff --git a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h index d4df0e0ee4ee..facecf55670c 100644 --- a/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/Hexagon/HexagonTargetHandler.h @@ -40,8 +40,8 @@ public: (contentType == DefinedAtom::typeZeroFillFast)) return ORDER_SDATA; - return DefaultLayout::getSectionOrder(name, contentType, - contentPermissions); + return TargetLayout::getSectionOrder(name, contentType, + contentPermissions); } /// \brief Return the appropriate input section name. @@ -53,7 +53,7 @@ public: default: break; } - return DefaultLayout::getInputSectionName(da); + return TargetLayout::getInputSectionName(da); } /// \brief Gets or creates a section. @@ -64,7 +64,7 @@ public: if ((contentType == DefinedAtom::typeDataFast) || (contentType == DefinedAtom::typeZeroFillFast)) return _sdataSection; - return DefaultLayout::createSection( + return TargetLayout::createSection( name, contentType, contentPermissions, sectionOrder); } @@ -74,7 +74,7 @@ public: if (section->order() == ORDER_SDATA) return PT_LOAD; - return DefaultLayout::getSegmentType(section); + return TargetLayout::getSegmentType(section); } Section *getSDataSection() const { diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h b/lld/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h index 0e2bc18f5796..9e667de9c935 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsDynamicTable.h @@ -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 &layout) : DynamicTable(ctx, layout, ".dynamic", - DefaultLayout::ORDER_DYNAMIC), + TargetLayout::ORDER_DYNAMIC), _targetLayout(layout) {} void createDefaultEntries() override { diff --git a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h index 1018e332ffe5..cf1388960fdf 100644 --- a/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h +++ b/lld/lib/ReaderWriter/ELF/Mips/MipsTargetHandler.h @@ -39,7 +39,7 @@ public: return _gotSection; if (type == DefinedAtom::typeStub && name == ".plt") return _pltSection; - return DefaultLayout::createSection(name, type, permissions, order); + return TargetLayout::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::ORDER_TEXT; + return TargetLayout::ORDER_TEXT; - return DefaultLayout::getSectionOrder(name, contentType, - contentPermissions); + return TargetLayout::getSectionOrder(name, contentType, + contentPermissions); } protected: @@ -130,7 +130,7 @@ public: MipsSymbolTable(const ELFLinkingContext &ctx) : SymbolTable(ctx, ".symtab", - DefaultLayout::ORDER_SYMBOL_TABLE) {} + TargetLayout::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 &layout) : DynamicSymbolTable(ctx, layout, ".dynsym", - DefaultLayout::ORDER_DYNAMIC_SYMBOLS), + TargetLayout::ORDER_DYNAMIC_SYMBOLS), _targetLayout(layout) {} void sortSymbols() override { diff --git a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h index 68c258afd5dd..936d1122eeab 100644 --- a/lld/lib/ReaderWriter/ELF/OutputELFWriter.h +++ b/lld/lib/ReaderWriter/ELF/OutputELFWriter.h @@ -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::assignSectionsWithNoSegments() { _layout.assignFileOffsetsForMiscSections(); for (auto sec : _layout.sections()) if (auto section = dyn_cast>(sec)) - if (!DefaultLayout::hasOutputSegment(section)) + if (!TargetLayout::hasOutputSegment(section)) _shdrtab->updateSection(section); } @@ -398,11 +397,11 @@ template void OutputELFWriter::createDefaultSections() { _symtab = std::move(this->createSymbolTable()); _strtab.reset(new (_alloc) StringTable( - _ctx, ".strtab", DefaultLayout::ORDER_STRING_TABLE)); + _ctx, ".strtab", TargetLayout::ORDER_STRING_TABLE)); _shstrtab.reset(new (_alloc) StringTable( - _ctx, ".shstrtab", DefaultLayout::ORDER_SECTION_STRINGS)); + _ctx, ".shstrtab", TargetLayout::ORDER_SECTION_STRINGS)); _shdrtab.reset(new (_alloc) SectionHeader( - _ctx, DefaultLayout::ORDER_SECTION_HEADERS)); + _ctx, TargetLayout::ORDER_SECTION_HEADERS)); _layout.addSection(_symtab.get()); _layout.addSection(_strtab.get()); _layout.addSection(_shstrtab.get()); @@ -416,8 +415,7 @@ template void OutputELFWriter::createDefaultSections() { if (!section || section->outputSectionName() != ".eh_frame") continue; _ehFrameHeader.reset(new (_alloc) EHFrameHeader( - _ctx, ".eh_frame_hdr", _layout, - DefaultLayout::ORDER_EH_FRAMEHDR)); + _ctx, ".eh_frame_hdr", _layout, TargetLayout::ORDER_EH_FRAMEHDR)); _layout.addSection(_ehFrameHeader.get()); break; } @@ -425,10 +423,10 @@ template void OutputELFWriter::createDefaultSections() { if (_ctx.isDynamic()) { _dynamicTable = std::move(createDynamicTable()); _dynamicStringTable.reset(new (_alloc) StringTable( - _ctx, ".dynstr", DefaultLayout::ORDER_DYNAMIC_STRINGS, true)); + _ctx, ".dynstr", TargetLayout::ORDER_DYNAMIC_STRINGS, true)); _dynamicSymbolTable = std::move(createDynamicSymbolTable()); _hashTable.reset(new (_alloc) HashSection( - _ctx, ".hash", DefaultLayout::ORDER_HASH)); + _ctx, ".hash", TargetLayout::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 unique_bump_ptr> OutputELFWriter::createSymbolTable() { return unique_bump_ptr>(new (_alloc) SymbolTable( - this->_ctx, ".symtab", DefaultLayout::ORDER_SYMBOL_TABLE)); + this->_ctx, ".symtab", TargetLayout::ORDER_SYMBOL_TABLE)); } /// \brief create dynamic table @@ -461,7 +459,7 @@ template unique_bump_ptr> OutputELFWriter::createDynamicTable() { return unique_bump_ptr>(new (_alloc) DynamicTable( - this->_ctx, _layout, ".dynamic", DefaultLayout::ORDER_DYNAMIC)); + this->_ctx, _layout, ".dynamic", TargetLayout::ORDER_DYNAMIC)); } /// \brief create dynamic symbol table @@ -471,7 +469,7 @@ unique_bump_ptr> return unique_bump_ptr>( new (_alloc) DynamicSymbolTable(this->_ctx, _layout, ".dynsym", - DefaultLayout::ORDER_DYNAMIC_SYMBOLS)); + TargetLayout::ORDER_DYNAMIC_SYMBOLS)); } template diff --git a/lld/lib/ReaderWriter/ELF/SegmentChunks.h b/lld/lib/ReaderWriter/ELF/SegmentChunks.h index 4f8e8f1aaf7c..462eacb5aba8 100644 --- a/lld/lib/ReaderWriter/ELF/SegmentChunks.h +++ b/lld/lib/ReaderWriter/ELF/SegmentChunks.h @@ -29,7 +29,7 @@ namespace lld { namespace elf { -template class DefaultLayout; +template class TargetLayout; /// \brief A segment can be divided into segment slices /// depending on how the segments can be split @@ -527,7 +527,7 @@ template void Segment::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::ORDER_TBSS) + if ((*si)->order() != TargetLayout::ORDER_TBSS) curSliceSize = (*si)->memSize(); } else { uint64_t curAddr = curSliceAddress + curSliceSize; @@ -610,7 +610,7 @@ template void Segment::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::ORDER_TBSS) + if ((*si)->order() != TargetLayout::ORDER_TBSS) curSliceSize = newAddr - curSliceAddress + (*si)->memSize(); else curSliceSize = newAddr - curSliceAddress; diff --git a/lld/lib/ReaderWriter/ELF/TargetLayout.h b/lld/lib/ReaderWriter/ELF/TargetLayout.h index 1bb0363eb164..ee1f1042972d 100644 --- a/lld/lib/ReaderWriter/ELF/TargetLayout.h +++ b/lld/lib/ReaderWriter/ELF/TargetLayout.h @@ -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 +#include 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 TargetLayout : public DefaultLayout { +/// \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 TargetLayout : public Layout { public: - TargetLayout(ELFLinkingContext &ctx) : DefaultLayout(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 *>::iterator ChunkIter; + typedef typename std::vector *>::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 AdditionalSegmentKey; + // The segments are created using + // SegmentName, Segment flags + typedef std::pair 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 *> OutputSectionMapT; + typedef + typename std::vector *>::iterator OutputSectionIter; + + typedef std::unordered_map *, SectionKeyHash, + SectionKeyEq> SectionMapT; + typedef std::unordered_map *, + AdditionalSegmentHashKey> AdditionalSegmentMapT; + typedef std::unordered_map *, SegmentHashKey> + SegmentMapT; + + typedef typename std::vector::iterator AbsoluteAtomIterT; + + typedef llvm::DenseSet 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 * + 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 *section) const; + + /// \brief Returns true/false depending on whether the section has a Output + // segment or not + static bool hasOutputSegment(Section *section); + + // Adds an atom to the section + ErrorOr addAtom(const Atom *atom) override; + + /// \brief Find an output Section given a section name. + OutputSection *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 . This + /// is used to add linker script expressions before each section. + virtual void addExtraChunksToSegment(Segment *segment, + StringRef archivePath, + StringRef memberPath, + StringRef sectionName); + + void assignSectionsToSegments() override; + + void assignVirtualAddress() override; + + void assignFileOffsetsForMiscSections(); + + range absoluteAtoms() { return _absoluteAtoms; } + + void addSection(Chunk *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>(sec)) + if (auto *al = section->findAtomLayoutByName(name)) + return al; + return nullptr; + } + + void setHeader(ELFHeader *elfHeader) { _elfHeader = elfHeader; } + + void setProgramHeader(ProgramHeader *p) { + _programHeader = p; + } + + range outputSections() { return _outputSections; } + + range sections() { return _sections; } + + range segments() { return _segments; } + + ELFHeader *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 *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 *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 *createSection( + StringRef name, int32_t contentType, + DefinedAtom::ContentPermissions contentPermissions, + SectionOrder sectionOrder); + + /// \brief Create a new relocation table. + virtual unique_bump_ptr> + createRelocationTable(StringRef name, int32_t order) { + return unique_bump_ptr>( + new (_allocator) RelocationTable(_ctx, name, order)); + } + +protected: + llvm::BumpPtrAllocator _allocator; + SectionMapT _sectionMap; + OutputSectionMapT _outputSectionMap; + AdditionalSegmentMapT _additionalSegmentMap; + SegmentMapT _segmentMap; + std::vector *> _sections; + std::vector *> _segments; + std::vector *> _outputSections; + ELFHeader *_elfHeader; + ProgramHeader *_programHeader; + unique_bump_ptr> _dynamicRelocationTable; + unique_bump_ptr> _pltRelocationTable; + std::vector _absoluteAtoms; + AtomSetT _referencedDynAtoms; + llvm::StringSet<> _copiedDynSymNames; + ELFLinkingContext &_ctx; + script::Sema &_linkerScriptSema; }; + +template +Layout::SectionOrder +TargetLayout::getSectionOrder(StringRef name, int32_t contentType, + int32_t contentPermissions) { + switch (contentType) { + case DefinedAtom::typeResolver: + case DefinedAtom::typeCode: + return llvm::StringSwitch(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(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(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 +StringRef TargetLayout::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 +StringRef +TargetLayout::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(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 +Layout::SegmentType +TargetLayout::getSegmentType(Section *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 +bool TargetLayout::hasOutputSegment(Section *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 +AtomSection * +TargetLayout::createSection(StringRef sectionName, int32_t contentType, + DefinedAtom::ContentPermissions permissions, + SectionOrder sectionOrder) { + return new (_allocator) AtomSection(_ctx, sectionName, contentType, + permissions, sectionOrder); +} + +template +AtomSection * +TargetLayout::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 *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 +ErrorOr TargetLayout::addAtom(const Atom *atom) { + if (const DefinedAtom *definedAtom = dyn_cast(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 *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(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(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 void TargetLayout::createOutputSections() { + OutputSection *outputSection; + + for (auto &si : _sections) { + Section *section = dyn_cast>(si); + if (!section) + continue; + const std::pair *> currentOutputSection( + section->outputSectionName(), nullptr); + std::pair outputSectionInsert( + _outputSectionMap.insert(currentOutputSection)); + if (!outputSectionInsert.second) { + outputSection = outputSectionInsert.first->second; + } else { + outputSection = new (_allocator.Allocate>()) + OutputSection(section->outputSectionName()); + _outputSections.push_back(outputSection); + outputSectionInsert.first->second = outputSection; + } + outputSection->appendSection(si); + } +} + +template void TargetLayout::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 >(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 *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 *> + additionalSegment(key, nullptr); + std::pair + additionalSegmentInsert( + _additionalSegmentMap.insert(additionalSegment)); + if (!additionalSegmentInsert.second) { + segment = additionalSegmentInsert.first->second; + } else { + segment = + new (_allocator) Segment(_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 *> currentSegment(key, + nullptr); + std::pair segmentInsert( + _segmentMap.insert(currentSegment)); + if (!segmentInsert.second) { + segment = segmentInsert.first->second; + } else { + segment = new (_allocator) + Segment(_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 *segment = new (_allocator) ProgramHeaderSegment(_ctx); + _segments.push_back(segment); + segment->append(_elfHeader); + segment->append(_programHeader); + } +} + +template void TargetLayout::assignVirtualAddress() { + if (_segments.empty()) + return; + + std::sort(_segments.begin(), _segments.end(), Segment::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 *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 *section; + // Fix the offsets of all the atoms within a section + for (auto &si : _sections) { + section = dyn_cast>(si); + if (section && TargetLayout::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 +void TargetLayout::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 *section; + for (auto si : _sections) { + section = dyn_cast>(si); + if (section && TargetLayout::hasOutputSegment(section)) + continue; + fileoffset = llvm::RoundUpToAlignment(fileoffset, si->alignment()); + si->setFileOffset(fileoffset); + si->setVirtualAddr(0); + fileoffset += si->fileSize(); + } +} + +template void TargetLayout::sortInputSections() { + // First, sort according to default layout's order + std::stable_sort( + _sections.begin(), _sections.end(), + [](Chunk *A, Chunk *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 *A, Chunk *B) { + auto *a = dyn_cast>(A); + auto *b = dyn_cast>(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>(*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 +void TargetLayout::addExtraChunksToSegment(Segment *segment, + StringRef archivePath, + StringRef memberPath, + StringRef sectionName) { + if (!_linkerScriptSema.hasLayoutCommands()) + return; + + std::vector exprs = + _linkerScriptSema.getExprs({archivePath, memberPath, sectionName}); + for (auto expr : exprs) { + auto expChunk = + new (this->_allocator) ExpressionChunk(this->_ctx, expr); + segment->append(expChunk); + } +} + } // end namespace elf } // end namespace lld