summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2016-02-04 21:33:05 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2016-02-04 21:33:05 +0000
commitde9857e3c16cb4e8f241b72066b8a8853e441af5 (patch)
tree55b7924dad8e7b194f66b79049008600940186f2
parent35706ad6bbffef75fc74dcb4b4022cc3b3abaa6d (diff)
downloadbcm5719-llvm-de9857e3c16cb4e8f241b72066b8a8853e441af5.tar.gz
bcm5719-llvm-de9857e3c16cb4e8f241b72066b8a8853e441af5.zip
Avoid code duplication when creating dynamic relocations.
Another case where we currently have almost duplicated code is the creation of dynamic relocations. First to decide if we need one, then to decide what to write. This patch fixes it by passing more information from the relocation scan to the section writing code. This is the same idea used for r258723. I actually think it should be possible to simplify this further by reordering things a bit in the writer. For example, we should be able to represent almost every position in the file with an OutputSeciton and offset. When writing it out we then just need to add the offset to the OutputSection VA. llvm-svn: 259829
-rw-r--r--lld/ELF/OutputSections.cpp137
-rw-r--r--lld/ELF/OutputSections.h46
-rw-r--r--lld/ELF/Writer.cpp104
3 files changed, 144 insertions, 143 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);
}
}
diff --git a/lld/ELF/OutputSections.h b/lld/ELF/OutputSections.h
index 536aabdc134..614edf533a1 100644
--- a/lld/ELF/OutputSections.h
+++ b/lld/ELF/OutputSections.h
@@ -172,9 +172,46 @@ private:
};
template <class ELFT> struct DynamicReloc {
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- InputSectionBase<ELFT> *C;
- const Elf_Rel *RI;
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ uint32_t Type;
+
+ // Where the relocation is.
+ enum OffsetKind {
+ Off_Got, // The got entry of Sym.
+ Off_GotPlt, // The got.plt entry of Sym.
+ Off_Bss, // The bss entry of Sym (copy reloc).
+ Off_Sec, // The final position of the given input section and offset.
+ Off_LTlsIndex, // The local tls index.
+ Off_GTlsIndex, // The global tls index of Sym.
+ Off_GTlsOffset // The global tls offset of Sym.
+ } OKind;
+
+ SymbolBody *Sym = nullptr;
+ InputSectionBase<ELFT> *OffsetSec = nullptr;
+ uintX_t OffsetInSec = 0;
+ bool UseSymVA = false;
+ InputSectionBase<ELFT> *TargetSec = nullptr;
+ uintX_t OffsetInTargetSec = 0;
+ uintX_t Addend = 0;
+
+ DynamicReloc(uint32_t Type, OffsetKind OKind, SymbolBody *Sym)
+ : Type(Type), OKind(OKind), Sym(Sym) {}
+
+ DynamicReloc(uint32_t Type, OffsetKind OKind, bool UseSymVA, SymbolBody *Sym)
+ : Type(Type), OKind(OKind), Sym(Sym), UseSymVA(UseSymVA) {}
+
+ DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
+ uintX_t OffsetInSec, bool UseSymVA, SymbolBody *Sym,
+ uintX_t Addend)
+ : Type(Type), OKind(Off_Sec), Sym(Sym), OffsetSec(OffsetSec),
+ OffsetInSec(OffsetInSec), UseSymVA(UseSymVA), Addend(Addend) {}
+
+ DynamicReloc(uint32_t Type, InputSectionBase<ELFT> *OffsetSec,
+ uintX_t OffsetInSec, InputSectionBase<ELFT> *TargetSec,
+ uintX_t OffsetInTargetSec, uintX_t Addend)
+ : Type(Type), OKind(Off_Sec), OffsetSec(OffsetSec),
+ OffsetInSec(OffsetInSec), TargetSec(TargetSec),
+ OffsetInTargetSec(OffsetInTargetSec), Addend(Addend) {}
};
template <class ELFT>
@@ -228,9 +265,6 @@ public:
bool Static = false;
private:
- bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P,
- Elf_Rel *N);
-
std::vector<DynamicReloc<ELFT>> Relocs;
const bool IsRela;
};
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index c184d755dc0..1ce64d6a5b8 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -219,7 +219,9 @@ static bool handleTlsRelocation(unsigned Type, SymbolBody *Body,
if (Target->canRelaxTls(Type, nullptr))
return true;
if (Out<ELFT>::Got->addCurrentModuleTlsIndex())
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ Out<ELFT>::RelaDyn->addReloc({Target->TlsModuleIndexRel,
+ DynamicReloc<ELFT>::Off_LTlsIndex,
+ nullptr});
return true;
}
@@ -229,8 +231,10 @@ static bool handleTlsRelocation(unsigned Type, SymbolBody *Body,
if (Target->isTlsGlobalDynamicRel(Type)) {
bool Opt = Target->canRelaxTls(Type, Body);
if (!Opt && Out<ELFT>::Got->addDynTlsEntry(Body)) {
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
- Out<ELFT>::RelaDyn->addReloc({nullptr, nullptr});
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsModuleIndexRel, DynamicReloc<ELFT>::Off_GTlsIndex, Body});
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->TlsOffsetRel, DynamicReloc<ELFT>::Off_GTlsOffset, Body});
Body->setUsedInDynamicReloc();
return true;
}
@@ -283,12 +287,9 @@ void Writer<ELFT>::scanRelocs(
if (handleTlsRelocation<ELFT>(Type, Body, C, RI))
continue;
- if (Target->needsDynRelative(Type)) {
- RelType *Rel = new (Alloc) RelType;
- Rel->setSymbolAndType(0, Target->RelativeRel, Config->Mips64EL);
- Rel->r_offset = RI.r_offset;
- Out<ELFT>::RelaDyn->addReloc({&C, Rel});
- }
+ if (Target->needsDynRelative(Type))
+ Out<ELFT>::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true,
+ Body, getAddend<ELFT>(RI)});
// MIPS has a special rule to create GOTs for local symbols.
if (Config->EMachine == EM_MIPS && !canBePreempted(Body, true)) {
@@ -307,7 +308,8 @@ void Writer<ELFT>::scanRelocs(
if (Target->needsCopyRel(Type, *B)) {
B->NeedsCopy = true;
B->setUsedInDynamicReloc();
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->CopyRel, DynamicReloc<ELFT>::Off_Bss, B});
continue;
}
}
@@ -320,12 +322,17 @@ void Writer<ELFT>::scanRelocs(
if (Body->isInGot())
continue;
Out<ELFT>::Plt->addEntry(Body);
+ bool CBP = canBePreempted(Body, /*NeedsGot=*/true);
if (Target->UseLazyBinding) {
Out<ELFT>::GotPlt->addEntry(Body);
- Out<ELFT>::RelaPlt->addReloc({&C, &RI});
+ Out<ELFT>::RelaPlt->addReloc(
+ {CBP ? Target->PltRel : Target->IRelativeRel,
+ DynamicReloc<ELFT>::Off_GotPlt, !CBP, Body});
} else {
Out<ELFT>::Got->addEntry(Body);
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ Out<ELFT>::RelaDyn->addReloc(
+ {CBP ? Target->PltRel : Target->IRelativeRel,
+ DynamicReloc<ELFT>::Off_Got, !CBP, Body});
}
continue;
}
@@ -339,12 +346,14 @@ void Writer<ELFT>::scanRelocs(
if (Target->UseLazyBinding) {
Out<ELFT>::GotPlt->addEntry(Body);
- Out<ELFT>::RelaPlt->addReloc({&C, &RI});
+ Out<ELFT>::RelaPlt->addReloc(
+ {Target->PltRel, DynamicReloc<ELFT>::Off_GotPlt, Body});
} else {
if (Body->isInGot())
continue;
Out<ELFT>::Got->addEntry(Body);
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->GotRel, DynamicReloc<ELFT>::Off_Got, Body});
}
if (canBePreempted(Body, /*NeedsGot=*/true))
@@ -373,8 +382,15 @@ void Writer<ELFT>::scanRelocs(
!Target->isSizeRel(Type);
if (CBP)
Body->setUsedInDynamicReloc();
- if (CBP || Dynrel)
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ if (CBP || Dynrel) {
+ uint32_t DynType;
+ if (CBP)
+ DynType = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel;
+ else
+ DynType = Target->RelativeRel;
+ Out<ELFT>::RelaDyn->addReloc(
+ {DynType, DynamicReloc<ELFT>::Off_Got, !CBP, Body});
+ }
continue;
}
@@ -395,24 +411,48 @@ void Writer<ELFT>::scanRelocs(
continue;
}
- // We get here if a program was not compiled as PIC.
if (canBePreempted(Body, /*NeedsGot=*/false)) {
+ // We don't know anything about the finaly symbol. Just ask the dynamic
+ // linker to handle the relocation for us.
Body->setUsedInDynamicReloc();
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ Out<ELFT>::RelaDyn->addReloc({Target->getDynRel(Type), &C, RI.r_offset,
+ false, Body, getAddend<ELFT>(RI)});
continue;
}
- // If we get here, the code we are handling is not PIC. We need to copy
- // relocations from object files to the output file, so that the
- // dynamic linker can fix up addresses. But there are a few exceptions.
- // If the relocation will not change at runtime, we don't need to copy
- // them. For example, we don't copy PC-relative relocations because
- // the distance between two symbols won't change whereever they are
- // loaded. Likewise, if we are linking an executable, it will be loaded
- // at a fixed address, so we don't copy relocations.
- if (Config->Shared && !Target->isRelRelative(Type) &&
- !Target->isSizeRel(Type))
- Out<ELFT>::RelaDyn->addReloc({&C, &RI});
+ // We know that this is the final symbol. If the program being produced
+ // is position independent, the final value is still not known.
+ // If the relocation depends on the symbol value (not the size or distances
+ // in the output), we still need some help from the dynamic linker.
+ // We can however do better than just copying the incoming relocation. We
+ // can process some of it and and just ask the dynamic linker to add the
+ // load address.
+ if (!Config->Shared || Target->isRelRelative(Type) ||
+ Target->isSizeRel(Type))
+ continue;
+
+ uintX_t Addend = getAddend<ELFT>(RI);
+ if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) {
+ Out<ELFT>::RelaDyn->addReloc({R_PPC64_RELATIVE, &C, RI.r_offset, false,
+ nullptr,
+ (uintX_t)getPPC64TocBase() + Addend});
+ continue;
+ }
+ if (Body) {
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->RelativeRel, &C, RI.r_offset, true, Body, Addend});
+ continue;
+ }
+ const Elf_Sym *Sym =
+ File.getObj().getRelocationSymbol(&RI, File.getSymbolTable());
+ InputSectionBase<ELFT> *Section = File.getSection(*Sym);
+ uintX_t Offset = Sym->st_value;
+ if (Sym->getType() == STT_SECTION) {
+ Offset += Addend;
+ Addend = 0;
+ }
+ Out<ELFT>::RelaDyn->addReloc(
+ {Target->RelativeRel, &C, RI.r_offset, Section, Offset, Addend});
}
}
@@ -906,6 +946,9 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
for (OutputSectionBase<ELFT> *Sec : RegularSections)
addStartStopSymbols(Sec);
+ // Define __rel[a]_iplt_{start,end} symbols if needed.
+ addRelIpltSymbols();
+
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
@@ -920,9 +963,6 @@ template <class ELFT> bool Writer<ELFT>::createSections() {
}
}
- // Define __rel[a]_iplt_{start,end} symbols if needed.
- addRelIpltSymbols();
-
// Now that we have defined all possible symbols including linker-
// synthesized ones. Visit all symbols to give the finishing touches.
std::vector<DefinedCommon *> CommonSymbols;
OpenPOWER on IntegriCloud