diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -96,6 +96,15 @@ StringRef getExportName() const { return ExportName.getValue(); } void setExportName(StringRef Name) { ExportName = Name; } + bool isFunctionTable() const { + return isTable() && hasTableType() && + getTableType() == wasm::ValType::FUNCREF; + } + void setFunctionTable() { + setType(wasm::WASM_SYMBOL_TYPE_TABLE); + setTableType(wasm::ValType::FUNCREF); + } + void setUsedInGOT() const { IsUsedInGOT = true; } bool isUsedInGOT() const { return IsUsedInGOT; } @@ -111,8 +120,9 @@ } void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; } - const wasm::ValType &getTableType() const { - assert(TableType.hasValue()); + bool hasTableType() const { return TableType.hasValue(); } + wasm::ValType getTableType() const { + assert(hasTableType()); return TableType.getValue(); } void setTableType(wasm::ValType TT) { TableType = TT; } diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -299,6 +299,7 @@ uint32_t DataSection = 0; uint32_t EventSection = 0; uint32_t GlobalSection = 0; + uint32_t TableSection = 0; }; class WasmSectionOrderChecker { diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -40,8 +40,8 @@ namespace { -// Went we ceate the indirect function table we start at 1, so that there is -// and emtpy slot at 0 and therefore calling a null function pointer will trap. +// When we create the indirect function table we start at 1, so that there is +// and empty slot at 0 and therefore calling a null function pointer will trap. static const uint32_t InitialTableOffset = 1; // For patching purposes, we need to remember where each section starts, both @@ -218,9 +218,7 @@ SmallVector DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; - // NumTableImports is initialized to 1 to account for the hardcoded import of - // __indirect_function_table - unsigned NumTableImports = 1; + unsigned NumTableImports = 0; unsigned NumEventImports = 0; uint32_t SectionCount = 0; @@ -270,7 +268,7 @@ SectionFunctions.clear(); NumFunctionImports = 0; NumGlobalImports = 0; - NumTableImports = 1; + NumTableImports = 0; MCObjectWriter::reset(); } @@ -497,6 +495,29 @@ SymA = cast(SectionSymbol); } + if (Type == wasm::R_WASM_TABLE_INDEX_REL_SLEB || + Type == wasm::R_WASM_TABLE_INDEX_SLEB || + Type == wasm::R_WASM_TABLE_INDEX_SLEB64 || + Type == wasm::R_WASM_TABLE_INDEX_I32 || + Type == wasm::R_WASM_TABLE_INDEX_I64) { + // TABLE_INDEX relocs implicitly use the default indirect function table. + auto TableName = "__indirect_function_table"; + MCSymbolWasm *Sym = cast_or_null(Ctx.lookupSymbol(TableName)); + if (Sym) { + if (!Sym->isFunctionTable()) + Ctx.reportError( + Fixup.getLoc(), + "symbol '__indirect_function_table' is not a function table"); + } else { + Sym = cast(Ctx.getOrCreateSymbol(TableName)); + Sym->setFunctionTable(); + // The default function table is synthesized by the linker. + Sym->setUndefined(); + } + Sym->setUsedInReloc(); + Asm.registerSymbol(*Sym); + } + // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be // against a named symbol. if (Type != wasm::R_WASM_TYPE_INDEX_LEB) { @@ -1201,16 +1222,6 @@ : wasm::WASM_LIMITS_FLAG_NONE; Imports.push_back(MemImport); - // For now, always emit the table section, since indirect calls are not - // valid without it. In the future, we could perhaps be more clever and omit - // it if there are no indirect calls. - wasm::WasmImport TableImport; - TableImport.Module = "env"; - TableImport.Field = "__indirect_function_table"; - TableImport.Kind = wasm::WASM_EXTERNAL_TABLE; - TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF; - Imports.push_back(TableImport); - // Populate SignatureIndices, and Imports and WasmIndices for undefined // symbols. This must be done before populating WasmIndices for defined // symbols. @@ -1269,6 +1280,23 @@ Imports.push_back(Import); assert(WasmIndices.count(&WS) == 0); WasmIndices[&WS] = NumEventImports++; + } else if (WS.isTable()) { + if (WS.isWeak()) + report_fatal_error("undefined table symbol cannot be weak"); + + wasm::WasmImport Import; + Import.Module = WS.getImportModule(); + Import.Field = WS.getImportName(); + Import.Kind = wasm::WASM_EXTERNAL_TABLE; + wasm::ValType ElemType = WS.getTableType(); + Import.Table.ElemType = uint8_t(ElemType); + // FIXME: Extend table type to include limits? For now we don't specify + // a min or max which does not place any restrictions on the size of the + // imported table. + Import.Table.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; + Imports.push_back(Import); + assert(WasmIndices.count(&WS) == 0); + WasmIndices[&WS] = NumTableImports++; } } } @@ -1618,6 +1646,10 @@ WS.setIndex(InvalidIndex); continue; } + if (WS.isTable() && WS.getName() == "__indirect_function_table") { + // For the moment, don't emit table symbols -- wasm-ld can't handle them. + continue; + } LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n"); uint32_t Flags = 0; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -498,9 +498,11 @@ std::vector ImportedGlobals; std::vector ImportedFunctions; std::vector ImportedEvents; + std::vector ImportedTables; ImportedGlobals.reserve(Imports.size()); ImportedFunctions.reserve(Imports.size()); ImportedEvents.reserve(Imports.size()); + ImportedTables.reserve(Imports.size()); for (auto &I : Imports) { if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) ImportedFunctions.emplace_back(&I); @@ -508,6 +510,8 @@ ImportedGlobals.emplace_back(&I); else if (I.Kind == wasm::WASM_EXTERNAL_EVENT) ImportedEvents.emplace_back(&I); + else if (I.Kind == wasm::WASM_EXTERNAL_TABLE) + ImportedTables.emplace_back(&I); } while (Count--) { @@ -600,8 +604,18 @@ if (Table.SymbolName.empty()) Table.SymbolName = Info.Name; } else { - return make_error("undefined table symbol", - object_error::parse_failed); + wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex]; + if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) { + Info.Name = readString(Ctx); + Info.ImportName = Import.Field; + } else { + Info.Name = Import.Field; + } + TableType = Import.Table.ElemType; + // FIXME: Parse limits here too. + if (!Import.Module.empty()) { + Info.ImportModule = Import.Module; + } } break; @@ -1060,6 +1074,7 @@ } Error WasmObjectFile::parseTableSection(ReadContext &Ctx) { + TableSection = Sections.size(); uint32_t Count = readVaruint32(Ctx); Tables.reserve(Count); while (Count--) { @@ -1432,6 +1447,7 @@ case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_EVENT: + case wasm::WASM_SYMBOL_TYPE_TABLE: return Sym.Info.ElementIndex; case wasm::WASM_SYMBOL_TYPE_DATA: { // The value of a data symbol is the segment offset, plus the symbol @@ -1481,6 +1497,8 @@ return SymbolRef::ST_Debug; case wasm::WASM_SYMBOL_TYPE_EVENT: return SymbolRef::ST_Other; + case wasm::WASM_SYMBOL_TYPE_TABLE: + return SymbolRef::ST_Other; } llvm_unreachable("Unknown WasmSymbol::SymbolType"); @@ -1515,6 +1533,8 @@ return Sym.Info.ElementIndex; case wasm::WASM_SYMBOL_TYPE_EVENT: return EventSection; + case wasm::WASM_SYMBOL_TYPE_TABLE: + return TableSection; default: llvm_unreachable("Unknown WasmSymbol::SymbolType"); } diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -52,14 +52,6 @@ ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x0 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK-NEXT: Kind: TABLE -; CHECK-NEXT: Table: -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x0 -; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: bar ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -39,14 +39,6 @@ ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x1 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK-NEXT: Kind: TABLE -; CHECK-NEXT: Table: -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x0 -; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: funcImport ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 0 diff --git a/llvm/test/MC/WebAssembly/custom-sections.ll b/llvm/test/MC/WebAssembly/custom-sections.ll --- a/llvm/test/MC/WebAssembly/custom-sections.ll +++ b/llvm/test/MC/WebAssembly/custom-sections.ll @@ -15,18 +15,18 @@ ; CHECK: Section { ; CHECK: Type: CUSTOM (0x0) ; CHECK: Size: 3 -; CHECK: Offset: 72 +; CHECK: Offset: 38 ; CHECK: Name: red ; CHECK: } ; CHECK: Section { ; CHECK: Type: CUSTOM (0x0) ; CHECK: Size: 6 -; CHECK: Offset: 85 +; CHECK: Offset: 51 ; CHECK: Name: green ; CHECK: } ; CHECK: Section { ; CHECK: Type: CUSTOM (0x0) ; CHECK: Size: 25 -; CHECK: Offset: 118 +; CHECK: Offset: 84 ; CHECK: Name: producers ; CHECK: } diff --git a/llvm/test/MC/WebAssembly/data-section.s b/llvm/test/MC/WebAssembly/data-section.s --- a/llvm/test/MC/WebAssembly/data-section.s +++ b/llvm/test/MC/WebAssembly/data-section.s @@ -45,14 +45,6 @@ # BIN-NEXT: Kind: MEMORY # BIN-NEXT: Memory: # BIN-NEXT: Initial: 0x1 -# BIN-NEXT: - Module: env -# BIN-NEXT: Field: __indirect_function_table -# BIN-NEXT: Kind: TABLE -# BIN-NEXT: Table: -# BIN-NEXT: Index: 0 -# BIN-NEXT: ElemType: FUNCREF -# BIN-NEXT: Limits: -# BIN-NEXT: Initial: 0x0 # BIN-NEXT: - Type: FUNCTION # BIN-NEXT: FunctionTypes: [ 0 ] # BIN-NEXT: - Type: DATACOUNT diff --git a/llvm/test/MC/WebAssembly/event-section.ll b/llvm/test/MC/WebAssembly/event-section.ll --- a/llvm/test/MC/WebAssembly/event-section.ll +++ b/llvm/test/MC/WebAssembly/event-section.ll @@ -56,4 +56,4 @@ ; SEC: Type: EVENT (0xD) ; SEC-NEXT: Size: 3 -; SEC-NEXT: Offset: 97 +; SEC-NEXT: Offset: 63 diff --git a/llvm/test/MC/WebAssembly/external-func-address.ll b/llvm/test/MC/WebAssembly/external-func-address.ll --- a/llvm/test/MC/WebAssembly/external-func-address.ll +++ b/llvm/test/MC/WebAssembly/external-func-address.ll @@ -42,8 +42,6 @@ ; CHECK: - Module: env ; CHECK-NEXT: Field: __linear_memory ; CHECK: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK: - Module: env ; CHECK-NEXT: Field: varargs ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 @@ -53,6 +51,8 @@ ; CHECK-NEXT: Field: f1 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 0 +; CHECK: - Module: env +; CHECK-NEXT: Field: __indirect_function_table ; CHECK: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -27,14 +27,6 @@ ; CHECK-NEXT: Memory: ; CHECK-NEXT: Initial: 0x1 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: __indirect_function_table -; CHECK-NEXT: Kind: TABLE -; CHECK-NEXT: Table: -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: ElemType: FUNCREF -; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x2 -; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: func3 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 @@ -54,6 +46,14 @@ ; CHECK-NEXT: Field: func0 ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: SigIndex: 1 +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: __indirect_function_table +; CHECK-NEXT: Kind: TABLE +; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: ElemType: FUNCREF +; CHECK-NEXT: Limits: +; CHECK-NEXT: Initial: 0x2 ; CHECK-NEXT: - Type: FUNCTION ; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1 ] ; CHECK-NEXT: - Type: ELEM diff --git a/llvm/test/MC/WebAssembly/reloc-pic.s b/llvm/test/MC/WebAssembly/reloc-pic.s --- a/llvm/test/MC/WebAssembly/reloc-pic.s +++ b/llvm/test/MC/WebAssembly/reloc-pic.s @@ -63,6 +63,10 @@ # CHECK-NEXT: Memory: # CHECK-NEXT: Initial: 0x1 # CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: default_func +# CHECK-NEXT: Kind: FUNCTION +# CHECK-NEXT: SigIndex: 0 +# CHECK-NEXT: - Module: env # CHECK-NEXT: Field: __indirect_function_table # CHECK-NEXT: Kind: TABLE # CHECK-NEXT: Table: @@ -70,10 +74,6 @@ # CHECK-NEXT: ElemType: FUNCREF # CHECK-NEXT: Limits: # CHECK-NEXT: Initial: 0x1 -# CHECK-NEXT: - Module: env -# CHECK-NEXT: Field: default_func -# CHECK-NEXT: Kind: FUNCTION -# CHECK-NEXT: SigIndex: 0 # CHECK-NEXT: - Module: GOT.mem # CHECK-NEXT: Field: default_data # CHECK-NEXT: Kind: GLOBAL diff --git a/llvm/test/MC/WebAssembly/tables.s b/llvm/test/MC/WebAssembly/tables.s --- a/llvm/test/MC/WebAssembly/tables.s +++ b/llvm/test/MC/WebAssembly/tables.s @@ -121,14 +121,22 @@ # BIN: - Type: TABLE # BIN-NEXT: Tables: -# BIN-NEXT: - Index: 1 +# BIN-NEXT: - Index: 0 # BIN-NEXT: ElemType: EXTERNREF # BIN-NEXT: Limits: # BIN-NEXT: Initial: 0x0 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x0 # BIN-NEXT: - Index: 2 # BIN-NEXT: ElemType: FUNCREF # BIN-NEXT: Limits: # BIN-NEXT: Initial: 0x0 +# BIN-NEXT: - Index: 3 +# BIN-NEXT: ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x0 # BIN: - Type: CODE # BIN-NEXT: Relocations: @@ -162,19 +170,19 @@ # BIN-NEXT: Functions: # BIN-NEXT: - Index: 0 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 20002001FC108380808000FC0E838080800084808080000B +# BIN-NEXT: Body: 20002001FC108280808000FC0E828080800083808080000B # BIN-NEXT: - Index: 1 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 20002581808080000B +# BIN-NEXT: Body: 20002580808080000B # BIN-NEXT: - Index: 2 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 200020012681808080000B +# BIN-NEXT: Body: 200020012680808080000B # BIN-NEXT: - Index: 3 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 41002581808080002000FC0F818080800020006A0B +# BIN-NEXT: Body: 41002580808080002000FC0F808080800020006A0B # BIN-NEXT: - Index: 4 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 200041002583808080002001FC1183808080000B +# BIN-NEXT: Body: 200041002582808080002001FC1182808080000B # BIN: - Type: CUSTOM # BIN-NEXT: Name: linking @@ -184,9 +192,20 @@ # BIN-NEXT: Kind: TABLE # BIN-NEXT: Name: foo # BIN-NEXT: Flags: [ BINDING_LOCAL ] -# BIN-NEXT: Table: 1 +# BIN-NEXT: Table: 0 # BIN-NEXT: - Index: 1 # BIN-NEXT: Kind: TABLE # BIN-NEXT: Name: bar # BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Table: 1 +# BIN-NEXT: - Index: 2 +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Name: table1 +# BIN-NEXT: Flags: [ BINDING_LOCAL ] # BIN-NEXT: Table: 2 +# BIN-NEXT: - Index: 3 +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Name: table2 +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Table: 3 +# BIN-NEXT: - Index: 4 diff --git a/llvm/test/MC/WebAssembly/type-index.s b/llvm/test/MC/WebAssembly/type-index.s --- a/llvm/test/MC/WebAssembly/type-index.s +++ b/llvm/test/MC/WebAssembly/type-index.s @@ -38,14 +38,6 @@ # BIN-NEXT: Kind: MEMORY # BIN-NEXT: Memory: # BIN-NEXT: Initial: 0x0 -# BIN-NEXT: - Module: env -# BIN-NEXT: Field: __indirect_function_table -# BIN-NEXT: Kind: TABLE -# BIN-NEXT: Table: -# BIN-NEXT: Index: 0 -# BIN-NEXT: ElemType: FUNCREF -# BIN-NEXT: Limits: -# BIN-NEXT: Initial: 0x0 # BIN-NEXT: - Type: FUNCTION # BIN-NEXT: FunctionTypes: [ 0 ] # BIN-NEXT: - Type: CODE diff --git a/llvm/test/MC/WebAssembly/wasm64.s b/llvm/test/MC/WebAssembly/wasm64.s --- a/llvm/test/MC/WebAssembly/wasm64.s +++ b/llvm/test/MC/WebAssembly/wasm64.s @@ -150,14 +150,6 @@ # BIN-NEXT: Flags: [ IS_64 ] # BIN-NEXT: Initial: 0x1 # BIN-NEXT: - Module: env -# BIN-NEXT: Field: __indirect_function_table -# BIN-NEXT: Kind: TABLE -# BIN-NEXT: Table: -# BIN-NEXT: Index: 0 -# BIN-NEXT: ElemType: FUNCREF -# BIN-NEXT: Limits: -# BIN-NEXT: Initial: 0x0 -# BIN-NEXT: - Module: env # BIN-NEXT: Field: myglob64 # BIN-NEXT: Kind: GLOBAL # BIN-NEXT: GlobalType: I64