summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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