[WebAssembly] Apply data relocations at runtime in shared objects

See: https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md

Data section relocations in wasm shared libraries are applied by the
library itself at static constructor time.  This change adds a new
synthetic function that applies relocations to relevant memory locations
on startup.

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

llvm-svn: 357715
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 8da52f5..3450c51 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -65,7 +65,9 @@
   uint32_t lookupType(const WasmSignature &Sig);
   uint32_t registerType(const WasmSignature &Sig);
 
-  void createCtorFunction();
+  void createApplyRelocationsFunction();
+  void createCallCtorsFunction();
+
   void calculateInitFunctions();
   void processRelocations(InputChunk *Chunk);
   void assignIndexes();
@@ -1149,17 +1151,6 @@
       File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]);
       File->TypeIsUsed[Reloc.Index] = true;
       break;
-    case R_WASM_MEMORY_ADDR_SLEB:
-    case R_WASM_MEMORY_ADDR_I32:
-    case R_WASM_MEMORY_ADDR_LEB: {
-      DataSymbol *Sym = File->getDataSymbol(Reloc.Index);
-      if (!Config->Relocatable && !isa<DefinedData>(Sym) && !Sym->isWeak())
-        error(File->getName() + ": relocation " +
-              relocTypeToString(Reloc.Type) + " cannot be used againt symbol " +
-              Sym->getName() + "; recompile with -fPIC");
-
-      break;
-    }
     case R_WASM_GLOBAL_INDEX_LEB: {
       auto* Sym = File->getSymbols()[Reloc.Index];
       if (!isa<GlobalSymbol>(Sym) && !Sym->isInGOT()) {
@@ -1168,7 +1159,24 @@
       }
     }
     }
+
+    if (Config->Pic) {
+      // Certain relocation types can't be used when building PIC output, since
+      // they would require absolute symbol addresses at link time.
+      switch (Reloc.Type) {
+      case R_WASM_TABLE_INDEX_SLEB:
+      case R_WASM_MEMORY_ADDR_SLEB:
+      case R_WASM_MEMORY_ADDR_LEB: {
+        Symbol *Sym = File->getSymbols()[Reloc.Index];
+        error(toString(File) + ": relocation " +
+              relocTypeToString(Reloc.Type) + " cannot be used againt symbol " +
+              toString(*Sym) + "; recompile with -fPIC");
+        break;
+      }
+      }
+    }
   }
+
 }
 
 void Writer::assignIndexes() {
@@ -1272,12 +1280,38 @@
   }
 }
 
-static const int OPCODE_CALL = 0x10;
-static const int OPCODE_END = 0xb;
+// For -shared (PIC) output, we create create a synthetic function which will
+// apply any relocations to the data segments on startup.  This function is
+// called __wasm_apply_relocs and is added at the very beginning of
+// __wasm_call_ctors before any of the constructors run.
+void Writer::createApplyRelocationsFunction() {
+  LLVM_DEBUG(dbgs() << "createApplyRelocationsFunction\n");
+  // First write the body's contents to a string.
+  std::string BodyContent;
+  {
+    raw_string_ostream OS(BodyContent);
+    writeUleb128(OS, 0, "num locals");
+    for (const OutputSegment *Seg : Segments)
+      for (const InputSegment *InSeg : Seg->InputSegments)
+        InSeg->generateRelocationCode(OS);
+    writeU8(OS, WASM_OPCODE_END, "END");
+  }
+
+  // Once we know the size of the body we can create the final function body
+  std::string FunctionBody;
+  {
+    raw_string_ostream OS(FunctionBody);
+    writeUleb128(OS, BodyContent.size(), "function size");
+    OS << BodyContent;
+  }
+
+  ArrayRef<uint8_t> Body = arrayRefFromStringRef(Saver.save(FunctionBody));
+  cast<SyntheticFunction>(WasmSym::ApplyRelocs->Function)->setBody(Body);
+}
 
 // Create synthetic "__wasm_call_ctors" function based on ctor functions
 // in input object.
-void Writer::createCtorFunction() {
+void Writer::createCallCtorsFunction() {
   if (!WasmSym::CallCtors->isLive())
     return;
 
@@ -1286,11 +1320,16 @@
   {
     raw_string_ostream OS(BodyContent);
     writeUleb128(OS, 0, "num locals");
+    if (Config->Pic) {
+      writeU8(OS, WASM_OPCODE_CALL, "CALL");
+      writeUleb128(OS, WasmSym::ApplyRelocs->getFunctionIndex(),
+                   "function index");
+    }
     for (const WasmInitEntry &F : InitFunctions) {
-      writeU8(OS, OPCODE_CALL, "CALL");
+      writeU8(OS, WASM_OPCODE_CALL, "CALL");
       writeUleb128(OS, F.Sym->getFunctionIndex(), "function index");
     }
-    writeU8(OS, OPCODE_END, "END");
+    writeU8(OS, WASM_OPCODE_END, "END");
   }
 
   // Once we know the size of the body we can create the final function body
@@ -1348,12 +1387,15 @@
   assignIndexes();
   log("-- calculateInitFunctions");
   calculateInitFunctions();
-  if (!Config->Relocatable)
-    createCtorFunction();
   log("-- calculateTypes");
   calculateTypes();
   log("-- layoutMemory");
   layoutMemory();
+  if (!Config->Relocatable) {
+    if (Config->Pic)
+      createApplyRelocationsFunction();
+    createCallCtorsFunction();
+  }
   log("-- calculateExports");
   calculateExports();
   log("-- calculateCustomSections");