Index: wasm/InputFiles.h
===================================================================
--- wasm/InputFiles.h
+++ wasm/InputFiles.h
@@ -17,6 +17,7 @@
 #include "llvm/Object/Wasm.h"
 #include "llvm/Support/MemoryBuffer.h"
 
+#include "Symbols.h"
 #include "WriterUtils.h"
 
 #include <vector>
@@ -32,7 +33,6 @@
 namespace lld {
 namespace wasm {
 
-class Symbol;
 class InputFunction;
 class InputSegment;
 
@@ -98,8 +98,6 @@
   uint32_t relocateTableIndex(uint32_t Original) const;
   uint32_t getRelocatedAddress(uint32_t Index) const;
 
-  size_t getNumGlobalImports() const { return NumGlobalImports; }
-
   const WasmSection *CodeSection = nullptr;
 
   std::vector<uint32_t> TypeMap;
@@ -110,14 +108,16 @@
   ArrayRef<Symbol *> getTableSymbols() { return TableSymbols; }
 
 private:
-  Symbol *createDefined(const WasmSymbol &Sym,
+  Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
                         const InputSegment *Segment = nullptr,
-                        InputFunction *Function = nullptr);
-  Symbol *createUndefined(const WasmSymbol &Sym,
+                        InputFunction *Function = nullptr,
+                        uint32_t Address = 0);
+  Symbol *createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
                           const WasmSignature *Signature = nullptr);
   void initializeSymbols();
   InputSegment *getSegment(const WasmSymbol &WasmSym) const;
   const WasmSignature *getFunctionSig(const WasmSymbol &Sym) const;
+  uint32_t getGlobalValue(const WasmSymbol &Sym) const;
   InputFunction *getFunction(const WasmSymbol &Sym) const;
 
   // List of all symbols referenced or defined by this file.
Index: wasm/InputFiles.cpp
===================================================================
--- wasm/InputFiles.cpp
+++ wasm/InputFiles.cpp
@@ -136,6 +136,15 @@
       To.push_back(R);
 }
 
+// Get the value stored in the wasm global represented by this symbol.
+// This represents the virtual address of the symbol in the input file.
+uint32_t ObjFile::getGlobalValue(const WasmSymbol &Sym) const {
+  const WasmGlobal &Global =
+      getWasmObj()->globals()[Sym.ElementIndex - NumGlobalImports];
+  assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
+  return Global.InitExpr.Value.Int32;
+}
+
 // Get the signature for a given function symbol, either by looking
 // it up in function sections (for defined functions), of the imports section
 // (for imported functions).
@@ -200,16 +209,19 @@
     Symbol *S;
     switch (WasmSym.Type) {
     case WasmSymbol::SymbolType::FUNCTION_IMPORT:
-      S = createUndefined(WasmSym, getFunctionSig(WasmSym));
+      S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind,
+                          getFunctionSig(WasmSym));
       break;
     case WasmSymbol::SymbolType::GLOBAL_IMPORT:
-      S = createUndefined(WasmSym);
+      S = createUndefined(WasmSym, Symbol::Kind::UndefinedGlobalKind);
       break;
     case WasmSymbol::SymbolType::GLOBAL_EXPORT:
-      S = createDefined(WasmSym, getSegment(WasmSym), nullptr);
+      S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
+                        getSegment(WasmSym), nullptr, getGlobalValue(WasmSym));
       break;
     case WasmSymbol::SymbolType::FUNCTION_EXPORT:
-      S = createDefined(WasmSym, nullptr, getFunction(WasmSym));
+      S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
+                        getFunction(WasmSym));
       break;
     case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
       // These are for debugging only, no need to create linker symbols for them
@@ -250,28 +262,22 @@
   DEBUG(dbgs() << "Globals     : " << GlobalSymbols.size() << "\n");
 }
 
-Symbol *ObjFile::createUndefined(const WasmSymbol &Sym,
+Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
                                  const WasmSignature *Signature) {
-  return Symtab->addUndefined(this, &Sym, Signature);
+  return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature);
 }
 
-Symbol *ObjFile::createDefined(const WasmSymbol &Sym,
+Symbol *ObjFile::createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
                                const InputSegment *Segment,
-                               InputFunction *Function) {
+                               InputFunction *Function, uint32_t Address) {
   Symbol *S;
   if (Sym.isLocal()) {
     S = make<Symbol>(Sym.Name, true);
-    Symbol::Kind Kind;
-    if (Sym.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT)
-      Kind = Symbol::Kind::DefinedFunctionKind;
-    else if (Sym.Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
-      Kind = Symbol::Kind::DefinedGlobalKind;
-    else
-      llvm_unreachable("invalid local symbol type");
-    S->update(Kind, this, &Sym, Segment, Function);
+    S->update(Kind, this, Sym.Flags, Segment, Function, Address);
     return S;
   }
-  return Symtab->addDefined(this, &Sym, Segment, Function);
+  return Symtab->addDefined(Sym.Name, Kind, Sym.Flags, this, Segment, Function,
+                            Address);
 }
 
 void ArchiveFile::parse() {
Index: wasm/SymbolTable.h
===================================================================
--- wasm/SymbolTable.h
+++ wasm/SymbolTable.h
@@ -17,7 +17,6 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/raw_ostream.h"
 
-using llvm::object::WasmSymbol;
 using llvm::wasm::WasmSignature;
 
 namespace lld {
@@ -49,11 +48,11 @@
   ArrayRef<Symbol *> getSymbols() const { return SymVector; }
   Symbol *find(StringRef Name);
 
-  Symbol *addDefined(InputFile *F, const WasmSymbol *Sym,
-                     const InputSegment *Segment = nullptr,
-                     InputFunction *Function = nullptr);
-  Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym,
-                       const WasmSignature *Signature = nullptr);
+  Symbol *addDefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
+                     InputFile *F, const InputSegment *Segment = nullptr,
+                     InputFunction *Function = nullptr, uint32_t Address = 0);
+  Symbol *addUndefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
+                       InputFile *F, const WasmSignature *Signature = nullptr);
   Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type);
   Symbol *addDefinedGlobal(StringRef Name);
   void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
Index: wasm/SymbolTable.cpp
===================================================================
--- wasm/SymbolTable.cpp
+++ wasm/SymbolTable.cpp
@@ -20,6 +20,7 @@
 #define DEBUG_TYPE "lld"
 
 using namespace llvm;
+using namespace llvm::wasm;
 using namespace lld;
 using namespace lld::wasm;
 
@@ -80,18 +81,17 @@
 // Check the type of new symbol matches that of the symbol is replacing.
 // For functions this can also involve verifying that the signatures match.
 static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
-                             const WasmSymbol &New,
-                             const WasmSignature *NewSig) {
+                             Symbol::Kind Kind, const WasmSignature *NewSig) {
   if (Existing.isLazy())
     return;
 
-  bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
-                       New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
+  bool NewIsFunction = Kind == Symbol::Kind::UndefinedFunctionKind ||
+                       Kind == Symbol::Kind::DefinedFunctionKind;
 
   // First check the symbol types match (i.e. either both are function
   // symbols or both are data symbols).
   if (Existing.isFunction() != NewIsFunction) {
-    error("symbol type mismatch: " + New.Name + "\n>>> defined as " +
+    error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " +
           (Existing.isFunction() ? "Function" : "Global") + " in " +
           toString(Existing.getFile()) + "\n>>> defined as " +
           (NewIsFunction ? "Function" : "Global") + " in " + F.getName());
@@ -106,16 +106,17 @@
   if (!Existing.hasFunctionType())
     return;
 
-  DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n");
+  DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n");
   assert(NewSig);
 
   const WasmSignature &OldSig = Existing.getFunctionType();
   if (*NewSig == OldSig)
     return;
 
-  error("function signature mismatch: " + New.Name + "\n>>> defined as " +
-        toString(OldSig) + " in " + toString(Existing.getFile()) +
-        "\n>>> defined as " + toString(*NewSig) + " in " + F.getName());
+  error("function signature mismatch: " + Existing.getName() +
+        "\n>>> defined as " + toString(OldSig) + " in " +
+        toString(Existing.getFile()) + "\n>>> defined as " + toString(*NewSig) +
+        " in " + F.getName());
 }
 
 Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
@@ -130,40 +131,37 @@
   return S;
 }
 
-Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
+Symbol *SymbolTable::addDefined(StringRef Name, Symbol::Kind Kind,
+                                uint32_t Flags, InputFile *F,
                                 const InputSegment *Segment,
-                                InputFunction *Function) {
-  DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n");
+                                InputFunction *Function, uint32_t Address) {
+  DEBUG(dbgs() << "addDefined: " << Name << "\n");
   Symbol *S;
   bool WasInserted;
-  Symbol::Kind Kind = Symbol::DefinedFunctionKind;
-  if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
-    Kind = Symbol::DefinedGlobalKind;
 
-  std::tie(S, WasInserted) = insert(Sym->Name);
+  std::tie(S, WasInserted) = insert(Name);
   if (WasInserted) {
-    S->update(Kind, F, Sym, Segment, Function);
+    S->update(Kind, F, Flags, Segment, Function, Address);
   } else if (S->isLazy()) {
     // The existing symbol is lazy. Replace it without checking types since
     // lazy symbols don't have any type information.
-    DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n");
-    S->update(Kind, F, Sym, Segment, Function);
+    DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n");
+    S->update(Kind, F, Flags, Segment, Function);
   } else if (!S->isDefined()) {
     // The existing symbol table entry is undefined. The new symbol replaces
     // it, after checking the type matches
-    DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name
-                 << "\n");
-    checkSymbolTypes(*S, *F, *Sym, Function ? &Function->Signature : nullptr);
-    S->update(Kind, F, Sym, Segment, Function);
-  } else if (Sym->isWeak()) {
+    DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n");
+    checkSymbolTypes(*S, *F, Kind, Function ? &Function->Signature : nullptr);
+    S->update(Kind, F, Flags, Segment, Function, Address);
+  } else if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
     // the new symbol is weak we can ignore it
     DEBUG(dbgs() << "existing symbol takes precedence\n");
   } else if (S->isWeak()) {
     // the new symbol is not weak and the existing symbol is, so we replace
     // it
     DEBUG(dbgs() << "replacing existing weak symbol\n");
-    checkSymbolTypes(*S, *F, *Sym, Function ? &Function->Signature : nullptr);
-    S->update(Kind, F, Sym, Segment, Function);
+    checkSymbolTypes(*S, *F, Kind, Function ? &Function->Signature : nullptr);
+    S->update(Kind, F, Flags, Segment, Function, Address);
   } else {
     // neither symbol is week. They conflict.
     reportDuplicate(S, F);
@@ -185,17 +183,15 @@
   return S;
 }
 
-Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym,
+Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
+                                  uint32_t Flags, InputFile *F,
                                   const WasmSignature *Type) {
-  DEBUG(dbgs() << "addUndefined: " << Sym->Name << "\n");
+  DEBUG(dbgs() << "addUndefined: " << Name << "\n");
   Symbol *S;
   bool WasInserted;
-  Symbol::Kind Kind = Symbol::UndefinedFunctionKind;
-  if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT)
-    Kind = Symbol::UndefinedGlobalKind;
-  std::tie(S, WasInserted) = insert(Sym->Name);
+  std::tie(S, WasInserted) = insert(Name);
   if (WasInserted) {
-    S->update(Kind, F, Sym);
+    S->update(Kind, F, Flags);
     if (Type)
       S->setFunctionType(Type);
   } else if (S->isLazy()) {
@@ -204,7 +200,7 @@
     AF->addMember(&S->getArchiveSymbol());
   } else if (S->isDefined()) {
     DEBUG(dbgs() << "resolved by existing\n");
-    checkSymbolTypes(*S, *F, *Sym, Type);
+    checkSymbolTypes(*S, *F, Kind, Type);
   }
   return S;
 }
Index: wasm/Symbols.h
===================================================================
--- wasm/Symbols.h
+++ wasm/Symbols.h
@@ -15,9 +15,6 @@
 #include "llvm/Object/Wasm.h"
 
 using llvm::object::Archive;
-using llvm::object::WasmSymbol;
-using llvm::wasm::WasmExport;
-using llvm::wasm::WasmImport;
 using llvm::wasm::WasmSignature;
 
 namespace lld {
@@ -41,8 +38,8 @@
     InvalidKind,
   };
 
-  Symbol(StringRef Name, bool IsLocal)
-      : WrittenToSymtab(0), WrittenToNameSec(0), IsLocal(IsLocal), Name(Name) {}
+  Symbol(StringRef Name, uint32_t Flags)
+      : WrittenToSymtab(0), WrittenToNameSec(0), Flags(Flags), Name(Name) {}
 
   Kind getKind() const { return SymbolKind; }
 
@@ -57,7 +54,7 @@
            SymbolKind == UndefinedFunctionKind;
   }
   bool isGlobal() const { return !isFunction(); }
-  bool isLocal() const { return IsLocal; }
+  bool isLocal() const;
   bool isWeak() const;
   bool isHidden() const;
 
@@ -89,9 +86,9 @@
 
   void setVirtualAddress(uint32_t VA);
 
-  void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr,
+  void update(Kind K, InputFile *F = nullptr, uint32_t Flags = 0,
               const InputSegment *Segment = nullptr,
-              const InputFunction *Function = nullptr);
+              const InputFunction *Function = nullptr, uint32_t Address = 0);
 
   void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
   const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
@@ -102,18 +99,17 @@
   unsigned WrittenToNameSec : 1;
 
 protected:
-  unsigned IsLocal : 1;
+  uint32_t Flags;
+  uint32_t VirtualAddress;
 
   StringRef Name;
   Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};
   Kind SymbolKind = InvalidKind;
   InputFile *File = nullptr;
-  const WasmSymbol *Sym = nullptr;
   const InputSegment *Segment = nullptr;
   const InputFunction *Function = nullptr;
   llvm::Optional<uint32_t> OutputIndex;
   llvm::Optional<uint32_t> TableIndex;
-  llvm::Optional<uint32_t> VirtualAddress;
   const WasmSignature *FunctionType = nullptr;
 };
 
Index: wasm/Symbols.cpp
===================================================================
--- wasm/Symbols.cpp
+++ wasm/Symbols.cpp
@@ -19,6 +19,7 @@
 #define DEBUG_TYPE "lld"
 
 using namespace llvm;
+using namespace llvm::wasm;
 using namespace lld;
 using namespace lld::wasm;
 
@@ -41,17 +42,7 @@
   DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
   if (isUndefined())
     return UINT32_MAX;
-  if (VirtualAddress.hasValue())
-    return VirtualAddress.getValue();
-
-  ObjFile *Obj = cast<ObjFile>(File);
-  assert(Sym != nullptr);
-  const WasmGlobal &Global =
-      Obj->getWasmObj()
-          ->globals()[Sym->ElementIndex - Obj->getNumGlobalImports()];
-  assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
-  assert(Segment);
-  return Segment->translateVA(Global.InitExpr.Value.Int32);
+  return Segment ? Segment->translateVA(VirtualAddress) : VirtualAddress;
 }
 
 uint32_t Symbol::getOutputIndex() const {
@@ -64,7 +55,7 @@
 
 void Symbol::setVirtualAddress(uint32_t Value) {
   DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
-  assert(!VirtualAddress.hasValue());
+  assert(isGlobal());
   VirtualAddress = Value;
 }
 
@@ -81,18 +72,29 @@
   TableIndex = Index;
 }
 
-void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym,
-                    const InputSegment *Seg, const InputFunction *Func) {
+void Symbol::update(Kind K, InputFile *F, uint32_t Flags_,
+                    const InputSegment *Seg, const InputFunction *Func,
+                    uint32_t Address) {
   SymbolKind = K;
   File = F;
-  Sym = WasmSym;
+  Flags = Flags_;
   Segment = Seg;
   Function = Func;
+  if (Address)
+    setVirtualAddress(Address);
 }
 
-bool Symbol::isWeak() const { return Sym && Sym->isWeak(); }
+bool Symbol::isWeak() const {
+  return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
+}
 
-bool Symbol::isHidden() const { return Sym && Sym->isHidden(); }
+bool Symbol::isLocal() const {
+  return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
+}
+
+bool Symbol::isHidden() const {
+  return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
+}
 
 std::string lld::toString(const wasm::Symbol &Sym) {
   if (Config->Demangle)