From d65ed8cde0a2b595a36f031d65158b08e6421b4f Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Fri, 24 Feb 2023 10:09:07 -0800 Subject: [PATCH] [lld][WebAssembly] Fix handling of mixed strong and weak references When adding a undefined symbols to the symbol table, if the existing reference is weak replace the symbol flags with (potentially) non-weak binding. Fixes: https://github.com/llvm/llvm-project/issues/60829 Differential Revision: https://reviews.llvm.org/D144747 --- lld/test/wasm/Inputs/strong-refs.s | 5 +++++ lld/test/wasm/weak-undefined.s | 14 +++++++++++--- lld/wasm/SymbolTable.cpp | 10 ++++++++++ llvm/lib/Object/WasmObjectFile.cpp | 13 ++++++++++++- 4 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 lld/test/wasm/Inputs/strong-refs.s diff --git a/lld/test/wasm/Inputs/strong-refs.s b/lld/test/wasm/Inputs/strong-refs.s new file mode 100644 index 0000000..bbf04e1 --- /dev/null +++ b/lld/test/wasm/Inputs/strong-refs.s @@ -0,0 +1,5 @@ +.globl f2 +f2: + .functype f2 () -> (i32) + i32.const global_var + end_function diff --git a/lld/test/wasm/weak-undefined.s b/lld/test/wasm/weak-undefined.s index 5b8b977..e1f551d 100644 --- a/lld/test/wasm/weak-undefined.s +++ b/lld/test/wasm/weak-undefined.s @@ -1,9 +1,18 @@ +# Test that undefined weak externals (global_var) and (foo) don't cause +# link failures and resolve to zero. + # RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s # RUN: wasm-ld -strip-all %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. +# Also verify test that strong references in another file do cause link +# failure (See https://github.com/llvm/llvm-project/issues/60806) + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/strong-refs.s -o %t-strong.o +# RUN: not wasm-ld -strip-all %t.o %t-strong.o -o %t.wasm 2>&1 | FileCheck --check-prefix=ERROR %s +# RUN: not wasm-ld -strip-all %t-strong.o %t.o -o %t.wasm 2>&1 | FileCheck --check-prefix=ERROR %s + +# ERROR: undefined symbol: global_var .functype foo () -> (i32) @@ -33,7 +42,6 @@ _start: .weak foo .weak global_var - # CHECK: --- !WASM # CHECK-NEXT: FileHeader: # CHECK-NEXT: Version: 0x1 diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 8ca5e94..d14e9d5 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -548,6 +548,8 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name, file); if (isCalledDirectly) existingUndefined->isCalledDirectly = true; + if (s->isWeak()) + s->flags = flags; } } @@ -574,6 +576,8 @@ Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags, lazy->fetch(); } else if (s->isDefined()) { checkDataType(s, file); + } else if (s->isWeak()) { + s->flags = flags; } return s; } @@ -599,6 +603,8 @@ Symbol *SymbolTable::addUndefinedGlobal(StringRef name, lazy->fetch(); else if (s->isDefined()) checkGlobalType(s, file, type); + else if (s->isWeak()) + s->flags = flags; return s; } @@ -623,6 +629,8 @@ Symbol *SymbolTable::addUndefinedTable(StringRef name, lazy->fetch(); else if (s->isDefined()) checkTableType(s, file, type); + else if (s->isWeak()) + s->flags = flags; return s; } @@ -647,6 +655,8 @@ Symbol *SymbolTable::addUndefinedTag(StringRef name, lazy->fetch(); else if (s->isDefined()) checkTagType(s, file, sig); + else if (s->isWeak()) + s->flags = flags; return s; } diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 400911d..471b68f 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -38,7 +38,18 @@ using namespace object; void WasmSymbol::print(raw_ostream &Out) const { Out << "Name=" << Info.Name << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x" - << Twine::utohexstr(Info.Flags); + << Twine::utohexstr(Info.Flags) << " ["; + switch (getBinding()) { + case wasm::WASM_SYMBOL_BINDING_GLOBAL: Out << "global"; break; + case wasm::WASM_SYMBOL_BINDING_LOCAL: Out << "local"; break; + case wasm::WASM_SYMBOL_BINDING_WEAK: Out << "weak"; break; + } + if (isHidden()) { + Out << ", hidden"; + } else { + Out << ", default"; + } + Out << "]"; if (!isTypeData()) { Out << ", ElemIndex=" << Info.ElementIndex; } else if (isDefined()) { -- 2.7.4