10b57cec5SDimitry Andric //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric ///
90b57cec5SDimitry Andric /// \file
100b57cec5SDimitry Andric /// This file handles Wasm-specific object emission, converting LLVM's
110b57cec5SDimitry Andric /// internal fixups into the appropriate relocations.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyFixupKinds.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
170b57cec5SDimitry Andric #include "llvm/BinaryFormat/Wasm.h"
180b57cec5SDimitry Andric #include "llvm/MC/MCAsmBackend.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCFixup.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCFixupKindInfo.h"
210b57cec5SDimitry Andric #include "llvm/MC/MCObjectWriter.h"
220b57cec5SDimitry Andric #include "llvm/MC/MCSectionWasm.h"
230b57cec5SDimitry Andric #include "llvm/MC/MCSymbolWasm.h"
240b57cec5SDimitry Andric #include "llvm/MC/MCValue.h"
250b57cec5SDimitry Andric #include "llvm/MC/MCWasmObjectWriter.h"
260b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
270b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {
320b57cec5SDimitry Andric class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
330b57cec5SDimitry Andric public:
348bcb0991SDimitry Andric   explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten);
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric private:
37fe6060f1SDimitry Andric   unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
38fe6060f1SDimitry Andric                         const MCSectionWasm &FixupSection,
39fe6060f1SDimitry Andric                         bool IsLocRel) const override;
400b57cec5SDimitry Andric };
410b57cec5SDimitry Andric } // end anonymous namespace
420b57cec5SDimitry Andric 
438bcb0991SDimitry Andric WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit,
448bcb0991SDimitry Andric                                                          bool IsEmscripten)
458bcb0991SDimitry Andric     : MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {}
460b57cec5SDimitry Andric 
47fe6060f1SDimitry Andric static const MCSection *getTargetSection(const MCExpr *Expr) {
480b57cec5SDimitry Andric   if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
490b57cec5SDimitry Andric     if (SyExp->getSymbol().isInSection())
500b57cec5SDimitry Andric       return &SyExp->getSymbol().getSection();
510b57cec5SDimitry Andric     return nullptr;
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
55fe6060f1SDimitry Andric     auto SectionLHS = getTargetSection(BinOp->getLHS());
56fe6060f1SDimitry Andric     auto SectionRHS = getTargetSection(BinOp->getRHS());
570b57cec5SDimitry Andric     return SectionLHS == SectionRHS ? nullptr : SectionLHS;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
61fe6060f1SDimitry Andric     return getTargetSection(UnOp->getSubExpr());
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   return nullptr;
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric 
66fe6060f1SDimitry Andric unsigned WebAssemblyWasmObjectWriter::getRelocType(
67fe6060f1SDimitry Andric     const MCValue &Target, const MCFixup &Fixup,
68fe6060f1SDimitry Andric     const MCSectionWasm &FixupSection, bool IsLocRel) const {
690b57cec5SDimitry Andric   const MCSymbolRefExpr *RefA = Target.getSymA();
700b57cec5SDimitry Andric   assert(RefA);
710b57cec5SDimitry Andric   auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
740b57cec5SDimitry Andric 
750b57cec5SDimitry Andric   switch (Modifier) {
760b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_GOT:
77349cc55cSDimitry Andric     case MCSymbolRefExpr::VK_WASM_GOT_TLS:
780b57cec5SDimitry Andric       return wasm::R_WASM_GLOBAL_INDEX_LEB;
790b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_WASM_TBREL:
800b57cec5SDimitry Andric       assert(SymA.isFunction());
81fe6060f1SDimitry Andric       return is64Bit() ? wasm::R_WASM_TABLE_INDEX_REL_SLEB64
82fe6060f1SDimitry Andric                        : wasm::R_WASM_TABLE_INDEX_REL_SLEB;
83e8d8bef9SDimitry Andric     case MCSymbolRefExpr::VK_WASM_TLSREL:
84fe6060f1SDimitry Andric       return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64
85fe6060f1SDimitry Andric                        : wasm::R_WASM_MEMORY_ADDR_TLS_SLEB;
860b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_WASM_MBREL:
870b57cec5SDimitry Andric       assert(SymA.isData());
885ffd83dbSDimitry Andric       return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB64
895ffd83dbSDimitry Andric                        : wasm::R_WASM_MEMORY_ADDR_REL_SLEB;
900b57cec5SDimitry Andric     case MCSymbolRefExpr::VK_WASM_TYPEINDEX:
910b57cec5SDimitry Andric       return wasm::R_WASM_TYPE_INDEX_LEB;
92349cc55cSDimitry Andric     case MCSymbolRefExpr::VK_None:
93349cc55cSDimitry Andric       break;
9406c3fb27SDimitry Andric     case MCSymbolRefExpr::VK_WASM_FUNCINDEX:
9506c3fb27SDimitry Andric       return wasm::R_WASM_FUNCTION_INDEX_I32;
960b57cec5SDimitry Andric     default:
97349cc55cSDimitry Andric       report_fatal_error("unknown VariantKind");
980b57cec5SDimitry Andric       break;
990b57cec5SDimitry Andric   }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   switch (unsigned(Fixup.getKind())) {
1020b57cec5SDimitry Andric   case WebAssembly::fixup_sleb128_i32:
1030b57cec5SDimitry Andric     if (SymA.isFunction())
1040b57cec5SDimitry Andric       return wasm::R_WASM_TABLE_INDEX_SLEB;
1050b57cec5SDimitry Andric     return wasm::R_WASM_MEMORY_ADDR_SLEB;
1060b57cec5SDimitry Andric   case WebAssembly::fixup_sleb128_i64:
107e8d8bef9SDimitry Andric     if (SymA.isFunction())
108e8d8bef9SDimitry Andric       return wasm::R_WASM_TABLE_INDEX_SLEB64;
1095ffd83dbSDimitry Andric     return wasm::R_WASM_MEMORY_ADDR_SLEB64;
1100b57cec5SDimitry Andric   case WebAssembly::fixup_uleb128_i32:
1110b57cec5SDimitry Andric     if (SymA.isGlobal())
1120b57cec5SDimitry Andric       return wasm::R_WASM_GLOBAL_INDEX_LEB;
1130b57cec5SDimitry Andric     if (SymA.isFunction())
1140b57cec5SDimitry Andric       return wasm::R_WASM_FUNCTION_INDEX_LEB;
115fe6060f1SDimitry Andric     if (SymA.isTag())
116fe6060f1SDimitry Andric       return wasm::R_WASM_TAG_INDEX_LEB;
117e8d8bef9SDimitry Andric     if (SymA.isTable())
118e8d8bef9SDimitry Andric       return wasm::R_WASM_TABLE_NUMBER_LEB;
1190b57cec5SDimitry Andric     return wasm::R_WASM_MEMORY_ADDR_LEB;
1205ffd83dbSDimitry Andric   case WebAssembly::fixup_uleb128_i64:
1215ffd83dbSDimitry Andric     assert(SymA.isData());
1225ffd83dbSDimitry Andric     return wasm::R_WASM_MEMORY_ADDR_LEB64;
1230b57cec5SDimitry Andric   case FK_Data_4:
124fe6060f1SDimitry Andric     if (SymA.isFunction()) {
125*0fca6ea1SDimitry Andric       if (FixupSection.isMetadata())
126fe6060f1SDimitry Andric         return wasm::R_WASM_FUNCTION_OFFSET_I32;
127fe6060f1SDimitry Andric       assert(FixupSection.isWasmData());
1280b57cec5SDimitry Andric       return wasm::R_WASM_TABLE_INDEX_I32;
129fe6060f1SDimitry Andric     }
1305ffd83dbSDimitry Andric     if (SymA.isGlobal())
1315ffd83dbSDimitry Andric       return wasm::R_WASM_GLOBAL_INDEX_I32;
1320b57cec5SDimitry Andric     if (auto Section = static_cast<const MCSectionWasm *>(
133fe6060f1SDimitry Andric             getTargetSection(Fixup.getValue()))) {
134*0fca6ea1SDimitry Andric       if (Section->isText())
1350b57cec5SDimitry Andric         return wasm::R_WASM_FUNCTION_OFFSET_I32;
1360b57cec5SDimitry Andric       else if (!Section->isWasmData())
1370b57cec5SDimitry Andric         return wasm::R_WASM_SECTION_OFFSET_I32;
1380b57cec5SDimitry Andric     }
139fe6060f1SDimitry Andric     return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
140fe6060f1SDimitry Andric                     : wasm::R_WASM_MEMORY_ADDR_I32;
1415ffd83dbSDimitry Andric   case FK_Data_8:
142fe6060f1SDimitry Andric     if (SymA.isFunction()) {
143*0fca6ea1SDimitry Andric       if (FixupSection.isMetadata())
144fe6060f1SDimitry Andric         return wasm::R_WASM_FUNCTION_OFFSET_I64;
145e8d8bef9SDimitry Andric       return wasm::R_WASM_TABLE_INDEX_I64;
146fe6060f1SDimitry Andric     }
147e8d8bef9SDimitry Andric     if (SymA.isGlobal())
148e8d8bef9SDimitry Andric       llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64");
149e8d8bef9SDimitry Andric     if (auto Section = static_cast<const MCSectionWasm *>(
150fe6060f1SDimitry Andric             getTargetSection(Fixup.getValue()))) {
151*0fca6ea1SDimitry Andric       if (Section->isText())
152e8d8bef9SDimitry Andric         return wasm::R_WASM_FUNCTION_OFFSET_I64;
153e8d8bef9SDimitry Andric       else if (!Section->isWasmData())
154e8d8bef9SDimitry Andric         llvm_unreachable("unimplemented R_WASM_SECTION_OFFSET_I64");
155e8d8bef9SDimitry Andric     }
1565ffd83dbSDimitry Andric     assert(SymA.isData());
1575ffd83dbSDimitry Andric     return wasm::R_WASM_MEMORY_ADDR_I64;
1580b57cec5SDimitry Andric   default:
1590b57cec5SDimitry Andric     llvm_unreachable("unimplemented fixup kind");
1600b57cec5SDimitry Andric   }
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric std::unique_ptr<MCObjectTargetWriter>
1648bcb0991SDimitry Andric llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) {
1658bcb0991SDimitry Andric   return std::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit, IsEmscripten);
1660b57cec5SDimitry Andric }
167