1 | //===- lib/MC/MCWasmStreamer.cpp - Wasm Object Output ---------------------===// |
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 | // This file assembles .s files and emits Wasm .o object files. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/MC/MCWasmStreamer.h" |
14 | #include "llvm/ADT/SmallString.h" |
15 | #include "llvm/ADT/SmallVector.h" |
16 | #include "llvm/MC/MCAsmBackend.h" |
17 | #include "llvm/MC/MCAssembler.h" |
18 | #include "llvm/MC/MCCodeEmitter.h" |
19 | #include "llvm/MC/MCExpr.h" |
20 | #include "llvm/MC/MCFixup.h" |
21 | #include "llvm/MC/MCFragment.h" |
22 | #include "llvm/MC/MCObjectStreamer.h" |
23 | #include "llvm/MC/MCSection.h" |
24 | #include "llvm/MC/MCSectionWasm.h" |
25 | #include "llvm/MC/MCSymbol.h" |
26 | #include "llvm/MC/MCSymbolWasm.h" |
27 | #include "llvm/MC/TargetRegistry.h" |
28 | #include "llvm/Support/Casting.h" |
29 | #include "llvm/Support/ErrorHandling.h" |
30 | #include "llvm/Support/raw_ostream.h" |
31 | |
32 | namespace llvm { |
33 | class MCContext; |
34 | class MCStreamer; |
35 | class MCSubtargetInfo; |
36 | } // namespace llvm |
37 | |
38 | using namespace llvm; |
39 | |
40 | MCWasmStreamer::~MCWasmStreamer() = default; // anchor. |
41 | |
42 | void MCWasmStreamer::emitLabel(MCSymbol *S, SMLoc Loc) { |
43 | auto *Symbol = cast<MCSymbolWasm>(Val: S); |
44 | MCObjectStreamer::emitLabel(Symbol, Loc); |
45 | |
46 | const MCSectionWasm &Section = |
47 | static_cast<const MCSectionWasm &>(*getCurrentSectionOnly()); |
48 | if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS) |
49 | Symbol->setTLS(); |
50 | } |
51 | |
52 | void MCWasmStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCDataFragment &F, |
53 | uint64_t Offset) { |
54 | auto *Symbol = cast<MCSymbolWasm>(Val: S); |
55 | MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset); |
56 | |
57 | const MCSectionWasm &Section = |
58 | static_cast<const MCSectionWasm &>(*getCurrentSectionOnly()); |
59 | if (Section.getSegmentFlags() & wasm::WASM_SEG_FLAG_TLS) |
60 | Symbol->setTLS(); |
61 | } |
62 | |
63 | void MCWasmStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) { |
64 | // Let the target do whatever target specific stuff it needs to do. |
65 | getAssembler().getBackend().handleAssemblerFlag(Flag); |
66 | |
67 | // Do any generic stuff we need to do. |
68 | llvm_unreachable("invalid assembler flag!" ); |
69 | } |
70 | |
71 | void MCWasmStreamer::changeSection(MCSection *Section, uint32_t Subsection) { |
72 | MCAssembler &Asm = getAssembler(); |
73 | auto *SectionWasm = cast<MCSectionWasm>(Val: Section); |
74 | const MCSymbol *Grp = SectionWasm->getGroup(); |
75 | if (Grp) |
76 | Asm.registerSymbol(Symbol: *Grp); |
77 | |
78 | this->MCObjectStreamer::changeSection(Section, Subsection); |
79 | Asm.registerSymbol(Symbol: *Section->getBeginSymbol()); |
80 | } |
81 | |
82 | void MCWasmStreamer::emitWeakReference(MCSymbol *Alias, |
83 | const MCSymbol *Symbol) { |
84 | getAssembler().registerSymbol(Symbol: *Symbol); |
85 | const MCExpr *Value = MCSymbolRefExpr::create( |
86 | Symbol, Kind: MCSymbolRefExpr::VK_WEAKREF, Ctx&: getContext()); |
87 | Alias->setVariableValue(Value); |
88 | } |
89 | |
90 | bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { |
91 | assert(Attribute != MCSA_IndirectSymbol && "indirect symbols not supported" ); |
92 | |
93 | auto *Symbol = cast<MCSymbolWasm>(Val: S); |
94 | |
95 | // Adding a symbol attribute always introduces the symbol; note that an |
96 | // important side effect of calling registerSymbol here is to register the |
97 | // symbol with the assembler. |
98 | getAssembler().registerSymbol(Symbol: *Symbol); |
99 | |
100 | switch (Attribute) { |
101 | case MCSA_LazyReference: |
102 | case MCSA_Reference: |
103 | case MCSA_SymbolResolver: |
104 | case MCSA_PrivateExtern: |
105 | case MCSA_WeakDefinition: |
106 | case MCSA_WeakDefAutoPrivate: |
107 | case MCSA_Invalid: |
108 | case MCSA_IndirectSymbol: |
109 | case MCSA_Protected: |
110 | case MCSA_Exported: |
111 | return false; |
112 | |
113 | case MCSA_Hidden: |
114 | Symbol->setHidden(true); |
115 | break; |
116 | |
117 | case MCSA_Weak: |
118 | case MCSA_WeakReference: |
119 | Symbol->setWeak(true); |
120 | Symbol->setExternal(true); |
121 | break; |
122 | |
123 | case MCSA_Global: |
124 | Symbol->setExternal(true); |
125 | break; |
126 | |
127 | case MCSA_ELF_TypeFunction: |
128 | Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); |
129 | break; |
130 | |
131 | case MCSA_ELF_TypeTLS: |
132 | Symbol->setTLS(); |
133 | break; |
134 | |
135 | case MCSA_ELF_TypeObject: |
136 | case MCSA_Cold: |
137 | break; |
138 | |
139 | case MCSA_NoDeadStrip: |
140 | Symbol->setNoStrip(); |
141 | break; |
142 | |
143 | default: |
144 | // unrecognized directive |
145 | llvm_unreachable("unexpected MCSymbolAttr" ); |
146 | return false; |
147 | } |
148 | |
149 | return true; |
150 | } |
151 | |
152 | void MCWasmStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size, |
153 | Align ByteAlignment) { |
154 | llvm_unreachable("Common symbols are not yet implemented for Wasm" ); |
155 | } |
156 | |
157 | void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { |
158 | cast<MCSymbolWasm>(Val: Symbol)->setSize(Value); |
159 | } |
160 | |
161 | void MCWasmStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size, |
162 | Align ByteAlignment) { |
163 | llvm_unreachable("Local common symbols are not yet implemented for Wasm" ); |
164 | } |
165 | |
166 | void MCWasmStreamer::emitIdent(StringRef IdentString) { |
167 | // TODO(sbc): Add the ident section once we support mergable strings |
168 | // sections in the object format |
169 | } |
170 | |
171 | void MCWasmStreamer::emitInstToFragment(const MCInst &Inst, |
172 | const MCSubtargetInfo &STI) { |
173 | this->MCObjectStreamer::emitInstToFragment(Inst, STI); |
174 | MCRelaxableFragment &F = *cast<MCRelaxableFragment>(Val: getCurrentFragment()); |
175 | |
176 | for (auto &Fixup : F.getFixups()) |
177 | fixSymbolsInTLSFixups(expr: Fixup.getValue()); |
178 | } |
179 | |
180 | void MCWasmStreamer::emitInstToData(const MCInst &Inst, |
181 | const MCSubtargetInfo &STI) { |
182 | MCAssembler &Assembler = getAssembler(); |
183 | SmallVector<MCFixup, 4> Fixups; |
184 | SmallString<256> Code; |
185 | Assembler.getEmitter().encodeInstruction(Inst, CB&: Code, Fixups, STI); |
186 | |
187 | for (auto &Fixup : Fixups) |
188 | fixSymbolsInTLSFixups(expr: Fixup.getValue()); |
189 | |
190 | // Append the encoded instruction to the current data fragment (or create a |
191 | // new such fragment if the current fragment is not a data fragment). |
192 | MCDataFragment *DF = getOrCreateDataFragment(); |
193 | |
194 | // Add the fixups and data. |
195 | for (unsigned I = 0, E = Fixups.size(); I != E; ++I) { |
196 | Fixups[I].setOffset(Fixups[I].getOffset() + DF->getContents().size()); |
197 | DF->getFixups().push_back(Elt: Fixups[I]); |
198 | } |
199 | DF->setHasInstructions(STI); |
200 | DF->getContents().append(in_start: Code.begin(), in_end: Code.end()); |
201 | } |
202 | |
203 | void MCWasmStreamer::finishImpl() { |
204 | emitFrames(MAB: nullptr); |
205 | |
206 | this->MCObjectStreamer::finishImpl(); |
207 | } |
208 | |
209 | void MCWasmStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { |
210 | switch (expr->getKind()) { |
211 | case MCExpr::Target: |
212 | case MCExpr::Constant: |
213 | break; |
214 | |
215 | case MCExpr::Binary: { |
216 | const MCBinaryExpr *be = cast<MCBinaryExpr>(Val: expr); |
217 | fixSymbolsInTLSFixups(expr: be->getLHS()); |
218 | fixSymbolsInTLSFixups(expr: be->getRHS()); |
219 | break; |
220 | } |
221 | |
222 | case MCExpr::SymbolRef: { |
223 | const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(Val: expr); |
224 | switch (symRef.getKind()) { |
225 | case MCSymbolRefExpr::VK_WASM_TLSREL: |
226 | case MCSymbolRefExpr::VK_WASM_GOT_TLS: |
227 | getAssembler().registerSymbol(Symbol: symRef.getSymbol()); |
228 | cast<MCSymbolWasm>(Val: symRef.getSymbol()).setTLS(); |
229 | break; |
230 | default: |
231 | break; |
232 | } |
233 | break; |
234 | } |
235 | |
236 | case MCExpr::Unary: |
237 | fixSymbolsInTLSFixups(expr: cast<MCUnaryExpr>(Val: expr)->getSubExpr()); |
238 | break; |
239 | } |
240 | } |
241 | |
242 | void MCWasmStreamer::emitThumbFunc(MCSymbol *Func) { |
243 | llvm_unreachable("Generic Wasm doesn't support this directive" ); |
244 | } |
245 | |
246 | void MCWasmStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { |
247 | llvm_unreachable("Wasm doesn't support this directive" ); |
248 | } |
249 | |
250 | void MCWasmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, |
251 | uint64_t Size, Align ByteAlignment, |
252 | SMLoc Loc) { |
253 | llvm_unreachable("Wasm doesn't support this directive" ); |
254 | } |
255 | |
256 | void MCWasmStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, |
257 | uint64_t Size, Align ByteAlignment) { |
258 | llvm_unreachable("Wasm doesn't support this directive" ); |
259 | } |
260 | |
261 | MCStreamer *llvm::createWasmStreamer(MCContext &Context, |
262 | std::unique_ptr<MCAsmBackend> &&MAB, |
263 | std::unique_ptr<MCObjectWriter> &&OW, |
264 | std::unique_ptr<MCCodeEmitter> &&CE) { |
265 | MCWasmStreamer *S = |
266 | new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); |
267 | return S; |
268 | } |
269 | |