1 //===-- WebAssemblyAsmBackend.cpp - WebAssembly Assembler Backend ---------===// 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 /// \brief This file implements the WebAssemblyAsmBackend class. 12 /// 13 //===----------------------------------------------------------------------===// 14 15 #include "MCTargetDesc/WebAssemblyFixupKinds.h" 16 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" 17 #include "llvm/MC/MCAsmBackend.h" 18 #include "llvm/MC/MCAssembler.h" 19 #include "llvm/MC/MCDirectives.h" 20 #include "llvm/MC/MCELFObjectWriter.h" 21 #include "llvm/MC/MCExpr.h" 22 #include "llvm/MC/MCFixupKindInfo.h" 23 #include "llvm/MC/MCObjectWriter.h" 24 #include "llvm/MC/MCSubtargetInfo.h" 25 #include "llvm/MC/MCSymbol.h" 26 #include "llvm/MC/MCWasmObjectWriter.h" 27 #include "llvm/Support/ErrorHandling.h" 28 #include "llvm/Support/raw_ostream.h" 29 using namespace llvm; 30 31 namespace { 32 class WebAssemblyAsmBackendELF final : public MCAsmBackend { 33 bool Is64Bit; 34 35 public: 36 explicit WebAssemblyAsmBackendELF(bool Is64Bit) 37 : MCAsmBackend(), Is64Bit(Is64Bit) {} 38 ~WebAssemblyAsmBackendELF() override {} 39 40 void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data, 41 uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; 42 43 MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; 44 45 // No instruction requires relaxation 46 bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, 47 const MCRelaxableFragment *DF, 48 const MCAsmLayout &Layout) const override { 49 return false; 50 } 51 52 unsigned getNumFixupKinds() const override { 53 // We currently just use the generic fixups in MCFixup.h and don't have any 54 // target-specific fixups. 55 return 0; 56 } 57 58 bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } 59 60 void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, 61 MCInst &Res) const override {} 62 63 bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; 64 }; 65 66 class WebAssemblyAsmBackend final : public MCAsmBackend { 67 bool Is64Bit; 68 69 public: 70 explicit WebAssemblyAsmBackend(bool Is64Bit) 71 : MCAsmBackend(), Is64Bit(Is64Bit) {} 72 ~WebAssemblyAsmBackend() override {} 73 74 unsigned getNumFixupKinds() const override { 75 return WebAssembly::NumTargetFixupKinds; 76 } 77 78 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; 79 80 void applyFixup(const MCFixup &Fixup, MutableArrayRef<char> Data, 81 uint64_t Value, bool IsPCRel, MCContext &Ctx) const override; 82 83 MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; 84 85 // No instruction requires relaxation 86 bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, 87 const MCRelaxableFragment *DF, 88 const MCAsmLayout &Layout) const override { 89 return false; 90 } 91 92 bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } 93 94 void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, 95 MCInst &Res) const override {} 96 97 bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; 98 }; 99 100 bool WebAssemblyAsmBackendELF::writeNopData(uint64_t Count, 101 MCObjectWriter *OW) const { 102 for (uint64_t i = 0; i < Count; ++i) 103 OW->write8(WebAssembly::Nop); 104 105 return true; 106 } 107 108 void WebAssemblyAsmBackendELF::applyFixup(const MCFixup &Fixup, 109 MutableArrayRef<char> Data, 110 uint64_t Value, bool IsPCRel, 111 MCContext &Ctx) const { 112 const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); 113 assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); 114 115 unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; 116 if (Value == 0) 117 return; // Doesn't change encoding. 118 119 // Shift the value into position. 120 Value <<= Info.TargetOffset; 121 122 unsigned Offset = Fixup.getOffset(); 123 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 124 125 // For each byte of the fragment that the fixup touches, mask in the 126 // bits from the fixup value. 127 for (unsigned i = 0; i != NumBytes; ++i) 128 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 129 } 130 131 MCObjectWriter * 132 WebAssemblyAsmBackendELF::createObjectWriter(raw_pwrite_stream &OS) const { 133 return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0); 134 } 135 136 const MCFixupKindInfo & 137 WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 138 const static MCFixupKindInfo Infos[WebAssembly::NumTargetFixupKinds] = { 139 // This table *must* be in the order that the fixup_* kinds are defined in 140 // WebAssemblyFixupKinds.h. 141 // 142 // Name Offset (bits) Size (bits) Flags 143 { "fixup_code_sleb128_i32", 0, 5*8, 0 }, 144 { "fixup_code_sleb128_i64", 0, 10*8, 0 }, 145 { "fixup_code_uleb128_i32", 0, 5*8, 0 }, 146 }; 147 148 if (Kind < FirstTargetFixupKind) 149 return MCAsmBackend::getFixupKindInfo(Kind); 150 151 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 152 "Invalid kind!"); 153 return Infos[Kind - FirstTargetFixupKind]; 154 } 155 156 bool WebAssemblyAsmBackend::writeNopData(uint64_t Count, 157 MCObjectWriter *OW) const { 158 if (Count == 0) 159 return true; 160 161 for (uint64_t i = 0; i < Count; ++i) 162 OW->write8(WebAssembly::Nop); 163 164 return true; 165 } 166 167 void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, 168 MutableArrayRef<char> Data, 169 uint64_t Value, bool IsPCRel, 170 MCContext &Ctx) const { 171 const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); 172 assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); 173 174 unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; 175 if (Value == 0) 176 return; // Doesn't change encoding. 177 178 // Shift the value into position. 179 Value <<= Info.TargetOffset; 180 181 unsigned Offset = Fixup.getOffset(); 182 assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); 183 184 // For each byte of the fragment that the fixup touches, mask in the 185 // bits from the fixup value. 186 for (unsigned i = 0; i != NumBytes; ++i) 187 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 188 } 189 190 MCObjectWriter * 191 WebAssemblyAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { 192 return createWebAssemblyWasmObjectWriter(OS, Is64Bit); 193 } 194 } // end anonymous namespace 195 196 MCAsmBackend *llvm::createWebAssemblyAsmBackend(const Triple &TT) { 197 if (TT.isOSBinFormatELF()) 198 return new WebAssemblyAsmBackendELF(TT.isArch64Bit()); 199 return new WebAssemblyAsmBackend(TT.isArch64Bit()); 200 } 201