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