summaryrefslogtreecommitdiffstats
path: root/lld/ELF/Writer.cpp
diff options
context:
space:
mode:
authorRafael Espindola <rafael.espindola@gmail.com>2016-04-21 16:57:32 +0000
committerRafael Espindola <rafael.espindola@gmail.com>2016-04-21 16:57:32 +0000
commit0c869a752ecb3aa06b4c01d36962bac7a301264e (patch)
treee0c70dfe6324d0be0dc563b1477c3f6f8cef8cf6 /lld/ELF/Writer.cpp
parent358efd65575a142b059da2bee617986ac18d9ec6 (diff)
downloadbcm5719-llvm-0c869a752ecb3aa06b4c01d36962bac7a301264e.tar.gz
bcm5719-llvm-0c869a752ecb3aa06b4c01d36962bac7a301264e.zip
Moves needsPlt to Writer.cpp.
It was only used there. llvm-svn: 267002
Diffstat (limited to 'lld/ELF/Writer.cpp')
-rw-r--r--lld/ELF/Writer.cpp44
1 files changed, 42 insertions, 2 deletions
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index e0ed5264afe..a227cb86923 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -431,6 +431,46 @@ template <class ELFT> static bool isAbsolute(const SymbolBody &Body) {
return false;
}
+namespace {
+enum PltNeed { Plt_No, Plt_Explicit, Plt_Implicit };
+}
+
+static PltNeed needsPlt(uint32_t Type, const SymbolBody &S) {
+ if (S.isGnuIFunc())
+ return Plt_Explicit;
+ if (S.isPreemptible() && Target->needsPlt(Type))
+ return Plt_Explicit;
+
+ // 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 true 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).
+ if (S.isShared() && !Config->Pic && S.isFunc()) {
+ RelExpr Expr = Target->getRelExpr(Type, S);
+ if (!refersToGotEntry(Expr))
+ return Plt_Implicit;
+ }
+
+ return Plt_No;
+}
+
// 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.
@@ -528,9 +568,9 @@ void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &C, ArrayRef<RelTy> Rels) {
// If a relocation needs PLT, we create a PLT and a GOT slot
// for the symbol.
- TargetInfo::PltNeed NeedPlt = Target->needsPlt(Type, Body);
+ PltNeed NeedPlt = needsPlt(Type, Body);
if (NeedPlt) {
- if (NeedPlt == TargetInfo::Plt_Implicit)
+ if (NeedPlt == Plt_Implicit)
Body.NeedsCopyOrPltAddr = true;
RelExpr E;
if (Expr == R_PPC_OPD)
OpenPOWER on IntegriCloud