summaryrefslogtreecommitdiffstats
path: root/lld/lib/ReaderWriter/ELF/TargetLayout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/ReaderWriter/ELF/TargetLayout.cpp')
-rw-r--r--lld/lib/ReaderWriter/ELF/TargetLayout.cpp699
1 files changed, 699 insertions, 0 deletions
diff --git a/lld/lib/ReaderWriter/ELF/TargetLayout.cpp b/lld/lib/ReaderWriter/ELF/TargetLayout.cpp
new file mode 100644
index 00000000000..e587bf17a4d
--- /dev/null
+++ b/lld/lib/ReaderWriter/ELF/TargetLayout.cpp
@@ -0,0 +1,699 @@
+//===- lib/ReaderWriter/ELF/TargetLayout.cpp ------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TargetLayout.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Errc.h"
+
+namespace lld {
+namespace elf {
+
+template <class ELFT>
+typename TargetLayout<ELFT>::SectionOrder
+TargetLayout<ELFT>::getSectionOrder(StringRef name, int32_t contentType,
+ int32_t contentPermissions) {
+ switch (contentType) {
+ case DefinedAtom::typeResolver:
+ case DefinedAtom::typeCode:
+ return llvm::StringSwitch<typename TargetLayout<ELFT>::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<typename TargetLayout<ELFT>::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<typename TargetLayout<ELFT>::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>
+typename TargetLayout<ELFT>::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>
+const AtomLayout *
+TargetLayout<ELFT>::findAtomLayoutByName(StringRef name) const {
+ for (auto sec : _sections)
+ if (auto section = dyn_cast<Section<ELFT>>(sec))
+ if (auto *al = section->findAtomLayoutByName(name))
+ return al;
+ return nullptr;
+}
+
+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);
+ }
+}
+
+template <class ELFT>
+RelocationTable<ELFT> *TargetLayout<ELFT>::getDynamicRelocationTable() {
+ if (!_dynamicRelocationTable) {
+ _dynamicRelocationTable = std::move(createRelocationTable(
+ _ctx.isRelaOutputFormat() ? ".rela.dyn" : ".rel.dyn",
+ ORDER_DYNAMIC_RELOCS));
+ addSection(_dynamicRelocationTable.get());
+ }
+ return _dynamicRelocationTable.get();
+}
+
+template <class ELFT>
+RelocationTable<ELFT> *TargetLayout<ELFT>::getPLTRelocationTable() {
+ if (!_pltRelocationTable) {
+ _pltRelocationTable = std::move(createRelocationTable(
+ _ctx.isRelaOutputFormat() ? ".rela.plt" : ".rel.plt",
+ ORDER_DYNAMIC_PLT_RELOCS));
+ addSection(_pltRelocationTable.get());
+ }
+ return _pltRelocationTable.get();
+}
+
+template <class ELFT> uint64_t TargetLayout<ELFT>::getTLSSize() const {
+ for (const auto &phdr : *_programHeader)
+ if (phdr->p_type == llvm::ELF::PT_TLS)
+ return phdr->p_memsz;
+ return 0;
+}
+
+template class TargetLayout<ELF32LE>;
+template class TargetLayout<ELF32BE>;
+template class TargetLayout<ELF64LE>;
+template class TargetLayout<ELF64BE>;
+
+} // end namespace elf
+} // end namespace lld
OpenPOWER on IntegriCloud