diff --git a/lld/test/wasm/pic-static.ll b/lld/test/wasm/pic-static.ll --- a/lld/test/wasm/pic-static.ll +++ b/lld/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: diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp --- a/lld/wasm/InputFiles.cpp +++ b/lld/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: diff --git a/lld/wasm/Relocations.cpp b/lld/wasm/Relocations.cpp --- a/lld/wasm/Relocations.cpp +++ b/lld/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) { diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -109,8 +109,6 @@ const WasmSignature* getSignature() const; - bool isInGOT() const { return gotIndex != INVALID_INDEX; } - uint32_t getGOTIndex() const { assert(gotIndex != INVALID_INDEX); return gotIndex; @@ -122,8 +120,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; @@ -135,6 +134,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 diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h --- a/lld/wasm/SyntheticSections.h +++ b/lld/wasm/SyntheticSections.h @@ -175,17 +175,18 @@ public: GlobalSection() : SyntheticSection(llvm::wasm::WASM_SEC_GLOBAL) {} uint32_t numGlobals() const { - return inputGlobals.size() + definedFakeGlobals.size() + gotSymbols.size(); + return inputGlobals.size() + definedFakeGlobals.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 addStaticGOTEntry(Symbol *sym); std::vector definedFakeGlobals; std::vector inputGlobals; - std::vector gotSymbols; + std::vector staticGotSymbols; }; // The event section contains a list of declared wasm events associated with the diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/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); } @@ -240,15 +240,19 @@ uint32_t globalIndex = out.importSec->getNumImportedGlobals(); for (InputGlobal *g : inputGlobals) g->setGlobalIndex(globalIndex++); - for (Symbol *sym : gotSymbols) + for (Symbol *sym : staticGotSymbols) sym->setGOTIndex(globalIndex++); } -void GlobalSection::addDummyGOTEntry(Symbol *sym) { - LLVM_DEBUG(dbgs() << "addDummyGOTEntry: " << toString(*sym) << "\n"); - if (sym->hasGOTIndex()) +void GlobalSection::addStaticGOTEntry(Symbol *sym) { + 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() { @@ -257,21 +261,21 @@ 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 : definedFakeGlobals) { 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); } } diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -497,8 +497,7 @@ out.exportSec->exports.push_back( WasmExport{functionTableName, WASM_EXTERNAL_TABLE, 0}); - unsigned fakeGlobalIndex = out.importSec->getNumImportedGlobals() + - out.globalSec->inputGlobals.size(); + unsigned fakeGlobalIndex = out.globalSec->numGlobals(); for (Symbol *sym : symtab->getSymbols()) { if (!sym->isExported())