[WebAssembly] Error on relocations against undefined data symbols.

We can't (currently) meaningfully resolve certain types of relocations
against undefined data symbols.  Previously when `--allow-undefined` was
used we were treating such relocation much like weak data symbols and
simply inserting zeros.  This change turns such use cases in to an
error.

This means that `--allow-undefined` is no longer effective for data
symbols.

Fixes https://bugs.llvm.org/show_bug.cgi?id=40364

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

llvm-svn: 358899
diff --git a/lld/test/wasm/undefined-data.ll b/lld/test/wasm/undefined-data.ll
index 635dccd..c3928bc 100644
--- a/lld/test/wasm/undefined-data.ll
+++ b/lld/test/wasm/undefined-data.ll
@@ -1,6 +1,7 @@
 ; RUN: llc -filetype=obj %s -o %t.o
 ; RUN: not wasm-ld -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=UNDEF
-; RUN: not wasm-ld --shared -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=BADRELOC
+; RUN: not wasm-ld --allow-undefined -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=ALLOW
+; RUN: not wasm-ld --shared -o %t.wasm %t.o 2>&1 | FileCheck %s -check-prefix=SHARED
 
 target triple = "wasm32-unknown-unknown"
 
@@ -13,4 +14,5 @@
 }
 
 ; UNDEF: undefined symbol: data_external
-; BADRELOC: undefined-data.ll.tmp.o: relocation R_WASM_MEMORY_ADDR_LEB cannot be used againt symbol data_external; recompile with -fPIC
+; ALLOW: undefined-data.ll.tmp.o: cannot resolve relocation of type R_WASM_MEMORY_ADDR_LEB against undefined (non-weak) data symbol: data_external
+; SHARED: undefined-data.ll.tmp.o: relocation R_WASM_MEMORY_ADDR_LEB cannot be used againt symbol data_external; recompile with -fPIC
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index 2929379..807651a 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -141,6 +141,30 @@
 
 // Translate from the relocation's index into the final linked output value.
 uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const {
+  const Symbol* Sym = nullptr;
+  if (Reloc.Type != R_WASM_TYPE_INDEX_LEB) {
+    Sym = Symbols[Reloc.Index];
+
+    // We can end up with relocations against non-live symbols.  For example
+    // in debug sections.
+    if ((isa<FunctionSymbol>(Sym) || isa<DataSymbol>(Sym)) && !Sym->isLive())
+      return 0;
+
+    // Special handling for undefined data symbols.  Most relocations against
+    // such symbols cannot be resolved.
+    if (isa<DataSymbol>(Sym) && Sym->isUndefined()) {
+      if (Sym->isWeak() || Config->Relocatable)
+        return 0;
+      if (Config->Shared && Reloc.Type == R_WASM_MEMORY_ADDR_I32)
+        return 0;
+      if (Reloc.Type != R_WASM_GLOBAL_INDEX_LEB) {
+        llvm_unreachable(
+          ("invalid relocation against undefined data symbol: " + toString(*Sym))
+              .c_str());
+      }
+    }
+  }
+
   switch (Reloc.Type) {
   case R_WASM_TABLE_INDEX_I32:
   case R_WASM_TABLE_INDEX_SLEB:
@@ -150,28 +174,22 @@
   case R_WASM_MEMORY_ADDR_I32:
   case R_WASM_MEMORY_ADDR_LEB:
   case R_WASM_MEMORY_ADDR_REL_SLEB:
-    if (auto *Sym = dyn_cast<DefinedData>(getDataSymbol(Reloc.Index)))
-      if (Sym->isLive())
-        return Sym->getVirtualAddress() + Reloc.Addend;
-    return 0;
+    return cast<DefinedData>(Sym)->getVirtualAddress() + Reloc.Addend;
   case R_WASM_TYPE_INDEX_LEB:
     return TypeMap[Reloc.Index];
   case R_WASM_FUNCTION_INDEX_LEB:
     return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
-  case R_WASM_GLOBAL_INDEX_LEB: {
-    const Symbol* Sym = Symbols[Reloc.Index];
+  case R_WASM_GLOBAL_INDEX_LEB:
     if (auto GS = dyn_cast<GlobalSymbol>(Sym))
       return GS->getGlobalIndex();
     return Sym->getGOTIndex();
-  } case R_WASM_EVENT_INDEX_LEB:
+  case R_WASM_EVENT_INDEX_LEB:
     return getEventSymbol(Reloc.Index)->getEventIndex();
-  case R_WASM_FUNCTION_OFFSET_I32:
-    if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) {
-      if (Sym->isLive())
-        return Sym->Function->OutputOffset +
-               Sym->Function->getFunctionCodeOffset() + Reloc.Addend;
-    }
-    return 0;
+  case R_WASM_FUNCTION_OFFSET_I32: {
+    auto *F = cast<DefinedFunction>(Sym);
+    return F->Function->OutputOffset + F->Function->getFunctionCodeOffset() +
+           Reloc.Addend;
+  }
   case R_WASM_SECTION_OFFSET_I32:
     return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend;
   default:
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 6a835ce..d4014d7 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -1170,6 +1170,20 @@
         Sym->setGOTIndex(NumImportedGlobals++);
         GOTSymbols.push_back(Sym);
       }
+      break;
+    }
+    case R_WASM_MEMORY_ADDR_SLEB:
+    case R_WASM_MEMORY_ADDR_LEB:
+    case R_WASM_MEMORY_ADDR_REL_SLEB: {
+      if (!Config->Relocatable) {
+        auto* Sym = File->getSymbols()[Reloc.Index];
+        if (Sym->isUndefined() && !Sym->isWeak()) {
+          error(toString(File) + ": cannot resolve relocation of type " +
+                relocTypeToString(Reloc.Type) +
+                " against undefined (non-weak) data symbol: " + toString(*Sym));
+        }
+      }
+      break;
     }
     }