Mercurial > hg > CbC > CbC_llvm
diff lld/ELF/Writer.cpp @ 207:2e18cbf3894f
LLVM12
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 08 Jun 2021 06:07:14 +0900 |
parents | 0572611fdcc8 |
children | 5f17cb93ff66 |
line wrap: on
line diff
--- a/lld/ELF/Writer.cpp Mon May 25 11:55:54 2020 +0900 +++ b/lld/ELF/Writer.cpp Tue Jun 08 06:07:14 2021 +0900 @@ -19,6 +19,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "lld/Common/Arrays.h" #include "lld/Common/Filesystem.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" @@ -45,10 +46,9 @@ // 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 +131,14 @@ // 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 +158,6 @@ } template <class ELFT> void elf::writeResult() { - llvm::TimeTraceScope timeScope("Write output file"); Writer<ELFT>().run(); } @@ -200,6 +204,7 @@ } 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. @@ -264,6 +269,8 @@ // glibc *crt1.o has a undefined reference to _SDA_BASE_. Since we don't // support Small Data Area, define it arbitrarily as 0. addOptionalRegular("_SDA_BASE_", nullptr, 0, STV_HIDDEN); + } else if (config->emachine == EM_PPC64) { + addPPC64SaveRestore(); } // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which @@ -629,28 +636,32 @@ // 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; + + if (!config->oFormatBinary) { + if (config->zSeparate != SeparateSegmentKind::None) + writeTrapInstr(); + writeHeader(); + writeSections(); + } else { + writeSectionsBinary(); + } + + // 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))); } - - // 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> @@ -756,14 +767,13 @@ 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) { ObjFile<ELFT> *f = cast<ObjFile<ELFT>>(file); for (Symbol *b : f->getLocalSymbols()) { - if (!b->isLocal()) - fatal(toString(f) + - ": broken object: getLocalSymbols returns a non-local symbol"); + assert(b->isLocal() && "should have been caught in initializeSymbols()"); auto *dr = dyn_cast<Defined>(b); // No reason to keep local undefined symbol in symtab. @@ -806,9 +816,12 @@ 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); } } @@ -1279,22 +1292,39 @@ // Adds random priorities to sections not already in the map. static void maybeShuffle(DenseMap<const InputSectionBase *, int> &order) { - if (!config->shuffleSectionSeed) + if (config->shuffleSections.empty()) return; - std::vector<int> priorities(inputSections.size() - order.size()); + std::vector<InputSectionBase *> matched, sections = inputSections; + matched.reserve(sections.size()); + for (const auto &patAndSeed : config->shuffleSections) { + matched.clear(); + for (InputSectionBase *sec : sections) + if (patAndSeed.first.match(sec->name)) + matched.push_back(sec); + const uint32_t seed = patAndSeed.second; + if (seed == UINT32_MAX) { + // If --shuffle-sections <section-glob>=-1, reverse the section order. The + // section order is stable even if the number of sections changes. This is + // useful to catch issues like static initialization order fiasco + // reliably. + std::reverse(matched.begin(), matched.end()); + } else { + std::mt19937 g(seed ? seed : std::random_device()()); + llvm::shuffle(matched.begin(), matched.end(), g); + } + size_t i = 0; + for (InputSectionBase *&sec : sections) + if (patAndSeed.first.match(sec->name)) + sec = matched[i++]; + } + // Existing priorities are < 0, so use priorities >= 0 for the missing // sections. - int curPrio = 0; - for (int &prio : priorities) - prio = curPrio++; - uint32_t seed = *config->shuffleSectionSeed; - std::mt19937 g(seed ? seed : std::random_device()()); - llvm::shuffle(priorities.begin(), priorities.end(), g); - int prioIndex = 0; - for (InputSectionBase *sec : inputSections) { - if (order.try_emplace(sec, priorities[prioIndex]).second) - ++prioIndex; + int prio = 0; + for (InputSectionBase *sec : sections) { + if (order.try_emplace(sec, prio).second) + ++prio; } } @@ -1346,9 +1376,11 @@ 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 +1463,14 @@ if (name == ".init" || name == ".fini") return; + // IRelative relocations that usually live in the .rel[a].dyn section should + // be processed last by the dynamic loader. To achieve that we add synthetic + // sections in the required order from the beginning 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 +1526,7 @@ } 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 +1645,12 @@ } 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 +1660,7 @@ } 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 +1671,42 @@ 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 +1714,7 @@ // 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 +1736,8 @@ 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; } @@ -1748,7 +1787,7 @@ Twine(os->alignment) + ")"); } -// If Input Sections have been shrinked (basic block sections) then +// If Input Sections have been shrunk (basic block sections) then // update symbol values and sizes associated with these sections. With basic // block sections, input sections can shrink when the jump instructions at // the end of the section are relaxed. @@ -1932,11 +1971,14 @@ } } - // 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 +1987,17 @@ // 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 +2005,11 @@ if (in.iplt && in.iplt->isNeeded()) in.iplt->addSymbols(); - if (!config->allowShlibUndefined) { + if (config->unresolvedSymbolsInShlib != UnresolvedPolicy::Ignore) { + auto diagnose = + config->unresolvedSymbolsInShlib == UnresolvedPolicy::ReportError + ? errorOrWarn + : warn; // 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. @@ -1968,44 +2017,48 @@ // ld.bfd traces all DT_NEEDED to emulate the logic of the dynamic linker to // catch more cases. That is too much for us. Our approach resembles the one // used in ld.gold, achieves a good balance to be useful but not too smart. - for (SharedFile *file : sharedFiles) - file->allNeededIsKnown = + for (SharedFile *file : sharedFiles) { + bool allNeededIsKnown = llvm::all_of(file->dtNeeded, [&](StringRef needed) { return symtab->soNames.count(needed); }); - - for (Symbol *sym : symtab->symbols()) - if (sym->isUndefined() && !sym->isWeak()) - if (auto *f = dyn_cast_or_null<SharedFile>(sym->file)) - if (f->allNeededIsKnown) - error(toString(f) + ": undefined reference to " + toString(*sym)); - } - - // 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); + if (!allNeededIsKnown) + continue; + for (Symbol *sym : file->requiredSymbols) + if (sym->isUndefined() && !sym->isWeak()) + diagnose(toString(file) + ": undefined reference to " + + toString(*sym) + " [--no-allow-shlib-undefined]"); } } - // 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); + { + 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); + } } // Do not proceed if there was an undefined symbol. @@ -2086,35 +2139,39 @@ // 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) @@ -2145,9 +2202,13 @@ 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 @@ -2228,8 +2289,10 @@ StringRef s = sec->name; if (!isValidCIdentifier(s)) return; - addOptionalRegular(saver.save("__start_" + s), sec, 0, STV_PROTECTED); - addOptionalRegular(saver.save("__stop_" + s), sec, -1, STV_PROTECTED); + addOptionalRegular(saver.save("__start_" + s), sec, 0, + config->zStartStopVisibility); + addOptionalRegular(saver.save("__stop_" + s), sec, -1, + config->zStartStopVisibility); } static bool needsPtLoad(OutputSection *sec) { @@ -2323,8 +2386,6 @@ } for (OutputSection *sec : outputSections) { - if (!(sec->flags & SHF_ALLOC)) - break; if (!needsPtLoad(sec)) continue; @@ -2544,11 +2605,24 @@ } 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) { @@ -2567,7 +2641,11 @@ 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 @@ -2577,6 +2655,9 @@ 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); @@ -2808,7 +2889,13 @@ 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; } @@ -2885,19 +2972,6 @@ sec->writeTo<ELFT>(Out::bufferStart + sec->offset); } -// Split one uint8 array into small pieces of uint8 arrays. -static std::vector<ArrayRef<uint8_t>> split(ArrayRef<uint8_t> arr, - size_t chunkSize) { - std::vector<ArrayRef<uint8_t>> ret; - while (arr.size() > chunkSize) { - ret.push_back(arr.take_front(chunkSize)); - arr = arr.drop_front(chunkSize); - } - if (!arr.empty()) - ret.push_back(arr); - return ret; -} - // Computes a hash value of Data using a given hash function. // In order to utilize multiple cores, we first split data into 1MB // chunks, compute a hash for each chunk, and then compute a hash value