Index: test/wasm/alias.ll =================================================================== --- test/wasm/alias.ll +++ test/wasm/alias.ll @@ -58,6 +58,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/call-indirect.ll =================================================================== --- test/wasm/call-indirect.ll +++ test/wasm/call-indirect.ll @@ -99,6 +99,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/comdats.ll =================================================================== --- test/wasm/comdats.ll +++ test/wasm/comdats.ll @@ -45,6 +45,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/cxx-mangling.ll =================================================================== --- test/wasm/cxx-mangling.ll +++ test/wasm/cxx-mangling.ll @@ -26,6 +26,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/entry.ll =================================================================== --- test/wasm/entry.ll +++ test/wasm/entry.ll @@ -17,6 +17,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 @@ -38,6 +41,9 @@ ; CHECK-CTOR-NEXT: - Name: memory ; CHECK-CTOR-NEXT: Kind: MEMORY ; CHECK-CTOR-NEXT: Index: 0 +; CHECK-CTOR-NEXT: - Name: __indirect_function_table +; CHECK-CTOR-NEXT: Kind: TABLE +; CHECK-CTOR-NEXT: Index: 0 ; CHECK-CTOR-NEXT: - Name: __wasm_call_ctors ; CHECK-CTOR-NEXT: Kind: FUNCTION ; CHECK-CTOR-NEXT: Index: 0 Index: test/wasm/export.ll =================================================================== --- test/wasm/export.ll +++ test/wasm/export.ll @@ -22,6 +22,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/import-table.test =================================================================== --- /dev/null +++ test/wasm/import-table.test @@ -0,0 +1,18 @@ +# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o +# RUN: wasm-ld --check-signatures --import-table -o %t.wasm %t.start.o +# RUN: obj2yaml %t.wasm | FileCheck %s + +# Verify the --import-table flag creates a table import + +# CHECK: - Type: IMPORT +# CHECK-NEXT: Imports: +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __indirect_function_table +# CHECK-NEXT: Kind: TABLE +# CHECK-NEXT: Table: +# CHECK-NEXT: ElemType: ANYFUNC +# CHECK-NEXT: Limits: +# CHECK-NEXT: Flags: [ HAS_MAX ] +# CHECK-NEXT: Initial: 0x00000001 +# CHECK-NEXT: Maximum: 0x00000001 + Index: test/wasm/load-undefined.test =================================================================== --- test/wasm/load-undefined.test +++ test/wasm/load-undefined.test @@ -13,6 +13,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/local-symbols.ll =================================================================== --- test/wasm/local-symbols.ll +++ test/wasm/local-symbols.ll @@ -74,6 +74,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/locals-duplicate.test =================================================================== --- test/wasm/locals-duplicate.test +++ test/wasm/locals-duplicate.test @@ -65,6 +65,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/undefined-weak-call.ll =================================================================== --- test/wasm/undefined-weak-call.ll +++ test/wasm/undefined-weak-call.ll @@ -75,6 +75,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/visibility-hidden.ll =================================================================== --- test/wasm/visibility-hidden.ll +++ test/wasm/visibility-hidden.ll @@ -36,6 +36,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/weak-alias-overide.ll =================================================================== --- test/wasm/weak-alias-overide.ll +++ test/wasm/weak-alias-overide.ll @@ -68,6 +68,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/weak-alias.ll =================================================================== --- test/wasm/weak-alias.ll +++ test/wasm/weak-alias.ll @@ -65,6 +65,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/weak-symbols.ll =================================================================== --- test/wasm/weak-symbols.ll +++ test/wasm/weak-symbols.ll @@ -71,6 +71,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: test/wasm/weak-undefined.ll =================================================================== --- test/wasm/weak-undefined.ll +++ test/wasm/weak-undefined.ll @@ -75,6 +75,9 @@ ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: wasm/Config.h =================================================================== --- wasm/Config.h +++ wasm/Config.h @@ -23,6 +23,7 @@ bool Demangle; bool GcSections; bool ImportMemory; + bool ImportTable; bool PrintGcSections; bool Relocatable; bool StripAll; Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -287,6 +287,7 @@ Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start"); Config->ImportMemory = Args.hasArg(OPT_import_memory); + Config->ImportTable = Args.hasArg(OPT_import_table); Config->OutputFile = Args.getLastArgValue(OPT_o); Config->Relocatable = Args.hasArg(OPT_relocatable); Config->GcSections = Index: wasm/Options.td =================================================================== --- wasm/Options.td +++ wasm/Options.td @@ -109,6 +109,9 @@ def import_memory: F<"import-memory">, HelpText<"Import memory from the environment">; +def import_table: F<"import-table">, + HelpText<"Import function table from the environment">; + def initial_memory: J<"initial-memory=">, HelpText<"Initial size of the linear memory">; Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -38,6 +38,7 @@ static constexpr int kStackAlignment = 16; static constexpr int kInitialTableOffset = 1; +static constexpr const char *kFunctionTableName = "__indirect_function_table"; namespace { @@ -157,6 +158,8 @@ uint32_t NumImports = ImportedSymbols.size(); if (Config->ImportMemory) ++NumImports; + if (Config->ImportTable) + ++NumImports; if (NumImports == 0) return; @@ -176,6 +179,17 @@ writeImport(OS, Import); } + if (Config->ImportTable) { + uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size(); + WasmImport Import; + Import.Module = "env"; + Import.Field = kFunctionTableName; + Import.Kind = WASM_EXTERNAL_TABLE; + Import.Table.ElemType = WASM_TYPE_ANYFUNC; + Import.Table.Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize}; + writeImport(OS, Import); + } + for (const Symbol *Sym : ImportedSymbols) { WasmImport Import; Import.Module = "env"; @@ -245,8 +259,11 @@ } void Writer::createTableSection() { - // Always output a table section, even if there are no indirect calls. - // There are two reasons for this: + if (Config->ImportTable) + return; + + // 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 @@ -259,16 +276,16 @@ raw_ostream &OS = Section->getStream(); writeUleb128(OS, 1, "table count"); - writeU8(OS, WASM_TYPE_ANYFUNC, "table type"); - writeUleb128(OS, WASM_LIMITS_FLAG_HAS_MAX, "table flags"); - writeUleb128(OS, TableSize, "table initial size"); - writeUleb128(OS, TableSize, "table max size"); + WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize}; + writeTableType(OS, WasmTable{WASM_TYPE_ANYFUNC, Limits}); } void Writer::createExportSection() { bool ExportMemory = !Config->Relocatable && !Config->ImportMemory; + bool ExportTable = !Config->Relocatable && !Config->ImportTable; - uint32_t NumExports = (ExportMemory ? 1 : 0) + ExportedSymbols.size(); + uint32_t NumExports = + (ExportMemory ? 1 : 0) + (ExportTable ? 1 : 0) + ExportedSymbols.size(); if (!NumExports) return; @@ -279,6 +296,8 @@ if (ExportMemory) writeExport(OS, {"memory", WASM_EXTERNAL_MEMORY, 0}); + if (ExportTable) + writeExport(OS, {kFunctionTableName, WASM_EXTERNAL_TABLE, 0}); unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size(); Index: wasm/WriterUtils.h =================================================================== --- wasm/WriterUtils.h +++ wasm/WriterUtils.h @@ -69,6 +69,8 @@ void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global); +void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type); + void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import); void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export); Index: wasm/WriterUtils.cpp =================================================================== --- wasm/WriterUtils.cpp +++ wasm/WriterUtils.cpp @@ -126,6 +126,11 @@ writeInitExpr(OS, Global.InitExpr); } +void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) { + writeU8(OS, WASM_TYPE_ANYFUNC, "table type"); + writeLimits(OS, Type.Limits); +} + void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { writeStr(OS, Import.Module, "import module name"); writeStr(OS, Import.Field, "import field name"); @@ -140,6 +145,9 @@ case WASM_EXTERNAL_MEMORY: writeLimits(OS, Import.Memory); break; + case WASM_EXTERNAL_TABLE: + writeTableType(OS, Import.Table); + break; default: fatal("unsupported import type: " + Twine(Import.Kind)); } @@ -158,6 +166,9 @@ case WASM_EXTERNAL_MEMORY: writeUleb128(OS, Export.Index, "memory index"); break; + case WASM_EXTERNAL_TABLE: + writeUleb128(OS, Export.Index, "table index"); + break; default: fatal("unsupported export type: " + Twine(Export.Kind)); }