forked from OSchip/llvm-project
[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:
parent
48129cf0ed
commit
b0f18af30b
|
@ -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 ]
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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};
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue