Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -172,9 +172,46 @@ }; template struct DynamicReloc { - typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; - InputSectionBase *C; - const Elf_Rel *RI; + typedef typename llvm::object::ELFFile::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 *OffsetSec = nullptr; + uintX_t OffsetInSec = 0; + bool UseSymVA = false; + InputSectionBase *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 *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 *OffsetSec, + uintX_t OffsetInSec, InputSectionBase *TargetSec, + uintX_t OffsetInTargetSec, uintX_t Addend) + : Type(Type), OKind(Off_Sec), OffsetSec(OffsetSec), + OffsetInSec(OffsetInSec), TargetSec(TargetSec), + OffsetInTargetSec(OffsetInTargetSec), Addend(Addend) {} }; template @@ -228,9 +265,6 @@ bool Static = false; private: - bool applyTlsDynamicReloc(SymbolBody *Body, uint32_t Type, Elf_Rel *P, - Elf_Rel *N); - std::vector> Relocs; const bool IsRela; }; Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -213,123 +213,50 @@ this->Header.sh_addralign = sizeof(uintX_t); } -// Applies corresponding symbol and type for dynamic tls relocation. -// Returns true if relocation was handled. template -bool RelocationSection::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::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(); - return true; +static typename ELFFile::uintX_t +getOffset(const DynamicReloc &Rel) { + typedef typename ELFFile::uintX_t uintX_t; + SymbolBody *Sym = Rel.Sym; + switch (Rel.OKind) { + case DynamicReloc::Off_GTlsIndex: + return Out::Got->getGlobalDynAddr(*Sym); + case DynamicReloc::Off_GTlsOffset: + return Out::Got->getGlobalDynAddr(*Sym) + sizeof(uintX_t); + case DynamicReloc::Off_LTlsIndex: + return Out::Got->getLocalTlsIndexVA(); + case DynamicReloc::Off_Sec: + return Rel.OffsetSec->getOffset(Rel.OffsetInSec) + + Rel.OffsetSec->OutSec->getVA(); + case DynamicReloc::Off_Bss: + return cast>(Sym)->OffsetInBss + Out::Bss->getVA(); + case DynamicReloc::Off_Got: + return Sym->template getGotVA(); + case DynamicReloc::Off_GotPlt: + return Sym->template getGotPltVA(); } - - P->setSymbolAndType(Body->DynsymIndex, Target->TlsModuleIndexRel, - Config->Mips64EL); - P->r_offset = Out::Got->getGlobalDynAddr(*Body); - N->setSymbolAndType(Body->DynsymIndex, Target->TlsOffsetRel, - Config->Mips64EL); - N->r_offset = Out::Got->getGlobalDynAddr(*Body) + sizeof(uintX_t); - return true; + llvm_unreachable("Invalid offset kind"); } template void RelocationSection::writeTo(uint8_t *Buf) { for (const DynamicReloc &Rel : Relocs) { auto *P = reinterpret_cast(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 &C = *Rel.C; - const Elf_Rel &RI = *Rel.RI; - uint32_t SymIndex = RI.getSymbol(Config->Mips64EL); - const ObjectFile &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(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>(Body); - if (SS && SS->NeedsCopy) { - P->setSymbolAndType(Body->DynsymIndex, Target->CopyRel, Config->Mips64EL); - P->r_offset = Out::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(RI); - auto S = static_cast(P); - uintX_t A = NeedsGot ? 0 : R.r_addend; - if (CBP) - S->r_addend = A; - else if (Body) - S->r_addend = Body->getVA() + 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(*Body)) { - P->setSymbolAndType(0, Target->IRelativeRel, Config->Mips64EL); - if (Out::GotPlt) - P->r_offset = Body->getGotPltVA(); - else - P->r_offset = Body->getGotVA(); - continue; + uintX_t VA = 0; + if (Rel.UseSymVA) + VA = Sym->template getVA(); + else if (Rel.TargetSec) + VA = Rel.TargetSec->getOffset(Rel.OffsetInTargetSec) + + Rel.TargetSec->OutSec->getVA(); + reinterpret_cast(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(); - else if (NeedsGot) - P->r_offset = Body->getGotVA(); - 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); } } Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -219,7 +219,9 @@ if (Target->canRelaxTls(Type, nullptr)) return true; if (Out::Got->addCurrentModuleTlsIndex()) - Out::RelaDyn->addReloc({&C, &RI}); + Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, + DynamicReloc::Off_LTlsIndex, + nullptr}); return true; } @@ -229,8 +231,10 @@ if (Target->isTlsGlobalDynamicRel(Type)) { bool Opt = Target->canRelaxTls(Type, Body); if (!Opt && Out::Got->addDynTlsEntry(Body)) { - Out::RelaDyn->addReloc({&C, &RI}); - Out::RelaDyn->addReloc({nullptr, nullptr}); + Out::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, DynamicReloc::Off_GTlsIndex, Body}); + Out::RelaDyn->addReloc( + {Target->TlsOffsetRel, DynamicReloc::Off_GTlsOffset, Body}); Body->setUsedInDynamicReloc(); return true; } @@ -283,12 +287,9 @@ if (handleTlsRelocation(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::RelaDyn->addReloc({&C, Rel}); - } + if (Target->needsDynRelative(Type)) + Out::RelaDyn->addReloc({Target->RelativeRel, &C, RI.r_offset, true, + Body, getAddend(RI)}); // MIPS has a special rule to create GOTs for local symbols. if (Config->EMachine == EM_MIPS && needsMipsLocalGot(Type, Body)) { @@ -307,7 +308,8 @@ if (Target->needsCopyRel(Type, *B)) { B->NeedsCopy = true; B->setUsedInDynamicReloc(); - Out::RelaDyn->addReloc({&C, &RI}); + Out::RelaDyn->addReloc( + {Target->CopyRel, DynamicReloc::Off_Bss, B}); continue; } } @@ -320,12 +322,17 @@ if (Body->isInGot()) continue; Out::Plt->addEntry(Body); + bool CBP = canBePreempted(Body, /*NeedsGot=*/true); if (Target->UseLazyBinding) { Out::GotPlt->addEntry(Body); - Out::RelaPlt->addReloc({&C, &RI}); + Out::RelaPlt->addReloc( + {CBP ? Target->PltRel : Target->IRelativeRel, + DynamicReloc::Off_GotPlt, !CBP, Body}); } else { Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({&C, &RI}); + Out::RelaDyn->addReloc( + {CBP ? Target->PltRel : Target->IRelativeRel, + DynamicReloc::Off_Got, !CBP, Body}); } continue; } @@ -339,12 +346,14 @@ if (Target->UseLazyBinding) { Out::GotPlt->addEntry(Body); - Out::RelaPlt->addReloc({&C, &RI}); + Out::RelaPlt->addReloc( + {Target->PltRel, DynamicReloc::Off_GotPlt, Body}); } else { if (Body->isInGot()) continue; Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({&C, &RI}); + Out::RelaDyn->addReloc( + {Target->GotRel, DynamicReloc::Off_Got, Body}); } if (canBePreempted(Body, /*NeedsGot=*/true)) @@ -371,8 +380,15 @@ !Target->isSizeRel(Type); if (CBP) Body->setUsedInDynamicReloc(); - if (CBP || Dynrel) - Out::RelaDyn->addReloc({&C, &RI}); + if (CBP || Dynrel) { + uint32_t DynType; + if (CBP) + DynType = Body->isTls() ? Target->getTlsGotRel() : Target->GotRel; + else + DynType = Target->RelativeRel; + Out::RelaDyn->addReloc( + {DynType, DynamicReloc::Off_Got, !CBP, Body}); + } continue; } @@ -393,24 +409,48 @@ 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::RelaDyn->addReloc({&C, &RI}); + Out::RelaDyn->addReloc({Target->getDynRel(Type), &C, RI.r_offset, + false, Body, getAddend(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::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(RI); + if (Config->EMachine == EM_PPC64 && RI.getType(false) == R_PPC64_TOC) { + Out::RelaDyn->addReloc({R_PPC64_RELATIVE, &C, RI.r_offset, false, + nullptr, + (uintX_t)getPPC64TocBase() + Addend}); + continue; + } + if (Body) { + Out::RelaDyn->addReloc( + {Target->RelativeRel, &C, RI.r_offset, true, Body, Addend}); + continue; + } + const Elf_Sym *Sym = + File.getObj().getRelocationSymbol(&RI, File.getSymbolTable()); + InputSectionBase *Section = File.getSection(*Sym); + uintX_t Offset = Sym->st_value; + if (Sym->getType() == STT_SECTION) { + Offset += Addend; + Addend = 0; + } + Out::RelaDyn->addReloc( + {Target->RelativeRel, &C, RI.r_offset, Section, Offset, Addend}); } } @@ -904,6 +944,9 @@ for (OutputSectionBase *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> &F : Symtab.getObjectFiles()) { @@ -918,9 +961,6 @@ } } - // 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 CommonSymbols;