aboutsummaryrefslogtreecommitdiff
path: root/test/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'test/wasm')
-rw-r--r--test/wasm/Inputs/archive1.ll7
-rw-r--r--test/wasm/Inputs/archive2.ll7
-rw-r--r--test/wasm/Inputs/call-indirect.ll17
-rw-r--r--test/wasm/Inputs/hello.ll15
-rw-r--r--test/wasm/Inputs/hidden.ll11
-rw-r--r--test/wasm/Inputs/many-funcs.ll776
-rw-r--r--test/wasm/Inputs/ret32.ll6
-rw-r--r--test/wasm/Inputs/ret64.ll4
-rw-r--r--test/wasm/Inputs/weak-alias.ll13
-rw-r--r--test/wasm/Inputs/weak-symbol1.ll9
-rw-r--r--test/wasm/Inputs/weak-symbol2.ll9
-rw-r--r--test/wasm/archive.ll31
-rw-r--r--test/wasm/call-indirect.ll112
-rw-r--r--test/wasm/conflict.test6
-rw-r--r--test/wasm/data-layout.ll61
-rw-r--r--test/wasm/entry.ll19
-rw-r--r--test/wasm/function-imports-first.ll42
-rw-r--r--test/wasm/function-imports.ll37
-rw-r--r--test/wasm/function-index.test18
-rw-r--r--test/wasm/import-memory.test13
-rw-r--r--test/wasm/invalid-stack-size.test9
-rw-r--r--test/wasm/lit.local.cfg4
-rw-r--r--test/wasm/load-undefined.ll38
-rw-r--r--test/wasm/local-symbols.ll78
-rw-r--r--test/wasm/many-functions.ll695
-rw-r--r--test/wasm/relocatable.ll194
-rw-r--r--test/wasm/signature-mismatch.ll16
-rw-r--r--test/wasm/stack-pointer.ll64
-rw-r--r--test/wasm/strip-debug.test6
-rw-r--r--test/wasm/symbol-type-mismatch.ll9
-rw-r--r--test/wasm/undefined-entry.test4
-rw-r--r--test/wasm/undefined.ll20
-rw-r--r--test/wasm/version.ll13
-rw-r--r--test/wasm/visibility-hidden.ll46
-rw-r--r--test/wasm/weak-alias-overide.ll92
-rw-r--r--test/wasm/weak-alias.ll82
-rw-r--r--test/wasm/weak-external.ll86
-rw-r--r--test/wasm/weak-symbols.ll93
38 files changed, 2762 insertions, 0 deletions
diff --git a/test/wasm/Inputs/archive1.ll b/test/wasm/Inputs/archive1.ll
new file mode 100644
index 000000000000..c942fa2c1b55
--- /dev/null
+++ b/test/wasm/Inputs/archive1.ll
@@ -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
+}
diff --git a/test/wasm/Inputs/archive2.ll b/test/wasm/Inputs/archive2.ll
new file mode 100644
index 000000000000..35534dc9e076
--- /dev/null
+++ b/test/wasm/Inputs/archive2.ll
@@ -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
+}
diff --git a/test/wasm/Inputs/call-indirect.ll b/test/wasm/Inputs/call-indirect.ll
new file mode 100644
index 000000000000..388ea60c3a07
--- /dev/null
+++ b/test/wasm/Inputs/call-indirect.ll
@@ -0,0 +1,17 @@
+@indirect_bar = internal local_unnamed_addr global i32 ()* @bar, align 4
+@indirect_foo = internal local_unnamed_addr global i32 ()* @foo, align 4
+
+declare i32 @foo() local_unnamed_addr
+
+define i32 @bar() {
+entry:
+ ret i32 1
+}
+
+define void @call_bar_indirect() local_unnamed_addr #1 {
+entry:
+ %0 = load i32 ()*, i32 ()** @indirect_bar, align 4
+ %1 = load i32 ()*, i32 ()** @indirect_foo, align 4
+ %call = tail call i32 %0() #2
+ ret void
+}
diff --git a/test/wasm/Inputs/hello.ll b/test/wasm/Inputs/hello.ll
new file mode 100644
index 000000000000..93df0f559809
--- /dev/null
+++ b/test/wasm/Inputs/hello.ll
@@ -0,0 +1,15 @@
+; Wasm module generated from the following C code:
+; void puts(const char*);
+; void hello() { puts("hello\n"); }
+
+@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
diff --git a/test/wasm/Inputs/hidden.ll b/test/wasm/Inputs/hidden.ll
new file mode 100644
index 000000000000..25890e9f03f2
--- /dev/null
+++ b/test/wasm/Inputs/hidden.ll
@@ -0,0 +1,11 @@
+; Function Attrs: norecurse nounwind readnone
+define hidden i32 @archiveHidden() #0 {
+entry:
+ ret i32 0
+}
+
+; Function Attrs: norecurse nounwind readnone
+define i32 @archiveDefault() #1 {
+entry:
+ ret i32 0
+}
diff --git a/test/wasm/Inputs/many-funcs.ll b/test/wasm/Inputs/many-funcs.ll
new file mode 100644
index 000000000000..b8daab23638d
--- /dev/null
+++ b/test/wasm/Inputs/many-funcs.ll
@@ -0,0 +1,776 @@
+@g0 = global i32 1, align 4
+@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
+}
diff --git a/test/wasm/Inputs/ret32.ll b/test/wasm/Inputs/ret32.ll
new file mode 100644
index 000000000000..a4565288f08b
--- /dev/null
+++ b/test/wasm/Inputs/ret32.ll
@@ -0,0 +1,6 @@
+; Function Attrs: norecurse nounwind readnone
+define i32 @ret32(float %arg) #0 {
+entry:
+ ret i32 0
+ ; ptrtoint (i32 (float)* @ret32 to i32)
+}
diff --git a/test/wasm/Inputs/ret64.ll b/test/wasm/Inputs/ret64.ll
new file mode 100644
index 000000000000..6a9de0dace1d
--- /dev/null
+++ b/test/wasm/Inputs/ret64.ll
@@ -0,0 +1,4 @@
+define i64 @ret64(double %arg) local_unnamed_addr #0 {
+entry:
+ ret i64 1
+}
diff --git a/test/wasm/Inputs/weak-alias.ll b/test/wasm/Inputs/weak-alias.ll
new file mode 100644
index 000000000000..079e68e3ce7a
--- /dev/null
+++ b/test/wasm/Inputs/weak-alias.ll
@@ -0,0 +1,13 @@
+; Function Attrs: norecurse nounwind readnone
+define i32 @foo() #0 {
+entry:
+ ret i32 0
+}
+
+@bar = weak alias i32 (), i32 ()* @foo
+
+define i32 @call_bar() #0 {
+entry:
+ %call = call i32 @bar()
+ ret i32 %call
+}
diff --git a/test/wasm/Inputs/weak-symbol1.ll b/test/wasm/Inputs/weak-symbol1.ll
new file mode 100644
index 000000000000..2d561716f825
--- /dev/null
+++ b/test/wasm/Inputs/weak-symbol1.ll
@@ -0,0 +1,9 @@
+define weak i32 @weakFn() #0 {
+entry:
+ ret i32 1
+}
+
+define i32 @exportWeak1() {
+entry:
+ ret i32 ptrtoint (i32 ()* @weakFn to i32)
+}
diff --git a/test/wasm/Inputs/weak-symbol2.ll b/test/wasm/Inputs/weak-symbol2.ll
new file mode 100644
index 000000000000..f43ea96673b9
--- /dev/null
+++ b/test/wasm/Inputs/weak-symbol2.ll
@@ -0,0 +1,9 @@
+define weak i32 @weakFn() #0 {
+entry:
+ ret i32 2
+}
+
+define i32 @exportWeak2() {
+entry:
+ ret i32 ptrtoint (i32 ()* @weakFn to i32)
+}
diff --git a/test/wasm/archive.ll b/test/wasm/archive.ll
new file mode 100644
index 000000000000..18f35330d1e9
--- /dev/null
+++ b/test/wasm/archive.ll
@@ -0,0 +1,31 @@
+; 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 %t.a1.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/archive2.ll -o %t.a2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %S/Inputs/hello.ll -o %t.a3.o
+; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o
+; RUN: lld -flavor wasm %t.a %t.o -o %t.wasm
+; RUN: llvm-nm -a %t.wasm | FileCheck %s
+
+declare i32 @foo() local_unnamed_addr #1
+
+define i32 @_start() local_unnamed_addr #0 {
+entry:
+ %call = tail call i32 @foo() #2
+ ret i32 %call
+}
+
+; Verify that multually dependant object files in an archive is handled
+; correctly.
+
+; CHECK: 00000002 T _start
+; CHECK-NEXT: 00000002 T _start
+; CHECK-NEXT: 00000000 T bar
+; CHECK-NEXT: 00000000 T bar
+; CHECK-NEXT: 00000001 T foo
+; CHECK-NEXT: 00000001 T foo
+
+; Verify that symbols from unused objects don't appear in the symbol table
+; CHECK-NOT: hello
+
+; Specifying the same archive twice is allowed.
+; RUN: lld -flavor wasm %t.a %t.a %t.o -o %t.wasm
diff --git a/test/wasm/call-indirect.ll b/test/wasm/call-indirect.ll
new file mode 100644
index 000000000000..14845eb50f83
--- /dev/null
+++ b/test/wasm/call-indirect.ll
@@ -0,0 +1,112 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/call-indirect.ll -o %t2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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(); }
+
+@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4
+
+; Function Attrs: norecurse nounwind readnone
+define i32 @foo() #0 {
+entry:
+ ret i32 2
+}
+
+; Function Attrs: nounwind
+define i32 @_start() local_unnamed_addr #1 {
+entry:
+ %0 = load i32 ()*, i32 ()** @indirect_func, align 4
+ %call = tail call i32 %0() #2
+ 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: - 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: [ HAS_MAX ]
+; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: foo
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; 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: - 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-NEXT: - Locals:
+; CHECK-NEXT: Body: 41010B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 410028028088808000118080808000001A0B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 410028028888808000118080808000001A41000B
+; 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: '010000000200000002000000'
+; CHECK-NEXT: - Type: CUSTOM
+; CHECK-NEXT: Name: linking
+; CHECK-NEXT: DataSize: 12
+; 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
diff --git a/test/wasm/conflict.test b/test/wasm/conflict.test
new file mode 100644
index 000000000000..a0a2eb4e3b3a
--- /dev/null
+++ b/test/wasm/conflict.test
@@ -0,0 +1,6 @@
+# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
diff --git a/test/wasm/data-layout.ll b/test/wasm/data-layout.ll
new file mode 100644
index 000000000000..0b2c61da5547
--- /dev/null
+++ b/test/wasm/data-layout.ll
@@ -0,0 +1,61 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/hello.ll -o %t.hello.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm --emit-relocs --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+@foo = hidden global i32 1, align 4
+@aligned_bar = hidden global i32 3, align 16
+
+@hello_str = external global i8*
+@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
diff --git a/test/wasm/entry.ll b/test/wasm/entry.ll
new file mode 100644
index 000000000000..e51c7055b80e
--- /dev/null
+++ b/test/wasm/entry.ll
@@ -0,0 +1,19 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
+
+define 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
diff --git a/test/wasm/function-imports-first.ll b/test/wasm/function-imports-first.ll
new file mode 100644
index 000000000000..085345ad7ffc
--- /dev/null
+++ b/test/wasm/function-imports-first.ll
@@ -0,0 +1,42 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o %t.ret32.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; 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: ...
diff --git a/test/wasm/function-imports.ll b/test/wasm/function-imports.ll
new file mode 100644
index 000000000000..e0988ff95f96
--- /dev/null
+++ b/test/wasm/function-imports.ll
@@ -0,0 +1,37 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.ret32.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; 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: ...
diff --git a/test/wasm/function-index.test b/test/wasm/function-index.test
new file mode 100644
index 000000000000..03bd879b5176
--- /dev/null
+++ b/test/wasm/function-index.test
@@ -0,0 +1,18 @@
+# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
+# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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 ]
diff --git a/test/wasm/import-memory.test b/test/wasm/import-memory.test
new file mode 100644
index 000000000000..af0ff910449c
--- /dev/null
+++ b/test/wasm/import-memory.test
@@ -0,0 +1,13 @@
+# RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
diff --git a/test/wasm/invalid-stack-size.test b/test/wasm/invalid-stack-size.test
new file mode 100644
index 000000000000..6597c548499a
--- /dev/null
+++ b/test/wasm/invalid-stack-size.test
@@ -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
diff --git a/test/wasm/lit.local.cfg b/test/wasm/lit.local.cfg
new file mode 100644
index 000000000000..bc76e57c8e87
--- /dev/null
+++ b/test/wasm/lit.local.cfg
@@ -0,0 +1,4 @@
+if 'wasm' not in config.available_features:
+ config.unsupported = True
+
+config.suffixes = ['.test', '.yaml', '.ll']
diff --git a/test/wasm/load-undefined.ll b/test/wasm/load-undefined.ll
new file mode 100644
index 000000000000..f979c9acb517
--- /dev/null
+++ b/test/wasm/load-undefined.ll
@@ -0,0 +1,38 @@
+; Verify that the -u / --undefined option is able to pull in symbols from
+; an archive, and doesn't error when uses to pull in a symbol already loaded.
+;
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret64.ll -o %t.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret32.ll -o %t2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t3.o
+; RUN: llvm-ar rcs %t2.a %t2.o
+; RUN: lld -flavor wasm %t3.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+define i32 @_start() local_unnamed_addr {
+entry:
+ ret i32 1
+}
+
+; CHECK: - 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: 0
+; CHECK-NEXT: - Name: ret32
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: ret64
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Type:
+
+
+; Verify that referencing a symbol that doesn't exist won't work
+; RUN: not lld -flavor wasm %t3.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s
+; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist
+
+; RUN: not lld -flavor wasm %t3.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s
+; CHECK-UNDEFINED2: function forced with --undefined not found: symboldoesnotexist
diff --git a/test/wasm/local-symbols.ll b/test/wasm/local-symbols.ll
new file mode 100644
index 000000000000..3e6722b124ec
--- /dev/null
+++ b/test/wasm/local-symbols.ll
@@ -0,0 +1,78 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+@foo = default global i32 1, align 4
+@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: [ HAS_MAX ]
+; 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: ...
diff --git a/test/wasm/many-functions.ll b/test/wasm/many-functions.ll
new file mode 100644
index 000000000000..77326d739a8b
--- /dev/null
+++ b/test/wasm/many-functions.ll
@@ -0,0 +1,695 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/many-funcs.ll -o %t.many.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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.
+
+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: [ ]
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: .data.foo
+; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Flags: [ ]
diff --git a/test/wasm/relocatable.ll b/test/wasm/relocatable.ll
new file mode 100644
index 000000000000..cb86aa20cab2
--- /dev/null
+++ b/test/wasm/relocatable.ll
@@ -0,0 +1,194 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/hello.ll -o %t.hello.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -r -o %t.wasm %t.hello.o %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; 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
+@data_import = external global i64
+
+@func_addr1 = hidden global i32()* @my_func, align 4
+@func_addr2 = hidden global i32()* @foo_import, align 4
+@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: [ HAS_MAX ]
+; 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: - Name: hello_str
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: func_addr1
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: func_addr2
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 3
+; CHECK-NEXT: - Name: data_addr1
+; CHECK-NEXT: Kind: GLOBAL
+; CHECK-NEXT: Index: 4
+; 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: [ ]
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: Name: .data.func_addr1
+; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Index: 2
+; CHECK-NEXT: Name: .data.func_addr2
+; CHECK-NEXT: Alignment: 4
+; CHECK-NEXT: Flags: [ ]
+; CHECK-NEXT: - Index: 3
+; CHECK-NEXT: Name: .data.data_addr1
+; CHECK-NEXT: Alignment: 8
+; CHECK-NEXT: Flags: [ ]
+; 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: ...
diff --git a/test/wasm/signature-mismatch.ll b/test/wasm/signature-mismatch.ll
new file mode 100644
index 000000000000..88f70fea5123
--- /dev/null
+++ b/test/wasm/signature-mismatch.ll
@@ -0,0 +1,16 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.main.o
+; RUN: not lld -flavor wasm --check-signatures -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s
+
+; Function Attrs: nounwind
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+ %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2
+ ret void
+}
+
+declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1
+
+; CHECK: error: function signature mismatch: ret32
+; CHECK-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o
+; CHECK-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o
diff --git a/test/wasm/stack-pointer.ll b/test/wasm/stack-pointer.ll
new file mode 100644
index 000000000000..738f0dce8e81
--- /dev/null
+++ b/test/wasm/stack-pointer.ll
@@ -0,0 +1,64 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm --emit-relocs -o %t.wasm %t.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Function Attrs: nounwind
+define hidden i32 @_start() local_unnamed_addr {
+entry:
+ %retval = alloca i32, 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 ]
+; CHECK-NEXT: - Type: TABLE
+; CHECK-NEXT: Tables:
+; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Flags: [ HAS_MAX ]
+; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Relocations:
+; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: Offset: 0x00000004
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 23808080800041106B1A41000B
+; 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: ...
diff --git a/test/wasm/strip-debug.test b/test/wasm/strip-debug.test
new file mode 100644
index 000000000000..57667a9f4406
--- /dev/null
+++ b/test/wasm/strip-debug.test
@@ -0,0 +1,6 @@
+RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
diff --git a/test/wasm/symbol-type-mismatch.ll b/test/wasm/symbol-type-mismatch.ll
new file mode 100644
index 000000000000..706a361dd767
--- /dev/null
+++ b/test/wasm/symbol-type-mismatch.ll
@@ -0,0 +1,9 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
+
+@ret32 = extern_weak global i32, align 4
+
+; CHECK: error: symbol type mismatch: ret32
+; CHECK: >>> defined as Global in {{.*}}symbol-type-mismatch.ll.tmp.o
+; CHECK: >>> defined as Function in {{.*}}.ret32.o
diff --git a/test/wasm/undefined-entry.test b/test/wasm/undefined-entry.test
new file mode 100644
index 000000000000..00a0761f4b6c
--- /dev/null
+++ b/test/wasm/undefined-entry.test
@@ -0,0 +1,4 @@
+RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
diff --git a/test/wasm/undefined.ll b/test/wasm/undefined.ll
new file mode 100644
index 000000000000..c5f266431702
--- /dev/null
+++ b/test/wasm/undefined.ll
@@ -0,0 +1,20 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %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
+
+; Takes the address of the external foo() resulting in undefined external
+@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
+}
diff --git a/test/wasm/version.ll b/test/wasm/version.ll
new file mode 100644
index 000000000000..aed7b39ff3b9
--- /dev/null
+++ b/test/wasm/version.ll
@@ -0,0 +1,13 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o
+; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s
+
+define hidden void @_start() local_unnamed_addr #0 {
+entry:
+ ret void
+}
+
+; CHECK: Format: WASM
+; CHECK: Arch: wasm32
+; CHECK: AddressSize: 32bit
+; CHECK: Version: 0x1
diff --git a/test/wasm/visibility-hidden.ll b/test/wasm/visibility-hidden.ll
new file mode 100644
index 000000000000..9960b952492b
--- /dev/null
+++ b/test/wasm/visibility-hidden.ll
@@ -0,0 +1,46 @@
+; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s
+; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/hidden.ll -o %t2.o
+; RUN: llvm-ar rcs %t2.a %t2.o
+; RUN: lld -flavor wasm %t.o %t2.a -o %t.wasm
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+; Test that hidden symbols are not exported, whether pulled in from an archive
+; or directly.
+
+define hidden i32 @objectHidden() {
+entry:
+ ret i32 0
+}
+
+define i32 @objectDefault() {
+entry:
+ ret i32 0
+}
+
+declare i32 @archiveHidden()
+declare i32 @archiveDefault()
+
+define i32 @_start() {
+entry:
+ %call1 = call i32 @objectHidden()
+ %call2 = call i32 @objectDefault()
+ %call3 = call i32 @archiveHidden()
+ %call4 = call i32 @archiveDefault()
+ ret i32 0
+}
+
+; CHECK: - 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: 2
+; CHECK-NEXT: - Name: archiveDefault
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 4
+; CHECK-NEXT: - Name: objectDefault
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Type:
diff --git a/test/wasm/weak-alias-overide.ll b/test/wasm/weak-alias-overide.ll
new file mode 100644
index 000000000000..5f4021e18b0f
--- /dev/null
+++ b/test/wasm/weak-alias-overide.ll
@@ -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: [ HAS_MAX ]
+; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: bar
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+; 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: ...
diff --git a/test/wasm/weak-alias.ll b/test/wasm/weak-alias.ll
new file mode 100644
index 000000000000..6f96d4d17643
--- /dev/null
+++ b/test/wasm/weak-alias.ll
@@ -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: [ HAS_MAX ]
+; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: bar
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; 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: ...
diff --git a/test/wasm/weak-external.ll b/test/wasm/weak-external.ll
new file mode 100644
index 000000000000..891f7666ec76
--- /dev/null
+++ b/test/wasm/weak-external.ll
@@ -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.
+
+@global_var = extern_weak global i32, align 4
+
+declare extern_weak i32 @foo()
+
+define i8* @get_address_of_foo() #0 {
+entry:
+ ret i8* bitcast (i32 ()* @foo to i8*)
+}
+
+define i32* @get_address_of_global_var() #0 {
+ ret i32* @global_var
+}
+
+define 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: [ HAS_MAX ]
+; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; 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: - 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: ...
diff --git a/test/wasm/weak-symbols.ll b/test/wasm/weak-symbols.ll
new file mode 100644
index 000000000000..c282d005623f
--- /dev/null
+++ b/test/wasm/weak-symbols.ll
@@ -0,0 +1,93 @@
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/weak-symbol1.ll -o %t1.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/weak-symbol2.ll -o %t2.o
+; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o
+; RUN: lld -flavor wasm -o %t.wasm %t.o %t1.o %t2.o
+; RUN: obj2yaml %t.wasm | FileCheck %s
+
+declare i32 @weakFn() local_unnamed_addr
+
+define void @_start() local_unnamed_addr {
+entry:
+ %call = call i32 @weakFn()
+ 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: NORESULT
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Index: 1
+; CHECK-NEXT: ReturnType: I32
+; CHECK-NEXT: ParamTypes:
+; CHECK-NEXT: - Type: FUNCTION
+; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1 ]
+; CHECK-NEXT: - Type: TABLE
+; CHECK-NEXT: Tables:
+; CHECK-NEXT: - ElemType: ANYFUNC
+; CHECK-NEXT: Limits:
+; CHECK-NEXT: Flags: [ HAS_MAX ]
+; 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: _start
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 0
+; CHECK-NEXT: - Name: weakFn
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 1
+; CHECK-NEXT: - Name: exportWeak1
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 2
+; CHECK-NEXT: - Name: exportWeak2
+; CHECK-NEXT: Kind: FUNCTION
+; CHECK-NEXT: Index: 4
+; CHECK-NEXT: - Type: ELEM
+; CHECK-NEXT: Segments:
+; CHECK-NEXT: - Offset:
+; CHECK-NEXT: Opcode: I32_CONST
+; CHECK-NEXT: Value: 1
+; CHECK-NEXT: Functions: [ 1 ]
+; CHECK-NEXT: - Type: CODE
+; CHECK-NEXT: Functions:
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 1081808080001A0B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 41010B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 4181808080000B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 41020B
+; CHECK-NEXT: - Locals:
+; CHECK-NEXT: Body: 4181808080000B
+; 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: 2
+; CHECK-NEXT: Name: exportWeak1
+; CHECK-NEXT: - Index: 4
+; CHECK-NEXT: Name: exportWeak2
+; CHECK-NEXT: ...