//===- Relocations.cpp ----------------------------------------------------===// // // The LLVM Linker // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file contains platform-independent functions to process relocations. // I'll describe the overview of this file here. // // Simple relocations are easy to handle for the linker. For example, // for R_X86_64_PC64 relocs, the linker just has to fix up locations // with the relative offsets to the target symbols. It would just be // reading records from relocation sections and applying them to output. // // But not all relocations are that easy to handle. For example, for // R_386_GOTOFF relocs, the linker has to create new GOT entries for // symbols if they don't exist, and fix up locations with GOT entry // offsets from the beginning of GOT section. So there is more than // fixing addresses in relocation processing. // // ELF defines a large number of complex relocations. // // The functions in this file analyze relocations and do whatever needs // to be done. It includes, but not limited to, the following. // // - create GOT/PLT entries // - create new relocations in .dynsym to let the dynamic linker resolve // them at runtime (since ELF supports dynamic linking, not all // relocations can be resolved at link-time) // - create COPY relocs and reserve space in .bss // - replace expensive relocs (in terms of runtime cost) with cheap ones // - error out infeasible combinations such as PIC and non-relative relocs // // Note that the functions in this file don't actually apply relocations // because it doesn't know about the output file nor the output file buffer. // It instead stores Relocation objects to InputSection's Relocations // vector to let it apply later in InputSection::writeTo. // //===----------------------------------------------------------------------===// #include "Relocations.h" #include "Config.h" #include "OutputSections.h" #include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support::endian; namespace lld { namespace elf { static bool refersToGotEntry(RelExpr Expr) { return isRelExprOneOf(Expr); } static bool isPreemptible(const SymbolBody &Body, uint32_t Type) { // In case of MIPS GP-relative relocations always resolve to a definition // in a regular input file, ignoring the one-definition rule. So we, // for example, should not attempt to create a dynamic relocation even // if the target symbol is preemptible. There are two two MIPS GP-relative // relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 // can be against a preemptible symbol. // To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all // relocation types occupy eight bit. In case of N64 ABI we extract first // relocation from 3-in-1 packet because only the first relocation can // be against a real symbol. if (Config->EMachine == EM_MIPS && (Type & 0xff) == R_MIPS_GPREL16) return false; return Body.isPreemptible(); } // This function is similar to the `handleTlsRelocation`. ARM and MIPS do not // support any relaxations for TLS relocations so by factoring out ARM and MIPS // handling in to the separate function we can simplify the code and do not // pollute `handleTlsRelocation` by ARM and MIPS `ifs` statements. template static unsigned handleNoRelaxTlsRelocation( GOT *Got, uint32_t Type, SymbolBody &Body, InputSectionBase &C, typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) { typedef typename ELFT::uint uintX_t; auto addModuleReloc = [](SymbolBody &Body, GOT *Got, uintX_t Off, bool LD) { // The Dynamic TLS Module Index Relocation can be statically resolved to 1 // if we know that we are linking an executable. For ARM we resolve the // relocation when writing the Got. MIPS has a custom Got implementation // that writes the Module index in directly. if (!Body.isPreemptible() && !Config->Pic && Config->EMachine == EM_ARM) Got->Relocations.push_back( {R_ABS, Target->TlsModuleIndexRel, Off, 0, &Body}); else { SymbolBody *Dest = LD ? nullptr : &Body; In::RelaDyn->addReloc( {Target->TlsModuleIndexRel, Got, Off, false, Dest, 0}); } }; if (Expr == R_MIPS_TLSLD || Expr == R_TLSLD_PC) { if (Got->addTlsIndex() && (Config->Pic || Config->EMachine == EM_ARM)) addModuleReloc(Body, Got, Got->getTlsIndexOff(), true); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } if (Target->isTlsGlobalDynamicRel(Type)) { if (Got->addDynTlsEntry(Body) && (Body.isPreemptible() || Config->EMachine == EM_ARM)) { uintX_t Off = Got->getGlobalDynOffset(Body); addModuleReloc(Body, Got, Off, false); if (Body.isPreemptible()) In::RelaDyn->addReloc({Target->TlsOffsetRel, Got, Off + (uintX_t)sizeof(uintX_t), false, &Body, 0}); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } return 0; } // Returns the number of relocations processed. template static unsigned handleTlsRelocation(uint32_t Type, SymbolBody &Body, InputSectionBase &C, typename ELFT::uint Offset, typename ELFT::uint Addend, RelExpr Expr) { if (!(C.Flags & SHF_ALLOC)) return 0; if (!Body.isTls()) return 0; typedef typename ELFT::uint uintX_t; if (Config->EMachine == EM_ARM) return handleNoRelaxTlsRelocation(In::Got, Type, Body, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) return handleNoRelaxTlsRelocation(In::MipsGot, Type, Body, C, Offset, Addend, Expr); bool IsPreemptible = isPreemptible(Body, Type); if ((Expr == R_TLSDESC || Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC_CALL) && Config->Shared) { if (In::Got->addDynTlsEntry(Body)) { uintX_t Off = In::Got->getGlobalDynOffset(Body); In::RelaDyn->addReloc({Target->TlsDescRel, In::Got, Off, !IsPreemptible, &Body, 0}); } if (Expr != R_TLSDESC_CALL) C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } if (Expr == R_TLSLD_PC || Expr == R_TLSLD) { // Local-Dynamic relocs can be relaxed to Local-Exec. if (!Config->Shared) { C.Relocations.push_back( {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); return 2; } if (In::Got->addTlsIndex()) In::RelaDyn->addReloc({Target->TlsModuleIndexRel, In::Got, In::Got->getTlsIndexOff(), false, nullptr, 0}); C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } // Local-Dynamic relocs can be relaxed to Local-Exec. if (Target->isTlsLocalDynamicRel(Type) && !Config->Shared) { C.Relocations.push_back( {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Body}); return 1; } if (Expr == R_TLSDESC_PAGE || Expr == R_TLSDESC || Expr == R_TLSDESC_CALL || Target->isTlsGlobalDynamicRel(Type)) { if (Config->Shared) { if (In::Got->addDynTlsEntry(Body)) { uintX_t Off = In::Got->getGlobalDynOffset(Body); In::RelaDyn->addReloc( {Target->TlsModuleIndexRel, In::Got, Off, false, &Body, 0}); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uintX_t OffsetOff = Off + (uintX_t)sizeof(uintX_t); if (IsPreemptible) In::RelaDyn->addReloc({Target->TlsOffsetRel, In::Got, OffsetOff, false, &Body, 0}); else In::Got->Relocations.push_back( {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Body}); } C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); return 1; } // Global-Dynamic relocs can be relaxed to Initial-Exec or Local-Exec // depending on the symbol being locally defined or not. if (IsPreemptible) { C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_IE), Type, Offset, Addend, &Body}); if (!Body.isInGot()) { In::Got->addEntry(Body); In::RelaDyn->addReloc({Target->TlsGotRel, In::Got, Body.getGotOffset(), false, &Body, 0}); } return Target->TlsGdRelaxSkip; } C.Relocations.push_back( {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_GD_TO_LE), Type, Offset, Addend, &Body}); return Target->TlsGdRelaxSkip; } // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally // defined. if (Target->isTlsInitialExecRel(Type) && !Config->Shared && !IsPreemptible) { C.Relocations.push_back( {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); return 1; } return 0; } template static int16_t readSignedLo16(const uint8_t *Loc) { return read32(Loc) & 0xffff; } template static uint32_t getMipsPairType(const RelTy *Rel, const SymbolBody &Sym) { switch (Rel->getType(Config->Mips64EL)) { case R_MIPS_HI16: return R_MIPS_LO16; case R_MIPS_GOT16: return Sym.isLocal() ? R_MIPS_LO16 : R_MIPS_NONE; case R_MIPS_PCHI16: return R_MIPS_PCLO16; case R_MICROMIPS_HI16: return R_MICROMIPS_LO16; default: return R_MIPS_NONE; } } template static int32_t findMipsPairedAddend(const uint8_t *Buf, const uint8_t *BufLoc, SymbolBody &Sym, const RelTy *Rel, const RelTy *End) { uint32_t SymIndex = Rel->getSymbol(Config->Mips64EL); uint32_t Type = getMipsPairType(Rel, Sym); // Some MIPS relocations use addend calculated from addend of the relocation // itself and addend of paired relocation. ABI requires to compute such // combined addend in case of REL relocation record format only. // See p. 4-17 at ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf if (RelTy::IsRela || Type == R_MIPS_NONE) return 0; for (const RelTy *RI = Rel; RI != End; ++RI) { if (RI->getType(Config->Mips64EL) != Type) continue; if (RI->getSymbol(Config->Mips64EL) != SymIndex) continue; const endianness E = ELFT::TargetEndianness; return ((read32(BufLoc) & 0xffff) << 16) + readSignedLo16(Buf + RI->r_offset); } warn("can't find matching " + toString(Type) + " relocation for " + toString(Rel->getType(Config->Mips64EL))); return 0; } // True if non-preemptable symbol always has the same value regardless of where // the DSO is loaded. template static bool isAbsolute(const SymbolBody &Body) { if (Body.isUndefined()) return !Body.isLocal() && Body.symbol()->isWeak(); if (const auto *DR = dyn_cast>(&Body)) return DR->Section == nullptr; // Absolute symbol. return false; } template static bool isAbsoluteValue(const SymbolBody &Body) { return isAbsolute(Body) || Body.isTls(); } static bool needsPlt(RelExpr Expr) { return isRelExprOneOf(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( Expr); } template static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, const SymbolBody &Body, InputSectionBase &S, typename ELFT::uint RelOff) { // These expressions always compute a constant if (isRelExprOneOf(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) return Target->usesOnlyLowPageBits(Type) || !Config->Pic; if (isPreemptible(Body, Type)) return false; if (!Config->Pic) return true; bool AbsVal = isAbsoluteValue(Body); bool RelE = isRelExpr(E); if (AbsVal && !RelE) return true; if (!AbsVal && RelE) return true; // Relative relocation to an absolute value. This is normally unrepresentable, // but if the relocation refers to a weak undefined symbol, we allow it to // resolve to the image base. This is a little strange, but it allows us to // link function calls to such symbols. Normally such a call will be guarded // with a comparison, which will load a zero from the GOT. // Another special case is MIPS _gp_disp symbol which represents offset // between start of a function and '_gp' value and defined as absolute just // to simplify the code. if (AbsVal && RelE) { if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) return true; if (&Body == ElfSym::MipsGpDisp) return true; error(S.getLocation(RelOff) + ": relocation " + toString(Type) + " cannot refer to absolute symbol '" + toString(Body) + "' defined in " + toString(Body.File)); return true; } return Target->usesOnlyLowPageBits(Type); } static RelExpr toPlt(RelExpr Expr) { if (Expr == R_PPC_OPD) return R_PPC_PLT_OPD; if (Expr == R_PC) return R_PLT_PC; if (Expr == R_PAGE_PC) return R_PLT_PAGE_PC; if (Expr == R_ABS) return R_PLT; return Expr; } static RelExpr fromPlt(RelExpr Expr) { // We decided not to use a plt. Optimize a reference to the plt to a // reference to the symbol itself. if (Expr == R_PLT_PC) return R_PC; if (Expr == R_PPC_PLT_OPD) return R_PPC_OPD; if (Expr == R_PLT) return R_ABS; return Expr; } template static uint32_t getAlignment(SharedSymbol *SS) { typedef typename ELFT::uint uintX_t; uintX_t SecAlign = SS->file()->getSection(SS->Sym)->sh_addralign; uintX_t SymValue = SS->Sym.st_value; int TrailingZeros = std::min(countTrailingZeros(SecAlign), countTrailingZeros(SymValue)); return 1 << TrailingZeros; } template static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::uint uintX_t; typedef typename ELFT::Phdr Elf_Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. uintX_t Value = SS->Sym.st_value; for (const Elf_Phdr &Phdr : check(SS->file()->getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && !(Phdr.p_flags & ELF::PF_W) && Value >= Phdr.p_vaddr && Value < Phdr.p_vaddr + Phdr.p_memsz) return true; return false; } // Reserve space in .bss or .bss.rel.ro for copy relocation. template static void addCopyRelSymbol(SharedSymbol *SS) { typedef typename ELFT::uint uintX_t; typedef typename ELFT::Sym Elf_Sym; // Copy relocation against zero-sized symbol doesn't make sense. uintX_t SymSize = SS->template getSize(); if (SymSize == 0) fatal("cannot create a copy relocation for symbol " + toString(*SS)); // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. bool IsReadOnly = isReadOnly(SS); OutputSection *CopySec = IsReadOnly ? Out::BssRelRo : Out::Bss; uintX_t Alignment = getAlignment(SS); uintX_t Off = alignTo(CopySec->Size, Alignment); CopySec->Size = Off + SymSize; CopySec->updateAlignment(Alignment); uintX_t Shndx = SS->Sym.st_shndx; uintX_t Value = SS->Sym.st_value; // 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 // interpose any aliases. for (const Elf_Sym &S : SS->file()->getGlobalSymbols()) { if (S.st_shndx != Shndx || S.st_value != Value) continue; auto *Alias = dyn_cast_or_null>( Symtab::X->find(check(S.getName(SS->file()->getStringTable())))); if (!Alias) continue; Alias->CopyIsInBssRelRo = IsReadOnly; Alias->CopyOffset = Off; Alias->NeedsCopyOrPltAddr = true; Alias->symbol()->IsUsedInRegularObj = true; } In::RelaDyn->addReloc({Target->CopyRel, CopySec, Off, false, SS, 0}); } template static RelExpr adjustExpr(const elf::ObjectFile &File, SymbolBody &Body, bool IsWrite, RelExpr Expr, uint32_t Type, const uint8_t *Data, InputSectionBase &S, typename ELFT::uint RelOff) { bool Preemptible = isPreemptible(Body, Type); if (Body.isGnuIFunc()) { Expr = toPlt(Expr); } else if (!Preemptible) { if (needsPlt(Expr)) Expr = fromPlt(Expr); if (Expr == R_GOT_PC && !isAbsoluteValue(Body)) Expr = Target->adjustRelaxExpr(Type, Data, Expr); } Expr = Target->getThunkExpr(Expr, Type, File, Body); if (IsWrite || isStaticLinkTimeConstant(Expr, Type, Body, S, RelOff)) return Expr; // This relocation would require the dynamic linker to write a value to read // only memory. We can hack around it if we are producing an executable and // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { error(S.getLocation(RelOff) + ": can't create dynamic relocation " + toString(Type) + " against " + (Body.getName().empty() ? "local symbol in readonly segment" : "symbol '" + toString(Body) + "'") + " defined in " + toString(Body.File)); return Expr; } if (Body.getVisibility() != STV_DEFAULT) { error(S.getLocation(RelOff) + ": cannot preempt symbol '" + toString(Body) + "' defined in " + toString(Body.File)); return Expr; } if (Body.isObject()) { // Produce a copy relocation. auto *B = cast>(&Body); if (!B->needsCopy()) addCopyRelSymbol(B); return Expr; } if (Body.isFunc()) { // This handles a non PIC program call to function in a shared library. In // an ideal world, we could just report an error saying the relocation can // overflow at runtime. In the real world with glibc, crt1.o has a // R_X86_64_PC32 pointing to libc.so. // // The general idea on how to handle such cases is to create a PLT entry and // use that as the function value. // // For the static linking part, we just return a plt expr and everything // else will use the the PLT entry as the address. // // The remaining problem is making sure pointer equality still works. We // need the help of the dynamic linker for that. We let it know that we have // a direct reference to a so symbol by creating an undefined symbol with a // non zero st_value. Seeing that, the dynamic linker resolves the symbol to // the value of the symbol we created. This is true even for got entries, so // pointer equality is maintained. To avoid an infinite loop, the only entry // that points to the real function is a dedicated got entry used by the // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, // R_386_JMP_SLOT, etc). Body.NeedsCopyOrPltAddr = true; return toPlt(Expr); } error("symbol '" + toString(Body) + "' defined in " + toString(Body.File) + " is missing type"); return Expr; } template static typename ELFT::uint computeAddend(const elf::ObjectFile &File, const uint8_t *SectionData, const RelTy *End, const RelTy &RI, RelExpr Expr, SymbolBody &Body) { typedef typename ELFT::uint uintX_t; uint32_t Type = RI.getType(Config->Mips64EL); uintX_t Addend = getAddend(RI); const uint8_t *BufLoc = SectionData + RI.r_offset; if (!RelTy::IsRela) Addend += Target->getImplicitAddend(BufLoc, Type); if (Config->EMachine == EM_MIPS) { Addend += findMipsPairedAddend(SectionData, BufLoc, Body, &RI, End); if (Type == R_MIPS_LO16 && Expr == R_PC) // R_MIPS_LO16 expression has R_PC type iif the target is _gp_disp // symbol. In that case we should use the following formula for // calculation "AHL + GP - P + 4". Let's add 4 right here. // For details see p. 4-19 at // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf Addend += 4; if (Expr == R_MIPS_GOTREL && Body.isLocal()) Addend += File.MipsGp0; } if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC) Addend += getPPC64TocBase(); return Addend; } template static void reportUndefined(SymbolBody &Sym, InputSectionBase &S, typename ELFT::uint Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore) return; if (Config->Shared && Sym.symbol()->Visibility == STV_DEFAULT && Config->UnresolvedSymbols != UnresolvedPolicy::NoUndef) return; std::string Msg = S.getLocation(Offset) + ": undefined symbol '" + toString(Sym) + "'"; if (Config->UnresolvedSymbols == UnresolvedPolicy::Warn) warn(Msg); else error(Msg); } template static std::pair mergeMipsN32RelTypes(uint32_t Type, uint32_t Offset, RelTy *I, RelTy *E) { // MIPS N32 ABI treats series of successive relocations with the same offset // as a single relocation. The similar approach used by N64 ABI, but this ABI // packs all relocations into the single relocation record. Here we emulate // this for the N32 ABI. Iterate over relocation with the same offset and put // theirs types into the single bit-set. uint32_t Processed = 0; for (; I != E && Offset == I->r_offset; ++I) { ++Processed; Type |= I->getType(Config->Mips64EL) << (8 * Processed); } return std::make_pair(Type, Processed); } // The reason we have to do this early scan is as follows // * To mmap the output file, we need to know the size // * For that, we need to know how many dynamic relocs we will have. // It might be possible to avoid this by outputting the file with write: // * Write the allocated output sections, computing addresses. // * Apply relocations, recording which ones require a dynamic reloc. // * Write the dynamic relocations. // * Write the rest of the file. // This would have some drawbacks. For example, we would only know if .rela.dyn // is needed after applying relocations. If it is, it will go after rw and rx // sections. Given that it is ro, we will need an extra PT_LOAD. This // complicates things for the dynamic linker and means we would have to reserve // space for the extra PT_LOAD even if we end up not using it. template static void scanRelocs(InputSectionBase &C, ArrayRef Rels) { typedef typename ELFT::uint uintX_t; bool IsWrite = C.Flags & SHF_WRITE; auto AddDyn = [=](const DynamicReloc &Reloc) { In::RelaDyn->addReloc(Reloc); }; const elf::ObjectFile *File = C.getFile(); ArrayRef SectionData = C.Data; const uint8_t *Buf = SectionData.begin(); ArrayRef Pieces; if (auto *Eh = dyn_cast>(&C)) Pieces = Eh->Pieces; ArrayRef::iterator PieceI = Pieces.begin(); ArrayRef::iterator PieceE = Pieces.end(); for (auto I = Rels.begin(), E = Rels.end(); I != E; ++I) { const RelTy &RI = *I; SymbolBody &Body = File->getRelocTargetSym(RI); uint32_t Type = RI.getType(Config->Mips64EL); if (Config->MipsN32Abi) { uint32_t Processed; std::tie(Type, Processed) = mergeMipsN32RelTypes(Type, RI.r_offset, I + 1, E); I += Processed; } // We only report undefined symbols if they are referenced somewhere in the // code. if (!Body.isLocal() && Body.isUndefined() && !Body.symbol()->isWeak()) reportUndefined(Body, C, RI.r_offset); RelExpr Expr = Target->getRelExpr(Type, Body); bool Preemptible = isPreemptible(Body, Type); Expr = adjustExpr(*File, Body, IsWrite, Expr, Type, Buf + RI.r_offset, C, RI.r_offset); if (ErrorCount) continue; // Skip a relocation that points to a dead piece // in a eh_frame section. while (PieceI != PieceE && (PieceI->InputOff + PieceI->size() <= RI.r_offset)) ++PieceI; // Compute the offset of this section in the output section. We do it here // to try to compute it only once. uintX_t Offset; if (PieceI != PieceE) { assert(PieceI->InputOff <= RI.r_offset && "Relocation not in any piece"); if (PieceI->OutputOff == -1) continue; Offset = PieceI->OutputOff + RI.r_offset - PieceI->InputOff; } else { Offset = RI.r_offset; } // 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 (Expr == R_GOTONLY_PC || Expr == R_GOTONLY_PC_FROM_END || Expr == R_GOTREL || Expr == R_GOTREL_FROM_END || Expr == R_PPC_TOC) In::Got->HasGotOffRel = true; uintX_t Addend = computeAddend(*File, Buf, E, RI, Expr, Body); if (unsigned Processed = handleTlsRelocation(Type, Body, C, Offset, Addend, Expr)) { I += (Processed - 1); continue; } // Ignore "hint" and TLS Descriptor call relocation because they are // only markers for relaxation. if (isRelExprOneOf(Expr)) continue; if (needsPlt(Expr) || isRelExprOneOf(Expr) || refersToGotEntry(Expr) || !isPreemptible(Body, Type)) { // If the relocation points to something in the file, we can process it. bool Constant = isStaticLinkTimeConstant(Expr, Type, Body, C, RI.r_offset); // If the output being produced is position independent, the final value // is still not known. In that case 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 (!Constant) AddDyn({Target->RelativeRel, &C, Offset, true, &Body, Addend}); // If the produced value is a constant, we just remember to write it // when outputting this section. We also have to do it if the format // uses Elf_Rel, since in that case the written value is the addend. if (Constant || !RelTy::IsRela) C.Relocations.push_back({Expr, Type, Offset, Addend, &Body}); } else { // We don't know anything about the finaly symbol. Just ask the dynamic // linker to handle the relocation for us. if (!Target->isPicRel(Type)) error(C.getLocation(Offset) + ": relocation " + toString(Type) + " cannot be used against shared object; recompile with -fPIC."); AddDyn({Target->getDynRel(Type), &C, Offset, false, &Body, Addend}); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries // MIPS ABI requires dynamic linker to fills up GOT entries using // specially sorted dynamic symbol table. This affects even dynamic // relocations against symbols which do not require GOT entries // creation explicitly, i.e. do not have any GOT-relocations. So if // a preemptible symbol has a dynamic relocation we anyway have // to create a GOT entry for it. // If a non-preemptible symbol has a dynamic relocation against it, // dynamic linker takes it st_value, adds offset and writes down // result of the dynamic relocation. In case of preemptible symbol // dynamic linker performs symbol resolution, writes the symbol value // to the GOT entry and reads the GOT entry when it needs to perform // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) In::MipsGot->addEntry(Body, Addend, Expr); continue; } // At this point we are done with the relocated position. Some relocations // also require us to create a got or plt entry. // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol. if (needsPlt(Expr)) { if (Body.isInPlt()) continue; if (Body.isGnuIFunc() && !Preemptible) { In::Iplt->addEntry(Body); In::IgotPlt->addEntry(Body); In::RelaIplt->addReloc({Target->IRelativeRel, In::IgotPlt, Body.getGotPltOffset(), !Preemptible, &Body, 0}); } else { In::Plt->addEntry(Body); In::GotPlt->addEntry(Body); In::RelaPlt->addReloc({Target->PltRel, In::GotPlt, Body.getGotPltOffset(), !Preemptible, &Body, 0}); } continue; } if (refersToGotEntry(Expr)) { if (Config->EMachine == EM_MIPS) { // MIPS ABI has special rules to process GOT entries and doesn't // require relocation entries for them. A special case is TLS // relocations. In that case dynamic loader applies dynamic // relocations to initialize TLS GOT entries. // 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 In::MipsGot->addEntry(Body, Addend, Expr); if (Body.isTls() && Body.isPreemptible()) AddDyn({Target->TlsGotRel, In::MipsGot, Body.getGotOffset(), false, &Body, 0}); continue; } if (Body.isInGot()) continue; In::Got->addEntry(Body); uintX_t Off = Body.getGotOffset(); uint32_t DynType; RelExpr GotRE = R_ABS; if (Body.isTls()) { DynType = Target->TlsGotRel; GotRE = R_TLS; } else if (!Preemptible && Config->Pic && !isAbsolute(Body)) DynType = Target->RelativeRel; else DynType = Target->GotRel; // FIXME: this logic is almost duplicated above. bool Constant = !Preemptible && !(Config->Pic && !isAbsolute(Body)); if (!Constant) AddDyn({DynType, In::Got, Off, !Preemptible, &Body, 0}); if (Constant || (!RelTy::IsRela && !Preemptible)) In::Got->Relocations.push_back({GotRE, DynType, Off, 0, &Body}); continue; } } } template void scanRelocations(InputSectionBase &S) { if (S.AreRelocsRela) scanRelocs(S, S.relas()); else scanRelocs(S, S.rels()); } template static void createThunks(InputSectionBase &C, ArrayRef Rels) { const elf::ObjectFile *File = C.getFile(); for (const RelTy &Rel : Rels) { SymbolBody &Body = File->getRelocTargetSym(Rel); uint32_t Type = Rel.getType(Config->Mips64EL); RelExpr Expr = Target->getRelExpr(Type, Body); if (!isPreemptible(Body, Type) && needsPlt(Expr)) Expr = fromPlt(Expr); Expr = Target->getThunkExpr(Expr, Type, *File, Body); // Some targets might require creation of thunks for relocations. // Now we support only MIPS which requires LA25 thunk to call PIC // code from non-PIC one, and ARM which requires interworking. if (Expr == R_THUNK_ABS || Expr == R_THUNK_PC || Expr == R_THUNK_PLT_PC) { auto *Sec = cast>(&C); addThunk(Type, Body, *Sec); } } } template void createThunks(InputSectionBase &S) { if (S.AreRelocsRela) createThunks(S, S.relas()); else createThunks(S, S.rels()); } template void scanRelocations(InputSectionBase &); template void scanRelocations(InputSectionBase &); template void scanRelocations(InputSectionBase &); template void scanRelocations(InputSectionBase &); template void createThunks(InputSectionBase &); template void createThunks(InputSectionBase &); template void createThunks(InputSectionBase &); template void createThunks(InputSectionBase &); } }