Use the plt entry as the address of some symbols.

This is the function equivalent of a copy relocation.

Since functions are expected to change sizes, we cannot use copy
relocations. In situations where one would be needed, what is done
instead is:
* Create a plt entry
* Output an undefined symbol whose addr is the plt entry.

The dynamic linker makes sure any shared library uses the plt entry as
the function address.

llvm-svn: 260224
diff --git a/lld/ELF/OutputSections.cpp b/lld/ELF/OutputSections.cpp
index b179c97..fba6196 100644
--- a/lld/ELF/OutputSections.cpp
+++ b/lld/ELF/OutputSections.cpp
@@ -1328,7 +1328,7 @@
       OutSec = Out<ELFT>::Bss;
       break;
     case SymbolBody::SharedKind: {
-      if (cast<SharedSymbol<ELFT>>(Body)->NeedsCopy)
+      if (cast<SharedSymbol<ELFT>>(Body)->needsCopy())
         OutSec = Out<ELFT>::Bss;
       break;
     }
diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp
index 4b238f8..8b1c70c 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -56,9 +56,12 @@
     return Out<ELFT>::Bss->getVA() + cast<DefinedCommon>(this)->OffsetInBss;
   case SharedKind: {
     auto *SS = cast<SharedSymbol<ELFT>>(this);
-    if (SS->NeedsCopy)
+    if (!SS->NeedsCopyOrPltAddr)
+      return 0;
+    if (SS->IsFunc)
+      return getPltVA<ELFT>();
+    else
       return Out<ELFT>::Bss->getVA() + SS->OffsetInBss;
-    return 0;
   }
   case UndefinedElfKind:
   case UndefinedKind:
diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 84b880f..53f5d53 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -130,7 +130,8 @@
   SymbolBody(Kind K, StringRef Name, bool IsWeak, uint8_t Visibility,
              bool IsTls, bool IsFunc)
       : SymbolKind(K), IsWeak(IsWeak), Visibility(Visibility),
-        MustBeInDynSym(false), IsTls(IsTls), IsFunc(IsFunc), Name(Name) {
+        MustBeInDynSym(false), NeedsCopyOrPltAddr(false), IsTls(IsTls),
+        IsFunc(IsFunc), Name(Name) {
     IsUsedInRegularObj = K != SharedKind && K != LazyKind;
   }
 
@@ -148,9 +149,14 @@
   // If true, the symbol is added to .dynsym symbol table.
   unsigned MustBeInDynSym : 1;
 
+  // True if the linker has to generate a copy relocation for this shared
+  // symbol or if the symbol should point to its plt entry.
+  unsigned NeedsCopyOrPltAddr : 1;
+
 protected:
   unsigned IsTls : 1;
   unsigned IsFunc : 1;
+
   StringRef Name;
   Symbol *Backref = nullptr;
 };
@@ -280,10 +286,10 @@
 
   SharedFile<ELFT> *File;
 
-  // True if the linker has to generate a copy relocation for this shared
-  // symbol. OffsetInBss is significant only when NeedsCopy is true.
-  bool NeedsCopy = false;
+  // OffsetInBss is significant only when needsCopy() is true.
   uintX_t OffsetInBss = 0;
+
+  bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->IsFunc; }
 };
 
 // This class represents a symbol defined in an archive file. It is
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp
index 70edfd3..0352c79 100644
--- a/lld/ELF/Target.cpp
+++ b/lld/ELF/Target.cpp
@@ -90,8 +90,8 @@
                 int32_t Index, unsigned RelOff) const override;
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
   bool needsDynRelative(unsigned Type) const override;
-  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
-  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+  bool needsGot(uint32_t Type, SymbolBody &S) const override;
+  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
                    uint64_t SA, uint64_t ZA = 0,
                    uint8_t *PairedLoc = nullptr) const override;
@@ -121,8 +121,8 @@
   void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
                 int32_t Index, unsigned RelOff) const override;
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
-  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
-  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+  bool needsGot(uint32_t Type, SymbolBody &S) const override;
+  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
                    uint64_t SA, uint64_t ZA = 0,
                    uint8_t *PairedLoc = nullptr) const override;
@@ -157,8 +157,8 @@
   PPC64TargetInfo();
   void writePlt(uint8_t *Buf, uint64_t GotEntryAddr, uint64_t PltEntryAddr,
                 int32_t Index, unsigned RelOff) const override;
-  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
-  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+  bool needsGot(uint32_t Type, SymbolBody &S) const override;
+  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
                    uint64_t SA, uint64_t ZA = 0,
                    uint8_t *PairedLoc = nullptr) const override;
@@ -176,8 +176,8 @@
   unsigned getTlsGotRel(unsigned Type = -1) const override;
   bool isTlsDynRel(unsigned Type, const SymbolBody &S) const override;
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
-  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
-  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+  bool needsGot(uint32_t Type, SymbolBody &S) const override;
+  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
                    uint64_t SA, uint64_t ZA = 0,
                    uint8_t *PairedLoc = nullptr) const override;
@@ -197,8 +197,8 @@
   unsigned getDynRel(unsigned Type) const override;
   void writeGotHeader(uint8_t *Buf) const override;
   bool needsCopyRel(uint32_t Type, const SymbolBody &S) const override;
-  bool needsGot(uint32_t Type, const SymbolBody &S) const override;
-  bool needsPlt(uint32_t Type, const SymbolBody &S) const override;
+  bool needsGot(uint32_t Type, SymbolBody &S) const override;
+  bool needsPlt(uint32_t Type, SymbolBody &S) const override;
   void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type, uint64_t P,
                    uint64_t SA, uint64_t ZA = 0,
                    uint8_t *PairedLoc = nullptr) const override;
@@ -263,13 +263,9 @@
 bool TargetInfo::isRelRelative(uint32_t Type) const { return true; }
 bool TargetInfo::isSizeRel(uint32_t Type) const { return false; }
 
-bool TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
-  return false;
-}
+bool TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const { return false; }
 
-bool TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
-  return false;
-}
+bool TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const { return false; }
 
 unsigned TargetInfo::relaxTls(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
                               uint64_t P, uint64_t SA,
@@ -376,7 +372,7 @@
   return false;
 }
 
-bool X86TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool X86TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
   if (S.isTls() && Type == R_386_TLS_GD)
     return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
   if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
@@ -384,7 +380,7 @@
   return Type == R_386_GOT32 || needsPlt(Type, S);
 }
 
-bool X86TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool X86TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
   return isGnuIFunc<ELF32LE>(S) ||
          (Type == R_386_PLT32 && canBePreempted(&S, true)) ||
          (Type == R_386_PC32 && S.isShared());
@@ -646,7 +642,7 @@
   return false;
 }
 
-bool X86_64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool X86_64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
   if (Type == R_X86_64_TLSGD)
     return Target->canRelaxTls(Type, &S) && canBePreempted(&S, true);
   if (Type == R_X86_64_GOTTPOFF)
@@ -658,7 +654,7 @@
   return Type == R_X86_64_GOTTPOFF || Type == R_X86_64_TLSGD;
 }
 
-bool X86_64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool X86_64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
   if (needsCopyRel(Type, S))
     return false;
   if (isGnuIFunc<ELF64LE>(S))
@@ -684,17 +680,19 @@
     // For the static linking part, we just return true and everything else
     // will use the the PLT entry as the address.
     //
-    // The remaining (unimplemented) 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,
+    // 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).
-    return S.isShared();
+    if (!S.isShared())
+      return false;
+    S.NeedsCopyOrPltAddr = true;
+    return true;
   case R_X86_64_PLT32:
     return canBePreempted(&S, true);
   }
@@ -989,7 +987,7 @@
   write32be(Buf + 28, 0x4e800420);                   // bctr
 }
 
-bool PPC64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool PPC64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
   if (needsPlt(Type, S))
     return true;
 
@@ -1005,7 +1003,7 @@
   }
 }
 
-bool PPC64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool PPC64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
   // These are function calls that need to be redirected through a PLT stub.
   return Type == R_PPC64_REL24 && canBePreempted(&S, false);
 }
@@ -1240,7 +1238,7 @@
   }
 }
 
-bool AArch64TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool AArch64TargetInfo::needsGot(uint32_t Type, SymbolBody &S) const {
   switch (Type) {
   case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
   case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
@@ -1252,7 +1250,7 @@
   }
 }
 
-bool AArch64TargetInfo::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool AArch64TargetInfo::needsPlt(uint32_t Type, SymbolBody &S) const {
   if (isGnuIFunc<ELF64LE>(S))
     return true;
   switch (Type) {
@@ -1439,12 +1437,12 @@
 }
 
 template <class ELFT>
-bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, const SymbolBody &S) const {
+bool MipsTargetInfo<ELFT>::needsGot(uint32_t Type, SymbolBody &S) const {
   return Type == R_MIPS_GOT16 || Type == R_MIPS_CALL16;
 }
 
 template <class ELFT>
-bool MipsTargetInfo<ELFT>::needsPlt(uint32_t Type, const SymbolBody &S) const {
+bool MipsTargetInfo<ELFT>::needsPlt(uint32_t Type, SymbolBody &S) const {
   return false;
 }
 
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index 2f9cd3a..6655cf5 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -54,8 +54,8 @@
 
   virtual bool isSizeRel(uint32_t Type) const;
   virtual bool needsDynRelative(unsigned Type) const { return false; }
-  virtual bool needsGot(uint32_t Type, const SymbolBody &S) const;
-  virtual bool needsPlt(uint32_t Type, const SymbolBody &S) const;
+  virtual bool needsGot(uint32_t Type, SymbolBody &S) const;
+  virtual bool needsPlt(uint32_t Type, SymbolBody &S) const;
   virtual void relocateOne(uint8_t *Loc, uint8_t *BufEnd, uint32_t Type,
                            uint64_t P, uint64_t SA, uint64_t ZA = 0,
                            uint8_t *PairedLoc = nullptr) const = 0;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 71d774b..c86c0ad 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -302,10 +302,10 @@
     // If a symbol in a DSO is referenced directly instead of through GOT,
     // we need to create a copy relocation for the symbol.
     if (auto *B = dyn_cast_or_null<SharedSymbol<ELFT>>(Body)) {
-      if (B->NeedsCopy)
+      if (B->needsCopy())
         continue;
       if (Target->needsCopyRel(Type, *B)) {
-        B->NeedsCopy = true;
+        B->NeedsCopyOrPltAddr = true;
         Out<ELFT>::RelaDyn->addReloc(
             {Target->CopyRel, DynamicReloc<ELFT>::Off_Bss, B});
         continue;
@@ -968,7 +968,7 @@
     if (auto *C = dyn_cast<DefinedCommon>(Body))
       CommonSymbols.push_back(C);
     if (auto *SC = dyn_cast<SharedSymbol<ELFT>>(Body))
-      if (SC->NeedsCopy)
+      if (SC->needsCopy())
         CopyRelSymbols.push_back(SC);
 
     if (!includeInSymtab<ELFT>(*Body))
diff --git a/lld/test/ELF/Inputs/undef-with-plt-addr.s b/lld/test/ELF/Inputs/undef-with-plt-addr.s
new file mode 100644
index 0000000..158e637
--- /dev/null
+++ b/lld/test/ELF/Inputs/undef-with-plt-addr.s
@@ -0,0 +1,4 @@
+	.globl	set_data
+	.type	set_data,@function
+set_data:
+	retq
diff --git a/lld/test/ELF/symbol-override.s b/lld/test/ELF/symbol-override.s
index ae21149..487885b 100644
--- a/lld/test/ELF/symbol-override.s
+++ b/lld/test/ELF/symbol-override.s
@@ -43,4 +43,4 @@
 .text
 .globl _start
 _start:
-callq do
+callq do@plt
diff --git a/lld/test/ELF/undef-with-plt-addr.s b/lld/test/ELF/undef-with-plt-addr.s
new file mode 100644
index 0000000..89a85df
--- /dev/null
+++ b/lld/test/ELF/undef-with-plt-addr.s
@@ -0,0 +1,23 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/undef-with-plt-addr.s -o %t2.o
+// RUN: ld.lld %t2.o -o %t2.so -shared
+// RUN: ld.lld %t.o %t2.so -o %t3
+// RUN: llvm-readobj -t -s %t3 | FileCheck %s
+
+.globl _start
+_start:
+movabsq	$set_data, %rax
+
+// Test that set_data has an address in the .plt
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x11010
+
+// CHECK:      Name:    set_data
+// CHECK-NEXT: Value:   0x11020