[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
This commit is contained in:
Sam Clegg 2023-02-24 10:09:07 -08:00
parent 45391e1394
commit d65ed8cde0
4 changed files with 38 additions and 4 deletions

View File

@ -0,0 +1,5 @@
.globl f2
f2:
.functype f2 () -> (i32)
i32.const global_var
end_function

View File

@ -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: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.o %s
# RUN: wasm-ld -strip-all %t.o -o %t.wasm # RUN: wasm-ld -strip-all %t.o -o %t.wasm
# RUN: obj2yaml %t.wasm | FileCheck %s # RUN: obj2yaml %t.wasm | FileCheck %s
# Test that undefined weak externals (global_var) and (foo) don't cause # Also verify test that strong references in another file do cause link
# link failures and resolve to zero. # 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) .functype foo () -> (i32)
@ -33,7 +42,6 @@ _start:
.weak foo .weak foo
.weak global_var .weak global_var
# CHECK: --- !WASM # CHECK: --- !WASM
# CHECK-NEXT: FileHeader: # CHECK-NEXT: FileHeader:
# CHECK-NEXT: Version: 0x1 # CHECK-NEXT: Version: 0x1

View File

@ -548,6 +548,8 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef name,
file); file);
if (isCalledDirectly) if (isCalledDirectly)
existingUndefined->isCalledDirectly = true; existingUndefined->isCalledDirectly = true;
if (s->isWeak())
s->flags = flags;
} }
} }
@ -574,6 +576,8 @@ Symbol *SymbolTable::addUndefinedData(StringRef name, uint32_t flags,
lazy->fetch(); lazy->fetch();
} else if (s->isDefined()) { } else if (s->isDefined()) {
checkDataType(s, file); checkDataType(s, file);
} else if (s->isWeak()) {
s->flags = flags;
} }
return s; return s;
} }
@ -599,6 +603,8 @@ Symbol *SymbolTable::addUndefinedGlobal(StringRef name,
lazy->fetch(); lazy->fetch();
else if (s->isDefined()) else if (s->isDefined())
checkGlobalType(s, file, type); checkGlobalType(s, file, type);
else if (s->isWeak())
s->flags = flags;
return s; return s;
} }
@ -623,6 +629,8 @@ Symbol *SymbolTable::addUndefinedTable(StringRef name,
lazy->fetch(); lazy->fetch();
else if (s->isDefined()) else if (s->isDefined())
checkTableType(s, file, type); checkTableType(s, file, type);
else if (s->isWeak())
s->flags = flags;
return s; return s;
} }
@ -647,6 +655,8 @@ Symbol *SymbolTable::addUndefinedTag(StringRef name,
lazy->fetch(); lazy->fetch();
else if (s->isDefined()) else if (s->isDefined())
checkTagType(s, file, sig); checkTagType(s, file, sig);
else if (s->isWeak())
s->flags = flags;
return s; return s;
} }

View File

@ -38,7 +38,18 @@ using namespace object;
void WasmSymbol::print(raw_ostream &Out) const { void WasmSymbol::print(raw_ostream &Out) const {
Out << "Name=" << Info.Name Out << "Name=" << Info.Name
<< ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x" << ", 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()) { if (!isTypeData()) {
Out << ", ElemIndex=" << Info.ElementIndex; Out << ", ElemIndex=" << Info.ElementIndex;
} else if (isDefined()) { } else if (isDefined()) {