[lld][WebAssemby] Demote LazySymbols back to undefined symbols if they are not loaded

A LazySymbol is one that lives in `.a` archive and gets pulled in by a
strong reference.  However, weak references to such symbols do not
result in them be loaded from the archive.  In this case we want to
treat such symbols at undefined rather then lazy, once symbols
resolution is complete.

This fixes a crash bug in the linker when weakly referenced symbol that
lives in an archive file is live at the end of the link.  In the case of
dynamic linking this is expected to turn into an import with (in the
case of a function symbol) a function index.

Differential Revision: https://reviews.llvm.org/D130736
This commit is contained in:
Sam Clegg 2022-07-28 15:45:02 -07:00
parent 48129cf0ed
commit b0f18af30b
4 changed files with 50 additions and 1 deletions

View File

@ -3,11 +3,24 @@
# RUN: obj2yaml %t.wasm | FileCheck %s
# RUN: llvm-objdump -d %t.wasm | FileCheck %s -check-prefix=ASM
# Run the same test but include a definition of ret32 in a library file.
# This verifies that LazySymbols (those found in library archives) are correctly
# demoted to undefined symbols in the final link when they are only weakly
# referenced.
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.ret32.o %p/Inputs/ret32.s
# RUN: rm -f %T/libret32.a
# RUN: llvm-ar cru %T/libret32.a %t.ret32.o
# RUN: wasm-ld --experimental-pic -shared -o %t.ret32.wasm %t.o %T/libret32.a
# RUN: obj2yaml %t.wasm | FileCheck %s
# RUN: llvm-objdump -d %t.wasm | FileCheck %s -check-prefix=ASM
# Verify the weak undefined symbols are marked as such in the
# dylink section.
.weak weak_func
.functype weak_func () -> (i32)
.weak ret32
.functype ret32 (f32) -> (i32)
.globl call_weak
call_weak:
@ -18,6 +31,19 @@ call_weak:
end_function
# ASM-NEXT: 0b end
# This function is defined in library archive, but since our reference to it
# is weak we don't expect this definition to be used. Instead we expect it to
# act like an undefined reference and result in an imported function.
.globl call_weak_libfunc
call_weak_libfunc:
# ASM: <call_weak_libfunc>:
.functype call_weak_libfunc () -> (i32)
f32.const 1.0
call ret32
# ASM: 10 81 80 80 80 00 call 1
end_function
# ASM-NEXT: 0b end
# CHECK: Sections:
# CHECK-NEXT: - Type: CUSTOM
# CHECK-NEXT: Name: dylink.0
@ -30,3 +56,6 @@ call_weak:
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: weak_func
# CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ]
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: ret32
# CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ]

View File

@ -570,6 +570,21 @@ static void handleLibcall(StringRef name) {
}
}
// Equivalent of demote demoteSharedAndLazySymbols() in the ELF linker
static void demoteLazySymbols() {
for (Symbol *sym : symtab->getSymbols()) {
if (auto* s = dyn_cast<LazySymbol>(sym)) {
if (s->signature) {
LLVM_DEBUG(llvm::dbgs()
<< "demoting lazy func: " << s->getName() << "\n");
replaceSymbol<UndefinedFunction>(s, s->getName(), None, None,
WASM_SYMBOL_BINDING_WEAK, s->getFile(),
s->signature);
}
}
}
}
static UndefinedGlobal *
createUndefinedGlobal(StringRef name, llvm::wasm::WasmGlobalType *type) {
auto *sym = cast<UndefinedGlobal>(symtab->addUndefinedGlobal(
@ -1030,6 +1045,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// collection.
splitSections();
// Any remaining lazy symbols should be demoted to Undefined
demoteLazySymbols();
// Do size optimizations: garbage collection
markLive();

View File

@ -112,6 +112,7 @@ std::pair<Symbol *, bool> SymbolTable::insertName(StringRef name) {
sym->canInline = true;
sym->traced = trace;
sym->forceExport = false;
sym->referenced = !config->gcSections;
symVector.emplace_back(sym);
return {sym, true};
}

View File

@ -500,7 +500,7 @@ public:
MemoryBufferRef getMemberBuffer();
// Lazy symbols can have a signature because they can replace an
// UndefinedFunction which which case we need to be able to preserve the
// UndefinedFunction in which case we need to be able to preserve the
// signature.
// TODO(sbc): This repetition of the signature field is inelegant. Revisit
// the use of class hierarchy to represent symbol taxonomy.
@ -649,6 +649,7 @@ T *replaceSymbol(Symbol *s, ArgT &&... arg) {
s2->forceExport = symCopy.forceExport;
s2->canInline = symCopy.canInline;
s2->traced = symCopy.traced;
s2->referenced = symCopy.referenced;
// Print out a log message if --trace-symbol was specified.
// This is for debugging.