diff options
-rw-r--r-- | lld/ELF/OutputSections.cpp | 137 | ||||
-rw-r--r-- | lld/ELF/OutputSections.h | 46 | ||||
-rw-r--r-- | lld/ELF/Writer.cpp | 104 |
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; |