Index: llvm/trunk/lib/MC/WasmObjectWriter.cpp =================================================================== --- llvm/trunk/lib/MC/WasmObjectWriter.cpp +++ llvm/trunk/lib/MC/WasmObjectWriter.cpp @@ -553,7 +553,7 @@ case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: if (!IndirectSymbolIndices.count(RelEntry.Symbol)) - report_fatal_error("symbol not found table index space: " + + report_fatal_error("symbol not found in table index space: " + RelEntry.Symbol->getName()); return IndirectSymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: @@ -562,7 +562,7 @@ case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: if (!SymbolIndices.count(RelEntry.Symbol)) - report_fatal_error("symbol not found function/global index space: " + + report_fatal_error("symbol not found in function/global index space: " + RelEntry.Symbol->getName()); return SymbolIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: @@ -994,33 +994,10 @@ SmallVector Exports; SmallVector, 4> SymbolFlags; SmallVector, 2> InitFuncs; - SmallPtrSet IsAddressTaken; unsigned NumFuncImports = 0; SmallVector DataSegments; uint32_t DataSize = 0; - // Populate the IsAddressTaken set. - for (const WasmRelocationEntry &RelEntry : CodeRelocations) { - switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - IsAddressTaken.insert(RelEntry.Symbol); - break; - default: - break; - } - } - for (const WasmRelocationEntry &RelEntry : DataRelocations) { - switch (RelEntry.Type) { - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - IsAddressTaken.insert(RelEntry.Symbol); - break; - default: - break; - } - } - // In the special .global_variables section, we've encoded global // variables used by the function. Translate them into the Globals // list. @@ -1217,14 +1194,7 @@ } DEBUG(dbgs() << " -> function index: " << Index << "\n"); - - // If needed, prepare the function to be called indirectly. - if (IsAddressTaken.count(&WS) != 0) { - IndirectSymbolIndices[&WS] = TableElems.size(); - DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n"); - TableElems.push_back(Index); - } - } else { + } else { if (WS.isTemporary() && !WS.getSize()) continue; @@ -1288,7 +1258,6 @@ uint32_t Index = SymbolIndices.find(ResolvedSym)->second; DEBUG(dbgs() << " -> index:" << Index << "\n"); - //SymbolIndices[&WS] = Index; WasmExport Export; Export.FieldName = WS.getName(); Export.Index = Index; @@ -1303,12 +1272,34 @@ SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); } - // Add types for indirect function calls. - for (const WasmRelocationEntry &Fixup : CodeRelocations) { - if (Fixup.Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) - continue; + { + auto HandleReloc = [&](const WasmRelocationEntry &Rel) { + // Functions referenced by a relocation need to prepared to be called + // indirectly. + const MCSymbolWasm& WS = *Rel.Symbol; + if (WS.isFunction() && IndirectSymbolIndices.count(&WS) == 0) { + switch (Rel.Type) { + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { + uint32_t Index = SymbolIndices.find(&WS)->second; + IndirectSymbolIndices[&WS] = TableElems.size(); + DEBUG(dbgs() << " -> adding to table: " << TableElems.size() << "\n"); + TableElems.push_back(Index); + registerFunctionType(WS); + break; + } + default: + break; + } + } + }; - registerFunctionType(*Fixup.Symbol); + for (const WasmRelocationEntry &RelEntry : CodeRelocations) + HandleReloc(RelEntry); + for (const WasmRelocationEntry &RelEntry : DataRelocations) + HandleReloc(RelEntry); } // Translate .init_array section contents into start functions. Index: llvm/trunk/test/MC/WebAssembly/weak-alias.ll =================================================================== --- llvm/trunk/test/MC/WebAssembly/weak-alias.ll +++ llvm/trunk/test/MC/WebAssembly/weak-alias.ll @@ -8,21 +8,41 @@ @bar = global i32 7, align 8 @bar_alias = weak hidden alias i32, i32* @bar -@bar_alias_address = global i32* @bar_alias, align 8 - @foo_alias = weak hidden alias i32 (), i32 ()* @foo +@direct_address = global i32()* @foo, align 8 +@alias_address = global i32()* @foo_alias, align 8 + +define hidden i32 @foo() #0 { +entry: + ret i32 0 +} + +define hidden i32 @call_direct() #0 { +entry: + %call = call i32 @foo() + ret i32 %call +} + define hidden i32 @call_alias() #0 { entry: %call = call i32 @foo_alias() ret i32 %call } -define hidden i32 @foo() #0 { +define hidden i32 @call_direct_ptr() #0 { entry: - ret i32 0 + %0 = load i32 ()*, i32 ()** @direct_address, align 8 + %call = call i32 %0() + ret i32 %call } +define hidden i32 @call_alias_ptr() #0 { +entry: + %0 = load i32 ()*, i32 ()** @alias_address, align 8 + %call = call i32 %0() + ret i32 %call +} ; CHECK: - Type: TYPE ; CHECK-NEXT: Signatures: @@ -42,7 +62,7 @@ ; CHECK-NEXT: Table: ; CHECK-NEXT: ElemType: ANYFUNC ; CHECK-NEXT: Limits: -; CHECK-NEXT: Initial: 0x00000000 +; CHECK-NEXT: Initial: 0x00000002 ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: foo_alias ; CHECK-NEXT: Kind: FUNCTION @@ -53,54 +73,101 @@ ; CHECK-NEXT: GlobalType: I32 ; CHECK-NEXT: GlobalMutable: false ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ] ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Value: 8 ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 8 +; CHECK-NEXT: Value: 16 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: -; CHECK-NEXT: - Name: call_alias +; CHECK-NEXT: - Name: foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: foo +; CHECK-NEXT: - Name: call_direct ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: bar +; CHECK-NEXT: - Name: call_alias +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: call_direct_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: direct_address ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: bar_alias_address +; CHECK-NEXT: - Name: call_alias_ptr +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Name: alias_address ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: bar +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: foo_alias ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: bar_alias ; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Functions: [ 1, 0 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x00000009 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000012 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x0000001E +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TYPE_INDEX_LEB ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: Offset: 0x00000004 +; CHECK-NEXT: Offset: 0x00000024 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Offset: 0x00000031 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TYPE_INDEX_LEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000037 ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 41000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 1081808080000B +; CHECK-NEXT: - Locals: ; CHECK-NEXT: Body: 1080808080000B ; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41000B +; CHECK-NEXT: Body: 410028028880808000118080808000000B +; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 410028029080808000118080808000000B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Relocations: -; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 ; CHECK-NEXT: Index: 0 ; CHECK-NEXT: Offset: 0x0000000F +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Offset: 0x00000018 ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 6 ; CHECK-NEXT: MemoryIndex: 0 @@ -121,20 +188,32 @@ ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: foo_alias ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: call_alias -; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: foo +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: call_direct +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: call_alias +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: call_direct_ptr +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: call_alias_ptr ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 12 +; CHECK-NEXT: DataSize: 20 ; CHECK-NEXT: SymbolInfo: ; CHECK-NEXT: - Name: foo_alias ; CHECK-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN ] ; CHECK-NEXT: - Name: bar_alias ; CHECK-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN ] +; CHECK-NEXT: - Name: foo +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: - Name: call_direct +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] ; CHECK-NEXT: - Name: call_alias ; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] -; CHECK-NEXT: - Name: foo +; CHECK-NEXT: - Name: call_direct_ptr +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: - Name: call_alias_ptr ; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] ; CHECK-NEXT: SegmentInfo: ; CHECK-NEXT: - Index: 0 @@ -142,18 +221,29 @@ ; CHECK-NEXT: Alignment: 8 ; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: .data.bar_alias_address +; CHECK-NEXT: Name: .data.direct_address +; CHECK-NEXT: Alignment: 8 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: .data.alias_address ; CHECK-NEXT: Alignment: 8 ; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: ... ; CHECK-SYMS: SYMBOL TABLE: ; CHECK-SYMS-NEXT: 00000000 g F name foo_alias -; CHECK-SYMS-NEXT: 00000001 g F name call_alias -; CHECK-SYMS-NEXT: 00000002 g F name foo -; CHECK-SYMS-NEXT: 00000002 gw F EXPORT .hidden foo_alias +; CHECK-SYMS-NEXT: 00000001 g F name foo +; CHECK-SYMS-NEXT: 00000002 g F name call_direct +; CHECK-SYMS-NEXT: 00000003 g F name call_alias +; CHECK-SYMS-NEXT: 00000004 g F name call_direct_ptr +; CHECK-SYMS-NEXT: 00000005 g F name call_alias_ptr +; CHECK-SYMS-NEXT: 00000001 gw F EXPORT .hidden foo_alias ; CHECK-SYMS-NEXT: 00000000 gw EXPORT .hidden bar_alias -; CHECK-SYMS-NEXT: 00000001 g F EXPORT .hidden call_alias -; CHECK-SYMS-NEXT: 00000002 g F EXPORT .hidden foo +; CHECK-SYMS-NEXT: 00000001 g F EXPORT .hidden foo +; CHECK-SYMS-NEXT: 00000002 g F EXPORT .hidden call_direct +; CHECK-SYMS-NEXT: 00000003 g F EXPORT .hidden call_alias +; CHECK-SYMS-NEXT: 00000004 g F EXPORT .hidden call_direct_ptr +; CHECK-SYMS-NEXT: 00000008 g EXPORT direct_address +; CHECK-SYMS-NEXT: 00000005 g F EXPORT .hidden call_alias_ptr +; CHECK-SYMS-NEXT: 00000010 g EXPORT alias_address ; CHECK-SYMS-NEXT: 00000000 g EXPORT bar -; CHECK-SYMS-NEXT: 00000008 g EXPORT bar_alias_address