diff --git a/lld/ELF/CallGraphSort.cpp b/lld/ELF/CallGraphSort.cpp --- a/lld/ELF/CallGraphSort.cpp +++ b/lld/ELF/CallGraphSort.cpp @@ -114,8 +114,8 @@ // Create the graph. for (std::pair &c : profile) { - const auto *fromSB = cast(c.first.first->repl); - const auto *toSB = cast(c.first.second->repl); + const auto *fromSB = cast(c.first.first); + const auto *toSB = cast(c.first.second); uint64_t weight = c.second; // Ignore edges between input sections belonging to different output diff --git a/lld/ELF/ICF.cpp b/lld/ELF/ICF.cpp --- a/lld/ELF/ICF.cpp +++ b/lld/ELF/ICF.cpp @@ -550,6 +550,22 @@ } }); + // Change Defined symbol's section field to the canonical one. + auto fold = [](Symbol *sym) { + if (auto *d = dyn_cast(sym)) + if (auto *sec = dyn_cast_or_null(d->section)) + if (sec->repl != d->section) { + d->section = sec->repl; + d->folded = true; + } + }; + for (Symbol *sym : symtab->symbols()) + fold(sym); + parallelForEach(objectFiles, [&](ELFFileBase *file) { + for (Symbol *sym : file->getLocalSymbols()) + fold(sym); + }); + // InputSectionDescription::sections is populated by processSectionCommands(). // ICF may fold some input sections assigned to output sections. Remove them. for (SectionCommand *cmd : script->sectionCommands) diff --git a/lld/ELF/InputSection.h b/lld/ELF/InputSection.h --- a/lld/ELF/InputSection.h +++ b/lld/ELF/InputSection.h @@ -52,13 +52,6 @@ StringRef name; - // This pointer points to the "real" instance of this instance. - // Usually Repl == this. However, if ICF merges two sections, - // Repl pointer of one section points to another section. So, - // if you need to get a pointer to this instance, do not use - // this but instead this->Repl. - SectionBase *repl; - uint8_t sectionKind : 3; // The next two bit fields are only used by InputSectionBase, but we @@ -102,9 +95,9 @@ constexpr SectionBase(Kind sectionKind, StringRef name, uint64_t flags, uint32_t entsize, uint32_t alignment, uint32_t type, uint32_t info, uint32_t link) - : name(name), repl(this), sectionKind(sectionKind), bss(false), - keepUnique(false), partition(0), alignment(alignment), flags(flags), - entsize(entsize), type(type), link(link), info(info) {} + : name(name), sectionKind(sectionKind), bss(false), keepUnique(false), + partition(0), alignment(alignment), flags(flags), entsize(entsize), + type(type), link(link), info(info) {} }; // This corresponds to a section of an input file. @@ -367,6 +360,10 @@ template void relocateNonAlloc(uint8_t *buf, llvm::ArrayRef rels); + // Points to the canonical section. If ICF folds two sections, repl pointer of + // one section points to the other. + InputSection *repl = this; + // Used by ICF. uint32_t eqClass[2] = {0, 0}; diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -442,7 +442,7 @@ p->setSymbolAndType(0, 0, false); continue; } - SectionBase *section = d->section->repl; + SectionBase *section = d->section; if (!section->isLive()) { p->setSymbolAndType(0, 0, false); continue; @@ -948,10 +948,10 @@ // // If the referenced symbol is discarded (made Undefined), or the // section defining the referenced symbol is garbage collected, - // sym.getOutputSection() is nullptr. `ds->section->repl != ds->section` - // catches the ICF folded case. However, resolving a relocation in - // .debug_line to -1 would stop debugger users from setting breakpoints on - // the folded-in function, so exclude .debug_line. + // sym.getOutputSection() is nullptr. `ds->folded` catches the ICF folded + // case. However, resolving a relocation in .debug_line to -1 would stop + // debugger users from setting breakpoints on the folded-in function, so + // exclude .debug_line. // // For pre-DWARF-v5 .debug_loc and .debug_ranges, -1 is a reserved value // (base address selection entry), use 1 (which is used by GNU ld for @@ -960,8 +960,7 @@ // TODO To reduce disruption, we use 0 instead of -1 as the tombstone // value. Enable -1 in a future release. auto *ds = dyn_cast(&sym); - if (!sym.getOutputSection() || - (ds && ds->section->repl != ds->section && !isDebugLine)) { + if (!sym.getOutputSection() || (ds && ds->folded && !isDebugLine)) { // If -z dead-reloc-in-nonalloc= is specified, respect it. const uint64_t value = tombstone ? SignExtend64(*tombstone) : (isDebugLocOrRanges ? 1 : 0); diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -2004,8 +2004,8 @@ // non-Thunk target, so we cannot fold offset + addend. if (auto *d = dyn_cast(rel.sym)) if (!d->isInPlt() && d->section) - thunkVec = &thunkedSymbolsBySectionAndAddend[{ - {d->section->repl, d->value}, keyAddend}]; + thunkVec = &thunkedSymbolsBySectionAndAddend[{{d->section, d->value}, + keyAddend}]; if (!thunkVec) thunkVec = &thunkedSymbols[{rel.sym, keyAddend}]; diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -248,8 +248,9 @@ exportDynamic(isExportDynamic(k, visibility)), inDynamicList(false), canInline(false), referenced(false), traced(false), isInIplt(false), gotInIgot(false), isPreemptible(false), used(!config->gcSections), - needsTocRestore(false), scriptDefined(false), needsCopy(false), - needsGot(false), needsPlt(false), hasDirectReloc(false) {} + folded(false), needsTocRestore(false), scriptDefined(false), + needsCopy(false), needsGot(false), needsPlt(false), + hasDirectReloc(false) {} public: // True if this symbol is in the Iplt sub-section of the Plt and the Igot @@ -269,6 +270,9 @@ // which are referenced by relocations when -r or --emit-relocs is given. uint8_t used : 1; + // True if defined relative to a section discarded by ICF. + uint8_t folded : 1; + // True if a call to this symbol needs to be followed by a restore of the // PPC64 toc pointer. uint8_t needsTocRestore : 1; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -78,7 +78,6 @@ return d.value; assert(isec != &InputSection::discarded); - isec = isec->repl; uint64_t offset = d.value; @@ -348,7 +347,7 @@ report(": unable to order absolute symbol: "); else if (d && isa(d->section)) report(": unable to order synthetic symbol: "); - else if (d && !d->section->repl->isLive()) + else if (d && !d->section->isLive()) report(": unable to order discarded symbol: "); } diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -391,7 +391,7 @@ // FDEs for garbage-collected or merged-by-ICF sections, or sections in // another partition, are dead. if (auto *d = dyn_cast(&b)) - if (d->section && d->section->partition == partition) + if (!d->folded && d->section && d->section->partition == partition) return d; return nullptr; } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -679,7 +679,6 @@ SectionBase *sec = d->section; if (!sec) return true; - sec = sec->repl; // Exclude symbols pointing to garbage-collected sections. if (isa(sec) && !sec->isLive()) @@ -1302,7 +1301,7 @@ if (auto *d = dyn_cast(&sym)) { if (auto *sec = dyn_cast_or_null(d->section)) { - int &priority = sectionOrder[cast(sec->repl)]; + int &priority = sectionOrder[cast(sec)]; priority = std::min(priority, ent.priority); } } @@ -1725,7 +1724,7 @@ if (!sec) return; - const InputSectionBase *inputSec = dyn_cast(sec->repl); + const InputSectionBase *inputSec = dyn_cast(sec); if (!inputSec || !inputSec->bytesDropped) return;