165 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file handles Wasm-specific object emission, converting LLVM's11/// internal fixups into the appropriate relocations.12///13//===----------------------------------------------------------------------===//14 15#include "MCTargetDesc/WebAssemblyFixupKinds.h"16#include "MCTargetDesc/WebAssemblyMCAsmInfo.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/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 29using namespace llvm;30 31namespace {32class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter {33public:34 explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten);35 36private:37 unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup,38 const MCSectionWasm &FixupSection,39 bool IsLocRel) const override;40};41} // end anonymous namespace42 43WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit,44 bool IsEmscripten)45 : MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {}46 47static const MCSection *getTargetSection(const MCExpr *Expr) {48 if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) {49 if (SyExp->getSymbol().isInSection())50 return &SyExp->getSymbol().getSection();51 return nullptr;52 }53 54 if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) {55 auto SectionLHS = getTargetSection(BinOp->getLHS());56 auto SectionRHS = getTargetSection(BinOp->getRHS());57 return SectionLHS == SectionRHS ? nullptr : SectionLHS;58 }59 60 if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr))61 return getTargetSection(UnOp->getSubExpr());62 63 return nullptr;64}65 66unsigned WebAssemblyWasmObjectWriter::getRelocType(67 const MCValue &Target, const MCFixup &Fixup,68 const MCSectionWasm &FixupSection, bool IsLocRel) const {69 auto &SymA = static_cast<const MCSymbolWasm &>(*Target.getAddSym());70 auto Spec = WebAssembly::Specifier(Target.getSpecifier());71 switch (Spec) {72 case WebAssembly::S_GOT:73 SymA.setUsedInGOT();74 return wasm::R_WASM_GLOBAL_INDEX_LEB;75 case WebAssembly::S_GOT_TLS:76 SymA.setUsedInGOT();77 SymA.setTLS();78 return wasm::R_WASM_GLOBAL_INDEX_LEB;79 case WebAssembly::S_TBREL:80 assert(SymA.isFunction());81 return is64Bit() ? wasm::R_WASM_TABLE_INDEX_REL_SLEB6482 : wasm::R_WASM_TABLE_INDEX_REL_SLEB;83 case WebAssembly::S_TLSREL:84 SymA.setTLS();85 return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_TLS_SLEB6486 : wasm::R_WASM_MEMORY_ADDR_TLS_SLEB;87 case WebAssembly::S_MBREL:88 assert(SymA.isData());89 return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB6490 : wasm::R_WASM_MEMORY_ADDR_REL_SLEB;91 case WebAssembly::S_TYPEINDEX:92 return wasm::R_WASM_TYPE_INDEX_LEB;93 case WebAssembly::S_None:94 break;95 case WebAssembly::S_FUNCINDEX:96 return wasm::R_WASM_FUNCTION_INDEX_I32;97 }98 99 switch (unsigned(Fixup.getKind())) {100 case WebAssembly::fixup_sleb128_i32:101 if (SymA.isFunction())102 return wasm::R_WASM_TABLE_INDEX_SLEB;103 return wasm::R_WASM_MEMORY_ADDR_SLEB;104 case WebAssembly::fixup_sleb128_i64:105 if (SymA.isFunction())106 return wasm::R_WASM_TABLE_INDEX_SLEB64;107 return wasm::R_WASM_MEMORY_ADDR_SLEB64;108 case WebAssembly::fixup_uleb128_i32:109 if (SymA.isGlobal())110 return wasm::R_WASM_GLOBAL_INDEX_LEB;111 if (SymA.isFunction())112 return wasm::R_WASM_FUNCTION_INDEX_LEB;113 if (SymA.isTag())114 return wasm::R_WASM_TAG_INDEX_LEB;115 if (SymA.isTable())116 return wasm::R_WASM_TABLE_NUMBER_LEB;117 return wasm::R_WASM_MEMORY_ADDR_LEB;118 case WebAssembly::fixup_uleb128_i64:119 assert(SymA.isData());120 return wasm::R_WASM_MEMORY_ADDR_LEB64;121 case FK_Data_4:122 if (SymA.isFunction()) {123 if (FixupSection.isMetadata())124 return wasm::R_WASM_FUNCTION_OFFSET_I32;125 assert(FixupSection.isWasmData());126 return wasm::R_WASM_TABLE_INDEX_I32;127 }128 if (SymA.isGlobal())129 return wasm::R_WASM_GLOBAL_INDEX_I32;130 if (auto Section = static_cast<const MCSectionWasm *>(131 getTargetSection(Fixup.getValue()))) {132 if (Section->isText())133 return wasm::R_WASM_FUNCTION_OFFSET_I32;134 else if (!Section->isWasmData())135 return wasm::R_WASM_SECTION_OFFSET_I32;136 }137 return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32138 : wasm::R_WASM_MEMORY_ADDR_I32;139 case FK_Data_8:140 if (SymA.isFunction()) {141 if (FixupSection.isMetadata())142 return wasm::R_WASM_FUNCTION_OFFSET_I64;143 return wasm::R_WASM_TABLE_INDEX_I64;144 }145 if (SymA.isGlobal())146 llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64");147 if (auto Section = static_cast<const MCSectionWasm *>(148 getTargetSection(Fixup.getValue()))) {149 if (Section->isText())150 return wasm::R_WASM_FUNCTION_OFFSET_I64;151 else if (!Section->isWasmData())152 llvm_unreachable("unimplemented R_WASM_SECTION_OFFSET_I64");153 }154 assert(SymA.isData());155 return wasm::R_WASM_MEMORY_ADDR_I64;156 default:157 llvm_unreachable("unimplemented fixup kind");158 }159}160 161std::unique_ptr<MCObjectTargetWriter>162llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) {163 return std::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit, IsEmscripten);164}165