diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -282,6 +282,7 @@ ExprValue getSymbolValue(StringRef name, const Twine &loc); void addOrphanSections(); + void diagnoseOrphanHandling() const; void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); @@ -321,6 +322,9 @@ // to be reordered. std::vector insertCommands; + // Sections that will be warned/errored by --orphan-handling. + std::vector orphanSections; + // Sections whose addresses are not equal to their addrExpr values. std::vector> changedSectionAddresses; diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -681,13 +681,9 @@ std::function 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); + StringRef name = getOutputSectionName(s); if (OutputSection *sec = findByName(sectionCommands, name)) { sec->recordSection(s); } else { @@ -732,6 +728,16 @@ sectionCommands.insert(sectionCommands.begin(), v.begin(), v.end()); } +void LinkerScript::diagnoseOrphanHandling() const { + for (const InputSectionBase *sec : orphanSections) { + 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; diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -1678,12 +1678,15 @@ if (!os || ss->isNeeded()) continue; - // If we reach here, then SS is an unused synthetic section and we want to - // remove it from corresponding input section description of output section. + // If we reach here, then ss is an unused synthetic section and we want to + // remove it from the corresponding input section description, and + // orphanSections. for (BaseCommand *b : os->sectionCommands) if (auto *isd = dyn_cast(b)) llvm::erase_if(isd->sections, [=](InputSection *isec) { return isec == ss; }); + llvm::erase_if(script->orphanSections, + [=](const InputSectionBase *isec) { return isec == ss; }); } } @@ -1830,6 +1833,7 @@ in.mipsGot->build(); removeUnusedSyntheticSections(); + script->diagnoseOrphanHandling(); sortSections(); diff --git a/lld/test/ELF/linkerscript/orphan-report.s b/lld/test/ELF/linkerscript/orphan-report.s --- a/lld/test/ELF/linkerscript/orphan-report.s +++ b/lld/test/ELF/linkerscript/orphan-report.s @@ -12,37 +12,33 @@ # RUN: %t.o 2>&1 -verbose -error-limit=0 | FileCheck %s --check-prefix=DEFAULT ## Check --orphan-handling=error reports errors about orphans. -# RUN: not ld.lld -shared --orphan-handling=error -o /dev/null --script %t.script \ -# RUN: %t.o 2>&1 -verbose -error-limit=0 | FileCheck %s --check-prefix=REPORT -# REPORT: {{.*}}.o:(.text) is being placed in '.text' -# REPORT-NEXT: {{.*}}.o:(.text.2) is being placed in '.text' -# REPORT-NEXT: :(.comment) is being placed in '.comment' -# REPORT-NEXT: :(.bss) is being placed in '.bss' -# REPORT-NEXT: :(.bss.rel.ro) is being placed in '.bss.rel.ro' -# REPORT-NEXT: :(.dynsym) is being placed in '.dynsym' -# REPORT-NEXT: :(.gnu.version) is being placed in '.gnu.version' -# REPORT-NEXT: :(.gnu.version_r) is being placed in '.gnu.version_r' -# REPORT-NEXT: :(.gnu.hash) is being placed in '.gnu.hash' -# REPORT-NEXT: :(.hash) is being placed in '.hash' -# REPORT-NEXT: :(.dynamic) is being placed in '.dynamic' -# REPORT-NEXT: :(.dynstr) is being placed in '.dynstr' -# REPORT-NEXT: :(.rela.dyn) is being placed in '.rela.dyn' -# REPORT-NEXT: :(.eh_frame) is being placed in '.eh_frame' -# REPORT-NEXT: :(.got) is being placed in '.got' -# REPORT-NEXT: :(.got.plt) is being placed in '.got.plt' -# REPORT-NEXT: :(.got.plt) is being placed in '.got.plt' -# REPORT-NEXT: :(.rela.plt) is being placed in '.rela.plt' -# REPORT-NEXT: :(.rela.dyn) is being placed in '.rela.dyn' -# REPORT-NEXT: :(.plt) is being placed in '.plt' -# REPORT-NEXT: :(.iplt) is being placed in '.iplt' -# REPORT-NEXT: :(.symtab) is being placed in '.symtab' -# REPORT-NEXT: :(.symtab_shndx) is being placed in '.symtab_shndx' -# REPORT-NEXT: :(.shstrtab) is being placed in '.shstrtab' -# REPORT-NEXT: :(.strtab) is being placed in '.strtab' +# RUN: not ld.lld --orphan-handling=error -o /dev/null -T %t.script \ +# RUN: %t.o 2>&1 | FileCheck %s --check-prefixes=COMMON,SYMTAB + +## --strip-all discards .strtab and .symtab sections. Don't error about them. +# RUN: not ld.lld --orphan-handling=error --strip-all -o /dev/null -T %t.script \ +# RUN: %t.o 2>&1 | FileCheck %s --check-prefix=COMMON + +## -shared enables some .dynsym related sections. +# RUN: not ld.lld -shared --orphan-handling=error -o /dev/null -T %t.script \ +# RUN: %t.o 2>&1 | FileCheck %s --check-prefixes=COMMON,DYNSYM,SYMTAB + +# COMMON: {{.*}}.o:(.text) is being placed in '.text' +# COMMON-NEXT: {{.*}}.o:(.text.2) is being placed in '.text' +# COMMON-NEXT: :(.comment) is being placed in '.comment' +# DYNSYM-NEXT: :(.dynsym) is being placed in '.dynsym' +# DYNSYM-NEXT: :(.gnu.hash) is being placed in '.gnu.hash' +# DYNSYM-NEXT: :(.hash) is being placed in '.hash' +# DYNSYM-NEXT: :(.dynamic) is being placed in '.dynamic' +# DYNSYM-NEXT: :(.dynstr) is being placed in '.dynstr' +# SYMTAB-NEXT: :(.symtab) is being placed in '.symtab' +# COMMON-NEXT: :(.shstrtab) is being placed in '.shstrtab' +# SYMTAB-NEXT: :(.strtab) is being placed in '.strtab' +# COMMON-NOT: ## Check --orphan-handling=warn reports warnings about orphans. -# RUN: ld.lld -shared --orphan-handling=warn -o %t.out --script %t.script \ -# RUN: %t.o 2>&1 -verbose | FileCheck %s --check-prefix=REPORT +# RUN: ld.lld --orphan-handling=warn -o /dev/null -T %t.script \ +# RUN: %t.o 2>&1 | FileCheck %s --check-prefixes=COMMON,SYMTAB # RUN: not ld.lld --orphan-handling=foo -o /dev/null --script %t.script %t.o 2>&1 \ # RUN: | FileCheck %s --check-prefix=UNKNOWN