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);
+
// Build a map of sections to the function that defines them, for use
// in recordRelocation.
for (const MCSymbol &S : Asm.symbols()) {
}
};
+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<MCSymbolWasm>(Ctx.lookupSymbol(Name));
+ if (Sym) {
+ if (!Sym->isFunctionTable())
+ Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
+ } else {
+ Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
+ Sym->setFunctionTable();
+ // The default function table is synthesized by the linker.
+ Sym->setUndefined();
+ }
+ return Sym;
+}
+
class WebAssemblyAsmParser final : public MCTargetAsmParser {
MCAsmParser &Parser;
MCAsmLexer &Lexer;
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();
} else if (Name == "ref.null") {
ExpectHeapType = true;
}
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/CodeGen/FastISel.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
// Add placeholders for the type index and immediate flags
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();
}
for (unsigned ArgReg : Args)
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
if (IsIndirect) {
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();
}
for (auto Use : CallParams.uses())
#include "WebAssemblyMachineFunctionInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
+#include "llvm/MC/MCContext.h"
using namespace llvm;
const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate";
llvm_unreachable("Not a call instruction");
}
}
+
+MCSymbolWasm *
+WebAssembly::getOrCreateFunctionTableSymbol(MCContext &Ctx,
+ const StringRef &Name) {
+ // FIXME: Duplicates functionality from
+ // MC/WasmObjectWriter::recordRelocation.
+ MCSymbolWasm *Sym = cast_or_null<MCSymbolWasm>(Ctx.lookupSymbol(Name));
+ if (Sym) {
+ if (!Sym->isFunctionTable())
+ Ctx.reportError(SMLoc(), "symbol is not a wasm funcref table");
+ } else {
+ Sym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(Name));
+ Sym->setFunctionTable();
+ // The default function table is synthesized by the linker.
+ Sym->setUndefined();
+ }
+ return Sym;
+}
class MachineInstr;
class MachineOperand;
+class MCContext;
+class MCSymbolWasm;
+class StringRef;
class WebAssemblyFunctionInfo;
namespace WebAssembly {
/// 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);
+
} // end namespace WebAssembly
} // end namespace llvm
--- /dev/null
+; RUN: llc < %s -asm-verbose=false -O2 | FileCheck --check-prefix=CHECK %s
+; RUN: llc < %s -asm-verbose=false -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=OBJ %s
+
+; Test that compilation units with call_indirect but without any
+; function pointer declarations still get a table.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+; CHECK-LABEL: call_indirect_void:
+; CHECK-NEXT: .functype call_indirect_void (i32) -> ()
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call_indirect () -> ()
+; CHECK-NEXT: end_function
+define void @call_indirect_void(void ()* %callee) {
+ call void %callee()
+ ret void
+}
+
+; OBJ: Imports:
+; OBJ-NEXT: - Module: env
+; OBJ-NEXT: Field: __linear_memory
+; OBJ-NEXT: Kind: MEMORY
+; OBJ-NEXT: Memory:
+; OBJ-NEXT: Initial: 0x0
+; OBJ-NEXT: - Module: env
+; OBJ-NEXT: Field: __indirect_function_table
+; OBJ-NEXT: Kind: TABLE
# 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