1 //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file handles Wasm-specific object emission, converting LLVM's
11 /// internal fixups into the appropriate relocations.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #include "MCTargetDesc/WebAssemblyFixupKinds.h"
16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17 #include "llvm/BinaryFormat/Wasm.h"
18 #include "llvm/MC/MCAsmBackend.h"
19 #include "llvm/MC/MCFixup.h"
20 #include "llvm/MC/MCFixupKindInfo.h"
21 #include "llvm/MC/MCObjectWriter.h"
22 #include "llvm/MC/MCSectionWasm.h"
23 #include "llvm/MC/MCSymbolWasm.h"
24 #include "llvm/MC/MCValue.h"
25 #include "llvm/MC/MCWasmObjectWriter.h"
26 #include "llvm/Support/Casting.h"
27 #include "llvm/Support/ErrorHandling.h"
28 
29 using namespace llvm;
30 
31 namespace {
32 class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
33 public:
34   explicit WebAssemblyWasmObjectWriter(bool Is64Bit);
35 
36 private:
37   unsigned getRelocType(const MCValue &Target,
38                         const MCFixup &Fixup) const override;
39 };
40 } // end anonymous namespace
41 
42 WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
43     : MCWasmObjectTargetWriter(Is64Bit) {}
44 
45 static bool isFunctionSignatureRef(const MCSymbolRefExpr *Ref) {
46   return Ref->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
47 }
48 
49 static const MCSection *getFixupSection(const MCExpr *Expr) {
50   if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
51     if (SyExp->getSymbol().isInSection())
52       return &SyExp->getSymbol().getSection();
53     return nullptr;
54   }
55 
56   if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
57     auto SectionLHS = getFixupSection(BinOp->getLHS());
58     auto SectionRHS = getFixupSection(BinOp->getRHS());
59     return SectionLHS == SectionRHS ? nullptr : SectionLHS;
60   }
61 
62   if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
63     return getFixupSection(UnOp->getSubExpr());
64 
65   return nullptr;
66 }
67 
68 unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
69                                                    const MCFixup &Fixup) const {
70   const MCSymbolRefExpr *RefA = Target.getSymA();
71   assert(RefA);
72   auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
73 
74   switch (unsigned(Fixup.getKind())) {
75   case WebAssembly::fixup_code_sleb128_i32:
76     if (SymA.isFunction())
77       return wasm::R_WASM_TABLE_INDEX_SLEB;
78     return wasm::R_WASM_MEMORY_ADDR_SLEB;
79   case WebAssembly::fixup_code_sleb128_i64:
80     llvm_unreachable("fixup_sleb128_i64 not implemented yet");
81   case WebAssembly::fixup_code_uleb128_i32:
82     if (SymA.isFunction()) {
83       if (isFunctionSignatureRef(RefA))
84         return wasm::R_WASM_TYPE_INDEX_LEB;
85       else
86         return wasm::R_WASM_FUNCTION_INDEX_LEB;
87     }
88     if (SymA.isGlobal())
89       return wasm::R_WASM_GLOBAL_INDEX_LEB;
90     if (SymA.isEvent())
91       return wasm::R_WASM_EVENT_INDEX_LEB;
92     return wasm::R_WASM_MEMORY_ADDR_LEB;
93   case FK_Data_4:
94     if (SymA.isFunction())
95       return wasm::R_WASM_TABLE_INDEX_I32;
96     if (auto Section = static_cast<const MCSectionWasm *>(
97             getFixupSection(Fixup.getValue()))) {
98       if (Section->getKind().isText())
99         return wasm::R_WASM_FUNCTION_OFFSET_I32;
100       else if (!Section->isWasmData())
101         return wasm::R_WASM_SECTION_OFFSET_I32;
102     }
103     return wasm::R_WASM_MEMORY_ADDR_I32;
104   case FK_Data_8:
105     llvm_unreachable("FK_Data_8 not implemented yet");
106   default:
107     llvm_unreachable("unimplemented fixup kind");
108   }
109 }
110 
111 std::unique_ptr<MCObjectTargetWriter>
112 llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit) {
113   return llvm::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit);
114 }
115