1 | //===-- WebAssemblyAsmBackend.cpp - WebAssembly Assembler Backend ---------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | /// |
9 | /// \file |
10 | /// This file implements the WebAssemblyAsmBackend class. |
11 | /// |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "MCTargetDesc/WebAssemblyFixupKinds.h" |
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/MCExpr.h" |
20 | #include "llvm/MC/MCFixupKindInfo.h" |
21 | #include "llvm/MC/MCObjectWriter.h" |
22 | #include "llvm/MC/MCSubtargetInfo.h" |
23 | #include "llvm/MC/MCSymbol.h" |
24 | #include "llvm/MC/MCWasmObjectWriter.h" |
25 | #include "llvm/Support/ErrorHandling.h" |
26 | #include "llvm/Support/raw_ostream.h" |
27 | |
28 | using namespace llvm; |
29 | |
30 | namespace { |
31 | |
32 | class WebAssemblyAsmBackend final : public MCAsmBackend { |
33 | bool Is64Bit; |
34 | bool IsEmscripten; |
35 | |
36 | public: |
37 | explicit WebAssemblyAsmBackend(bool Is64Bit, bool IsEmscripten) |
38 | : MCAsmBackend(llvm::endianness::little), Is64Bit(Is64Bit), |
39 | IsEmscripten(IsEmscripten) {} |
40 | |
41 | unsigned getNumFixupKinds() const override { |
42 | return WebAssembly::NumTargetFixupKinds; |
43 | } |
44 | |
45 | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; |
46 | |
47 | void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, |
48 | const MCValue &Target, MutableArrayRef<char> Data, |
49 | uint64_t Value, bool IsPCRel, |
50 | const MCSubtargetInfo *STI) const override; |
51 | |
52 | std::unique_ptr<MCObjectTargetWriter> |
53 | createObjectTargetWriter() const override; |
54 | |
55 | bool writeNopData(raw_ostream &OS, uint64_t Count, |
56 | const MCSubtargetInfo *STI) const override; |
57 | }; |
58 | |
59 | const MCFixupKindInfo & |
60 | WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { |
61 | const static MCFixupKindInfo Infos[WebAssembly::NumTargetFixupKinds] = { |
62 | // This table *must* be in the order that the fixup_* kinds are defined in |
63 | // WebAssemblyFixupKinds.h. |
64 | // |
65 | // Name Offset (bits) Size (bits) Flags |
66 | {.Name: "fixup_sleb128_i32" , .TargetOffset: 0, .TargetSize: 5 * 8, .Flags: 0}, |
67 | {.Name: "fixup_sleb128_i64" , .TargetOffset: 0, .TargetSize: 10 * 8, .Flags: 0}, |
68 | {.Name: "fixup_uleb128_i32" , .TargetOffset: 0, .TargetSize: 5 * 8, .Flags: 0}, |
69 | {.Name: "fixup_uleb128_i64" , .TargetOffset: 0, .TargetSize: 10 * 8, .Flags: 0}, |
70 | }; |
71 | |
72 | if (Kind < FirstTargetFixupKind) |
73 | return MCAsmBackend::getFixupKindInfo(Kind); |
74 | |
75 | assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && |
76 | "Invalid kind!" ); |
77 | return Infos[Kind - FirstTargetFixupKind]; |
78 | } |
79 | |
80 | bool WebAssemblyAsmBackend::writeNopData(raw_ostream &OS, uint64_t Count, |
81 | const MCSubtargetInfo *STI) const { |
82 | for (uint64_t I = 0; I < Count; ++I) |
83 | OS << char(WebAssembly::Nop); |
84 | |
85 | return true; |
86 | } |
87 | |
88 | void WebAssemblyAsmBackend::applyFixup(const MCAssembler &Asm, |
89 | const MCFixup &Fixup, |
90 | const MCValue &Target, |
91 | MutableArrayRef<char> Data, |
92 | uint64_t Value, bool IsPCRel, |
93 | const MCSubtargetInfo *STI) const { |
94 | const MCFixupKindInfo &Info = getFixupKindInfo(Kind: Fixup.getKind()); |
95 | assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags" ); |
96 | |
97 | unsigned NumBytes = alignTo(Value: Info.TargetSize, Align: 8) / 8; |
98 | if (Value == 0) |
99 | return; // Doesn't change encoding. |
100 | |
101 | // Shift the value into position. |
102 | Value <<= Info.TargetOffset; |
103 | |
104 | unsigned Offset = Fixup.getOffset(); |
105 | assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!" ); |
106 | |
107 | // For each byte of the fragment that the fixup touches, mask in the |
108 | // bits from the fixup value. |
109 | for (unsigned I = 0; I != NumBytes; ++I) |
110 | Data[Offset + I] |= uint8_t((Value >> (I * 8)) & 0xff); |
111 | } |
112 | |
113 | std::unique_ptr<MCObjectTargetWriter> |
114 | WebAssemblyAsmBackend::createObjectTargetWriter() const { |
115 | return createWebAssemblyWasmObjectWriter(Is64Bit, IsEmscripten); |
116 | } |
117 | |
118 | } // end anonymous namespace |
119 | |
120 | MCAsmBackend *llvm::createWebAssemblyAsmBackend(const Triple &TT) { |
121 | return new WebAssemblyAsmBackend(TT.isArch64Bit(), TT.isOSEmscripten()); |
122 | } |
123 | |