[lld] r318539 - [WebAssembly] Initial wasm linker implementation

Sam Clegg via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 17 10:14:09 PST 2017


Author: sbc
Date: Fri Nov 17 10:14:09 2017
New Revision: 318539

URL: http://llvm.org/viewvc/llvm-project?rev=318539&view=rev
Log:
[WebAssembly] Initial wasm linker implementation

This linker backend is still a work in progress but is
enough to link simple programs including linking against
library archives.

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

Added:
    lld/trunk/docs/WebAssembly.rst
    lld/trunk/test/wasm/
    lld/trunk/test/wasm/Inputs/
    lld/trunk/test/wasm/Inputs/archive1.ll
    lld/trunk/test/wasm/Inputs/archive2.ll
    lld/trunk/test/wasm/Inputs/call-indirect.ll
    lld/trunk/test/wasm/Inputs/hello.ll
    lld/trunk/test/wasm/Inputs/many-funcs.ll
    lld/trunk/test/wasm/Inputs/ret32.ll
    lld/trunk/test/wasm/Inputs/ret64.ll
    lld/trunk/test/wasm/Inputs/weak-alias.ll
    lld/trunk/test/wasm/archive.ll
    lld/trunk/test/wasm/call-indirect.ll
    lld/trunk/test/wasm/conflict.test
    lld/trunk/test/wasm/data-layout.ll
    lld/trunk/test/wasm/entry.ll
    lld/trunk/test/wasm/function-imports-first.ll
    lld/trunk/test/wasm/function-imports.ll
    lld/trunk/test/wasm/function-index.test
    lld/trunk/test/wasm/import-memory.test
    lld/trunk/test/wasm/invalid-stack-size.test
    lld/trunk/test/wasm/lit.local.cfg
    lld/trunk/test/wasm/local-symbols.ll
    lld/trunk/test/wasm/many-functions.ll
    lld/trunk/test/wasm/relocatable.ll
    lld/trunk/test/wasm/strip-debug.test
    lld/trunk/test/wasm/symtol-type-mismatch.ll
    lld/trunk/test/wasm/undefined-entry.test
    lld/trunk/test/wasm/undefined.ll
    lld/trunk/test/wasm/version.ll
    lld/trunk/test/wasm/weak-alias-overide.ll
    lld/trunk/test/wasm/weak-alias.ll
    lld/trunk/test/wasm/weak-external.ll
    lld/trunk/wasm/
    lld/trunk/wasm/CMakeLists.txt   (with props)
    lld/trunk/wasm/Config.h   (with props)
    lld/trunk/wasm/Driver.cpp   (with props)
    lld/trunk/wasm/InputFiles.cpp   (with props)
    lld/trunk/wasm/InputFiles.h   (with props)
    lld/trunk/wasm/InputSegment.cpp   (with props)
    lld/trunk/wasm/InputSegment.h   (with props)
    lld/trunk/wasm/Memory.h   (with props)
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/OutputSections.cpp   (with props)
    lld/trunk/wasm/OutputSections.h   (with props)
    lld/trunk/wasm/OutputSegment.h   (with props)
    lld/trunk/wasm/Strings.cpp   (with props)
    lld/trunk/wasm/Strings.h   (with props)
    lld/trunk/wasm/SymbolTable.cpp   (with props)
    lld/trunk/wasm/SymbolTable.h   (with props)
    lld/trunk/wasm/Symbols.cpp   (with props)
    lld/trunk/wasm/Symbols.h   (with props)
    lld/trunk/wasm/Writer.cpp   (with props)
    lld/trunk/wasm/Writer.h   (with props)
    lld/trunk/wasm/WriterUtils.cpp   (with props)
    lld/trunk/wasm/WriterUtils.h   (with props)
Modified:
    lld/trunk/CMakeLists.txt
    lld/trunk/CODE_OWNERS.TXT
    lld/trunk/docs/NewLLD.rst
    lld/trunk/docs/index.rst
    lld/trunk/include/lld/Common/Driver.h
    lld/trunk/test/lit.cfg.py
    lld/trunk/tools/lld/CMakeLists.txt
    lld/trunk/tools/lld/lld.cpp

Modified: lld/trunk/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/CMakeLists.txt?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/CMakeLists.txt (original)
+++ lld/trunk/CMakeLists.txt Fri Nov 17 10:14:09 2017
@@ -223,4 +223,4 @@ add_subdirectory(docs)
 add_subdirectory(COFF)
 add_subdirectory(ELF)
 add_subdirectory(MinGW)
-
+add_subdirectory(wasm)

Modified: lld/trunk/CODE_OWNERS.TXT
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/CODE_OWNERS.TXT?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/CODE_OWNERS.TXT (original)
+++ lld/trunk/CODE_OWNERS.TXT Fri Nov 17 10:14:09 2017
@@ -17,3 +17,6 @@ N: Lang Hames, Nick Kledzik
 E: lhames at gmail.com, kledzik at apple.com
 D: Mach-O backend
 
+N: Sam Clegg
+E: sbc at chromium.org
+D: WebAssembly backend (wasm/*)

Modified: lld/trunk/docs/NewLLD.rst
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/docs/NewLLD.rst?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/docs/NewLLD.rst (original)
+++ lld/trunk/docs/NewLLD.rst Fri Nov 17 10:14:09 2017
@@ -1,5 +1,5 @@
-The ELF and COFF Linkers
-========================
+The ELF, COFF and Wasm Linkers
+==============================
 
 The ELF Linker as a Library
 ---------------------------
@@ -33,11 +33,12 @@ between speed, simplicity and extensibil
 
   We implemented the linkers as native linkers for each file format.
 
-  The two linkers share the same design but do not share code.
+  The linkers share the same design but share very little code.
   Sharing code makes sense if the benefit is worth its cost.
-  In our case, ELF and COFF are different enough that we thought the layer to
-  abstract the differences wouldn't worth its complexity and run-time cost.
-  Elimination of the abstract layer has greatly simplified the implementation.
+  In our case, the object formats are different enough that we thought the layer
+  to abstract the differences wouldn't be worth its complexity and run-time
+  cost.  Elimination of the abstract layer has greatly simplified the
+  implementation.
 
 * Speed by design
 

Added: lld/trunk/docs/WebAssembly.rst
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/docs/WebAssembly.rst?rev=318539&view=auto
==============================================================================
--- lld/trunk/docs/WebAssembly.rst (added)
+++ lld/trunk/docs/WebAssembly.rst Fri Nov 17 10:14:09 2017
@@ -0,0 +1,36 @@
+WebAssembly lld port
+====================
+
+Note: The WebAssembly port is still a work in progress and is be lacking
+certain features.
+
+The WebAssembly version of lld takes WebAssembly binaries as inputs and produces
+a WebAssembly binary as its output.  For the most part this port tried to mimic
+the behaviour of traditional ELF linkers and specifically the ELF lld port.
+Where possible that command line flags and the semantics should be the same.
+
+
+Object file format
+------------------
+
+The format the input object files that lld expects is specified as part of the
+the WebAssembly tool conventions
+https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md.
+
+This is object format that the llvm will produce when run with the
+``wasm32-unknown-unknown-wasm`` target.  To build llvm with WebAssembly support
+currently requires enabling the experimental backed using
+``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``.
+
+
+Missing features
+----------------
+
+There are several key features that are not yet implement in the WebAssembly
+ports:
+
+- COMDAT support.  This means that support for C++ is still very limited.
+- Function stripping.  Currently there is no support for ``--gc-sections`` so
+  functions and data from a given object will linked as a unit.
+- Section start/end symbols.  The synthetic symbols that mark the start and
+  of data regions are not yet created in the output file.

Modified: lld/trunk/docs/index.rst
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/docs/index.rst?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/docs/index.rst (original)
+++ lld/trunk/docs/index.rst Fri Nov 17 10:14:09 2017
@@ -5,13 +5,14 @@ LLD is a linker from the LLVM project. T
 for system linkers and runs much faster than them. It also provides
 features that are useful for toolchain developers.
 
-The linker supports ELF (Unix), PE/COFF (Windows) and Mach-O (macOS)
-in descending order of completeness. Internally, LLD consists of three
-different linkers. The ELF port is the one that will be described in
-this document. The PE/COFF port is almost complete except the lack of
-the Windows debug info (PDB) support. The Mach-O port is built based
-on a different architecture than the ELF or COFF ports. For the
-details about Mach-O, please read :doc:`AtomLLD`.
+The linker supports ELF (Unix), PE/COFF (Windows), Mach-O (macOS) and
+WebAssembly in descending order of completeness. Internally, LLD consists of
+several different linkers. The ELF port is the one that will be described in
+this document. The PE/COFF port is almost complete except the lack of the
+Windows debug info (PDB) support. The WebAssembly port is still a work in
+progress (See :doc:`WebAssembly`).  The Mach-O port is built based on a
+different architecture than the others. For the details about Mach-O, please
+read :doc:`AtomLLD`.
 
 Features
 --------
@@ -172,5 +173,6 @@ document soon.
 
    NewLLD
    AtomLLD
+   WebAssembly
    windows_support
    ReleaseNotes

Modified: lld/trunk/include/lld/Common/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Common/Driver.h?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/include/lld/Common/Driver.h (original)
+++ lld/trunk/include/lld/Common/Driver.h Fri Nov 17 10:14:09 2017
@@ -33,6 +33,11 @@ namespace mach_o {
 bool link(llvm::ArrayRef<const char *> Args,
           llvm::raw_ostream &Diag = llvm::errs());
 }
+
+namespace wasm {
+bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly,
+          llvm::raw_ostream &Diag = llvm::errs());
+}
 }
 
 #endif

Modified: lld/trunk/test/lit.cfg.py
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/lit.cfg.py?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/test/lit.cfg.py (original)
+++ lld/trunk/test/lit.cfg.py Fri Nov 17 10:14:09 2017
@@ -39,7 +39,7 @@ llvm_config.use_default_substitutions()
 llvm_config.use_lld()
 
 tool_patterns = [
-    'llvm-as', 'llvm-mc', 'llvm-nm',
+    'llc', 'llvm-as', 'llvm-mc', 'llvm-nm',
     'llvm-objdump', 'llvm-pdbutil', 'llvm-readobj', 'obj2yaml', 'yaml2obj']
 
 llvm_config.add_tool_substitutions(tool_patterns)
@@ -67,6 +67,7 @@ llvm_config.feature_config(
                           'Mips': 'mips',
                           'PowerPC': 'ppc',
                           'Sparc': 'sparc',
+                          'WebAssembly': 'wasm',
                           'X86': 'x86'})
      ])
 

Added: lld/trunk/test/wasm/Inputs/archive1.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/archive1.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/archive1.ll (added)
+++ lld/trunk/test/wasm/Inputs/archive1.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,7 @@
+declare i32 @bar() local_unnamed_addr #1
+
+define i32 @foo() local_unnamed_addr #0 {
+entry:
+  %call = tail call i32 @bar() #2
+  ret i32 %call
+}

Added: lld/trunk/test/wasm/Inputs/archive2.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/archive2.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/archive2.ll (added)
+++ lld/trunk/test/wasm/Inputs/archive2.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,7 @@
+declare i32 @foo() local_unnamed_addr #1
+
+define i32 @bar() local_unnamed_addr #0 {
+entry:
+  %call = tail call i32 @foo() #2
+  ret i32 %call
+}

Added: lld/trunk/test/wasm/Inputs/call-indirect.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/call-indirect.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/call-indirect.ll (added)
+++ lld/trunk/test/wasm/Inputs/call-indirect.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,18 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at indirect_bar = hidden local_unnamed_addr global i32 ()* @bar, align 4
+
+; Function Attrs: norecurse nounwind readnone
+define hidden i32 @bar() #0 {
+entry:
+  ret i32 1
+}
+
+; Function Attrs: nounwind
+define hidden void @call_bar_indirect() local_unnamed_addr #1 {
+entry:
+  %0 = load i32 ()*, i32 ()** @indirect_bar, align 4
+  %call = tail call i32 %0() #2
+  ret void
+}

Added: lld/trunk/test/wasm/Inputs/hello.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/hello.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/hello.ll (added)
+++ lld/trunk/test/wasm/Inputs/hello.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,18 @@
+; Wasm module generated from the following C code:
+;   void puts(const char*);
+;   void hello() { puts("hello\n"); }
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at hello_str = unnamed_addr constant [7 x i8] c"hello\0A\00", align 1
+
+; Function Attrs: nounwind
+define hidden void @hello() local_unnamed_addr #0 {
+entry:
+  tail call void @puts(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @hello_str, i32 0, i32 0))
+  ret void
+}
+
+; Function Attrs: nounwind
+declare void @puts(i8* nocapture readonly) local_unnamed_addr #1

Added: lld/trunk/test/wasm/Inputs/many-funcs.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/many-funcs.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/many-funcs.ll (added)
+++ lld/trunk/test/wasm/Inputs/many-funcs.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,779 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at g0 = global i32 1, align 4
+ at foo = global i32 1, align 4
+
+define i32 @f1() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f2() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f3() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f4() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f5() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f6() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f7() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f8() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f9() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f10() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f11() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f12() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f13() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f14() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f15() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f16() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f17() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f18() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f19() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f20() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f21() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f22() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f23() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f24() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f25() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f26() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f27() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f28() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f29() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f30() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f31() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f32() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f33() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f34() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f35() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f36() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f37() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f38() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f39() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f40() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f41() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f42() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f43() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f44() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f45() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f46() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f47() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f48() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f49() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f50() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f51() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f52() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f53() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f54() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f55() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f56() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f57() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f58() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f59() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f60() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f61() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f62() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f63() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f64() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f65() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f66() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f67() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f68() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f69() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f70() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f71() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f72() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f73() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f74() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f75() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f76() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f77() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f78() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f79() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f80() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f81() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f82() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f83() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f84() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f85() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f86() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f87() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f88() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f89() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f90() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f91() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f92() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f93() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f94() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f95() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f96() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f97() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f98() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f99() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f100() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f101() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f102() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f103() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f104() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f105() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f106() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f107() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f108() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f109() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f110() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f111() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f112() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f113() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f114() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f115() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f116() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f117() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f118() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f119() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f120() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f121() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f122() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f123() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f124() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f125() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f126() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f127() {
+entry:
+  %0 = load i32, i32* @foo, align 4
+  ret i32 %0
+}
+
+define i32 @f128() {
+entry:
+  %0 = load i32, i32* @g0, align 4
+  ret i32 %0
+}
+
+define i32 @f129() {
+entry:
+  %0 = load i32, i32* @g0, align 4
+  ret i32 %0
+}

Added: lld/trunk/test/wasm/Inputs/ret32.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/ret32.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/ret32.ll (added)
+++ lld/trunk/test/wasm/Inputs/ret32.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,9 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Function Attrs: norecurse nounwind readnone
+define hidden i32 @ret32(float %arg) #0 {
+entry:
+    ret i32 0
+     ; ptrtoint (i32 (float)* @ret32 to i32)
+}

Added: lld/trunk/test/wasm/Inputs/ret64.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/ret64.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/ret64.ll (added)
+++ lld/trunk/test/wasm/Inputs/ret64.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,7 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define hidden i64 @ret64(double %arg) local_unnamed_addr #0 {
+entry:
+    ret i64 1
+}

Added: lld/trunk/test/wasm/Inputs/weak-alias.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/Inputs/weak-alias.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/Inputs/weak-alias.ll (added)
+++ lld/trunk/test/wasm/Inputs/weak-alias.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,12 @@
+define i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+ at bar = weak alias i32 (), i32 ()* @foo
+
+define hidden i32 @call_bar() #0 {
+entry:
+  %call = call i32 @bar()
+  ret i32 %call
+}

Added: lld/trunk/test/wasm/archive.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/archive.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/archive.ll (added)
+++ lld/trunk/test/wasm/archive.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,24 @@
+; Verify that multually dependant object files in an archive is handled
+; correctly.
+;
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/archive1.ll -o %t2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/archive2.ll -o %t3.o
+; RUN: llvm-ar rcs %t.a %t2.o %t3.o
+; RUN: lld -flavor wasm %t.a %t.o -o %t.wasm
+; RUN: llvm-nm -a %t.wasm | FileCheck %s
+
+; Specifying the same archive twice is allowed.
+; RUN: lld -flavor wasm %t.a %t.a %t.o -o %t.wasm
+
+declare i32 @foo() local_unnamed_addr #1
+
+define i32 @_start() local_unnamed_addr #0 {
+entry:
+  %call = tail call i32 @foo() #2
+  ret i32 %call
+}
+
+; CHECK: T _start
+; CHECK: T bar
+; CHECK: T foo

Added: lld/trunk/test/wasm/call-indirect.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/call-indirect.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/call-indirect.ll (added)
+++ lld/trunk/test/wasm/call-indirect.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,110 @@
+; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t2.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; bitcode generated from the following C code:
+; int foo(void) { return 1; }
+; int (*indirect_func)(void) = &foo;
+; void _start(void) { indirect_func(); }
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at indirect_func = hidden local_unnamed_addr global i32 ()* @foo, align 4
+
+; Function Attrs: norecurse nounwind readnone
+define hidden i32 @foo() #0 {
+entry:
+  ret i32 1
+}
+
+; Function Attrs: nounwind
+define hidden void @_start() local_unnamed_addr #1 {
+entry:
+  %0 = load i32 ()*, i32 ()** @indirect_func, align 4
+  %call = tail call i32 %0() #2
+  ret void
+}
+
+; CHECK:      !WASM
+; CHECK-NEXT: FileHeader:      
+; CHECK-NEXT:   Version:         0x00000001
+; CHECK-NEXT: Sections:        
+; CHECK-NEXT:   - Type:            TYPE
+; CHECK-NEXT:     Signatures:      
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         ReturnType:      I32
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         ReturnType:      NORESULT
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:   - Type:            FUNCTION
+; CHECK-NEXT:     FunctionTypes:   [ 0, 1, 0, 1 ]
+; CHECK-NEXT:   - Type:            TABLE
+; CHECK-NEXT:     Tables:          
+; CHECK-NEXT:       - ElemType:        ANYFUNC
+; CHECK-NEXT:         Limits:          
+; CHECK-NEXT:           Flags:           0x00000001
+; CHECK-NEXT:           Initial:         0x00000003
+; CHECK-NEXT:           Maximum:         0x00000003
+; CHECK-NEXT:   - Type:            MEMORY
+; CHECK-NEXT:     Memories:        
+; CHECK-NEXT:       - Initial:         0x00000002
+; CHECK-NEXT:   - Type:            GLOBAL
+; CHECK-NEXT:     Globals:         
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         true
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           66576
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:         
+; CHECK-NEXT:       - Name:            memory
+; CHECK-NEXT:         Kind:            MEMORY
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            bar
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            call_bar_indirect
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:       - Name:            foo
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:       - Name:            _start
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           3
+; CHECK:        - Type:            ELEM
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1
+; CHECK-NEXT:         Functions:       [ 0, 2 ]
+; CHECK-NEXT:   - Type:            CODE
+; CHECK-NEXT:     Functions:       
+; CHECK:            - Locals:          
+; CHECK:            - Locals:          
+; CHECK:            - Locals:          
+; CHECK:        - Type:            DATA
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - SectionOffset:    7
+; CHECK-NEXT:         MemoryIndex:      0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1024
+; CHECK-NEXT:         Content:         '0100000002000000'
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        8
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            name
+; CHECK-NEXT:     FunctionNames:   
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            bar
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            call_bar_indirect
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         Name:            foo
+; CHECK-NEXT:       - Index:           3
+; CHECK-NEXT:         Name:            _start

Added: lld/trunk/test/wasm/conflict.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/conflict.test?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/conflict.test (added)
+++ lld/trunk/test/wasm/conflict.test Fri Nov 17 10:14:09 2017
@@ -0,0 +1,6 @@
+# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+# RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s
+
+# CHECK:      duplicate symbol: ret32
+# CHECK-NEXT: >>> defined in {{.*}}conflict.test.tmp.ret32.o
+# CHECK-NEXT: >>> defined in {{.*}}conflict.test.tmp.ret32.o

Added: lld/trunk/test/wasm/data-layout.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/data-layout.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/data-layout.ll (added)
+++ lld/trunk/test/wasm/data-layout.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,64 @@
+; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm --emit-relocs --allow-undefined -o %t.wasm %t.o %t.hello.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at foo = hidden global i32 1, align 4
+ at aligned_bar = hidden global i32 3, align 16
+
+ at hello_str = external global i8*
+ at external_ref = global i8** @hello_str, align 8
+
+; CHECK:        - Type:            GLOBAL
+; CHECK-NEXT:     Globals:
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         true
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           66608
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1024
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1040
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1048
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1052
+
+; CHECK:       - Type:            DATA
+; CHECK-NEXT:     Relocations:
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_I32
+; CHECK-NEXT:         Index:           4
+; CHECK-NEXT:         Offset:          0x0000001F
+; CHECK-NEXT:     Segments:
+; CHECK-NEXT:       - SectionOffset:   7
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1024
+; CHECK-NEXT:         Content:         0100000000000000000000000000000003000000000000001C040000
+; CHECK-NEXT:       - SectionOffset:   41
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1052
+; CHECK-NEXT:         Content:         68656C6C6F0A00
+
+; CHECK:       - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        35

Added: lld/trunk/test/wasm/entry.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/entry.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/entry.ll (added)
+++ lld/trunk/test/wasm/entry.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,22 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -e entry -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+; RUN: lld -flavor wasm --entry=entry -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define hidden void @entry() local_unnamed_addr #0 {
+entry:
+  ret void
+}
+
+; CHECK:   - Type:            EXPORT
+; CHECK:     Exports:         
+; CHECK:       - Name:            memory
+; CHECK:         Kind:            MEMORY
+; CHECK:         Index:           0
+; CHECK:       - Name:            entry
+; CHECK:         Kind:            FUNCTION
+; CHECK:         Index:           0

Added: lld/trunk/test/wasm/function-imports-first.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/function-imports-first.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/function-imports-first.ll (added)
+++ lld/trunk/test/wasm/function-imports-first.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,45 @@
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o %t.ret32.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Function Attrs: nounwind
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+  %call = tail call i32 @ret32(float 0.000000e+00) #2
+  ret void
+}
+
+declare i32 @ret32(float) local_unnamed_addr #1
+
+; CHECK:  - Type:            TYPE
+; CHECK:    Signatures:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        ReturnType:      NORESULT
+; CHECK-NEXT:        ParamTypes:
+; CHECK-NEXT:      - Index:           1
+; CHECK-NEXT:        ReturnType:      I32
+; CHECK-NEXT:        ParamTypes:
+; CHECK-NEXT:          - F32
+; CHECK:  - Type:            FUNCTION
+; CHECK-NEXT:    FunctionTypes: [ 0, 1 ]
+; CHECK:  - Type:            CODE
+; CHECK-NEXT:    Functions:
+; CHECK-NEXT:      - Locals:
+; CHECK-NEXT:        Body:            43000000001081808080001A0B
+; CHECK-NEXT:      - Locals:
+; CHECK-NEXT:        Body:            41000B
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        0
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            name
+; CHECK-NEXT:     FunctionNames:   
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            _start
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            ret32
+; CHECK-NEXT: ...

Added: lld/trunk/test/wasm/function-imports.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/function-imports.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/function-imports.ll (added)
+++ lld/trunk/test/wasm/function-imports.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,40 @@
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.ret32.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Function Attrs: nounwind
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+  %call = tail call i32 @ret32(float 0.000000e+00) #2
+  ret void
+}
+
+declare i32 @ret32(float) local_unnamed_addr #1
+
+; CHECK:      Sections:
+; CHECK:       - Type:            TYPE
+; CHECK-NEXT:    Signatures:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        ReturnType:      I32
+; CHECK-NEXT:        ParamTypes:
+; CHECK-NEXT:          - F32
+; CHECK-NEXT:      - Index:           1
+; CHECK-NEXT:        ReturnType:      NORESULT
+; CHECK-NEXT:        ParamTypes:
+; CHECK-NEXT:  - Type:            FUNCTION
+; CHECK-NEXT:    FunctionTypes:   [ 0, 1 ]
+; CHECK:       - Type:            CODE
+; CHECK-NEXT:    Functions:
+; CHECK:           - Locals:
+; CHECK:           - Locals:
+; CHECK:         Name:            name
+; CHECK-NEXT:    FunctionNames:
+; CHECK-NEXT:      - Index:           0
+; CHECK-NEXT:        Name:            ret32
+; CHECK-NEXT:      - Index:           1
+; CHECK-NEXT:        Name:            _start
+; CHECK-NEXT: ...

Added: lld/trunk/test/wasm/function-index.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/function-index.test?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/function-index.test (added)
+++ lld/trunk/test/wasm/function-index.test Fri Nov 17 10:14:09 2017
@@ -0,0 +1,18 @@
+# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+# RUN: llc -filetype=obj %p/Inputs/ret64.ll -o %t.ret64.o
+# RUN: lld -flavor wasm -r -o %t.wasm %t.ret32.o %t.ret64.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+CHECK: Sections:
+CHECK:   - Type:            TYPE
+CHECK:     Signatures:
+CHECK:       - Index:           0
+CHECK:         ReturnType:      I32
+CHECK:         ParamTypes:
+CHECK:           - F32
+CHECK:       - Index:           1
+CHECK:         ReturnType:      I64
+CHECK:         ParamTypes:
+CHECK:           - F64
+CHECK: - Type:            FUNCTION
+CHECK:   FunctionTypes: [ 0, 1 ]

Added: lld/trunk/test/wasm/import-memory.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/import-memory.test?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/import-memory.test (added)
+++ lld/trunk/test/wasm/import-memory.test Fri Nov 17 10:14:09 2017
@@ -0,0 +1,13 @@
+# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+# RUN: lld -flavor wasm -entry ret32 --import-memory -o %t.wasm %t.ret32.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify the --import-memory flag creates a memory import
+
+# CHECK:       - Type:            IMPORT
+# CHECK-NEXT:    Imports:         
+# CHECK-NEXT:      - Module:          env
+# CHECK-NEXT:        Field:           memory
+# CHECK-NEXT:        Kind:            MEMORY
+# CHECK-NEXT:        Memory:          
+# CHECK-NEXT:          Initial:         0x00000002

Added: lld/trunk/test/wasm/invalid-stack-size.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/invalid-stack-size.test?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/invalid-stack-size.test (added)
+++ lld/trunk/test/wasm/invalid-stack-size.test Fri Nov 17 10:14:09 2017
@@ -0,0 +1,9 @@
+; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o %t.o
+; RUN: not lld -flavor wasm -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s
+
+define i32 @_start() local_unnamed_addr #1 {
+entry:
+  ret i32 0
+}
+
+; CHECK: error: stack size must be 16-byte aligned

Added: lld/trunk/test/wasm/lit.local.cfg
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/lit.local.cfg?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/lit.local.cfg (added)
+++ lld/trunk/test/wasm/lit.local.cfg Fri Nov 17 10:14:09 2017
@@ -0,0 +1,4 @@
+if 'wasm' not in config.available_features:
+  config.unsupported = True
+
+config.suffixes = ['.test', '.yaml', '.ll']

Added: lld/trunk/test/wasm/local-symbols.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/local-symbols.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/local-symbols.ll (added)
+++ lld/trunk/test/wasm/local-symbols.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,81 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at foo = default global i32 1, align 4
+ at bar = internal default global i32 3, align 4
+
+define internal i32 @baz() local_unnamed_addr {
+entry:
+  ret i32 2
+}
+
+define i32 @_start() local_unnamed_addr {
+entry:
+  ret i32 1
+}
+
+; CHECK:      --- !WASM
+; CHECK-NEXT: FileHeader:      
+; CHECK-NEXT:   Version:         0x00000001
+; CHECK-NEXT: Sections:        
+; CHECK-NEXT:   - Type:            TYPE
+; CHECK-NEXT:     Signatures:      
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         ReturnType:      I32
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:   - Type:            FUNCTION
+; CHECK-NEXT:     FunctionTypes:   [ 0, 0 ]
+; CHECK-NEXT:   - Type:            TABLE
+; CHECK-NEXT:     Tables:          
+; CHECK-NEXT:       - ElemType:        ANYFUNC
+; CHECK-NEXT:         Limits:          
+; CHECK-NEXT:           Flags:           0x00000001
+; CHECK-NEXT:           Initial:         0x00000001
+; CHECK-NEXT:           Maximum:         0x00000001
+; CHECK-NEXT:   - Type:            MEMORY
+; CHECK-NEXT:     Memories:        
+; CHECK-NEXT:       - Initial:         0x00000002
+; CHECK-NEXT:   - Type:            GLOBAL
+; CHECK-NEXT:     Globals:         
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         true
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           66576
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:         
+; CHECK-NEXT:       - Name:            memory
+; CHECK-NEXT:         Kind:            MEMORY
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            _start
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:   - Type:            CODE
+; CHECK-NEXT:     Functions:       
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            41020B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            41010B
+; CHECK-NEXT:   - Type:            DATA
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - SectionOffset:   7
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1024
+; CHECK-NEXT:         Content:         '0100000003000000'
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        8
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            name
+; CHECK-NEXT:     FunctionNames:   
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            baz
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            _start
+; CHECK-NEXT: ...

Added: lld/trunk/test/wasm/many-functions.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/many-functions.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/many-functions.ll (added)
+++ lld/trunk/test/wasm/many-functions.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,699 @@
+; RUN: llc -filetype=obj %p/Inputs/many-funcs.ll -o %t.many.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -r -o %t.wasm %t.many.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Test that relocations within the CODE section correctly handle
+; linking object with different header sizes.  many-funcs.ll has
+; 128 function and so the final output requires a 2-byte LEB in
+; the CODE section header to store the function count.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define i32 @func() {
+entry:
+  %call = tail call i32 @func()
+  ret i32 %call
+}
+
+; CHECK:        - Type:            CODE
+; CHECK-NEXT:     Relocations:     
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000008
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000014
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000020
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000002C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000038
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000044
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000050
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000005C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000068
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000074
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000080
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000008C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000098
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000A4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000B0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000BC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000C8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000D4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000E0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000EC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000000F8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000104
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000110
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000011C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000128
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000134
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000140
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000014C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000158
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000164
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000170
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000017C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000188
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000194
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001A0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001AC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001B8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001C4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001D0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001DC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001E8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000001F4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000200
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000020C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000218
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000224
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000230
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000023C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000248
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000254
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000260
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000026C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000278
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000284
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000290
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000029C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002A8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002B4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002C0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002CC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002D8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002E4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002F0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000002FC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000308
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000314
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000320
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000032C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000338
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000344
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000350
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000035C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000368
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000374
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000380
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000038C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000398
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003A4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003B0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003BC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003C8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003D4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003E0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003EC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000003F8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000404
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000410
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000041C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000428
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000434
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000440
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000044C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000458
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000464
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000470
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000047C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000488
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000494
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004A0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004AC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004B8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004C4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004D0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004DC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004E8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000004F4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000500
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000050C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000518
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000524
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000530
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000053C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000548
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000554
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000560
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000056C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000578
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000584
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000590
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000059C
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005A8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005B4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005C0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005CC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005D8
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005E4
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x000005F0
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:         Offset:          0x000005FC
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_LEB
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:         Offset:          0x00000608
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT:         Index:           129
+; CHECK-NEXT:         Offset:          0x00000611
+; CHECK-NEXT:     Functions:       
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280284808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280280808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            4100280280808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            1081818080000B
+; CHECK-NEXT:   - Type:            DATA
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - SectionOffset:   6
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:         Content:         '01000000'
+; CHECK-NEXT:       - SectionOffset:   15
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           4
+; CHECK-NEXT:         Content:         '01000000'
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        8
+; CHECK-NEXT:     SegmentInfo:     
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            .data.g0
+; CHECK-NEXT:         Alignment:       4
+; CHECK-NEXT:         Flags:           0
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            .data.foo
+; CHECK-NEXT:         Alignment:       4
+; CHECK-NEXT:         Flags:           0
+

Added: lld/trunk/test/wasm/relocatable.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/relocatable.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/relocatable.ll (added)
+++ lld/trunk/test/wasm/relocatable.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,185 @@
+; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -r -o %t.wasm %t.hello.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Function Attrs: nounwind
+define hidden i32 @my_func() local_unnamed_addr {
+entry:
+  %call = tail call i32 @foo_import()
+  ret i32 1
+}
+
+declare i32 @foo_import() local_unnamed_addr
+ at data_import = external global i64
+
+ at func_addr1 = hidden global i32()* @my_func, align 4
+ at func_addr2 = hidden global i32()* @foo_import, align 4
+ at data_addr1 = hidden global i64* @data_import, align 8
+
+; CHECK:      --- !WASM
+; CHECK-NEXT: FileHeader:      
+; CHECK-NEXT:   Version:         0x00000001
+; CHECK-NEXT: Sections:        
+; CHECK-NEXT:   - Type:            TYPE
+; CHECK-NEXT:     Signatures:      
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         ReturnType:      NORESULT
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         ReturnType:      NORESULT
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:           - I32
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         ReturnType:      I32
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:   - Type:            IMPORT
+; CHECK-NEXT:     Imports:         
+; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           puts
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         SigIndex:        1
+; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           foo_import
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         SigIndex:        2
+; CHECK-NEXT:       - Module:          env
+; CHECK-NEXT:         Field:           data_import
+; CHECK-NEXT:         Kind:            GLOBAL
+; CHECK-NEXT:         GlobalType:      I32
+; CHECK-NEXT:         GlobalMutable:   false
+; CHECK-NEXT:   - Type:            FUNCTION
+; CHECK-NEXT:     FunctionTypes:   [ 0, 2 ]
+; CHECK-NEXT:   - Type:            TABLE
+; CHECK-NEXT:     Tables:          
+; CHECK-NEXT:       - ElemType:        ANYFUNC
+; CHECK-NEXT:         Limits:          
+; CHECK-NEXT:           Flags:           0x00000001
+; CHECK-NEXT:           Initial:         0x00000002
+; CHECK-NEXT:           Maximum:         0x00000002
+; CHECK-NEXT:   - Type:            MEMORY
+; CHECK-NEXT:     Memories:        
+; CHECK-NEXT:       - Initial:         0x00000001
+; CHECK-NEXT:   - Type:            GLOBAL
+; CHECK-NEXT:     Globals:         
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           8
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           12
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         false
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           16
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:         
+; CHECK-NEXT:       - Name:            hello
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:       - Name:            my_func
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           3
+; CHECK-NEXT:   - Type:            ELEM
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:         Functions:       [ 3, 1 ]
+; CHECK-NEXT:   - Type:            CODE
+; CHECK-NEXT:     Relocations:     
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_SLEB
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:         Offset:          0x00000004
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x0000000A
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_FUNCTION_INDEX_LEB
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:         Offset:          0x00000013
+; CHECK-NEXT:     Functions:       
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:          4180808080001080808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:          1081808080001A41010B
+; CHECK-NEXT:   - Type:            DATA
+; CHECK-NEXT:     Relocations:     
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_TABLE_INDEX_I32
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000012
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_TABLE_INDEX_I32
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:         Offset:          0x0000001B
+; CHECK-NEXT:       - Type:            R_WEBASSEMBLY_MEMORY_ADDR_I32
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:         Offset:          0x00000024
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - SectionOffset:   6
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           0
+; CHECK-NEXT:         Content:         68656C6C6F0A00
+; CHECK-NEXT:       - SectionOffset:   18
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           8
+; CHECK-NEXT:         Content:         '00000000'
+; CHECK-NEXT:       - SectionOffset:   27
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           12
+; CHECK-NEXT:         Content:         '01000000'
+; CHECK-NEXT:       - SectionOffset:   36
+; CHECK-NEXT:         MemoryIndex:     0
+; CHECK-NEXT:         Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           16
+; CHECK-NEXT:         Content:         FFFFFFFF
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        20
+; CHECK-NEXT:     SegmentInfo:     
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            .rodata.hello_str
+; CHECK-NEXT:         Alignment:       1
+; CHECK-NEXT:         Flags:           0
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            .data.func_addr1
+; CHECK-NEXT:         Alignment:       4
+; CHECK-NEXT:         Flags:           0
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         Name:            .data.func_addr2
+; CHECK-NEXT:         Alignment:       4
+; CHECK-NEXT:         Flags:           0
+; CHECK-NEXT:       - Index:           3
+; CHECK-NEXT:         Name:            .data.data_addr1
+; CHECK-NEXT:         Alignment:       8
+; CHECK-NEXT:         Flags:           0
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            name
+; CHECK-NEXT:     FunctionNames:   
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            puts
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            foo_import
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         Name:            hello
+; CHECK-NEXT:       - Index:           3
+; CHECK-NEXT:         Name:            my_func
+; CHECK-NEXT: ...

Added: lld/trunk/test/wasm/strip-debug.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/strip-debug.test?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/strip-debug.test (added)
+++ lld/trunk/test/wasm/strip-debug.test Fri Nov 17 10:14:09 2017
@@ -0,0 +1,6 @@
+RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+RUN: lld -flavor wasm --strip-debug --entry=ret32 -o %t.wasm %t.ret32.o
+RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Check that there is no name section
+CHECK-NOT:   Name:    name

Added: lld/trunk/test/wasm/symtol-type-mismatch.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/symtol-type-mismatch.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/symtol-type-mismatch.ll (added)
+++ lld/trunk/test/wasm/symtol-type-mismatch.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,12 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: not lld -flavor wasm -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+ at ret32 = extern_weak global i32, align 4
+
+; CHECK: error: symbol type mismatch: ret32
+; CHECK: >>> defined as Global in {{.*}}symtol-type-mismatch.ll.tmp.o
+; CHECK: >>> defined as Function in {{.*}}.ret32.o

Added: lld/trunk/test/wasm/undefined-entry.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/undefined-entry.test?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/undefined-entry.test (added)
+++ lld/trunk/test/wasm/undefined-entry.test Fri Nov 17 10:14:09 2017
@@ -0,0 +1,4 @@
+RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o
+RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s
+
+CHECK: error: undefined symbol: _start

Added: lld/trunk/test/wasm/undefined.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/undefined.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/undefined.ll (added)
+++ lld/trunk/test/wasm/undefined.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,23 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm --allow-undefined -o %t.wasm %t.o
+
+; Fails due to undefined 'foo'
+; RUN: not lld -flavor wasm -o %t.wasm %t.o 2>&1 | FileCheck %s
+; CHECK: error: {{.*}}.o: undefined symbol: foo
+
+; But succeeds if we pass a file containing 'foo' as --allow-undefined-file.
+; RUN: echo 'foo' > %t.txt
+; RUN: lld -flavor wasm --allow-undefined-file=%t.txt -o %t.wasm %t.o
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+; Takes the address of the external foo() resulting in undefined external
+ at bar = hidden local_unnamed_addr global i8* bitcast (i32 ()* @foo to i8*), align 4
+
+declare i32 @foo() #0
+
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+    ret void
+}

Added: lld/trunk/test/wasm/version.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/version.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/version.ll (added)
+++ lld/trunk/test/wasm/version.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,16 @@
+; RUN: llc -filetype=obj %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o
+; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown-wasm"
+
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+    ret void
+}
+
+; CHECK: Format: WASM
+; CHECK: Arch: wasm32
+; CHECK: AddressSize: 32bit
+; CHECK: Version: 0x1

Added: lld/trunk/test/wasm/weak-alias-overide.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/weak-alias-overide.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/weak-alias-overide.ll (added)
+++ lld/trunk/test/wasm/weak-alias-overide.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,92 @@
+; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
+; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
+; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Test that the strongly defined bar is used correctly despite the existence
+; of the weak alias
+
+define i32 @bar() local_unnamed_addr #1 {
+  ret i32 1
+}
+
+; Function Attrs: nounwind uwtable
+define void @_start() local_unnamed_addr #1 {
+entry:
+  %call = tail call i32 @bar() #2
+  ret void
+}
+
+; CHECK:      --- !WASM
+; CHECK-NEXT: FileHeader:      
+; CHECK-NEXT:   Version:         0x00000001
+; CHECK-NEXT: Sections:        
+; CHECK-NEXT:   - Type:            TYPE
+; CHECK-NEXT:     Signatures:      
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         ReturnType:      I32
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         ReturnType:      NORESULT
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:   - Type:            FUNCTION
+; CHECK-NEXT:     FunctionTypes:   [ 0, 1, 0, 0 ]
+; CHECK-NEXT:   - Type:            TABLE
+; CHECK-NEXT:     Tables:          
+; CHECK-NEXT:       - ElemType:        ANYFUNC
+; CHECK-NEXT:         Limits:          
+; CHECK-NEXT:           Flags:           0x00000001
+; CHECK-NEXT:           Initial:         0x00000001
+; CHECK-NEXT:           Maximum:         0x00000001
+; CHECK-NEXT:   - Type:            MEMORY
+; CHECK-NEXT:     Memories:        
+; CHECK-NEXT:       - Initial:         0x00000002
+; CHECK-NEXT:   - Type:            GLOBAL
+; CHECK-NEXT:     Globals:         
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         true
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           66560
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:         
+; CHECK-NEXT:       - Name:            memory
+; CHECK-NEXT:         Kind:            MEMORY
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            bar
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            _start
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:       - Name:            foo
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:       - Name:            call_bar
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           3
+; CHECK-NEXT:   - Type:            CODE
+; CHECK-NEXT:     Functions:       
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            41010B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            1080808080001A0B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            41000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            1080808080000B
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        0
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            name
+; CHECK-NEXT:     FunctionNames:   
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            bar
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            _start
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         Name:            foo
+; CHECK-NEXT:       - Index:           3
+; CHECK-NEXT:         Name:            call_bar
+; CHECK-NEXT: ...

Added: lld/trunk/test/wasm/weak-alias.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/weak-alias.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/weak-alias.ll (added)
+++ lld/trunk/test/wasm/weak-alias.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,82 @@
+; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
+; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o
+; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Test that weak aliases (bar is a weak alias of foo) are linked correctly
+
+declare i32 @bar() local_unnamed_addr #1
+
+; Function Attrs: nounwind uwtable
+define i32 @_start() local_unnamed_addr #1 {
+entry:
+  %call = tail call i32 @bar() #2
+  ret i32 %call
+}
+
+; CHECK:      --- !WASM
+; CHECK-NEXT: FileHeader:      
+; CHECK-NEXT:   Version:         0x00000001
+; CHECK-NEXT: Sections:        
+; CHECK-NEXT:   - Type:            TYPE
+; CHECK-NEXT:     Signatures:      
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         ReturnType:      I32
+; CHECK-NEXT:         ParamTypes:      
+; CHECK-NEXT:   - Type:            FUNCTION
+; CHECK-NEXT:     FunctionTypes:   [ 0, 0, 0 ]
+; CHECK-NEXT:   - Type:            TABLE
+; CHECK-NEXT:     Tables:          
+; CHECK-NEXT:       - ElemType:        ANYFUNC
+; CHECK-NEXT:         Limits:          
+; CHECK-NEXT:           Flags:           0x00000001
+; CHECK-NEXT:           Initial:         0x00000001
+; CHECK-NEXT:           Maximum:         0x00000001
+; CHECK-NEXT:   - Type:            MEMORY
+; CHECK-NEXT:     Memories:        
+; CHECK-NEXT:       - Initial:         0x00000002
+; CHECK-NEXT:   - Type:            GLOBAL
+; CHECK-NEXT:     Globals:         
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         true
+; CHECK-NEXT:         InitExpr:        
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           66560
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:         
+; CHECK-NEXT:       - Name:            memory
+; CHECK-NEXT:         Kind:            MEMORY
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            bar
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:       - Name:            _start
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            foo
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:       - Name:            call_bar
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:   - Type:            CODE
+; CHECK-NEXT:     Functions:       
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            1081808080000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            41000B
+; CHECK-NEXT:       - Locals:          
+; CHECK-NEXT:         Body:            1081808080000B
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        0
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            name
+; CHECK-NEXT:     FunctionNames:   
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         Name:            _start
+; CHECK-NEXT:       - Index:           1
+; CHECK-NEXT:         Name:            foo
+; CHECK-NEXT:       - Index:           2
+; CHECK-NEXT:         Name:            call_bar
+; CHECK-NEXT: ...

Added: lld/trunk/test/wasm/weak-external.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/weak-external.ll?rev=318539&view=auto
==============================================================================
--- lld/trunk/test/wasm/weak-external.ll (added)
+++ lld/trunk/test/wasm/weak-external.ll Fri Nov 17 10:14:09 2017
@@ -0,0 +1,86 @@
+; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
+; RUN: lld -flavor wasm -strip-debug %t.o -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Test that undefined weak externals (global_var) and (foo) don't cause
+; link failures and resolve to zero.
+
+ at global_var = extern_weak global i32, align 4
+
+declare extern_weak i32 @foo()
+
+define hidden i8* @get_address_of_foo() #0 {
+entry:
+  ret i8* bitcast (i32 ()* @foo to i8*)
+}
+
+define hidden i32* @get_address_of_global_var() #0 {
+  ret i32* @global_var
+}
+
+define hidden i32 @_start() #0 {
+entry:
+    %0 = load i32, i32* @global_var, align 4
+    ret i32 %0
+}
+
+; CHECK:      --- !WASM
+; CHECK-NEXT: FileHeader:
+; CHECK-NEXT:   Version:         0x00000001
+; CHECK-NEXT: Sections:
+; CHECK-NEXT:   - Type:            TYPE
+; CHECK-NEXT:     Signatures:
+; CHECK-NEXT:       - Index:           0
+; CHECK-NEXT:         ReturnType:      I32
+; CHECK-NEXT:         ParamTypes:
+; CHECK-NEXT:   - Type:            FUNCTION
+; CHECK-NEXT:     FunctionTypes:   [ 0, 0, 0 ]
+; CHECK-NEXT:   - Type:            TABLE
+; CHECK-NEXT:     Tables:          
+; CHECK-NEXT:       - ElemType:        ANYFUNC
+; CHECK-NEXT:         Limits:          
+; CHECK-NEXT:           Flags:           0x00000001
+; CHECK-NEXT:           Initial:         0x00000002
+; CHECK-NEXT:           Maximum:         0x00000002
+; CHECK-NEXT:   - Type:            MEMORY
+; CHECK-NEXT:     Memories:
+; CHECK-NEXT:       - Initial:         0x00000002
+; CHECK-NEXT:   - Type:            GLOBAL
+; CHECK-NEXT:     Globals:
+; CHECK-NEXT:       - Type:            I32
+; CHECK-NEXT:         Mutable:         true
+; CHECK-NEXT:         InitExpr:
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           66560
+; CHECK-NEXT:   - Type:            EXPORT
+; CHECK-NEXT:     Exports:
+; CHECK-NEXT:       - Name:            memory
+; CHECK-NEXT:         Kind:            MEMORY
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            get_address_of_foo
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           0
+; CHECK-NEXT:       - Name:            get_address_of_global_var
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           1
+; CHECK-NEXT:       - Name:            _start
+; CHECK-NEXT:         Kind:            FUNCTION
+; CHECK-NEXT:         Index:           2
+; CHECK-NEXT:   - Type:            ELEM
+; CHECK-NEXT:     Segments:        
+; CHECK-NEXT:       - Offset:          
+; CHECK-NEXT:           Opcode:          I32_CONST
+; CHECK-NEXT:           Value:           1
+; CHECK-NEXT:         Functions:       [ 0 ]
+; CHECK-NEXT:   - Type:            CODE
+; CHECK-NEXT:     Functions:
+; CHECK-NEXT:       - Locals:
+; CHECK-NEXT:         Body:            4181808080000B
+; CHECK-NEXT:       - Locals:
+; CHECK-NEXT:         Body:            41FFFFFFFF7F0B
+; CHECK-NEXT:       - Locals:
+; CHECK-NEXT:         Body:            41002802FFFFFFFF0F0B
+; CHECK-NEXT:   - Type:            CUSTOM
+; CHECK-NEXT:     Name:            linking
+; CHECK-NEXT:     DataSize:        0
+; CHECK-NEXT: ...

Modified: lld/trunk/tools/lld/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld/CMakeLists.txt?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/tools/lld/CMakeLists.txt (original)
+++ lld/trunk/tools/lld/CMakeLists.txt Fri Nov 17 10:14:09 2017
@@ -11,13 +11,14 @@ target_link_libraries(lld
   lldDriver
   lldELF
   lldMinGW
+  lldWasm
   )
 
 install(TARGETS lld
   RUNTIME DESTINATION bin)
 
 if(NOT LLD_SYMLINKS_TO_CREATE)
-  set(LLD_SYMLINKS_TO_CREATE lld-link ld.lld ld64.lld)
+  set(LLD_SYMLINKS_TO_CREATE lld-link ld.lld ld64.lld wasm-ld)
 endif()
 
 foreach(link ${LLD_SYMLINKS_TO_CREATE})

Modified: lld/trunk/tools/lld/lld.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld/lld.cpp?rev=318539&r1=318538&r2=318539&view=diff
==============================================================================
--- lld/trunk/tools/lld/lld.cpp (original)
+++ lld/trunk/tools/lld/lld.cpp Fri Nov 17 10:14:09 2017
@@ -34,6 +34,7 @@ enum Flavor {
   Gnu,     // -flavor gnu
   WinLink, // -flavor link
   Darwin,  // -flavor darwin
+  Wasm,    // -flavor wasm
 };
 
 LLVM_ATTRIBUTE_NORETURN static void die(const Twine &S) {
@@ -44,6 +45,7 @@ LLVM_ATTRIBUTE_NORETURN static void die(
 static Flavor getFlavor(StringRef S) {
   return StringSwitch<Flavor>(S)
       .CasesLower("ld", "ld.lld", "gnu", Gnu)
+      .CasesLower("wasm", "ld-wasm", Wasm)
       .CaseLower("link", WinLink)
       .CasesLower("ld64", "ld64.lld", "darwin", Darwin)
       .Default(Invalid);
@@ -118,6 +120,8 @@ int main(int Argc, const char **Argv) {
     return !coff::link(Args, true);
   case Darwin:
     return !mach_o::link(Args);
+  case Wasm:
+    return !wasm::link(Args, true);
   default:
     die("lld is a generic driver.\n"
         "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead.");

Added: lld/trunk/wasm/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/CMakeLists.txt?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/CMakeLists.txt (added)
+++ lld/trunk/wasm/CMakeLists.txt Fri Nov 17 10:14:09 2017
@@ -0,0 +1,28 @@
+set(LLVM_TARGET_DEFINITIONS Options.td)
+tablegen(LLVM Options.inc -gen-opt-parser-defs)
+add_public_tablegen_target(WasmOptionsTableGen)
+
+add_lld_library(lldWasm
+  Driver.cpp
+  InputFiles.cpp
+  InputSegment.cpp
+  OutputSections.cpp
+  Strings.cpp
+  SymbolTable.cpp
+  Symbols.cpp
+  Writer.cpp
+  WriterUtils.cpp
+
+  LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  BinaryFormat
+  Core
+  Demangle
+  Object
+  Option
+  Support
+
+  LINK_LIBS
+  lldCommon
+  lldCore
+  )

Propchange: lld/trunk/wasm/CMakeLists.txt
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Config.h (added)
+++ lld/trunk/wasm/Config.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,52 @@
+//===- Config.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_CONFIG_H
+#define LLD_WASM_CONFIG_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Wasm.h"
+
+#include "Symbols.h"
+
+using llvm::wasm::WasmGlobal;
+
+#include <set>
+
+namespace lld {
+namespace wasm {
+
+struct Configuration {
+  bool AllowUndefined = false;
+  bool Demangle = true;
+  bool EmitRelocs = false;
+  bool ImportMemory = false;
+  bool Relocatable = false;
+  bool StripDebug = false;
+  bool StripAll = false;
+  uint32_t ZStackSize = 0;
+  uint32_t MaxMemory = 0;
+  uint32_t GlobalBase = 0;
+  uint32_t InitialMemory = 0;
+  llvm::StringRef Entry;
+  llvm::StringRef Sysroot;
+  llvm::StringRef OutputFile;
+
+  std::vector<llvm::StringRef> SearchPaths;
+  std::set<llvm::StringRef> AllowUndefinedSymbols;
+  std::vector<std::pair<Symbol *, WasmGlobal>> SyntheticGlobals;
+};
+
+// The only instance of Configuration struct.
+extern Configuration *Config;
+
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/Config.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Driver.cpp (added)
+++ lld/trunk/wasm/Driver.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,357 @@
+//===- Driver.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Common/Driver.h"
+#include "Config.h"
+#include "Memory.h"
+#include "SymbolTable.h"
+#include "Writer.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Threads.h"
+#include "lld/Common/Version.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+
+using namespace llvm;
+using namespace llvm::sys;
+using namespace llvm::wasm;
+using llvm::sys::Process;
+
+using namespace lld;
+using namespace lld::wasm;
+
+namespace {
+
+// Parses command line options.
+class WasmOptTable : public llvm::opt::OptTable {
+public:
+  WasmOptTable();
+  llvm::opt::InputArgList parse(ArrayRef<const char *> Argv);
+};
+
+// Create enum with OPT_xxx values for each option in Options.td
+enum {
+  OPT_INVALID = 0,
+#define OPTION(_1, _2, ID, _4, _5, _6, _7, _8, _9, _10, _11, _12) OPT_##ID,
+#include "Options.inc"
+#undef OPTION
+};
+
+class LinkerDriver {
+public:
+  void link(ArrayRef<const char *> ArgsArr);
+
+private:
+  void createFiles(llvm::opt::InputArgList &Args);
+  void addFile(StringRef Path);
+  void addLibrary(StringRef Name);
+  std::vector<InputFile *> Files;
+};
+
+} // anonymous namespace
+
+std::vector<SpecificAllocBase *> lld::wasm::SpecificAllocBase::Instances;
+Configuration *lld::wasm::Config;
+BumpPtrAllocator lld::wasm::BAlloc;
+
+bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly,
+                     raw_ostream &Error) {
+  errorHandler().LogName = Args[0];
+  errorHandler().ErrorOS = &Error;
+  errorHandler().ColorDiagnostics = Error.has_colors();
+  errorHandler().ErrorLimitExceededMsg =
+      "too many errors emitted, stopping now (use "
+      "-error-limit=0 to see all errors)";
+
+  Config = make<Configuration>();
+  Symtab = make<SymbolTable>();
+
+  LinkerDriver().link(Args);
+
+  // Exit immediately if we don't need to return to the caller.
+  // This saves time because the overhead of calling destructors
+  // for all globally-allocated objects is not negligible.
+  if (CanExitEarly)
+    exitLld(errorCount() ? 1 : 0);
+
+  freeArena();
+  return !errorCount();
+}
+
+// Create OptTable
+
+// Create prefix string literals used in Options.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "Options.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in Options.td
+static const opt::OptTable::Info OptInfo[] = {
+#define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
+  {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
+   X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
+#include "Options.inc"
+#undef OPTION
+};
+
+static std::vector<StringRef> getArgs(opt::InputArgList &Args, int Id) {
+  std::vector<StringRef> V;
+  for (auto *Arg : Args.filtered(Id))
+    V.push_back(Arg->getValue());
+  return V;
+}
+
+static int getInteger(opt::InputArgList &Args, unsigned Key, int Default) {
+  int V = Default;
+  if (auto *Arg = Args.getLastArg(Key)) {
+    StringRef S = Arg->getValue();
+    if (S.getAsInteger(10, V))
+      error(Arg->getSpelling() + ": number expected, but got " + S);
+  }
+  return V;
+}
+
+static uint64_t getZOptionValue(opt::InputArgList &Args, StringRef Key,
+                                uint64_t Default) {
+  for (auto *Arg : Args.filtered(OPT_z)) {
+    StringRef Value = Arg->getValue();
+    size_t Pos = Value.find("=");
+    if (Pos != StringRef::npos && Key == Value.substr(0, Pos)) {
+      Value = Value.substr(Pos + 1);
+      uint64_t Res;
+      if (Value.getAsInteger(0, Res))
+        error("invalid " + Key + ": " + Value);
+      return Res;
+    }
+  }
+  return Default;
+}
+
+static std::vector<StringRef> getLines(MemoryBufferRef MB) {
+  SmallVector<StringRef, 0> Arr;
+  MB.getBuffer().split(Arr, '\n');
+
+  std::vector<StringRef> Ret;
+  for (StringRef S : Arr) {
+    S = S.trim();
+    if (!S.empty() && S[0] != '#')
+      Ret.push_back(S);
+  }
+  return Ret;
+}
+
+// Set color diagnostics according to -color-diagnostics={auto,always,never}
+// or -no-color-diagnostics flags.
+static void handleColorDiagnostics(opt::InputArgList &Args) {
+  auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq,
+                              OPT_no_color_diagnostics);
+  if (!Arg)
+    return;
+
+  if (Arg->getOption().getID() == OPT_color_diagnostics)
+    errorHandler().ColorDiagnostics = true;
+  else if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+    errorHandler().ColorDiagnostics = false;
+  else {
+    StringRef S = Arg->getValue();
+    if (S == "always")
+      errorHandler().ColorDiagnostics = true;
+    if (S == "never")
+      errorHandler().ColorDiagnostics = false;
+    if (S != "auto")
+      error("unknown option: -color-diagnostics=" + S);
+  }
+}
+
+// Find a file by concatenating given paths.
+static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) {
+  SmallString<128> S;
+  path::append(S, Path1, Path2);
+  if (fs::exists(S))
+    return S.str().str();
+  return None;
+}
+
+// Inject a new wasm global into the output binary with the given value.
+// Wasm global are used in relocatable object files to model symbol imports
+// and exports.  In the final exectuable the only use of wasm globals is the
+// for the exlicit stack pointer (__stack_pointer).
+static void addSyntheticGlobal(StringRef Name, int32_t Value) {
+  log("injecting global: " + Name);
+  Symbol *S = Symtab->addDefinedGlobal(Name);
+  S->setOutputIndex(Config->SyntheticGlobals.size());
+
+  WasmGlobal Global;
+  Global.Mutable = true;
+  Global.Type = WASM_TYPE_I32;
+  Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+  Global.InitExpr.Value.Int32 = Value;
+  Config->SyntheticGlobals.emplace_back(S, Global);
+}
+
+// Inject a new undefined symbol into the link.  This will cause the link to
+// fail unless this symbol can be found.
+static void addSyntheticUndefinedFunction(StringRef Name) {
+  log("injecting undefined func: " + Name);
+  Symtab->addUndefinedFunction(Name);
+}
+
+static void printHelp(const char *Argv0) {
+  WasmOptTable Table;
+  Table.PrintHelp(outs(), Argv0, "LLVM Linker", false);
+}
+
+WasmOptTable::WasmOptTable() : OptTable(OptInfo) {}
+
+opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) {
+  SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size());
+
+  unsigned MissingIndex;
+  unsigned MissingCount;
+  opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount);
+
+  handleColorDiagnostics(Args);
+  for (auto *Arg : Args.filtered(OPT_UNKNOWN))
+    error("unknown argument: " + Arg->getSpelling());
+  return Args;
+}
+
+void LinkerDriver::addFile(StringRef Path) {
+  Optional<MemoryBufferRef> Buffer = readFile(Path);
+  if (!Buffer.hasValue())
+    return;
+  MemoryBufferRef MBRef = *Buffer;
+
+  if (identify_magic(MBRef.getBuffer()) == file_magic::archive)
+    Files.push_back(make<ArchiveFile>(MBRef));
+  else
+    Files.push_back(make<ObjFile>(MBRef));
+}
+
+// Add a given library by searching it from input search paths.
+void LinkerDriver::addLibrary(StringRef Name) {
+  for (StringRef Dir : Config->SearchPaths) {
+    if (Optional<std::string> S = findFile(Dir, "lib" + Name + ".a")) {
+      addFile(*S);
+      return;
+    }
+  }
+
+  error("unable to find library -l" + Name);
+}
+
+void LinkerDriver::createFiles(opt::InputArgList &Args) {
+  for (auto *Arg : Args) {
+    switch (Arg->getOption().getUnaliasedOption().getID()) {
+    case OPT_l:
+      addLibrary(Arg->getValue());
+      break;
+    case OPT_INPUT:
+      addFile(Arg->getValue());
+      break;
+    }
+  }
+
+  if (Files.empty())
+    error("no input files");
+}
+
+void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
+  WasmOptTable Parser;
+  opt::InputArgList Args = Parser.parse(ArgsArr.slice(1));
+
+  // Handle --help
+  if (Args.hasArg(OPT_help)) {
+    printHelp(ArgsArr[0]);
+    return;
+  }
+
+  // Parse and evaluate -mllvm options.
+  std::vector<const char *> V;
+  V.push_back("lld-link (LLVM option parsing)");
+  for (auto *Arg : Args.filtered(OPT_mllvm))
+    V.push_back(Arg->getValue());
+  cl::ParseCommandLineOptions(V.size(), V.data());
+
+  errorHandler().ErrorLimit = getInteger(Args, OPT_error_limit, 20);
+
+  if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) {
+    outs() << getLLDVersion() << "\n";
+    return;
+  }
+
+  Config->AllowUndefined = Args.hasArg(OPT_allow_undefined);
+  Config->EmitRelocs = Args.hasArg(OPT_emit_relocs);
+  Config->Entry = Args.getLastArgValue(OPT_entry);
+  Config->ImportMemory = Args.hasArg(OPT_import_memory);
+  Config->OutputFile = Args.getLastArgValue(OPT_o);
+  Config->Relocatable = Args.hasArg(OPT_relocatable);
+  Config->SearchPaths = getArgs(Args, OPT_L);
+  Config->StripAll = Args.hasArg(OPT_strip_all);
+  Config->StripDebug = Args.hasArg(OPT_strip_debug);
+  Config->Sysroot = Args.getLastArgValue(OPT_sysroot);
+  errorHandler().Verbose = Args.hasArg(OPT_verbose);
+  ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
+
+  Config->InitialMemory = getInteger(Args, OPT_initial_memory, 0);
+  Config->GlobalBase = getInteger(Args, OPT_global_base, 1024);
+  Config->MaxMemory = getInteger(Args, OPT_max_memory, 0);
+  Config->ZStackSize = getZOptionValue(Args, "stack-size", WasmPageSize);
+
+  if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
+    if (Optional<MemoryBufferRef> Buf = readFile(Arg->getValue()))
+      for (StringRef Sym : getLines(*Buf))
+        Config->AllowUndefinedSymbols.insert(Sym);
+
+  if (Config->OutputFile.empty())
+    error("no output file specified");
+
+  if (!Args.hasArg(OPT_INPUT))
+    error("no input files");
+
+  if (Config->Relocatable && !Config->Entry.empty())
+    error("entry point specified for relocatable output file");
+
+  if (!Config->Relocatable) {
+    if (Config->Entry.empty())
+      Config->Entry = "_start";
+    addSyntheticUndefinedFunction(Config->Entry);
+
+    addSyntheticGlobal("__stack_pointer", 0);
+  }
+
+  createFiles(Args);
+  if (errorCount())
+    return;
+
+  // Add all files to the symbol table. This will add almost all
+  // symbols that we need to the symbol table.
+  for (InputFile *F : Files)
+    Symtab->addFile(F);
+
+  // Make sure we have resolved all symbols.
+  if (!Config->Relocatable && !Config->AllowUndefined) {
+    Symtab->reportRemainingUndefines();
+    if (errorCount())
+      return;
+  }
+
+  if (!Config->Entry.empty()) {
+    Symbol *Sym = Symtab->find(Config->Entry);
+    if (!Sym->isFunction())
+      fatal("entry point is not a function: " + Sym->getName());
+  }
+
+  // Write the result to the file.
+  writeResult();
+}

Propchange: lld/trunk/wasm/Driver.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/InputFiles.cpp (added)
+++ lld/trunk/wasm/InputFiles.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,275 @@
+//===- InputFiles.cpp -----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputFiles.h"
+
+#include "Config.h"
+#include "InputSegment.h"
+#include "Memory.h"
+#include "Strings.h"
+#include "SymbolTable.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace lld;
+using namespace lld::wasm;
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::wasm;
+
+Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
+  log("Loading: " + Path);
+
+  auto MBOrErr = MemoryBuffer::getFile(Path);
+  if (auto EC = MBOrErr.getError()) {
+    error("cannot open " + Path + ": " + EC.message());
+    return None;
+  }
+  std::unique_ptr<MemoryBuffer> &MB = *MBOrErr;
+  MemoryBufferRef MBRef = MB->getMemBufferRef();
+  make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); // take MB ownership
+
+  return MBRef;
+}
+
+void ObjFile::dumpInfo() const {
+  log("reloc info for: " + getName() + "\n" +
+      "        FunctionIndexOffset : " + Twine(FunctionIndexOffset) + "\n" +
+      "         NumFunctionImports : " + Twine(NumFunctionImports()) + "\n" +
+      "           TableIndexOffset : " + Twine(TableIndexOffset) + "\n" +
+      "          GlobalIndexOffset : " + Twine(GlobalIndexOffset) + "\n" +
+      "           NumGlobalImports : " + Twine(NumGlobalImports()) + "\n");
+}
+
+bool ObjFile::isImportedFunction(uint32_t Index) const {
+  return Index < NumFunctionImports();
+}
+
+const Symbol *ObjFile::getFunctionSymbol(uint32_t Index) const {
+  return FunctionSymbols[Index];
+}
+
+const Symbol *ObjFile::getGlobalSymbol(uint32_t Index) const {
+  return GlobalSymbols[Index];
+}
+
+uint32_t ObjFile::getRelocatedAddress(uint32_t Index) const {
+  return getGlobalSymbol(Index)->getVirtualAddress();
+}
+
+uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const {
+  DEBUG(dbgs() << "relocateFunctionIndex: " << Original);
+  const Symbol *Sym = getFunctionSymbol(Original);
+  uint32_t Index;
+  if (Sym)
+    Index = Sym->getOutputIndex();
+  else
+    Index = Original + FunctionIndexOffset;
+
+  DEBUG(dbgs() << " -> " << Index << "\n");
+  return Index;
+}
+
+uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
+  return TypeMap[Original];
+}
+
+uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
+  return Original + TableIndexOffset;
+}
+
+uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const {
+  DEBUG(dbgs() << "relocateGlobalIndex: " << Original);
+  uint32_t Index;
+  const Symbol *Sym = getGlobalSymbol(Original);
+  if (Sym)
+    Index = Sym->getOutputIndex();
+  else
+    Index = Original + GlobalIndexOffset;
+
+  DEBUG(dbgs() << " -> " << Index << "\n");
+  return Index;
+}
+
+void ObjFile::parse() {
+  // Parse a memory buffer as a wasm file.
+  DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n");
+  std::unique_ptr<Binary> Bin = check(createBinary(MB), toString(this));
+
+  auto *Obj = dyn_cast<WasmObjectFile>(Bin.get());
+  if (!Obj)
+    fatal(toString(this) + ": not a wasm file");
+  if (!Obj->isRelocatableObject())
+    fatal(toString(this) + ": not a relocatable wasm file");
+
+  Bin.release();
+  WasmObj.reset(Obj);
+
+  // Find the code and data sections.  Wasm objects can have at most one code
+  // and one data section.
+  for (const SectionRef &Sec : WasmObj->sections()) {
+    const WasmSection &Section = WasmObj->getWasmSection(Sec);
+    if (Section.Type == WASM_SEC_CODE)
+      CodeSection = &Section;
+    else if (Section.Type == WASM_SEC_DATA)
+      DataSection = &Section;
+  }
+
+  initializeSymbols();
+}
+
+// Return the InputSegment in which a given symbol is defined.
+InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) {
+  uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym);
+  for (InputSegment *Segment : Segments) {
+    if (Address >= Segment->startVA() && Address < Segment->endVA()) {
+      DEBUG(dbgs() << "Found symbol in segment: " << WasmSym.Name << " -> "
+                   << Segment->getName() << "\n");
+
+      return Segment;
+    }
+  }
+  error("Symbol not found in any segment: " + WasmSym.Name);
+  return nullptr;
+}
+
+void ObjFile::initializeSymbols() {
+  Symbols.reserve(WasmObj->getNumberOfSymbols());
+
+  for (const WasmImport &Import : WasmObj->imports()) {
+    switch (Import.Kind) {
+    case WASM_EXTERNAL_FUNCTION:
+      ++FunctionImports;
+      break;
+    case WASM_EXTERNAL_GLOBAL:
+      ++GlobalImports;
+      break;
+    }
+  }
+
+  FunctionSymbols.resize(FunctionImports + WasmObj->functions().size());
+  GlobalSymbols.resize(GlobalImports + WasmObj->globals().size());
+
+  for (const WasmSegment &Seg : WasmObj->dataSegments())
+    Segments.emplace_back(make<InputSegment>(&Seg, this));
+
+  Symbol *S;
+  for (const SymbolRef &Sym : WasmObj->symbols()) {
+    const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl());
+    switch (WasmSym.Type) {
+    case WasmSymbol::SymbolType::FUNCTION_IMPORT:
+    case WasmSymbol::SymbolType::GLOBAL_IMPORT:
+      S = createUndefined(WasmSym);
+      break;
+    case WasmSymbol::SymbolType::GLOBAL_EXPORT:
+      S = createDefined(WasmSym, getSegment(WasmSym));
+      break;
+    case WasmSymbol::SymbolType::FUNCTION_EXPORT:
+      S = createDefined(WasmSym);
+      break;
+    case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
+      // These are for debugging only, no need to create linker symbols for them
+      continue;
+    }
+
+    Symbols.push_back(S);
+    if (WasmSym.isFunction()) {
+      DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> "
+                   << toString(*S) << "\n");
+      FunctionSymbols[WasmSym.ElementIndex] = S;
+    } else {
+      DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> "
+                   << toString(*S) << "\n");
+      GlobalSymbols[WasmSym.ElementIndex] = S;
+    }
+  }
+
+  DEBUG(dbgs() << "Functions: " << FunctionSymbols.size() << "\n");
+  DEBUG(dbgs() << "Globals  : " << GlobalSymbols.size() << "\n");
+}
+
+Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) {
+  return Symtab->addUndefined(this, &Sym);
+}
+
+Symbol *ObjFile::createDefined(const WasmSymbol &Sym,
+                               const InputSegment *Segment) {
+  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);
+    return S;
+  }
+  return Symtab->addDefined(this, &Sym, Segment);
+}
+
+void ArchiveFile::parse() {
+  // Parse a MemoryBufferRef as an archive file.
+  DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n");
+  File = check(Archive::create(MB), toString(this));
+
+  // Read the symbol table to construct Lazy symbols.
+  int Count = 0;
+  for (const Archive::Symbol &Sym : File->symbols()) {
+    Symtab->addLazy(this, &Sym);
+    ++Count;
+  }
+  DEBUG(dbgs() << "Read " << Count << " symbols\n");
+}
+
+void ArchiveFile::addMember(const Archive::Symbol *Sym) {
+  const Archive::Child &C =
+      check(Sym->getMember(),
+            "could not get the member for symbol " + Sym->getName());
+
+  // Don't try to load the same member twice (this can happen when members
+  // mutually reference each other).
+  if (!Seen.insert(C.getChildOffset()).second)
+    return;
+
+  DEBUG(dbgs() << "loading lazy: " << displayName(Sym->getName()) << "\n");
+  DEBUG(dbgs() << "from archive: " << toString(this) << "\n");
+
+  MemoryBufferRef MB =
+      check(C.getMemoryBufferRef(),
+            "could not get the buffer for the member defining symbol " +
+                Sym->getName());
+
+  if (identify_magic(MB.getBuffer()) != file_magic::wasm_object) {
+    error("unknown file type: " + MB.getBufferIdentifier());
+    return;
+  }
+
+  InputFile *Obj = make<ObjFile>(MB);
+  Obj->ParentName = ParentName;
+  Symtab->addFile(Obj);
+}
+
+// Returns a string in the format of "foo.o" or "foo.a(bar.o)".
+std::string lld::toString(wasm::InputFile *File) {
+  if (!File)
+    return "<internal>";
+
+  if (File->ParentName.empty())
+    return File->getName();
+
+  return (File->ParentName + "(" + File->getName() + ")").str();
+}

Propchange: lld/trunk/wasm/InputFiles.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputFiles.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/InputFiles.h (added)
+++ lld/trunk/wasm/InputFiles.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,150 @@
+//===- InputFiles.h ---------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_INPUT_FILES_H
+#define LLD_WASM_INPUT_FILES_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include "WriterUtils.h"
+
+#include <vector>
+
+using llvm::object::WasmObjectFile;
+using llvm::object::WasmSection;
+using llvm::object::WasmSymbol;
+using llvm::object::Archive;
+using llvm::wasm::WasmImport;
+
+namespace lld {
+namespace wasm {
+
+class Symbol;
+class InputSegment;
+
+class InputFile {
+public:
+  enum Kind {
+    ObjectKind,
+    ArchiveKind,
+  };
+
+  virtual ~InputFile() {}
+
+  // Returns the filename.
+  StringRef getName() const { return MB.getBufferIdentifier(); }
+
+  // Reads a file (the constructor doesn't do that).
+  virtual void parse() = 0;
+
+  Kind kind() const { return FileKind; }
+
+  // An archive file name if this file is created from an archive.
+  StringRef ParentName;
+
+protected:
+  InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {}
+  MemoryBufferRef MB;
+
+private:
+  const Kind FileKind;
+};
+
+// .a file (ar archive)
+class ArchiveFile : public InputFile {
+public:
+  explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; }
+
+  void addMember(const Archive::Symbol *Sym);
+
+  void parse() override;
+
+private:
+  std::unique_ptr<Archive> File;
+  llvm::DenseSet<uint64_t> Seen;
+};
+
+// .o file (wasm object file)
+class ObjFile : public InputFile {
+public:
+  explicit ObjFile(MemoryBufferRef M) : InputFile(ObjectKind, M) {}
+  static bool classof(const InputFile *F) { return F->kind() == ObjectKind; }
+
+  void parse() override;
+
+  // Returns the underlying wasm file.
+  const WasmObjectFile *getWasmObj() const { return WasmObj.get(); }
+
+  void dumpInfo() const;
+
+  uint32_t relocateTypeIndex(uint32_t Original) const;
+  uint32_t relocateFunctionIndex(uint32_t Original) const;
+  uint32_t relocateGlobalIndex(uint32_t Original) const;
+  uint32_t relocateTableIndex(uint32_t Original) const;
+  uint32_t getRelocatedAddress(uint32_t Index) const;
+
+  // Returns true if the given function index is an imported function,
+  // as opposed to the locally defined function.
+  bool isImportedFunction(uint32_t Index) const;
+
+  size_t NumFunctionImports() const { return FunctionImports; }
+  size_t NumGlobalImports() const { return GlobalImports; }
+
+  int32_t FunctionIndexOffset = 0;
+  int32_t GlobalIndexOffset = 0;
+  int32_t TableIndexOffset = 0;
+  const WasmSection *CodeSection = nullptr;
+  std::vector<OutputRelocation> CodeRelocations;
+  int32_t CodeOffset = 0;
+  const WasmSection *DataSection = nullptr;
+
+  std::vector<uint32_t> TypeMap;
+  std::vector<InputSegment *> Segments;
+
+  const std::vector<Symbol *> &getSymbols() { return Symbols; }
+
+private:
+  Symbol *createDefined(const WasmSymbol &Sym,
+                        const InputSegment *Segment = nullptr);
+  Symbol *createUndefined(const WasmSymbol &Sym);
+  void initializeSymbols();
+  InputSegment *getSegment(const WasmSymbol &WasmSym);
+  const Symbol *getFunctionSymbol(uint32_t Index) const;
+  const Symbol *getGlobalSymbol(uint32_t Index) const;
+
+  // List of all symbols referenced or defined by this file.
+  std::vector<Symbol *> Symbols;
+
+  // List of all function symbols indexed by the function index space
+  std::vector<const Symbol *> FunctionSymbols;
+
+  // List of all global symbols indexed by the global index space
+  std::vector<const Symbol *> GlobalSymbols;
+
+  uint32_t GlobalImports = 0;
+  uint32_t FunctionImports = 0;
+  std::unique_ptr<WasmObjectFile> WasmObj;
+};
+
+// Opens a given file.
+llvm::Optional<MemoryBufferRef> readFile(StringRef Path);
+
+} // namespace wasm
+
+std::string toString(wasm::InputFile *File);
+
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/InputFiles.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/InputSegment.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputSegment.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/InputSegment.cpp (added)
+++ lld/trunk/wasm/InputSegment.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,25 @@
+//===- InputSegment.cpp ---------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InputSegment.h"
+#include "OutputSegment.h"
+#include "lld/Common/LLVM.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace lld::wasm;
+
+uint32_t InputSegment::translateVA(uint32_t Address) const {
+  assert(Address >= startVA() && Address < endVA());
+  int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA();
+  DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta
+               << " Address=" << Address << "\n");
+  return Address + Delta;
+}

Propchange: lld/trunk/wasm/InputSegment.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/InputSegment.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/InputSegment.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/InputSegment.h (added)
+++ lld/trunk/wasm/InputSegment.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,74 @@
+//===- InputSegment.h -------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Represents a WebAssembly data segment which can be included as part of
+// an output data segments.  Note that in WebAssembly, unlike ELF and other
+// formats, used the term "data segment" to refer to the continous regions of
+// memory that make on the data section. See:
+// https://webassembly.github.io/spec/syntax/modules.html#syntax-data
+//
+// For example, by default, clang will produce a separate data section for
+// each global variable.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_INPUT_SEGMENT_H
+#define LLD_WASM_INPUT_SEGMENT_H
+
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Wasm.h"
+
+using llvm::object::WasmSegment;
+using llvm::wasm::WasmRelocation;
+
+namespace lld {
+namespace wasm {
+
+class ObjFile;
+class OutputSegment;
+
+class InputSegment {
+public:
+  InputSegment(const WasmSegment *Seg, const ObjFile *F)
+      : Segment(Seg), File(F) {}
+
+  // Translate an offset in the input segment to an offset in the output
+  // segment.
+  uint32_t translateVA(uint32_t Address) const;
+
+  const OutputSegment *getOutputSegment() const { return OutputSeg; }
+
+  uint32_t getOutputSegmentOffset() const { return OutputSegmentOffset; }
+
+  uint32_t getInputSectionOffset() const { return Segment->SectionOffset; }
+
+  void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) {
+    OutputSeg = Segment;
+    OutputSegmentOffset = Offset;
+  }
+
+  uint32_t getSize() const { return Segment->Data.Content.size(); }
+  uint32_t getAlignment() const { return Segment->Data.Alignment; }
+  uint32_t startVA() const { return Segment->Data.Offset.Value.Int32; }
+  uint32_t endVA() const { return startVA() + getSize(); }
+  StringRef getName() const { return Segment->Data.Name; }
+
+  const WasmSegment *Segment;
+  const ObjFile *File;
+  std::vector<WasmRelocation> Relocations;
+
+protected:
+  const OutputSegment *OutputSeg = nullptr;
+  uint32_t OutputSegmentOffset = 0;
+};
+
+} // namespace wasm
+} // namespace lld
+
+#endif // LLD_WASM_INPUT_SEGMENT_H

Propchange: lld/trunk/wasm/InputSegment.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Memory.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Memory.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Memory.h (added)
+++ lld/trunk/wasm/Memory.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,52 @@
+//===- Memory.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See WASM/Memory.h
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_MEMORY_H
+#define LLD_WASM_MEMORY_H
+
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
+
+namespace lld {
+namespace wasm {
+
+extern llvm::BumpPtrAllocator BAlloc;
+extern llvm::StringSaver Saver;
+
+struct SpecificAllocBase {
+  SpecificAllocBase() { Instances.push_back(this); }
+  virtual ~SpecificAllocBase() = default;
+  virtual void reset() = 0;
+  static std::vector<SpecificAllocBase *> Instances;
+};
+
+template <class T> struct SpecificAlloc : public SpecificAllocBase {
+  void reset() override { Alloc.DestroyAll(); }
+  llvm::SpecificBumpPtrAllocator<T> Alloc;
+};
+
+template <typename T, typename... U> T *make(U &&... Args) {
+  static SpecificAlloc<T> Alloc;
+  return new (Alloc.Alloc.Allocate()) T(std::forward<U>(Args)...);
+}
+
+inline void freeArena() {
+  for (SpecificAllocBase *Alloc : SpecificAllocBase::Instances)
+    Alloc->reset();
+  BAlloc.Reset();
+}
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/Memory.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Options.td (added)
+++ lld/trunk/wasm/Options.td Fri Nov 17 10:14:09 2017
@@ -0,0 +1,89 @@
+include "llvm/Option/OptParser.td"
+
+// For options whose names are multiple letters, either one dash or
+// two can precede the option name except those that start with 'o'.
+class F<string name>: Flag<["--", "-"], name>;
+class J<string name>: Joined<["--", "-"], name>;
+class S<string name>: Separate<["--", "-"], name>;
+
+def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">,
+  HelpText<"Add a directory to the library search path">;
+
+def color_diagnostics: F<"color-diagnostics">,
+  HelpText<"Use colors in diagnostics">;
+
+def color_diagnostics_eq: J<"color-diagnostics=">,
+  HelpText<"Use colors in diagnostics">;
+
+// The follow flags are shared with the ELF linker
+def help: F<"help">, HelpText<"Print option help">;
+
+def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">,
+  HelpText<"Root name of library to use">;
+
+def mllvm: S<"mllvm">, HelpText<"Options to pass to LLVM">;
+
+def no_threads: F<"no-threads">,
+  HelpText<"Do not run the linker multi-threaded">;
+
+def no_color_diagnostics: F<"no-color-diagnostics">,
+  HelpText<"Do not use colors in diagnostics">;
+
+def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">,
+  HelpText<"Path to file to write output">;
+
+def threads: F<"threads">, HelpText<"Run the linker multi-threaded">;
+
+def v: Flag<["-"], "v">, HelpText<"Display the version number">;
+
+def version: F<"version">, HelpText<"Display the version number and exit">;
+
+def verbose: F<"verbose">, HelpText<"Verbose mode">;
+
+def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">;
+
+def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">;
+
+def strip_all: F<"strip-all">, HelpText<"Strip all symbols">;
+
+def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">;
+
+def sysroot: J<"sysroot=">, HelpText<"Set the system root">;
+
+def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">,
+  HelpText<"Linker option extensions">;
+
+def entry: S<"entry">, MetaVarName<"<entry>">,
+  HelpText<"Name of entry point symbol">;
+
+def error_limit: J<"error-limit=">,
+  HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">;
+
+// The follow flags are unique to wasm
+
+def global_base: J<"global-base=">,
+  HelpText<"Where to start to place global data">;
+
+def initial_memory: J<"initial-memory=">,
+  HelpText<"Initial size of the linear memory">;
+
+def max_memory: J<"max-memory=">,
+  HelpText<"Maximum size of the linear memory">;
+
+def import_memory: F<"import-memory">,
+  HelpText<"Import memory from the environment">;
+
+def allow_undefined: F<"allow-undefined">,
+  HelpText<"Allow undefined symbols in linked binary">;
+
+def allow_undefined_file: J<"allow-undefined-file=">,
+  HelpText<"Allow symbols listed in <file> to be undefined in linked binary">;
+
+def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, Alias<allow_undefined_file>;
+
+// Aliases
+def alias_initial_memory_i: Flag<["-"], "i">, Alias<initial_memory>;
+def alias_max_memory_m: Flag<["-"], "m">, Alias<max_memory>;
+def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>;
+def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>;
+def alias_entry_entry: J<"entry=">, Alias<entry>;

Added: lld/trunk/wasm/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSections.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/OutputSections.cpp (added)
+++ lld/trunk/wasm/OutputSections.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,330 @@
+//===- OutputSections.cpp -------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "OutputSections.h"
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "Memory.h"
+#include "OutputSegment.h"
+#include "SymbolTable.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Threads.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/LEB128.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace llvm::wasm;
+using namespace lld;
+using namespace lld::wasm;
+
+enum class RelocEncoding {
+  Uleb128,
+  Sleb128,
+  I32,
+};
+
+static StringRef sectionTypeToString(uint32_t SectionType) {
+  switch (SectionType) {
+  case WASM_SEC_CUSTOM:
+    return "CUSTOM";
+  case WASM_SEC_TYPE:
+    return "TYPE";
+  case WASM_SEC_IMPORT:
+    return "IMPORT";
+  case WASM_SEC_FUNCTION:
+    return "FUNCTION";
+  case WASM_SEC_TABLE:
+    return "TABLE";
+  case WASM_SEC_MEMORY:
+    return "MEMORY";
+  case WASM_SEC_GLOBAL:
+    return "GLOBAL";
+  case WASM_SEC_EXPORT:
+    return "EXPORT";
+  case WASM_SEC_START:
+    return "START";
+  case WASM_SEC_ELEM:
+    return "ELEM";
+  case WASM_SEC_CODE:
+    return "CODE";
+  case WASM_SEC_DATA:
+    return "DATA";
+  default:
+    fatal("invalid section type");
+  }
+}
+
+std::string lld::toString(OutputSection *Section) {
+  std::string rtn = sectionTypeToString(Section->Type);
+  if (!Section->Name.empty())
+    rtn += "(" + Section->Name + ")";
+  return rtn;
+}
+
+static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) {
+  DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type
+               << " index=" << Reloc.Reloc.Index << " new=" << Reloc.NewIndex
+               << " value=" << Reloc.Value << " offset=" << Reloc.Reloc.Offset
+               << "\n");
+  Buf += Reloc.Reloc.Offset;
+  int64_t ExistingValue;
+  switch (Reloc.Reloc.Type) {
+  case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+  case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+    ExistingValue = decodeULEB128(Buf);
+    if (ExistingValue != Reloc.Reloc.Index) {
+      DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n");
+      assert(decodeULEB128(Buf) == Reloc.Reloc.Index);
+    }
+    LLVM_FALLTHROUGH;
+  case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+  case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+    encodeULEB128(Reloc.Value, Buf, 5);
+    break;
+  case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+    ExistingValue = decodeSLEB128(Buf);
+    if (ExistingValue != Reloc.Reloc.Index) {
+      DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n");
+      assert(decodeSLEB128(Buf) == Reloc.Reloc.Index);
+    }
+    LLVM_FALLTHROUGH;
+  case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+    encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5);
+    break;
+  case R_WEBASSEMBLY_TABLE_INDEX_I32:
+  case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+    support::endian::write32<support::little>(Buf, Reloc.Value);
+    break;
+  default:
+    llvm_unreachable("unknown relocation type");
+  }
+}
+
+static void applyRelocations(uint8_t *Buf,
+                             const std::vector<OutputRelocation> &Relocs) {
+  log("applyRelocations: count=" + Twine(Relocs.size()));
+  for (const OutputRelocation &Reloc : Relocs) {
+    applyRelocation(Buf, Reloc);
+  }
+}
+
+// Relocations contain an index into the function, global or table index
+// space of the input file.  This function takes a relocation and returns the
+// relocated index (i.e. translates from the input index space to the output
+// index space).
+static uint32_t calcNewIndex(const ObjFile &File, const WasmRelocation &Reloc) {
+  switch (Reloc.Type) {
+  case R_WEBASSEMBLY_TYPE_INDEX_LEB:
+    return File.relocateTypeIndex(Reloc.Index);
+  case R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+    return File.relocateFunctionIndex(Reloc.Index);
+  case R_WEBASSEMBLY_TABLE_INDEX_I32:
+  case R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+    return File.relocateTableIndex(Reloc.Index);
+  case R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
+  case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+  case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+  case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+    return File.relocateGlobalIndex(Reloc.Index);
+  default:
+    llvm_unreachable("unknown relocation type");
+  }
+}
+
+// Take a vector of relocations from an input file and create output
+// relocations based on them. Calculates the updated index and offset for
+// each relocation as well as the value to write out in the final binary.
+static void calcRelocations(const ObjFile &File,
+                            ArrayRef<WasmRelocation> Relocs,
+                            std::vector<OutputRelocation> &OutputRelocs,
+                            int32_t OutputOffset) {
+  log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset));
+  for (const WasmRelocation &Reloc : Relocs) {
+    int64_t NewIndex = calcNewIndex(File, Reloc);
+    OutputRelocation NewReloc;
+    NewReloc.Reloc = Reloc;
+    NewReloc.Reloc.Offset += OutputOffset;
+    NewReloc.NewIndex = NewIndex;
+    DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index
+                 << " offset=" << Reloc.Offset << " new=" << NewIndex
+                 << " newOffset=" << NewReloc.Reloc.Offset << "\n");
+
+    switch (Reloc.Type) {
+    case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+    case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+    case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+      NewReloc.Value = File.getRelocatedAddress(Reloc.Index);
+      if (NewReloc.Value != UINT32_MAX)
+        NewReloc.Value += Reloc.Addend;
+      break;
+    default:
+      NewReloc.Value = NewIndex;
+    }
+
+    OutputRelocs.emplace_back(NewReloc);
+  }
+}
+
+void OutputSection::createHeader(size_t BodySize) {
+  raw_string_ostream OS(Header);
+  debugWrite(OS.tell(),
+             "section type [" + Twine(sectionTypeToString(Type)) + "]");
+  writeUleb128(OS, Type, nullptr);
+  writeUleb128(OS, BodySize, "section size");
+  OS.flush();
+  log("createHeader: " + toString(this) + " body=" + Twine(BodySize) +
+      " total=" + Twine(getSize()));
+}
+
+CodeSection::CodeSection(uint32_t NumFunctions, std::vector<ObjFile *> &Objs)
+    : OutputSection(WASM_SEC_CODE), InputObjects(Objs) {
+  raw_string_ostream OS(CodeSectionHeader);
+  writeUleb128(OS, NumFunctions, "function count");
+  OS.flush();
+  BodySize = CodeSectionHeader.size();
+
+  for (ObjFile *File : InputObjects) {
+    if (!File->CodeSection)
+      continue;
+
+    File->CodeOffset = BodySize;
+    ArrayRef<uint8_t> Content = File->CodeSection->Content;
+    unsigned HeaderSize = 0;
+    decodeULEB128(Content.data(), &HeaderSize);
+
+    calcRelocations(*File, File->CodeSection->Relocations,
+                    File->CodeRelocations, BodySize - HeaderSize);
+
+    size_t PayloadSize = Content.size() - HeaderSize;
+    BodySize += PayloadSize;
+  }
+
+  createHeader(BodySize);
+}
+
+void CodeSection::writeTo(uint8_t *Buf) {
+  log("writing " + toString(this));
+  log(" size=" + Twine(getSize()));
+  Buf += Offset;
+
+  // Write section header
+  memcpy(Buf, Header.data(), Header.size());
+  Buf += Header.size();
+
+  uint8_t *ContentsStart = Buf;
+
+  // Write code section headers
+  memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size());
+  Buf += CodeSectionHeader.size();
+
+  // Write code section bodies
+  parallelForEach(InputObjects, [ContentsStart](ObjFile *File) {
+    if (!File->CodeSection)
+      return;
+
+    ArrayRef<uint8_t> Content(File->CodeSection->Content);
+
+    // Payload doesn't include the initial header (function count)
+    unsigned HeaderSize = 0;
+    decodeULEB128(Content.data(), &HeaderSize);
+
+    size_t PayloadSize = Content.size() - HeaderSize;
+    memcpy(ContentsStart + File->CodeOffset, Content.data() + HeaderSize,
+           PayloadSize);
+
+    log("applying relocations for: " + File->getName());
+    if (File->CodeRelocations.size())
+      applyRelocations(ContentsStart, File->CodeRelocations);
+  });
+}
+
+uint32_t CodeSection::numRelocations() const {
+  uint32_t Count = 0;
+  for (ObjFile *File : InputObjects)
+    Count += File->CodeRelocations.size();
+  return Count;
+}
+
+void CodeSection::writeRelocations(raw_ostream &OS) const {
+  for (ObjFile *File : InputObjects)
+    for (const OutputRelocation &Reloc : File->CodeRelocations)
+      writeReloc(OS, Reloc);
+}
+
+DataSection::DataSection(std::vector<OutputSegment *> &Segments)
+    : OutputSection(WASM_SEC_DATA), Segments(Segments) {
+  raw_string_ostream OS(DataSectionHeader);
+
+  writeUleb128(OS, Segments.size(), "data segment count");
+  OS.flush();
+  BodySize = DataSectionHeader.size();
+
+  for (OutputSegment *Segment : Segments) {
+    raw_string_ostream OS(Segment->Header);
+    writeUleb128(OS, 0, "memory index");
+    writeUleb128(OS, WASM_OPCODE_I32_CONST, "opcode:i32const");
+    writeSleb128(OS, Segment->StartVA, "memory offset");
+    writeUleb128(OS, WASM_OPCODE_END, "opcode:end");
+    writeUleb128(OS, Segment->Size, "segment size");
+    OS.flush();
+    Segment->setSectionOffset(BodySize);
+    BodySize += Segment->Header.size();
+    log("Data segment: size=" + Twine(Segment->Size));
+    for (const InputSegment *InputSeg : Segment->InputSegments) {
+      uint32_t InputOffset = InputSeg->getInputSectionOffset();
+      uint32_t OutputOffset = Segment->getSectionOffset() +
+                              Segment->Header.size() +
+                              InputSeg->getOutputSegmentOffset();
+      calcRelocations(*InputSeg->File, InputSeg->Relocations, Relocations,
+                      OutputOffset - InputOffset);
+    }
+    BodySize += Segment->Size;
+  }
+
+  createHeader(BodySize);
+}
+
+void DataSection::writeTo(uint8_t *Buf) {
+  log("writing " + toString(this) + " size=" + Twine(getSize()) +
+      " body=" + Twine(BodySize));
+  Buf += Offset;
+
+  // Write section header
+  memcpy(Buf, Header.data(), Header.size());
+  Buf += Header.size();
+
+  uint8_t *ContentsStart = Buf;
+
+  // Write data section headers
+  memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size());
+
+  parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) {
+    // Write data segment header
+    uint8_t *SegStart = ContentsStart + Segment->getSectionOffset();
+    memcpy(SegStart, Segment->Header.data(), Segment->Header.size());
+
+    // Write segment data payload
+    for (const InputSegment *Input : Segment->InputSegments) {
+      ArrayRef<uint8_t> Content(Input->Segment->Data.Content);
+      memcpy(SegStart + Segment->Header.size() +
+                 Input->getOutputSegmentOffset(),
+             Content.data(), Content.size());
+    }
+  });
+
+  applyRelocations(ContentsStart, Relocations);
+}
+
+void DataSection::writeRelocations(raw_ostream &OS) const {
+  for (const OutputRelocation &Reloc : Relocations)
+    writeReloc(OS, Reloc);
+}

Propchange: lld/trunk/wasm/OutputSections.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSections.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/OutputSections.h (added)
+++ lld/trunk/wasm/OutputSections.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,138 @@
+//===- OutputSections.h -----------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_OUTPUT_SECTIONS_H
+#define LLD_WASM_OUTPUT_SECTIONS_H
+
+#include "InputSegment.h"
+#include "WriterUtils.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/ADT/DenseMap.h"
+
+using llvm::raw_ostream;
+using llvm::raw_string_ostream;
+
+namespace lld {
+
+namespace wasm {
+class OutputSection;
+}
+std::string toString(wasm::OutputSection *Section);
+
+namespace wasm {
+
+class OutputSegment;
+class ObjFile;
+
+class OutputSection {
+public:
+  OutputSection(uint32_t Type, std::string Name = "")
+      : Type(Type), Name(Name) {}
+
+  virtual ~OutputSection() = default;
+
+  void setOffset(size_t NewOffset) {
+    log("setOffset: " + toString(this) + " -> " + Twine(NewOffset));
+    Offset = NewOffset;
+  }
+
+  void createHeader(size_t BodySize);
+  virtual size_t getSize() const = 0;
+  virtual void writeTo(uint8_t *Buf) = 0;
+  virtual void finalizeContents() {}
+
+  std::string Header;
+  uint32_t Type;
+  std::string Name;
+
+  virtual uint32_t numRelocations() const { return 0; }
+  virtual void writeRelocations(raw_ostream &OS) const {}
+
+protected:
+  size_t Offset = 0;
+};
+
+class SyntheticSection : public OutputSection {
+public:
+  SyntheticSection(uint32_t Type, std::string Name = "")
+      : OutputSection(Type, Name), BodyOutputStream(Body) {
+    if (!Name.empty())
+      writeStr(BodyOutputStream, Name);
+  }
+
+  void writeTo(uint8_t *Buf) override {
+    assert(Offset);
+    log("writing " + toString(this));
+    memcpy(Buf + Offset, Header.data(), Header.size());
+    memcpy(Buf + Offset + Header.size(), Body.data(), Body.size());
+  }
+
+  size_t getSize() const override { return Header.size() + Body.size(); }
+
+  void finalizeContents() override {
+    BodyOutputStream.flush();
+    createHeader(Body.size());
+  }
+
+  raw_ostream &getStream() { return BodyOutputStream; }
+
+  std::string Body;
+
+protected:
+  raw_string_ostream BodyOutputStream;
+};
+
+// Some synthetic sections (e.g. "name" and "linking") have subsections.
+// Just like the synthetic sections themselves these need to be created before
+// they can be written out (since they are preceded by their length). This
+// class is used to create subsections and then write them into the stream
+// of the parent section.
+class SubSection : public SyntheticSection {
+public:
+  explicit SubSection(uint32_t Type) : SyntheticSection(Type) {}
+
+  void writeToStream(raw_ostream &OS) {
+    writeBytes(OS, Header.data(), Header.size());
+    writeBytes(OS, Body.data(), Body.size());
+  }
+};
+
+class CodeSection : public OutputSection {
+public:
+  explicit CodeSection(uint32_t NumFunctions, std::vector<ObjFile *> &Objs);
+  size_t getSize() const override { return Header.size() + BodySize; }
+  void writeTo(uint8_t *Buf) override;
+  uint32_t numRelocations() const override;
+  void writeRelocations(raw_ostream &OS) const override;
+
+protected:
+  std::vector<ObjFile *> &InputObjects;
+  std::string CodeSectionHeader;
+  size_t BodySize = 0;
+};
+
+class DataSection : public OutputSection {
+public:
+  explicit DataSection(std::vector<OutputSegment *> &Segments);
+  size_t getSize() const override { return Header.size() + BodySize; }
+  void writeTo(uint8_t *Buf) override;
+  uint32_t numRelocations() const override { return Relocations.size(); }
+  void writeRelocations(raw_ostream &OS) const override;
+
+protected:
+  std::vector<OutputRelocation> Relocations;
+  std::vector<OutputSegment *> &Segments;
+  std::string DataSectionHeader;
+  size_t BodySize = 0;
+};
+
+} // namespace wasm
+} // namespace lld
+
+#endif // LLD_WASM_OUTPUT_SECTIONS_H

Propchange: lld/trunk/wasm/OutputSections.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/OutputSegment.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/OutputSegment.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/OutputSegment.h (added)
+++ lld/trunk/wasm/OutputSegment.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,56 @@
+//===- OutputSegment.h ------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_OUTPUT_SEGMENT_H
+#define LLD_WASM_OUTPUT_SEGMENT_H
+
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Wasm.h"
+
+namespace lld {
+namespace wasm {
+
+class InputSegment;
+
+class OutputSegment {
+public:
+  OutputSegment(StringRef N) : Name(N) {}
+
+  void addInputSegment(InputSegment *Segment) {
+    Alignment = std::max(Alignment, Segment->getAlignment());
+    InputSegments.push_back(Segment);
+    Size = llvm::alignTo(Size, Segment->getAlignment());
+    ;
+    Segment->setOutputSegment(this, Size);
+    Size += Segment->getSize();
+  }
+
+  uint32_t getSectionOffset() const { return SectionOffset; }
+
+  void setSectionOffset(uint32_t Offset) { SectionOffset = Offset; }
+
+  StringRef Name;
+  uint32_t Alignment = 0;
+  uint32_t StartVA = 0;
+  std::vector<const InputSegment *> InputSegments;
+
+  // Sum of the size of the all the input segments
+  uint32_t Size = 0;
+
+  // Segment header
+  std::string Header;
+
+private:
+  uint32_t SectionOffset = 0;
+};
+
+} // namespace wasm
+} // namespace lld
+
+#endif // LLD_WASM_OUTPUT_SEGMENT_H

Propchange: lld/trunk/wasm/OutputSegment.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Strings.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Strings.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Strings.cpp (added)
+++ lld/trunk/wasm/Strings.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,40 @@
+//===- Strings.cpp -------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Strings.h"
+#include "Config.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Demangle/Demangle.h"
+
+using namespace llvm;
+
+// Returns the demangled C++ symbol name for Name.
+Optional<std::string> lld::wasm::demangle(StringRef Name) {
+  // itaniumDemangle can be used to demangle strings other than symbol
+  // names which do not necessarily start with "_Z". Name can be
+  // either a C or C++ symbol. Don't call itaniumDemangle if the name
+  // does not look like a C++ symbol name to avoid getting unexpected
+  // result for a C symbol that happens to match a mangled type name.
+  if (!Name.startswith("_Z"))
+    return None;
+
+  char *Buf = itaniumDemangle(Name.str().c_str(), nullptr, nullptr, nullptr);
+  if (!Buf)
+    return None;
+  std::string S(Buf);
+  free(Buf);
+  return S;
+}
+
+std::string lld::wasm::displayName(StringRef Name) {
+  if (Config->Demangle)
+    if (Optional<std::string> S = demangle(Name))
+      return "`" + *S + "'";
+  return Name;
+}

Propchange: lld/trunk/wasm/Strings.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Strings.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Strings.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Strings.h (added)
+++ lld/trunk/wasm/Strings.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,29 @@
+//===- Strings.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_STRINGS_H
+#define LLD_WASM_STRINGS_H
+
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include <string>
+
+namespace lld {
+namespace wasm {
+
+// Returns a demangled C++ symbol name. If Name is not a mangled
+// name, it returns Optional::None.
+llvm::Optional<std::string> demangle(llvm::StringRef Name);
+
+std::string displayName(llvm::StringRef Name);
+
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/Strings.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/SymbolTable.cpp (added)
+++ lld/trunk/wasm/SymbolTable.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,191 @@
+//===- SymbolTable.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolTable.h"
+
+#include "Config.h"
+#include "Memory.h"
+#include "Strings.h"
+#include "lld/Common/ErrorHandler.h"
+
+#include <unordered_set>
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::wasm;
+
+SymbolTable *lld::wasm::Symtab;
+
+void SymbolTable::addFile(InputFile *File) {
+  log("Processing: " + toString(File));
+  File->parse();
+
+  if (auto *F = dyn_cast<ObjFile>(File))
+    ObjectFiles.push_back(F);
+}
+
+void SymbolTable::reportRemainingUndefines() {
+  std::unordered_set<Symbol *> Undefs;
+  for (auto &I : Symtab) {
+    Symbol *Sym = I.second;
+    if (Sym->isUndefined() && !Sym->isWeak() &&
+        Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) {
+      Undefs.insert(Sym);
+    }
+  }
+
+  if (Undefs.empty())
+    return;
+
+  for (ObjFile *File : ObjectFiles)
+    for (Symbol *Sym : File->getSymbols())
+      if (Undefs.count(Sym))
+        error(toString(File) + ": undefined symbol: " + toString(*Sym));
+
+  for (Symbol *Sym : Undefs)
+    if (!Sym->getFile())
+      error("undefined symbol: " + toString(*Sym));
+}
+
+Symbol *SymbolTable::find(StringRef Name) {
+  auto It = Symtab.find(CachedHashStringRef(Name));
+  if (It == Symtab.end())
+    return nullptr;
+  return It->second;
+}
+
+std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
+  Symbol *&Sym = Symtab[CachedHashStringRef(Name)];
+  if (Sym)
+    return {Sym, false};
+  Sym = make<Symbol>(Name, false);
+  return {Sym, true};
+}
+
+void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
+  error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " +
+        toString(Existing->getFile()) + "\n>>> defined in " +
+        (NewFile ? toString(NewFile) : "<internal>"));
+}
+
+static void checkSymbolTypes(Symbol *Existing, InputFile *F,
+                             const WasmSymbol *New) {
+  if (Existing->isLazy())
+    return;
+
+  bool NewIsFunction = New->Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
+                       New->Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
+  if (Existing->isFunction() == NewIsFunction)
+    return;
+
+  std::string Filename = "<builtin>";
+  if (Existing->getFile())
+    Filename = toString(Existing->getFile());
+  error("symbol type mismatch: " + New->Name + "\n>>> defined as " +
+        (Existing->isFunction() ? "Function" : "Global") + " in " + Filename +
+        "\n>>> defined as " + (NewIsFunction ? "Function" : "Global") + " in " +
+        F->getName());
+}
+
+Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
+  DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n");
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted)
+    S->update(Symbol::DefinedGlobalKind);
+  else if (!S->isGlobal())
+    error("symbol type mismatch: " + Name);
+  return S;
+}
+
+Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
+                                const InputSegment *Segment) {
+  DEBUG(dbgs() << "addDefined: " << Sym->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);
+  if (WasInserted) {
+    S->update(Kind, F, Sym, Segment);
+  } else if (!S->isDefined()) {
+    // The existing symbol table entry is undefined. The new symbol replaces
+    // it
+    DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name
+                 << "\n");
+    checkSymbolTypes(S, F, Sym);
+    S->update(Kind, F, Sym, Segment);
+  } else if (Sym->isWeak()) {
+    // the new symbol is weak we can ignore it
+    DEBUG(dbgs() << "existing symbol takes precensence\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");
+    S->update(Kind, F, Sym, Segment);
+  } else {
+    // niether symbol is week. They conflict.
+    reportDuplicate(S, F);
+  }
+  return S;
+}
+
+Symbol *SymbolTable::addUndefinedFunction(StringRef Name) {
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted)
+    S->update(Symbol::UndefinedFunctionKind);
+  else if (!S->isFunction())
+    error("symbol type mismatch: " + Name);
+  return S;
+}
+
+Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) {
+  DEBUG(dbgs() << "addUndefined: " << displayName(Sym->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);
+  if (WasInserted) {
+    S->update(Kind, F, Sym);
+  } else if (S->isLazy()) {
+    DEBUG(dbgs() << "resolved by existing lazy\n");
+    auto *AF = cast<ArchiveFile>(S->getFile());
+    AF->addMember(&S->getArchiveSymbol());
+  } else if (S->isDefined()) {
+    DEBUG(dbgs() << "resolved by existing\n");
+    checkSymbolTypes(S, F, Sym);
+  }
+  return S;
+}
+
+void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
+  DEBUG(dbgs() << "addLazy: " << displayName(Sym->getName()) << "\n");
+  StringRef Name = Sym->getName();
+  Symbol *S;
+  bool WasInserted;
+  std::tie(S, WasInserted) = insert(Name);
+  if (WasInserted) {
+    S->update(Symbol::LazyKind, F);
+    S->setArchiveSymbol(*Sym);
+  } else if (S->isUndefined()) {
+    // There is an existing undefined symbol.  The can load from the
+    // archive.
+    DEBUG(dbgs() << "replacing existing undefined\n");
+    F->addMember(Sym);
+  }
+}

Propchange: lld/trunk/wasm/SymbolTable.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/SymbolTable.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/SymbolTable.h (added)
+++ lld/trunk/wasm/SymbolTable.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,69 @@
+//===- SymbolTable.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_SYMBOL_TABLE_H
+#define LLD_WASM_SYMBOL_TABLE_H
+
+#include "InputFiles.h"
+#include "Symbols.h"
+
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/Support/raw_ostream.h"
+
+using llvm::object::WasmSymbol;
+
+namespace lld {
+namespace wasm {
+
+class InputSegment;
+
+// SymbolTable is a bucket of all known symbols, including defined,
+// undefined, or lazy symbols (the last one is symbols in archive
+// files whose archive members are not yet loaded).
+//
+// We put all symbols of all files to a SymbolTable, and the
+// SymbolTable selects the "best" symbols if there are name
+// conflicts. For example, obviously, a defined symbol is better than
+// an undefined symbol. Or, if there's a conflict between a lazy and a
+// undefined, it'll read an archive member to read a real definition
+// to replace the lazy symbol. The logic is implemented in the
+// add*() functions, which are called by input files as they are parsed.
+// There is one add* function per symbol type.
+class SymbolTable {
+public:
+  void addFile(InputFile *File);
+
+  std::vector<ObjFile *> ObjectFiles;
+  std::vector<Symbol *> SyntheticSymbols;
+
+  void reportDuplicate(Symbol *Existing, InputFile *NewFile);
+  void reportRemainingUndefines();
+
+  Symbol *find(StringRef Name);
+
+  Symbol *addDefined(InputFile *F, const WasmSymbol *Sym,
+                     const InputSegment *Segment = nullptr);
+  Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym);
+  Symbol *addUndefinedFunction(StringRef Name);
+  Symbol *addDefinedGlobal(StringRef Name);
+  void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
+
+private:
+  std::pair<Symbol *, bool> insert(StringRef Name);
+
+  llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> Symtab;
+};
+
+extern SymbolTable *Symtab;
+
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/SymbolTable.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Symbols.cpp (added)
+++ lld/trunk/wasm/Symbols.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,104 @@
+//===- Symbols.cpp --------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Symbols.h"
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "InputSegment.h"
+#include "Strings.h"
+#include "lld/Common/ErrorHandler.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace lld;
+using namespace lld::wasm;
+
+uint32_t Symbol::getGlobalIndex() const {
+  assert(!Sym->isFunction());
+  return Sym->ElementIndex;
+}
+
+uint32_t Symbol::getFunctionIndex() const {
+  assert(Sym->isFunction());
+  return Sym->ElementIndex;
+}
+
+uint32_t Symbol::getFunctionTypeIndex() const {
+  assert(Sym->isFunction());
+  ObjFile *Obj = cast<ObjFile>(File);
+  if (Obj->isImportedFunction(Sym->ElementIndex)) {
+    const WasmImport &Import = Obj->getWasmObj()->imports()[Sym->ImportIndex];
+    DEBUG(dbgs() << "getFunctionTypeIndex: import: " << Sym->ImportIndex
+                 << " -> " << Import.SigIndex << "\n");
+    return Import.SigIndex;
+  }
+  DEBUG(dbgs() << "getFunctionTypeIndex: non import: " << Sym->ElementIndex
+               << "\n");
+  uint32_t FuntionIndex = Sym->ElementIndex - Obj->NumFunctionImports();
+  return Obj->getWasmObj()->functionTypes()[FuntionIndex];
+}
+
+uint32_t Symbol::getVirtualAddress() const {
+  assert(isGlobal());
+  DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
+  if (isUndefined())
+    return UINT32_MAX;
+
+  assert(Sym != nullptr);
+  ObjFile *Obj = cast<ObjFile>(File);
+  const WasmGlobal &Global =
+      Obj->getWasmObj()->globals()[getGlobalIndex() - Obj->NumGlobalImports()];
+  assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
+  assert(Segment);
+  return Segment->translateVA(Global.InitExpr.Value.Int32);
+}
+
+uint32_t Symbol::getOutputIndex() const {
+  if (isUndefined() && isWeak())
+    return 0;
+  return OutputIndex.getValue();
+}
+
+void Symbol::setOutputIndex(uint32_t Index) {
+  DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n");
+  assert(!hasOutputIndex());
+  OutputIndex = Index;
+}
+
+void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym,
+                    const InputSegment *Seg) {
+  SymbolKind = K;
+  File = F;
+  Sym = WasmSym;
+  Segment = Seg;
+}
+
+bool Symbol::isWeak() const { return Sym && Sym->isWeak(); }
+
+std::string lld::toString(wasm::Symbol &Sym) {
+  return wasm::displayName(Sym.getName());
+}
+
+std::string lld::toString(wasm::Symbol::Kind &Kind) {
+  switch (Kind) {
+  case wasm::Symbol::DefinedFunctionKind:
+    return "DefinedFunction";
+  case wasm::Symbol::DefinedGlobalKind:
+    return "DefinedGlobal";
+  case wasm::Symbol::UndefinedFunctionKind:
+    return "UndefinedFunction";
+  case wasm::Symbol::UndefinedGlobalKind:
+    return "UndefinedGlobal";
+  case wasm::Symbol::LazyKind:
+    return "LazyKind";
+  }
+  llvm_unreachable("Invalid symbol kind!");
+}

Propchange: lld/trunk/wasm/Symbols.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Symbols.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Symbols.h (added)
+++ lld/trunk/wasm/Symbols.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,113 @@
+//===- Symbols.h ------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_SYMBOLS_H
+#define LLD_WASM_SYMBOLS_H
+
+#include "lld/Common/LLVM.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Wasm.h"
+
+using llvm::object::Archive;
+using llvm::object::WasmSymbol;
+using llvm::wasm::WasmImport;
+using llvm::wasm::WasmExport;
+
+namespace lld {
+namespace wasm {
+
+class InputFile;
+class InputSegment;
+
+class Symbol {
+public:
+  enum Kind {
+    DefinedFunctionKind,
+    DefinedGlobalKind,
+
+    LazyKind,
+    UndefinedFunctionKind,
+    UndefinedGlobalKind,
+
+    LastDefinedKind = DefinedGlobalKind,
+    InvalidKind,
+  };
+
+  Symbol(StringRef Name, bool IsLocal)
+      : WrittenToSymtab(0), WrittenToNameSec(0), Name(Name), IsLocal(IsLocal) {}
+
+  Kind getKind() const { return SymbolKind; }
+
+  bool isLazy() const { return SymbolKind == LazyKind; }
+  bool isDefined() const { return SymbolKind <= LastDefinedKind; }
+  bool isUndefined() const {
+    return SymbolKind == UndefinedGlobalKind ||
+           SymbolKind == UndefinedFunctionKind;
+  }
+  bool isFunction() const {
+    return SymbolKind == DefinedFunctionKind ||
+           SymbolKind == UndefinedFunctionKind;
+  }
+  bool isGlobal() const { return !isFunction(); }
+  bool isLocal() const { return IsLocal; }
+  bool isWeak() const;
+
+  // Returns the symbol name.
+  StringRef getName() const { return Name; }
+
+  // Returns the file from which this symbol was created.
+  InputFile *getFile() const { return File; }
+
+  uint32_t getGlobalIndex() const;
+  uint32_t getFunctionIndex() const;
+  uint32_t getFunctionTypeIndex() const;
+  uint32_t getOutputIndex() const;
+
+  // Returns the virtual address of a defined global.
+  // Only works for globals, not functions.
+  uint32_t getVirtualAddress() const;
+
+  // Returns true if an output index has been set for this symbol
+  bool hasOutputIndex() { return OutputIndex.hasValue(); }
+
+  // Set the output index of the symbol (in the function or global index
+  // space of the output object.
+  void setOutputIndex(uint32_t Index);
+
+  void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr,
+              const InputSegment *Segment = nullptr);
+
+  void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
+  const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
+
+  // This bit is used by Writer::writeNameSection() to prevent
+  // symbols from being written to the symbol table more than once.
+  unsigned WrittenToSymtab : 1;
+  unsigned WrittenToNameSec : 1;
+
+protected:
+  StringRef Name;
+  bool IsLocal;
+  Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};
+  Kind SymbolKind = InvalidKind;
+  InputFile *File = nullptr;
+  const WasmSymbol *Sym = nullptr;
+  const InputSegment *Segment = nullptr;
+  llvm::Optional<uint32_t> OutputIndex;
+};
+
+} // namespace wasm
+
+// Returns a symbol name for an error message.
+std::string toString(wasm::Symbol &Sym);
+std::string toString(wasm::Symbol::Kind &Kind);
+
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/Symbols.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Writer.cpp (added)
+++ lld/trunk/wasm/Writer.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,779 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Writer.h"
+
+#include "Config.h"
+#include "Memory.h"
+#include "OutputSections.h"
+#include "OutputSegment.h"
+#include "SymbolTable.h"
+#include "WriterUtils.h"
+#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Threads.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/LEB128.h"
+
+#include <cstdarg>
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace llvm::wasm;
+using namespace lld;
+using namespace lld::wasm;
+
+static constexpr int kStackAlignment = 16;
+
+namespace {
+
+// Needed for WasmSignatureDenseMapInfo
+bool operator==(const WasmSignature &LHS, const WasmSignature &RHS) {
+  return LHS.ReturnType == RHS.ReturnType && LHS.ParamTypes == RHS.ParamTypes;
+}
+
+// Traits for using WasmSignature in a DenseMap.
+struct WasmSignatureDenseMapInfo {
+  static WasmSignature getEmptyKey() {
+    WasmSignature Sig;
+    Sig.ReturnType = 1;
+    return Sig;
+  }
+  static WasmSignature getTombstoneKey() {
+    WasmSignature Sig;
+    Sig.ReturnType = 2;
+    return Sig;
+  }
+  static unsigned getHashValue(const WasmSignature &Sig) {
+    uintptr_t Value = 0;
+    Value += DenseMapInfo<int32_t>::getHashValue(Sig.ReturnType);
+    for (int32_t Param : Sig.ParamTypes)
+      Value += DenseMapInfo<int32_t>::getHashValue(Param);
+    return Value;
+  }
+  static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// The writer writes a SymbolTable result to a file.
+class Writer {
+public:
+  void run();
+
+private:
+  void openFile();
+
+  void assignSymbolIndexes();
+  void calculateImports();
+  void calculateOffsets();
+  void calculateTypes();
+  void createOutputSegments();
+  void layoutMemory();
+  void createHeader();
+  void createSections();
+  SyntheticSection *createSyntheticSection(uint32_t Type,
+                                           std::string Name = "");
+
+  // Builtin sections
+  void createTypeSection();
+  void createFunctionSection();
+  void createTableSection();
+  void createGlobalSection();
+  void createExportSection();
+  void createImportSection();
+  void createMemorySection();
+  void createElemSection();
+  void createStartSection();
+  void createCodeSection();
+  void createDataSection();
+
+  // Custom sections
+  void createRelocSections();
+  void createLinkingSection();
+  void createNameSection();
+
+  void writeHeader();
+  void writeSections();
+
+  uint64_t FileSize = 0;
+  uint32_t DataSize = 0;
+  uint32_t NumFunctions = 0;
+  uint32_t NumGlobals = 0;
+  uint32_t NumMemoryPages = 0;
+  uint32_t NumTableElems = 0;
+  uint32_t NumElements = 0;
+  uint32_t InitialTableOffset = 0;
+
+  std::vector<const WasmSignature *> Types;
+  DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;
+  std::vector<Symbol *> FunctionImports;
+  std::vector<Symbol *> GlobalImports;
+
+  // Elements that are used to construct the final output
+  std::string Header;
+  std::vector<OutputSection *> OutputSections;
+
+  std::unique_ptr<FileOutputBuffer> Buffer;
+
+  std::vector<OutputSegment *> Segments;
+  llvm::SmallDenseMap<StringRef, OutputSegment *> SegmentMap;
+};
+
+} // anonymous namespace
+
+static void debugPrint(const char *fmt, ...) {
+  if (!errorHandler().Verbose)
+    return;
+  fprintf(stderr, "lld: ");
+  va_list ap;
+  va_start(ap, fmt);
+  vfprintf(stderr, fmt, ap);
+  va_end(ap);
+}
+
+void Writer::createImportSection() {
+  uint32_t NumImports = FunctionImports.size() + GlobalImports.size();
+  if (Config->ImportMemory)
+    ++NumImports;
+
+  if (NumImports == 0)
+    return;
+
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_IMPORT);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, NumImports, "import count");
+
+  for (Symbol *Sym : FunctionImports) {
+    WasmImport Import;
+    Import.Module = "env";
+    Import.Field = Sym->getName();
+    Import.Kind = WASM_EXTERNAL_FUNCTION;
+    auto *Obj = cast<ObjFile>(Sym->getFile());
+    Import.SigIndex = Obj->relocateTypeIndex(Sym->getFunctionTypeIndex());
+    writeImport(OS, Import);
+  }
+
+  if (Config->ImportMemory) {
+    WasmImport Import;
+    Import.Module = "env";
+    Import.Field = "memory";
+    Import.Kind = WASM_EXTERNAL_MEMORY;
+    Import.Memory.Flags = 0;
+    Import.Memory.Initial = NumMemoryPages;
+    writeImport(OS, Import);
+  }
+
+  for (Symbol *Sym : GlobalImports) {
+    WasmImport Import;
+    Import.Module = "env";
+    Import.Field = Sym->getName();
+    Import.Kind = WASM_EXTERNAL_GLOBAL;
+    Import.Global.Mutable = false;
+    assert(isa<ObjFile>(Sym->getFile()));
+    // TODO(sbc): Set type of this import
+    // ObjFile* Obj = dyn_cast<ObjFile>(Sym->getFile());
+    Import.Global.Type = WASM_TYPE_I32; // Sym->getGlobalType();
+    writeImport(OS, Import);
+  }
+}
+
+void Writer::createTypeSection() {
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_TYPE);
+  raw_ostream &OS = Section->getStream();
+  writeUleb128(OS, Types.size(), "type count");
+  for (const WasmSignature *Sig : Types) {
+    writeSig(OS, *Sig);
+  }
+}
+
+void Writer::createFunctionSection() {
+  if (!NumFunctions)
+    return;
+
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, NumFunctions, "function count");
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    for (uint32_t Sig : File->getWasmObj()->functionTypes()) {
+      writeUleb128(OS, File->relocateTypeIndex(Sig), "sig index");
+    }
+  }
+}
+
+void Writer::createMemorySection() {
+  if (Config->ImportMemory)
+    return;
+
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, 1, "memory count");
+  writeUleb128(OS, 0, "memory limits flags");
+  writeUleb128(OS, NumMemoryPages, "initial pages");
+}
+
+void Writer::createGlobalSection() {
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, NumGlobals, "global count");
+  for (auto &Pair : Config->SyntheticGlobals) {
+    WasmGlobal &Global = Pair.second;
+    writeGlobal(OS, Global);
+  }
+
+  if (Config->Relocatable || Config->EmitRelocs) {
+    for (ObjFile *File : Symtab->ObjectFiles) {
+      uint32_t GlobalIndex = File->NumGlobalImports();
+      for (const WasmGlobal &Global : File->getWasmObj()->globals()) {
+        WasmGlobal RelocatedGlobal(Global);
+        if (Global.Type != WASM_TYPE_I32)
+          fatal("unsupported global type: " + Twine(Global.Type));
+        if (Global.InitExpr.Opcode != WASM_OPCODE_I32_CONST)
+          fatal("unsupported global init opcode: " +
+                Twine(Global.InitExpr.Opcode));
+        RelocatedGlobal.InitExpr.Value.Int32 =
+            File->getRelocatedAddress(GlobalIndex);
+        writeGlobal(OS, RelocatedGlobal);
+        ++GlobalIndex;
+      }
+    }
+  }
+}
+
+void Writer::createTableSection() {
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, 1, "table count");
+  writeSleb128(OS, WASM_TYPE_ANYFUNC, "table type");
+  writeUleb128(OS, WASM_LIMITS_FLAG_HAS_MAX, "table flags");
+  writeUleb128(OS, NumTableElems, "table initial size");
+  writeUleb128(OS, NumTableElems, "table max size");
+}
+
+void Writer::createExportSection() {
+  // Memory is and main function are exported for executables.
+  bool ExportMemory = !Config->Relocatable && !Config->ImportMemory;
+  bool ExportMain = !Config->Relocatable;
+  bool ExportOther = true; // Config->Relocatable;
+
+  uint32_t NumExports = 0;
+
+  if (ExportMemory)
+    ++NumExports;
+
+  if (ExportMain && !ExportOther)
+    ++NumExports;
+
+  if (ExportOther) {
+    for (ObjFile *File : Symtab->ObjectFiles) {
+      for (Symbol *Sym : File->getSymbols()) {
+        if (!Sym->isFunction() || Sym->isLocal() || Sym->isUndefined() ||
+            Sym->WrittenToSymtab)
+          continue;
+        Sym->WrittenToSymtab = true;
+        ++NumExports;
+      }
+    }
+  }
+
+  if (!NumExports)
+    return;
+
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, NumExports, "export count");
+
+  if (ExportMemory) {
+    WasmExport MemoryExport;
+    MemoryExport.Name = "memory";
+    MemoryExport.Kind = WASM_EXTERNAL_MEMORY;
+    MemoryExport.Index = 0;
+    writeExport(OS, MemoryExport);
+  }
+
+  if (ExportMain) {
+    Symbol *Sym = Symtab->find(Config->Entry);
+    if (Sym->isDefined()) {
+      if (!Sym->isFunction())
+        fatal("entry point is not a function: " + Sym->getName());
+
+      if (!ExportOther) {
+        WasmExport MainExport;
+        MainExport.Name = Config->Entry;
+        MainExport.Kind = WASM_EXTERNAL_FUNCTION;
+        MainExport.Index = Sym->getOutputIndex();
+        writeExport(OS, MainExport);
+      }
+    }
+  }
+
+  if (ExportOther) {
+    for (ObjFile *File : Symtab->ObjectFiles) {
+      for (Symbol *Sym : File->getSymbols()) {
+        if (!Sym->isFunction() || Sym->isLocal() | Sym->isUndefined() ||
+            !Sym->WrittenToSymtab)
+          continue;
+        Sym->WrittenToSymtab = false;
+        log("Export: " + Sym->getName());
+        WasmExport Export;
+        Export.Name = Sym->getName();
+        Export.Index = Sym->getOutputIndex();
+        if (Sym->isFunction())
+          Export.Kind = WASM_EXTERNAL_FUNCTION;
+        else
+          Export.Kind = WASM_EXTERNAL_GLOBAL;
+        writeExport(OS, Export);
+      }
+    }
+
+    // TODO(sbc): Export local symbols too, Even though they are not part
+    // of the symbol table?
+  }
+}
+
+void Writer::createStartSection() {}
+
+void Writer::createElemSection() {
+  if (!NumElements)
+    return;
+
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_ELEM);
+  raw_ostream &OS = Section->getStream();
+
+  writeUleb128(OS, 1, "segment count");
+  writeUleb128(OS, 0, "table index");
+  WasmInitExpr InitExpr;
+  InitExpr.Opcode = WASM_OPCODE_I32_CONST;
+  InitExpr.Value.Int32 = InitialTableOffset;
+  writeInitExpr(OS, InitExpr);
+  writeUleb128(OS, NumElements, "elem count");
+
+  for (ObjFile *File : Symtab->ObjectFiles)
+    for (const WasmElemSegment &Segment : File->getWasmObj()->elements())
+      for (uint64_t FunctionIndex : Segment.Functions)
+        writeUleb128(OS, File->relocateFunctionIndex(FunctionIndex),
+                     "function index");
+}
+
+void Writer::createCodeSection() {
+  if (!NumFunctions)
+    return;
+
+  log("createCodeSection");
+
+  auto Section = make<CodeSection>(NumFunctions, Symtab->ObjectFiles);
+  OutputSections.push_back(Section);
+}
+
+void Writer::createDataSection() {
+  if (!Segments.size())
+    return;
+
+  log("createDataSection");
+  auto Section = make<DataSection>(Segments);
+  OutputSections.push_back(Section);
+}
+
+// Create reloctions sections in the final output.
+// These are only created when relocatable output is requested.
+void Writer::createRelocSections() {
+  log("createRelocSections");
+  // Don't use iterator here since we are adding to OutputSection
+  size_t OrigSize = OutputSections.size();
+  for (size_t i = 0; i < OrigSize; i++) {
+    OutputSection *S = OutputSections[i];
+    const char *name;
+    uint32_t Count = S->numRelocations();
+    if (!Count)
+      continue;
+
+    if (S->Type == WASM_SEC_DATA)
+      name = "reloc.DATA";
+    else if (S->Type == WASM_SEC_CODE)
+      name = "reloc.CODE";
+    else
+      llvm_unreachable("relocations only support for code and data");
+
+    SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, name);
+    raw_ostream &OS = Section->getStream();
+    writeUleb128(OS, S->Type, "reloc section");
+    writeUleb128(OS, Count, "reloc count");
+    S->writeRelocations(OS);
+  }
+}
+
+// Create the custome "linking" section containing linker metadata.
+// This is only created when relocatable output is requested.
+void Writer::createLinkingSection() {
+  SyntheticSection *Section =
+      createSyntheticSection(WASM_SEC_CUSTOM, "linking");
+  raw_ostream &OS = Section->getStream();
+
+  SubSection DataSizeSubSection(WASM_DATA_SIZE);
+  writeUleb128(DataSizeSubSection.getStream(), DataSize, "data size");
+  DataSizeSubSection.finalizeContents();
+  DataSizeSubSection.writeToStream(OS);
+
+  if (Segments.size() && Config->Relocatable) {
+    SubSection SubSection(WASM_SEGMENT_INFO);
+    writeUleb128(SubSection.getStream(), Segments.size(), "num data segments");
+    for (const OutputSegment *S : Segments) {
+      writeStr(SubSection.getStream(), S->Name, "segment name");
+      writeUleb128(SubSection.getStream(), S->Alignment, "alignment");
+      writeUleb128(SubSection.getStream(), 0, "flags");
+    }
+    SubSection.finalizeContents();
+    SubSection.writeToStream(OS);
+  }
+}
+
+// Create the custom "name" section containing debug symbol names.
+void Writer::createNameSection() {
+  // Create an array of all function sorted by function index space
+  std::vector<const Symbol *> Names;
+
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    Names.reserve(Names.size() + File->getSymbols().size());
+    for (Symbol *S : File->getSymbols()) {
+      if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec)
+        continue;
+      S->WrittenToNameSec = true;
+      Names.emplace_back(S);
+    }
+  }
+
+  SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name");
+
+  std::sort(Names.begin(), Names.end(), [](const Symbol *A, const Symbol *B) {
+    return A->getOutputIndex() < B->getOutputIndex();
+  });
+
+  SubSection FunctionSubsection(WASM_NAMES_FUNCTION);
+  raw_ostream &OS = FunctionSubsection.getStream();
+  writeUleb128(OS, Names.size(), "name count");
+
+  // We have to iterate through the inputs twice so that all the imports
+  // appear first before any of the local function names.
+  for (const Symbol *S : Names) {
+    writeUleb128(OS, S->getOutputIndex(), "func index");
+    writeStr(OS, S->getName(), "symbol name");
+  }
+
+  FunctionSubsection.finalizeContents();
+  FunctionSubsection.writeToStream(Section->getStream());
+}
+
+void Writer::writeHeader() {
+  memcpy(Buffer->getBufferStart(), Header.data(), Header.size());
+}
+
+void Writer::writeSections() {
+  uint8_t *Buf = Buffer->getBufferStart();
+  parallelForEach(OutputSections, [Buf](OutputSection *S) { S->writeTo(Buf); });
+}
+
+// Fix the memory layout of the output binary.  This assigns memory offsets
+// to each of the intput data sections as well as the explicit stack region.
+void Writer::layoutMemory() {
+  uint32_t MemoryPtr = 0;
+  if (!Config->Relocatable) {
+    MemoryPtr = Config->GlobalBase;
+    debugPrint("mem: global base = %d\n", Config->GlobalBase);
+  }
+
+  createOutputSegments();
+
+  // Static data comes first
+  for (OutputSegment *Seg : Segments) {
+    MemoryPtr = alignTo(MemoryPtr, Seg->Alignment);
+    Seg->StartVA = MemoryPtr;
+    debugPrint("mem: %-10s offset=%-8d size=%-4d align=%d\n",
+               Seg->Name.str().c_str(), MemoryPtr, Seg->Size, Seg->Alignment);
+    MemoryPtr += Seg->Size;
+  }
+
+  DataSize = MemoryPtr;
+  if (!Config->Relocatable)
+    DataSize -= Config->GlobalBase;
+  debugPrint("mem: static data = %d\n", DataSize);
+
+  // Stack comes after static data
+  if (!Config->Relocatable) {
+    MemoryPtr = alignTo(MemoryPtr, kStackAlignment);
+    if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment))
+      error("stack size must be " + Twine(kStackAlignment) + "-byte aligned");
+    debugPrint("mem: stack size  = %d\n", Config->ZStackSize);
+    debugPrint("mem: stack base  = %d\n", MemoryPtr);
+    MemoryPtr += Config->ZStackSize;
+    Config->SyntheticGlobals[0].second.InitExpr.Value.Int32 = MemoryPtr;
+    debugPrint("mem: stack top   = %d\n", MemoryPtr);
+  }
+
+  uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize);
+  NumMemoryPages = MemSize / WasmPageSize;
+  debugPrint("mem: total pages = %d\n", NumMemoryPages);
+}
+
+SyntheticSection *Writer::createSyntheticSection(uint32_t Type,
+                                                 std::string Name) {
+  auto Sec = make<SyntheticSection>(Type, Name);
+  log("createSection: " + toString(Sec));
+  OutputSections.push_back(Sec);
+  return Sec;
+}
+
+void Writer::createSections() {
+  // Known sections
+  createTypeSection();
+  createImportSection();
+  createFunctionSection();
+  createTableSection();
+  createMemorySection();
+  createGlobalSection();
+  createExportSection();
+  createStartSection();
+  createElemSection();
+  createCodeSection();
+  createDataSection();
+
+  // Custom sections
+  if (Config->EmitRelocs || Config->Relocatable)
+    createRelocSections();
+  createLinkingSection();
+  if (!Config->StripDebug && !Config->StripAll)
+    createNameSection();
+
+  for (OutputSection *S : OutputSections) {
+    S->setOffset(FileSize);
+    S->finalizeContents();
+    FileSize += S->getSize();
+  }
+}
+
+void Writer::calculateOffsets() {
+  NumGlobals = Config->SyntheticGlobals.size();
+  NumTableElems = InitialTableOffset;
+
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    const WasmObjectFile *WasmFile = File->getWasmObj();
+
+    // Function Index
+    File->FunctionIndexOffset =
+        FunctionImports.size() - File->NumFunctionImports() + NumFunctions;
+    NumFunctions += WasmFile->functions().size();
+
+    // Global Index
+    if (Config->Relocatable || Config->EmitRelocs) {
+      File->GlobalIndexOffset =
+          GlobalImports.size() - File->NumGlobalImports() + NumGlobals;
+      NumGlobals += WasmFile->globals().size();
+    }
+
+    // Memory
+    if (WasmFile->memories().size()) {
+      if (WasmFile->memories().size() > 1) {
+        fatal(File->getName() + ": contains more than one memory");
+      }
+    }
+
+    // Table
+    uint32_t TableCount = WasmFile->tables().size();
+    if (TableCount) {
+      if (TableCount > 1)
+        fatal(File->getName() + ": contains more than one table");
+      File->TableIndexOffset = NumTableElems;
+      NumTableElems += WasmFile->tables()[0].Limits.Initial;
+    }
+
+    // Elem
+    uint32_t SegmentCount = WasmFile->elements().size();
+    if (SegmentCount) {
+      if (SegmentCount > 1) {
+        fatal(File->getName() + ": contains more than element segment");
+      } else {
+        const WasmElemSegment &Segment = WasmFile->elements()[0];
+        if (Segment.TableIndex != 0)
+          fatal(File->getName() + ": unsupported table index");
+        else if (Segment.Offset.Value.Int32 != 0)
+          fatal(File->getName() + ": unsupported segment offset");
+        else
+          NumElements += Segment.Functions.size();
+      }
+    }
+  }
+}
+
+void Writer::calculateImports() {
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    for (Symbol *Sym : File->getSymbols()) {
+      if (Sym->hasOutputIndex() || Sym->isDefined() || Sym->isWeak())
+        continue;
+
+      if (Sym->isFunction()) {
+        Sym->setOutputIndex(FunctionImports.size());
+        FunctionImports.push_back(Sym);
+      } else {
+        Sym->setOutputIndex(GlobalImports.size());
+        GlobalImports.push_back(Sym);
+      }
+    }
+  }
+}
+
+void Writer::calculateTypes() {
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    File->TypeMap.reserve(File->getWasmObj()->types().size());
+    for (const WasmSignature &Sig : File->getWasmObj()->types()) {
+      auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size()));
+      if (Pair.second)
+        Types.push_back(&Sig);
+
+      // Now we map the input files index to the index in the linked output
+      File->TypeMap.push_back(Pair.first->second);
+    }
+  }
+}
+
+void Writer::assignSymbolIndexes() {
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    DEBUG(dbgs() << "assignSymbolIndexes: " << File->getName() << "\n");
+    for (Symbol *Sym : File->getSymbols()) {
+      if (Sym->hasOutputIndex() || !Sym->isDefined())
+        continue;
+
+      if (Sym->getFile() && isa<ObjFile>(Sym->getFile())) {
+        auto *Obj = cast<ObjFile>(Sym->getFile());
+        if (Sym->isFunction())
+          Sym->setOutputIndex(Obj->FunctionIndexOffset +
+                              Sym->getFunctionIndex());
+        else
+          Sym->setOutputIndex(Obj->GlobalIndexOffset + Sym->getGlobalIndex());
+      }
+    }
+  }
+}
+
+static StringRef getOutputDataSegmentName(StringRef Name) {
+  if (Config->Relocatable)
+    return Name;
+
+  for (StringRef V :
+       {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.",
+        ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.",
+        ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) {
+    StringRef Prefix = V.drop_back();
+    if (Name.startswith(V) || Name == Prefix)
+      return Prefix;
+  }
+
+  return Name;
+}
+
+void Writer::createOutputSegments() {
+  for (ObjFile *File : Symtab->ObjectFiles) {
+    for (InputSegment *Segment : File->Segments) {
+      StringRef Name = getOutputDataSegmentName(Segment->getName());
+      OutputSegment *&S = SegmentMap[Name];
+      if (S == nullptr) {
+        DEBUG(dbgs() << "new segment: " << Name << "\n");
+        S = make<OutputSegment>(Name);
+        Segments.push_back(S);
+      }
+      S->addInputSegment(Segment);
+      DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n");
+      for (const WasmRelocation &R : File->DataSection->Relocations) {
+        if (R.Offset >= Segment->getInputSectionOffset() &&
+            R.Offset < Segment->getInputSectionOffset() + Segment->getSize()) {
+          Segment->Relocations.push_back(R);
+        }
+      }
+    }
+  }
+}
+
+void Writer::run() {
+  if (!Config->Relocatable)
+    InitialTableOffset = 1;
+
+  log("-- calculateTypes");
+  calculateTypes();
+  log("-- calculateImports");
+  calculateImports();
+  log("-- calculateOffsets");
+  calculateOffsets();
+
+  if (errorHandler().Verbose) {
+    log("NumFunctions    : " + Twine(NumFunctions));
+    log("NumGlobals      : " + Twine(NumGlobals));
+    log("NumImports      : " +
+        Twine(FunctionImports.size() + GlobalImports.size()));
+    log("FunctionImports : " + Twine(FunctionImports.size()));
+    log("GlobalImports   : " + Twine(GlobalImports.size()));
+    for (ObjFile *File : Symtab->ObjectFiles)
+      File->dumpInfo();
+  }
+
+  log("-- assignSymbolIndexes");
+  assignSymbolIndexes();
+  log("-- layoutMemory");
+  layoutMemory();
+
+  createHeader();
+  log("-- createSections");
+  createSections();
+
+  log("-- openFile");
+  openFile();
+  if (errorCount())
+    return;
+
+  writeHeader();
+
+  log("-- writeSections");
+  writeSections();
+  if (errorCount())
+    return;
+
+  if (Error E = Buffer->commit())
+    fatal("failed to write the output file: " + toString(std::move(E)));
+}
+
+// Open a result file.
+void Writer::openFile() {
+  log("writing: " + Config->OutputFile);
+  ::remove(Config->OutputFile.str().c_str());
+
+  Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+      FileOutputBuffer::create(Config->OutputFile, FileSize,
+                               FileOutputBuffer::F_executable);
+
+  if (!BufferOrErr)
+    error("failed to open " + Config->OutputFile + ": " +
+          toString(BufferOrErr.takeError()));
+  else
+    Buffer = std::move(*BufferOrErr);
+}
+
+void Writer::createHeader() {
+  raw_string_ostream OS(Header);
+  writeBytes(OS, WasmMagic, sizeof(WasmMagic), "wasm magic");
+  writeU32(OS, WasmVersion, "wasm version");
+  OS.flush();
+  FileSize += Header.size();
+}
+
+void lld::wasm::writeResult() { Writer().run(); }

Propchange: lld/trunk/wasm/Writer.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/Writer.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/Writer.h (added)
+++ lld/trunk/wasm/Writer.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,21 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_WRITER_H
+#define LLD_WASM_WRITER_H
+
+namespace lld {
+namespace wasm {
+
+void writeResult();
+
+} // namespace wasm
+} // namespace lld
+
+#endif

Propchange: lld/trunk/wasm/Writer.h
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/WriterUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/WriterUtils.cpp?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/WriterUtils.cpp (added)
+++ lld/trunk/wasm/WriterUtils.cpp Fri Nov 17 10:14:09 2017
@@ -0,0 +1,189 @@
+//===- WriterUtils.cpp ----------------------------------------------------===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "WriterUtils.h"
+
+#include "lld/Common/ErrorHandler.h"
+
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/LEB128.h"
+
+#define DEBUG_TYPE "lld"
+
+using namespace llvm;
+using namespace llvm::wasm;
+using namespace lld::wasm;
+
+static const char *valueTypeToString(int32_t Type) {
+  switch (Type) {
+  case WASM_TYPE_I32:
+    return "i32";
+  case WASM_TYPE_I64:
+    return "i64";
+  case WASM_TYPE_F32:
+    return "f32";
+  case WASM_TYPE_F64:
+    return "f64";
+  default:
+    llvm_unreachable("invalid value type");
+  }
+}
+
+namespace lld {
+
+void wasm::debugWrite(uint64_t offset, Twine msg) {
+  DEBUG(dbgs() << format("  | %08" PRIx64 ": ", offset) << msg << "\n");
+}
+
+void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg) {
+  if (msg)
+    debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number));
+  encodeULEB128(Number, OS);
+}
+
+void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const char *msg) {
+  if (msg)
+    debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number));
+  encodeSLEB128(Number, OS);
+}
+
+void wasm::writeBytes(raw_ostream &OS, const char *bytes, size_t count,
+                      const char *msg) {
+  if (msg)
+    debugWrite(OS.tell(), msg + formatv(" [data[{0}]]", count));
+  OS.write(bytes, count);
+}
+
+void wasm::writeStr(raw_ostream &OS, const StringRef String, const char *msg) {
+  if (msg)
+    debugWrite(OS.tell(),
+               msg + formatv(" [str[{0}]: {1}]", String.size(), String));
+  writeUleb128(OS, String.size(), nullptr);
+  writeBytes(OS, String.data(), String.size());
+}
+
+void wasm::writeU8(raw_ostream &OS, uint8_t byte, const char *msg) {
+  OS << byte;
+}
+
+void wasm::writeU32(raw_ostream &OS, uint32_t Number, const char *msg) {
+  debugWrite(OS.tell(), msg + formatv("[{0:x}]", Number));
+  support::endian::Writer<support::little>(OS).write(Number);
+}
+
+void wasm::writeValueType(raw_ostream &OS, int32_t Type, const char *msg) {
+  debugWrite(OS.tell(), msg + formatv("[type: {0}]", valueTypeToString(Type)));
+  writeSleb128(OS, Type, nullptr);
+}
+
+void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) {
+  writeSleb128(OS, WASM_TYPE_FUNC, "signature type");
+  writeUleb128(OS, Sig.ParamTypes.size(), "param count");
+  for (int32_t ParamType : Sig.ParamTypes) {
+    writeValueType(OS, ParamType, "param type");
+  }
+  if (Sig.ReturnType == WASM_TYPE_NORESULT) {
+    writeUleb128(OS, 0, "result count");
+  } else {
+    writeUleb128(OS, 1, "result count");
+    writeValueType(OS, Sig.ReturnType, "result type");
+  }
+}
+
+void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) {
+  writeU8(OS, InitExpr.Opcode, "opcode");
+  switch (InitExpr.Opcode) {
+  case WASM_OPCODE_I32_CONST:
+    writeSleb128(OS, InitExpr.Value.Int32, "literal (i32)");
+    break;
+  case WASM_OPCODE_I64_CONST:
+    writeSleb128(OS, InitExpr.Value.Int64, "literal (i64)");
+    break;
+  case WASM_OPCODE_GET_GLOBAL:
+    writeUleb128(OS, InitExpr.Value.Global, "literal (global index)");
+    break;
+  default:
+    fatal("unknown opcode in init expr: " + Twine(InitExpr.Opcode));
+    break;
+  }
+  writeU8(OS, WASM_OPCODE_END, "opcode:end");
+}
+
+void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) {
+  writeUleb128(OS, Limits.Flags, "limits flags");
+  writeUleb128(OS, Limits.Initial, "limits initial");
+  if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
+    writeUleb128(OS, Limits.Maximum, "limits max");
+}
+
+void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) {
+  writeValueType(OS, Global.Type, "global type");
+  writeUleb128(OS, Global.Mutable, "global mutable");
+  writeInitExpr(OS, Global.InitExpr);
+}
+
+void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
+  writeStr(OS, Import.Module, "import module name");
+  writeStr(OS, Import.Field, "import field name");
+  writeU8(OS, Import.Kind, "import kind");
+  switch (Import.Kind) {
+  case WASM_EXTERNAL_FUNCTION:
+    writeUleb128(OS, Import.SigIndex, "import sig index");
+    break;
+  case WASM_EXTERNAL_GLOBAL:
+    writeValueType(OS, Import.Global.Type, "import global type");
+    writeUleb128(OS, Import.Global.Mutable, "import global mutable");
+    break;
+  case WASM_EXTERNAL_MEMORY:
+    writeLimits(OS, Import.Memory);
+    break;
+  default:
+    fatal("unsupported import type: " + Twine(Import.Kind));
+    break;
+  }
+}
+
+void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) {
+  writeStr(OS, Export.Name, "export name");
+  writeU8(OS, Export.Kind, "export kind");
+  switch (Export.Kind) {
+  case WASM_EXTERNAL_FUNCTION:
+    writeUleb128(OS, Export.Index, "function index");
+    break;
+  case WASM_EXTERNAL_GLOBAL:
+    writeUleb128(OS, Export.Index, "global index");
+    break;
+  case WASM_EXTERNAL_MEMORY:
+    writeUleb128(OS, Export.Index, "memory index");
+    break;
+  default:
+    fatal("unsupported export type: " + Twine(Export.Kind));
+    break;
+  }
+}
+
+void wasm::writeReloc(raw_ostream &OS, const OutputRelocation &Reloc) {
+  writeUleb128(OS, Reloc.Reloc.Type, "reloc type");
+  writeUleb128(OS, Reloc.Reloc.Offset, "reloc offset");
+  writeUleb128(OS, Reloc.NewIndex, "reloc index");
+
+  switch (Reloc.Reloc.Type) {
+  case R_WEBASSEMBLY_MEMORY_ADDR_LEB:
+  case R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
+  case R_WEBASSEMBLY_MEMORY_ADDR_I32:
+    writeUleb128(OS, Reloc.Reloc.Addend, "reloc addend");
+    break;
+  default:
+    break;
+  }
+}
+
+} // namespace lld

Propchange: lld/trunk/wasm/WriterUtils.cpp
------------------------------------------------------------------------------
    svn:eol-style = LF

Added: lld/trunk/wasm/WriterUtils.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/WriterUtils.h?rev=318539&view=auto
==============================================================================
--- lld/trunk/wasm/WriterUtils.h (added)
+++ lld/trunk/wasm/WriterUtils.h Fri Nov 17 10:14:09 2017
@@ -0,0 +1,63 @@
+//===- WriterUtils.h --------------------------------------------*- C++ -*-===//
+//
+//                             The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_WRITERUTILS_H
+#define LLD_WASM_WRITERUTILS_H
+
+#include "llvm/ADT/Twine.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/raw_ostream.h"
+
+using llvm::raw_ostream;
+
+namespace lld {
+namespace wasm {
+
+struct OutputRelocation {
+  llvm::wasm::WasmRelocation Reloc;
+  uint32_t NewIndex;
+  uint32_t Value;
+};
+
+void debugWrite(uint64_t offset, llvm::Twine msg);
+
+void writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg);
+
+void writeSleb128(raw_ostream &OS, int32_t Number, const char *msg);
+
+void writeBytes(raw_ostream &OS, const char *bytes, size_t count,
+                const char *msg = nullptr);
+
+void writeStr(raw_ostream &OS, const llvm::StringRef String,
+              const char *msg = nullptr);
+
+void writeU8(raw_ostream &OS, uint8_t byte, const char *msg);
+
+void writeU32(raw_ostream &OS, uint32_t Number, const char *msg);
+
+void writeValueType(raw_ostream &OS, int32_t Type, const char *msg);
+
+void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig);
+
+void writeInitExpr(raw_ostream &OS, const llvm::wasm::WasmInitExpr &InitExpr);
+
+void writeLimits(raw_ostream &OS, const llvm::wasm::WasmLimits &Limits);
+
+void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global);
+
+void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
+
+void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);
+
+void writeReloc(raw_ostream &OS, const OutputRelocation &Reloc);
+
+} // namespace wasm
+} // namespace lld
+
+#endif // LLD_WASM_WRITERUTILS_H

Propchange: lld/trunk/wasm/WriterUtils.h
------------------------------------------------------------------------------
    svn:eol-style = LF




More information about the llvm-commits mailing list