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/WebAssemblyMCTargetDesc.h" 16 #include "MCTargetDesc/WebAssemblyFixupKinds.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, char *Data, unsigned DataSize, 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, char *Data, unsigned DataSize, 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, char *Data, 109 unsigned DataSize, uint64_t Value, 110 bool IsPCRel, MCContext &Ctx) const { 111 const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); 112 assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); 113 114 unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; 115 if (Value == 0) 116 return; // Doesn't change encoding. 117 118 // Shift the value into position. 119 Value <<= Info.TargetOffset; 120 121 unsigned Offset = Fixup.getOffset(); 122 assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); 123 124 // For each byte of the fragment that the fixup touches, mask in the 125 // bits from the fixup value. 126 for (unsigned i = 0; i != NumBytes; ++i) 127 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 128 } 129 130 MCObjectWriter * 131 WebAssemblyAsmBackendELF::createObjectWriter(raw_pwrite_stream &OS) const { 132 return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0); 133 } 134 135 const MCFixupKindInfo & 136 WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { 137 const static MCFixupKindInfo Infos[WebAssembly::NumTargetFixupKinds] = { 138 // This table *must* be in the order that the fixup_* kinds are defined in 139 // WebAssemblyFixupKinds.h. 140 // 141 // Name Offset (bits) Size (bits) Flags 142 { "fixup_code_sleb128_i32", 0, 5*8, 0 }, 143 { "fixup_code_sleb128_i64", 0, 10*8, 0 }, 144 { "fixup_code_uleb128_i32", 0, 5*8, 0 }, 145 }; 146 147 if (Kind < FirstTargetFixupKind) 148 return MCAsmBackend::getFixupKindInfo(Kind); 149 150 assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && 151 "Invalid kind!"); 152 return Infos[Kind - FirstTargetFixupKind]; 153 } 154 155 bool WebAssemblyAsmBackend::writeNopData(uint64_t Count, 156 MCObjectWriter *OW) const { 157 if (Count == 0) 158 return true; 159 160 for (uint64_t i = 0; i < Count; ++i) 161 OW->write8(WebAssembly::Nop); 162 163 return true; 164 } 165 166 void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, 167 unsigned DataSize, uint64_t Value, 168 bool IsPCRel, MCContext &Ctx) const { 169 const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); 170 assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); 171 172 unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; 173 if (Value == 0) 174 return; // Doesn't change encoding. 175 176 // Shift the value into position. 177 Value <<= Info.TargetOffset; 178 179 unsigned Offset = Fixup.getOffset(); 180 assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); 181 182 // For each byte of the fragment that the fixup touches, mask in the 183 // bits from the fixup value. 184 for (unsigned i = 0; i != NumBytes; ++i) 185 Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); 186 } 187 188 MCObjectWriter * 189 WebAssemblyAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { 190 return createWebAssemblyWasmObjectWriter(OS, Is64Bit); 191 } 192 } // end anonymous namespace 193 194 MCAsmBackend *llvm::createWebAssemblyAsmBackend(const Triple &TT) { 195 if (TT.isOSBinFormatELF()) 196 return new WebAssemblyAsmBackendELF(TT.isArch64Bit()); 197 return new WebAssemblyAsmBackend(TT.isArch64Bit()); 198 } 199