diff --git a/lld/test/wasm/Inputs/libsearch-dyn.s b/lld/test/wasm/Inputs/libsearch-dyn.s index bb59580b830f..96c351d6262f 100644 --- a/lld/test/wasm/Inputs/libsearch-dyn.s +++ b/lld/test/wasm/Inputs/libsearch-dyn.s @@ -1,4 +1,4 @@ -.globl _bar,_dynamic +.globl _bar,_dynamic,_foo_tag .section .data,"",@ _bar: @@ -6,3 +6,6 @@ _bar: _dynamic: .size _dynamic,4 + +.tagtype _foo_tag i32 +_foo_tag: diff --git a/lld/test/wasm/dylink.s b/lld/test/wasm/dylink.s index ab604fc1adc1..d40778c3b2d6 100644 --- a/lld/test/wasm/dylink.s +++ b/lld/test/wasm/dylink.s @@ -1,4 +1,4 @@ -# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten -o %t.o %s +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten -mattr=+exception-handling -o %t.o %s # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten %p/Inputs/ret32.s -o %t.ret32.o # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-emscripten %p/Inputs/libsearch-dyn.s -o %t.dyn.o # RUN: wasm-ld --experimental-pic -shared %t.ret32.o %t.dyn.o -o %t.lib.so @@ -8,7 +8,7 @@ # Same again for wasm64 -# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten -o %t.o %s +# RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten -mattr=+exception-handling -o %t.o %s # RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten %p/Inputs/ret32.s -o %t.ret32.o # RUN: llvm-mc -filetype=obj -triple=wasm64-unknown-emscripten %p/Inputs/libsearch-dyn.s -o %t.dyn.o # RUN: wasm-ld --experimental-pic -mwasm64 -shared %t.ret32.o %t.dyn.o -o %t.lib.so @@ -18,8 +18,9 @@ # ERROR: error: {{.*}}: undefined symbol: ret32 # ERROR: error: {{.*}}: undefined symbol: _bar +# ERROR: error: {{.*}}: undefined symbol: _foo_tag .functype ret32 (f32) -> (i32) - +.tagtype _foo_tag i32 .globl _start _start: .functype _start () -> () @@ -28,6 +29,8 @@ _start: drop i32.const _bar@GOT drop + i32.const 0 + throw _foo_tag end_function # CHECK: Sections: @@ -39,3 +42,7 @@ _start: # CHECK-NEXT: TableAlignment: 0 # CHECK-NEXT: Needed: # CHECK-NEXT: - {{.*}}.lib.so +# +# CHECK: Field: _foo_tag +# CHECK-NEXT: Kind: TAG +# CHECK-NEXT: SigIndex: 1 diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp index dcdd138508c1..ad7f207259a5 100644 --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -453,6 +453,9 @@ void SharedFile::parse() { case WASM_SYMBOL_TYPE_DATA: s = symtab->addSharedData(name, flags, this); break; + case WASM_SYMBOL_TYPE_TAG: + s = symtab->addSharedTag(name, flags, this, wasmSym.Signature); + break; default: continue; } diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 9bd93f317c3c..05e653ea23ed 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -352,6 +352,44 @@ static void reportFunctionSignatureMismatch(StringRef symName, isError); } +Symbol *SymbolTable::addSharedTag(StringRef name, uint32_t flags, + InputFile *file, const WasmSignature *sig) { + LLVM_DEBUG(dbgs() << "addSharedTag: " << name << " [" << toString(*sig) + << "]\n"); + Symbol *s; + bool wasInserted; + std::tie(s, wasInserted) = insert(name, file); + + auto replaceSym = [&](Symbol *sym) { + replaceSymbol(sym, name, flags, file, sig); + }; + + // same as addSharedFunction, but this is in its own function + if (wasInserted || s->isLazy()) { + replaceSym(s); + return s; + } + + auto *existingTag = dyn_cast(s); + if (!existingTag) { + reportTypeError(s, file, WASM_SYMBOL_TYPE_TAG); + return s; + } + + if (s->isDefined()) { + return s; + } + + // undefined existing sym + const WasmSignature *oldSig = existingTag->signature; + if (oldSig && sig && *oldSig != *sig) + error("Tag signature mismatch: " + name + "\n>>> defined as " + + toString(*oldSig) + " in " + toString(existingTag->getFile()) + + "\n>>> defined as " + toString(*sig) + " in " + toString(file)); + replaceSym(s); + return s; +} + Symbol *SymbolTable::addSharedFunction(StringRef name, uint32_t flags, InputFile *file, const WasmSignature *sig) { diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h index 649614298c52..0667cedecdb4 100644 --- a/lld/wasm/SymbolTable.h +++ b/lld/wasm/SymbolTable.h @@ -53,6 +53,8 @@ public: Symbol *addSharedFunction(StringRef name, uint32_t flags, InputFile *file, const WasmSignature *sig); Symbol *addSharedData(StringRef name, uint32_t flags, InputFile *file); + Symbol *addSharedTag(StringRef name, uint32_t flags, InputFile *file, + const WasmSignature *sig); Symbol *addDefinedFunction(StringRef name, uint32_t flags, InputFile *file, InputFunction *function); Symbol *addDefinedData(StringRef name, uint32_t flags, InputFile *file, diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp index 97a9871a0630..9ce2a9f9f509 100644 --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -72,6 +72,8 @@ std::string toString(wasm::Symbol::Kind kind) { return "SharedFunctionKind"; case wasm::Symbol::SharedDataKind: return "SharedDataKind"; + case wasm::Symbol::SharedTagKind: + return "SharedTagSymbol"; } llvm_unreachable("invalid symbol kind"); } diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index 3dda36f88d5e..47f1b3ad54ea 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -62,6 +62,7 @@ public: LazyKind, SharedFunctionKind, SharedDataKind, + SharedTagKind, }; Kind kind() const { return symbolKind; } @@ -77,7 +78,8 @@ public: bool isLazy() const { return symbolKind == LazyKind; } bool isShared() const { - return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind; + return symbolKind == SharedFunctionKind || symbolKind == SharedDataKind || + symbolKind == SharedTagKind; } bool isLocal() const; @@ -461,7 +463,8 @@ public: class TagSymbol : public Symbol { public: static bool classof(const Symbol *s) { - return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind; + return s->kind() == DefinedTagKind || s->kind() == UndefinedTagKind || + s->kind() == SharedTagKind; } // Get/set the tag index @@ -501,6 +504,15 @@ public: static bool classof(const Symbol *s) { return s->kind() == UndefinedTagKind; } }; +class SharedTagSymbol : public TagSymbol { +public: + SharedTagSymbol(StringRef name, uint32_t flags, InputFile *f, + const WasmSignature *sig) + : TagSymbol(name, SharedTagKind, flags, f, sig) {} + + static bool classof(const Symbol *s) { return s->kind() == SharedTagKind; } +}; + class SharedFunctionSymbol : public FunctionSymbol { public: SharedFunctionSymbol(StringRef name, uint32_t flags, InputFile *file, @@ -553,6 +565,7 @@ union SymbolUnion { alignas(UndefinedTable) char j[sizeof(UndefinedTable)]; alignas(SectionSymbol) char k[sizeof(SectionSymbol)]; alignas(SharedFunctionSymbol) char l[sizeof(SharedFunctionSymbol)]; + alignas(SharedTagSymbol) char m[sizeof(SharedTagSymbol)]; }; // It is important to keep the size of SymbolUnion small for performance and diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 852dc23f99e5..5f125ffb1019 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1547,6 +1547,10 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { object_error::parse_failed); Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG; Info.ElementIndex = Ex.Index; + if (isDefinedTagIndex(Ex.Index)) { + unsigned TagIndex = Ex.Index - NumImportedTags; + Signature = &Signatures[Tags[TagIndex].SigIndex]; + } break; case wasm::WASM_EXTERNAL_MEMORY: break;