diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -1116,8 +1116,15 @@ // COMDAT member sections, and if a comdat group is discarded, some // defined symbol in a .eh_frame becomes dangling symbols. if (sec == &InputSection::discarded) { - this->symbols[i]->resolve( - Undefined{this, name, binding, stOther, type, secIdx}); + Undefined und{this, name, binding, stOther, type, secIdx}; + Symbol *sym = this->symbols[i]; + // If file is an ArchiveFile/LazyObjFile, file->symbols.empty() represents + // that the file has not been processed, i.e. this function is a result of + // lazy symbol fetch. We should demote the lazy symbol to an Undefined. + if (sym->isLazy() && sym->file->symbols.empty()) + sym->replace(und); + else + sym->resolve(und); continue; } @@ -1140,6 +1147,10 @@ void ArchiveFile::parse() { for (const Archive::Symbol &sym : file->symbols()) symtab->addSymbol(LazyArchive{*this, sym}); + + // Arbitrarily make symbols non-empty to inform a future invocation of + // ObjFile::initializeSymbols() that this archive has been processed. + symbols.push_back(nullptr); } // Returns a buffer pointing to a member file containing a given symbol. @@ -1573,6 +1584,10 @@ // Copy symbol vector so that the new InputFile doesn't have to // insert the same defined symbols to the symbol table again. file->symbols = std::move(symbols); + // symbols is in a valid but unspecified state. Make it empty and inform a + // future invocation of ObjFile::initializeSymbols() that this + // LazyObjFile has been processed. + symbols.clear(); parseFile(file); } diff --git a/lld/test/ELF/comdat-discarded-lazy.s b/lld/test/ELF/comdat-discarded-lazy.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/comdat-discarded-lazy.s @@ -0,0 +1,58 @@ +# REQUIRES: x86 +## Test that lazy symbols in a section group can be demoted to Undefined, +## so that we can report a "discarded section" error. + +# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t.o +# RUN: echo '.globl f1, foo; f1: call foo; \ +# RUN: .section .text.foo,"axG",@progbits,foo,comdat; foo:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %t1.o + +## Test the case when the symbol causing a "discarded section" is ordered +## *before* the symbol fetching the lazy object. +# RUN: echo '.globl f2, aa; f2: call aa; \ +# RUN: .section .text.foo,"axG",@progbits,foo,comdat; aa:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %taa.o +# RUN: llvm-nm -p %taa.o | FileCheck --check-prefix=AA-NM %s +# RUN: not ld.lld %t.o --start-lib %t1.o %taa.o --end-lib -o /dev/null 2>&1 | FileCheck --check-prefix=AA %s +# RUN: rm -f %taa.a && llvm-ar rc %taa.a %taa.o +# RUN: not ld.lld %t.o --start-lib %t1.o --end-lib %taa.a -o /dev/null 2>&1 | FileCheck --check-prefix=AA %s + +# AA-NM: aa +# AA-NM: f2 + +# AA: error: relocation refers to a symbol in a discarded section: aa +# AA-NEXT: >>> defined in {{.*}}aa.o +# AA-NEXT: >>> section group signature: foo +# AA-NEXT: >>> prevailing definition is in {{.*}}1.o +# AA-NEXT: >>> referenced by {{.*}}aa.o:(.text+0x1) + +## Test the case when the symbol causing a "discarded section" is ordered +## *after* the symbol fetching the lazy object. +# RUN: echo '.globl f2, zz; f2: call zz; \ +# RUN: .section .text.foo,"axG",@progbits,foo,comdat; zz:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64 - -o %tzz.o +# RUN: llvm-nm -p %tzz.o | FileCheck --check-prefix=ZZ-NM %s +# RUN: not ld.lld %t.o --start-lib %t1.o %tzz.o --end-lib -o /dev/null 2>&1 | FileCheck --check-prefix=ZZ %s +# RUN: rm -f %tzz.a && llvm-ar rc %tzz.a %tzz.o +# RUN: not ld.lld %t.o --start-lib %t1.o --end-lib %tzz.a -o /dev/null 2>&1 | FileCheck --check-prefix=ZZ %s + +# ZZ-NM: f2 +# ZZ-NM: zz + +# ZZ: error: relocation refers to a symbol in a discarded section: zz +# ZZ-NEXT: >>> defined in {{.*}}zz.o +# ZZ-NEXT: >>> section group signature: foo +# ZZ-NEXT: >>> prevailing definition is in {{.*}}1.o +# ZZ-NEXT: >>> referenced by {{.*}}zz.o:(.text+0x1) + +## Don't error if the symbol which would cause "discarded section" +## was inserted before %tzz.o +# RUN: echo '.globl zz; zz:' | llvm-mc -filetype=obj -triple=x86_64 - -o %tdef.o +# RUN: ld.lld %t.o --start-lib %t1.o %tdef.o %tzz.o --end-lib -o /dev/null +# RUN: rm -f %tdef.a && llvm-ar rc %tdef.a %tdef.o +# RUN: ld.lld %t.o --start-lib %t1.o %tdef.a %tzz.o --end-lib -o /dev/null + +.globl _start +_start: + call f1 + call f2 diff --git a/lld/test/ELF/i386-linkonce.s b/lld/test/ELF/i386-linkonce.s --- a/lld/test/ELF/i386-linkonce.s +++ b/lld/test/ELF/i386-linkonce.s @@ -2,7 +2,9 @@ // RUN: llvm-mc -filetype=obj -triple=i386-linux-gnu %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=i386-linux-gnu %p/Inputs/i386-linkonce.s -o %t2.o // RUN: llvm-ar rcs %t2.a %t2.o -// RUN: ld.lld %t.o %t2.a -o %t +// RUN: not ld.lld %t.o %t2.a -o /dev/null 2>&1 | FileCheck %s + +// CHECK: error: relocation refers to a symbol in a discarded section: __i686.get_pc_thunk.bx .globl _start _start: diff --git a/lld/test/ELF/start-lib-comdat.s b/lld/test/ELF/start-lib-comdat.s --- a/lld/test/ELF/start-lib-comdat.s +++ b/lld/test/ELF/start-lib-comdat.s @@ -6,7 +6,7 @@ // RUN: ld.lld -shared -o %t3 %t1.o --start-lib %t2.o --end-lib // RUN: llvm-readobj --symbols %t3 | FileCheck %s // RUN: ld.lld -shared -o %t3 --start-lib %t2.o --end-lib %t1.o -// RUN: llvm-readobj --symbols %t3 | FileCheck %s +// RUN: llvm-readobj --symbols %t3 | FileCheck /dev/null --implicit-check-not='Name: zed' // CHECK: Name: zed // CHECK-NEXT: Value: