diff options
Diffstat (limited to 'ELF/Relocations.cpp')
| -rw-r--r-- | ELF/Relocations.cpp | 363 |
1 files changed, 214 insertions, 149 deletions
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 467219ad0542..812468896f0d 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -50,6 +50,7 @@ #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" #include "lld/Common/Strings.h" #include "llvm/ADT/SmallSet.h" @@ -65,6 +66,14 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; +static Optional<std::string> getLinkerScriptLocation(const Symbol &Sym) { + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) + if (Cmd->Sym == &Sym) + return Cmd->Location; + return None; +} + // Construct a message in the following format. // // >>> defined in /home/alice/src/foo.o @@ -72,8 +81,13 @@ using namespace lld::elf; // >>> /home/alice/src/bar.o:(.text+0x1) static std::string getLocation(InputSectionBase &S, const Symbol &Sym, uint64_t Off) { - std::string Msg = - "\n>>> defined in " + toString(Sym.File) + "\n>>> referenced by "; + std::string Msg = "\n>>> defined in "; + if (Sym.File) + Msg += toString(Sym.File); + else if (Optional<std::string> Loc = getLinkerScriptLocation(Sym)) + Msg += *Loc; + + Msg += "\n>>> referenced by "; std::string Src = S.getSrcMsg(Sym, Off); if (!Src.empty()) Msg += Src + "\n>>> "; @@ -90,12 +104,12 @@ static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { - InX::MipsGot->addTlsIndex(*C.File); + In.MipsGot->addTlsIndex(*C.File); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } if (Expr == R_MIPS_TLSGD) { - InX::MipsGot->addDynTlsEntry(*C.File, Sym); + In.MipsGot->addDynTlsEntry(*C.File, Sym); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -128,17 +142,17 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { if (Dyn) - InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest); + In.RelaDyn->addReloc(Type, In.Got, Off, Dest); else - InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); + In.Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); }; // Local Dynamic is for access to module local TLS variables, while still // being suitable for being dynamically loaded via dlopen. // GOT[e0] is the module index, with a special value of 0 for the current // module. GOT[e1] is unused. There only needs to be one module index entry. - if (Expr == R_TLSLD_PC && InX::Got->addTlsIndex()) { - AddTlsReloc(InX::Got->getTlsIndexOff(), Target->TlsModuleIndexRel, + if (Expr == R_TLSLD_PC && In.Got->addTlsIndex()) { + AddTlsReloc(In.Got->getTlsIndexOff(), Target->TlsModuleIndexRel, NeedDynId ? nullptr : &Sym, NeedDynId); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; @@ -148,8 +162,8 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, // the module index and offset of symbol in TLS block we can fill these in // using static GOT relocations. if (Expr == R_TLSGD_PC) { - if (InX::Got->addDynTlsEntry(Sym)) { - uint64_t Off = InX::Got->getGlobalDynOffset(Sym); + if (In.Got->addDynTlsEntry(Sym)) { + uint64_t Off = In.Got->getGlobalDynOffset(Sym); AddTlsReloc(Off, Target->TlsModuleIndexRel, &Sym, NeedDynId); AddTlsReloc(Off + Config->Wordsize, Target->TlsOffsetRel, &Sym, NeedDynOff); @@ -165,9 +179,6 @@ template <class ELFT> static unsigned handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, typename ELFT::uint Offset, int64_t Addend, RelExpr Expr) { - if (!(C.Flags & SHF_ALLOC)) - return 0; - if (!Sym.isTls()) return 0; @@ -176,12 +187,12 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, if (Config->EMachine == EM_MIPS) return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); - if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) && + if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) && Config->Shared) { - if (InX::Got->addDynTlsEntry(Sym)) { - uint64_t Off = InX::Got->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc( - {Target->TlsDescRel, InX::Got, Off, !Sym.IsPreemptible, &Sym, 0}); + if (In.Got->addDynTlsEntry(Sym)) { + uint64_t Off = In.Got->getGlobalDynOffset(Sym); + In.RelaDyn->addReloc( + {Target->TlsDescRel, In.Got, Off, !Sym.IsPreemptible, &Sym, 0}); } if (Expr != R_TLSDESC_CALL) C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); @@ -199,9 +210,9 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, } if (Expr == R_TLSLD_HINT) return 1; - if (InX::Got->addTlsIndex()) - InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, - InX::Got->getTlsIndexOff(), nullptr); + if (In.Got->addTlsIndex()) + In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, + In.Got->getTlsIndexOff(), nullptr); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -223,29 +234,29 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, return 1; } if (!Sym.isInGot()) { - InX::Got->addEntry(Sym); + In.Got->addEntry(Sym); uint64_t Off = Sym.getGotOffset(); - InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); + In.Got->Relocations.push_back( + {R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } - if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT, - R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) { + if (isRelExprOneOf<R_TLSDESC, R_AARCH64_TLSDESC_PAGE, R_TLSDESC_CALL, + R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) { if (Config->Shared) { - if (InX::Got->addDynTlsEntry(Sym)) { - uint64_t Off = InX::Got->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym); + if (In.Got->addDynTlsEntry(Sym)) { + uint64_t Off = In.Got->getGlobalDynOffset(Sym); + In.RelaDyn->addReloc(Target->TlsModuleIndexRel, In.Got, Off, &Sym); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t OffsetOff = Off + Config->Wordsize; if (Sym.IsPreemptible) - InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff, - &Sym); + In.RelaDyn->addReloc(Target->TlsOffsetRel, In.Got, OffsetOff, &Sym); else - InX::Got->Relocations.push_back( + In.Got->Relocations.push_back( {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); @@ -259,9 +270,9 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, Offset, Addend, &Sym}); if (!Sym.isInGot()) { - InX::Got->addEntry(Sym); - InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(), - &Sym); + In.Got->addEntry(Sym); + In.RelaDyn->addReloc(Target->TlsGotRel, In.Got, Sym.getGotOffset(), + &Sym); } } else { C.Relocations.push_back( @@ -273,13 +284,14 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally // defined. - if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_GOT_PAGE_PC>(Expr) && + if (isRelExprOneOf<R_GOT, R_GOT_FROM_END, R_GOT_PC, R_AARCH64_GOT_PAGE_PC, + R_GOT_OFF, R_TLSIE_HINT>(Expr) && !Config->Shared && !Sym.IsPreemptible) { C.Relocations.push_back({R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Sym}); return 1; } - if (Expr == R_TLSDESC_CALL) + if (Expr == R_TLSIE_HINT) return 1; return 0; } @@ -325,23 +337,25 @@ static bool isAbsoluteValue(const Symbol &Sym) { // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr Expr) { - return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr); + return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_AARCH64_PLT_PAGE_PC, + R_GOT_PLT, R_AARCH64_GOT_PAGE_PC_PLT>(Expr); } // Returns true if Expr refers a GOT entry. Note that this function // returns false for TLS variables even though they need GOT, because // TLS variables uses GOT differently than the regular variables. static bool needsGot(RelExpr Expr) { - return isRelExprOneOf<R_GOT, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOT_OFF, - R_MIPS_GOT_OFF32, R_GOT_PAGE_PC, R_GOT_PC, - R_GOT_FROM_END>(Expr); + return isRelExprOneOf<R_GOT, R_GOT_OFF, R_HEXAGON_GOT, R_MIPS_GOT_LOCAL_PAGE, + R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_AARCH64_GOT_PAGE_PC, + R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, R_GOT_FROM_END, + R_GOT_PLT>(Expr); } // True if this expression is of the form Sym - X, where X is a position in the // file (PC, or GOT for example). static bool isRelExpr(RelExpr Expr) { return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL, - R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC, + R_PPC_CALL, R_PPC_CALL_PLT, R_AARCH64_PAGE_PC, R_RELAX_GOT_PC>(Expr); } @@ -357,18 +371,19 @@ static bool isRelExpr(RelExpr Expr) { static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant - if (isRelExprOneOf< - R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, - R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, - R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, - R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, - R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT, - R_TLSLD_HINT>(E)) + if (isRelExprOneOf<R_GOT_FROM_END, R_GOT_OFF, R_HEXAGON_GOT, R_TLSLD_GOT_OFF, + R_MIPS_GOT_LOCAL_PAGE, R_MIPS_GOTREL, R_MIPS_GOT_OFF, + R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, R_MIPS_TLSGD, + R_AARCH64_GOT_PAGE_PC, R_AARCH64_GOT_PAGE_PC_PLT, R_GOT_PC, + R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, + R_TLSGD_GOT_FROM_END, R_TLSGD_PC, R_PPC_CALL_PLT, + R_TLSDESC_CALL, R_AARCH64_TLSDESC_PAGE, R_HINT, + R_TLSLD_HINT, R_TLSIE_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if // only the low bits are used. - if (E == R_GOT || E == R_PLT || E == R_TLSDESC) + if (E == R_GOT || E == R_GOT_PLT || E == R_PLT || E == R_TLSDESC) return Target->usesOnlyLowPageBits(Type) || !Config->Pic; if (Sym.IsPreemptible) @@ -414,10 +429,14 @@ static RelExpr toPlt(RelExpr Expr) { return R_PPC_CALL_PLT; case R_PC: return R_PLT_PC; - case R_PAGE_PC: - return R_PLT_PAGE_PC; + case R_AARCH64_PAGE_PC: + return R_AARCH64_PLT_PAGE_PC; + case R_AARCH64_GOT_PAGE_PC: + return R_AARCH64_GOT_PAGE_PC_PLT; case R_ABS: return R_PLT; + case R_GOT: + return R_GOT_PLT; default: return Expr; } @@ -466,7 +485,7 @@ static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) { SmallSet<SharedSymbol *, 4> Ret; for (const Elf_Sym &S : File.getGlobalELFSyms()) { if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || - S.st_value != SS.Value) + S.getType() == STT_TLS || S.st_value != SS.Value) continue; StringRef Name = check(S.getName(File.getStringTable())); Symbol *Sym = Symtab->find(Name); @@ -489,6 +508,7 @@ static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, Sym.PltIndex = Old.PltIndex; Sym.GotIndex = Old.GotIndex; Sym.VerdefIndex = Old.VerdefIndex; + Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex; Sym.IsPreemptible = true; Sym.ExportDynamic = true; Sym.IsUsedInRegularObj = true; @@ -549,9 +569,9 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) { BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss", SymSize, SS.Alignment); if (IsReadOnly) - InX::BssRelRo->getParent()->addSection(Sec); + In.BssRelRo->getParent()->addSection(Sec); else - InX::Bss->getParent()->addSection(Sec); + In.Bss->getParent()->addSection(Sec); // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly @@ -559,7 +579,7 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) { for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) replaceWithDefined(*Sym, Sec, 0, Sym->Size); - InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); + In.RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); } // MIPS has an odd notion of "paired" relocations to calculate addends. @@ -583,7 +603,7 @@ static int64_t computeMipsAddend(const RelTy &Rel, const RelTy *End, if (PairTy == R_MIPS_NONE) return 0; - const uint8_t *Buf = Sec.Data.data(); + const uint8_t *Buf = Sec.data().data(); uint32_t SymIndex = Rel.getSymbol(Config->IsMips64EL); // To make things worse, paired relocations might not be contiguous in @@ -611,7 +631,7 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End, if (RelTy::IsRela) { Addend = getAddend<ELFT>(Rel); } else { - const uint8_t *Buf = Sec.Data.data(); + const uint8_t *Buf = Sec.data().data(); Addend = Target->getImplicitAddend(Buf + Rel.r_offset, Type); } @@ -627,9 +647,6 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End, // Returns true if this function printed out an error message. static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { - if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) - return false; - if (Sym.isLocal() || !Sym.isUndefined() || Sym.isWeak()) return false; @@ -646,6 +663,10 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, Msg += Src + "\n>>> "; Msg += Sec.getObjMsg(Offset); + if (Sym.getName().startswith("_ZTV")) + Msg += "\nthe vtable symbol may be undefined because the class is missing " + "its key function (see https://lld.llvm.org/missingkeyfunction)"; + if ((Config->UnresolvedSymbols == UnresolvedPolicy::Warn && CanBeExternal) || Config->NoinhibitExec) { warn(Msg); @@ -700,7 +721,7 @@ public: while (I != Pieces.size() && Pieces[I].InputOff + Pieces[I].Size <= Off) ++I; if (I == Pieces.size()) - return Off; + fatal(".eh_frame: relocation is not in any piece"); // Pieces must be contiguous, so there must be no holes in between. assert(Pieces[I].InputOff <= Off && "Relocation not in any piece"); @@ -726,13 +747,13 @@ static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, // RelrDyn sections don't support odd offsets. Also, RelrDyn sections // don't store the addend values, so we must write it to the relocated // address. - if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { + if (In.RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); - InX::RelrDyn->Relocs.push_back({IS, OffsetInSec}); + In.RelrDyn->Relocs.push_back({IS, OffsetInSec}); return; } - InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, - Expr, Type); + In.RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, Expr, + Type); } template <class ELFT, class GotPltSection> @@ -745,9 +766,16 @@ static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, } template <class ELFT> static void addGotEntry(Symbol &Sym) { - InX::Got->addEntry(Sym); + In.Got->addEntry(Sym); + + RelExpr Expr; + if (Sym.isTls()) + Expr = R_TLS; + else if (Sym.isGnuIFunc()) + Expr = R_PLT; + else + Expr = R_ABS; - RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS; uint64_t Off = Sym.getGotOffset(); // If a GOT slot value can be calculated at link-time, which is now, @@ -760,19 +788,19 @@ template <class ELFT> static void addGotEntry(Symbol &Sym) { bool IsLinkTimeConstant = !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym)); if (IsLinkTimeConstant) { - InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym}); + In.Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym}); return; } // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that // the GOT slot will be fixed at load-time. if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { - addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel); + addRelativeReloc(In.Got, Off, &Sym, 0, R_ABS, Target->GotRel); return; } - InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, - InX::Got, Off, &Sym, 0, - Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel); + In.RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, In.Got, + Off, &Sym, 0, Sym.IsPreemptible ? R_ADDEND : R_ABS, + Target->GotRel); } // Return true if we can define a symbol in the executable that @@ -825,7 +853,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); return; } else if (RelType Rel = Target->getDynRel(Type)) { - InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); + In.RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries @@ -843,7 +871,7 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); + In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); return; } } @@ -930,10 +958,9 @@ static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, "' cannot be preempted; recompile with -fPIE" + getLocation(Sec, Sym, Offset)); if (!Sym.isInPlt()) - addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, - Sym); + addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym); if (!Sym.isDefined()) - replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0); + replaceWithDefined(Sym, In.Plt, getPltEntryOffset(Sym.PltIndex), 0); Sym.NeedsPltAddr = true; Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return; @@ -967,7 +994,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) return; - const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset; + const uint8_t *RelocatedAddr = Sec.data().begin() + Rel.r_offset; RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr); // Ignore "hint" relocations because they are only markers for relaxation. @@ -985,18 +1012,28 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, // all dynamic symbols that can be resolved within the executable will // actually be resolved that way at runtime, because the main exectuable // is always at the beginning of a search list. We can leverage that fact. - if (Sym.isGnuIFunc()) + if (Sym.isGnuIFunc()) { + if (!Config->ZText && Config->WarnIfuncTextrel) { + warn("using ifunc symbols when text relocations are allowed may produce " + "a binary that will segfault, if the object file is linked with " + "old version of glibc (glibc 2.28 and earlier). If this applies to " + "you, consider recompiling the object files without -fPIC and " + "without -Wl,-z,notext option. Use -no-warn-ifunc-textrel to " + "turn off this warning." + + getLocation(Sec, Sym, Offset)); + } Expr = toPlt(Expr); - else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + } else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) { Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); - else if (!Sym.IsPreemptible) + } else if (!Sym.IsPreemptible) { Expr = fromPlt(Expr); + } // This relocation does not require got entry, but it is relative to got and // needs it to be created. Here we request for that. if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) - InX::Got->HasGotOffRel = true; + In.Got->HasGotOffRel = true; // Read an addend. int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); @@ -1012,11 +1049,10 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. if (needsPlt(Expr) && !Sym.isInPlt()) { if (Sym.isGnuIFunc() && !Sym.IsPreemptible) - addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, - Target->IRelativeRel, Sym); - else - addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, + addPltEntry<ELFT>(In.Iplt, In.IgotPlt, In.RelaIplt, Target->IRelativeRel, Sym); + else + addPltEntry<ELFT>(In.Plt, In.GotPlt, In.RelaPlt, Target->PltRel, Sym); } // Create a GOT slot if a relocation needs GOT. @@ -1029,7 +1065,7 @@ static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, // See "Global Offset Table" in Chapter 5 in the following document // for detailed description: // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); + In.MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); } else if (!Sym.isInGot()) { addGotEntry<ELFT>(Sym); } @@ -1047,6 +1083,11 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { for (auto I = Rels.begin(), End = Rels.end(); I != End;) scanReloc<ELFT>(Sec, GetOffset, I, End); + + // Sort relocations by offset to binary search for R_RISCV_PCREL_HI20 + if (Config->EMachine == EM_RISCV) + std::stable_sort(Sec.Relocations.begin(), Sec.Relocations.end(), + RelocationOffsetComparator{}); } template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { @@ -1056,6 +1097,43 @@ template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { scanRelocs<ELFT>(S, S.rels<ELFT>()); } +static bool mergeCmp(const InputSection *A, const InputSection *B) { + // std::merge requires a strict weak ordering. + if (A->OutSecOff < B->OutSecOff) + return true; + + if (A->OutSecOff == B->OutSecOff) { + auto *TA = dyn_cast<ThunkSection>(A); + auto *TB = dyn_cast<ThunkSection>(B); + + // Check if Thunk is immediately before any specific Target + // InputSection for example Mips LA25 Thunks. + if (TA && TA->getTargetInputSection() == B) + return true; + + // Place Thunk Sections without specific targets before + // non-Thunk Sections. + if (TA && !TB && !TA->getTargetInputSection()) + return true; + } + + return false; +} + +// Call Fn on every executable InputSection accessed via the linker script +// InputSectionDescription::Sections. +static void forEachInputSectionDescription( + ArrayRef<OutputSection *> OutputSections, + llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) { + for (OutputSection *OS : OutputSections) { + if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) + continue; + for (BaseCommand *BC : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) + Fn(OS, ISD); + } +} + // Thunk Implementation // // Thunks (sometimes called stubs, veneers or branch islands) are small pieces @@ -1158,6 +1236,7 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) { [](const std::pair<ThunkSection *, uint32_t> &TS) { return TS.first->getSize() == 0; }); + // ISD->ThunkSections contains all created ThunkSections, including // those inserted in previous passes. Extract the Thunks created this // pass and order them in ascending OutSecOff. @@ -1173,27 +1252,11 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> OutputSections) { // Merge sorted vectors of Thunks and InputSections by OutSecOff std::vector<InputSection *> Tmp; Tmp.reserve(ISD->Sections.size() + NewThunks.size()); - auto MergeCmp = [](const InputSection *A, const InputSection *B) { - // std::merge requires a strict weak ordering. - if (A->OutSecOff < B->OutSecOff) - return true; - if (A->OutSecOff == B->OutSecOff) { - auto *TA = dyn_cast<ThunkSection>(A); - auto *TB = dyn_cast<ThunkSection>(B); - // Check if Thunk is immediately before any specific Target - // InputSection for example Mips LA25 Thunks. - if (TA && TA->getTargetInputSection() == B) - return true; - if (TA && !TB && !TA->getTargetInputSection()) - // Place Thunk Sections without specific targets before - // non-Thunk Sections. - return true; - } - return false; - }; + std::merge(ISD->Sections.begin(), ISD->Sections.end(), NewThunks.begin(), NewThunks.end(), std::back_inserter(Tmp), - MergeCmp); + mergeCmp); + ISD->Sections = std::move(Tmp); }); } @@ -1237,20 +1300,23 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { // Find InputSectionRange within Target Output Section (TOS) that the // InputSection (IS) that we need to precede is in. OutputSection *TOS = IS->getParent(); - for (BaseCommand *BC : TOS->SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { - if (ISD->Sections.empty()) - continue; - InputSection *first = ISD->Sections.front(); - InputSection *last = ISD->Sections.back(); - if (IS->OutSecOff >= first->OutSecOff && - IS->OutSecOff <= last->OutSecOff) { - TS = addThunkSection(TOS, ISD, IS->OutSecOff); - ThunkedSections[IS] = TS; - break; - } - } - return TS; + for (BaseCommand *BC : TOS->SectionCommands) { + auto *ISD = dyn_cast<InputSectionDescription>(BC); + if (!ISD || ISD->Sections.empty()) + continue; + + InputSection *First = ISD->Sections.front(); + InputSection *Last = ISD->Sections.back(); + + if (IS->OutSecOff < First->OutSecOff || Last->OutSecOff < IS->OutSecOff) + continue; + + TS = addThunkSection(TOS, ISD, IS->OutSecOff); + ThunkedSections[IS] = TS; + return TS; + } + + return nullptr; } // Create one or more ThunkSections per OS that can be used to place Thunks. @@ -1271,26 +1337,29 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { // allow for the creation of a short thunk. void ThunkCreator::createInitialThunkSections( ArrayRef<OutputSection *> OutputSections) { + uint32_t ThunkSectionSpacing = Target->getThunkSectionSpacing(); + forEachInputSectionDescription( OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { if (ISD->Sections.empty()) return; + uint32_t ISDBegin = ISD->Sections.front()->OutSecOff; uint32_t ISDEnd = ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize(); uint32_t LastThunkLowerBound = -1; - if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2) - LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing; + if (ISDEnd - ISDBegin > ThunkSectionSpacing * 2) + LastThunkLowerBound = ISDEnd - ThunkSectionSpacing; uint32_t ISLimit; uint32_t PrevISLimit = ISDBegin; - uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing; + uint32_t ThunkUpperBound = ISDBegin + ThunkSectionSpacing; for (const InputSection *IS : ISD->Sections) { ISLimit = IS->OutSecOff + IS->getSize(); if (ISLimit > ThunkUpperBound) { addThunkSection(OS, ISD, PrevISLimit); - ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + ThunkUpperBound = PrevISLimit + ThunkSectionSpacing; } if (ISLimit > LastThunkLowerBound) break; @@ -1304,13 +1373,14 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, InputSectionDescription *ISD, uint64_t Off) { auto *TS = make<ThunkSection>(OS, Off); - ISD->ThunkSections.push_back(std::make_pair(TS, Pass)); + ISD->ThunkSections.push_back({TS, Pass}); return TS; } std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, uint64_t Src) { std::vector<Thunk *> *ThunkVec = nullptr; + // We use (section, offset) pair to find the thunk position if possible so // that we create only one thunk for aliased symbols or ICFed sections. if (auto *D = dyn_cast<Defined>(&Sym)) @@ -1318,40 +1388,28 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}]; if (!ThunkVec) ThunkVec = &ThunkedSymbols[&Sym]; + // Check existing Thunks for Sym to see if they can be reused - for (Thunk *ET : *ThunkVec) - if (ET->isCompatibleWith(Type) && - Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA())) - return std::make_pair(ET, false); + for (Thunk *T : *ThunkVec) + if (T->isCompatibleWith(Type) && + Target->inBranchRange(Type, Src, T->getThunkTargetSym()->getVA())) + return std::make_pair(T, false); + // No existing compatible Thunk in range, create a new one Thunk *T = addThunk(Type, Sym); ThunkVec->push_back(T); return std::make_pair(T, true); } -// Call Fn on every executable InputSection accessed via the linker script -// InputSectionDescription::Sections. -void ThunkCreator::forEachInputSectionDescription( - ArrayRef<OutputSection *> OutputSections, - llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) { - for (OutputSection *OS : OutputSections) { - if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) - continue; - for (BaseCommand *BC : OS->SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) - Fn(OS, ISD); - } -} - // Return true if the relocation target is an in range Thunk. // Return false if the relocation is not to a Thunk. If the relocation target // was originally to a Thunk, but is no longer in range we revert the // relocation back to its original non-Thunk target. bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) { - if (Thunk *ET = Thunks.lookup(Rel.Sym)) { + if (Thunk *T = Thunks.lookup(Rel.Sym)) { if (Target->inBranchRange(Rel.Type, Src, Rel.Sym->getVA())) return true; - Rel.Sym = &ET->Destination; + Rel.Sym = &T->Destination; if (Rel.Sym->isInPlt()) Rel.Expr = toPlt(Rel.Expr); } @@ -1385,11 +1443,13 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &Rel, uint64_t Src) { // relocation out of range error. bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { bool AddressesChanged = false; - if (Pass == 0 && Target->ThunkSectionSpacing) + + if (Pass == 0 && Target->getThunkSectionSpacing()) createInitialThunkSections(OutputSections); - else if (Pass == 10) - // With Thunk Size much smaller than branch range we expect to - // converge quickly; if we get to 10 something has gone wrong. + + // With Thunk Size much smaller than branch range we expect to + // converge quickly; if we get to 10 something has gone wrong. + if (Pass == 10) fatal("thunk creation not converged"); // Create all the Thunks and insert them into synthetic ThunkSections. The @@ -1412,9 +1472,11 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Src, *Rel.Sym)) continue; + Thunk *T; bool IsNew; std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src); + if (IsNew) { // Find or create a ThunkSection for the new Thunk ThunkSection *TS; @@ -1425,13 +1487,16 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { TS->addThunk(T); Thunks[T->getThunkTargetSym()] = T; } + // Redirect relocation to Thunk, we never go via the PLT to a Thunk Rel.Sym = T->getThunkTargetSym(); Rel.Expr = fromPlt(Rel.Expr); } + for (auto &P : ISD->ThunkSections) AddressesChanged |= P.first->assignOffsets(); }); + for (auto &P : ThunkedSections) AddressesChanged |= P.second->assignOffsets(); |
