Index: lld/trunk/test/wasm/Inputs/comdat2.ll =================================================================== --- lld/trunk/test/wasm/Inputs/comdat2.ll +++ lld/trunk/test/wasm/Inputs/comdat2.ll @@ -9,5 +9,5 @@ define i32 @callInline2() { entry: - ret i32 ptrtoint (i32 ()* @inlineFn to i32) + ret i32 ptrtoint (i32 ()* @inlineFn to i32) } Index: lld/trunk/test/wasm/data-layout.ll =================================================================== --- lld/trunk/test/wasm/data-layout.ll +++ lld/trunk/test/wasm/data-layout.ll @@ -13,7 +13,7 @@ @local_struct = hidden global %struct.s zeroinitializer, align 4 @local_struct_internal_ptr = hidden local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @local_struct, i32 0, i32 1), align 4 -; RUN: wasm-ld -no-gc-sections --allow-undefined -o %t.wasm %t.o %t.hello.o +; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o ; RUN: obj2yaml %t.wasm | FileCheck %s ; CHECK: - Type: MEMORY @@ -57,7 +57,7 @@ ; CHECK-NEXT: - Type: CUSTOM -; RUN: wasm-ld -no-gc-sections --allow-undefined \ +; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry \ ; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \ ; RUN: %t.hello.o ; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX Index: lld/trunk/test/wasm/data-segment-merging.ll =================================================================== --- lld/trunk/test/wasm/data-segment-merging.ll +++ lld/trunk/test/wasm/data-segment-merging.ll @@ -7,7 +7,7 @@ ; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o -; RUN: wasm-ld -no-gc-sections --allow-undefined -o %t.merged.wasm %t.data-segment-merging.o +; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o ; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE ; MERGE: - Type: DATA ; MERGE-NEXT: Segments: @@ -18,7 +18,7 @@ ; MERGE-NEXT: Value: 1024 ; MERGE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 -; RUN: wasm-ld -no-gc-sections --allow-undefined --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o +; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o ; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE ; SEPARATE: - Type: DATA ; SEPARATE-NEXT: Segments: Index: lld/trunk/test/wasm/entry-signature.ll =================================================================== --- lld/trunk/test/wasm/entry-signature.ll +++ lld/trunk/test/wasm/entry-signature.ll @@ -0,0 +1,10 @@ +; Verify that the entry point signauture can be flexible. +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t1.wasm %t.o + +target triple = "wasm32-unknown-unknown-wasm" + +define hidden i32 @_start(i32, i64) local_unnamed_addr #0 { +entry: + ret i32 0 +} Index: lld/trunk/test/wasm/entry.ll =================================================================== --- lld/trunk/test/wasm/entry.ll +++ lld/trunk/test/wasm/entry.ll @@ -28,8 +28,8 @@ ; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Type: -; The __wasm_call_ctors is somewhat special. Make sure we can use it -; as the entry point if we choose +; The __wasm_call_ctors is somewhat special since its created by the linker. +; Make sure we can use it as the entry point if we choose ; RUN: wasm-ld --entry=__wasm_call_ctors -o %t3.wasm %t.o ; RUN: obj2yaml %t3.wasm | FileCheck %s -check-prefix=CHECK-CTOR Index: lld/trunk/test/wasm/fatal-warnings.ll =================================================================== --- lld/trunk/test/wasm/fatal-warnings.ll +++ lld/trunk/test/wasm/fatal-warnings.ll @@ -1,14 +1,17 @@ ; RUN: llc -filetype=obj %s -o %t.main.o -; RUN: lld -flavor wasm -o %t.wasm %t.main.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN -; RUN: not lld -flavor wasm --fatal-warnings -o %t.wasm %t.main.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: lld -flavor wasm -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN +; RUN: not lld -flavor wasm --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL -; CHECK-WARN: warning: Function type mismatch: _start -; CHECK-FATAL: error: Function type mismatch: _start +; CHECK-WARN: warning: Function type mismatch: ret32 +; CHECK-FATAL: error: Function type mismatch: ret32 target triple = "wasm32-unknown-unknown" -define hidden i32 @_start(i32 %arg) local_unnamed_addr { +define hidden void @_start() local_unnamed_addr #0 { entry: - ret i32 %arg + %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2 + ret void } +declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1 Index: lld/trunk/test/wasm/load-undefined.test =================================================================== --- lld/trunk/test/wasm/load-undefined.test +++ lld/trunk/test/wasm/load-undefined.test @@ -36,4 +36,4 @@ ; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist ; RUN: not wasm-ld %t.start.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 +; CHECK-UNDEFINED2: symbol forced with --undefined not found: symboldoesnotexist Index: lld/trunk/test/wasm/undefined-entry.test =================================================================== --- lld/trunk/test/wasm/undefined-entry.test +++ lld/trunk/test/wasm/undefined-entry.test @@ -1,10 +1,11 @@ RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o RUN: not wasm-ld -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s - -CHECK: error: undefined symbol: _start - RUN: not wasm-ld -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM +RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-ALLOW +CHECK: error: undefined symbol: _start CHECK-CUSTOM: error: undefined symbol: foo +CHECK-ALLOW: error: entry symbol not defined (pass --no-entry to supress): +_start -RUN: wasm-ld -entry=foo --allow-undefined -o %t.wasm %t.ret32.o +RUN: wasm-ld --no-entry -o %t.wasm %t.ret32.o Index: lld/trunk/wasm/Driver.cpp =================================================================== --- lld/trunk/wasm/Driver.cpp +++ lld/trunk/wasm/Driver.cpp @@ -360,9 +360,11 @@ "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN); WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0); + // For now, since we don't actually use the start function as the + // wasm start symbol, we don't need to care about it signature. if (!Config->Entry.empty()) - EntrySym = Symtab->addUndefinedFunction(Config->Entry, 0, nullptr, - &NullSignature); + EntrySym = + Symtab->addUndefinedFunction(Config->Entry, 0, nullptr, nullptr); // Handle the `--undefined ` options. for (auto *Arg : Args.filtered(OPT_undefined)) @@ -386,15 +388,19 @@ if (!Config->Relocatable && !Config->AllowUndefined) { Symtab->reportRemainingUndefines(); } else { - // When we allow undefined symbols we cannot include those defined in - // -u/--undefined since these undefined symbols have only names and no - // function signature, which means they cannot be written to the final - // output. + // Even when using --allow-undefined we still want to report the absence of + // our initial set of undefined symbols (i.e. the entry point and symbols + // specified via --undefined). + // Part of the reason for this is that these function don't have signatures + // so which means they cannot be written as wasm function imports. for (auto *Arg : Args.filtered(OPT_undefined)) { Symbol *Sym = Symtab->find(Arg->getValue()); if (!Sym->isDefined()) - error("function forced with --undefined not found: " + Sym->getName()); + error("symbol forced with --undefined not found: " + Sym->getName()); } + if (EntrySym && !EntrySym->isDefined()) + error("entry symbol not defined (pass --no-entry to supress): " + + EntrySym->getName()); } if (errorCount()) return; Index: lld/trunk/wasm/SymbolTable.cpp =================================================================== --- lld/trunk/wasm/SymbolTable.cpp +++ lld/trunk/wasm/SymbolTable.cpp @@ -78,14 +78,14 @@ static void checkFunctionType(const Symbol *Existing, const InputFile *File, const WasmSignature *NewSig) { - if (!isa(Existing)) { + auto ExistingFunction = dyn_cast(Existing); + if (!ExistingFunction) { reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION); return; } - const WasmSignature *OldSig = - cast(Existing)->getFunctionType(); - if (OldSig && *NewSig != *OldSig) { + const WasmSignature *OldSig = ExistingFunction->getFunctionType(); + if (OldSig && NewSig && *NewSig != *OldSig) { warn("Function type mismatch: " + Existing->getName() + "\n>>> defined as " + toString(*OldSig) + " in " + toString(Existing->getFile()) + "\n>>> defined as " +