//===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file handles Wasm-specific object emission, converting LLVM's /// internal fixups into the appropriate relocations. /// //===----------------------------------------------------------------------===// #include "MCTargetDesc/WebAssemblyFixupKinds.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionWasm.h" #include "llvm/MC/MCSymbolWasm.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCWasmObjectWriter.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" using namespace llvm; namespace { class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter { public: explicit WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten); private: unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup, const MCSectionWasm &FixupSection, bool IsLocRel) const override; }; } // end anonymous namespace WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) : MCWasmObjectTargetWriter(Is64Bit, IsEmscripten) {} static const MCSection *getTargetSection(const MCExpr *Expr) { if (auto SyExp = dyn_cast(Expr)) { if (SyExp->getSymbol().isInSection()) return &SyExp->getSymbol().getSection(); return nullptr; } if (auto BinOp = dyn_cast(Expr)) { auto SectionLHS = getTargetSection(BinOp->getLHS()); auto SectionRHS = getTargetSection(BinOp->getRHS()); return SectionLHS == SectionRHS ? nullptr : SectionLHS; } if (auto UnOp = dyn_cast(Expr)) return getTargetSection(UnOp->getSubExpr()); return nullptr; } unsigned WebAssemblyWasmObjectWriter::getRelocType( const MCValue &Target, const MCFixup &Fixup, const MCSectionWasm &FixupSection, bool IsLocRel) const { const MCSymbolRefExpr *RefA = Target.getSymA(); assert(RefA); auto& SymA = cast(RefA->getSymbol()); MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); switch (Modifier) { case MCSymbolRefExpr::VK_GOT: return wasm::R_WASM_GLOBAL_INDEX_LEB; case MCSymbolRefExpr::VK_WASM_TBREL: assert(SymA.isFunction()); return is64Bit() ? wasm::R_WASM_TABLE_INDEX_REL_SLEB64 : wasm::R_WASM_TABLE_INDEX_REL_SLEB; case MCSymbolRefExpr::VK_WASM_TLSREL: return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64 : wasm::R_WASM_MEMORY_ADDR_TLS_SLEB; case MCSymbolRefExpr::VK_WASM_MBREL: assert(SymA.isData()); return is64Bit() ? wasm::R_WASM_MEMORY_ADDR_REL_SLEB64 : wasm::R_WASM_MEMORY_ADDR_REL_SLEB; case MCSymbolRefExpr::VK_WASM_TYPEINDEX: return wasm::R_WASM_TYPE_INDEX_LEB; default: break; } switch (unsigned(Fixup.getKind())) { case WebAssembly::fixup_sleb128_i32: if (SymA.isFunction()) return wasm::R_WASM_TABLE_INDEX_SLEB; return wasm::R_WASM_MEMORY_ADDR_SLEB; case WebAssembly::fixup_sleb128_i64: if (SymA.isFunction()) return wasm::R_WASM_TABLE_INDEX_SLEB64; return wasm::R_WASM_MEMORY_ADDR_SLEB64; case WebAssembly::fixup_uleb128_i32: if (SymA.isGlobal()) return wasm::R_WASM_GLOBAL_INDEX_LEB; if (SymA.isFunction()) return wasm::R_WASM_FUNCTION_INDEX_LEB; if (SymA.isTag()) return wasm::R_WASM_TAG_INDEX_LEB; if (SymA.isTable()) return wasm::R_WASM_TABLE_NUMBER_LEB; return wasm::R_WASM_MEMORY_ADDR_LEB; case WebAssembly::fixup_uleb128_i64: assert(SymA.isData()); return wasm::R_WASM_MEMORY_ADDR_LEB64; case FK_Data_4: if (SymA.isFunction()) { if (FixupSection.getKind().isMetadata()) return wasm::R_WASM_FUNCTION_OFFSET_I32; assert(FixupSection.isWasmData()); return wasm::R_WASM_TABLE_INDEX_I32; } if (SymA.isGlobal()) return wasm::R_WASM_GLOBAL_INDEX_I32; if (auto Section = static_cast( getTargetSection(Fixup.getValue()))) { if (Section->getKind().isText()) return wasm::R_WASM_FUNCTION_OFFSET_I32; else if (!Section->isWasmData()) return wasm::R_WASM_SECTION_OFFSET_I32; } return IsLocRel ? wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 : wasm::R_WASM_MEMORY_ADDR_I32; case FK_Data_8: if (SymA.isFunction()) { if (FixupSection.getKind().isMetadata()) return wasm::R_WASM_FUNCTION_OFFSET_I64; return wasm::R_WASM_TABLE_INDEX_I64; } if (SymA.isGlobal()) llvm_unreachable("unimplemented R_WASM_GLOBAL_INDEX_I64"); if (auto Section = static_cast( getTargetSection(Fixup.getValue()))) { if (Section->getKind().isText()) return wasm::R_WASM_FUNCTION_OFFSET_I64; else if (!Section->isWasmData()) llvm_unreachable("unimplemented R_WASM_SECTION_OFFSET_I64"); } assert(SymA.isData()); return wasm::R_WASM_MEMORY_ADDR_I64; default: llvm_unreachable("unimplemented fixup kind"); } } std::unique_ptr llvm::createWebAssemblyWasmObjectWriter(bool Is64Bit, bool IsEmscripten) { return std::make_unique(Is64Bit, IsEmscripten); }