summaryrefslogtreecommitdiff
path: root/src/binary-writer.cc
diff options
context:
space:
mode:
authorAndy Wingo <wingo@igalia.com>2020-10-01 17:30:58 +0200
committerGitHub <noreply@github.com>2020-10-01 08:30:58 -0700
commitee87440dedb4335d5ca8ec25e86b36c27a5b3368 (patch)
tree522ec9766d5da42fd8b8ba6efa0c6e74fc370748 /src/binary-writer.cc
parentcd63243c5b3b2fa938f365edab30139f74549b51 (diff)
downloadwabt-ee87440dedb4335d5ca8ec25e86b36c27a5b3368.tar.gz
wabt-ee87440dedb4335d5ca8ec25e86b36c27a5b3368.tar.bz2
wabt-ee87440dedb4335d5ca8ec25e86b36c27a5b3368.zip
Add --relocatable support for tables (#1549) (#1549)
We add relocations for table numbers on each place where we reify a table number (call_indirect, table.get, table.set...), but only if reference types are enabled. Also, fix symbol table generation with unnamed definitions, to allow for relocating references to anonymous functions or tables. As tests, add variants of the relocations and symbol-tables dump tests, with and without all features enabled. Enabling reference types causes relocs to be emitted. We also add --details to the relocations dump tests, so that we can see the target symbols for the relocations.
Diffstat (limited to 'src/binary-writer.cc')
-rw-r--r--src/binary-writer.cc107
1 files changed, 85 insertions, 22 deletions
diff --git a/src/binary-writer.cc b/src/binary-writer.cc
index c628b108..b5732533 100644
--- a/src/binary-writer.cc
+++ b/src/binary-writer.cc
@@ -122,6 +122,10 @@ class Symbol {
static const SymbolType type = SymbolType::Event;
Index index;
};
+ struct Table {
+ static const SymbolType type = SymbolType::Table;
+ Index index;
+ };
private:
SymbolType type_;
@@ -133,6 +137,7 @@ class Symbol {
Global global_;
Section section_;
Event event_;
+ Table table_;
};
public:
@@ -146,6 +151,8 @@ class Symbol {
: type_(Section::type), name_(name), flags_(flags), section_(s) {}
Symbol(const string_view& name, uint8_t flags, const Event& e)
: type_(Event::type), name_(name), flags_(flags), event_(e) {}
+ Symbol(const string_view& name, uint8_t flags, const Table& t)
+ : type_(Table::type), name_(name), flags_(flags), table_(t) {}
SymbolType type() const { return type_; }
const string_view& name() const { return name_; }
@@ -168,6 +175,7 @@ class Symbol {
bool IsGlobal() const { return type() == Global::type; }
bool IsSection() const { return type() == Section::type; }
bool IsEvent() const { return type() == Event::type; }
+ bool IsTable() const { return type() == Table::type; }
const Function& AsFunction() const {
assert(IsFunction());
@@ -189,6 +197,10 @@ class Symbol {
assert(IsEvent());
return event_;
}
+ const Table& AsTable() const {
+ assert(IsTable());
+ return table_;
+ }
};
class SymbolTable {
@@ -197,6 +209,7 @@ class SymbolTable {
std::vector<Symbol> symbols_;
std::vector<Index> functions_;
+ std::vector<Index> tables_;
std::vector<Index> globals_;
std::set<string_view> seen_names_;
@@ -222,17 +235,17 @@ class SymbolTable {
// name fabricated by wabt.
name = string_view();
} else {
- // Functions defined in this module without a name don't go in the symbol
- // table.
if (name.empty()) {
- return Result::Ok;
+ // Definitions without a name are local.
+ flags |= uint8_t(SymbolBinding::Local);
+ flags |= uint8_t(SymbolVisibility::Hidden);
+ } else {
+ // Otherwise, strip the dollar off the name; a definition $foo is
+ // available for linking as "foo".
+ assert(name[0] == '$');
+ name.remove_prefix(1);
}
- // Otherwise, strip the dollar off the name; a function $foo is available
- // for linking as "foo".
- assert(name[0] == '$');
- name.remove_prefix(1);
-
if (exported) {
CHECK_RESULT(EnsureUnique(name));
flags |= uint8_t(SymbolVisibility::Hidden);
@@ -248,6 +261,13 @@ class SymbolTable {
return Result::Ok;
};
+ Index SymbolIndex(const std::vector<Index>& table, Index index) const {
+ // For well-formed modules, an index into (e.g.) functions_ will always be
+ // within bounds; the out-of-bounds case here is just to allow --relocatable
+ // to write known-invalid modules.
+ return index < table.size() ? table[index] : kInvalidIndex;
+ }
+
public:
SymbolTable() {}
@@ -276,8 +296,8 @@ class SymbolTable {
}
}
- // We currently only create symbol table entries for function and global
- // symbols.
+ // We currently only create symbol table entries for function, table, and
+ // global symbols.
for (size_t i = 0; i < module->funcs.size(); ++i) {
const Func* func = module->funcs[i];
bool imported = i < module->num_func_imports;
@@ -286,6 +306,14 @@ class SymbolTable {
Symbol::Function{Index(i)}));
}
+ for (size_t i = 0; i < module->tables.size(); ++i) {
+ const Table* table = module->tables[i];
+ bool imported = i < module->num_table_imports;
+ bool exported = exported_tables.count(i);
+ CHECK_RESULT(AddSymbol(&tables_, table->name, imported, exported,
+ Symbol::Table{Index(i)}));
+ }
+
for (size_t i = 0; i < module->globals.size(); ++i) {
const Global* global = module->globals[i];
bool imported = i < module->num_global_imports;
@@ -298,8 +326,15 @@ class SymbolTable {
}
const std::vector<Symbol>& symbols() const { return symbols_; }
- Index FunctionSymbolIndex(Index index) const { return functions_[index]; }
- Index GlobalSymbolIndex(Index index) const { return globals_[index]; }
+ Index FunctionSymbolIndex(Index index) const {
+ return SymbolIndex(functions_, index);
+ }
+ Index TableSymbolIndex(Index index) const {
+ return SymbolIndex(tables_, index);
+ }
+ Index GlobalSymbolIndex(Index index) const {
+ return SymbolIndex(globals_, index);
+ }
};
class BinaryWriter {
@@ -336,6 +371,7 @@ class BinaryWriter {
void WriteS32Leb128WithReloc(int32_t value,
const char* desc,
RelocType reloc_type);
+ void WriteTableNumberWithReloc(Index table_number, const char* desc);
template <typename T>
void WriteLoadStoreExpr(const Func* func, const Expr* expr, const char* desc);
void WriteExpr(const Func* func, const Expr* expr);
@@ -513,6 +549,8 @@ Index BinaryWriter::GetSymbolIndex(RelocType reloc_type, Index index) {
switch (reloc_type) {
case RelocType::FuncIndexLEB:
return symtab_.FunctionSymbolIndex(index);
+ case RelocType::TableNumberLEB:
+ return symtab_.TableSymbolIndex(index);
case RelocType::GlobalIndexLEB:
return symtab_.GlobalSymbolIndex(index);
case RelocType::TypeIndexLEB:
@@ -537,6 +575,12 @@ void BinaryWriter::AddReloc(RelocType reloc_type, Index index) {
// Add a new relocation to the curent reloc section
size_t offset = stream_->offset() - last_section_payload_offset_;
Index symbol_index = GetSymbolIndex(reloc_type, index);
+ if (symbol_index == kInvalidIndex) {
+ // The file is invalid, for example a reference to function 42 where only 10
+ // functions are defined. The user must have already passed --no-check, so
+ // no extra warning here is needed.
+ return;
+ }
current_reloc_section_->relocations.emplace_back(reloc_type, offset,
symbol_index);
}
@@ -563,6 +607,18 @@ void BinaryWriter::WriteS32Leb128WithReloc(int32_t value,
}
}
+void BinaryWriter::WriteTableNumberWithReloc(Index value,
+ const char* desc) {
+ // Unless reference types are enabled, all references to tables refer to table
+ // 0, so no relocs need be emitted when making relocatable binaries.
+ if (options_.relocatable && options_.features.reference_types_enabled()) {
+ AddReloc(RelocType::TableNumberLEB, value);
+ WriteFixedS32Leb128(stream_, value, desc);
+ } else {
+ WriteS32Leb128(stream_, value, desc);
+ }
+}
+
Index BinaryWriter::GetLocalIndex(const Func* func, const Var& var) {
// func can be nullptr when using local.get/local.set/local.tee in an
// init_expr.
@@ -674,7 +730,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
module_->GetTableIndex(cast<CallIndirectExpr>(expr)->table);
WriteOpcode(stream_, Opcode::CallIndirect);
WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB);
- WriteU32Leb128(stream_, table_index, "table index");
+ WriteTableNumberWithReloc(table_index, "table index");
break;
}
case ExprType::ReturnCallIndirect: {
@@ -684,7 +740,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
module_->GetTableIndex(cast<ReturnCallIndirectExpr>(expr)->table);
WriteOpcode(stream_, Opcode::ReturnCallIndirect);
WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB);
- WriteU32Leb128(stream_, table_index, "table index");
+ WriteTableNumberWithReloc(table_index, "table index");
break;
}
case ExprType::Compare:
@@ -815,8 +871,8 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
Index dst = module_->GetTableIndex(copy_expr->dst_table);
Index src = module_->GetTableIndex(copy_expr->src_table);
WriteOpcode(stream_, Opcode::TableCopy);
- WriteU32Leb128(stream_, dst, "table.copy dst_table");
- WriteU32Leb128(stream_, src, "table.copy src_table");
+ WriteTableNumberWithReloc(dst, "table.copy dst_table");
+ WriteTableNumberWithReloc(src, "table.copy src_table");
break;
}
case ExprType::ElemDrop: {
@@ -833,42 +889,42 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) {
module_->GetElemSegmentIndex(init_expr->segment_index);
WriteOpcode(stream_, Opcode::TableInit);
WriteU32Leb128(stream_, segment_index, "table.init segment");
- WriteU32Leb128(stream_, table_index, "table.init table");
+ WriteTableNumberWithReloc(table_index, "table.init table");
break;
}
case ExprType::TableGet: {
Index index =
module_->GetTableIndex(cast<TableGetExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableGet);
- WriteU32Leb128(stream_, index, "table.get table index");
+ WriteTableNumberWithReloc(index, "table.get table index");
break;
}
case ExprType::TableSet: {
Index index =
module_->GetTableIndex(cast<TableSetExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableSet);
- WriteU32Leb128(stream_, index, "table.set table index");
+ WriteTableNumberWithReloc(index, "table.set table index");
break;
}
case ExprType::TableGrow: {
Index index =
module_->GetTableIndex(cast<TableGrowExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableGrow);
- WriteU32Leb128(stream_, index, "table.grow table index");
+ WriteTableNumberWithReloc(index, "table.grow table index");
break;
}
case ExprType::TableSize: {
Index index =
module_->GetTableIndex(cast<TableSizeExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableSize);
- WriteU32Leb128(stream_, index, "table.size table index");
+ WriteTableNumberWithReloc(index, "table.size table index");
break;
}
case ExprType::TableFill: {
Index index =
module_->GetTableIndex(cast<TableFillExpr>(expr)->var);
WriteOpcode(stream_, Opcode::TableFill);
- WriteU32Leb128(stream_, index, "table.fill table index");
+ WriteTableNumberWithReloc(index, "table.fill table index");
break;
}
case ExprType::RefFunc: {
@@ -1042,6 +1098,7 @@ void BinaryWriter::WriteRelocSection(const RelocSection* reloc_section) {
case RelocType::GlobalIndexLEB:
case RelocType::EventIndexLEB:
case RelocType::TableIndexRelSLEB:
+ case RelocType::TableNumberLEB:
break;
default:
fprintf(stderr, "warning: unsupported relocation type: %s\n",
@@ -1094,6 +1151,12 @@ void BinaryWriter::WriteLinkingSection() {
WriteStr(stream_, sym.name(), "event name", PrintChars::Yes);
}
break;
+ case SymbolType::Table:
+ WriteU32Leb128(stream_, sym.AsTable().index, "table index");
+ if (sym.defined() || sym.explicit_name()) {
+ WriteStr(stream_, sym.name(), "table name", PrintChars::Yes);
+ }
+ break;
}
}
EndSubsection();