Index: lld/trunk/test/wasm/pic-static.ll =================================================================== --- lld/trunk/test/wasm/pic-static.ll +++ lld/trunk/test/wasm/pic-static.ll @@ -3,12 +3,13 @@ ; fixed values. ; RUN: llc -relocation-model=pic -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o ; RUN: llc -relocation-model=pic -filetype=obj %s -o %t.o -; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o +; RUN: wasm-ld --allow-undefined --export-all -o %t.wasm %t.o %t.ret32.o ; RUN: obj2yaml %t.wasm | FileCheck %s target triple = "wasm32-unknown-emscripten" declare i32 @ret32(float) +declare i32 @missing_function(float) @global_float = global float 1.0 @hidden_float = hidden global float 2.0 @@ -18,6 +19,10 @@ ret i32 (float)* @ret32; } +define i32 (float)* @getaddr_missing_function() { + ret i32 (float)* @missing_function; +} + define i32 ()* @getaddr_hidden() { ret i32 ()* @hidden_func; } @@ -60,10 +65,18 @@ ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 + +; GOT.func.missing_function +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 2 ; __table_base -; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: @@ -71,7 +84,7 @@ ; CHECK-NEXT: Value: 1 ; GOT.mem.global_float -; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: @@ -79,7 +92,7 @@ ; CHECK-NEXT: Value: 1024 ; GOT.mem.ret32_ptr -; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: @@ -87,7 +100,7 @@ ; CHECK-NEXT: Value: 1032 ; __memory_base -; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: - Index: 6 ; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: Index: lld/trunk/wasm/InputFiles.cpp =================================================================== --- lld/trunk/wasm/InputFiles.cpp +++ lld/trunk/wasm/InputFiles.cpp @@ -165,10 +165,15 @@ switch (reloc.Type) { case R_WASM_TABLE_INDEX_I32: case R_WASM_TABLE_INDEX_SLEB: - case R_WASM_TABLE_INDEX_REL_SLEB: + case R_WASM_TABLE_INDEX_REL_SLEB: { if (!getFunctionSymbol(reloc.Index)->hasTableIndex()) return 0; - return getFunctionSymbol(reloc.Index)->getTableIndex(); + uint32_t index = getFunctionSymbol(reloc.Index)->getTableIndex(); + if (reloc.Type == R_WASM_TABLE_INDEX_REL_SLEB) + index -= config->tableBase; + return index; + + } case R_WASM_MEMORY_ADDR_SLEB: case R_WASM_MEMORY_ADDR_I32: case R_WASM_MEMORY_ADDR_LEB: Index: lld/trunk/wasm/Relocations.cpp =================================================================== --- lld/trunk/wasm/Relocations.cpp +++ lld/trunk/wasm/Relocations.cpp @@ -51,7 +51,7 @@ if (config->isPic) out.importSec->addGOTEntry(sym); else - out.globalSec->addDummyGOTEntry(sym); + out.globalSec->addStaticGOTEntry(sym); } void lld::wasm::scanRelocations(InputChunk *chunk) { Index: lld/trunk/wasm/Symbols.h =================================================================== --- lld/trunk/wasm/Symbols.h +++ lld/trunk/wasm/Symbols.h @@ -113,8 +113,6 @@ const WasmSignature* getSignature() const; - bool isInGOT() const { return gotIndex != INVALID_INDEX; } - uint32_t getGOTIndex() const { assert(gotIndex != INVALID_INDEX); return gotIndex; @@ -126,8 +124,9 @@ protected: Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f) : name(name), file(f), flags(flags), symbolKind(k), - referenced(!config->gcSections), isUsedInRegularObj(false), - forceExport(false), canInline(false), traced(false) {} + referenced(!config->gcSections), requiresGOT(false), + isUsedInRegularObj(false), forceExport(false), canInline(false), + traced(false) {} StringRef name; InputFile *file; @@ -139,6 +138,10 @@ public: bool referenced : 1; + // True for data symbols that needs a dummy GOT entry. Used for static + // linking of GOT accesses. + bool requiresGOT : 1; + // True if the symbol was used for linking and thus need to be added to the // output file's symbol table. This is true for all symbols except for // unreferenced DSO symbols, lazy (archive) symbols, and bitcode symbols that Index: lld/trunk/wasm/SyntheticSections.h =================================================================== --- lld/trunk/wasm/SyntheticSections.h +++ lld/trunk/wasm/SyntheticSections.h @@ -175,17 +175,23 @@ public: GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {} uint32_t numGlobals() const { - return inputGlobals.size() + definedFakeGlobals.size() + gotSymbols.size(); + assert(isSealed); + return inputGlobals.size() + dataAddressGlobals.size() + + staticGotSymbols.size(); } bool isNeeded() const override { return numGlobals() > 0; } void assignIndexes() override; void writeBody() override; void addGlobal(InputGlobal *global); - void addDummyGOTEntry(Symbol *sym); + void addDataAddressGlobal(DefinedData *global); + void addStaticGOTEntry(Symbol *sym); + + std::vector dataAddressGlobals; - std::vector definedFakeGlobals; +protected: + bool isSealed = false; std::vector inputGlobals; - std::vector gotSymbols; + std::vector staticGotSymbols; }; // The event section contains a list of declared wasm events associated with the Index: lld/trunk/wasm/SyntheticSections.cpp =================================================================== --- lld/trunk/wasm/SyntheticSections.cpp +++ lld/trunk/wasm/SyntheticSections.cpp @@ -103,9 +103,9 @@ void ImportSection::addGOTEntry(Symbol *sym) { assert(!isSealed); - LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n"); if (sym->hasGOTIndex()) return; + LLVM_DEBUG(dbgs() << "addGOTEntry: " << toString(*sym) << "\n"); sym->setGOTIndex(numImportedGlobals++); gotSymbols.push_back(sym); } @@ -244,15 +244,21 @@ uint32_t globalIndex = out.importSec->getNumImportedGlobals(); for (InputGlobal *g : inputGlobals) g->setGlobalIndex(globalIndex++); - for (Symbol *sym : gotSymbols) + for (Symbol *sym : staticGotSymbols) sym->setGOTIndex(globalIndex++); + isSealed = true; } -void GlobalSection::addDummyGOTEntry(Symbol *sym) { - LLVM_DEBUG(dbgs() << "addDummyGOTEntry: " << toString(*sym) << "\n"); - if (sym->hasGOTIndex()) +void GlobalSection::addStaticGOTEntry(Symbol *sym) { + assert(!isSealed); + if (sym->requiresGOT) return; - gotSymbols.push_back(sym); + LLVM_DEBUG(dbgs() << "addStaticGOTEntry: " << sym->getName() << " " + << toString(sym->kind()) << "\n"); + sym->requiresGOT = true; + if (auto *F = dyn_cast(sym)) + out.elemSec->addEntry(F); + staticGotSymbols.push_back(sym); } void GlobalSection::writeBody() { @@ -261,26 +267,27 @@ writeUleb128(os, numGlobals(), "global count"); for (InputGlobal *g : inputGlobals) writeGlobal(os, g->global); - for (const DefinedData *sym : definedFakeGlobals) { + for (const Symbol *sym : staticGotSymbols) { WasmGlobal global; global.Type = {WASM_TYPE_I32, false}; global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - global.InitExpr.Value.Int32 = sym->getVirtualAddress(); + if (auto *d = dyn_cast(sym)) + global.InitExpr.Value.Int32 = d->getVirtualAddress(); + else if (auto *f = cast(sym)) + global.InitExpr.Value.Int32 = f->getTableIndex(); writeGlobal(os, global); } - for (const Symbol *sym : gotSymbols) { + for (const DefinedData *sym : dataAddressGlobals) { WasmGlobal global; global.Type = {WASM_TYPE_I32, false}; global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; - if (auto *d = dyn_cast(sym)) - global.InitExpr.Value.Int32 = d->getVirtualAddress(); - else if (auto *f = cast(sym)) - global.InitExpr.Value.Int32 = f->getTableIndex(); + global.InitExpr.Value.Int32 = sym->getVirtualAddress(); writeGlobal(os, global); } } void GlobalSection::addGlobal(InputGlobal *global) { + assert(!isSealed); if (!global->live) return; inputGlobals.push_back(global); Index: lld/trunk/wasm/Writer.cpp =================================================================== --- lld/trunk/wasm/Writer.cpp +++ lld/trunk/wasm/Writer.cpp @@ -509,8 +509,8 @@ out.exportSec->exports.push_back( WasmExport{functionTableName, WASM_EXTERNAL_TABLE, 0}); - unsigned fakeGlobalIndex = out.importSec->getNumImportedGlobals() + - out.globalSec->inputGlobals.size(); + unsigned globalIndex = + out.importSec->getNumImportedGlobals() + out.globalSec->numGlobals(); for (Symbol *sym : symtab->getSymbols()) { if (!sym->isExported()) @@ -536,8 +536,8 @@ export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()}; } else { auto *d = cast(sym); - out.globalSec->definedFakeGlobals.emplace_back(d); - export_ = {name, WASM_EXTERNAL_GLOBAL, fakeGlobalIndex++}; + out.globalSec->dataAddressGlobals.push_back(d); + export_ = {name, WASM_EXTERNAL_GLOBAL, globalIndex++}; } LLVM_DEBUG(dbgs() << "Export: " << name << "\n"); @@ -1035,7 +1035,7 @@ if (errorHandler().verbose) { log("Defined Functions: " + Twine(out.functionSec->inputFunctions.size())); - log("Defined Globals : " + Twine(out.globalSec->inputGlobals.size())); + log("Defined Globals : " + Twine(out.globalSec->numGlobals())); log("Defined Events : " + Twine(out.eventSec->inputEvents.size())); log("Function Imports : " + Twine(out.importSec->getNumImportedFunctions()));