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:
parent
b810314825
commit
8614c566e2
|
@ -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);
|
||||||
|
|
|
@ -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> &);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
.global bar
|
||||||
|
bar:
|
|
@ -0,0 +1 @@
|
||||||
|
.quad bar
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue