summaryrefslogtreecommitdiffstats
path: root/lld/ELF/OutputSections.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lld/ELF/OutputSections.cpp')
-rw-r--r--lld/ELF/OutputSections.cpp137
1 files changed, 32 insertions, 105 deletions
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index 391fe3902ca..f1189e691df 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -213,123 +213,50 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool IsRela)
this->Header.sh_addralign = sizeof(uintX_t);
}
-// Applies corresponding symbol and type for dynamic tls relocation.
-// Returns true if relocation was handled.
template <class ELFT>
-bool RelocationSection<ELFT>::applyTlsDynamicReloc(SymbolBody *Body,
- uint32_t Type, Elf_Rel *P,
- Elf_Rel *N) {
- if (Target->isTlsLocalDynamicRel(Type)) {
- P->setSymbolAndType(0, Target->TlsModuleIndexRel, Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getLocalTlsIndexVA();
- return true;
- }
-
- if (!Body || !Target->isTlsGlobalDynamicRel(Type))
- return false;
-
- if (Target->canRelaxTls(Type, Body)) {
- P->setSymbolAndType(Body->DynsymIndex, Target->getTlsGotRel(),
- Config->Mips64EL);
- P->r_offset = Body->getGotVA<ELFT>();
- return true;
+static typename ELFFile<ELFT>::uintX_t
+getOffset(const DynamicReloc<ELFT> &Rel) {
+ typedef typename ELFFile<ELFT>::uintX_t uintX_t;
+ SymbolBody *Sym = Rel.Sym;
+ switch (Rel.OKind) {
+ case DynamicReloc<ELFT>::Off_GTlsIndex:
+ return Out<ELFT>::Got->getGlobalDynAddr(*Sym);
+ case DynamicReloc<ELFT>::Off_GTlsOffset:
+ return Out<ELFT>::Got->getGlobalDynAddr(*Sym) + sizeof(uintX_t);
+ case DynamicReloc<ELFT>::Off_LTlsIndex:
+ return Out<ELFT>::Got->getLocalTlsIndexVA();
+ case DynamicReloc<ELFT>::Off_Sec:
+ return Rel.OffsetSec->getOffset(Rel.OffsetInSec) +
+ Rel.OffsetSec->OutSec->getVA();
+ case DynamicReloc<ELFT>::Off_Bss:
+ return cast<SharedSymbol<ELFT>>(Sym)->OffsetInBss + Out<ELFT>::Bss->getVA();
+ case DynamicReloc<ELFT>::Off_Got:
+ return Sym->getGotVA<ELFT>();
+ case DynamicReloc<ELFT>::Off_GotPlt:
+ return Sym->getGotPltVA<ELFT>();
}
-
- P->setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel,
- Config->Mips64EL);
- P->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body);
- N->setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel,
- Config->Mips64EL);
- N->r_offset = Out<ELFT>::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t);
- return true;
+ llvm_unreachable("Invalid offset kind");
}
template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) {
for (const DynamicReloc<ELFT> &Rel : Relocs) {
auto *P = reinterpret_cast<Elf_Rel *>(Buf);
Buf += IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
-
- // Skip placeholder for global dynamic TLS relocation pair. It was already
- // handled by the previous relocation.
- if (!Rel.C)
- continue;
-
- InputSectionBase<ELFT> &C = *Rel.C;
- const Elf_Rel &RI = *Rel.RI;
- uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
- const ObjectFile<ELFT> &File = *C.getFile();
- SymbolBody *Body = File.getSymbolBody(SymIndex);
- if (Body)
- Body = Body->repl();
-
- uint32_t Type = RI.getType(Config->Mips64EL);
- if (applyTlsDynamicReloc(Body, Type, P, reinterpret_cast<Elf_Rel *>(Buf)))
- continue;
-
- // Writer::scanRelocs creates a RELATIVE reloc for some type of TLS reloc.
- // We want to write it down as is.
- if (Type == Target->RelativeRel) {
- P->setSymbolAndType(0, Type, Config->Mips64EL);
- P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
- continue;
- }
-
- // Emit a copy relocation.
- auto *SS = dyn_cast_or_null<SharedSymbol<ELFT>>(Body);
- if (SS && SS->NeedsCopy) {
- P->setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL);
- P->r_offset = Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
- continue;
- }
-
- bool NeedsGot = Body && Target->needsGot(Type, *Body);
- bool CBP = canBePreempted(Body, NeedsGot);
+ SymbolBody *Sym = Rel.Sym;
if (IsRela) {
- auto R = static_cast<const Elf_Rela &>(RI);
- auto S = static_cast<Elf_Rela *>(P);
- uintX_t A = NeedsGot ? 0 : R.r_addend;
- if (CBP)
- S->r_addend = A;
- else if (Body)
- S->r_addend = Body->getVA<ELFT>() + A;
- else
- S->r_addend = getLocalRelTarget(File, R, A);
- }
-
- // For a symbol with STT_GNU_IFUNC type, we always create a PLT and
- // a GOT entry for the symbol, and emit an IRELATIVE reloc rather than
- // the usual JUMP_SLOT reloc for the GOT entry. For the details, you
- // want to read http://www.airs.com/blog/archives/403
- if (!CBP && Body && isGnuIFunc<ELFT>(*Body)) {
- P->setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL);
- if (Out<ELFT>::GotPlt)
- P->r_offset = Body->getGotPltVA<ELFT>();
- else
- P->r_offset = Body->getGotVA<ELFT>();
- continue;
+ uintX_t VA = 0;
+ if (Rel.UseSymVA)
+ VA = Sym->getVA<ELFT>();
+ else if (Rel.TargetSec)
+ VA = Rel.TargetSec->getOffset(Rel.OffsetInTargetSec) +
+ Rel.TargetSec->OutSec->getVA();
+ reinterpret_cast<Elf_Rela *>(P)->r_addend = Rel.Addend + VA;
}
- bool LazyReloc =
- Body && Target->UseLazyBinding && Target->needsPlt(Type, *Body);
-
- unsigned Reloc;
- if (!CBP)
- Reloc = Target->RelativeRel;
- else if (LazyReloc)
- Reloc = Target->PltRel;
- else if (NeedsGot)
- Reloc = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel;
- else
- Reloc = Target->getDynRel(Type);
- P->setSymbolAndType(CBP ? Body->DynsymIndex : 0, Reloc, Config->Mips64EL);
-
- if (LazyReloc)
- P->r_offset = Body->getGotPltVA<ELFT>();
- else if (NeedsGot)
- P->r_offset = Body->getGotVA<ELFT>();
- else
- P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
+ P->r_offset = getOffset(Rel);
+ uint32_t SymIdx = (!Rel.UseSymVA && Sym) ? Sym->DynsymIndex : 0;
+ P->setSymbolAndType(SymIdx, Rel.Type, Config->Mips64EL);
}
}
OpenPOWER on IntegriCloud