Handle strong undefined symbols fetching members after a weak undefined.

This is a case that requires --start-group --end-group with regular ELF
linkers. Fortunately it is still possible to handle it with lazy symbols without
taking a second look at archives.

Thanks to Michael Spencer for the bug report.

llvm-svn: 249406
This commit is contained in:
Rafael Espindola 2015-10-06 14:33:58 +00:00
parent b810314825
commit 8614c566e2
8 changed files with 70 additions and 42 deletions

View File

@ -49,8 +49,7 @@ void InputSection<ELFT>::relocate(
continue; continue;
SymVA = getLocalSymVA(Sym, File); SymVA = getLocalSymVA(Sym, File);
} else { } else {
const auto &Body = SymbolBody &Body = *File.getSymbolBody(SymIndex);
*cast<ELFSymbolBody<ELFT>>(File.getSymbolBody(SymIndex));
SymVA = getSymVA<ELFT>(Body, BssSec); SymVA = getSymVA<ELFT>(Body, BssSec);
if (Target->relocNeedsPlt(Type, Body)) { if (Target->relocNeedsPlt(Type, Body)) {
SymVA = PltSec.getEntryAddr(Body); SymVA = PltSec.getEntryAddr(Body);

View File

@ -349,13 +349,14 @@ void OutputSection<ELFT>::addSection(InputSection<ELFT> *C) {
template <class ELFT> template <class ELFT>
typename ELFFile<ELFT>::uintX_t typename ELFFile<ELFT>::uintX_t
lld::elf2::getSymVA(const ELFSymbolBody<ELFT> &S, lld::elf2::getSymVA(const SymbolBody &S, const OutputSection<ELFT> &BssSec) {
const OutputSection<ELFT> &BssSec) {
switch (S.kind()) { switch (S.kind()) {
case SymbolBody::DefinedSyntheticKind: case SymbolBody::DefinedSyntheticKind: {
return cast<DefinedSynthetic<ELFT>>(S).Section.getVA() + S.Sym.st_value; auto &D = cast<DefinedSynthetic<ELFT>>(S);
return D.Section.getVA() + D.Sym.st_value;
}
case SymbolBody::DefinedAbsoluteKind: case SymbolBody::DefinedAbsoluteKind:
return S.Sym.st_value; return cast<DefinedAbsolute<ELFT>>(S).Sym.st_value;
case SymbolBody::DefinedRegularKind: { case SymbolBody::DefinedRegularKind: {
const auto &DR = cast<DefinedRegular<ELFT>>(S); const auto &DR = cast<DefinedRegular<ELFT>>(S);
const InputSection<ELFT> *SC = &DR.Section; const InputSection<ELFT> *SC = &DR.Section;
@ -368,9 +369,9 @@ lld::elf2::getSymVA(const ELFSymbolBody<ELFT> &S,
case SymbolBody::UndefinedKind: case SymbolBody::UndefinedKind:
return 0; return 0;
case SymbolBody::LazyKind: case SymbolBody::LazyKind:
break; assert(S.isUsedInRegularObj() && "Lazy symbol reached writer");
return 0;
} }
llvm_unreachable("Lazy symbol reached writer");
} }
template <class ELFT> template <class ELFT>
@ -409,8 +410,6 @@ void StringTableSection<Is64Bits>::writeTo(uint8_t *Buf) {
} }
template <class ELFT> bool lld::elf2::includeInSymtab(const SymbolBody &B) { template <class ELFT> bool lld::elf2::includeInSymtab(const SymbolBody &B) {
if (B.isLazy())
return false;
if (!B.isUsedInRegularObj()) if (!B.isUsedInRegularObj())
return false; return false;
@ -521,21 +520,20 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *&Buf) {
if (StrTabSec.isDynamic() && !includeInDynamicSymtab(*Body)) if (StrTabSec.isDynamic() && !includeInDynamicSymtab(*Body))
continue; continue;
const auto &EBody = *cast<ELFSymbolBody<ELFT>>(Body);
const Elf_Sym &InputSym = EBody.Sym;
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf); auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
Buf += sizeof(*ESym); Buf += sizeof(*ESym);
ESym->st_name = StrTabSec.getFileOff(Name); ESym->st_name = StrTabSec.getFileOff(Name);
const OutputSection<ELFT> *Out = nullptr; const OutputSection<ELFT> *Out = nullptr;
const InputSection<ELFT> *Section = nullptr; const InputSection<ELFT> *Section = nullptr;
switch (EBody.kind()) { switch (Body->kind()) {
case SymbolBody::DefinedSyntheticKind: case SymbolBody::DefinedSyntheticKind:
Out = &cast<DefinedSynthetic<ELFT>>(Body)->Section; Out = &cast<DefinedSynthetic<ELFT>>(Body)->Section;
break; break;
case SymbolBody::DefinedRegularKind: case SymbolBody::DefinedRegularKind:
Section = &cast<DefinedRegular<ELFT>>(EBody).Section; Section = &cast<DefinedRegular<ELFT>>(Body)->Section;
break; break;
case SymbolBody::DefinedCommonKind: case SymbolBody::DefinedCommonKind:
Out = &BssSec; Out = &BssSec;
@ -543,25 +541,33 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *&Buf) {
case SymbolBody::UndefinedKind: case SymbolBody::UndefinedKind:
case SymbolBody::DefinedAbsoluteKind: case SymbolBody::DefinedAbsoluteKind:
case SymbolBody::SharedKind: case SymbolBody::SharedKind:
break;
case SymbolBody::LazyKind: case SymbolBody::LazyKind:
llvm_unreachable("Lazy symbol got to output symbol table!"); break;
} }
unsigned char Binding = InputSym.getBinding(); unsigned char Binding = Body->isWeak() ? STB_WEAK : STB_GLOBAL;
unsigned char Visibility = EBody.getMostConstrainingVisibility(); unsigned char Type = STT_NOTYPE;
uintX_t Size = 0;
if (const auto *EBody = dyn_cast<ELFSymbolBody<ELFT>>(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) if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
Binding = STB_LOCAL; Binding = STB_LOCAL;
ESym->setBindingAndType(Binding, InputSym.getType()); ESym->setBindingAndType(Binding, Type);
ESym->st_size = InputSym.st_size; ESym->st_size = Size;
ESym->setVisibility(Visibility); ESym->setVisibility(Visibility);
ESym->st_value = getSymVA(EBody, BssSec); ESym->st_value = getSymVA(*Body, BssSec);
if (Section) if (Section)
Out = Section->getOutputSection(); Out = Section->getOutputSection();
if (InputSym.isAbsolute()) if (isa<DefinedAbsolute<ELFT>>(Body))
ESym->st_shndx = SHN_ABS; ESym->st_shndx = SHN_ABS;
else if (Out) else if (Out)
ESym->st_shndx = Out->getSectionIndex(); ESym->st_shndx = Out->getSectionIndex();
@ -629,17 +635,14 @@ template class SymbolTableSection<ELF32BE>;
template class SymbolTableSection<ELF64LE>; template class SymbolTableSection<ELF64LE>;
template class SymbolTableSection<ELF64BE>; template class SymbolTableSection<ELF64BE>;
template ELFFile<ELF32LE>::uintX_t template ELFFile<ELF32LE>::uintX_t getSymVA(const SymbolBody &,
getSymVA(const ELFSymbolBody<ELF32LE> &, const OutputSection<ELF32LE> &); const OutputSection<ELF32LE> &);
template ELFFile<ELF32BE>::uintX_t getSymVA(const SymbolBody &,
template ELFFile<ELF32BE>::uintX_t const OutputSection<ELF32BE> &);
getSymVA(const ELFSymbolBody<ELF32BE> &, const OutputSection<ELF32BE> &); template ELFFile<ELF64LE>::uintX_t getSymVA(const SymbolBody &,
const OutputSection<ELF64LE> &);
template ELFFile<ELF64LE>::uintX_t template ELFFile<ELF64BE>::uintX_t getSymVA(const SymbolBody &,
getSymVA(const ELFSymbolBody<ELF64LE> &, const OutputSection<ELF64LE> &); const OutputSection<ELF64BE> &);
template ELFFile<ELF64BE>::uintX_t
getSymVA(const ELFSymbolBody<ELF64BE> &, const OutputSection<ELF64BE> &);
template ELFFile<ELF32LE>::uintX_t template ELFFile<ELF32LE>::uintX_t
getLocalSymVA(const ELFFile<ELF32LE>::Elf_Sym *, const ObjectFile<ELF32LE> &); getLocalSymVA(const ELFFile<ELF32LE>::Elf_Sym *, const ObjectFile<ELF32LE> &);

View File

@ -34,7 +34,7 @@ template <class ELFT> class ELFSymbolBody;
template <class ELFT> template <class ELFT>
typename llvm::object::ELFFile<ELFT>::uintX_t typename llvm::object::ELFFile<ELFT>::uintX_t
getSymVA(const ELFSymbolBody<ELFT> &S, const OutputSection<ELFT> &BssSec); getSymVA(const SymbolBody &S, const OutputSection<ELFT> &BssSec);
template <class ELFT> template <class ELFT>
typename llvm::object::ELFFile<ELFT>::uintX_t typename llvm::object::ELFFile<ELFT>::uintX_t

View File

@ -256,10 +256,23 @@ void SymbolTable::addLazy(Lazy *New) {
if (Sym->Body == New) if (Sym->Body == New)
return; return;
SymbolBody *Existing = Sym->Body; SymbolBody *Existing = Sym->Body;
if (Existing->isDefined() || Existing->isLazy() || Existing->isWeak()) if (Existing->isDefined() || Existing->isLazy())
return; return;
Sym->Body = New; Sym->Body = New;
assert(Existing->isUndefined() && "Unexpected symbol kind."); 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); addMemberFile(New);
} }

View File

@ -103,7 +103,7 @@ protected:
} }
const unsigned SymbolKind : 8; const unsigned SymbolKind : 8;
const unsigned IsWeak : 1; unsigned IsWeak : 1;
unsigned MostConstrainingVisibility : 2; unsigned MostConstrainingVisibility : 2;
unsigned IsUsedInRegularObj : 1; unsigned IsUsedInRegularObj : 1;
unsigned IsUsedInDynamicReloc : 1; unsigned IsUsedInDynamicReloc : 1;
@ -282,6 +282,9 @@ public:
// was already returned. // was already returned.
std::unique_ptr<InputFile> getMember(); std::unique_ptr<InputFile> getMember();
void setWeak() { IsWeak = true; }
void setUsedInRegularObj() { IsUsedInRegularObj = true; }
private: private:
ArchiveFile *File; ArchiveFile *File;
const llvm::object::Archive::Symbol Sym; const llvm::object::Archive::Symbol Sym;

View File

@ -0,0 +1,2 @@
.global bar
bar:

View File

@ -0,0 +1 @@
.quad bar

View File

@ -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 -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/archive.s -o %t2
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t3 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t3
# RUN: llvm-ar rcs %tar %t2 %t3 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive3.s -o %t4
# RUN: lld -flavor gnu2 %t %tar -o %tout # 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 # RUN: llvm-nm %tout | FileCheck %s
# REQUIRES: x86 # REQUIRES: x86
@ -13,6 +15,11 @@
.weak foo .weak foo
.quad foo .quad foo
# CHECK: T _start .weak bar
# CHECK: T end .quad bar
# CHECK: w foo
# CHECK: T _start
# CHECK-NEXT: T bar
# CHECK-NEXT: T end
# CHECK-NEXT: w foo