Compute value of local symbol with getVA.

llvm-svn: 263225
This commit is contained in:
Rafael Espindola 2016-03-11 12:19:05 +00:00
parent ccb8b4d4fe
commit 87d9f10733
4 changed files with 80 additions and 93 deletions

View File

@ -171,48 +171,6 @@ InputSectionBase<ELFT>::findMipsPairedReloc(uint8_t *Buf, uint32_t SymIndex,
return nullptr;
}
// Returns a VA which a relocatin RI refers to. Used only for local symbols.
// For non-local symbols, use SymbolBody::getVA instead.
template <class ELFT, bool IsRela>
static typename ELFFile<ELFT>::uintX_t
getLocalRelTarget(const ObjectFile<ELFT> &File,
const Elf_Rel_Impl<ELFT, IsRela> &RI,
typename ELFFile<ELFT>::uintX_t Addend) {
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
// PPC64 has a special relocation representing the TOC base pointer
// that does not have a corresponding symbol.
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC)
return getPPC64TocBase() + Addend;
const Elf_Sym *Sym =
File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
if (!Sym)
fatal("Unsupported relocation without symbol");
InputSectionBase<ELFT> *Section = File.getSection(*Sym);
if (Sym->getType() == STT_TLS)
return (Section->OutSec->getVA() + Section->getOffset(*Sym) + Addend) -
Out<ELFT>::TlsPhdr->p_vaddr;
// According to the ELF spec reference to a local symbol from outside
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
if (Section == InputSection<ELFT>::Discarded || !Section->Live)
return Addend;
uintX_t Offset = Sym->st_value;
if (Sym->getType() == STT_SECTION) {
Offset += Addend;
Addend = 0;
}
return Section->OutSec->getVA() + Section->getOffset(Offset) + Addend;
}
template <class ELFT>
template <bool isRela>
void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
@ -244,7 +202,7 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
if (Target->canRelaxTls(Type, &Body)) {
uintX_t SymVA;
if (Body.isLocal())
SymVA = getLocalRelTarget(*File, RI, 0);
SymVA = Body.getVA<ELFT>();
else if (Target->needsGot(Type, Body))
SymVA = Body.getGotVA<ELFT>();
else
@ -256,11 +214,19 @@ void InputSectionBase<ELFT>::relocate(uint8_t *Buf, uint8_t *BufEnd,
continue;
}
// Handle relocations for local symbols -- they never get
// resolved so we don't allocate a SymbolBody.
uintX_t A = getAddend<ELFT>(RI);
// PPC64 has a special relocation representing the TOC base pointer
// that does not have a corresponding symbol.
if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
uintX_t SymVA = getPPC64TocBase() + A;
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc, SymVA, 0);
continue;
}
// Handle relocations for local symbols.
if (Body.isLocal()) {
uintX_t SymVA = getLocalRelTarget(*File, RI, A);
uintX_t SymVA = Body.getVA<ELFT>(A);
uint8_t *PairedLoc = nullptr;
if (Config->EMachine == EM_MIPS) {
if (Type == R_MIPS_GPREL16 || Type == R_MIPS_GPREL32)

View File

@ -266,21 +266,12 @@ template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
SymbolBody *Sym = Rel.Sym;
if (IsRela) {
uintX_t VA = 0;
uintX_t Addend = Rel.Addend;
if (Rel.UseSymVA) {
if (auto *L = dyn_cast<LocalSymbol<ELFT>>(Sym)) {
uintX_t Pos = L->Sym.st_value;
if (L->Sym.getType() == STT_SECTION) {
Pos += Addend;
Addend = 0;
}
VA = L->Section->OutSec->getVA() + L->Section->getOffset(Pos);
} else {
VA = Sym->getVA<ELFT>();
}
}
reinterpret_cast<Elf_Rela *>(P)->r_addend = Addend + VA;
uintX_t VA;
if (Rel.UseSymVA)
VA = Sym->getVA<ELFT>(Rel.Addend);
else
VA = Rel.Addend;
reinterpret_cast<Elf_Rela *>(P)->r_addend = VA;
}
P->r_offset = Rel.getOffset();

View File

@ -29,51 +29,80 @@ using namespace lld;
using namespace lld::elf;
template <class ELFT>
typename ELFFile<ELFT>::uintX_t SymbolBody::getVA() const {
switch (kind()) {
case DefinedSyntheticKind: {
auto *D = cast<DefinedSynthetic<ELFT>>(this);
return D->Section.getVA() + D->Value;
static typename ELFFile<ELFT>::uintX_t
getSymVA(const SymbolBody &Body, typename ELFFile<ELFT>::uintX_t &Addend) {
typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename ELFFile<ELFT>::uintX_t uintX_t;
switch (Body.kind()) {
case SymbolBody::DefinedSyntheticKind: {
auto &D = cast<DefinedSynthetic<ELFT>>(Body);
return D.Section.getVA() + D.Value;
}
case DefinedRegularKind: {
auto *D = cast<DefinedRegular<ELFT>>(this);
InputSectionBase<ELFT> *SC = D->Section;
case SymbolBody::DefinedRegularKind: {
auto &D = cast<DefinedRegular<ELFT>>(Body);
InputSectionBase<ELFT> *SC = D.Section;
// This is an absolute symbol.
if (!SC)
return D->Sym.st_value;
return D.Sym.st_value;
assert(SC->Live);
if (D->Sym.getType() == STT_TLS)
return SC->OutSec->getVA() + SC->getOffset(D->Sym) -
if (D.Sym.getType() == STT_TLS)
return SC->OutSec->getVA() + SC->getOffset(D.Sym) -
Out<ELFT>::TlsPhdr->p_vaddr;
return SC->OutSec->getVA() + SC->getOffset(D->Sym);
return SC->OutSec->getVA() + SC->getOffset(D.Sym);
}
case DefinedCommonKind:
return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(this)->OffsetInBss;
case SharedKind: {
auto *SS = cast<SharedSymbol<ELFT>>(this);
if (!SS->NeedsCopyOrPltAddr)
case SymbolBody::DefinedCommonKind:
return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(Body).OffsetInBss;
case SymbolBody::SharedKind: {
auto &SS = cast<SharedSymbol<ELFT>>(Body);
if (!SS.NeedsCopyOrPltAddr)
return 0;
if (SS->IsFunc)
return getPltVA<ELFT>();
if (SS.IsFunc)
return Body.getPltVA<ELFT>();
else
return Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
}
case UndefinedElfKind:
case UndefinedKind:
case SymbolBody::UndefinedElfKind:
case SymbolBody::UndefinedKind:
return 0;
case LazyKind:
assert(isUsedInRegularObj() && "Lazy symbol reached writer");
case SymbolBody::LazyKind:
assert(Body.isUsedInRegularObj() && "Lazy symbol reached writer");
return 0;
case DefinedBitcodeKind:
case SymbolBody::DefinedBitcodeKind:
llvm_unreachable("Should have been replaced");
case DefinedLocalKind:
llvm_unreachable("Should not be used");
case SymbolBody::DefinedLocalKind: {
auto &L = cast<LocalSymbol<ELFT>>(Body);
InputSectionBase<ELFT> *SC = L.Section;
// According to the ELF spec reference to a local symbol from outside the
// group are not allowed. Unfortunately .eh_frame breaks that rule and must
// be treated specially. For now we just replace the symbol with 0.
if (SC == InputSection<ELFT>::Discarded || !SC->Live)
return 0;
const Elf_Sym &Sym = L.Sym;
uintX_t Offset = Sym.st_value;
if (Sym.getType() == STT_TLS)
return (SC->OutSec->getVA() + SC->getOffset(Sym) + Addend) -
Out<ELFT>::TlsPhdr->p_vaddr;
if (Sym.getType() == STT_SECTION) {
Offset += Addend;
Addend = 0;
}
return SC->OutSec->getVA() + SC->getOffset(Offset);
}
}
llvm_unreachable("Invalid symbol kind");
}
template <class ELFT>
typename ELFFile<ELFT>::uintX_t
SymbolBody::getVA(typename ELFFile<ELFT>::uintX_t Addend) const {
return getSymVA<ELFT>(*this, Addend) + Addend;
}
template <class ELFT>
typename ELFFile<ELFT>::uintX_t SymbolBody::getGotVA() const {
return Out<ELFT>::Got->getVA() +
@ -231,10 +260,10 @@ std::string elf::demangle(StringRef Name) {
#endif
}
template uint32_t SymbolBody::template getVA<ELF32LE>() const;
template uint32_t SymbolBody::template getVA<ELF32BE>() const;
template uint64_t SymbolBody::template getVA<ELF64LE>() const;
template uint64_t SymbolBody::template getVA<ELF64BE>() const;
template uint32_t SymbolBody::template getVA<ELF32LE>(uint32_t) const;
template uint32_t SymbolBody::template getVA<ELF32BE>(uint32_t) const;
template uint64_t SymbolBody::template getVA<ELF64LE>(uint64_t) const;
template uint64_t SymbolBody::template getVA<ELF64BE>(uint64_t) const;
template uint32_t SymbolBody::template getGotVA<ELF32LE>() const;
template uint32_t SymbolBody::template getGotVA<ELF32BE>() const;

View File

@ -98,7 +98,8 @@ public:
bool isInPlt() const { return PltIndex != -1U; }
template <class ELFT>
typename llvm::object::ELFFile<ELFT>::uintX_t getVA() const;
typename llvm::object::ELFFile<ELFT>::uintX_t
getVA(typename llvm::object::ELFFile<ELFT>::uintX_t Addend = 0) const;
template <class ELFT>
typename llvm::object::ELFFile<ELFT>::uintX_t getGotVA() const;
template <class ELFT>