diff --git a/lld/test/wasm/Inputs/tag-section1.ll b/lld/test/wasm/Inputs/tag-section1.ll
--- a/lld/test/wasm/Inputs/tag-section1.ll
+++ b/lld/test/wasm/Inputs/tag-section1.ll
@@ -1,5 +1,5 @@
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-emscripten"
 
 declare void @llvm.wasm.throw(i32, i8*)
 
diff --git a/lld/test/wasm/Inputs/tag-section2.ll b/lld/test/wasm/Inputs/tag-section2.ll
--- a/lld/test/wasm/Inputs/tag-section2.ll
+++ b/lld/test/wasm/Inputs/tag-section2.ll
@@ -1,5 +1,5 @@
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-emscripten"
 
 declare void @llvm.wasm.throw(i32, i8*)
 
diff --git a/lld/test/wasm/tag-section.ll b/lld/test/wasm/tag-section.ll
--- a/lld/test/wasm/tag-section.ll
+++ b/lld/test/wasm/tag-section.ll
@@ -1,13 +1,21 @@
+; Static code
 ; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling %p/Inputs/tag-section1.ll -o %t1.o
 ; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling %p/Inputs/tag-section2.ll -o %t2.o
 ; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling %s -o %t.o
 ; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o
 ; RUN: wasm-ld --export-all -o %t-export-all.wasm %t.o %t1.o %t2.o
-; RUN: obj2yaml %t.wasm | FileCheck %s
-; RUN: obj2yaml %t-export-all.wasm | FileCheck %s --check-prefix=EXPORT-ALL
+; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefix=NOPIC
+; RUN: obj2yaml %t-export-all.wasm | FileCheck %s --check-prefix=NOPIC-EXPORT-ALL
+
+; PIC code
+; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic %p/Inputs/tag-section1.ll -o %t1.o
+; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic %p/Inputs/tag-section2.ll -o %t2.o
+; RUN: llc -filetype=obj -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic %s -o %t.o
+; RUN: wasm-ld --import-undefined --experimental-pic -pie -o %t.wasm %t.o %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s --check-prefix=PIC
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-emscripten"
 
 declare void @foo(i8*)
 declare void @bar(i8*)
@@ -18,25 +26,47 @@
   ret void
 }
 
-; CHECK:      Sections:
-; CHECK-NEXT:   - Type:            TYPE
-; CHECK-NEXT:     Signatures:
-; CHECK-NEXT:       - Index:           0
-; CHECK-NEXT:         ParamTypes:      []
-; CHECK-NEXT:         ReturnTypes:     []
-; CHECK-NEXT:       - Index:           1
-; CHECK-NEXT:         ParamTypes:
-; CHECK-NEXT:           - I32
-; CHECK-NEXT:         ReturnTypes:     []
+; NOPIC:      Sections:
+; NOPIC-NEXT:   - Type:            TYPE
+; NOPIC-NEXT:     Signatures:
+; NOPIC-NEXT:       - Index:           0
+; NOPIC-NEXT:         ParamTypes:      []
+; NOPIC-NEXT:         ReturnTypes:     []
+; NOPIC-NEXT:       - Index:           1
+; NOPIC-NEXT:         ParamTypes:
+; NOPIC-NEXT:           - I32
+; NOPIC-NEXT:         ReturnTypes:     []
 
-; CHECK:        - Type:            TAG
-; CHECK-NEXT:     TagTypes:        [ 1 ]
+; NOPIC:        - Type:            TAG
+; NOPIC-NEXT:     TagTypes:        [ 1 ]
 
 ; Global section has to come after tag section
-; CHECK:        - Type:            GLOBAL
+; NOPIC:        - Type:            GLOBAL
+
+; NOPIC-EXPORT-ALL:   - Type:            EXPORT
+; NOPIC-EXPORT-ALL-NEXT Exports:
+; NOPIC-EXPORT-ALL:       - Name:            __cpp_exception
+; NOPIC-EXPORT-ALL:         Kind:            TAG
+; NOPIC-EXPORT-ALL:         Index:           0
+
+; In PIC mode, tags are undefined and imported from JS.
+; PIC:        Sections:
+; PIC:         - Type:            TYPE
+; PIC-NEXT:      Signatures:
+; PIC-NEXT:        - Index:           0
+; PIC-NEXT:          ParamTypes:
+; PIC-NEXT:            - I32
+; PIC-NEXT:          ReturnTypes:     []
+; PIC-NEXT:        - Index:           1
+; PIC-NEXT:          ParamTypes:      []
+; PIC-NEXT:          ReturnTypes:     []
+
+; PIC:         - Type:            IMPORT
+; PIC-NEXT:      Imports:
+; PIC:             - Module:          env
+; PIC:               Field:           __cpp_exception
+; PIC-NEXT:          Kind:            TAG
+; PIC-NEXT:          SigIndex:        0
 
-; EXPORT-ALL:   - Type:            EXPORT
-; EXPORT-ALL-NEXT Exports:
-; EXPORT-ALL:       - Name:            __cpp_exception
-; EXPORT-ALL:         Kind:            TAG
-; EXPORT-ALL:         Index:           0
+; In PIC mode, tags should NOT be defined in the module; they are imported.
+; PIC-NOT:     - Type:            TAG
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -663,6 +663,14 @@
     return symtab->addUndefinedTable(name, sym.Info.ImportName,
                                      sym.Info.ImportModule, flags, this,
                                      sym.TableType);
+  case WASM_SYMBOL_TYPE_TAG:
+    if (sym.isBindingLocal())
+      return make<UndefinedTag>(name, sym.Info.ImportName,
+                                sym.Info.ImportModule, flags, this,
+                                sym.Signature);
+    return symtab->addUndefinedTag(name, sym.Info.ImportName,
+                                   sym.Info.ImportModule, flags, this,
+                                   sym.Signature);
   case WASM_SYMBOL_TYPE_SECTION:
     llvm_unreachable("section symbols cannot be undefined");
   }
diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h
--- a/lld/wasm/SymbolTable.h
+++ b/lld/wasm/SymbolTable.h
@@ -79,6 +79,10 @@
                             llvm::Optional<StringRef> importModule,
                             uint32_t flags, InputFile *file,
                             const WasmTableType *type);
+  Symbol *addUndefinedTag(StringRef name, llvm::Optional<StringRef> importName,
+                          llvm::Optional<StringRef> importModule,
+                          uint32_t flags, InputFile *file,
+                          const WasmSignature *sig);
 
   TableSymbol *resolveIndirectFunctionTable(bool required);
 
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -625,6 +625,30 @@
   return s;
 }
 
+Symbol *SymbolTable::addUndefinedTag(StringRef name,
+                                     Optional<StringRef> importName,
+                                     Optional<StringRef> importModule,
+                                     uint32_t flags, InputFile *file,
+                                     const WasmSignature *sig) {
+  LLVM_DEBUG(dbgs() << "addUndefinedTag: " << name << "\n");
+  assert(flags & WASM_SYMBOL_UNDEFINED);
+
+  Symbol *s;
+  bool wasInserted;
+  std::tie(s, wasInserted) = insert(name, file);
+  if (s->traced)
+    printTraceSymbolUndefined(name, file);
+
+  if (wasInserted)
+    replaceSymbol<UndefinedTag>(s, name, importName, importModule, flags, file,
+                                sig);
+  else if (auto *lazy = dyn_cast<LazySymbol>(s))
+    lazy->fetch();
+  else if (s->isDefined())
+    checkTagType(s, file, sig);
+  return s;
+}
+
 TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) {
   WasmLimits limits{0, 0, 0}; // Set by the writer.
   WasmTableType *type = make<WasmTableType>();
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -55,6 +55,7 @@
     UndefinedDataKind,
     UndefinedGlobalKind,
     UndefinedTableKind,
+    UndefinedTagKind,
     LazyKind,
   };
 
@@ -66,7 +67,7 @@
     return symbolKind == UndefinedFunctionKind ||
            symbolKind == UndefinedDataKind ||
            symbolKind == UndefinedGlobalKind ||
-           symbolKind == UndefinedTableKind;
+           symbolKind == UndefinedTableKind || symbolKind == UndefinedTagKind;
   }
 
   bool isLazy() const { return symbolKind == LazyKind; }
@@ -437,7 +438,9 @@
 // and is named '__cpp_exception' for linking.
 class TagSymbol : public Symbol {
 public:
-  static bool classof(const Symbol *s) { return s->kind() == DefinedTagKind; }
+  static bool classof(const Symbol *s) {
+    return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind;
+  }
 
   // Get/set the tag index
   uint32_t getTagIndex() const;
@@ -463,6 +466,19 @@
   InputTag *tag;
 };
 
+class UndefinedTag : public TagSymbol {
+public:
+  UndefinedTag(StringRef name, llvm::Optional<StringRef> importName,
+               llvm::Optional<StringRef> importModule, uint32_t flags,
+               InputFile *file = nullptr, const WasmSignature *sig = nullptr)
+      : TagSymbol(name, UndefinedTagKind, flags, file, sig) {
+    this->importName = importName;
+    this->importModule = importModule;
+  }
+
+  static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; }
+};
+
 // LazySymbol represents a symbol that is not yet in the link, but we know where
 // to find it if needed. If the resolver finds both Undefined and Lazy for the
 // same name, it will ask the Lazy to load a file.
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -58,6 +58,8 @@
     return "UndefinedGlobal";
   case wasm::Symbol::UndefinedTableKind:
     return "UndefinedTable";
+  case wasm::Symbol::UndefinedTagKind:
+    return "UndefinedTag";
   case wasm::Symbol::LazyKind:
     return "LazyKind";
   case wasm::Symbol::SectionKind:
@@ -113,6 +115,8 @@
 const WasmSignature *Symbol::getSignature() const {
   if (auto* f = dyn_cast<FunctionSymbol>(this))
     return f->signature;
+  if (auto *t = dyn_cast<TagSymbol>(this))
+    return t->signature;
   if (auto *l = dyn_cast<LazySymbol>(this))
     return l->signature;
   return nullptr;
diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h
--- a/lld/wasm/SyntheticSections.h
+++ b/lld/wasm/SyntheticSections.h
@@ -198,6 +198,7 @@
   llvm::DenseMap<ImportKey<WasmGlobalType>, uint32_t> importedGlobals;
   llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedFunctions;
   llvm::DenseMap<ImportKey<WasmTableType>, uint32_t> importedTables;
+  llvm::DenseMap<ImportKey<WasmSignature>, uint32_t> importedTags;
 };
 
 class FunctionSection : public SyntheticSection {
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -170,10 +170,14 @@
       g->setGlobalIndex(entry.first->second);
     }
   } else if (auto *t = dyn_cast<TagSymbol>(sym)) {
-    // NB: There's currently only one possible kind of tag, and no
-    // `UndefinedTag`, so we don't bother de-duplicating tag imports.
-    importedSymbols.emplace_back(sym);
-    t->setTagIndex(numImportedTags++);
+    ImportKey<WasmSignature> key(*(t->getSignature()), module, name);
+    auto entry = importedTags.try_emplace(key, numImportedTags);
+    if (entry.second) {
+      importedSymbols.emplace_back(sym);
+      t->setTagIndex(numImportedTags++);
+    } else {
+      t->setTagIndex(entry.first->second);
+    }
   } else {
     assert(TableSymbol::classof(sym));
     auto *table = cast<TableSymbol>(sym);
diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
--- a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp
@@ -23,12 +23,19 @@
   // the symbols has already been created, i.e., we have at least one 'throw' or
   // 'catch' instruction with the symbol in the module, and emit the symbol only
   // if so.
-  for (const char *SymName : {"__cpp_exception", "__c_longjmp"}) {
-    SmallString<60> NameStr;
-    Mangler::getNameWithPrefix(NameStr, SymName, Asm->getDataLayout());
-    if (Asm->OutContext.lookupSymbol(NameStr)) {
-      MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol(SymName);
-      Asm->OutStreamer->emitLabel(ExceptionSym);
+  //
+  // But in dynamic linking, it is in general not possible to come up with a
+  // module instantiating order in which tag-defining modules are loaded before
+  // the importing modules. So we make them undefined symbols here, define tags
+  // in the JS side, and feed them to each importing module.
+  if (!Asm->isPositionIndependent()) {
+    for (const char *SymName : {"__cpp_exception", "__c_longjmp"}) {
+      SmallString<60> NameStr;
+      Mangler::getNameWithPrefix(NameStr, SymName, Asm->getDataLayout());
+      if (Asm->OutContext.lookupSymbol(NameStr)) {
+        MCSymbol *ExceptionSym = Asm->GetExternalSymbolSymbol(SymName);
+        Asm->OutStreamer->emitLabel(ExceptionSym);
+      }
     }
   }
 }
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -1124,6 +1124,9 @@
     }
     case wasm::WASM_EXTERNAL_TAG:
       NumImportedTags++;
+      if (readUint8(Ctx) != 0) // Reserved 'attribute' field
+        return make_error<GenericBinaryError>("invalid attribute",
+                                              object_error::parse_failed);
       Im.SigIndex = readVaruint32(Ctx);
       if (Im.SigIndex >= NumTypes)
         return make_error<GenericBinaryError>("invalid tag type",
@@ -1203,8 +1206,7 @@
   Tags.reserve(Count);
   uint32_t NumTypes = Signatures.size();
   while (Count--) {
-    char Attr = readUint8(Ctx); // Reserved 'attribute' field
-    if (Attr != 0)
+    if (readUint8(Ctx) != 0) // Reserved 'attribute' field
       return make_error<GenericBinaryError>("invalid attribute",
                                             object_error::parse_failed);
     uint32_t Type = readVaruint32(Ctx);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -234,14 +234,22 @@
     return WasmSym;
   }
 
+  if (Name.startswith("GCC_except_table")) {
+    WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);
+    return WasmSym;
+  }
+
   SmallVector<wasm::ValType, 4> Returns;
   SmallVector<wasm::ValType, 4> Params;
   if (Name == "__cpp_exception" || Name == "__c_longjmp") {
     WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TAG);
-    // We may have multiple C++ compilation units to be linked together, each of
-    // which defines the exception symbol. To resolve them, we declare them as
-    // weak.
-    WasmSym->setWeak(true);
+    // In static linking we define tag symbols in WasmException::endModule().
+    // But we may have multiple objects to be linked together, each of which
+    // defines the tag symbols. To resolve them, we declare them as weak. In
+    // dynamic linking we make tag symbols undefined in the backend, define it
+    // in JS, and feed them to each importing module.
+    if (!isPositionIndependent())
+      WasmSym->setWeak(true);
     WasmSym->setExternal(true);
 
     // Currently both C++ exceptions and C longjmps have a single pointer type
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1751,14 +1751,22 @@
     return SDValue(); // Don't custom lower most intrinsics.
 
   case Intrinsic::wasm_lsda: {
-    EVT VT = Op.getValueType();
-    const TargetLowering &TLI = DAG.getTargetLoweringInfo();
-    MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout());
-    auto &Context = MF.getMMI().getContext();
-    MCSymbol *S = Context.getOrCreateSymbol(Twine("GCC_except_table") +
-                                            Twine(MF.getFunctionNumber()));
-    return DAG.getNode(WebAssemblyISD::Wrapper, DL, VT,
-                       DAG.getMCSymbol(S, PtrVT));
+    auto PtrVT = getPointerTy(MF.getDataLayout());
+    const char *SymName = MF.createExternalSymbolName(
+        "GCC_except_table" + std::to_string(MF.getFunctionNumber()));
+    if (isPositionIndependent()) {
+      SDValue Node = DAG.getTargetExternalSymbol(
+          SymName, PtrVT, WebAssemblyII::MO_MEMORY_BASE_REL);
+      const char *BaseName = MF.createExternalSymbolName("__memory_base");
+      SDValue BaseAddr =
+          DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT,
+                      DAG.getTargetExternalSymbol(BaseName, PtrVT));
+      SDValue SymAddr =
+          DAG.getNode(WebAssemblyISD::WrapperREL, DL, PtrVT, Node);
+      return DAG.getNode(ISD::ADD, DL, PtrVT, BaseAddr, SymAddr);
+    }
+    SDValue Node = DAG.getTargetExternalSymbol(SymName, PtrVT);
+    return DAG.getNode(WebAssemblyISD::Wrapper, DL, PtrVT, Node);
   }
 
   case Intrinsic::wasm_shuffle: {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -417,8 +417,10 @@
 def : Pat<(i64 (WebAssemblyWrapper texternalsym:$addr)),
           (CONST_I64 texternalsym:$addr)>, Requires<[IsNotPIC, HasAddr64]>;
 
-def : Pat<(i32 (WebAssemblyWrapper mcsym:$sym)), (CONST_I32 mcsym:$sym)>;
-def : Pat<(i64 (WebAssemblyWrapper mcsym:$sym)), (CONST_I64 mcsym:$sym)>;
+def : Pat<(i32 (WebAssemblyWrapperREL texternalsym:$addr)),
+          (CONST_I32 texternalsym:$addr)>, Requires<[IsPIC, HasAddr32]>;
+def : Pat<(i64 (WebAssemblyWrapperREL texternalsym:$addr)),
+          (CONST_I64 texternalsym:$addr)>, Requires<[IsPIC, HasAddr64]>;
 
 //===----------------------------------------------------------------------===//
 // Additional sets of instructions.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -278,15 +278,9 @@
       MCOp = lowerSymbolOperand(MO, GetGlobalAddressSymbol(MO));
       break;
     case MachineOperand::MO_ExternalSymbol:
-      // The target flag indicates whether this is a symbol for a
-      // variable or a function.
-      assert(MO.getTargetFlags() == 0 &&
-             "WebAssembly uses only symbol flags on ExternalSymbols");
       MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO));
       break;
     case MachineOperand::MO_MCSymbol:
-      // This is currently used only for LSDA symbols (GCC_except_table),
-      // because global addresses or other external symbols are handled above.
       assert(MO.getTargetFlags() == 0 &&
              "WebAssembly does not use target flags on MCSymbol");
       MCOp = lowerSymbolOperand(MO, MO.getMCSymbol());
diff --git a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
--- a/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
+++ b/llvm/test/CodeGen/WebAssembly/eh-lsda.ll
@@ -1,6 +1,9 @@
-; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck -allow-deprecated-dag-overlap %s
-
-target triple = "wasm32-unknown-unknown"
+; RUN: llc < %s --mtriple=wasm32-unknown-unknown -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=32
+; RUN: llc < %s --mtriple=wasm64-unknown-unknown -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=64
+; RUN: llc < %s --mtriple=wasm32-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=32
+; RUN: llc < %s --mtriple=wasm64-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling | FileCheck %s -check-prefixes=CHECK,NOPIC -DPTR=64
+; RUN: llc < %s --mtriple=wasm32-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic | FileCheck %s -check-prefixes=CHECK,PIC -DPTR=32
+; RUN: llc < %s --mtriple=wasm64-unknown-emscripten -wasm-disable-explicit-locals -wasm-keep-registers -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -relocation-model=pic | FileCheck %s -check-prefixes=CHECK,PIC -DPTR=64
 
 @_ZTIi = external constant i8*
 @_ZTIf = external constant i8*
@@ -60,7 +63,22 @@
 ; entries with the first landing pad because they end with the same sequence
 ; (double -> ...). But the third landing table cannot share action table entries
 ; with others, so it should create its own entries.
+
 ; CHECK-LABEL: test1:
+; In static linking, we load GCC_except_table as a constant directly.
+; NOPIC:      i[[PTR]].const  $push[[CONTEXT:.*]]=, __wasm_lpad_context
+; NOPIC-NEXT: i[[PTR]].const  $push[[EXCEPT_TABLE:.*]]=, GCC_except_table1
+; NOPIC-NEXT: i[[PTR]].store  {{[48]}}($pop[[CONTEXT]]), $pop[[EXCEPT_TABLE]]
+
+; In case of PIC, we make GCC_except_table symbols a relative on based on
+; __memory_base.
+; PIC:        global.get  $push[[CONTEXT:.*]]=, __wasm_lpad_context@GOT
+; PIC-NEXT:   local.tee  $push{{.*}}=, $[[CONTEXT_LOCAL:.*]]=, $pop[[CONTEXT]]
+; PIC:        global.get  $push[[MEMORY_BASE:.*]]=, __memory_base
+; PIC-NEXT:   i[[PTR]].const  $push[[EXCEPT_TABLE_REL:.*]]=, GCC_except_table1@MBREL
+; PIC-NEXT:   i[[PTR]].add   $push[[EXCEPT_TABLE:.*]]=, $pop[[MEMORY_BASE]], $pop[[EXCEPT_TABLE_REL]]
+; PIC-NEXT:   i[[PTR]].store  {{[48]}}($[[CONTEXT_LOCAL]]), $pop[[EXCEPT_TABLE]]
+
 ; CHECK: .section  .rodata.gcc_except_table,"",@
 ; CHECK-NEXT:   .p2align  2
 ; CHECK-NEXT: GCC_except_table[[START:[0-9]+]]:
@@ -102,10 +120,10 @@
 ; CHECK-NEXT:   .int8  125                     #   Continue to action 5
 ; CHECK-NEXT:   .p2align  2
 ; CHECK-NEXT:                                  # >> Catch TypeInfos <<
-; CHECK-NEXT:   .int32  _ZTIi                  # TypeInfo 4
-; CHECK-NEXT:   .int32  _ZTIf                  # TypeInfo 3
-; CHECK-NEXT:   .int32  _ZTId                  # TypeInfo 2
-; CHECK-NEXT:   .int32  0                      # TypeInfo 1
+; CHECK-NEXT:   .int[[PTR]]  _ZTIi             # TypeInfo 4
+; CHECK-NEXT:   .int[[PTR]]  _ZTIf             # TypeInfo 3
+; CHECK-NEXT:   .int[[PTR]]  _ZTId             # TypeInfo 2
+; CHECK-NEXT:   .int[[PTR]]  0                 # TypeInfo 1
 ; CHECK-NEXT: .Lttbase0:
 ; CHECK-NEXT:   .p2align  2
 ; CHECK-NEXT: .LGCC_except_table_end[[END:[0-9]+]]: