diff --git a/lld/test/wasm/Inputs/ctor-ctor.s b/lld/test/wasm/Inputs/ctor-ctor.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/Inputs/ctor-ctor.s @@ -0,0 +1,19 @@ + .section .text.def,"",@ + .hidden def + .globl def + .type def,@function +def: + .functype def () -> () + end_function + + .section .text.ctor,"",@ + .hidden ctor + .globl ctor + .type ctor,@function +ctor: + .functype ctor () -> () + end_function + + .section .init_array,"",@ + .p2align 2 + .int32 ctor diff --git a/lld/test/wasm/Inputs/ctor-lib.s b/lld/test/wasm/Inputs/ctor-lib.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/Inputs/ctor-lib.s @@ -0,0 +1,18 @@ + .section .text.usethis,"",@ + .hidden usethis + .globl usethis + .type usethis,@function +usethis: + .functype usethis () -> () + end_function + + .section .text.bar,"",@ + .hidden bar + .globl bar + .type bar,@function +bar: + .functype bar () -> () + call def + end_function + + .functype def () -> () diff --git a/lld/test/wasm/Inputs/ctor-start.s b/lld/test/wasm/Inputs/ctor-start.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/Inputs/ctor-start.s @@ -0,0 +1,9 @@ + .section .text.main,"",@ + .globl _start + .type _start,@function +_start: + .functype _start () -> () + call usethis + end_function + + .functype usethis () -> () diff --git a/lld/test/wasm/ctor-gc.test b/lld/test/wasm/ctor-gc.test new file mode 100644 --- /dev/null +++ b/lld/test/wasm/ctor-gc.test @@ -0,0 +1,14 @@ +; Verify that constructors from a .o file which is initially depends on but +; doesn't ultimately contribute to the final link are not included. +; +; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/ctor-ctor.s -o %t.ctor.o +; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/ctor-lib.s -o %t.lib.o +; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/ctor-start.s -o %t.start.o +; RUN: rm -f %t.ctor.a +; RUN: rm -f %t.lib.a +; RUN: llvm-ar rcs %t.ctor.a %t.ctor.o +; RUN: llvm-ar rcs %t.lib.a %t.lib.o +; RUN: wasm-ld %t.start.o %t.lib.a %t.ctor.a -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; CHECK-NOT: __wasm_call_ctors diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h --- a/lld/wasm/InputFiles.h +++ b/lld/wasm/InputFiles.h @@ -60,8 +60,12 @@ MutableArrayRef getMutableSymbols() { return symbols; } + void markLive() { live = true; } + bool isLive() const { return live; } + protected: - InputFile(Kind k, MemoryBufferRef m) : mb(m), fileKind(k) {} + InputFile(Kind k, MemoryBufferRef m) + : mb(m), fileKind(k), live(!config->gcSections) {} MemoryBufferRef mb; // List of all symbols referenced or defined by this file. @@ -69,6 +73,7 @@ private: const Kind fileKind; + bool live; }; // .a file (ar archive) @@ -92,6 +97,10 @@ explicit ObjFile(MemoryBufferRef m, StringRef archiveName) : InputFile(ObjectKind, m) { this->archiveName = std::string(archiveName); + + // If this isn't part of an archive, it's eagerly linked, so mark it live. + if (archiveName.empty()) + markLive(); } static bool classof(const InputFile *f) { return f->kind() == ObjectKind; } @@ -156,6 +165,10 @@ explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName) : InputFile(BitcodeKind, m) { this->archiveName = std::string(archiveName); + + // If this isn't part of an archive, it's eagerly linked, so mark it live. + if (archiveName.empty()) + markLive(); } static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; } diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp --- a/lld/wasm/MarkLive.cpp +++ b/lld/wasm/MarkLive.cpp @@ -75,30 +75,34 @@ if (Symbol *callDtors = WasmSym::callDtors) enqueue(callDtors); + // In Emscripten-style PIC, `__wasm_call_ctors` calls `__wasm_apply_relocs`. + if (config->isPic) + enqueue(WasmSym::applyRelocs); + + if (config->sharedMemory && !config->shared) + enqueue(WasmSym::initMemory); + + mark(); + // The ctor functions are all referenced by the synthetic callCtors // function. However, this function does not contain relocations so we // have to manually mark the ctors as live. for (const ObjFile *obj : symtab->objectFiles) { - const WasmLinkingData &l = obj->getWasmObj()->linkingData(); - for (const WasmInitFunc &f : l.InitFunctions) { - auto *initSym = obj->getFunctionSymbol(f.Symbol); - if (!initSym->isDiscarded()) - enqueue(initSym); + if (obj->isLive()) { + const WasmLinkingData &l = obj->getWasmObj()->linkingData(); + for (const WasmInitFunc &f : l.InitFunctions) { + auto *initSym = obj->getFunctionSymbol(f.Symbol); + if (!initSym->isDiscarded()) + enqueue(initSym); + } } } - // In Emscripten-style PIC, `__wasm_call_ctors` calls `__wasm_apply_relocs`. - if (config->isPic) - enqueue(WasmSym::applyRelocs); - // If we have any non-discarded init functions, mark `__wasm_call_ctors` as // live so that we assign it an index and call it. if (isCallCtorsLive()) enqueue(WasmSym::callCtors); - if (config->sharedMemory && !config->shared) - enqueue(WasmSym::initMemory); - mark(); } @@ -181,9 +185,11 @@ // it can call them. for (const ObjFile *file : symtab->objectFiles) { const WasmLinkingData &l = file->getWasmObj()->linkingData(); - for (const WasmInitFunc &f : l.InitFunctions) - if (!file->getFunctionSymbol(f.Symbol)->isDiscarded()) + for (const WasmInitFunc &f : l.InitFunctions) { + auto *sym = file->getFunctionSymbol(f.Symbol); + if (!sym->isDiscarded() && sym->isLive()) return true; + } } return false; diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp --- a/lld/wasm/Symbols.cpp +++ b/lld/wasm/Symbols.cpp @@ -132,6 +132,8 @@ void Symbol::markLive() { assert(!isDiscarded()); + if (file != NULL) + file->markLive(); if (auto *g = dyn_cast(this)) g->global->live = true; if (auto *e = dyn_cast(this)) diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -1085,7 +1085,7 @@ for (const WasmInitFunc &f : l.InitFunctions) { FunctionSymbol *sym = file->getFunctionSymbol(f.Symbol); // comdat exclusions can cause init functions be discarded. - if (sym->isDiscarded()) + if (sym->isDiscarded() || !sym->isLive()) continue; assert(sym->isLive()); if (sym->signature->Params.size() != 0)