diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-07-26 19:36:28 +0000 |
commit | cfca06d7963fa0909f90483b42a6d7d194d01e08 (patch) | |
tree | 209fb2a2d68f8f277793fc8df46c753d31bc853b /lld/ELF/LinkerScript.cpp | |
parent | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (diff) |
Notes
Diffstat (limited to 'lld/ELF/LinkerScript.cpp')
-rw-r--r-- | lld/ELF/LinkerScript.cpp | 170 |
1 files changed, 108 insertions, 62 deletions
diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 57e0e1e8acbf..72e2ebff9b8c 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -21,7 +21,6 @@ #include "Writer.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" -#include "lld/Common/Threads.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/ELF.h" @@ -29,6 +28,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Parallel.h" #include "llvm/Support/Path.h" #include <algorithm> #include <cassert> @@ -43,10 +43,10 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; +using namespace lld; +using namespace lld::elf; -namespace lld { -namespace elf { -LinkerScript *script; +LinkerScript *elf::script; static uint64_t getOutputSectionVA(SectionBase *sec) { OutputSection *os = sec->getOutputSection(); @@ -88,7 +88,7 @@ OutputSection *LinkerScript::createOutputSection(StringRef name, if (!secRef) secRef = sec; } - sec->location = location; + sec->location = std::string(location); return sec; } @@ -103,10 +103,11 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef name) { static void expandMemoryRegion(MemoryRegion *memRegion, uint64_t size, StringRef regionName, StringRef secName) { memRegion->curPos += size; - uint64_t newSize = memRegion->curPos - memRegion->origin; - if (newSize > memRegion->length) + uint64_t newSize = memRegion->curPos - (memRegion->origin)().getValue(); + uint64_t length = (memRegion->length)().getValue(); + if (newSize > length) error("section '" + secName + "' will not fit in region '" + regionName + - "': overflowed by " + Twine(newSize - memRegion->length) + " bytes"); + "': overflowed by " + Twine(newSize - length) + " bytes"); } void LinkerScript::expandMemoryRegions(uint64_t size) { @@ -246,32 +247,30 @@ getChangedSymbolAssignment(const SymbolAssignmentMap &oldValues) { return changed; } -// This method is used to handle INSERT AFTER statement. Here we rebuild -// the list of script commands to mix sections inserted into. +// Process INSERT [AFTER|BEFORE] commands. For each command, we move the +// specified output section to the designated place. void LinkerScript::processInsertCommands() { - std::vector<BaseCommand *> v; - auto insert = [&](std::vector<BaseCommand *> &from) { - v.insert(v.end(), from.begin(), from.end()); - from.clear(); - }; - - for (BaseCommand *base : sectionCommands) { - if (auto *os = dyn_cast<OutputSection>(base)) { - insert(insertBeforeCommands[os->name]); - v.push_back(base); - insert(insertAfterCommands[os->name]); + for (const InsertCommand &cmd : insertCommands) { + // If cmd.os is empty, it may have been discarded by + // adjustSectionsBeforeSorting(). We do not handle such output sections. + auto from = llvm::find(sectionCommands, cmd.os); + if (from == sectionCommands.end()) continue; + sectionCommands.erase(from); + + auto insertPos = llvm::find_if(sectionCommands, [&cmd](BaseCommand *base) { + auto *to = dyn_cast<OutputSection>(base); + return to != nullptr && to->name == cmd.where; + }); + if (insertPos == sectionCommands.end()) { + error("unable to insert " + cmd.os->name + + (cmd.isAfter ? " after " : " before ") + cmd.where); + } else { + if (cmd.isAfter) + ++insertPos; + sectionCommands.insert(insertPos, cmd.os); } - v.push_back(base); } - - for (auto &cmds : {insertBeforeCommands, insertAfterCommands}) - for (const std::pair<StringRef, std::vector<BaseCommand *>> &p : cmds) - if (!p.second.empty()) - error("unable to INSERT AFTER/BEFORE " + p.first + - ": section not defined"); - - sectionCommands = std::move(v); } // Symbols defined in script should not be inlined by LTO. At the same time @@ -324,8 +323,8 @@ static std::string getFilename(InputFile *file) { if (!file) return ""; if (file->archiveName.empty()) - return file->getName(); - return (file->archiveName + "(" + file->getName() + ")").str(); + return std::string(file->getName()); + return (file->archiveName + ':' + file->getName()).str(); } bool LinkerScript::shouldKeep(InputSectionBase *s) { @@ -335,7 +334,9 @@ bool LinkerScript::shouldKeep(InputSectionBase *s) { for (InputSectionDescription *id : keptSections) if (id->filePat.match(filename)) for (SectionPattern &p : id->sectionPatterns) - if (p.sectionPat.match(s->name)) + if (p.sectionPat.match(s->name) && + (s->flags & id->withFlags) == id->withFlags && + (s->flags & id->withoutFlags) == 0) return true; return false; } @@ -406,14 +407,15 @@ static void sortInputSections(MutableArrayRef<InputSectionBase *> vec, // Compute and remember which sections the InputSectionDescription matches. std::vector<InputSectionBase *> -LinkerScript::computeInputSections(const InputSectionDescription *cmd) { +LinkerScript::computeInputSections(const InputSectionDescription *cmd, + ArrayRef<InputSectionBase *> sections) { std::vector<InputSectionBase *> ret; // Collects all sections that satisfy constraints of Cmd. for (const SectionPattern &pat : cmd->sectionPatterns) { size_t sizeBefore = ret.size(); - for (InputSectionBase *sec : inputSections) { + for (InputSectionBase *sec : sections) { if (!sec->isLive() || sec->parent) continue; @@ -426,10 +428,15 @@ LinkerScript::computeInputSections(const InputSectionDescription *cmd) { cast<InputSection>(sec)->getRelocatedSection()) continue; + // Check the name early to improve performance in the common case. + if (!pat.sectionPat.match(sec->name)) + continue; + std::string filename = getFilename(sec->file); if (!cmd->filePat.match(filename) || pat.excludedFilePat.match(filename) || - !pat.sectionPat.match(sec->name)) + (sec->flags & cmd->withFlags) != cmd->withFlags || + (sec->flags & cmd->withoutFlags) != 0) continue; ret.push_back(sec); @@ -459,13 +466,29 @@ void LinkerScript::discard(InputSectionBase *s) { discard(ds); } +void LinkerScript::discardSynthetic(OutputSection &outCmd) { + for (Partition &part : partitions) { + if (!part.armExidx || !part.armExidx->isLive()) + continue; + std::vector<InputSectionBase *> secs(part.armExidx->exidxSections.begin(), + part.armExidx->exidxSections.end()); + for (BaseCommand *base : outCmd.sectionCommands) + if (auto *cmd = dyn_cast<InputSectionDescription>(base)) { + std::vector<InputSectionBase *> matches = + computeInputSections(cmd, secs); + for (InputSectionBase *s : matches) + discard(s); + } + } +} + std::vector<InputSectionBase *> LinkerScript::createInputSectionList(OutputSection &outCmd) { std::vector<InputSectionBase *> ret; for (BaseCommand *base : outCmd.sectionCommands) { if (auto *cmd = dyn_cast<InputSectionDescription>(base)) { - cmd->sectionBases = computeInputSections(cmd); + cmd->sectionBases = computeInputSections(cmd, inputSections); for (InputSectionBase *s : cmd->sectionBases) s->parent = &outCmd; ret.insert(ret.end(), cmd->sectionBases.begin(), cmd->sectionBases.end()); @@ -486,6 +509,7 @@ void LinkerScript::processSectionCommands() { if (sec->name == "/DISCARD/") { for (InputSectionBase *s : v) discard(s); + discardSynthetic(*sec); sec->sectionCommands.clear(); continue; } @@ -676,14 +700,12 @@ void LinkerScript::addOrphanSections() { std::function<void(InputSectionBase *)> add; add = [&](InputSectionBase *s) { if (s->isLive() && !s->parent) { - StringRef name = getOutputSectionName(s); - - if (config->orphanHandling == OrphanHandlingPolicy::Error) - error(toString(s) + " is being placed in '" + name + "'"); - else if (config->orphanHandling == OrphanHandlingPolicy::Warn) - warn(toString(s) + " is being placed in '" + name + "'"); + orphanSections.push_back(s); - if (OutputSection *sec = findByName(sectionCommands, name)) { + StringRef name = getOutputSectionName(s); + if (config->unique) { + v.push_back(createSection(s, name)); + } else if (OutputSection *sec = findByName(sectionCommands, name)) { sec->recordSection(s); } else { if (OutputSection *os = addInputSec(map, s, name)) @@ -727,6 +749,22 @@ void LinkerScript::addOrphanSections() { sectionCommands.insert(sectionCommands.begin(), v.begin(), v.end()); } +void LinkerScript::diagnoseOrphanHandling() const { + for (const InputSectionBase *sec : orphanSections) { + // Input SHT_REL[A] retained by --emit-relocs are ignored by + // computeInputSections(). Don't warn/error. + if (isa<InputSection>(sec) && + cast<InputSection>(sec)->getRelocatedSection()) + continue; + + StringRef name = getOutputSectionName(sec); + if (config->orphanHandling == OrphanHandlingPolicy::Error) + error(toString(sec) + " is being placed in '" + name + "'"); + else if (config->orphanHandling == OrphanHandlingPolicy::Warn) + warn(toString(sec) + " is being placed in '" + name + "'"); + } +} + uint64_t LinkerScript::advance(uint64_t size, unsigned alignment) { bool isTbss = (ctx->outSec->flags & SHF_TLS) && ctx->outSec->type == SHT_NOBITS; @@ -756,9 +794,16 @@ void LinkerScript::output(InputSection *s) { void LinkerScript::switchTo(OutputSection *sec) { ctx->outSec = sec; - uint64_t before = advance(0, 1); - ctx->outSec->addr = advance(0, ctx->outSec->alignment); - expandMemoryRegions(ctx->outSec->addr - before); + uint64_t pos = advance(0, 1); + if (sec->addrExpr && script->hasSectionsCommand) { + // The alignment is ignored. + ctx->outSec->addr = pos; + } else { + // ctx->outSec->alignment is the max of ALIGN and the maximum of input + // section alignments. + ctx->outSec->addr = advance(0, ctx->outSec->alignment); + expandMemoryRegions(ctx->outSec->addr - pos); + } } // This function searches for a memory region to place the given output @@ -806,6 +851,8 @@ void LinkerScript::assignOffsets(OutputSection *sec) { if (!(sec->flags & SHF_ALLOC)) dot = 0; + const bool sameMemRegion = ctx->memRegion == sec->memRegion; + const bool prevLMARegionIsDefault = ctx->lmaRegion == nullptr; ctx->memRegion = sec->memRegion; ctx->lmaRegion = sec->lmaRegion; if (ctx->memRegion) @@ -824,18 +871,20 @@ void LinkerScript::assignOffsets(OutputSection *sec) { switchTo(sec); + // ctx->lmaOffset is LMA minus VMA. If LMA is explicitly specified via AT() or + // AT>, recompute ctx->lmaOffset; otherwise, if both previous/current LMA + // region is the default, and the two sections are in the same memory region, + // reuse previous lmaOffset; otherwise, reset lmaOffset to 0. This emulates + // heuristics described in + // https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html if (sec->lmaExpr) ctx->lmaOffset = sec->lmaExpr().getValue() - dot; + else if (MemoryRegion *mr = sec->lmaRegion) + ctx->lmaOffset = alignTo(mr->curPos, sec->alignment) - dot; + else if (!sameMemRegion || !prevLMARegionIsDefault) + ctx->lmaOffset = 0; - if (MemoryRegion *mr = sec->lmaRegion) - ctx->lmaOffset = mr->curPos - dot; - - // If neither AT nor AT> is specified for an allocatable section, the linker - // will set the LMA such that the difference between VMA and LMA for the - // section is the same as the preceding output section in the same region - // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html - // This, however, should only be done by the first "non-header" section - // in the segment. + // Propagate ctx->lmaOffset to the first "non-header" section. if (PhdrEntry *l = ctx->outSec->ptLoad) if (sec == findFirstSection(l)) l->lmaOffset = ctx->lmaOffset; @@ -946,7 +995,7 @@ void LinkerScript::adjustSectionsBeforeSorting() { // We do not want to keep any special flags for output section // in case it is empty. - bool isEmpty = getInputSections(sec).empty(); + bool isEmpty = (getFirstInputSection(sec) == nullptr); if (isEmpty) sec->flags = flags & ((sec->nonAlloc ? 0 : (uint64_t)SHF_ALLOC) | SHF_WRITE | SHF_EXECINSTR); @@ -1068,7 +1117,7 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &phdrs) { LinkerScript::AddressState::AddressState() { for (auto &mri : script->memoryRegions) { MemoryRegion *mr = mri.second; - mr->curPos = mr->origin; + mr->curPos = (mr->origin)().getValue(); } } @@ -1195,11 +1244,8 @@ std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *cmd) { if (Optional<size_t> idx = getPhdrIndex(phdrsCommands, s)) ret.push_back(*idx); else if (s != "NONE") - error(cmd->location + ": section header '" + s + + error(cmd->location + ": program header '" + s + "' is not listed in PHDRS"); } return ret; } - -} // namespace elf -} // namespace lld |