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