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