diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 3f7ced0c7462..cdcbe879f288 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -49,8 +49,7 @@ void InputSection::relocate( continue; SymVA = getLocalSymVA(Sym, File); } else { - const auto &Body = - *cast>(File.getSymbolBody(SymIndex)); + SymbolBody &Body = *File.getSymbolBody(SymIndex); SymVA = getSymVA(Body, BssSec); if (Target->relocNeedsPlt(Type, Body)) { SymVA = PltSec.getEntryAddr(Body); diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp index 5335cc5786dc..9bcfaa6d02db 100644 --- a/lld/ELF/OutputSections.cpp +++ b/lld/ELF/OutputSections.cpp @@ -349,13 +349,14 @@ void OutputSection::addSection(InputSection *C) { template typename ELFFile::uintX_t -lld::elf2::getSymVA(const ELFSymbolBody &S, - const OutputSection &BssSec) { +lld::elf2::getSymVA(const SymbolBody &S, const OutputSection &BssSec) { switch (S.kind()) { - case SymbolBody::DefinedSyntheticKind: - return cast>(S).Section.getVA() + S.Sym.st_value; + case SymbolBody::DefinedSyntheticKind: { + auto &D = cast>(S); + return D.Section.getVA() + D.Sym.st_value; + } case SymbolBody::DefinedAbsoluteKind: - return S.Sym.st_value; + return cast>(S).Sym.st_value; case SymbolBody::DefinedRegularKind: { const auto &DR = cast>(S); const InputSection *SC = &DR.Section; @@ -368,9 +369,9 @@ lld::elf2::getSymVA(const ELFSymbolBody &S, case SymbolBody::UndefinedKind: return 0; case SymbolBody::LazyKind: - break; + assert(S.isUsedInRegularObj() && "Lazy symbol reached writer"); + return 0; } - llvm_unreachable("Lazy symbol reached writer"); } template @@ -409,8 +410,6 @@ void StringTableSection::writeTo(uint8_t *Buf) { } template bool lld::elf2::includeInSymtab(const SymbolBody &B) { - if (B.isLazy()) - return false; if (!B.isUsedInRegularObj()) return false; @@ -521,21 +520,20 @@ void SymbolTableSection::writeGlobalSymbols(uint8_t *&Buf) { if (StrTabSec.isDynamic() && !includeInDynamicSymtab(*Body)) continue; - const auto &EBody = *cast>(Body); - const Elf_Sym &InputSym = EBody.Sym; auto *ESym = reinterpret_cast(Buf); Buf += sizeof(*ESym); + ESym->st_name = StrTabSec.getFileOff(Name); const OutputSection *Out = nullptr; const InputSection *Section = nullptr; - switch (EBody.kind()) { + switch (Body->kind()) { case SymbolBody::DefinedSyntheticKind: Out = &cast>(Body)->Section; break; case SymbolBody::DefinedRegularKind: - Section = &cast>(EBody).Section; + Section = &cast>(Body)->Section; break; case SymbolBody::DefinedCommonKind: Out = &BssSec; @@ -543,25 +541,33 @@ void SymbolTableSection::writeGlobalSymbols(uint8_t *&Buf) { case SymbolBody::UndefinedKind: case SymbolBody::DefinedAbsoluteKind: case SymbolBody::SharedKind: - break; case SymbolBody::LazyKind: - llvm_unreachable("Lazy symbol got to output symbol table!"); + break; } - unsigned char Binding = InputSym.getBinding(); - unsigned char Visibility = EBody.getMostConstrainingVisibility(); + unsigned char Binding = Body->isWeak() ? STB_WEAK : STB_GLOBAL; + unsigned char Type = STT_NOTYPE; + uintX_t Size = 0; + if (const auto *EBody = dyn_cast>(Body)) { + const Elf_Sym &InputSym = EBody->Sym; + Binding = InputSym.getBinding(); + Type = InputSym.getType(); + Size = InputSym.st_size; + } + + unsigned char Visibility = Body->getMostConstrainingVisibility(); if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED) Binding = STB_LOCAL; - ESym->setBindingAndType(Binding, InputSym.getType()); - ESym->st_size = InputSym.st_size; + ESym->setBindingAndType(Binding, Type); + ESym->st_size = Size; ESym->setVisibility(Visibility); - ESym->st_value = getSymVA(EBody, BssSec); + ESym->st_value = getSymVA(*Body, BssSec); if (Section) Out = Section->getOutputSection(); - if (InputSym.isAbsolute()) + if (isa>(Body)) ESym->st_shndx = SHN_ABS; else if (Out) ESym->st_shndx = Out->getSectionIndex(); @@ -629,17 +635,14 @@ template class SymbolTableSection; template class SymbolTableSection; template class SymbolTableSection; -template ELFFile::uintX_t -getSymVA(const ELFSymbolBody &, const OutputSection &); - -template ELFFile::uintX_t -getSymVA(const ELFSymbolBody &, const OutputSection &); - -template ELFFile::uintX_t -getSymVA(const ELFSymbolBody &, const OutputSection &); - -template ELFFile::uintX_t -getSymVA(const ELFSymbolBody &, const OutputSection &); +template ELFFile::uintX_t getSymVA(const SymbolBody &, + const OutputSection &); +template ELFFile::uintX_t getSymVA(const SymbolBody &, + const OutputSection &); +template ELFFile::uintX_t getSymVA(const SymbolBody &, + const OutputSection &); +template ELFFile::uintX_t getSymVA(const SymbolBody &, + const OutputSection &); template ELFFile::uintX_t getLocalSymVA(const ELFFile::Elf_Sym *, const ObjectFile &); diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h index 96de43700a73..b0cf435ded18 100644 --- a/lld/ELF/OutputSections.h +++ b/lld/ELF/OutputSections.h @@ -34,7 +34,7 @@ template class ELFSymbolBody; template typename llvm::object::ELFFile::uintX_t -getSymVA(const ELFSymbolBody &S, const OutputSection &BssSec); +getSymVA(const SymbolBody &S, const OutputSection &BssSec); template typename llvm::object::ELFFile::uintX_t diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index d077ce690659..6177e91d4389 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -256,10 +256,23 @@ void SymbolTable::addLazy(Lazy *New) { if (Sym->Body == New) return; SymbolBody *Existing = Sym->Body; - if (Existing->isDefined() || Existing->isLazy() || Existing->isWeak()) + if (Existing->isDefined() || Existing->isLazy()) return; Sym->Body = New; assert(Existing->isUndefined() && "Unexpected symbol kind."); + + // Weak undefined symbols should not fetch members from archives. + // If we were to keep old symbol we would not know that an archive member was + // available if a strong undefined symbol shows up afterwards in the link. + // If a strong undefined symbol never shows up, this lazy symbol will + // get to the end of the link and must be treated as the weak undefined one. + // We set UsedInRegularObj in a similar way to what is done with shared + // symbols and mark it as weak to reduce how many special cases are needed. + if (Existing->isWeak()) { + New->setUsedInRegularObj(); + New->setWeak(); + return; + } addMemberFile(New); } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h index 39e3d31b4aef..b47f365dc398 100644 --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -103,7 +103,7 @@ protected: } const unsigned SymbolKind : 8; - const unsigned IsWeak : 1; + unsigned IsWeak : 1; unsigned MostConstrainingVisibility : 2; unsigned IsUsedInRegularObj : 1; unsigned IsUsedInDynamicReloc : 1; @@ -282,6 +282,9 @@ public: // was already returned. std::unique_ptr getMember(); + void setWeak() { IsWeak = true; } + void setUsedInRegularObj() { IsUsedInRegularObj = true; } + private: ArchiveFile *File; const llvm::object::Archive::Symbol Sym; diff --git a/lld/test/elf2/Inputs/archive3.s b/lld/test/elf2/Inputs/archive3.s new file mode 100644 index 000000000000..3e11d4314104 --- /dev/null +++ b/lld/test/elf2/Inputs/archive3.s @@ -0,0 +1,2 @@ +.global bar +bar: diff --git a/lld/test/elf2/Inputs/archive4.s b/lld/test/elf2/Inputs/archive4.s new file mode 100644 index 000000000000..e842874f187c --- /dev/null +++ b/lld/test/elf2/Inputs/archive4.s @@ -0,0 +1 @@ +.quad bar diff --git a/lld/test/elf2/archive.s b/lld/test/elf2/archive.s index e0e4c1ee5543..f9cd17bd57b9 100644 --- a/lld/test/elf2/archive.s +++ b/lld/test/elf2/archive.s @@ -1,8 +1,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive.s -o %t2 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t3 -# RUN: llvm-ar rcs %tar %t2 %t3 -# RUN: lld -flavor gnu2 %t %tar -o %tout +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive3.s -o %t4 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive4.s -o %t5 +# RUN: llvm-ar rcs %tar %t2 %t3 %t4 +# RUN: lld -flavor gnu2 %t %tar %t5 -o %tout # RUN: llvm-nm %tout | FileCheck %s # REQUIRES: x86 @@ -13,6 +15,11 @@ .weak foo .quad foo -# CHECK: T _start -# CHECK: T end -# CHECK: w foo +.weak bar +.quad bar + + +# CHECK: T _start +# CHECK-NEXT: T bar +# CHECK-NEXT: T end +# CHECK-NEXT: w foo