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