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