diff --git a/lld/test/wasm/shared.ll b/lld/test/wasm/shared.ll --- a/lld/test/wasm/shared.ll +++ b/lld/test/wasm/shared.ll @@ -5,18 +5,18 @@ target triple = "wasm32-unknown-unknown" @data = hidden global i32 2, align 4 -@indirect_func = local_unnamed_addr global void ()* @foo, align 4 +@indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 @indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4 -define default void @foo() { +define default i32 @foo() { entry: ; To ensure we use __stack_pointer %ptr = alloca i32 %0 = load i32, i32* @data, align 4 %1 = load i32, i32* @data_external, align 4 - %2 = load void ()*, void ()** @indirect_func, align 4 - call void %2() - ret void + %2 = load i32 ()*, i32 ()** @indirect_func, align 4 + call i32 %2() + ret i32 %1 } declare void @func_external() @@ -60,6 +60,15 @@ ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: false +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: data_external +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I32 +; CHECK-NEXT: GlobalMutable: true +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: func_external +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 1 ; check for elem segment initialized with __table_base global as offset diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -331,6 +331,7 @@ "--thinlto-cache-policy: invalid cache policy"); Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); errorHandler().Verbose = Args.hasArg(OPT_verbose); + LLVM_DEBUG(errorHandler().Verbose = true); ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0); diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -249,6 +249,23 @@ static bool classof(const Symbol *S) { return S->kind() == UndefinedDataKind; } + + // Undefined data symbols are imported as wasm globals so also have a global + // index. + uint32_t getGlobalIndex() const { + assert(GlobalIndex != INVALID_INDEX); + return GlobalIndex; + } + void setGlobalIndex(uint32_t Index) { + assert(GlobalIndex == INVALID_INDEX); + GlobalIndex = Index; + } + bool hasGlobalIndex() const { + return GlobalIndex != INVALID_INDEX; + } + +protected: + uint32_t GlobalIndex = INVALID_INDEX; }; class GlobalSymbol : public Symbol { diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -198,6 +198,9 @@ if (auto *FunctionSym = dyn_cast(Sym)) { Import.Kind = WASM_EXTERNAL_FUNCTION; Import.SigIndex = lookupType(*FunctionSym->Signature); + } else if (auto *DataSym = dyn_cast(Sym)) { + Import.Kind = WASM_EXTERNAL_GLOBAL; + Import.Global = {WASM_TYPE_I32, true}; } else if (auto *GlobalSym = dyn_cast(Sym)) { Import.Kind = WASM_EXTERNAL_GLOBAL; Import.Global = *GlobalSym->getGlobalType(); @@ -851,14 +854,16 @@ for (Symbol *Sym : Symtab->getSymbols()) { if (!Sym->isUndefined()) continue; - if (isa(Sym)) - continue; if (Sym->isWeak() && !Config->Relocatable) continue; if (!Sym->isLive()) continue; if (!Sym->IsUsedInRegularObj) continue; + // In relocatable output we don't generate imports for data symbols. + // These live only in the symbol table. + if (Config->Relocatable && isa(Sym)) + continue; LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n"); ImportedSymbols.emplace_back(Sym); @@ -866,6 +871,8 @@ F->setFunctionIndex(NumImportedFunctions++); else if (auto *G = dyn_cast(Sym)) G->setGlobalIndex(NumImportedGlobals++); + else if (auto *D = dyn_cast(Sym)) + D->setGlobalIndex(NumImportedGlobals++); else cast(Sym)->setEventIndex(NumImportedEvents++); }