define i32 @callInline2() {
entry:
- ret i32 ptrtoint (i32 ()* @inlineFn to i32)
+ ret i32 ptrtoint (i32 ()* @inlineFn to i32)
}
@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
; 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
; 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:
; 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:
--- /dev/null
+; 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
+}
; 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
; 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
; 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
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
"__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 <sym>` options.
for (auto *Arg : Args.filtered(OPT_undefined))
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;
static void checkFunctionType(const Symbol *Existing, const InputFile *File,
const WasmSignature *NewSig) {
- if (!isa<FunctionSymbol>(Existing)) {
+ auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing);
+ if (!ExistingFunction) {
reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION);
return;
}
- const WasmSignature *OldSig =
- cast<FunctionSymbol>(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 " +