118eafb6cSDan Gohman //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===//
218eafb6cSDan Gohman //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
618eafb6cSDan Gohman //
718eafb6cSDan Gohman //===----------------------------------------------------------------------===//
818eafb6cSDan Gohman ///
918eafb6cSDan Gohman /// \file
105f8f34e4SAdrian Prantl /// This file handles Wasm-specific object emission, converting LLVM's
1118eafb6cSDan Gohman /// internal fixups into the appropriate relocations.
1218eafb6cSDan Gohman ///
1318eafb6cSDan Gohman //===----------------------------------------------------------------------===//
1418eafb6cSDan Gohman 
15d934cb88SDan Gohman #include "MCTargetDesc/WebAssemblyFixupKinds.h"
166bda14b3SChandler Carruth #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
17264b5d9eSZachary Turner #include "llvm/BinaryFormat/Wasm.h"
18ae03c1e7SSam Clegg #include "llvm/MC/MCAsmBackend.h"
1918eafb6cSDan Gohman #include "llvm/MC/MCFixup.h"
20ae03c1e7SSam Clegg #include "llvm/MC/MCFixupKindInfo.h"
21669300dbSDerek Schuff #include "llvm/MC/MCObjectWriter.h"
226a31a0d6SSam Clegg #include "llvm/MC/MCSectionWasm.h"
23d934cb88SDan Gohman #include "llvm/MC/MCSymbolWasm.h"
24ae03c1e7SSam Clegg #include "llvm/MC/MCValue.h"
256a31a0d6SSam Clegg #include "llvm/MC/MCWasmObjectWriter.h"
26d934cb88SDan Gohman #include "llvm/Support/Casting.h"
2718eafb6cSDan Gohman #include "llvm/Support/ErrorHandling.h"
28ae03c1e7SSam Clegg 
2918eafb6cSDan Gohman using namespace llvm;
3018eafb6cSDan Gohman 
3118eafb6cSDan Gohman namespace {
3218eafb6cSDan Gohman class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
3318eafb6cSDan Gohman public:
34da84b688SDan Gohman   explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten);
3518eafb6cSDan Gohman 
3618eafb6cSDan Gohman private:
37aa0c571aSYuta Saito   unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,
38aa0c571aSYuta Saito                         bool IsLocRel) const override;
3918eafb6cSDan Gohman };
4018eafb6cSDan Gohman } // end anonymous namespace
4118eafb6cSDan Gohman 
42da84b688SDan Gohman WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit,
43da84b688SDan Gohman                                                          bool IsEmscripten)
44da84b688SDan Gohman     : MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {}
4518eafb6cSDan Gohman 
4618c56a07SHeejin Ahn static const MCSection *getFixupSection(const MCExpr *Expr) {
476a31a0d6SSam Clegg   if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
486a31a0d6SSam Clegg     if (SyExp->getSymbol().isInSection())
496a31a0d6SSam Clegg       return &SyExp->getSymbol().getSection();
506a31a0d6SSam Clegg     return nullptr;
516a31a0d6SSam Clegg   }
526a31a0d6SSam Clegg 
536a31a0d6SSam Clegg   if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
5418c56a07SHeejin Ahn     auto SectionLHS = getFixupSection(BinOp->getLHS());
5518c56a07SHeejin Ahn     auto SectionRHS = getFixupSection(BinOp->getRHS());
566a31a0d6SSam Clegg     return SectionLHS == SectionRHS ? nullptr : SectionLHS;
576a31a0d6SSam Clegg   }
586a31a0d6SSam Clegg 
596a31a0d6SSam Clegg   if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
6018c56a07SHeejin Ahn     return getFixupSection(UnOp->getSubExpr());
616a31a0d6SSam Clegg 
626a31a0d6SSam Clegg   return nullptr;
636a31a0d6SSam Clegg }
646a31a0d6SSam Clegg 
65f208f631SHeejin Ahn unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
66aa0c571aSYuta Saito                                                    const MCFixup &Fixup,
67aa0c571aSYuta Saito                                                    bool IsLocRel) const {
688fffa1dfSSam Clegg   const MCSymbolRefExpr *RefA = Target.getSymA();
698fffa1dfSSam Clegg   assert(RefA);
708fffa1dfSSam Clegg   auto& SymA = cast<MCSymbolWasm>(RefA->getSymbol());
71d934cb88SDan Gohman 
722a7cac93SSam Clegg   MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant();
732a7cac93SSam Clegg 
742a7cac93SSam Clegg   switch (Modifier) {
752a7cac93SSam Clegg     case MCSymbolRefExpr::VK_GOT:
762a7cac93SSam Clegg       return wasm::R_WASM_GLOBAL_INDEX_LEB;
772a7cac93SSam Clegg     case MCSymbolRefExpr::VK_WASM_TBREL:
782a7cac93SSam Clegg       assert(SymA.isFunction());
79*3a293cbfSWouter van Oortmerssen       return is64Bit() ? wasm::R_WASM_TABLE_INDEX_REL_SLEB64
80*3a293cbfSWouter van Oortmerssen                        : wasm::R_WASM_TABLE_INDEX_REL_SLEB;
81a28a4662SSam Clegg     case MCSymbolRefExpr::VK_WASM_TLSREL:
82a28a4662SSam Clegg       return wasm::R_WASM_MEMORY_ADDR_TLS_SLEB;
832a7cac93SSam Clegg     case MCSymbolRefExpr::VK_WASM_MBREL:
842a7cac93SSam Clegg       assert(SymA.isData());
853b29376eSWouter van Oortmerssen       return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB64
863b29376eSWouter van Oortmerssen                        : wasm::R_WASM_MEMORY_ADDR_REL_SLEB;
872a7cac93SSam Clegg     case MCSymbolRefExpr::VK_WASM_TYPEINDEX:
882a7cac93SSam Clegg       return wasm::R_WASM_TYPE_INDEX_LEB;
892a7cac93SSam Clegg     default:
902a7cac93SSam Clegg       break;
912a7cac93SSam Clegg   }
922a7cac93SSam Clegg 
93d934cb88SDan Gohman   switch (unsigned(Fixup.getKind())) {
94a5e175c6SSam Clegg   case WebAssembly::fixup_sleb128_i32:
958fffa1dfSSam Clegg     if (SymA.isFunction())
96d1152a26SSam Clegg       return wasm::R_WASM_TABLE_INDEX_SLEB;
97d1152a26SSam Clegg     return wasm::R_WASM_MEMORY_ADDR_SLEB;
983b29376eSWouter van Oortmerssen   case WebAssembly::fixup_sleb128_i64:
99cc1b9b68SWouter van Oortmerssen     if (SymA.isFunction())
100cc1b9b68SWouter van Oortmerssen       return wasm::R_WASM_TABLE_INDEX_SLEB64;
1013b29376eSWouter van Oortmerssen     return wasm::R_WASM_MEMORY_ADDR_SLEB64;
102a5e175c6SSam Clegg   case WebAssembly::fixup_uleb128_i32:
1032a7cac93SSam Clegg     if (SymA.isGlobal())
104492f7529SSam Clegg       return wasm::R_WASM_GLOBAL_INDEX_LEB;
1052a7cac93SSam Clegg     if (SymA.isFunction())
106d1152a26SSam Clegg       return wasm::R_WASM_FUNCTION_INDEX_LEB;
1078fffa1dfSSam Clegg     if (SymA.isEvent())
108d1152a26SSam Clegg       return wasm::R_WASM_EVENT_INDEX_LEB;
10969e2797eSPaulo Matos     if (SymA.isTable())
11069e2797eSPaulo Matos       return wasm::R_WASM_TABLE_NUMBER_LEB;
111d1152a26SSam Clegg     return wasm::R_WASM_MEMORY_ADDR_LEB;
1123b29376eSWouter van Oortmerssen   case WebAssembly::fixup_uleb128_i64:
1133b29376eSWouter van Oortmerssen     assert(SymA.isData());
1143b29376eSWouter van Oortmerssen     return wasm::R_WASM_MEMORY_ADDR_LEB64;
115d934cb88SDan Gohman   case FK_Data_4:
1168fffa1dfSSam Clegg     if (SymA.isFunction())
117d1152a26SSam Clegg       return wasm::R_WASM_TABLE_INDEX_I32;
11848139ebcSWouter van Oortmerssen     if (SymA.isGlobal())
11948139ebcSWouter van Oortmerssen       return wasm::R_WASM_GLOBAL_INDEX_I32;
1206a31a0d6SSam Clegg     if (auto Section = static_cast<const MCSectionWasm *>(
12118c56a07SHeejin Ahn             getFixupSection(Fixup.getValue()))) {
1226a31a0d6SSam Clegg       if (Section->getKind().isText())
123d1152a26SSam Clegg         return wasm::R_WASM_FUNCTION_OFFSET_I32;
1246a31a0d6SSam Clegg       else if (!Section->isWasmData())
125d1152a26SSam Clegg         return wasm::R_WASM_SECTION_OFFSET_I32;
1266a31a0d6SSam Clegg     }
127aa0c571aSYuta Saito     return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32
128aa0c571aSYuta Saito                     : wasm::R_WASM_MEMORY_ADDR_I32;
1293b29376eSWouter van Oortmerssen   case FK_Data_8:
130cc1b9b68SWouter van Oortmerssen     if (SymA.isFunction())
131cc1b9b68SWouter van Oortmerssen       return wasm::R_WASM_TABLE_INDEX_I64;
13286cd2332SWouter van Oortmerssen     if (SymA.isGlobal())
13386cd2332SWouter van Oortmerssen       llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64");
13486cd2332SWouter van Oortmerssen     if (auto Section = static_cast<const MCSectionWasm *>(
13586cd2332SWouter van Oortmerssen             getFixupSection(Fixup.getValue()))) {
13686cd2332SWouter van Oortmerssen       if (Section->getKind().isText())
13716f02431SWouter van Oortmerssen         return wasm::R_WASM_FUNCTION_OFFSET_I64;
13886cd2332SWouter van Oortmerssen       else if (!Section->isWasmData())
13986cd2332SWouter van Oortmerssen         llvm_unreachable("unimplemented R_WASM_SECTION_OFFSET_I64");
14086cd2332SWouter van Oortmerssen     }
1413b29376eSWouter van Oortmerssen     assert(SymA.isData());
1423b29376eSWouter van Oortmerssen     return wasm::R_WASM_MEMORY_ADDR_I64;
143d934cb88SDan Gohman   default:
144d934cb88SDan Gohman     llvm_unreachable("unimplemented fixup kind");
145d934cb88SDan Gohman   }
14618eafb6cSDan Gohman }
14718eafb6cSDan Gohman 
148dcd7d6c3SPeter Collingbourne std::unique_ptr<MCObjectTargetWriter>
149da84b688SDan Gohman llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) {
150da84b688SDan Gohman   return std::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit, IsEmscripten);
15118eafb6cSDan Gohman }
152