Index: test/wasm/shared.ll =================================================================== --- test/wasm/shared.ll +++ test/wasm/shared.ll @@ -1,10 +1,11 @@ -; RUN: llc -O0 -filetype=obj %s -o %t.o +; RUN: llc -relocation-model=pic -filetype=obj %s -o %t.o ; RUN: wasm-ld -shared -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s target triple = "wasm32-unknown-unknown" @data = hidden global i32 2, align 4 +@data_external = external global i32 @indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 @indirect_func_external = local_unnamed_addr global void ()* @func_external, align 4 @@ -13,18 +14,22 @@ ; To ensure we use __stack_pointer %ptr = alloca i32 %0 = load i32, i32* @data, align 4 - ; TODO(sbc): Re-enable once the codegen supports generating the correct - ; relocation type when referencing external data in shared libraries. - ; %1 = load i32, i32* @data_external, align 4 %1 = load i32 ()*, i32 ()** @indirect_func, align 4 call i32 %1() ret i32 %0 } -declare void @func_external() +define default i32* @get_data_address() { +entry: + ret i32* @data_external +} -@data_external = external global i32 +define default i8* @get_func_address() { +entry: + ret i8* bitcast (void ()* @func_external to i8*) +} +declare void @func_external() ; check for dylink section at start @@ -43,6 +48,11 @@ ; CHECK: - Type: IMPORT ; CHECK-NEXT: Imports: ; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Memory: +; CHECK-NEXT: Initial: 0x0000000 +; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: @@ -64,15 +74,21 @@ ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: false -; XCHECK-NEXT: - Module: env -; XCHECK-NEXT: Field: data_external -; XCHECK-NEXT: Kind: GLOBAL -; XCHECK-NEXT: GlobalType: I32 -; XCHECK-NEXT: GlobalMutable: true ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: func_external ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 +; CHECK-NEXT: - Module: GOT.mem +; CHECK-NEXT: Field: data_external +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I32 +; CHECK-NEXT: GlobalMutable: true +; CHECK-NEXT: - Module: GOT.func +; CHECK-NEXT: Field: func_external +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I32 +; CHECK-NEXT: GlobalMutable: true +; CHECK-NEXT: - Type: FUNCTION ; check for elem segment initialized with __table_base global as offset Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -519,6 +519,7 @@ } if (Config->Shared) { + Config->ImportMemory = true; Config->ExportDynamic = true; Config->AllowUndefined = true; } Index: wasm/InputChunks.cpp =================================================================== --- wasm/InputChunks.cpp +++ wasm/InputChunks.cpp @@ -74,11 +74,14 @@ if (BytesRead && BytesRead != 5) warn("expected LEB at relocation site be 5-byte padded"); - uint32_t ExpectedValue = File->calcExpectedValue(Rel); - if (ExpectedValue != ExistingValue) - warn("unexpected existing value for " + reloctTypeToString(Rel.Type) + - ": existing=" + Twine(ExistingValue) + - " expected=" + Twine(ExpectedValue)); + + if (Rel.Type != R_WASM_GLOBAL_INDEX_LEB) { + uint32_t ExpectedValue = File->calcExpectedValue(Rel); + if (ExpectedValue != ExistingValue) + warn("unexpected existing value for " + reloctTypeToString(Rel.Type) + + ": existing=" + Twine(ExistingValue) + + " expected=" + Twine(ExpectedValue)); + } } } Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -152,9 +152,12 @@ return TypeMap[Reloc.Index]; case R_WASM_FUNCTION_INDEX_LEB: return getFunctionSymbol(Reloc.Index)->getFunctionIndex(); - case R_WASM_GLOBAL_INDEX_LEB: - return getGlobalSymbol(Reloc.Index)->getGlobalIndex(); - case R_WASM_EVENT_INDEX_LEB: + case R_WASM_GLOBAL_INDEX_LEB: { + const Symbol* Sym = Symbols[Reloc.Index]; + if (auto GS = dyn_cast(Sym)) + return GS->getGlobalIndex(); + return Sym->getGOTIndex(); + } case R_WASM_EVENT_INDEX_LEB: return getEventSymbol(Reloc.Index)->getEventIndex(); case R_WASM_FUNCTION_OFFSET_I32: if (auto *Sym = dyn_cast(getFunctionSymbol(Reloc.Index))) { Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -113,6 +113,16 @@ const WasmSignature* getSignature() const; + bool isInGOT() const { return GOTIndex != INVALID_INDEX; } + + uint32_t getGOTIndex() const { + assert(GOTIndex != INVALID_INDEX); + return GOTIndex; + } + + void setGOTIndex(uint32_t Index); + bool hasGOTIndex() const { return GOTIndex != INVALID_INDEX; } + protected: Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) : IsUsedInRegularObj(false), ForceExport(false), Traced(false), @@ -124,6 +134,7 @@ uint32_t Flags; InputFile *File; uint32_t OutputSymbolIndex = INVALID_INDEX; + uint32_t GOTIndex = INVALID_INDEX; bool Referenced; }; @@ -249,21 +260,6 @@ 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 { Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -93,6 +93,12 @@ OutputSymbolIndex = Index; } +void Symbol::setGOTIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "setGOTIndex " << Name << " -> " << Index << "\n"); + assert(GOTIndex == INVALID_INDEX); + GOTIndex = Index; +} + bool Symbol::isWeak() const { return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; } Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -118,6 +118,7 @@ std::vector Types; DenseMap TypeIndices; std::vector ImportedSymbols; + std::vector GOTSymbols; unsigned NumImportedFunctions = 0; unsigned NumImportedGlobals = 0; unsigned NumImportedEvents = 0; @@ -147,7 +148,7 @@ } // anonymous namespace void Writer::createImportSection() { - uint32_t NumImports = ImportedSymbols.size(); + uint32_t NumImports = ImportedSymbols.size() + GOTSymbols.size(); if (Config->ImportMemory) ++NumImports; if (Config->ImportTable) @@ -204,9 +205,6 @@ 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(); @@ -218,6 +216,18 @@ } writeImport(OS, Import); } + + for (const Symbol *Sym : GOTSymbols) { + WasmImport Import; + Import.Kind = WASM_EXTERNAL_GLOBAL; + Import.Global = {WASM_TYPE_I32, true}; + if (isa(Sym)) + Import.Module = "GOT.mem"; + else + Import.Module = "GOT.func"; + Import.Field = Sym->getName(); + writeImport(OS, Import); + } } void Writer::createTypeSection() { @@ -957,9 +967,9 @@ 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)) + // We don't generate imports for data symbols. They however can be imported + // as GOT entries. + if (isa(Sym)) continue; LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n"); @@ -968,8 +978,6 @@ 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++); } @@ -1145,6 +1153,13 @@ DataSym->getName()); break; } + case R_WASM_GLOBAL_INDEX_LEB: { + auto* Sym = File->getSymbols()[Reloc.Index]; + if (!isa(Sym) && !Sym->isInGOT()) { + Sym->setGOTIndex(NumImportedGlobals++); + GOTSymbols.push_back(Sym); + } + } } } }