Index: test/wasm/shared.ll
===================================================================
--- test/wasm/shared.ll
+++ test/wasm/shared.ll
@@ -1,10 +1,11 @@
-; RUN: llc -O0 -filetype=obj %s -o %t.o
+; RUN: llc -relocation-model=pic -filetype=obj %s -o %t.o
 ; RUN: wasm-ld -shared -o %t.wasm %t.o
 ; RUN: obj2yaml %t.wasm | FileCheck %s
 
 target triple = "wasm32-unknown-unknown"
 
 @data = hidden global i32 2, align 4
+@data_external = external global i32
 @indirect_func = local_unnamed_addr global i32 ()* @foo, align 4
 @indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4
 
@@ -13,18 +14,22 @@
   ; To ensure we use __stack_pointer
   %ptr = alloca i32
   %0 = load i32, i32* @data, align 4
-  ; TODO(sbc): Re-enable once the codegen supports generating the correct
-  ; relocation type when referencing external data in shared libraries.
-  ; %1 = load i32, i32* @data_external, align 4
   %1 = load i32 ()*, i32 ()** @indirect_func, align 4
   call i32 %1()
   ret i32 %0
 }
 
-declare void @func_external()
+define default i32* @get_data_address() {
+entry:
+  ret i32* @data_external
+}
 
-@data_external = external global i32
+define default i8* @get_func_address() {
+entry:
+  ret i8* bitcast (void ()* @func_external to i8*)
+}
 
+declare void @func_external()
 
 ; check for dylink section at start
 
@@ -43,6 +48,11 @@
 ; CHECK:        - Type:            IMPORT
 ; CHECK-NEXT:     Imports:
 ; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           memory
+; CHECK-NEXT:         Kind:            MEMORY
+; CHECK-NEXT:         Memory:
+; CHECK-NEXT:           Initial:       0x0000000
+; CHECK-NEXT:       - Module:          env
 ; CHECK-NEXT:         Field:           __indirect_function_table
 ; CHECK-NEXT:         Kind:            TABLE
 ; CHECK-NEXT:         Table:
@@ -64,15 +74,21 @@
 ; CHECK-NEXT:         Kind:            GLOBAL
 ; CHECK-NEXT:         GlobalType:      I32
 ; CHECK-NEXT:         GlobalMutable:   false
-; XCHECK-NEXT:       - Module:          env
-; XCHECK-NEXT:         Field:           data_external
-; XCHECK-NEXT:         Kind:            GLOBAL
-; XCHECK-NEXT:         GlobalType:      I32
-; XCHECK-NEXT:         GlobalMutable:   true
 ; CHECK-NEXT:       - Module:          env
 ; CHECK-NEXT:         Field:           func_external
 ; CHECK-NEXT:         Kind:            FUNCTION
 ; CHECK-NEXT:         SigIndex:        1
+; CHECK-NEXT:       - Module:          GOT.mem
+; CHECK-NEXT:         Field:           data_external
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         GlobalType:      I32
+; CHECK-NEXT:         GlobalMutable:   true
+; CHECK-NEXT:       - Module:          GOT.func
+; CHECK-NEXT:         Field:           func_external
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         GlobalType:      I32
+; CHECK-NEXT:         GlobalMutable:   true
+; CHECK-NEXT:   - Type:            FUNCTION
 
 ; check for elem segment initialized with __table_base global as offset
 
Index: wasm/Driver.cpp
===================================================================
--- wasm/Driver.cpp
+++ wasm/Driver.cpp
@@ -519,6 +519,7 @@
   }
 
   if (Config->Shared) {
+    Config->ImportMemory = true;
     Config->ExportDynamic = true;
     Config->AllowUndefined = true;
   }
Index: wasm/InputChunks.cpp
===================================================================
--- wasm/InputChunks.cpp
+++ wasm/InputChunks.cpp
@@ -74,11 +74,14 @@
 
     if (BytesRead && BytesRead != 5)
       warn("expected LEB at relocation site be 5-byte padded");
-    uint32_t ExpectedValue = File->calcExpectedValue(Rel);
-    if (ExpectedValue != ExistingValue)
-      warn("unexpected existing value for " + reloctTypeToString(Rel.Type) +
-           ": existing=" + Twine(ExistingValue) +
-           " expected=" + Twine(ExpectedValue));
+
+    if (Rel.Type != R_WASM_GLOBAL_INDEX_LEB) {
+      uint32_t ExpectedValue = File->calcExpectedValue(Rel);
+      if (ExpectedValue != ExistingValue)
+        warn("unexpected existing value for " + reloctTypeToString(Rel.Type) +
+             ": existing=" + Twine(ExistingValue) +
+             " expected=" + Twine(ExpectedValue));
+    }
   }
 }
 
Index: wasm/InputFiles.cpp
===================================================================
--- wasm/InputFiles.cpp
+++ wasm/InputFiles.cpp
@@ -152,9 +152,12 @@
     return TypeMap[Reloc.Index];
   case R_WASM_FUNCTION_INDEX_LEB:
     return getFunctionSymbol(Reloc.Index)->getFunctionIndex();
-  case R_WASM_GLOBAL_INDEX_LEB:
-    return getGlobalSymbol(Reloc.Index)->getGlobalIndex();
-  case R_WASM_EVENT_INDEX_LEB:
+  case R_WASM_GLOBAL_INDEX_LEB: {
+    const Symbol* Sym = Symbols[Reloc.Index];
+    if (auto GS = dyn_cast<GlobalSymbol>(Sym))
+      return GS->getGlobalIndex();
+    return Sym->getGOTIndex();
+  } 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))) {
Index: wasm/Symbols.h
===================================================================
--- wasm/Symbols.h
+++ wasm/Symbols.h
@@ -113,6 +113,16 @@
 
   const WasmSignature* getSignature() const;
 
+  bool isInGOT() const { return GOTIndex != INVALID_INDEX; }
+
+  uint32_t getGOTIndex() const {
+    assert(GOTIndex != INVALID_INDEX);
+    return GOTIndex;
+  }
+
+  void setGOTIndex(uint32_t Index);
+  bool hasGOTIndex() const { return GOTIndex != INVALID_INDEX; }
+
 protected:
   Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F)
       : IsUsedInRegularObj(false), ForceExport(false), Traced(false),
@@ -124,6 +134,7 @@
   uint32_t Flags;
   InputFile *File;
   uint32_t OutputSymbolIndex = INVALID_INDEX;
+  uint32_t GOTIndex = INVALID_INDEX;
   bool Referenced;
 };
 
@@ -249,21 +260,6 @@
   static bool classof(const Symbol *S) {
     return S->kind() == UndefinedDataKind;
   }
-
-  // Undefined data symbols are imported as wasm globals so also have a global
-  // index.
-  uint32_t getGlobalIndex() const {
-    assert(GlobalIndex != INVALID_INDEX);
-    return GlobalIndex;
-  }
-  void setGlobalIndex(uint32_t Index) {
-    assert(GlobalIndex == INVALID_INDEX);
-    GlobalIndex = Index;
-  }
-  bool hasGlobalIndex() const { return GlobalIndex != INVALID_INDEX; }
-
-protected:
-  uint32_t GlobalIndex = INVALID_INDEX;
 };
 
 class GlobalSymbol : public Symbol {
Index: wasm/Symbols.cpp
===================================================================
--- wasm/Symbols.cpp
+++ wasm/Symbols.cpp
@@ -93,6 +93,12 @@
   OutputSymbolIndex = Index;
 }
 
+void Symbol::setGOTIndex(uint32_t Index) {
+  LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n");
+  assert(GOTIndex == INVALID_INDEX);
+  GOTIndex = Index;
+}
+
 bool Symbol::isWeak() const {
   return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
 }
Index: wasm/Writer.cpp
===================================================================
--- wasm/Writer.cpp
+++ wasm/Writer.cpp
@@ -118,6 +118,7 @@
   std::vector<const WasmSignature *> Types;
   DenseMap<WasmSignature, int32_t> TypeIndices;
   std::vector<const Symbol *> ImportedSymbols;
+  std::vector<const Symbol *> GOTSymbols;
   unsigned NumImportedFunctions = 0;
   unsigned NumImportedGlobals = 0;
   unsigned NumImportedEvents = 0;
@@ -147,7 +148,7 @@
 } // anonymous namespace
 
 void Writer::createImportSection() {
-  uint32_t NumImports = ImportedSymbols.size();
+  uint32_t NumImports = ImportedSymbols.size() + GOTSymbols.size();
   if (Config->ImportMemory)
     ++NumImports;
   if (Config->ImportTable)
@@ -204,9 +205,6 @@
     if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) {
       Import.Kind = WASM_EXTERNAL_FUNCTION;
       Import.SigIndex = lookupType(*FunctionSym->Signature);
-    } else if (auto *DataSym = dyn_cast<UndefinedData>(Sym)) {
-      Import.Kind = WASM_EXTERNAL_GLOBAL;
-      Import.Global = {WASM_TYPE_I32, true};
     } else if (auto *GlobalSym = dyn_cast<GlobalSymbol>(Sym)) {
       Import.Kind = WASM_EXTERNAL_GLOBAL;
       Import.Global = *GlobalSym->getGlobalType();
@@ -218,6 +216,18 @@
     }
     writeImport(OS, Import);
   }
+
+  for (const Symbol *Sym : GOTSymbols) {
+    WasmImport Import;
+    Import.Kind = WASM_EXTERNAL_GLOBAL;
+    Import.Global = {WASM_TYPE_I32, true};
+    if (isa<DataSymbol>(Sym))
+      Import.Module = "GOT.mem";
+    else
+      Import.Module = "GOT.func";
+    Import.Field = Sym->getName();
+    writeImport(OS, Import);
+  }
 }
 
 void Writer::createTypeSection() {
@@ -957,9 +967,9 @@
       continue;
     if (!Sym->IsUsedInRegularObj)
       continue;
-    // In relocatable output we don't generate imports for data symbols.
-    // These live only in the symbol table.
-    if (Config->Relocatable && isa<DataSymbol>(Sym))
+    // We don't generate imports for data symbols. They however can be imported
+    // as GOT entries.
+    if (isa<DataSymbol>(Sym))
       continue;
 
     LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n");
@@ -968,8 +978,6 @@
       F->setFunctionIndex(NumImportedFunctions++);
     else if (auto *G = dyn_cast<GlobalSymbol>(Sym))
       G->setGlobalIndex(NumImportedGlobals++);
-    else if (auto *D = dyn_cast<UndefinedData>(Sym))
-      D->setGlobalIndex(NumImportedGlobals++);
     else
       cast<EventSymbol>(Sym)->setEventIndex(NumImportedEvents++);
   }
@@ -1145,6 +1153,13 @@
               DataSym->getName());
       break;
     }
+    case R_WASM_GLOBAL_INDEX_LEB: {
+      auto* Sym = File->getSymbols()[Reloc.Index];
+      if (!isa<GlobalSymbol>(Sym) && !Sym->isInGOT()) {
+        Sym->setGOTIndex(NumImportedGlobals++);
+        GOTSymbols.push_back(Sym);
+      }
+    }
     }
   }
 }