[lld] 53e3b81 - [lld][WebAssembly] Add support for handling table symbols
Andy Wingo via llvm-commits
llvm-commits at lists.llvm.org
Thu Jan 14 02:20:21 PST 2021
Author: Andy Wingo
Date: 2021-01-14T11:13:13+01:00
New Revision: 53e3b81faaf32a495189182e0e4d635cbe19c5dd
URL: https://github.com/llvm/llvm-project/commit/53e3b81faaf32a495189182e0e4d635cbe19c5dd
DIFF: https://github.com/llvm/llvm-project/commit/53e3b81faaf32a495189182e0e4d635cbe19c5dd.diff
LOG: [lld][WebAssembly] Add support for handling table symbols
This commit adds table symbol support in a partial way, while still
including some special cases for the __indirect_function_table symbol.
No change in tests.
Differential Revision: https://reviews.llvm.org/D94075
Added:
lld/wasm/InputTable.h
Modified:
lld/include/lld/Common/LLVM.h
lld/wasm/InputChunks.cpp
lld/wasm/InputFiles.cpp
lld/wasm/InputFiles.h
lld/wasm/MarkLive.cpp
lld/wasm/SymbolTable.cpp
lld/wasm/SymbolTable.h
lld/wasm/Symbols.cpp
lld/wasm/Symbols.h
lld/wasm/SyntheticSections.cpp
lld/wasm/SyntheticSections.h
lld/wasm/Writer.cpp
lld/wasm/WriterUtils.cpp
lld/wasm/WriterUtils.h
llvm/include/llvm/BinaryFormat/Wasm.h
llvm/include/llvm/Object/Wasm.h
llvm/lib/Object/WasmObjectFile.cpp
llvm/tools/llvm-readobj/WasmDumper.cpp
Removed:
################################################################################
diff --git a/lld/include/lld/Common/LLVM.h b/lld/include/lld/Common/LLVM.h
index 663944771aa9..f6eca27b02ff 100644
--- a/lld/include/lld/Common/LLVM.h
+++ b/lld/include/lld/Common/LLVM.h
@@ -49,8 +49,11 @@ struct WasmEventType;
struct WasmFunction;
struct WasmGlobal;
struct WasmGlobalType;
+struct WasmLimits;
struct WasmRelocation;
struct WasmSignature;
+struct WasmTable;
+struct WasmTableType;
} // namespace wasm
} // namespace llvm
@@ -88,8 +91,11 @@ using llvm::wasm::WasmEventType;
using llvm::wasm::WasmFunction;
using llvm::wasm::WasmGlobal;
using llvm::wasm::WasmGlobalType;
+using llvm::wasm::WasmLimits;
using llvm::wasm::WasmRelocation;
using llvm::wasm::WasmSignature;
+using llvm::wasm::WasmTable;
+using llvm::wasm::WasmTableType;
} // end namespace lld.
namespace std {
diff --git a/lld/wasm/InputChunks.cpp b/lld/wasm/InputChunks.cpp
index 52d19e6ddc10..d8c5f84c0487 100644
--- a/lld/wasm/InputChunks.cpp
+++ b/lld/wasm/InputChunks.cpp
@@ -69,6 +69,7 @@ void InputChunk::verifyRelocTargets() const {
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
+ case R_WASM_TABLE_NUMBER_LEB:
existingValue = decodeULEB128(loc, &bytesRead);
break;
case R_WASM_MEMORY_ADDR_LEB64:
@@ -152,6 +153,7 @@ void InputChunk::writeTo(uint8_t *buf) const {
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
+ case R_WASM_TABLE_NUMBER_LEB:
encodeULEB128(value, loc, 5);
break;
case R_WASM_MEMORY_ADDR_LEB64:
@@ -233,6 +235,7 @@ static unsigned writeCompressedReloc(uint8_t *buf, const WasmRelocation &rel,
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
case R_WASM_MEMORY_ADDR_LEB64:
+ case R_WASM_TABLE_NUMBER_LEB:
return encodeULEB128(value, buf);
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_TABLE_INDEX_SLEB64:
@@ -251,6 +254,7 @@ static unsigned getRelocWidthPadded(const WasmRelocation &rel) {
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_EVENT_INDEX_LEB:
case R_WASM_MEMORY_ADDR_LEB:
+ case R_WASM_TABLE_NUMBER_LEB:
case R_WASM_TABLE_INDEX_SLEB:
case R_WASM_MEMORY_ADDR_SLEB:
return 5;
diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp
index eb37ae548b80..1d0f016f325a 100644
--- a/lld/wasm/InputFiles.cpp
+++ b/lld/wasm/InputFiles.cpp
@@ -11,6 +11,7 @@
#include "InputChunks.h"
#include "InputEvent.h"
#include "InputGlobal.h"
+#include "InputTable.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
#include "lld/Common/ErrorHandler.h"
@@ -94,7 +95,8 @@ void ObjFile::dumpInfo() const {
"\n Symbols : " + Twine(symbols.size()) +
"\n Function Imports : " + Twine(wasmObj->getNumImportedFunctions()) +
"\n Global Imports : " + Twine(wasmObj->getNumImportedGlobals()) +
- "\n Event Imports : " + Twine(wasmObj->getNumImportedEvents()));
+ "\n Event Imports : " + Twine(wasmObj->getNumImportedEvents()) +
+ "\n Table Imports : " + Twine(wasmObj->getNumImportedTables()));
}
// Relocations contain either symbol or type indices. This function takes a
@@ -188,7 +190,8 @@ uint64_t ObjFile::calcExpectedValue(const WasmRelocation &reloc) const {
case R_WASM_FUNCTION_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_LEB:
case R_WASM_GLOBAL_INDEX_I32:
- case R_WASM_EVENT_INDEX_LEB: {
+ case R_WASM_EVENT_INDEX_LEB:
+ case R_WASM_TABLE_NUMBER_LEB: {
const WasmSymbol &sym = wasmObj->syms()[reloc.Index];
return sym.Info.ElementIndex;
}
@@ -270,6 +273,8 @@ uint64_t ObjFile::calcNewValue(const WasmRelocation &reloc, uint64_t tombstone)
}
case R_WASM_SECTION_OFFSET_I32:
return getSectionSymbol(reloc.Index)->section->outputOffset + reloc.Addend;
+ case R_WASM_TABLE_NUMBER_LEB:
+ return getTableSymbol(reloc.Index)->getTableNumber();
default:
llvm_unreachable("unknown relocation type");
}
@@ -405,6 +410,10 @@ void ObjFile::parse(bool ignoreComdats) {
}
setRelocs(functions, codeSection);
+ // Populate `Tables`.
+ for (const WasmTable &t : wasmObj->tables())
+ tables.emplace_back(make<InputTable>(t, this));
+
// Populate `Globals`.
for (const WasmGlobal &g : wasmObj->globals())
globals.emplace_back(make<InputGlobal>(g, this));
@@ -449,6 +458,10 @@ EventSymbol *ObjFile::getEventSymbol(uint32_t index) const {
return cast<EventSymbol>(symbols[index]);
}
+TableSymbol *ObjFile::getTableSymbol(uint32_t index) const {
+ return cast<TableSymbol>(symbols[index]);
+}
+
SectionSymbol *ObjFile::getSectionSymbol(uint32_t index) const {
return cast<SectionSymbol>(symbols[index]);
}
@@ -504,6 +517,13 @@ Symbol *ObjFile::createDefined(const WasmSymbol &sym) {
return make<DefinedEvent>(name, flags, this, event);
return symtab->addDefinedEvent(name, flags, this, event);
}
+ case WASM_SYMBOL_TYPE_TABLE: {
+ InputTable *table =
+ tables[sym.Info.ElementIndex - wasmObj->getNumImportedTables()];
+ if (sym.isBindingLocal())
+ return make<DefinedTable>(name, flags, this, table);
+ return symtab->addDefinedTable(name, flags, this, table);
+ }
}
llvm_unreachable("unknown symbol kind");
}
@@ -533,6 +553,14 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &sym, bool isCalledDirectly) {
return symtab->addUndefinedGlobal(name, sym.Info.ImportName,
sym.Info.ImportModule, flags, this,
sym.GlobalType);
+ case WASM_SYMBOL_TYPE_TABLE:
+ if (sym.isBindingLocal())
+ return make<UndefinedTable>(name, sym.Info.ImportName,
+ sym.Info.ImportModule, flags, this,
+ sym.TableType);
+ return symtab->addUndefinedTable(name, sym.Info.ImportName,
+ sym.Info.ImportModule, flags, this,
+ sym.TableType);
case WASM_SYMBOL_TYPE_SECTION:
llvm_unreachable("section symbols cannot be undefined");
}
diff --git a/lld/wasm/InputFiles.h b/lld/wasm/InputFiles.h
index 18b4f8de9bb5..4243a4447a92 100644
--- a/lld/wasm/InputFiles.h
+++ b/lld/wasm/InputFiles.h
@@ -32,6 +32,7 @@ class InputFunction;
class InputSegment;
class InputGlobal;
class InputEvent;
+class InputTable;
class InputSection;
// If --reproduce option is given, all input files are written
@@ -139,6 +140,7 @@ class ObjFile : public InputFile {
std::vector<InputFunction *> functions;
std::vector<InputGlobal *> globals;
std::vector<InputEvent *> events;
+ std::vector<InputTable *> tables;
std::vector<InputSection *> customSections;
llvm::DenseMap<uint32_t, InputSection *> customSectionsByIndex;
@@ -148,6 +150,7 @@ class ObjFile : public InputFile {
GlobalSymbol *getGlobalSymbol(uint32_t index) const;
SectionSymbol *getSectionSymbol(uint32_t index) const;
EventSymbol *getEventSymbol(uint32_t index) const;
+ TableSymbol *getTableSymbol(uint32_t index) const;
private:
Symbol *createDefined(const WasmSymbol &sym);
diff --git a/lld/wasm/InputTable.h b/lld/wasm/InputTable.h
new file mode 100644
index 000000000000..066975dacee2
--- /dev/null
+++ b/lld/wasm/InputTable.h
@@ -0,0 +1,60 @@
+//===- InputTable.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLD_WASM_INPUT_TABLE_H
+#define LLD_WASM_INPUT_TABLE_H
+
+#include "Config.h"
+#include "InputFiles.h"
+#include "WriterUtils.h"
+#include "lld/Common/ErrorHandler.h"
+#include "llvm/Object/Wasm.h"
+
+namespace lld {
+namespace wasm {
+
+// Represents a single Wasm Table within an input file. These are combined to
+// form the final TABLES section.
+class InputTable {
+public:
+ InputTable(const WasmTable &t, ObjFile *f)
+ : file(f), table(t), live(!config->gcSections) {}
+
+ StringRef getName() const { return table.SymbolName; }
+ const WasmTableType &getType() const { return table.Type; }
+
+ // Somewhat confusingly, we generally use the term "table index" to refer to
+ // the offset of a function in the well-known indirect function table. We
+ // refer to
diff erent tables instead by "table numbers".
+ uint32_t getTableNumber() const { return tableNumber.getValue(); }
+ bool hasTableNumber() const { return tableNumber.hasValue(); }
+ void setTableNumber(uint32_t n) {
+ assert(!hasTableNumber());
+ tableNumber = n;
+ }
+
+ void setLimits(const WasmLimits &limits) { table.Type.Limits = limits; }
+
+ ObjFile *file;
+ WasmTable table;
+
+ bool live = false;
+
+protected:
+ llvm::Optional<uint32_t> tableNumber;
+};
+
+} // namespace wasm
+
+inline std::string toString(const wasm::InputTable *t) {
+ return (toString(t->file) + ":(" + t->getName() + ")").str();
+}
+
+} // namespace lld
+
+#endif // LLD_WASM_INPUT_TABLE_H
diff --git a/lld/wasm/MarkLive.cpp b/lld/wasm/MarkLive.cpp
index 63c12545d554..c47e0953bfaa 100644
--- a/lld/wasm/MarkLive.cpp
+++ b/lld/wasm/MarkLive.cpp
@@ -23,6 +23,7 @@
#include "InputChunks.h"
#include "InputEvent.h"
#include "InputGlobal.h"
+#include "InputTable.h"
#include "SymbolTable.h"
#include "Symbols.h"
@@ -166,6 +167,9 @@ void markLive() {
for (InputEvent *e : obj->events)
if (!e->live)
message("removing unused section " + toString(e));
+ for (InputTable *t : obj->tables)
+ if (!t->live)
+ message("removing unused section " + toString(t));
}
for (InputChunk *c : symtab->syntheticFunctions)
if (!c->live)
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp
index d8a070c3c2f2..c5af5cafa8bd 100644
--- a/lld/wasm/SymbolTable.cpp
+++ b/lld/wasm/SymbolTable.cpp
@@ -11,6 +11,7 @@
#include "InputChunks.h"
#include "InputEvent.h"
#include "InputGlobal.h"
+#include "InputTable.h"
#include "WriterUtils.h"
#include "lld/Common/ErrorHandler.h"
#include "lld/Common/Memory.h"
@@ -191,6 +192,22 @@ static void checkEventType(const Symbol *existing, const InputFile *file,
toString(*newSig) + " in " + toString(file));
}
+static void checkTableType(const Symbol *existing, const InputFile *file,
+ const WasmTableType *newType) {
+ if (!isa<TableSymbol>(existing)) {
+ reportTypeError(existing, file, WASM_SYMBOL_TYPE_TABLE);
+ return;
+ }
+
+ const WasmTableType *oldType = cast<TableSymbol>(existing)->getTableType();
+ if (newType->ElemType != oldType->ElemType) {
+ error("Table type mismatch: " + existing->getName() + "\n>>> defined as " +
+ toString(*oldType) + " in " + toString(existing->getFile()) +
+ "\n>>> defined as " + toString(*newType) + " in " + toString(file));
+ }
+ // FIXME: No assertions currently on the limits.
+}
+
static void checkDataType(const Symbol *existing, const InputFile *file) {
if (!isa<DataSymbol>(existing))
reportTypeError(existing, file, WASM_SYMBOL_TYPE_DATA);
@@ -410,6 +427,30 @@ Symbol *SymbolTable::addDefinedEvent(StringRef name, uint32_t flags,
return s;
}
+Symbol *SymbolTable::addDefinedTable(StringRef name, uint32_t flags,
+ InputFile *file, InputTable *table) {
+ LLVM_DEBUG(dbgs() << "addDefinedTable:" << name << "\n");
+
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+
+ auto replaceSym = [&]() {
+ replaceSymbol<DefinedTable>(s, name, flags, file, table);
+ };
+
+ if (wasInserted || s->isLazy()) {
+ replaceSym();
+ return s;
+ }
+
+ checkTableType(s, file, &table->getType());
+
+ if (shouldReplace(s, file, flags))
+ replaceSym();
+ return s;
+}
+
// This function get called when an undefined symbol is added, and there is
// already an existing one in the symbols table. In this case we check that
// custom 'import-module' and 'import-field' symbol attributes agree.
@@ -553,6 +594,30 @@ Symbol *SymbolTable::addUndefinedGlobal(StringRef name,
return s;
}
+Symbol *SymbolTable::addUndefinedTable(StringRef name,
+ Optional<StringRef> importName,
+ Optional<StringRef> importModule,
+ uint32_t flags, InputFile *file,
+ const WasmTableType *type) {
+ LLVM_DEBUG(dbgs() << "addUndefinedTable: " << name << "\n");
+ assert(flags & WASM_SYMBOL_UNDEFINED);
+
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(name, file);
+ if (s->traced)
+ printTraceSymbolUndefined(name, file);
+
+ if (wasInserted)
+ replaceSymbol<UndefinedTable>(s, name, importName, importModule, flags,
+ file, type);
+ else if (auto *lazy = dyn_cast<LazySymbol>(s))
+ lazy->fetch();
+ else if (s->isDefined())
+ checkTableType(s, file, type);
+ return s;
+}
+
void SymbolTable::addLazy(ArchiveFile *file, const Archive::Symbol *sym) {
LLVM_DEBUG(dbgs() << "addLazy: " << sym->getName() << "\n");
StringRef name = sym->getName();
diff --git a/lld/wasm/SymbolTable.h b/lld/wasm/SymbolTable.h
index d3a937a7a473..921a6edaa516 100644
--- a/lld/wasm/SymbolTable.h
+++ b/lld/wasm/SymbolTable.h
@@ -60,6 +60,8 @@ class SymbolTable {
InputGlobal *g);
Symbol *addDefinedEvent(StringRef name, uint32_t flags, InputFile *file,
InputEvent *e);
+ Symbol *addDefinedTable(StringRef name, uint32_t flags, InputFile *file,
+ InputTable *t);
Symbol *addUndefinedFunction(StringRef name,
llvm::Optional<StringRef> importName,
@@ -73,6 +75,11 @@ class SymbolTable {
llvm::Optional<StringRef> importModule,
uint32_t flags, InputFile *file,
const WasmGlobalType *type);
+ Symbol *addUndefinedTable(StringRef name,
+ llvm::Optional<StringRef> importName,
+ llvm::Optional<StringRef> importModule,
+ uint32_t flags, InputFile *file,
+ const WasmTableType *type);
void addLazy(ArchiveFile *f, const llvm::object::Archive::Symbol *sym);
diff --git a/lld/wasm/Symbols.cpp b/lld/wasm/Symbols.cpp
index aa3b6be8a9b8..a403a47dcdd5 100644
--- a/lld/wasm/Symbols.cpp
+++ b/lld/wasm/Symbols.cpp
@@ -12,9 +12,11 @@
#include "InputEvent.h"
#include "InputFiles.h"
#include "InputGlobal.h"
+#include "InputTable.h"
#include "OutputSections.h"
#include "OutputSegment.h"
#include "lld/Common/ErrorHandler.h"
+#include "lld/Common/Memory.h"
#include "lld/Common/Strings.h"
#define DEBUG_TYPE "lld"
@@ -46,6 +48,8 @@ std::string toString(wasm::Symbol::Kind kind) {
return "DefinedData";
case wasm::Symbol::DefinedGlobalKind:
return "DefinedGlobal";
+ case wasm::Symbol::DefinedTableKind:
+ return "DefinedTable";
case wasm::Symbol::DefinedEventKind:
return "DefinedEvent";
case wasm::Symbol::UndefinedFunctionKind:
@@ -54,6 +58,8 @@ std::string toString(wasm::Symbol::Kind kind) {
return "UndefinedData";
case wasm::Symbol::UndefinedGlobalKind:
return "UndefinedGlobal";
+ case wasm::Symbol::UndefinedTableKind:
+ return "UndefinedTable";
case wasm::Symbol::LazyKind:
return "LazyKind";
case wasm::Symbol::SectionKind:
@@ -95,6 +101,8 @@ WasmSymbolType Symbol::getWasmType() const {
return WASM_SYMBOL_TYPE_GLOBAL;
if (isa<EventSymbol>(this))
return WASM_SYMBOL_TYPE_EVENT;
+ if (isa<TableSymbol>(this))
+ return WASM_SYMBOL_TYPE_TABLE;
if (isa<SectionSymbol>(this) || isa<OutputSectionSymbol>(this))
return WASM_SYMBOL_TYPE_SECTION;
llvm_unreachable("invalid symbol kind");
@@ -130,6 +138,8 @@ bool Symbol::isLive() const {
return g->global->live;
if (auto *e = dyn_cast<DefinedEvent>(this))
return e->event->live;
+ if (auto *t = dyn_cast<DefinedTable>(this))
+ return t->table->live;
if (InputChunk *c = getChunk())
return c->live;
return referenced;
@@ -143,6 +153,8 @@ void Symbol::markLive() {
g->global->live = true;
if (auto *e = dyn_cast<DefinedEvent>(this))
e->event->live = true;
+ if (auto *t = dyn_cast<DefinedTable>(this))
+ t->table->live = true;
if (InputChunk *c = getChunk())
c->live = true;
referenced = true;
@@ -339,6 +351,39 @@ DefinedEvent::DefinedEvent(StringRef name, uint32_t flags, InputFile *file,
event ? &event->signature : nullptr),
event(event) {}
+void TableSymbol::setLimits(const WasmLimits &limits) {
+ if (auto *t = dyn_cast<DefinedTable>(this))
+ t->table->setLimits(limits);
+ auto *newType = make<WasmTableType>(*tableType);
+ newType->Limits = limits;
+ tableType = newType;
+}
+
+uint32_t TableSymbol::getTableNumber() const {
+ if (const auto *t = dyn_cast<DefinedTable>(this))
+ return t->table->getTableNumber();
+ assert(tableNumber != INVALID_INDEX);
+ return tableNumber;
+}
+
+void TableSymbol::setTableNumber(uint32_t number) {
+ LLVM_DEBUG(dbgs() << "setTableNumber " << name << " -> " << number << "\n");
+ assert(tableNumber == INVALID_INDEX);
+ tableNumber = number;
+}
+
+bool TableSymbol::hasTableNumber() const {
+ if (const auto *t = dyn_cast<DefinedTable>(this))
+ return t->table->hasTableNumber();
+ return tableNumber != INVALID_INDEX;
+}
+
+DefinedTable::DefinedTable(StringRef name, uint32_t flags, InputFile *file,
+ InputTable *table)
+ : TableSymbol(name, DefinedTableKind, flags, file,
+ table ? &table->getType() : nullptr),
+ table(table) {}
+
const OutputSectionSymbol *SectionSymbol::getOutputSectionSymbol() const {
assert(section->outputSec && section->outputSec->sectionSym);
return section->outputSec->sectionSym;
diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h
index 4fa1a834db37..8434f82539b9 100644
--- a/lld/wasm/Symbols.h
+++ b/lld/wasm/Symbols.h
@@ -35,6 +35,7 @@ class InputFunction;
class InputGlobal;
class InputEvent;
class InputSection;
+class InputTable;
class OutputSection;
#define INVALID_INDEX UINT32_MAX
@@ -47,11 +48,13 @@ class Symbol {
DefinedDataKind,
DefinedGlobalKind,
DefinedEventKind,
+ DefinedTableKind,
SectionKind,
OutputSectionKind,
UndefinedFunctionKind,
UndefinedDataKind,
UndefinedGlobalKind,
+ UndefinedTableKind,
LazyKind,
};
@@ -61,7 +64,9 @@ class Symbol {
bool isUndefined() const {
return symbolKind == UndefinedFunctionKind ||
- symbolKind == UndefinedDataKind || symbolKind == UndefinedGlobalKind;
+ symbolKind == UndefinedDataKind ||
+ symbolKind == UndefinedGlobalKind ||
+ symbolKind == UndefinedTableKind;
}
bool isLazy() const { return symbolKind == LazyKind; }
@@ -359,6 +364,55 @@ class UndefinedGlobal : public GlobalSymbol {
llvm::Optional<StringRef> importModule;
};
+class TableSymbol : public Symbol {
+public:
+ static bool classof(const Symbol *s) {
+ return s->kind() == DefinedTableKind || s->kind() == UndefinedTableKind;
+ }
+
+ const WasmTableType *getTableType() const { return tableType; }
+ void setLimits(const WasmLimits &limits);
+
+ // Get/set the table number
+ uint32_t getTableNumber() const;
+ void setTableNumber(uint32_t number);
+ bool hasTableNumber() const;
+
+protected:
+ TableSymbol(StringRef name, Kind k, uint32_t flags, InputFile *f,
+ const WasmTableType *type)
+ : Symbol(name, k, flags, f), tableType(type) {}
+
+ const WasmTableType *tableType;
+ uint32_t tableNumber = INVALID_INDEX;
+};
+
+class DefinedTable : public TableSymbol {
+public:
+ DefinedTable(StringRef name, uint32_t flags, InputFile *file,
+ InputTable *table);
+
+ static bool classof(const Symbol *s) { return s->kind() == DefinedTableKind; }
+
+ InputTable *table;
+};
+
+class UndefinedTable : public TableSymbol {
+public:
+ UndefinedTable(StringRef name, llvm::Optional<StringRef> importName,
+ llvm::Optional<StringRef> importModule, uint32_t flags,
+ InputFile *file, const WasmTableType *type)
+ : TableSymbol(name, UndefinedTableKind, flags, file, type),
+ importName(importName), importModule(importModule) {}
+
+ static bool classof(const Symbol *s) {
+ return s->kind() == UndefinedTableKind;
+ }
+
+ llvm::Optional<StringRef> importName;
+ llvm::Optional<StringRef> importModule;
+};
+
// Wasm events are features that suspend the current execution and transfer the
// control flow to a corresponding handler. Currently the only supported event
// kind is exceptions.
@@ -524,11 +578,13 @@ union SymbolUnion {
alignas(DefinedData) char b[sizeof(DefinedData)];
alignas(DefinedGlobal) char c[sizeof(DefinedGlobal)];
alignas(DefinedEvent) char d[sizeof(DefinedEvent)];
- alignas(LazySymbol) char e[sizeof(LazySymbol)];
- alignas(UndefinedFunction) char f[sizeof(UndefinedFunction)];
- alignas(UndefinedData) char g[sizeof(UndefinedData)];
- alignas(UndefinedGlobal) char h[sizeof(UndefinedGlobal)];
- alignas(SectionSymbol) char i[sizeof(SectionSymbol)];
+ alignas(DefinedTable) char e[sizeof(DefinedTable)];
+ alignas(LazySymbol) char f[sizeof(LazySymbol)];
+ alignas(UndefinedFunction) char g[sizeof(UndefinedFunction)];
+ alignas(UndefinedData) char h[sizeof(UndefinedData)];
+ alignas(UndefinedGlobal) char i[sizeof(UndefinedGlobal)];
+ alignas(UndefinedTable) char j[sizeof(UndefinedTable)];
+ alignas(SectionSymbol) char k[sizeof(SectionSymbol)];
};
// It is important to keep the size of SymbolUnion small for performance and
diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp
index 768a265b3d09..967c2e240924 100644
--- a/lld/wasm/SyntheticSections.cpp
+++ b/lld/wasm/SyntheticSections.cpp
@@ -15,6 +15,7 @@
#include "InputChunks.h"
#include "InputEvent.h"
#include "InputGlobal.h"
+#include "InputTable.h"
#include "OutputSegment.h"
#include "SymbolTable.h"
#include "llvm/Support/Path.h"
@@ -91,6 +92,13 @@ void TypeSection::writeBody() {
writeSig(bodyOutputStream, *sig);
}
+ImportSection::ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {
+ // FIXME: Remove when we treat __indirect_function_table as any other symbol.
+ if (config->importTable) {
+ numImportedTables++;
+ }
+}
+
uint32_t ImportSection::getNumImports() const {
assert(isSealed);
uint32_t numImports = importedSymbols.size() + gotSymbols.size();
@@ -117,8 +125,10 @@ void ImportSection::addImport(Symbol *sym) {
f->setFunctionIndex(numImportedFunctions++);
else if (auto *g = dyn_cast<GlobalSymbol>(sym))
g->setGlobalIndex(numImportedGlobals++);
+ else if (auto *e = dyn_cast<EventSymbol>(sym))
+ e->setEventIndex(numImportedEvents++);
else
- cast<EventSymbol>(sym)->setEventIndex(numImportedEvents++);
+ cast<TableSymbol>(sym)->setTableNumber(numImportedTables++);
}
void ImportSection::writeBody() {
@@ -163,6 +173,9 @@ void ImportSection::writeBody() {
} else if (auto *g = dyn_cast<UndefinedGlobal>(sym)) {
import.Field = g->importName ? *g->importName : sym->getName();
import.Module = g->importModule ? *g->importModule : defaultModule;
+ } else if (auto *t = dyn_cast<UndefinedTable>(sym)) {
+ import.Field = t->importName ? *t->importName : sym->getName();
+ import.Module = t->importModule ? *t->importModule : defaultModule;
} else {
import.Field = sym->getName();
import.Module = defaultModule;
@@ -174,11 +187,14 @@ void ImportSection::writeBody() {
} else if (auto *globalSym = dyn_cast<GlobalSymbol>(sym)) {
import.Kind = WASM_EXTERNAL_GLOBAL;
import.Global = *globalSym->getGlobalType();
- } else {
- auto *eventSym = cast<EventSymbol>(sym);
+ } else if (auto *eventSym = dyn_cast<EventSymbol>(sym)) {
import.Kind = WASM_EXTERNAL_EVENT;
import.Event.Attribute = eventSym->getEventType()->Attribute;
import.Event.SigIndex = out.typeSec->lookupType(*eventSym->signature);
+ } else {
+ auto *tableSym = cast<TableSymbol>(sym);
+ import.Kind = WASM_EXTERNAL_TABLE;
+ import.Table = *tableSym->getTableType();
}
writeImport(os, import);
}
@@ -214,16 +230,37 @@ void FunctionSection::addFunction(InputFunction *func) {
}
void TableSection::writeBody() {
- uint32_t tableSize = config->tableBase + out.elemSec->numEntries();
+ bool hasIndirectFunctionTable = !config->importTable;
+
+ uint32_t tableCount = inputTables.size();
+ if (hasIndirectFunctionTable)
+ tableCount++;
raw_ostream &os = bodyOutputStream;
- writeUleb128(os, 1, "table count");
- WasmLimits limits;
- if (config->growableTable)
- limits = {0, tableSize, 0};
- else
- limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
- writeTableType(os, WasmTableType{WASM_TYPE_FUNCREF, limits});
+
+ writeUleb128(os, tableCount, "table count");
+
+ if (hasIndirectFunctionTable) {
+ uint32_t tableSize = config->tableBase + out.elemSec->numEntries();
+ WasmLimits limits;
+ if (config->growableTable)
+ limits = {0, tableSize, 0};
+ else
+ limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
+ writeTableType(os, WasmTableType{WASM_TYPE_FUNCREF, limits});
+ }
+
+ for (const InputTable *table : inputTables)
+ writeTableType(os, table->getType());
+}
+
+void TableSection::addTable(InputTable *table) {
+ if (!table->live)
+ return;
+ uint32_t tableNumber =
+ out.importSec->getNumImportedTables() + inputTables.size();
+ inputTables.push_back(table);
+ table->setTableNumber(tableNumber);
}
void MemorySection::writeBody() {
@@ -458,6 +495,10 @@ void LinkingSection::writeBody() {
writeUleb128(sub.os, e->getEventIndex(), "index");
if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
writeStr(sub.os, sym->getName(), "sym name");
+ } else if (auto *t = dyn_cast<TableSymbol>(sym)) {
+ writeUleb128(sub.os, t->getTableNumber(), "table number");
+ if (sym->isDefined() || (flags & WASM_SYMBOL_EXPLICIT_NAME) != 0)
+ writeStr(sub.os, sym->getName(), "sym name");
} else if (isa<DataSymbol>(sym)) {
writeStr(sub.os, sym->getName(), "sym name");
if (auto *dataSym = dyn_cast<DefinedData>(sym)) {
diff --git a/lld/wasm/SyntheticSections.h b/lld/wasm/SyntheticSections.h
index b4d833d212a6..7af931b4adc7 100644
--- a/lld/wasm/SyntheticSections.h
+++ b/lld/wasm/SyntheticSections.h
@@ -98,7 +98,7 @@ class TypeSection : public SyntheticSection {
class ImportSection : public SyntheticSection {
public:
- ImportSection() : SyntheticSection(llvm::wasm::WASM_SEC_IMPORT) {}
+ ImportSection();
bool isNeeded() const override { return getNumImports() > 0; }
void writeBody() override;
void addImport(Symbol *sym);
@@ -117,6 +117,10 @@ class ImportSection : public SyntheticSection {
assert(isSealed);
return numImportedEvents;
}
+ uint32_t getNumImportedTables() const {
+ assert(isSealed);
+ return numImportedTables;
+ }
std::vector<const Symbol *> importedSymbols;
std::vector<const Symbol *> gotSymbols;
@@ -126,6 +130,7 @@ class ImportSection : public SyntheticSection {
unsigned numImportedGlobals = 0;
unsigned numImportedFunctions = 0;
unsigned numImportedEvents = 0;
+ unsigned numImportedTables = 0;
};
class FunctionSection : public SyntheticSection {
@@ -146,18 +151,19 @@ class TableSection : public SyntheticSection {
TableSection() : SyntheticSection(llvm::wasm::WASM_SEC_TABLE) {}
bool isNeeded() const override {
- // Always output a table section (or table import), even if there are no
- // indirect calls. There are two reasons for this:
- // 1. For executables it is useful to have an empty table slot at 0
- // which can be filled with a null function call handler.
- // 2. If we don't do this, any program that contains a call_indirect but
- // no address-taken function will fail at validation time since it is
- // a validation error to include a call_indirect instruction if there
- // is not table.
- return !config->importTable;
+ // The linker currently always writes an indirect function table to the
+ // output, so unless the indirect function table is imported, we need a
+ // table section. FIXME: Treat __indirect_function_table as a normal
+ // symbol, and only residualize a table section as needed.
+ if (!config->importTable)
+ return true;
+ return inputTables.size() > 0;
}
void writeBody() override;
+ void addTable(InputTable *table);
+
+ std::vector<InputTable *> inputTables;
};
class MemorySection : public SyntheticSection {
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp
index 710404943df2..99cf48c08c52 100644
--- a/lld/wasm/Writer.cpp
+++ b/lld/wasm/Writer.cpp
@@ -11,6 +11,7 @@
#include "InputChunks.h"
#include "InputEvent.h"
#include "InputGlobal.h"
+#include "InputTable.h"
#include "MapFile.h"
#include "OutputSections.h"
#include "OutputSegment.h"
@@ -574,6 +575,8 @@ static bool shouldImport(Symbol *sym) {
return g->importName.hasValue();
if (auto *f = dyn_cast<UndefinedFunction>(sym))
return f->importName.hasValue();
+ if (auto *t = dyn_cast<UndefinedTable>(sym))
+ return t->importName.hasValue();
return false;
}
@@ -636,10 +639,12 @@ void Writer::calculateExports() {
export_ = {name, WASM_EXTERNAL_GLOBAL, g->getGlobalIndex()};
} else if (auto *e = dyn_cast<DefinedEvent>(sym)) {
export_ = {name, WASM_EXTERNAL_EVENT, e->getEventIndex()};
- } else {
- auto *d = cast<DefinedData>(sym);
+ } else if (auto *d = dyn_cast<DefinedData>(sym)) {
out.globalSec->dataAddressGlobals.push_back(d);
export_ = {name, WASM_EXTERNAL_GLOBAL, globalIndex++};
+ } else {
+ auto *t = cast<DefinedTable>(sym);
+ export_ = {name, WASM_EXTERNAL_TABLE, t->getTableNumber()};
}
LLVM_DEBUG(dbgs() << "Export: " << name << "\n");
@@ -781,6 +786,12 @@ void Writer::assignIndexes() {
out.eventSec->addEvent(event);
}
+ for (ObjFile *file : symtab->objectFiles) {
+ LLVM_DEBUG(dbgs() << "Tables: " << file->getName() << "\n");
+ for (InputTable *table : file->tables)
+ out.tableSec->addTable(table);
+ }
+
out.globalSec->assignIndexes();
}
@@ -1385,10 +1396,12 @@ void Writer::run() {
log("Defined Functions: " + Twine(out.functionSec->inputFunctions.size()));
log("Defined Globals : " + Twine(out.globalSec->numGlobals()));
log("Defined Events : " + Twine(out.eventSec->inputEvents.size()));
+ log("Defined Tables : " + Twine(out.tableSec->inputTables.size()));
log("Function Imports : " +
Twine(out.importSec->getNumImportedFunctions()));
log("Global Imports : " + Twine(out.importSec->getNumImportedGlobals()));
log("Event Imports : " + Twine(out.importSec->getNumImportedEvents()));
+ log("Table Imports : " + Twine(out.importSec->getNumImportedTables()));
for (ObjFile *file : symtab->objectFiles)
file->dumpInfo();
}
diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp
index b53637f27f27..80845882b936 100644
--- a/lld/wasm/WriterUtils.cpp
+++ b/lld/wasm/WriterUtils.cpp
@@ -64,6 +64,21 @@ std::string toString(const WasmEventType &type) {
return "unknown";
}
+static std::string toString(const llvm::wasm::WasmLimits &limits) {
+ std::string ret;
+ ret += "flags=0x" + std::to_string(limits.Flags);
+ ret += "; initial=" + std::to_string(limits.Initial);
+ if (limits.Flags & WASM_LIMITS_FLAG_HAS_MAX)
+ ret += "; max=" + std::to_string(limits.Maximum);
+ return ret;
+}
+
+std::string toString(const WasmTableType &type) {
+ SmallString<128> ret("");
+ return "type=" + toString(static_cast<ValType>(type.ElemType)) +
+ "; limits=[" + toString(type.Limits) + "]";
+}
+
namespace wasm {
void debugWrite(uint64_t offset, const Twine &msg) {
LLVM_DEBUG(dbgs() << format(" | %08lld: ", offset) << msg << "\n");
@@ -202,7 +217,7 @@ void writeEvent(raw_ostream &os, const WasmEvent &event) {
}
void writeTableType(raw_ostream &os, const WasmTableType &type) {
- writeU8(os, WASM_TYPE_FUNCREF, "table type");
+ writeValueType(os, ValType(type.ElemType), "table type");
writeLimits(os, type.Limits);
}
diff --git a/lld/wasm/WriterUtils.h b/lld/wasm/WriterUtils.h
index 5854c8c3eb19..7b0b78c976d2 100644
--- a/lld/wasm/WriterUtils.h
+++ b/lld/wasm/WriterUtils.h
@@ -69,6 +69,7 @@ std::string toString(llvm::wasm::ValType type);
std::string toString(const llvm::wasm::WasmSignature &sig);
std::string toString(const llvm::wasm::WasmGlobalType &type);
std::string toString(const llvm::wasm::WasmEventType &type);
+std::string toString(const llvm::wasm::WasmTableType &type);
} // namespace lld
diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h
index 71022792841c..bdef959fafdc 100644
--- a/llvm/include/llvm/BinaryFormat/Wasm.h
+++ b/llvm/include/llvm/BinaryFormat/Wasm.h
@@ -192,8 +192,8 @@ struct WasmSymbolInfo {
// For symbols to be exported from the final module
Optional<StringRef> ExportName;
union {
- // For function or global symbols, the index in function or global index
- // space.
+ // For function, table, or global symbols, the index in function, table, or
+ // global index space.
uint32_t ElementIndex;
// For a data symbols, the address of the data relative to segment.
WasmDataReference DataRef;
diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h
index 089046d7d42f..f7cd2e622ae3 100644
--- a/llvm/include/llvm/Object/Wasm.h
+++ b/llvm/include/llvm/Object/Wasm.h
@@ -35,7 +35,8 @@ namespace object {
class WasmSymbol {
public:
WasmSymbol(const wasm::WasmSymbolInfo &Info,
- const wasm::WasmGlobalType *GlobalType, const uint8_t TableType,
+ const wasm::WasmGlobalType *GlobalType,
+ const wasm::WasmTableType *TableType,
const wasm::WasmEventType *EventType,
const wasm::WasmSignature *Signature)
: Info(Info), GlobalType(GlobalType), TableType(TableType),
@@ -43,7 +44,7 @@ class WasmSymbol {
const wasm::WasmSymbolInfo &Info;
const wasm::WasmGlobalType *GlobalType;
- const uint8_t TableType;
+ const wasm::WasmTableType *TableType;
const wasm::WasmEventType *EventType;
const wasm::WasmSignature *Signature;
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index c9b13e4afb4e..dac16d225bf5 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -527,7 +527,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
wasm::WasmSymbolInfo Info;
const wasm::WasmSignature *Signature = nullptr;
const wasm::WasmGlobalType *GlobalType = nullptr;
- uint8_t TableType = 0;
+ const wasm::WasmTableType *TableType = nullptr;
const wasm::WasmEventType *EventType = nullptr;
Info.Kind = readUint8(Ctx);
@@ -609,7 +609,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
Info.Name = readString(Ctx);
unsigned TableIndex = Info.ElementIndex - NumImportedTables;
wasm::WasmTable &Table = Tables[TableIndex];
- TableType = Table.Type.ElemType;
+ TableType = &Table.Type;
if (Table.SymbolName.empty())
Table.SymbolName = Info.Name;
} else {
@@ -620,8 +620,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
} else {
Info.Name = Import.Field;
}
- TableType = Import.Table.ElemType;
- // FIXME: Parse limits here too.
+ TableType = &Import.Table;
if (!Import.Module.empty()) {
Info.ImportModule = Import.Module;
}
diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp
index 488c6faa26b8..fb7134d20a85 100644
--- a/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -24,7 +24,7 @@ static const EnumEntry<unsigned> WasmSymbolTypes[] = {
#define ENUM_ENTRY(X) \
{ #X, wasm::WASM_SYMBOL_TYPE_##X }
ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL),
- ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT),
+ ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT), ENUM_ENTRY(TABLE),
#undef ENUM_ENTRY
};
More information about the llvm-commits
mailing list