Home | History | Annotate | Download | only in MCTargetDesc
      1 //===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 ///
     10 /// \file
     11 /// This file handles Wasm-specific object emission, converting LLVM's
     12 /// internal fixups into the appropriate relocations.
     13 ///
     14 //===----------------------------------------------------------------------===//
     15 
     16 #include "MCTargetDesc/WebAssemblyFixupKinds.h"
     17 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
     18 #include "llvm/BinaryFormat/Wasm.h"
     19 #include "llvm/MC/MCAsmBackend.h"
     20 #include "llvm/MC/MCFixup.h"
     21 #include "llvm/MC/MCFixupKindInfo.h"
     22 #include "llvm/MC/MCObjectWriter.h"
     23 #include "llvm/MC/MCSectionWasm.h"
     24 #include "llvm/MC/MCSymbolWasm.h"
     25 #include "llvm/MC/MCValue.h"
     26 #include "llvm/MC/MCWasmObjectWriter.h"
     27 #include "llvm/Support/Casting.h"
     28 #include "llvm/Support/ErrorHandling.h"
     29 
     30 using namespace llvm;
     31 
     32 namespace {
     33 class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {
     34 public:
     35   explicit WebAssemblyWasmObjectWriter(bool Is64Bit);
     36 
     37 private:
     38   unsigned getRelocType(const MCValue &Target,
     39                         const MCFixup &Fixup) const override;
     40 };
     41 } // end anonymous namespace
     42 
     43 WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
     44     : MCWasmObjectTargetWriter(Is64Bit) {}
     45 
     46 // Test whether the given expression computes a function address.
     47 static bool IsFunctionExpr(const MCExpr *Expr) {
     48   if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr))
     49     return cast<MCSymbolWasm>(SyExp->getSymbol()).isFunction();
     50 
     51   if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr))
     52     return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS());
     53 
     54   if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
     55     return IsFunctionExpr(UnOp->getSubExpr());
     56 
     57   return false;
     58 }
     59 
     60 static bool IsFunctionType(const MCValue &Target) {
     61   const MCSymbolRefExpr *RefA = Target.getSymA();
     62   return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX;
     63 }
     64 
     65 static const MCSection *GetFixupSection(const MCExpr *Expr) {
     66   if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {
     67     if (SyExp->getSymbol().isInSection())
     68       return &SyExp->getSymbol().getSection();
     69     return nullptr;
     70   }
     71 
     72   if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {
     73     auto SectionLHS = GetFixupSection(BinOp->getLHS());
     74     auto SectionRHS = GetFixupSection(BinOp->getRHS());
     75     return SectionLHS == SectionRHS ? nullptr : SectionLHS;
     76   }
     77 
     78   if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))
     79     return GetFixupSection(UnOp->getSubExpr());
     80 
     81   return nullptr;
     82 }
     83 
     84 unsigned
     85 WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
     86                                           const MCFixup &Fixup) const {
     87   // WebAssembly functions are not allocated in the data address space. To
     88   // resolve a pointer to a function, we must use a special relocation type.
     89   bool IsFunction = IsFunctionExpr(Fixup.getValue());
     90 
     91   switch (unsigned(Fixup.getKind())) {
     92   case WebAssembly::fixup_code_global_index:
     93     return wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB;
     94   case WebAssembly::fixup_code_sleb128_i32:
     95     if (IsFunction)
     96       return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
     97     return wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB;
     98   case WebAssembly::fixup_code_sleb128_i64:
     99     llvm_unreachable("fixup_sleb128_i64 not implemented yet");
    100   case WebAssembly::fixup_code_uleb128_i32:
    101     if (IsFunctionType(Target))
    102       return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB;
    103     if (IsFunction)
    104       return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
    105     return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB;
    106   case FK_Data_4:
    107     if (IsFunction)
    108       return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
    109     if (auto Section = static_cast<const MCSectionWasm *>(
    110             GetFixupSection(Fixup.getValue()))) {
    111       if (Section->getKind().isText())
    112         return wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32;
    113       else if (!Section->isWasmData())
    114         return wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32;
    115     }
    116     return wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32;
    117   case FK_Data_8:
    118     llvm_unreachable("FK_Data_8 not implemented yet");
    119   default:
    120     llvm_unreachable("unimplemented fixup kind");
    121   }
    122 }
    123 
    124 std::unique_ptr<MCObjectTargetWriter>
    125 llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit) {
    126   return llvm::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit);
    127 }
    128