Index: lld/trunk/ELF/CMakeLists.txt =================================================================== --- lld/trunk/ELF/CMakeLists.txt +++ lld/trunk/ELF/CMakeLists.txt @@ -14,6 +14,7 @@ LinkerScript.cpp MarkLive.cpp OutputSections.cpp + Relocations.cpp ScriptParser.cpp SymbolListFile.cpp SymbolTable.cpp Index: lld/trunk/ELF/InputSection.h =================================================================== --- lld/trunk/ELF/InputSection.h +++ lld/trunk/ELF/InputSection.h @@ -11,6 +11,7 @@ #define LLD_ELF_INPUT_SECTION_H #include "Config.h" +#include "Relocations.h" #include "lld/Core/LLVM.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" @@ -27,54 +28,6 @@ template class OutputSection; template class OutputSectionBase; -enum RelExpr { - R_ABS, - R_GOT, - R_GOTONLY_PC, - R_GOTREL, - R_GOT_FROM_END, - R_GOT_OFF, - R_GOT_PAGE_PC, - R_GOT_PC, - R_HINT, - R_MIPS_GOT_LOCAL, - R_MIPS_GOT_LOCAL_PAGE, - R_NEG_TLS, - R_PAGE_PC, - R_PC, - R_PLT, - R_PLT_PC, - R_PPC_OPD, - R_PPC_PLT_OPD, - R_PPC_TOC, - R_RELAX_TLS_GD_TO_IE, - R_RELAX_TLS_GD_TO_LE, - R_RELAX_TLS_IE_TO_LE, - R_RELAX_TLS_LD_TO_LE, - R_SIZE, - R_THUNK, - R_TLS, - R_TLSGD, - R_TLSGD_PC, - R_TLSLD, - R_TLSLD_PC -}; - -inline bool refersToGotEntry(RelExpr Expr) { - return Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL || - Expr == R_MIPS_GOT_LOCAL_PAGE || Expr == R_GOT_PAGE_PC || - Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD || - Expr == R_TLSGD_PC; -} - -struct Relocation { - RelExpr Expr; - uint32_t Type; - uint64_t Offset; - uint64_t Addend; - SymbolBody *Sym; -}; - // This corresponds to a section of an input file. template class InputSectionBase { protected: Index: lld/trunk/ELF/Relocations.h =================================================================== --- lld/trunk/ELF/Relocations.h +++ lld/trunk/ELF/Relocations.h @@ -0,0 +1,69 @@ +//===- Relocations.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_RELOCATIONS_H +#define LLD_ELF_RELOCATIONS_H + +#include "lld/Core/LLVM.h" + +namespace lld { +namespace elf { +class SymbolBody; +template class InputSection; +template class InputSectionBase; + +enum RelExpr { + R_ABS, + R_GOT, + R_GOTONLY_PC, + R_GOTREL, + R_GOT_FROM_END, + R_GOT_OFF, + R_GOT_PAGE_PC, + R_GOT_PC, + R_HINT, + R_MIPS_GOT_LOCAL, + R_MIPS_GOT_LOCAL_PAGE, + R_NEG_TLS, + R_PAGE_PC, + R_PC, + R_PLT, + R_PLT_PC, + R_PPC_OPD, + R_PPC_PLT_OPD, + R_PPC_TOC, + R_RELAX_TLS_GD_TO_IE, + R_RELAX_TLS_GD_TO_LE, + R_RELAX_TLS_IE_TO_LE, + R_RELAX_TLS_LD_TO_LE, + R_SIZE, + R_THUNK, + R_TLS, + R_TLSGD, + R_TLSGD_PC, + R_TLSLD, + R_TLSLD_PC +}; + +struct Relocation { + RelExpr Expr; + uint32_t Type; + uint64_t Offset; + uint64_t Addend; + SymbolBody *Sym; +}; + +template void scanRelocations(InputSection &); + +template +void scanRelocations(InputSectionBase &, const typename ELFT::Shdr &); +} +} + +#endif Index: lld/trunk/ELF/Relocations.cpp =================================================================== --- lld/trunk/ELF/Relocations.cpp +++ lld/trunk/ELF/Relocations.cpp @@ -0,0 +1,637 @@ +//===- 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 processe 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 "SymbolTable.h" +#include "Target.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 Expr == R_GOT || Expr == R_GOT_OFF || Expr == R_MIPS_GOT_LOCAL || + Expr == R_MIPS_GOT_LOCAL_PAGE || Expr == R_GOT_PAGE_PC || + Expr == R_GOT_PC || Expr == R_GOT_FROM_END || Expr == R_TLSGD || + Expr == R_TLSGD_PC; +} + +// 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.getSectionHdr()->sh_flags & SHF_ALLOC)) + return 0; + + if (!Body.isTls()) + return 0; + + typedef typename ELFT::uint uintX_t; + 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 (Out::Got->addTlsIndex()) + Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, + Out::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 (Target->isTlsGlobalDynamicRel(Type)) { + if (Config->Shared) { + if (Out::Got->addDynTlsEntry(Body)) { + uintX_t Off = Out::Got->getGlobalDynOffset(Body); + Out::RelaDyn->addReloc( + {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); + Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, + Off + (uintX_t)sizeof(uintX_t), false, + &Body, 0}); + } + 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 (Body.isPreemptible()) { + C.Relocations.push_back( + {R_RELAX_TLS_GD_TO_IE, Type, Offset, Addend, &Body}); + if (!Body.isInGot()) { + Out::Got->addEntry(Body); + Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, + Body.getGotOffset(), false, &Body, + 0}); + } + return 2; + } + C.Relocations.push_back( + {R_RELAX_TLS_GD_TO_LE, Type, Offset, Addend, &Body}); + return Target->TlsGdToLeSkip; + } + + // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally + // defined. + if (Target->isTlsInitialExecRel(Type) && !Config->Shared && + !Body.isPreemptible()) { + C.Relocations.push_back( + {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); + return 1; + } + return 0; +} + +// 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. Scan relocations to find each one requires thunk. +template +static void scanRelocsForThunks(const elf::ObjectFile &File, + ArrayRef Rels) { + for (const RelTy &RI : Rels) { + uint32_t Type = RI.getType(Config->Mips64EL); + SymbolBody &Body = File.getRelocTargetSym(RI); + if (Body.hasThunk() || !Target->needsThunk(Type, File, Body)) + continue; + auto *D = cast>(&Body); + auto *S = cast>(D->Section); + S->addThunk(Body); + } +} + +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); + } + unsigned OldType = Rel->getType(Config->Mips64EL); + StringRef OldName = getELFRelocationTypeName(Config->EMachine, OldType); + StringRef NewName = getELFRelocationTypeName(Config->EMachine, Type); + warning("can't find matching " + NewName + " relocation for " + OldName); + 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; +} + +static bool needsPlt(RelExpr Expr) { + return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT; +} + +// 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 Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC; +} + +template +static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, + const SymbolBody &Body) { + // These expressions always compute a constant + if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || + E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE || + E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || + E == R_TLSGD || E == R_PPC_PLT_OPD) + 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) + return Target->usesOnlyLowPageBits(Type) || !Config->Pic; + + if (Body.isPreemptible()) + return false; + + if (!Config->Pic) + return true; + + bool AbsVal = isAbsolute(Body) || Body.isTls(); + 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. + if (AbsVal && RelE) { + if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) + return true; + StringRef S = getELFRelocationTypeName(Config->EMachine, Type); + error("relocation " + S + " cannot refer to absolute symbol " + + Body.getName()); + 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_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; +} + +// Reserve space in .bss 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 " + SS->getName()); + + uintX_t Align = getAlignment(SS); + uintX_t Off = alignTo(Out::Bss->getSize(), Align); + Out::Bss->setSize(Off + SymSize); + Out::Bss->updateAlign(Align); + 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->getElfSymbols(true)) { + 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->OffsetInBss = Off; + Alias->NeedsCopyOrPltAddr = true; + Alias->symbol()->IsUsedInRegularObj = true; + } + Out::RelaDyn->addReloc( + {Target->CopyRel, Out::Bss, SS->OffsetInBss, false, SS, 0}); +} + +template +static RelExpr adjustExpr(const elf::ObjectFile &File, SymbolBody &Body, + bool IsWrite, RelExpr Expr, uint32_t Type) { + if (Target->needsThunk(Type, File, Body)) + return R_THUNK; + bool Preemptible = Body.isPreemptible(); + if (Body.isGnuIFunc()) + Expr = toPlt(Expr); + else if (needsPlt(Expr) && !Preemptible) + Expr = fromPlt(Expr); + + if (IsWrite || isStaticLinkTimeConstant(Expr, Type, Body)) + 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))) { + StringRef S = getELFRelocationTypeName(Config->EMachine, Type); + error("relocation " + S + " cannot be used when making a shared " + "object; recompile with -fPIC."); + return Expr; + } + if (Body.getVisibility() != STV_DEFAULT) { + error("Cannot preempt symbol"); + 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 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_GOT_OFF) + Addend -= MipsGPOffset; + if (Expr == R_GOTREL) { + Addend -= MipsGPOffset; + if (Body.isLocal()) + Addend += File.getMipsGp0(); + } + } + if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC) + Addend += getPPC64TocBase(); + return Addend; +} + +// 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 +void scanRelocs(InputSectionBase &C, ArrayRef Rels) { + typedef typename ELFT::uint uintX_t; + + uintX_t Flags = C.getSectionHdr()->sh_flags; + bool IsWrite = Flags & SHF_WRITE; + + auto AddDyn = [=](const DynamicReloc &Reloc) { + Out::RelaDyn->addReloc(Reloc); + }; + + const elf::ObjectFile &File = *C.getFile(); + ArrayRef SectionData = C.getSectionData(); + const uint8_t *Buf = SectionData.begin(); + 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); + + RelExpr Expr = Target->getRelExpr(Type, Body); + // Ignore "hint" relocation because it is for optional code optimization. + if (Expr == R_HINT) + continue; + + uintX_t Offset = C.getOffset(RI.r_offset); + if (Offset == (uintX_t)-1) + continue; + + bool Preemptible = Body.isPreemptible(); + Expr = adjustExpr(File, Body, IsWrite, Expr, Type); + if (HasError) + continue; + + // 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_GOTREL || Expr == R_PPC_TOC) + Out::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; + } + + if (needsPlt(Expr) || Expr == R_THUNK || refersToGotEntry(Expr) || + !Body.isPreemptible()) { + // If the relocation points to something in the file, we can process it. + bool Constant = isStaticLinkTimeConstant(Expr, Type, Body); + + // 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.OutSec, 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. + AddDyn({Target->getDynRel(Type), C.OutSec, 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 && !Body.isInGot()) + Out::Got->addEntry(Body); + continue; + } + + if (Expr == R_THUNK) + 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; + Out::Plt->addEntry(Body); + + uint32_t Rel; + if (Body.isGnuIFunc() && !Preemptible) + Rel = Target->IRelativeRel; + else + Rel = Target->PltRel; + + Out::GotPlt->addEntry(Body); + Out::RelaPlt->addReloc({Rel, Out::GotPlt, + Body.getGotPltOffset(), !Preemptible, + &Body, 0}); + continue; + } + + if (refersToGotEntry(Expr)) { + if (Body.isInGot()) + continue; + Out::Got->addEntry(Body); + + if (Config->EMachine == EM_MIPS) + // MIPS ABI has special rules to process GOT entries + // and doesn't require relocation entries for them. + // 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 + continue; + + if (Preemptible || (Config->Pic && !isAbsolute(Body))) { + uint32_t DynType; + if (Body.isTls()) + DynType = Target->TlsGotRel; + else if (Preemptible) + DynType = Target->GotRel; + else + DynType = Target->RelativeRel; + AddDyn({DynType, Out::Got, Body.getGotOffset(), + !Preemptible, &Body, 0}); + } + continue; + } + } + + // Scan relocations for necessary thunks. + if (Config->EMachine == EM_MIPS) + scanRelocsForThunks(File, Rels); +} + +template void scanRelocations(InputSection &C) { + typedef typename ELFT::Shdr Elf_Shdr; + + // Scan all relocations. Each relocation goes through a series + // of tests to determine if it needs special treatment, such as + // creating GOT, PLT, copy relocations, etc. + // Note that relocations for non-alloc sections are directly + // processed by InputSection::relocateNative. + if (C.getSectionHdr()->sh_flags & SHF_ALLOC) + for (const Elf_Shdr *RelSec : C.RelocSections) + scanRelocations(C, *RelSec); +} + +template +void scanRelocations(InputSectionBase &S, + const typename ELFT::Shdr &RelSec) { + ELFFile &EObj = S.getFile()->getObj(); + if (RelSec.sh_type == SHT_RELA) + scanRelocs(S, EObj.relas(&RelSec)); + else + scanRelocs(S, EObj.rels(&RelSec)); +} + +template void scanRelocations(InputSection &); +template void scanRelocations(InputSection &); +template void scanRelocations(InputSection &); +template void scanRelocations(InputSection &); + +template void scanRelocations(InputSectionBase &, + const ELF32LE::Shdr &); +template void scanRelocations(InputSectionBase &, + const ELF32BE::Shdr &); +template void scanRelocations(InputSectionBase &, + const ELF64LE::Shdr &); +template void scanRelocations(InputSectionBase &, + const ELF64BE::Shdr &); +} +} Index: lld/trunk/ELF/Writer.cpp =================================================================== --- lld/trunk/ELF/Writer.cpp +++ lld/trunk/ELF/Writer.cpp @@ -11,13 +11,12 @@ #include "Config.h" #include "LinkerScript.h" #include "OutputSections.h" +#include "Relocations.h" #include "SymbolTable.h" #include "Target.h" -#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/StringSaver.h" #include "llvm/Support/raw_ostream.h" @@ -25,7 +24,6 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; -using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; @@ -270,523 +268,6 @@ }; } -// 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.getSectionHdr()->sh_flags & SHF_ALLOC)) - return 0; - - if (!Body.isTls()) - return 0; - - typedef typename ELFT::uint uintX_t; - 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 (Out::Got->addTlsIndex()) - Out::RelaDyn->addReloc({Target->TlsModuleIndexRel, Out::Got, - Out::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 (Target->isTlsGlobalDynamicRel(Type)) { - if (Config->Shared) { - if (Out::Got->addDynTlsEntry(Body)) { - uintX_t Off = Out::Got->getGlobalDynOffset(Body); - Out::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, Out::Got, Off, false, &Body, 0}); - Out::RelaDyn->addReloc({Target->TlsOffsetRel, Out::Got, - Off + (uintX_t)sizeof(uintX_t), false, - &Body, 0}); - } - 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 (Body.isPreemptible()) { - C.Relocations.push_back( - {R_RELAX_TLS_GD_TO_IE, Type, Offset, Addend, &Body}); - if (!Body.isInGot()) { - Out::Got->addEntry(Body); - Out::RelaDyn->addReloc({Target->TlsGotRel, Out::Got, - Body.getGotOffset(), false, &Body, - 0}); - } - return 2; - } - C.Relocations.push_back( - {R_RELAX_TLS_GD_TO_LE, Type, Offset, Addend, &Body}); - return Target->TlsGdToLeSkip; - } - - // Initial-Exec relocs can be relaxed to Local-Exec if the symbol is locally - // defined. - if (Target->isTlsInitialExecRel(Type) && !Config->Shared && - !Body.isPreemptible()) { - C.Relocations.push_back( - {R_RELAX_TLS_IE_TO_LE, Type, Offset, Addend, &Body}); - return 1; - } - return 0; -} - -// 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. Scan relocations to find each one requires thunk. -template -static void scanRelocsForThunks(const elf::ObjectFile &File, - ArrayRef Rels) { - for (const RelTy &RI : Rels) { - uint32_t Type = RI.getType(Config->Mips64EL); - SymbolBody &Body = File.getRelocTargetSym(RI); - if (Body.hasThunk() || !Target->needsThunk(Type, File, Body)) - continue; - auto *D = cast>(&Body); - auto *S = cast>(D->Section); - S->addThunk(Body); - } -} - -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); - } - unsigned OldType = Rel->getType(Config->Mips64EL); - StringRef OldName = getELFRelocationTypeName(Config->EMachine, OldType); - StringRef NewName = getELFRelocationTypeName(Config->EMachine, Type); - warning("can't find matching " + NewName + " relocation for " + OldName); - 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; -} - -static bool needsPlt(RelExpr Expr) { - return Expr == R_PLT_PC || Expr == R_PPC_PLT_OPD || Expr == R_PLT; -} - -// 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 Expr == R_PC || Expr == R_GOTREL || Expr == R_PAGE_PC; -} - -template -static bool isStaticLinkTimeConstant(RelExpr E, uint32_t Type, - const SymbolBody &Body) { - // These expressions always compute a constant - if (E == R_SIZE || E == R_GOT_FROM_END || E == R_GOT_OFF || - E == R_MIPS_GOT_LOCAL || E == R_MIPS_GOT_LOCAL_PAGE || - E == R_GOT_PAGE_PC || E == R_GOT_PC || E == R_PLT_PC || E == R_TLSGD_PC || - E == R_TLSGD || E == R_PPC_PLT_OPD) - 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) - return Target->usesOnlyLowPageBits(Type) || !Config->Pic; - - if (Body.isPreemptible()) - return false; - - if (!Config->Pic) - return true; - - bool AbsVal = isAbsolute(Body) || Body.isTls(); - 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. - if (AbsVal && RelE) { - if (Body.isUndefined() && !Body.isLocal() && Body.symbol()->isWeak()) - return true; - StringRef S = getELFRelocationTypeName(Config->EMachine, Type); - error("relocation " + S + " cannot refer to absolute symbol " + - Body.getName()); - 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_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 void addCopyRelSymbol(SharedSymbol *SS); - -template -static RelExpr adjustExpr(const elf::ObjectFile &File, SymbolBody &Body, - bool IsWrite, RelExpr Expr, uint32_t Type) { - if (Target->needsThunk(Type, File, Body)) - return R_THUNK; - bool Preemptible = Body.isPreemptible(); - if (Body.isGnuIFunc()) - Expr = toPlt(Expr); - else if (needsPlt(Expr) && !Preemptible) - Expr = fromPlt(Expr); - - if (IsWrite || isStaticLinkTimeConstant(Expr, Type, Body)) - 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))) { - StringRef S = getELFRelocationTypeName(Config->EMachine, Type); - error("relocation " + S + " cannot be used when making a shared " - "object; recompile with -fPIC."); - return Expr; - } - if (Body.getVisibility() != STV_DEFAULT) { - error("Cannot preempt symbol"); - 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 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_GOT_OFF) - Addend -= MipsGPOffset; - if (Expr == R_GOTREL) { - Addend -= MipsGPOffset; - if (Body.isLocal()) - Addend += File.getMipsGp0(); - } - } - if (Config->Pic && Config->EMachine == EM_PPC64 && Type == R_PPC64_TOC) - Addend += getPPC64TocBase(); - return Addend; -} - -// 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 -void scanRelocs(InputSectionBase &C, ArrayRef Rels) { - typedef typename ELFT::uint uintX_t; - - uintX_t Flags = C.getSectionHdr()->sh_flags; - bool IsWrite = Flags & SHF_WRITE; - - auto AddDyn = [=](const DynamicReloc &Reloc) { - Out::RelaDyn->addReloc(Reloc); - }; - - const elf::ObjectFile &File = *C.getFile(); - ArrayRef SectionData = C.getSectionData(); - const uint8_t *Buf = SectionData.begin(); - 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); - - RelExpr Expr = Target->getRelExpr(Type, Body); - // Ignore "hint" relocation because it is for optional code optimization. - if (Expr == R_HINT) - continue; - - uintX_t Offset = C.getOffset(RI.r_offset); - if (Offset == (uintX_t)-1) - continue; - - bool Preemptible = Body.isPreemptible(); - Expr = adjustExpr(File, Body, IsWrite, Expr, Type); - if (HasError) - continue; - - // 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_GOTREL || Expr == R_PPC_TOC) - Out::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; - } - - if (needsPlt(Expr) || Expr == R_THUNK || refersToGotEntry(Expr) || - !Body.isPreemptible()) { - // If the relocation points to something in the file, we can process it. - bool Constant = isStaticLinkTimeConstant(Expr, Type, Body); - - // 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.OutSec, 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. - AddDyn({Target->getDynRel(Type), C.OutSec, 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 && !Body.isInGot()) - Out::Got->addEntry(Body); - continue; - } - - if (Expr == R_THUNK) - 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; - Out::Plt->addEntry(Body); - - uint32_t Rel; - if (Body.isGnuIFunc() && !Preemptible) - Rel = Target->IRelativeRel; - else - Rel = Target->PltRel; - - Out::GotPlt->addEntry(Body); - Out::RelaPlt->addReloc({Rel, Out::GotPlt, - Body.getGotPltOffset(), !Preemptible, - &Body, 0}); - continue; - } - - if (refersToGotEntry(Expr)) { - if (Body.isInGot()) - continue; - Out::Got->addEntry(Body); - - if (Config->EMachine == EM_MIPS) - // MIPS ABI has special rules to process GOT entries - // and doesn't require relocation entries for them. - // 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 - continue; - - if (Preemptible || (Config->Pic && !isAbsolute(Body))) { - uint32_t DynType; - if (Body.isTls()) - DynType = Target->TlsGotRel; - else if (Preemptible) - DynType = Target->GotRel; - else - DynType = Target->RelativeRel; - AddDyn({DynType, Out::Got, Body.getGotOffset(), - !Preemptible, &Body, 0}); - } - continue; - } - } - - // Scan relocations for necessary thunks. - if (Config->EMachine == EM_MIPS) - scanRelocsForThunks(File, Rels); -} - -template -static void scanRelocs(InputSectionBase &S, - const typename ELFT::Shdr &RelSec); - -template static void scanRelocs(InputSection &C) { - typedef typename ELFT::Shdr Elf_Shdr; - - // Scan all relocations. Each relocation goes through a series - // of tests to determine if it needs special treatment, such as - // creating GOT, PLT, copy relocations, etc. - // Note that relocations for non-alloc sections are directly - // processed by InputSection::relocateNative. - if (C.getSectionHdr()->sh_flags & SHF_ALLOC) - for (const Elf_Shdr *RelSec : C.RelocSections) - scanRelocs(C, *RelSec); -} - -template -static void scanRelocs(InputSectionBase &S, - const typename ELFT::Shdr &RelSec) { - ELFFile &EObj = S.getFile()->getObj(); - if (RelSec.sh_type == SHT_RELA) - scanRelocs(S, EObj.relas(&RelSec)); - else - scanRelocs(S, EObj.rels(&RelSec)); -} - template static void reportUndefined(SymbolTable &Symtab, SymbolBody *Sym) { if (!Config->NoUndefined) { @@ -1019,50 +500,6 @@ Out::Bss->setSize(Off); } -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; -} - -// Reserve space in .bss 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 " + SS->getName()); - - uintX_t Align = getAlignment(SS); - uintX_t Off = alignTo(Out::Bss->getSize(), Align); - Out::Bss->setSize(Off + SymSize); - Out::Bss->updateAlign(Align); - 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->getElfSymbols(true)) { - 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->OffsetInBss = Off; - Alias->NeedsCopyOrPltAddr = true; - Alias->symbol()->IsUsedInRegularObj = true; - } - Out::RelaDyn->addReloc( - {Target->CopyRel, Out::Bss, SS->OffsetInBss, false, SS, 0}); -} - template StringRef Writer::getOutputSectionName(InputSectionBase *S) const { StringRef Dest = Script::X->getOutputSection(S); @@ -1355,17 +792,17 @@ for (OutputSectionBase *Sec : OutputSections) { Sec->forEachInputSection([&](InputSectionBase *S) { if (auto *IS = dyn_cast>(S)) { - // Set OutSecOff so that scanRelocs can use it. + // Set OutSecOff so that scanRelocations can use it. uintX_t Off = alignTo(Sec->getSize(), S->Align); IS->OutSecOff = Off; - scanRelocs(*IS); + scanRelocations(*IS); // Now that scan relocs possibly changed the size, update the offset. Sec->setSize(Off + S->getSize()); } else if (auto *EH = dyn_cast>(S)) { if (EH->RelocSection) - scanRelocs(*EH, *EH->RelocSection); + scanRelocations(*EH, *EH->RelocSection); } }); }