aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lld/ELF/Writer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lld/ELF/Writer.cpp')
-rw-r--r--contrib/llvm-project/lld/ELF/Writer.cpp355
1 files changed, 211 insertions, 144 deletions
diff --git a/contrib/llvm-project/lld/ELF/Writer.cpp b/contrib/llvm-project/lld/ELF/Writer.cpp
index b9fd03bc2eda..f550e6a73335 100644
--- a/contrib/llvm-project/lld/ELF/Writer.cpp
+++ b/contrib/llvm-project/lld/ELF/Writer.cpp
@@ -45,10 +45,9 @@ namespace {
// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
+ LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
+
Writer() : buffer(errorHandler().outputBuffer) {}
- using Elf_Shdr = typename ELFT::Shdr;
- using Elf_Ehdr = typename ELFT::Ehdr;
- using Elf_Phdr = typename ELFT::Phdr;
void run();
@@ -131,9 +130,14 @@ StringRef elf::getOutputSectionName(const InputSectionBase *s) {
// SampleFDO is used, if a function doesn't have sample, it could be very
// cold or it could be a new function never being sampled. Those functions
// will be kept in the ".text.unknown" section.
+ // ".text.split." holds symbols which are split out from functions in other
+ // input sections. For example, with -fsplit-machine-functions, placing the
+ // cold parts in .text.split instead of .text.unlikely mitigates against poor
+ // profile inaccuracy. Techniques such as hugepage remapping can make
+ // conservative decisions at the section granularity.
if (config->zKeepTextSectionPrefix)
for (StringRef v : {".text.hot.", ".text.unknown.", ".text.unlikely.",
- ".text.startup.", ".text.exit."})
+ ".text.startup.", ".text.exit.", ".text.split."})
if (isSectionPrefix(v, s->name))
return v.drop_back();
@@ -153,7 +157,6 @@ static bool needsInterpSection() {
}
template <class ELFT> void elf::writeResult() {
- llvm::TimeTraceScope timeScope("Write output file");
Writer<ELFT>().run();
}
@@ -200,6 +203,7 @@ void elf::copySectionsIntoPartitions() {
}
void elf::combineEhSections() {
+ llvm::TimeTraceScope timeScope("Combine EH sections");
for (InputSectionBase *&s : inputSections) {
// Ignore dead sections and the partition end marker (.part.end),
// whose partition number is out of bounds.
@@ -631,28 +635,32 @@ template <class ELFT> void Writer<ELFT>::run() {
// It does not make sense try to open the file if we have error already.
if (errorCount())
return;
- // Write the result down to a file.
- openFile();
- if (errorCount())
- return;
- if (!config->oFormatBinary) {
- if (config->zSeparate != SeparateSegmentKind::None)
- writeTrapInstr();
- writeHeader();
- writeSections();
- } else {
- writeSectionsBinary();
- }
+ {
+ llvm::TimeTraceScope timeScope("Write output file");
+ // Write the result down to a file.
+ openFile();
+ if (errorCount())
+ return;
- // Backfill .note.gnu.build-id section content. This is done at last
- // because the content is usually a hash value of the entire output file.
- writeBuildId();
- if (errorCount())
- return;
+ if (!config->oFormatBinary) {
+ if (config->zSeparate != SeparateSegmentKind::None)
+ writeTrapInstr();
+ writeHeader();
+ writeSections();
+ } else {
+ writeSectionsBinary();
+ }
- if (auto e = buffer->commit())
- error("failed to write to the output file: " + toString(std::move(e)));
+ // Backfill .note.gnu.build-id section content. This is done at last
+ // because the content is usually a hash value of the entire output file.
+ writeBuildId();
+ if (errorCount())
+ return;
+
+ if (auto e = buffer->commit())
+ error("failed to write to the output file: " + toString(std::move(e)));
+ }
}
template <class ELFT, class RelTy>
@@ -758,6 +766,7 @@ static bool includeInSymtab(const Symbol &b) {
template <class ELFT> void Writer<ELFT>::copyLocalSymbols() {
if (!in.symTab)
return;
+ llvm::TimeTraceScope timeScope("Add local symbols");
if (config->copyRelocs && config->discard != DiscardPolicy::None)
markUsedLocalSymbols<ELFT>();
for (InputFile *file : objectFiles) {
@@ -806,9 +815,12 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() {
if (isa<SyntheticSection>(isec) && !(isec->flags & SHF_MERGE))
continue;
+ // Set the symbol to be relative to the output section so that its st_value
+ // equals the output section address. Note, there may be a gap between the
+ // start of the output section and isec.
auto *sym =
make<Defined>(isec->file, "", STB_LOCAL, /*stOther=*/0, STT_SECTION,
- /*value=*/0, /*size=*/0, isec);
+ /*value=*/0, /*size=*/0, isec->getOutputSection());
in.symTab->addSymbol(sym);
}
}
@@ -1346,9 +1358,11 @@ static DenseMap<const InputSectionBase *, int> buildSectionOrder() {
addSym(*sym);
for (InputFile *file : objectFiles)
- for (Symbol *sym : file->getSymbols())
- if (sym->isLocal())
- addSym(*sym);
+ for (Symbol *sym : file->getSymbols()) {
+ if (!sym->isLocal())
+ break;
+ addSym(*sym);
+ }
if (config->warnSymbolOrdering)
for (auto orderEntry : symbolOrder)
@@ -1431,6 +1445,14 @@ static void sortSection(OutputSection *sec,
if (name == ".init" || name == ".fini")
return;
+ // IRelative relocations that usually live in the .rel[a].dyn section should
+ // be proccessed last by the dynamic loader. To achieve that we add synthetic
+ // sections in the required order from the begining so that the in.relaIplt
+ // section is placed last in an output section. Here we just do not apply
+ // sorting for an output section which holds the in.relaIplt section.
+ if (in.relaIplt->getParent() == sec)
+ return;
+
// Sort input sections by priority using the list provided by
// --symbol-ordering-file or --shuffle-sections=. This is a least significant
// digit radix sort. The sections may be sorted stably again by a more
@@ -1486,6 +1508,7 @@ template <class ELFT> void Writer<ELFT>::sortInputSections() {
}
template <class ELFT> void Writer<ELFT>::sortSections() {
+ llvm::TimeTraceScope timeScope("Sort sections");
script->adjustSectionsBeforeSorting();
// Don't sort if using -r. It is not necessary and we want to preserve the
@@ -1604,8 +1627,12 @@ template <class ELFT> void Writer<ELFT>::sortSections() {
}
static bool compareByFilePosition(InputSection *a, InputSection *b) {
- InputSection *la = a->getLinkOrderDep();
- InputSection *lb = b->getLinkOrderDep();
+ InputSection *la = a->flags & SHF_LINK_ORDER ? a->getLinkOrderDep() : nullptr;
+ InputSection *lb = b->flags & SHF_LINK_ORDER ? b->getLinkOrderDep() : nullptr;
+ // SHF_LINK_ORDER sections with non-zero sh_link are ordered before
+ // non-SHF_LINK_ORDER sections and SHF_LINK_ORDER sections with zero sh_link.
+ if (!la || !lb)
+ return la && !lb;
OutputSection *aOut = la->getParent();
OutputSection *bOut = lb->getParent();
@@ -1615,6 +1642,7 @@ static bool compareByFilePosition(InputSection *a, InputSection *b) {
}
template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
+ llvm::TimeTraceScope timeScope("Resolve SHF_LINK_ORDER");
for (OutputSection *sec : outputSections) {
if (!(sec->flags & SHF_LINK_ORDER))
continue;
@@ -1625,50 +1653,42 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() {
sec->type == SHT_ARM_EXIDX)
continue;
- // Link order may be distributed across several InputSectionDescriptions
- // but sort must consider them all at once.
+ // Link order may be distributed across several InputSectionDescriptions.
+ // Sorting is performed separately.
std::vector<InputSection **> scriptSections;
std::vector<InputSection *> sections;
- bool started = false, stopped = false;
for (BaseCommand *base : sec->sectionCommands) {
- if (auto *isd = dyn_cast<InputSectionDescription>(base)) {
- for (InputSection *&isec : isd->sections) {
- if (!(isec->flags & SHF_LINK_ORDER)) {
- if (started)
- stopped = true;
- } else if (stopped) {
- error(toString(isec) + ": SHF_LINK_ORDER sections in " + sec->name +
- " are not contiguous");
- } else {
- started = true;
-
- scriptSections.push_back(&isec);
- sections.push_back(isec);
-
- InputSection *link = isec->getLinkOrderDep();
- if (!link->getParent())
- error(toString(isec) + ": sh_link points to discarded section " +
- toString(link));
- }
+ auto *isd = dyn_cast<InputSectionDescription>(base);
+ if (!isd)
+ continue;
+ bool hasLinkOrder = false;
+ scriptSections.clear();
+ sections.clear();
+ for (InputSection *&isec : isd->sections) {
+ if (isec->flags & SHF_LINK_ORDER) {
+ InputSection *link = isec->getLinkOrderDep();
+ if (link && !link->getParent())
+ error(toString(isec) + ": sh_link points to discarded section " +
+ toString(link));
+ hasLinkOrder = true;
}
- } else if (started) {
- stopped = true;
+ scriptSections.push_back(&isec);
+ sections.push_back(isec);
+ }
+ if (hasLinkOrder && errorCount() == 0) {
+ llvm::stable_sort(sections, compareByFilePosition);
+ for (int i = 0, n = sections.size(); i != n; ++i)
+ *scriptSections[i] = sections[i];
}
}
-
- if (errorCount())
- continue;
-
- llvm::stable_sort(sections, compareByFilePosition);
-
- for (int i = 0, n = sections.size(); i < n; ++i)
- *scriptSections[i] = sections[i];
}
}
static void finalizeSynthetic(SyntheticSection *sec) {
- if (sec && sec->isNeeded() && sec->getParent())
+ if (sec && sec->isNeeded() && sec->getParent()) {
+ llvm::TimeTraceScope timeScope("Finalize synthetic sections", sec->name);
sec->finalizeContents();
+ }
}
// We need to generate and finalize the content that depends on the address of
@@ -1676,6 +1696,7 @@ static void finalizeSynthetic(SyntheticSection *sec) {
// addresses we must converge to a fixed point. We do that here. See the comment
// in Writer<ELFT>::finalizeSections().
template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
+ llvm::TimeTraceScope timeScope("Finalize address dependent content");
ThunkCreator tc;
AArch64Err843419Patcher a64p;
ARMErr657417Patcher a32p;
@@ -1697,8 +1718,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
bool changed = target->needsThunks && tc.createThunks(outputSections);
// With Thunk Size much smaller than branch range we expect to
- // converge quickly; if we get to 10 something has gone wrong.
- if (changed && tc.pass >= 10) {
+ // converge quickly; if we get to 15 something has gone wrong.
+ if (changed && tc.pass >= 15) {
error("thunk creation not converged");
break;
}
@@ -1932,11 +1953,14 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
}
}
- // This responsible for splitting up .eh_frame section into
- // pieces. The relocation scan uses those pieces, so this has to be
- // earlier.
- for (Partition &part : partitions)
- finalizeSynthetic(part.ehFrame);
+ {
+ llvm::TimeTraceScope timeScope("Finalize .eh_frame");
+ // This responsible for splitting up .eh_frame section into
+ // pieces. The relocation scan uses those pieces, so this has to be
+ // earlier.
+ for (Partition &part : partitions)
+ finalizeSynthetic(part.ehFrame);
+ }
for (Symbol *sym : symtab->symbols())
sym->isPreemptible = computeIsPreemptible(*sym);
@@ -1945,14 +1969,17 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// by declareSymbols) to actual definitions.
script->processSymbolAssignments();
- // Scan relocations. This must be done after every symbol is declared so that
- // we can correctly decide if a dynamic relocation is needed. This is called
- // after processSymbolAssignments() because it needs to know whether a
- // linker-script-defined symbol is absolute.
- ppc64noTocRelax.clear();
- if (!config->relocatable) {
- forEachRelSec(scanRelocations<ELFT>);
- reportUndefinedSymbols<ELFT>();
+ {
+ llvm::TimeTraceScope timeScope("Scan relocations");
+ // Scan relocations. This must be done after every symbol is declared so
+ // that we can correctly decide if a dynamic relocation is needed. This is
+ // called after processSymbolAssignments() because it needs to know whether
+ // a linker-script-defined symbol is absolute.
+ ppc64noTocRelax.clear();
+ if (!config->relocatable) {
+ forEachRelSec(scanRelocations<ELFT>);
+ reportUndefinedSymbols<ELFT>();
+ }
}
if (in.plt && in.plt->isNeeded())
@@ -1960,7 +1987,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (in.iplt && in.iplt->isNeeded())
in.iplt->addSymbols();
- if (!config->allowShlibUndefined) {
+ if (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) {
// Error on undefined symbols in a shared object, if all of its DT_NEEDED
// entries are seen. These cases would otherwise lead to runtime errors
// reported by the dynamic linker.
@@ -1977,36 +2004,44 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
for (Symbol *sym : symtab->symbols())
if (sym->isUndefined() && !sym->isWeak())
if (auto *f = dyn_cast_or_null<SharedFile>(sym->file))
- if (f->allNeededIsKnown)
- errorOrWarn(toString(f) + ": undefined reference to " +
- toString(*sym) + " [--no-allow-shlib-undefined]");
+ if (f->allNeededIsKnown) {
+ auto diagnose = config->unresolvedSymbolsInShlib ==
+ UnresolvedPolicy::ReportError
+ ? errorOrWarn
+ : warn;
+ diagnose(toString(f) + ": undefined reference to " +
+ toString(*sym) + " [--no-allow-shlib-undefined]");
+ }
}
- // Now that we have defined all possible global symbols including linker-
- // synthesized ones. Visit all symbols to give the finishing touches.
- for (Symbol *sym : symtab->symbols()) {
- if (!includeInSymtab(*sym))
- continue;
- if (in.symTab)
- in.symTab->addSymbol(sym);
-
- if (sym->includeInDynsym()) {
- partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
- if (auto *file = dyn_cast_or_null<SharedFile>(sym->file))
- if (file->isNeeded && !sym->isUndefined())
- addVerneed(sym);
+ {
+ llvm::TimeTraceScope timeScope("Add symbols to symtabs");
+ // Now that we have defined all possible global symbols including linker-
+ // synthesized ones. Visit all symbols to give the finishing touches.
+ for (Symbol *sym : symtab->symbols()) {
+ if (!includeInSymtab(*sym))
+ continue;
+ if (in.symTab)
+ in.symTab->addSymbol(sym);
+
+ if (sym->includeInDynsym()) {
+ partitions[sym->partition - 1].dynSymTab->addSymbol(sym);
+ if (auto *file = dyn_cast_or_null<SharedFile>(sym->file))
+ if (file->isNeeded && !sym->isUndefined())
+ addVerneed(sym);
+ }
}
- }
- // We also need to scan the dynamic relocation tables of the other partitions
- // and add any referenced symbols to the partition's dynsym.
- for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) {
- DenseSet<Symbol *> syms;
- for (const SymbolTableEntry &e : part.dynSymTab->getSymbols())
- syms.insert(e.sym);
- for (DynamicReloc &reloc : part.relaDyn->relocs)
- if (reloc.sym && !reloc.useSymVA && syms.insert(reloc.sym).second)
- part.dynSymTab->addSymbol(reloc.sym);
+ // We also need to scan the dynamic relocation tables of the other
+ // partitions and add any referenced symbols to the partition's dynsym.
+ for (Partition &part : MutableArrayRef<Partition>(partitions).slice(1)) {
+ DenseSet<Symbol *> syms;
+ for (const SymbolTableEntry &e : part.dynSymTab->getSymbols())
+ syms.insert(e.sym);
+ for (DynamicReloc &reloc : part.relaDyn->relocs)
+ if (reloc.sym && !reloc.useSymVA && syms.insert(reloc.sym).second)
+ part.dynSymTab->addSymbol(reloc.sym);
+ }
}
// Do not proceed if there was an undefined symbol.
@@ -2087,35 +2122,39 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
// have the headers, we can find out which sections they point to.
setReservedSymbolSections();
- finalizeSynthetic(in.bss);
- finalizeSynthetic(in.bssRelRo);
- finalizeSynthetic(in.symTabShndx);
- finalizeSynthetic(in.shStrTab);
- finalizeSynthetic(in.strTab);
- finalizeSynthetic(in.got);
- finalizeSynthetic(in.mipsGot);
- finalizeSynthetic(in.igotPlt);
- finalizeSynthetic(in.gotPlt);
- finalizeSynthetic(in.relaIplt);
- finalizeSynthetic(in.relaPlt);
- finalizeSynthetic(in.plt);
- finalizeSynthetic(in.iplt);
- finalizeSynthetic(in.ppc32Got2);
- finalizeSynthetic(in.partIndex);
-
- // Dynamic section must be the last one in this list and dynamic
- // symbol table section (dynSymTab) must be the first one.
- for (Partition &part : partitions) {
- finalizeSynthetic(part.dynSymTab);
- finalizeSynthetic(part.gnuHashTab);
- finalizeSynthetic(part.hashTab);
- finalizeSynthetic(part.verDef);
- finalizeSynthetic(part.relaDyn);
- finalizeSynthetic(part.relrDyn);
- finalizeSynthetic(part.ehFrameHdr);
- finalizeSynthetic(part.verSym);
- finalizeSynthetic(part.verNeed);
- finalizeSynthetic(part.dynamic);
+ {
+ llvm::TimeTraceScope timeScope("Finalize synthetic sections");
+
+ finalizeSynthetic(in.bss);
+ finalizeSynthetic(in.bssRelRo);
+ finalizeSynthetic(in.symTabShndx);
+ finalizeSynthetic(in.shStrTab);
+ finalizeSynthetic(in.strTab);
+ finalizeSynthetic(in.got);
+ finalizeSynthetic(in.mipsGot);
+ finalizeSynthetic(in.igotPlt);
+ finalizeSynthetic(in.gotPlt);
+ finalizeSynthetic(in.relaIplt);
+ finalizeSynthetic(in.relaPlt);
+ finalizeSynthetic(in.plt);
+ finalizeSynthetic(in.iplt);
+ finalizeSynthetic(in.ppc32Got2);
+ finalizeSynthetic(in.partIndex);
+
+ // Dynamic section must be the last one in this list and dynamic
+ // symbol table section (dynSymTab) must be the first one.
+ for (Partition &part : partitions) {
+ finalizeSynthetic(part.dynSymTab);
+ finalizeSynthetic(part.gnuHashTab);
+ finalizeSynthetic(part.hashTab);
+ finalizeSynthetic(part.verDef);
+ finalizeSynthetic(part.relaDyn);
+ finalizeSynthetic(part.relrDyn);
+ finalizeSynthetic(part.ehFrameHdr);
+ finalizeSynthetic(part.verSym);
+ finalizeSynthetic(part.verNeed);
+ finalizeSynthetic(part.dynamic);
+ }
}
if (!script->hasSectionsCommand && !config->relocatable)
@@ -2146,9 +2185,13 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() {
if (errorCount())
return;
- // finalizeAddressDependentContent may have added local symbols to the static symbol table.
- finalizeSynthetic(in.symTab);
- finalizeSynthetic(in.ppc64LongBranchTarget);
+ {
+ llvm::TimeTraceScope timeScope("Finalize synthetic sections");
+ // finalizeAddressDependentContent may have added local symbols to the
+ // static symbol table.
+ finalizeSynthetic(in.symTab);
+ finalizeSynthetic(in.ppc64LongBranchTarget);
+ }
// Relaxation to delete inter-basic block jumps created by basic block
// sections. Run after in.symTab is finalized as optimizeBasicBlockJumps
@@ -2326,8 +2369,6 @@ std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs(Partition &part) {
}
for (OutputSection *sec : outputSections) {
- if (!(sec->flags & SHF_ALLOC))
- break;
if (!needsPtLoad(sec))
continue;
@@ -2547,11 +2588,24 @@ static uint64_t setFileOffset(OutputSection *os, uint64_t off) {
}
template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() {
- uint64_t off = 0;
+ // Compute the minimum LMA of all non-empty non-NOBITS sections as minAddr.
+ auto needsOffset = [](OutputSection &sec) {
+ return sec.type != SHT_NOBITS && (sec.flags & SHF_ALLOC) && sec.size > 0;
+ };
+ uint64_t minAddr = UINT64_MAX;
for (OutputSection *sec : outputSections)
- if (sec->flags & SHF_ALLOC)
- off = setFileOffset(sec, off);
- fileSize = alignTo(off, config->wordsize);
+ if (needsOffset(*sec)) {
+ sec->offset = sec->getLMA();
+ minAddr = std::min(minAddr, sec->offset);
+ }
+
+ // Sections are laid out at LMA minus minAddr.
+ fileSize = 0;
+ for (OutputSection *sec : outputSections)
+ if (needsOffset(*sec)) {
+ sec->offset -= minAddr;
+ fileSize = std::max(fileSize, sec->offset + sec->size);
+ }
}
static std::string rangeToString(uint64_t addr, uint64_t len) {
@@ -2570,7 +2624,11 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
if (p->p_type == PT_LOAD && (p->p_flags & PF_X))
lastRX = p;
+ // Layout SHF_ALLOC sections before non-SHF_ALLOC sections. A non-SHF_ALLOC
+ // will not occupy file offsets contained by a PT_LOAD.
for (OutputSection *sec : outputSections) {
+ if (!(sec->flags & SHF_ALLOC))
+ continue;
off = setFileOffset(sec, off);
// If this is a last section of the last executable segment and that
@@ -2580,6 +2638,9 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() {
lastRX->lastSec == sec)
off = alignTo(off, config->commonPageSize);
}
+ for (OutputSection *sec : outputSections)
+ if (!(sec->flags & SHF_ALLOC))
+ off = setFileOffset(sec, off);
sectionHeaderOff = alignTo(off, config->wordsize);
fileSize = sectionHeaderOff + (outputSections.size() + 1) * sizeof(Elf_Shdr);
@@ -2811,7 +2872,13 @@ template <class ELFT> void Writer<ELFT>::writeHeader() {
template <class ELFT> void Writer<ELFT>::openFile() {
uint64_t maxSize = config->is64 ? INT64_MAX : UINT32_MAX;
if (fileSize != size_t(fileSize) || maxSize < fileSize) {
- error("output file too large: " + Twine(fileSize) + " bytes");
+ std::string msg;
+ raw_string_ostream s(msg);
+ s << "output file too large: " << Twine(fileSize) << " bytes\n"
+ << "section sizes:\n";
+ for (OutputSection *os : outputSections)
+ s << os->name << ' ' << os->size << "\n";
+ error(s.str());
return;
}