diff options
Diffstat (limited to 'ELF/Relocations.cpp')
-rw-r--r-- | ELF/Relocations.cpp | 112 |
1 files changed, 61 insertions, 51 deletions
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 96e409578f5c..94ea3e1557c4 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -70,12 +70,11 @@ using namespace lld::elf; // >>> defined in /home/alice/src/foo.o // >>> referenced by bar.c:12 (/home/alice/src/bar.c:12) // >>> /home/alice/src/bar.o:(.text+0x1) -template <class ELFT> 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 Src = S.getSrcMsg<ELFT>(Sym, Off); + std::string Src = S.getSrcMsg(Sym, Off); if (!Src.empty()) Msg += Src + "\n>>> "; return Msg + S.getObjMsg(Off); @@ -365,7 +364,6 @@ static bool isRelExpr(RelExpr Expr) { // // If this function returns false, that means we need to emit a // dynamic relocation so that the relocation will be fixed at load-time. -template <class ELFT> static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant @@ -410,7 +408,7 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, return true; error("relocation " + toString(Type) + " cannot refer to absolute symbol: " + - toString(Sym) + getLocation<ELFT>(S, Sym, RelOff)); + toString(Sym) + getLocation(S, Sym, RelOff)); return true; } @@ -443,8 +441,8 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { typedef typename ELFT::Phdr Elf_Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. - const SharedFile<ELFT> *File = SS->getFile<ELFT>(); - for (const Elf_Phdr &Phdr : check(File->getObj().program_headers())) + const SharedFile<ELFT> &File = SS->getFile<ELFT>(); + for (const Elf_Phdr &Phdr : check(File.getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && SS->Value < Phdr.p_vaddr + Phdr.p_memsz) @@ -461,14 +459,14 @@ template <class ELFT> static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { typedef typename ELFT::Sym Elf_Sym; - SharedFile<ELFT> *File = SS->getFile<ELFT>(); + SharedFile<ELFT> &File = SS->getFile<ELFT>(); std::vector<SharedSymbol *> Ret; - for (const Elf_Sym &S : File->getGlobalELFSyms()) { + for (const Elf_Sym &S : File.getGlobalELFSyms()) { if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || S.st_value != SS->Value) continue; - StringRef Name = check(S.getName(File->getStringTable())); + StringRef Name = check(S.getName(File.getStringTable())); Symbol *Sym = Symtab->find(Name); if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) Ret.push_back(Alias); @@ -554,22 +552,57 @@ static void errorOrWarn(const Twine &Msg) { warn(Msg); } +// Returns PLT relocation expression. +// +// 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). +static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) { + Sym.NeedsPltAddr = true; + Sym.IsPreemptible = false; + IsConstant = true; + return toPlt(Expr); +} + template <class ELFT> static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, - InputSectionBase &S, uint64_t RelOff) { + InputSectionBase &S, uint64_t RelOff, + bool &IsConstant) { // We can create any dynamic relocation if a section is simply writable. if (S.Flags & SHF_WRITE) return Expr; // Or, if we are allowed to create dynamic relocations against - // read-only sections (i.e. unless "-z notext" is given), + // read-only sections (i.e. when "-z notext" is given), // we can create a dynamic relocation as we want, too. - if (!Config->ZText) + if (!Config->ZText) { + // We use PLT for relocations that may overflow in runtime, + // see comment for getPltExpr(). + if (Sym.isFunc() && !Target->isPicRel(Type)) + return getPltExpr(Sym, Expr, IsConstant); return Expr; + } // If a relocation can be applied at link-time, we don't need to // create a dynamic relocation in the first place. - if (isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, S, RelOff)) + if (IsConstant) return Expr; // If we got here we know that this relocation would require the dynamic @@ -579,6 +612,7 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, // non preemptible 0. if (Sym.isUndefWeak()) { Sym.IsPreemptible = false; + IsConstant = true; return Expr; } @@ -589,13 +623,13 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, "can't create dynamic relocation " + toString(Type) + " against " + (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + " in readonly segment; recompile object files with -fPIC" + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); return Expr; } if (Sym.getVisibility() != STV_DEFAULT) { error("cannot preempt symbol: " + toString(Sym) + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); return Expr; } @@ -607,38 +641,16 @@ static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, error("unresolvable relocation " + toString(Type) + " against symbol '" + toString(*B) + "'; recompile with -fPIC or remove '-z nocopyreloc'" + - getLocation<ELFT>(S, Sym, RelOff)); + getLocation(S, Sym, RelOff)); addCopyRelSymbol<ELFT>(B); } + IsConstant = true; return Expr; } - if (Sym.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). - Sym.NeedsPltAddr = true; - Sym.IsPreemptible = false; - return toPlt(Expr); - } + if (Sym.isFunc()) + return getPltExpr(Sym, Expr, IsConstant); errorOrWarn("symbol '" + toString(Sym) + "' defined in " + toString(Sym.File) + " has no type"); @@ -708,7 +720,6 @@ static int64_t computeAddend(const RelTy &Rel, const RelTy *End, // Report an undefined symbol if necessary. // Returns true if this function printed out an error message. -template <class ELFT> static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, uint64_t Offset) { if (Config->UnresolvedSymbols == UnresolvedPolicy::IgnoreAll) @@ -725,7 +736,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, std::string Msg = "undefined symbol: " + toString(Sym) + "\n>>> referenced by "; - std::string Src = Sec.getSrcMsg<ELFT>(Sym, Offset); + std::string Src = Sec.getSrcMsg(Sym, Offset); if (!Src.empty()) Msg += Src + "\n>>> "; Msg += Sec.getObjMsg(Offset); @@ -846,7 +857,7 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // // This is ugly -- the difference between REL and RELA should be // handled in a better way. It's a TODO. - if (!Config->IsRela) + if (!Config->IsRela && !Preemptible) InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); } @@ -885,7 +896,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { continue; // Skip if the target symbol is an erroneous undefined symbol. - if (maybeReportUndefined<ELFT>(Sym, Sec, Rel.r_offset)) + if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) continue; RelExpr Expr = @@ -923,7 +934,10 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { else if (!Preemptible) Expr = fromPlt(Expr); - Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset); + bool IsConstant = + isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset); + + Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant); if (errorCount()) continue; @@ -980,7 +994,7 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { errorOrWarn( "relocation " + toString(Type) + " cannot be used against shared object; recompile with -fPIC" + - getLocation<ELFT>(Sec, Sym, Offset)); + getLocation(Sec, Sym, Offset)); InX::RelaDyn->addReloc( {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); @@ -1005,10 +1019,6 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { continue; } - // If the relocation points to something in the file, we can process it. - bool IsConstant = - isStaticLinkTimeConstant<ELFT>(Expr, Type, Sym, Sec, Rel.r_offset); - // The size is not going to change, so we fold it in here. if (Expr == R_SIZE) Addend += Sym.getSize(); |