[ELF] Don't emit dynamic relocations with weak undef in writable sections

In processRelocAux(), our handling of 1) link-time constant and 2) weak
undef is the same, so put them together to simplify the logic.

This moves the weak undef code around. The result is that: in a writable
section (or -z notext), we will no longer emit dynamic relocations for
weak undefined symbols.

The new behavior seems to match GNU linkers, and improves consistency
with the case of a readonly section.

The condition `!Config->Shared` was there probably because it is common
for a -shared link not to specify full dependencies. Keep it now but we
may revisit the decision in the future.

gABI says:

> The behavior of weak symbols in areas not specified by this document is
> implementation defined. Weak symbols are intended primarily for use in
> system software. Applications using weak symbols are unreliable since
> changes in the runtime environment might cause the execution to fail.

Reviewed By: ruiu

Differential Revision: https://reviews.llvm.org/D63003

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@363399 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp
index 1398d33..6a1c0fa 100644
--- a/ELF/Relocations.cpp
+++ b/ELF/Relocations.cpp
@@ -924,10 +924,19 @@
 static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type,
                             uint64_t Offset, Symbol &Sym, const RelTy &Rel,
                             int64_t Addend) {
-  if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) {
+  // If the relocation is known to be a link-time constant, we know no dynamic
+  // relocation will be created, pass the control to relocateAlloc() or
+  // relocateNonAlloc() to resolve it.
+  //
+  // The behavior of an undefined weak reference is implementation defined. If
+  // the relocation is to a weak undef, and we are producing an executable, let
+  // relocate{,Non}Alloc() resolve it.
+  if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset) ||
+      (!Config->Shared && Sym.isUndefWeak())) {
     Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
     return;
   }
+
   bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText;
   if (CanWrite) {
     // FIXME Improve the way we handle absolute relocation types that will
@@ -967,13 +976,6 @@
     }
   }
 
-  // If the relocation is to a weak undef, and we are producing
-  // executable, give up on it and produce a non preemptible 0.
-  if (!Config->Shared && Sym.isUndefWeak()) {
-    Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym});
-    return;
-  }
-
   if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) {
     error(
         "can't create dynamic relocation " + toString(Type) + " against " +
diff --git a/test/ELF/weak-undef-rw.s b/test/ELF/weak-undef-rw.s
index c75e7d6..e8d9515 100644
--- a/test/ELF/weak-undef-rw.s
+++ b/test/ELF/weak-undef-rw.s
@@ -1,9 +1,13 @@
 # REQUIRES: x86
 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
 # RUN: ld.lld %t.o -o %t --export-dynamic
-# RUN: llvm-readobj -r %t | FileCheck %s
+# RUN: llvm-readelf -r %t | FileCheck %s
 
-# CHECK: R_X86_64_64 foobar 0x0
+## gABI leaves the behavior of weak undefined references implementation defined.
+## We choose to resolve it statically and not create a dynamic relocation for
+## implementation simplicity. This also matches ld.bfd and gold.
+
+# CHECK: no relocations
 
         .global _start
 _start: