diff --git a/lld/test/wasm/compress-relocs.ll b/lld/test/wasm/compress-relocs.ll --- a/lld/test/wasm/compress-relocs.ll +++ b/lld/test/wasm/compress-relocs.ll @@ -1,5 +1,5 @@ ; RUN: llc -filetype=obj %s -o %t.o -; RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/call-indirect.s -o %t2.o +; RUN: llvm-mc -mattr=+reference-types -filetype=obj -triple=wasm32-unknown-unknown %p/Inputs/call-indirect.s -o %t2.o ; RUN: wasm-ld --export-dynamic -o %t.wasm %t2.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s ; RUN: wasm-ld --export-dynamic -O2 -o %t-opt.wasm %t2.o %t.o @@ -22,5 +22,5 @@ ; ERROR: wasm-ld: error: --compress-relocations is incompatible with output debug information. Please pass --strip-debug or --strip-all -; CHECK: Body: 410028028088808000118080808000001A410028028488808000118180808000001A0B +; CHECK: Body: 41002802808880800011808080800080808080001A41002802848880800011818080800080808080001A0B ; COMPRESS: Body: 4100280280081100001A4100280284081101001A0B 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 @@ -18,6 +18,7 @@ bool IsWeak = false; bool IsHidden = false; bool IsComdat = false; + bool OmitFromLinkingSection = false; mutable bool IsUsedInInitArray = false; mutable bool IsUsedInGOT = false; Optional ImportModule; @@ -75,6 +76,12 @@ bool isComdat() const { return IsComdat; } void setComdat(bool isComdat) { IsComdat = isComdat; } + // wasm-ld understands a finite set of symbol types. This flag allows the + // compiler to avoid emitting symbol table entries that would confuse the + // linker, unless the user specifically requests the feature. + bool omitFromLinkingSection() const { return OmitFromLinkingSection; } + void setOmitFromLinkingSection() { OmitFromLinkingSection = true; } + bool hasImportModule() const { return ImportModule.hasValue(); } StringRef getImportModule() const { if (ImportModule.hasValue()) 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 @@ -405,12 +405,17 @@ void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { - // As a stopgap measure until call_indirect instructions start explicitly - // referencing the indirect function table via TABLE_NUMBER relocs, ensure - // that the indirect function table import makes it to the output if anything - // in the compilation unit has caused it to be present. - if (auto *Sym = Asm.getContext().lookupSymbol("__indirect_function_table")) - Asm.registerSymbol(*Sym); + // Some compilation units require the indirect function table to be present + // but don't explicitly reference it. This is the case for call_indirect + // without the reference-types feature, and also function bitcasts in all + // cases. In those cases the __indirect_function_table has the + // WASM_SYMBOL_NO_STRIP attribute. Here we make sure this symbol makes it to + // the assembler, if needed. + if (auto *Sym = Asm.getContext().lookupSymbol("__indirect_function_table")) { + const auto *WasmSym = static_cast(Sym); + if (WasmSym->isNoStrip()) + Asm.registerSymbol(*Sym); + } // Build a map of sections to the function that defines them, for use // in recordRelocation. @@ -509,21 +514,18 @@ Type == wasm::R_WASM_TABLE_INDEX_I32 || Type == wasm::R_WASM_TABLE_INDEX_I64) { // TABLE_INDEX relocs implicitly use the default indirect function table. + // We require the function table to have already been defined. 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"); + if (!Sym || !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(); + // Ensure that __indirect_function_table reaches the output. + Sym->setNoStrip(); + Asm.registerSymbol(*Sym); } - Sym->setUsedInReloc(); - Asm.registerSymbol(*Sym); } // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be @@ -1211,6 +1213,9 @@ if (Sym.isSection()) return false; + if (Sym.omitFromLinkingSection()) + return false; + return true; } @@ -1674,10 +1679,6 @@ 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/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -171,9 +171,6 @@ static MCSymbolWasm *GetOrCreateFunctionTableSymbol(MCContext &Ctx, const StringRef &Name) { - // FIXME: Duplicates functionality from - // MC/WasmObjectWriter::recordRelocation, as well as WebAssemblyCodegen's - // WebAssembly:getOrCreateFunctionTableSymbol. MCSymbolWasm *Sym = cast_or_null(Ctx.lookupSymbol(Name)); if (Sym) { if (!Sym->isFunctionTable()) @@ -223,6 +220,7 @@ }; std::vector NestingStack; + MCSymbolWasm *DefaultFunctionTable = nullptr; MCSymbol *LastFunctionLabel = nullptr; public: @@ -233,6 +231,15 @@ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits())); } + void Initialize(MCAsmParser &Parser) override { + MCAsmParserExtension::Initialize(Parser); + + DefaultFunctionTable = GetOrCreateFunctionTableSymbol( + getContext(), "__indirect_function_table"); + if (!STI->checkFeatures("+reference-types")) + DefaultFunctionTable->setOmitFromLinkingSection(); + } + #define GET_ASSEMBLER_HEADER #include "WebAssemblyGenAsmMatcher.inc" @@ -480,6 +487,39 @@ WebAssemblyOperand::IntOp{static_cast(BT)})); } + bool addFunctionTableOperand(OperandVector &Operands, MCSymbolWasm *Sym, + SMLoc StartLoc, SMLoc EndLoc) { + const auto *Val = MCSymbolRefExpr::create(Sym, getContext()); + Operands.push_back(std::make_unique( + WebAssemblyOperand::Symbol, StartLoc, EndLoc, + WebAssemblyOperand::SymOp{Val})); + return false; + } + + bool addFunctionTableOperand(OperandVector &Operands, StringRef TableName, + SMLoc StartLoc, SMLoc EndLoc) { + return addFunctionTableOperand( + Operands, GetOrCreateFunctionTableSymbol(getContext(), TableName), + StartLoc, EndLoc); + } + + bool addDefaultFunctionTableOperand(OperandVector &Operands, SMLoc StartLoc, + SMLoc EndLoc) { + if (STI->checkFeatures("+reference-types")) { + return addFunctionTableOperand(Operands, DefaultFunctionTable, StartLoc, + EndLoc); + } else { + // For the MVP there is at most one table whose number is 0, but we can't + // write a table symbol or issue relocations. Instead we just ensure the + // table is live and write a zero. + getStreamer().emitSymbolAttribute(DefaultFunctionTable, MCSA_NoDeadStrip); + Operands.push_back(std::make_unique( + WebAssemblyOperand::Integer, StartLoc, EndLoc, + WebAssemblyOperand::IntOp{0})); + return false; + } + } + bool ParseInstruction(ParseInstructionInfo & /*Info*/, StringRef Name, SMLoc NameLoc, OperandVector &Operands) override { // Note: Name does NOT point into the sourcecode, but to a local, so @@ -516,6 +556,7 @@ bool ExpectBlockType = false; bool ExpectFuncType = false; bool ExpectHeapType = false; + bool ExpectFunctionTable = false; if (Name == "block") { push(Block); ExpectBlockType = true; @@ -562,15 +603,7 @@ return true; } else if (Name == "call_indirect" || Name == "return_call_indirect") { ExpectFuncType = true; - // Ensure that the object file has a __indirect_function_table import, as - // we call_indirect against it. - auto &Ctx = getStreamer().getContext(); - MCSymbolWasm *Sym = - GetOrCreateFunctionTableSymbol(Ctx, "__indirect_function_table"); - // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark - // it as NO_STRIP so as to ensure that the indirect function table makes - // it to linked output. - Sym->setNoStrip(); + ExpectFunctionTable = true; } else if (Name == "ref.null") { ExpectHeapType = true; } @@ -586,7 +619,7 @@ return true; // Got signature as block type, don't need more ExpectBlockType = false; - auto &Ctx = getStreamer().getContext(); + auto &Ctx = getContext(); // The "true" here will cause this to be a nameless symbol. MCSymbol *Sym = Ctx.createTempSymbol("typeindex", true); auto *WasmSym = cast(Sym); @@ -598,6 +631,16 @@ Operands.push_back(std::make_unique( WebAssemblyOperand::Symbol, Loc.getLoc(), Loc.getEndLoc(), WebAssemblyOperand::SymOp{Expr})); + + // Allow additional operands after the signature, notably for + // call_indirect against a named table. + if (Lexer.isNot(AsmToken::EndOfStatement)) { + if (expect(AsmToken::Comma, ",")) + return true; + if (Lexer.is(AsmToken::EndOfStatement)) { + return error("Unexpected trailing comma"); + } + } } while (Lexer.isNot(AsmToken::EndOfStatement)) { @@ -623,6 +666,11 @@ WebAssemblyOperand::Integer, Id.getLoc(), Id.getEndLoc(), WebAssemblyOperand::IntOp{static_cast(HeapType)})); Parser.Lex(); + } else if (ExpectFunctionTable) { + if (addFunctionTableOperand(Operands, Id.getString(), Id.getLoc(), + Id.getEndLoc())) + return true; + Parser.Lex(); } else { // Assume this identifier is a label. const MCExpr *Val; @@ -689,6 +737,12 @@ // Support blocks with no operands as default to void. addBlockTypeOperand(Operands, NameLoc, WebAssembly::BlockType::Void); } + if (ExpectFunctionTable && Operands.size() == 2) { + // If call_indirect doesn't specify a target table, supply one. + if (addDefaultFunctionTableOperand(Operands, NameLoc, + SMLoc::getFromPointer(Name.end()))) + return true; + } Parser.Lex(); return false; } diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -68,7 +68,7 @@ for (auto I = Start, E = MI->getNumOperands(); I < E; ++I) { if (MI->getOpcode() == WebAssembly::CALL_INDIRECT && I - Start == NumVariadicDefs) { - // Skip type and flags arguments when printing for tests + // Skip type and table arguments when printing for tests. ++I; continue; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -23,6 +23,7 @@ #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblyRegisterInfo.h" #include "WebAssemblyTargetMachine.h" +#include "WebAssemblyUtilities.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/BinaryFormat/Wasm.h" @@ -171,19 +172,25 @@ void WebAssemblyAsmPrinter::emitEndOfAsmFile(Module &M) { for (auto &It : OutContext.getSymbols()) { - // Emit a .globaltype and .eventtype declaration. + // Emit .globaltype, .eventtype, or .tabletype declarations. auto Sym = cast(It.getValue()); if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_GLOBAL) getTargetStreamer()->emitGlobalType(Sym); else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_EVENT) getTargetStreamer()->emitEventType(Sym); + else if (Sym->getType() == wasm::WASM_SYMBOL_TYPE_TABLE) + getTargetStreamer()->emitTableType(Sym); } DenseSet InvokeSymbols; + bool HasAddressTakenFunction = false; for (const auto &F : M) { if (F.isIntrinsic()) continue; + if (F.hasAddressTaken()) + HasAddressTakenFunction = true; + // Emit function type info for all undefined functions if (F.isDeclarationForLinker()) { SmallVector Results; @@ -242,6 +249,18 @@ } } + // When a function's address is taken, a TABLE_INDEX relocation is emitted + // against the function symbol at the use site. However the relocation + // doesn't explicitly refer to the table. In the future we may want to + // define a new kind of reloc against both the function and the table, so + // that the linker can see that the function symbol keeps the table alive, + // but for now manually mark the table as live. + if (HasAddressTakenFunction) { + MCSymbolWasm *FunctionTable = + WebAssembly::getOrCreateFunctionTableSymbol(OutContext, Subtarget); + OutStreamer->emitSymbolAttribute(FunctionTable, MCSA_NoDeadStrip); + } + for (const auto &G : M.globals()) { if (!G.hasInitializer() && G.hasExternalLinkage()) { if (G.getValueType()->isSized()) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -869,19 +869,20 @@ if (IsDirect) { MIB.addGlobalAddress(Func); } else { - // Add placeholders for the type index and immediate flags + // Placehoder for the type index. MIB.addImm(0); - MIB.addImm(0); - - // Ensure that the object file has a __indirect_function_table import, as we - // call_indirect against it. - MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol( - MF->getMMI().getContext(), "__indirect_function_table"); - // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark - // it as NO_STRIP so as to ensure that the indirect function table makes it - // to linked output. - Sym->setNoStrip(); - + // The table into which this call_indirect indexes. + MCSymbolWasm *Table = WebAssembly::getOrCreateFunctionTableSymbol( + MF->getMMI().getContext(), Subtarget); + if (Subtarget->hasReferenceTypes()) { + MIB.addSym(Table); + } else { + // Otherwise for the MVP there is at most one table whose number is 0, but + // we can't write a table symbol or issue relocations. Instead we just + // ensure the table is live. + Table->setNoStrip(); + MIB.addImm(0); + } // See if we must truncate the function pointer. // CALL_INDIRECT takes an i32, but in wasm64 we represent function pointers // as 64-bit for uniformity with other pointer types. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -426,9 +426,10 @@ return DoneMBB; } -static MachineBasicBlock *LowerCallResults(MachineInstr &CallResults, - DebugLoc DL, MachineBasicBlock *BB, - const TargetInstrInfo &TII) { +static MachineBasicBlock * +LowerCallResults(MachineInstr &CallResults, DebugLoc DL, MachineBasicBlock *BB, + const WebAssemblySubtarget *Subtarget, + const TargetInstrInfo &TII) { MachineInstr &CallParams = *CallResults.getPrevNode(); assert(CallParams.getOpcode() == WebAssembly::CALL_PARAMS); assert(CallResults.getOpcode() == WebAssembly::CALL_RESULTS || @@ -476,19 +477,21 @@ for (auto Def : CallResults.defs()) MIB.add(Def); - // Add placeholders for the type index and immediate flags if (IsIndirect) { + // Placeholder for the type index. MIB.addImm(0); - MIB.addImm(0); - - // Ensure that the object file has a __indirect_function_table import, as we - // call_indirect against it. - MCSymbolWasm *Sym = WebAssembly::getOrCreateFunctionTableSymbol( - MF.getContext(), "__indirect_function_table"); - // Until call_indirect emits TABLE_NUMBER relocs against this symbol, mark - // it as NO_STRIP so as to ensure that the indirect function table makes it - // to linked output. - Sym->setNoStrip(); + // The table into which this call_indirect indexes. + MCSymbolWasm *Table = + WebAssembly::getOrCreateFunctionTableSymbol(MF.getContext(), Subtarget); + if (Subtarget->hasReferenceTypes()) { + MIB.addSym(Table); + } else { + // For the MVP there is at most one table whose number is 0, but we can't + // write a table symbol or issue relocations. Instead we just ensure the + // table is live and write a zero. + Table->setNoStrip(); + MIB.addImm(0); + } } for (auto Use : CallParams.uses()) @@ -535,7 +538,7 @@ WebAssembly::I64_TRUNC_U_F64); case WebAssembly::CALL_RESULTS: case WebAssembly::RET_CALL_RESULTS: - return LowerCallResults(MI, DL, BB, TII); + return LowerCallResults(MI, DL, BB, Subtarget, TII); } } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -48,6 +48,9 @@ I<(outs), (ins variable_ops), (outs), (ins), [], "return_call_results", "return_call_results", -1>; +// Note that instructions with variable_ops have custom printers in +// WebAssemblyInstPrinter.cpp. + let variadicOpsAreDefs = 1 in defm CALL : I<(outs), (ins function32_op:$callee, variable_ops), @@ -56,9 +59,12 @@ let variadicOpsAreDefs = 1 in defm CALL_INDIRECT : - I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops), - (outs), (ins TypeIndex:$type, i32imm:$flags), [], - "call_indirect", "call_indirect\t$type", 0x11>; + I<(outs), + (ins TypeIndex:$type, table32_op:$table, variable_ops), + (outs), + (ins TypeIndex:$type, table32_op:$table), + [], + "call_indirect", "call_indirect\t$type, $table", 0x11>; let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in defm RET_CALL : @@ -69,9 +75,9 @@ let isReturn = 1 in defm RET_CALL_INDIRECT : - I<(outs), (ins TypeIndex:$type, i32imm:$flags, variable_ops), - (outs), (ins TypeIndex:$type, i32imm:$flags), [], - "return_call_indirect\t", "return_call_indirect\t$type", + I<(outs), (ins TypeIndex:$type, table32_op:$table, variable_ops), + (outs), (ins TypeIndex:$type, table32_op:$table), [], + "return_call_indirect\t", "return_call_indirect\t$type, $table", 0x13>, Requires<[HasTailCall]>; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -161,6 +161,8 @@ report_fatal_error("Global indexes with offsets not supported"); if (WasmSym->isEvent()) report_fatal_error("Event indexes with offsets not supported"); + if (WasmSym->isTable()) + report_fatal_error("Table indexes with offsets not supported"); Expr = MCBinaryExpr::createAdd( Expr, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -24,6 +24,7 @@ class MCSymbolWasm; class StringRef; class WebAssemblyFunctionInfo; +class WebAssemblySubtarget; namespace WebAssembly { @@ -41,10 +42,11 @@ /// instruction. const MachineOperand &getCalleeOp(const MachineInstr &MI); -/// Returns the operand number of a callee, assuming the argument is a call -/// instruction. -MCSymbolWasm *getOrCreateFunctionTableSymbol(MCContext &Ctx, - const StringRef &Name); +/// Returns the __indirect_function_table, for use in call_indirect and in +/// function bitcasts. +MCSymbolWasm * +getOrCreateFunctionTableSymbol(MCContext &Ctx, + const WebAssemblySubtarget *Subtarget); /// Find a catch instruction from an EH pad. Returns null if no catch /// instruction found or the catch is in an invalid location. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -98,11 +98,9 @@ } } -MCSymbolWasm * -WebAssembly::getOrCreateFunctionTableSymbol(MCContext &Ctx, - const StringRef &Name) { - // FIXME: Duplicates functionality from - // MC/WasmObjectWriter::recordRelocation. +MCSymbolWasm *WebAssembly::getOrCreateFunctionTableSymbol( + MCContext &Ctx, const WebAssemblySubtarget *Subtarget) { + StringRef Name = "__indirect_function_table"; MCSymbolWasm *Sym = cast_or_null(Ctx.lookupSymbol(Name)); if (Sym) { if (!Sym->isFunctionTable()) @@ -113,6 +111,9 @@ // The default function table is synthesized by the linker. Sym->setUndefined(); } + // MVP object files can't have symtab entries for tables. + if (!(Subtarget && Subtarget->hasReferenceTypes())) + Sym->setOmitFromLinkingSection(); return Sym; } diff --git a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll --- a/llvm/test/CodeGen/WebAssembly/function-pointer64.ll +++ b/llvm/test/CodeGen/WebAssembly/function-pointer64.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -asm-verbose=false -O2 | FileCheck %s +; RUN: llc < %s -asm-verbose=false -mattr=+reference-types -O2 | FileCheck --check-prefix=REF %s ; RUN: llc < %s -asm-verbose=false -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=YAML %s ; This tests pointer features that may codegen differently in wasm64. @@ -34,14 +35,16 @@ ; CHECK-NEXT: i32.const 1 ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: i32.wrap_i64 -; CHECK-NEXT: call_indirect (i32) -> () +; CHECK-NEXT: call_indirect (i32) -> (), 0 +; REF: call_indirect (i32) -> (), __indirect_function_table ; CHECK: .functype test () -> () ; CHECK-NEXT: i64.const bar ; CHECK-NEXT: call foo -; Check we're emitting a 64-bit reloc for `i64.const bar` and the global. +; Check we're emitting a 64-bit relocs for the call_indirect, the +; `i64.const bar` reference in code, and the global. ; YAML: Memory: ; YAML-NEXT: Flags: [ IS_64 ] @@ -51,6 +54,9 @@ ; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64 ; YAML-NEXT: Index: 0 ; YAML-NEXT: Offset: 0x16 +; YAML: - Type: R_WASM_TABLE_INDEX_SLEB64 +; YAML-NEXT: Index: 0 +; YAML-NEXT: Offset: 0x29 ; YAML: - Type: DATA ; YAML: - Type: R_WASM_TABLE_INDEX_I64 diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll --- a/llvm/test/CodeGen/WebAssembly/multivalue.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll @@ -1,4 +1,5 @@ ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mattr=+multivalue,+tail-call | FileCheck %s +; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mattr=+reference-types,+multivalue,+tail-call | FileCheck --check-prefix REF %s ; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+multivalue,+tail-call | FileCheck %s --check-prefix REGS ; RUN: llc < %s --filetype=obj -mattr=+multivalue,+tail-call | obj2yaml | FileCheck %s --check-prefix OBJ @@ -57,7 +58,8 @@ ; CHECK-LABEL: pair_call_indirect: ; CHECK-NEXT: .functype pair_call_indirect (i32) -> (i32, i64) ; CHECK-NEXT: local.get 0{{$}} -; CHECK-NEXT: call_indirect () -> (i32, i64){{$}} +; CHECK-NEXT: call_indirect () -> (i32, i64), 0{{$}} +; REF: call_indirect () -> (i32, i64), __indirect_function_table{{$}} ; CHECK-NEXT: end_function{{$}} ; REGS: call_indirect $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}} define %pair @pair_call_indirect(%pair()* %f) { diff --git a/llvm/test/MC/WebAssembly/basic-assembly.s b/llvm/test/MC/WebAssembly/basic-assembly.s --- a/llvm/test/MC/WebAssembly/basic-assembly.s +++ b/llvm/test/MC/WebAssembly/basic-assembly.s @@ -1,6 +1,6 @@ -# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types,atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s # Check that it converts to .o without errors, but don't check any output: -# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+atomics,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling -o %t.o < %s empty_func: @@ -156,7 +156,7 @@ # CHECK-NEXT: i64.const 1234 # CHECK-NEXT: call something2 # CHECK-NEXT: i32.const 0 -# CHECK-NEXT: call_indirect (i32, f64) -> () +# CHECK-NEXT: call_indirect (i32, f64) -> (), __indirect_function_table # CHECK-NEXT: i32.const 1 # CHECK-NEXT: i32.add # CHECK-NEXT: local.tee 0 diff --git a/llvm/test/MC/WebAssembly/call-indirect-relocs.s b/llvm/test/MC/WebAssembly/call-indirect-relocs.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/call-indirect-relocs.s @@ -0,0 +1,83 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck --check-prefix=CHECK %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s + +test0: + .functype test0 () -> () + i32.const 42 + f64.const 2.5 + i32.const 0 + call_indirect (i32, f64) -> (), empty_fref_table + end_function + +.tabletype empty_fref_table, funcref +empty_fref_table: + + +# CHECK: .text +# CHECK-LABEL: test0: +# CHECK-NEXT: .functype test0 () -> () +# CHECK-NEXT: i32.const 42 +# CHECK-NEXT: f64.const 0x1.4p1 +# CHECK-NEXT: i32.const 0 +# CHECK-NEXT: call_indirect (i32, f64) -> (), empty_fref_table +# CHECK-NEXT: end_function + +# CHECK: .tabletype empty_fref_table, funcref +# CHECK: empty_fref_table: + +# BIN: --- !WASM +# BIN-NEXT: FileHeader: +# BIN-NEXT: Version: 0x1 +# BIN-NEXT: Sections: +# BIN-NEXT: - Type: TYPE +# BIN-NEXT: Signatures: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: ParamTypes: [] +# BIN-NEXT: ReturnTypes: [] +# BIN-NEXT: - Index: 1 +# BIN-NEXT: ParamTypes: +# BIN-NEXT: - I32 +# BIN-NEXT: - F64 +# BIN-NEXT: ReturnTypes: [] +# BIN-NEXT: - Type: IMPORT +# BIN-NEXT: Imports: +# BIN-NEXT: - Module: env +# BIN-NEXT: Field: __linear_memory +# BIN-NEXT: Kind: MEMORY +# BIN-NEXT: Memory: +# BIN-NEXT: Initial: 0x0 +# BIN-NEXT: - Type: FUNCTION +# BIN-NEXT: FunctionTypes: [ 0 ] +# BIN-NEXT: - Type: TABLE +# BIN-NEXT: Tables: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x0 +# BIN-NEXT: - Type: CODE +# BIN-NEXT: Relocations: +# BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x11 +# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x16 +# BIN-NEXT: Functions: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Locals: [] +# BIN-NEXT: Body: 412A440000000000000440410011818080800080808080000B +# BIN-NEXT: - Type: CUSTOM +# BIN-NEXT: Name: linking +# BIN-NEXT: Version: 2 +# BIN-NEXT: SymbolTable: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Kind: FUNCTION +# BIN-NEXT: Name: test0 +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Function: 0 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Name: empty_fref_table +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Table: 0 +# BIN-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/function-alias.ll b/llvm/test/MC/WebAssembly/function-alias.ll --- a/llvm/test/MC/WebAssembly/function-alias.ll +++ b/llvm/test/MC/WebAssembly/function-alias.ll @@ -1,4 +1,5 @@ ; RUN: llc -filetype=obj %s -o - | llvm-readobj --symbols - | FileCheck %s +; RUN: llc -filetype=obj %s -mattr=+reference-types -o - | llvm-readobj --symbols - | FileCheck --check-prefix=REF %s target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" target triple = "wasm32-unknown-unknown-wasm" @@ -42,3 +43,44 @@ ; CHECK-NEXT: ElementIndex: 0x0 ; CHECK-NEXT: } ; CHECK-NEXT: ] + +; REF: Symbols [ +; REF-NEXT: Symbol { +; REF-NEXT: Name: func +; REF-NEXT: Type: FUNCTION (0x0) +; REF-NEXT: Flags [ (0x0) +; REF-NEXT: ] +; REF-NEXT: ElementIndex: 0x0 +; REF-NEXT: } +; REF-NEXT: Symbol { +; REF-NEXT: Name: bar2 +; REF-NEXT: Type: FUNCTION (0x0) +; REF-NEXT: Flags [ (0x0) +; REF-NEXT: ] +; REF-NEXT: ElementIndex: 0x0 +; REF-NEXT: } +; REF-NEXT: Symbol { +; REF-NEXT: Name: foo +; REF-NEXT: Type: FUNCTION (0x0) +; REF-NEXT: Flags [ (0x0) +; REF-NEXT: ] +; REF-NEXT: ElementIndex: 0x0 +; REF-NEXT: } +; REF-NEXT: Symbol { +; REF-NEXT: Name: bar +; REF-NEXT: Type: FUNCTION (0x0) +; REF-NEXT: Flags [ (0x0) +; REF-NEXT: ] +; REF-NEXT: ElementIndex: 0x0 +; REF-NEXT: } +; REF-NEXT: Symbol { +; REF-NEXT: Name: __indirect_function_table +; REF-NEXT: Type: TABLE (0x5) +; REF-NEXT: Flags [ (0x90) +; REF-NEXT: NO_STRIP (0x80) +; REF-NEXT: UNDEFINED (0x10) +; REF-NEXT: ] +; REF-NEXT: ImportModule: env +; REF-NEXT: ElementIndex: 0x0 +; REF-NEXT: } +; REF-NEXT: ] diff --git a/llvm/test/MC/WebAssembly/reloc-code.ll b/llvm/test/MC/WebAssembly/reloc-code.ll --- a/llvm/test/MC/WebAssembly/reloc-code.ll +++ b/llvm/test/MC/WebAssembly/reloc-code.ll @@ -1,4 +1,5 @@ ; RUN: llc -filetype=obj %s -o - | llvm-readobj -r --expand-relocs - | FileCheck %s +; RUN: llc -filetype=obj -mattr=+reference-types %s -o - | llvm-readobj -r --expand-relocs - | FileCheck --check-prefix=REF %s target triple = "wasm32-unknown-unknown" @@ -59,3 +60,51 @@ ; CHECK-NEXT: } ; CHECK-NEXT: } ; CHECK-NEXT: ] + +; REF: Format: WASM +; REF: Relocations [ +; REF-NEXT: Section (5) CODE { +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_MEMORY_ADDR_LEB (3) +; REF-NEXT: Offset: 0x9 +; REF-NEXT: Symbol: b +; REF-NEXT: Addend: 0 +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_MEMORY_ADDR_LEB (3) +; REF-NEXT: Offset: 0x14 +; REF-NEXT: Symbol: a +; REF-NEXT: Addend: 0 +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_TYPE_INDEX_LEB (6) +; REF-NEXT: Offset: 0x1A +; REF-NEXT: Index: 0x1 +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_TABLE_NUMBER_LEB (20) +; REF-NEXT: Offset: 0x1F +; REF-NEXT: Symbol: __indirect_function_table +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_TYPE_INDEX_LEB (6) +; REF-NEXT: Offset: 0x28 +; REF-NEXT: Index: 0x0 +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_TABLE_NUMBER_LEB (20) +; REF-NEXT: Offset: 0x2D +; REF-NEXT: Symbol: __indirect_function_table +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0) +; REF-NEXT: Offset: 0x35 +; REF-NEXT: Symbol: c +; REF-NEXT: } +; REF-NEXT: Relocation { +; REF-NEXT: Type: R_WASM_FUNCTION_INDEX_LEB (0) +; REF-NEXT: Offset: 0x3C +; REF-NEXT: Symbol: d +; REF-NEXT: } +; REF-NEXT: } +; REF-NEXT: ] 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 @@ -1,4 +1,5 @@ # RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=REF %s # Verify that @GOT relocation entryes result in R_WASM_GLOBAL_INDEX_LEB against # against the corrsponding function or data symbol and that the corresponding @@ -190,6 +191,11 @@ # CHECK-NEXT: Name: hidden_func # CHECK-NEXT: Flags: [ BINDING_LOCAL ] # CHECK-NEXT: Function: 5 +# REF: - Index: 10 +# REF-NEXT: Kind: TABLE +# REF-NEXT: Name: __indirect_function_table +# REF-NEXT: Flags: [ UNDEFINED, NO_STRIP ] +# REF-NEXT: Table: 0 # CHECK-NEXT: SegmentInfo: # CHECK-NEXT: - Index: 0 # CHECK-NEXT: Name: .rodata.hidden_data diff --git a/llvm/test/MC/WebAssembly/tail-call-encodings.s b/llvm/test/MC/WebAssembly/tail-call-encodings.s --- a/llvm/test/MC/WebAssembly/tail-call-encodings.s +++ b/llvm/test/MC/WebAssembly/tail-call-encodings.s @@ -1,4 +1,5 @@ # RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+tail-call < %s | FileCheck %s +# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+reference-types,+tail-call < %s | FileCheck --check-prefix=REF %s bar1: .functype bar1 () -> () @@ -16,7 +17,8 @@ foo2: .functype foo2 () -> () - # CHECK: return_call_indirect (i32) -> (i32) # encoding: [0x13, + # REF: return_call_indirect (i32) -> (i32), __indirect_function_table # encoding: [0x13, + # CHECK: return_call_indirect (i32) -> (i32), 0 # encoding: [0x13, # CHECK-NEXT: fixup A - offset: 1, value: .Ltypeindex0@TYPEINDEX, kind: fixup_uleb128_i32 return_call_indirect (i32) -> (i32) 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 @@ -1,8 +1,8 @@ -# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s # Check that it converts to .o without errors: -# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+reference-types,+unimplemented-simd128,+nontrapping-fptoint,+exception-handling < %s | obj2yaml | FileCheck -check-prefix=BIN %s -# Minimal test for type indices in call_indirect. +# Minimal test for type indices and table references in call_indirect. test0: .functype test0 (i32) -> (i32) @@ -53,10 +53,13 @@ # BIN-NEXT: - Type: R_WASM_TYPE_INDEX_LEB # BIN-NEXT: Index: 1 # BIN-NEXT: Offset: 0x4 +# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB +# BIN-NEXT: Index: 1 +# BIN-NEXT: Offset: 0x9 # BIN-NEXT: Functions: # BIN-NEXT: - Index: 0 # BIN-NEXT: Locals: [] -# BIN-NEXT: Body: 118180808000000B +# BIN-NEXT: Body: 11818080800080808080000B # BIN-NEXT: - Type: CUSTOM # BIN-NEXT: Name: linking # BIN-NEXT: Version: 2 @@ -66,4 +69,9 @@ # BIN-NEXT: Name: test0 # BIN-NEXT: Flags: [ BINDING_LOCAL ] # BIN-NEXT: Function: 0 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Name: __indirect_function_table +# BIN-NEXT: Flags: [ UNDEFINED ] +# BIN-NEXT: Table: 0 # BIN-NEXT: ... diff --git a/llvm/test/MC/WebAssembly/weak-alias.s b/llvm/test/MC/WebAssembly/weak-alias.s --- a/llvm/test/MC/WebAssembly/weak-alias.s +++ b/llvm/test/MC/WebAssembly/weak-alias.s @@ -1,5 +1,5 @@ -# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -o %t.o < %s -# RUN: obj2yaml %t.o | FileCheck %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=CHECK %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck --check-prefix=REF %s # 'foo_alias()' is weak alias of function 'foo()' # 'bar_alias' is weak alias of global variable 'bar' @@ -78,7 +78,7 @@ # CHECK: - Type: TYPE # CHECK-NEXT: Signatures: # CHECK-NEXT: - Index: 0 -# CHECK-NEXT: ParamTypes: +# CHECK-NEXT: ParamTypes: [] # CHECK-NEXT: ReturnTypes: # CHECK-NEXT: - I32 # CHECK-NEXT: - Type: IMPORT @@ -128,19 +128,19 @@ # CHECK-NEXT: Offset: 0x37 # CHECK-NEXT: Functions: # CHECK-NEXT: - Index: 0 -# CHECK-NEXT: Locals: +# CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 41000B # CHECK-NEXT: - Index: 1 -# CHECK-NEXT: Locals: +# CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 1080808080000B # CHECK-NEXT: - Index: 2 -# CHECK-NEXT: Locals: +# CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 1080808080000B # CHECK-NEXT: - Index: 3 -# CHECK-NEXT: Locals: +# CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 410028028880808000118080808000000B # CHECK-NEXT: - Index: 4 -# CHECK-NEXT: Locals: +# CHECK-NEXT: Locals: [] # CHECK-NEXT: Body: 410028029080808000118080808000000B # CHECK-NEXT: - Type: DATA # CHECK-NEXT: Relocations: @@ -231,17 +231,195 @@ # CHECK-NEXT: - Index: 0 # CHECK-NEXT: Name: .data.bar # CHECK-NEXT: Alignment: 3 -# CHECK-NEXT: Flags: [ ] +# CHECK-NEXT: Flags: [ ] # CHECK-NEXT: - Index: 1 # CHECK-NEXT: Name: .data.direct_address # CHECK-NEXT: Alignment: 3 -# CHECK-NEXT: Flags: [ ] +# CHECK-NEXT: Flags: [ ] # CHECK-NEXT: - Index: 2 # CHECK-NEXT: Name: .data.alias_address # CHECK-NEXT: Alignment: 3 -# CHECK-NEXT: Flags: [ ] +# CHECK-NEXT: Flags: [ ] # CHECK-NEXT: ... +# REF: - Type: TYPE +# REF-NEXT: Signatures: +# REF-NEXT: - Index: 0 +# REF-NEXT: ParamTypes: [] +# REF-NEXT: ReturnTypes: +# REF-NEXT: - I32 +# REF-NEXT: - Type: IMPORT +# REF-NEXT: Imports: +# REF-NEXT: - Module: env +# REF-NEXT: Field: __linear_memory +# REF-NEXT: Kind: MEMORY +# REF-NEXT: Memory: +# REF-NEXT: Initial: 0x1 +# REF-NEXT: - Module: env +# REF-NEXT: Field: __indirect_function_table +# REF-NEXT: Kind: TABLE +# REF-NEXT: Table: +# REF-NEXT: Index: 0 +# REF-NEXT: ElemType: FUNCREF +# REF-NEXT: Limits: +# REF-NEXT: Initial: 0x1 +# REF-NEXT: - Type: FUNCTION +# REF-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ] +# REF-NEXT: - Type: ELEM +# REF-NEXT: Segments: +# REF-NEXT: - Offset: +# REF-NEXT: Opcode: I32_CONST +# REF-NEXT: Value: 1 +# REF-NEXT: Functions: [ 0 ] +# REF-NEXT: - Type: DATACOUNT +# REF-NEXT: Count: 3 +# REF-NEXT: - Type: CODE +# REF-NEXT: Relocations: +# REF-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB +# REF-NEXT: Index: 0 +# REF-NEXT: Offset: 0x9 +# REF-NEXT: - Type: R_WASM_FUNCTION_INDEX_LEB +# REF-NEXT: Index: 3 +# REF-NEXT: Offset: 0x12 +# REF-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# REF-NEXT: Index: 5 +# REF-NEXT: Offset: 0x1E +# REF-NEXT: - Type: R_WASM_TYPE_INDEX_LEB +# REF-NEXT: Index: 0 +# REF-NEXT: Offset: 0x24 +# REF-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB +# REF-NEXT: Index: 6 +# REF-NEXT: Offset: 0x29 +# REF-NEXT: - Type: R_WASM_MEMORY_ADDR_LEB +# REF-NEXT: Index: 8 +# REF-NEXT: Offset: 0x35 +# REF-NEXT: - Type: R_WASM_TYPE_INDEX_LEB +# REF-NEXT: Index: 0 +# REF-NEXT: Offset: 0x3B +# REF-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB +# REF-NEXT: Index: 6 +# REF-NEXT: Offset: 0x40 +# REF-NEXT: Functions: +# REF-NEXT: - Index: 0 +# REF-NEXT: Locals: [] +# REF-NEXT: Body: 41000B +# REF-NEXT: - Index: 1 +# REF-NEXT: Locals: [] +# REF-NEXT: Body: 1080808080000B +# REF-NEXT: - Index: 2 +# REF-NEXT: Locals: [] +# REF-NEXT: Body: 1080808080000B +# REF-NEXT: - Index: 3 +# REF-NEXT: Locals: [] +# REF-NEXT: Body: 41002802888080800011808080800080808080000B +# REF-NEXT: - Index: 4 +# REF-NEXT: Locals: [] +# REF-NEXT: Body: 41002802908080800011808080800080808080000B +# REF-NEXT: - Type: DATA +# REF-NEXT: Relocations: +# REF-NEXT: - Type: R_WASM_TABLE_INDEX_I32 +# REF-NEXT: Index: 0 +# REF-NEXT: Offset: 0x13 +# REF-NEXT: - Type: R_WASM_TABLE_INDEX_I32 +# REF-NEXT: Index: 3 +# REF-NEXT: Offset: 0x20 +# REF-NEXT: Segments: +# REF-NEXT: - SectionOffset: 6 +# REF-NEXT: InitFlags: 0 +# REF-NEXT: Offset: +# REF-NEXT: Opcode: I32_CONST +# REF-NEXT: Value: 0 +# REF-NEXT: Content: '0700000000000000' +# REF-NEXT: - SectionOffset: 19 +# REF-NEXT: InitFlags: 0 +# REF-NEXT: Offset: +# REF-NEXT: Opcode: I32_CONST +# REF-NEXT: Value: 8 +# REF-NEXT: Content: '0100000000000000' +# REF-NEXT: - SectionOffset: 32 +# REF-NEXT: InitFlags: 0 +# REF-NEXT: Offset: +# REF-NEXT: Opcode: I32_CONST +# REF-NEXT: Value: 16 +# REF-NEXT: Content: '0100000000000000' +# REF-NEXT: - Type: CUSTOM +# REF-NEXT: Name: linking +# REF-NEXT: Version: 2 +# REF-NEXT: SymbolTable: +# REF-NEXT: - Index: 0 +# REF-NEXT: Kind: FUNCTION +# REF-NEXT: Name: foo +# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ] +# REF-NEXT: Function: 0 +# REF-NEXT: - Index: 1 +# REF-NEXT: Kind: FUNCTION +# REF-NEXT: Name: call_direct +# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ] +# REF-NEXT: Function: 1 +# REF-NEXT: - Index: 2 +# REF-NEXT: Kind: FUNCTION +# REF-NEXT: Name: call_alias +# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ] +# REF-NEXT: Function: 2 +# REF-NEXT: - Index: 3 +# REF-NEXT: Kind: FUNCTION +# REF-NEXT: Name: foo_alias +# REF-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, NO_STRIP ] +# REF-NEXT: Function: 0 +# REF-NEXT: - Index: 4 +# REF-NEXT: Kind: FUNCTION +# REF-NEXT: Name: call_direct_ptr +# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ] +# REF-NEXT: Function: 3 +# REF-NEXT: - Index: 5 +# REF-NEXT: Kind: DATA +# REF-NEXT: Name: direct_address +# REF-NEXT: Flags: [ ] +# REF-NEXT: Segment: 1 +# REF-NEXT: Size: 4 +# REF-NEXT: - Index: 6 +# REF-NEXT: Kind: TABLE +# REF-NEXT: Name: __indirect_function_table +# REF-NEXT: Flags: [ UNDEFINED, NO_STRIP ] +# REF-NEXT: Table: 0 +# REF-NEXT: - Index: 7 +# REF-NEXT: Kind: FUNCTION +# REF-NEXT: Name: call_alias_ptr +# REF-NEXT: Flags: [ VISIBILITY_HIDDEN ] +# REF-NEXT: Function: 4 +# REF-NEXT: - Index: 8 +# REF-NEXT: Kind: DATA +# REF-NEXT: Name: alias_address +# REF-NEXT: Flags: [ ] +# REF-NEXT: Segment: 2 +# REF-NEXT: Size: 4 +# REF-NEXT: - Index: 9 +# REF-NEXT: Kind: DATA +# REF-NEXT: Name: bar +# REF-NEXT: Flags: [ ] +# REF-NEXT: Segment: 0 +# REF-NEXT: Size: 4 +# REF-NEXT: - Index: 10 +# REF-NEXT: Kind: DATA +# REF-NEXT: Name: bar_alias +# REF-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, NO_STRIP ] +# REF-NEXT: Segment: 0 +# REF-NEXT: Size: 4 +# REF-NEXT: SegmentInfo: +# REF-NEXT: - Index: 0 +# REF-NEXT: Name: .data.bar +# REF-NEXT: Alignment: 3 +# REF-NEXT: Flags: [ ] +# REF-NEXT: - Index: 1 +# REF-NEXT: Name: .data.direct_address +# REF-NEXT: Alignment: 3 +# REF-NEXT: Flags: [ ] +# REF-NEXT: - Index: 2 +# REF-NEXT: Name: .data.alias_address +# REF-NEXT: Alignment: 3 +# REF-NEXT: Flags: [ ] +# REF-NEXT: ... + # CHECK-SYMS: SYMBOL TABLE: # CHECK-SYMS-NEXT: 00000001 g F CODE .hidden foo # CHECK-SYMS-NEXT: 00000006 g F CODE .hidden call_direct