118eafb6cSDan Gohman //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===//
218eafb6cSDan Gohman //
318eafb6cSDan Gohman //                     The LLVM Compiler Infrastructure
418eafb6cSDan Gohman //
518eafb6cSDan Gohman // This file is distributed under the University of Illinois Open Source
618eafb6cSDan Gohman // License. See LICENSE.TXT for details.
718eafb6cSDan Gohman //
818eafb6cSDan Gohman //===----------------------------------------------------------------------===//
918eafb6cSDan Gohman ///
1018eafb6cSDan Gohman /// \file
1118eafb6cSDan Gohman /// \brief This file handles Wasm-specific object emission, converting LLVM's
1218eafb6cSDan Gohman /// internal fixups into the appropriate relocations.
1318eafb6cSDan Gohman ///
1418eafb6cSDan Gohman //===----------------------------------------------------------------------===//
1518eafb6cSDan Gohman 
16d934cb88SDan Gohman #include "MCTargetDesc/WebAssemblyFixupKinds.h"
176bda14b3SChandler Carruth #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
1818eafb6cSDan Gohman #include "llvm/MC/MCFixup.h"
19d934cb88SDan Gohman #include "llvm/MC/MCSymbolWasm.h"
2018eafb6cSDan Gohman #include "llvm/MC/MCWasmObjectWriter.h"
21d934cb88SDan Gohman #include "llvm/Support/Casting.h"
2218eafb6cSDan Gohman #include "llvm/Support/ErrorHandling.h"
23d934cb88SDan Gohman #include "llvm/Support/Wasm.h"
2418eafb6cSDan Gohman using namespace llvm;
2518eafb6cSDan Gohman 
2618eafb6cSDan Gohman namespace {
2718eafb6cSDan Gohman class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
2818eafb6cSDan Gohman public:
2918eafb6cSDan Gohman   explicit WebAssemblyWasmObjectWriter(bool Is64Bit);
3018eafb6cSDan Gohman 
3118eafb6cSDan Gohman private:
3218eafb6cSDan Gohman   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
3318eafb6cSDan Gohman                         const MCFixup &Fixup, bool IsPCRel) const override;
3418eafb6cSDan Gohman };
3518eafb6cSDan Gohman } // end anonymous namespace
3618eafb6cSDan Gohman 
3718eafb6cSDan Gohman WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
3818eafb6cSDan Gohman     : MCWasmObjectTargetWriter(Is64Bit) {}
3918eafb6cSDan Gohman 
40d934cb88SDan Gohman // Test whether the given expression computes a function address.
41d934cb88SDan Gohman static bool IsFunctionExpr(const MCExpr *Expr) {
42d934cb88SDan Gohman   if (const MCSymbolRefExpr *SyExp =
43d934cb88SDan Gohman           dyn_cast<MCSymbolRefExpr>(Expr))
44d934cb88SDan Gohman     return cast<MCSymbolWasm>(SyExp->getSymbol()).isFunction();
45d934cb88SDan Gohman 
46d934cb88SDan Gohman   if (const MCBinaryExpr *BinOp =
47d934cb88SDan Gohman           dyn_cast<MCBinaryExpr>(Expr))
48d934cb88SDan Gohman     return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS());
49d934cb88SDan Gohman 
50d934cb88SDan Gohman   if (const MCUnaryExpr *UnOp =
51d934cb88SDan Gohman           dyn_cast<MCUnaryExpr>(Expr))
52d934cb88SDan Gohman     return IsFunctionExpr(UnOp->getSubExpr());
53d934cb88SDan Gohman 
54d934cb88SDan Gohman   return false;
55d934cb88SDan Gohman }
56d934cb88SDan Gohman 
57*acd7d2b0SSam Clegg static bool IsFunctionType(const MCValue &Target) {
58*acd7d2b0SSam Clegg   const MCSymbolRefExpr *RefA = Target.getSymA();
59*acd7d2b0SSam Clegg   return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
60*acd7d2b0SSam Clegg }
61*acd7d2b0SSam Clegg 
6218eafb6cSDan Gohman unsigned WebAssemblyWasmObjectWriter::getRelocType(MCContext &Ctx,
6318eafb6cSDan Gohman                                                    const MCValue &Target,
6418eafb6cSDan Gohman                                                    const MCFixup &Fixup,
6518eafb6cSDan Gohman                                                    bool IsPCRel) const {
66d934cb88SDan Gohman   // WebAssembly functions are not allocated in the data address space. To
67d934cb88SDan Gohman   // resolve a pointer to a function, we must use a special relocation type.
68d934cb88SDan Gohman   bool IsFunction = IsFunctionExpr(Fixup.getValue());
69d934cb88SDan Gohman 
70d934cb88SDan Gohman   assert(!IsPCRel);
71d934cb88SDan Gohman   switch (unsigned(Fixup.getKind())) {
72d934cb88SDan Gohman   case WebAssembly::fixup_code_sleb128_i32:
73d934cb88SDan Gohman     if (IsFunction)
74d934cb88SDan Gohman       return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
75d934cb88SDan Gohman     return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB;
76d934cb88SDan Gohman   case WebAssembly::fixup_code_sleb128_i64:
77d934cb88SDan Gohman     llvm_unreachable("fixup_sleb128_i64 not implemented yet");
78d934cb88SDan Gohman   case WebAssembly::fixup_code_uleb128_i32:
79*acd7d2b0SSam Clegg     if (IsFunctionType(Target))
80*acd7d2b0SSam Clegg       return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB;
81d934cb88SDan Gohman     if (IsFunction)
82d934cb88SDan Gohman       return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
83d934cb88SDan Gohman     return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB;
84d934cb88SDan Gohman   case FK_Data_4:
85d934cb88SDan Gohman     if (IsFunction)
86d934cb88SDan Gohman       return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
87d934cb88SDan Gohman     return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32;
88d934cb88SDan Gohman   case FK_Data_8:
89d934cb88SDan Gohman     llvm_unreachable("FK_Data_8 not implemented yet");
90d934cb88SDan Gohman   default:
91d934cb88SDan Gohman     llvm_unreachable("unimplemented fixup kind");
92d934cb88SDan Gohman   }
9318eafb6cSDan Gohman }
9418eafb6cSDan Gohman 
9518eafb6cSDan Gohman MCObjectWriter *llvm::createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS,
9618eafb6cSDan Gohman                                                         bool Is64Bit) {
9718eafb6cSDan Gohman   MCWasmObjectTargetWriter *MOTW = new WebAssemblyWasmObjectWriter(Is64Bit);
9818eafb6cSDan Gohman   return createWasmObjectWriter(MOTW, OS);
9918eafb6cSDan Gohman }
100