1 | //===- lib/MC/MCELFStreamer.cpp - ELF 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 ELF .o object files. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include "llvm/MC/MCELFStreamer.h" |
14 | #include "llvm/ADT/SmallVector.h" |
15 | #include "llvm/BinaryFormat/ELF.h" |
16 | #include "llvm/MC/MCAsmBackend.h" |
17 | #include "llvm/MC/MCAsmInfo.h" |
18 | #include "llvm/MC/MCAssembler.h" |
19 | #include "llvm/MC/MCCodeEmitter.h" |
20 | #include "llvm/MC/MCContext.h" |
21 | #include "llvm/MC/MCELFObjectWriter.h" |
22 | #include "llvm/MC/MCExpr.h" |
23 | #include "llvm/MC/MCFixup.h" |
24 | #include "llvm/MC/MCObjectFileInfo.h" |
25 | #include "llvm/MC/MCObjectWriter.h" |
26 | #include "llvm/MC/MCSection.h" |
27 | #include "llvm/MC/MCSectionELF.h" |
28 | #include "llvm/MC/MCStreamer.h" |
29 | #include "llvm/MC/MCSymbol.h" |
30 | #include "llvm/MC/MCSymbolELF.h" |
31 | #include "llvm/MC/TargetRegistry.h" |
32 | #include "llvm/Support/Casting.h" |
33 | #include "llvm/Support/ErrorHandling.h" |
34 | #include "llvm/Support/LEB128.h" |
35 | #include <cassert> |
36 | #include <cstdint> |
37 | |
38 | using namespace llvm; |
39 | |
40 | MCELFStreamer::MCELFStreamer(MCContext &Context, |
41 | std::unique_ptr<MCAsmBackend> TAB, |
42 | std::unique_ptr<MCObjectWriter> OW, |
43 | std::unique_ptr<MCCodeEmitter> Emitter) |
44 | : MCObjectStreamer(Context, std::move(TAB), std::move(OW), |
45 | std::move(Emitter)) {} |
46 | |
47 | ELFObjectWriter &MCELFStreamer::getWriter() { |
48 | return static_cast<ELFObjectWriter &>(getAssembler().getWriter()); |
49 | } |
50 | |
51 | bool MCELFStreamer::isBundleLocked() const { |
52 | return getCurrentSectionOnly()->isBundleLocked(); |
53 | } |
54 | |
55 | void MCELFStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) { |
56 | MCContext &Ctx = getContext(); |
57 | switchSection(Section: Ctx.getObjectFileInfo()->getTextSection()); |
58 | emitCodeAlignment(ByteAlignment: Align(Ctx.getObjectFileInfo()->getTextSectionAlignment()), |
59 | STI: &STI); |
60 | |
61 | if (NoExecStack) |
62 | switchSection(Section: Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx)); |
63 | } |
64 | |
65 | void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) { |
66 | auto *Symbol = cast<MCSymbolELF>(Val: S); |
67 | MCObjectStreamer::emitLabel(Symbol, Loc); |
68 | |
69 | const MCSectionELF &Section = |
70 | static_cast<const MCSectionELF &>(*getCurrentSectionOnly()); |
71 | if (Section.getFlags() & ELF::SHF_TLS) |
72 | Symbol->setType(ELF::STT_TLS); |
73 | } |
74 | |
75 | void MCELFStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCDataFragment &F, |
76 | uint64_t Offset) { |
77 | auto *Symbol = cast<MCSymbolELF>(Val: S); |
78 | MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset); |
79 | |
80 | const MCSectionELF &Section = |
81 | static_cast<const MCSectionELF &>(*getCurrentSectionOnly()); |
82 | if (Section.getFlags() & ELF::SHF_TLS) |
83 | Symbol->setType(ELF::STT_TLS); |
84 | } |
85 | |
86 | // If bundle alignment is used and there are any instructions in the section, it |
87 | // needs to be aligned to at least the bundle size. |
88 | static void setSectionAlignmentForBundling(const MCAssembler &Assembler, |
89 | MCSection *Section) { |
90 | if (Assembler.isBundlingEnabled() && Section->hasInstructions()) |
91 | Section->ensureMinAlignment(MinAlignment: Align(Assembler.getBundleAlignSize())); |
92 | } |
93 | |
94 | void MCELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) { |
95 | MCAssembler &Asm = getAssembler(); |
96 | if (auto *F = getCurrentFragment()) { |
97 | if (isBundleLocked()) |
98 | report_fatal_error(reason: "Unterminated .bundle_lock when changing a section" ); |
99 | |
100 | // Ensure the previous section gets aligned if necessary. |
101 | setSectionAlignmentForBundling(Assembler: Asm, Section: F->getParent()); |
102 | } |
103 | auto *SectionELF = static_cast<const MCSectionELF *>(Section); |
104 | const MCSymbol *Grp = SectionELF->getGroup(); |
105 | if (Grp) |
106 | Asm.registerSymbol(Symbol: *Grp); |
107 | if (SectionELF->getFlags() & ELF::SHF_GNU_RETAIN) |
108 | getWriter().markGnuAbi(); |
109 | |
110 | changeSectionImpl(Section, Subsection); |
111 | Asm.registerSymbol(Symbol: *Section->getBeginSymbol()); |
112 | } |
113 | |
114 | void MCELFStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) { |
115 | auto *A = cast<MCSymbolELF>(Val: Alias); |
116 | if (A->isDefined()) { |
117 | getContext().reportError(L: getStartTokLoc(), Msg: "symbol '" + A->getName() + |
118 | "' is already defined" ); |
119 | return; |
120 | } |
121 | A->setVariableValue(MCSymbolRefExpr::create(Symbol: Target, Ctx&: getContext())); |
122 | A->setIsWeakref(); |
123 | getWriter().Weakrefs.push_back(Elt: A); |
124 | } |
125 | |
126 | // When GNU as encounters more than one .type declaration for an object it seems |
127 | // to use a mechanism similar to the one below to decide which type is actually |
128 | // used in the object file. The greater of T1 and T2 is selected based on the |
129 | // following ordering: |
130 | // STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else |
131 | // If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user |
132 | // provided type). |
133 | static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) { |
134 | for (unsigned Type : {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC, |
135 | ELF::STT_GNU_IFUNC, ELF::STT_TLS}) { |
136 | if (T1 == Type) |
137 | return T2; |
138 | if (T2 == Type) |
139 | return T1; |
140 | } |
141 | |
142 | return T2; |
143 | } |
144 | |
145 | bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { |
146 | auto *Symbol = cast<MCSymbolELF>(Val: S); |
147 | |
148 | // Adding a symbol attribute always introduces the symbol, note that an |
149 | // important side effect of calling registerSymbol here is to register |
150 | // the symbol with the assembler. |
151 | getAssembler().registerSymbol(Symbol: *Symbol); |
152 | |
153 | // The implementation of symbol attributes is designed to match 'as', but it |
154 | // leaves much to desired. It doesn't really make sense to arbitrarily add and |
155 | // remove flags, but 'as' allows this (in particular, see .desc). |
156 | // |
157 | // In the future it might be worth trying to make these operations more well |
158 | // defined. |
159 | switch (Attribute) { |
160 | case MCSA_Cold: |
161 | case MCSA_Extern: |
162 | case MCSA_LazyReference: |
163 | case MCSA_Reference: |
164 | case MCSA_SymbolResolver: |
165 | case MCSA_PrivateExtern: |
166 | case MCSA_WeakDefinition: |
167 | case MCSA_WeakDefAutoPrivate: |
168 | case MCSA_Invalid: |
169 | case MCSA_IndirectSymbol: |
170 | case MCSA_Exported: |
171 | case MCSA_WeakAntiDep: |
172 | return false; |
173 | |
174 | case MCSA_NoDeadStrip: |
175 | // Ignore for now. |
176 | break; |
177 | |
178 | case MCSA_ELF_TypeGnuUniqueObject: |
179 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_OBJECT)); |
180 | Symbol->setBinding(ELF::STB_GNU_UNIQUE); |
181 | getWriter().markGnuAbi(); |
182 | break; |
183 | |
184 | case MCSA_Global: |
185 | // For `.weak x; .global x`, GNU as sets the binding to STB_WEAK while we |
186 | // traditionally set the binding to STB_GLOBAL. This is error-prone, so we |
187 | // error on such cases. Note, we also disallow changed binding from .local. |
188 | if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_GLOBAL) |
189 | getContext().reportError(L: getStartTokLoc(), |
190 | Msg: Symbol->getName() + |
191 | " changed binding to STB_GLOBAL" ); |
192 | Symbol->setBinding(ELF::STB_GLOBAL); |
193 | break; |
194 | |
195 | case MCSA_WeakReference: |
196 | case MCSA_Weak: |
197 | // For `.global x; .weak x`, both MC and GNU as set the binding to STB_WEAK. |
198 | // We emit a warning for now but may switch to an error in the future. |
199 | if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_WEAK) |
200 | getContext().reportWarning( |
201 | L: getStartTokLoc(), Msg: Symbol->getName() + " changed binding to STB_WEAK" ); |
202 | Symbol->setBinding(ELF::STB_WEAK); |
203 | break; |
204 | |
205 | case MCSA_Local: |
206 | if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_LOCAL) |
207 | getContext().reportError(L: getStartTokLoc(), |
208 | Msg: Symbol->getName() + |
209 | " changed binding to STB_LOCAL" ); |
210 | Symbol->setBinding(ELF::STB_LOCAL); |
211 | break; |
212 | |
213 | case MCSA_ELF_TypeFunction: |
214 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_FUNC)); |
215 | break; |
216 | |
217 | case MCSA_ELF_TypeIndFunction: |
218 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_GNU_IFUNC)); |
219 | getWriter().markGnuAbi(); |
220 | break; |
221 | |
222 | case MCSA_ELF_TypeObject: |
223 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_OBJECT)); |
224 | break; |
225 | |
226 | case MCSA_ELF_TypeTLS: |
227 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_TLS)); |
228 | break; |
229 | |
230 | case MCSA_ELF_TypeCommon: |
231 | // TODO: Emit these as a common symbol. |
232 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_OBJECT)); |
233 | break; |
234 | |
235 | case MCSA_ELF_TypeNoType: |
236 | Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_NOTYPE)); |
237 | break; |
238 | |
239 | case MCSA_Protected: |
240 | Symbol->setVisibility(ELF::STV_PROTECTED); |
241 | break; |
242 | |
243 | case MCSA_Memtag: |
244 | Symbol->setMemtag(true); |
245 | break; |
246 | |
247 | case MCSA_Hidden: |
248 | Symbol->setVisibility(ELF::STV_HIDDEN); |
249 | break; |
250 | |
251 | case MCSA_Internal: |
252 | Symbol->setVisibility(ELF::STV_INTERNAL); |
253 | break; |
254 | |
255 | case MCSA_AltEntry: |
256 | llvm_unreachable("ELF doesn't support the .alt_entry attribute" ); |
257 | |
258 | case MCSA_LGlobal: |
259 | llvm_unreachable("ELF doesn't support the .lglobl attribute" ); |
260 | } |
261 | |
262 | return true; |
263 | } |
264 | |
265 | void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size, |
266 | Align ByteAlignment) { |
267 | auto *Symbol = cast<MCSymbolELF>(Val: S); |
268 | getAssembler().registerSymbol(Symbol: *Symbol); |
269 | |
270 | if (!Symbol->isBindingSet()) |
271 | Symbol->setBinding(ELF::STB_GLOBAL); |
272 | |
273 | Symbol->setType(ELF::STT_OBJECT); |
274 | |
275 | if (Symbol->getBinding() == ELF::STB_LOCAL) { |
276 | MCSection &Section = *getAssembler().getContext().getELFSection( |
277 | Section: ".bss" , Type: ELF::SHT_NOBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC); |
278 | MCSectionSubPair P = getCurrentSection(); |
279 | switchSection(Section: &Section); |
280 | |
281 | emitValueToAlignment(ByteAlignment, 0, 1, 0); |
282 | emitLabel(S: Symbol); |
283 | emitZeros(NumBytes: Size); |
284 | |
285 | switchSection(Section: P.first, Subsec: P.second); |
286 | } else { |
287 | if (Symbol->declareCommon(Size, Alignment: ByteAlignment)) |
288 | report_fatal_error(reason: Twine("Symbol: " ) + Symbol->getName() + |
289 | " redeclared as different type" ); |
290 | } |
291 | |
292 | cast<MCSymbolELF>(Val: Symbol) |
293 | ->setSize(MCConstantExpr::create(Value: Size, Ctx&: getContext())); |
294 | } |
295 | |
296 | void MCELFStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { |
297 | cast<MCSymbolELF>(Val: Symbol)->setSize(Value); |
298 | } |
299 | |
300 | void MCELFStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym, |
301 | StringRef Name, |
302 | bool KeepOriginalSym) { |
303 | getWriter().Symvers.push_back(Elt: ELFObjectWriter::Symver{ |
304 | .Loc: getStartTokLoc(), .Sym: OriginalSym, .Name: Name, .KeepOriginalSym: KeepOriginalSym}); |
305 | } |
306 | |
307 | void MCELFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size, |
308 | Align ByteAlignment) { |
309 | auto *Symbol = cast<MCSymbolELF>(Val: S); |
310 | // FIXME: Should this be caught and done earlier? |
311 | getAssembler().registerSymbol(Symbol: *Symbol); |
312 | Symbol->setBinding(ELF::STB_LOCAL); |
313 | emitCommonSymbol(S: Symbol, Size, ByteAlignment); |
314 | } |
315 | |
316 | void MCELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, |
317 | SMLoc Loc) { |
318 | if (isBundleLocked()) |
319 | report_fatal_error(reason: "Emitting values inside a locked bundle is forbidden" ); |
320 | MCObjectStreamer::emitValueImpl(Value, Size, Loc); |
321 | } |
322 | |
323 | void MCELFStreamer::emitValueToAlignment(Align Alignment, int64_t Value, |
324 | unsigned ValueSize, |
325 | unsigned MaxBytesToEmit) { |
326 | if (isBundleLocked()) |
327 | report_fatal_error(reason: "Emitting values inside a locked bundle is forbidden" ); |
328 | MCObjectStreamer::emitValueToAlignment(Alignment, Value, ValueSize, |
329 | MaxBytesToEmit); |
330 | } |
331 | |
332 | void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, |
333 | const MCSymbolRefExpr *To, |
334 | uint64_t Count) { |
335 | getWriter().getCGProfile().push_back(Elt: {.From: From, .To: To, .Count: Count}); |
336 | } |
337 | |
338 | void MCELFStreamer::emitIdent(StringRef IdentString) { |
339 | MCSection * = getAssembler().getContext().getELFSection( |
340 | Section: ".comment" , Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_MERGE | ELF::SHF_STRINGS, EntrySize: 1); |
341 | pushSection(); |
342 | switchSection(Section: Comment); |
343 | if (!SeenIdent) { |
344 | emitInt8(Value: 0); |
345 | SeenIdent = true; |
346 | } |
347 | emitBytes(Data: IdentString); |
348 | emitInt8(Value: 0); |
349 | popSection(); |
350 | } |
351 | |
352 | void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE, |
353 | uint64_t Offset) { |
354 | const MCSymbol *S = &SRE->getSymbol(); |
355 | if (S->isTemporary()) { |
356 | if (!S->isInSection()) { |
357 | getContext().reportError( |
358 | L: SRE->getLoc(), Msg: Twine("Reference to undefined temporary symbol " ) + |
359 | "`" + S->getName() + "`" ); |
360 | return; |
361 | } |
362 | S = S->getSection().getBeginSymbol(); |
363 | S->setUsedInReloc(); |
364 | SRE = MCSymbolRefExpr::create(Symbol: S, Ctx&: getContext(), Loc: SRE->getLoc()); |
365 | } |
366 | const MCConstantExpr *MCOffset = MCConstantExpr::create(Value: Offset, Ctx&: getContext()); |
367 | if (std::optional<std::pair<bool, std::string>> Err = |
368 | MCObjectStreamer::emitRelocDirective( |
369 | Offset: *MCOffset, Name: "BFD_RELOC_NONE" , Expr: SRE, Loc: SRE->getLoc(), |
370 | STI: *getContext().getSubtargetInfo())) |
371 | report_fatal_error(reason: "Relocation for CG Profile could not be created: " + |
372 | Twine(Err->second)); |
373 | } |
374 | |
375 | void MCELFStreamer::finalizeCGProfile() { |
376 | ELFObjectWriter &W = getWriter(); |
377 | if (W.getCGProfile().empty()) |
378 | return; |
379 | MCSection *CGProfile = getAssembler().getContext().getELFSection( |
380 | Section: ".llvm.call-graph-profile" , Type: ELF::SHT_LLVM_CALL_GRAPH_PROFILE, |
381 | Flags: ELF::SHF_EXCLUDE, /*sizeof(Elf_CGProfile_Impl<>)=*/EntrySize: 8); |
382 | pushSection(); |
383 | switchSection(Section: CGProfile); |
384 | uint64_t Offset = 0; |
385 | for (auto &E : W.getCGProfile()) { |
386 | finalizeCGProfileEntry(SRE&: E.From, Offset); |
387 | finalizeCGProfileEntry(SRE&: E.To, Offset); |
388 | emitIntValue(Value: E.Count, Size: sizeof(uint64_t)); |
389 | Offset += sizeof(uint64_t); |
390 | } |
391 | popSection(); |
392 | } |
393 | |
394 | // A fragment can only have one Subtarget, and when bundling is enabled we |
395 | // sometimes need to use the same fragment. We give an error if there |
396 | // are conflicting Subtargets. |
397 | static void CheckBundleSubtargets(const MCSubtargetInfo *OldSTI, |
398 | const MCSubtargetInfo *NewSTI) { |
399 | if (OldSTI && NewSTI && OldSTI != NewSTI) |
400 | report_fatal_error(reason: "A Bundle can only have one Subtarget." ); |
401 | } |
402 | |
403 | void MCELFStreamer::emitInstToData(const MCInst &Inst, |
404 | const MCSubtargetInfo &STI) { |
405 | MCAssembler &Assembler = getAssembler(); |
406 | |
407 | // There are several possibilities here: |
408 | // |
409 | // If bundling is disabled, append the encoded instruction to the current data |
410 | // fragment (or create a new such fragment if the current fragment is not a |
411 | // data fragment, or the Subtarget has changed). |
412 | // |
413 | // If bundling is enabled: |
414 | // - If we're not in a bundle-locked group, emit the instruction into a |
415 | // fragment of its own. |
416 | // - If we're in a bundle-locked group, append the instruction to the current |
417 | // data fragment because we want all the instructions in a group to get into |
418 | // the same fragment. Be careful not to do that for the first instruction in |
419 | // the group, though. |
420 | MCDataFragment *DF; |
421 | |
422 | if (Assembler.isBundlingEnabled()) { |
423 | MCSection &Sec = *getCurrentSectionOnly(); |
424 | if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) { |
425 | // If we are bundle-locked, we re-use the current fragment. |
426 | // The bundle-locking directive ensures this is a new data fragment. |
427 | DF = cast<MCDataFragment>(Val: getCurrentFragment()); |
428 | CheckBundleSubtargets(OldSTI: DF->getSubtargetInfo(), NewSTI: &STI); |
429 | } else { |
430 | DF = getContext().allocFragment<MCDataFragment>(); |
431 | insert(F: DF); |
432 | } |
433 | if (Sec.getBundleLockState() == MCSection::BundleLockedAlignToEnd) { |
434 | // If this fragment is for a group marked "align_to_end", set a flag |
435 | // in the fragment. This can happen after the fragment has already been |
436 | // created if there are nested bundle_align groups and an inner one |
437 | // is the one marked align_to_end. |
438 | DF->setAlignToBundleEnd(true); |
439 | } |
440 | |
441 | // We're now emitting an instruction in a bundle group, so this flag has |
442 | // to be turned off. |
443 | Sec.setBundleGroupBeforeFirstInst(false); |
444 | } else { |
445 | DF = getOrCreateDataFragment(STI: &STI); |
446 | } |
447 | |
448 | // Emit instruction directly into data fragment. |
449 | size_t FixupStartIndex = DF->getFixups().size(); |
450 | size_t CodeOffset = DF->getContents().size(); |
451 | SmallVector<MCFixup, 1> Fixups; |
452 | Assembler.getEmitter().encodeInstruction(Inst, CB&: DF->getContentsForAppending(), |
453 | Fixups, STI); |
454 | DF->doneAppending(); |
455 | if (!Fixups.empty()) |
456 | DF->appendFixups(Fixups); |
457 | |
458 | for (auto &Fixup : MutableArrayRef(DF->getFixups()).slice(N: FixupStartIndex)) { |
459 | Fixup.setOffset(Fixup.getOffset() + CodeOffset); |
460 | if (Fixup.isLinkerRelaxable()) { |
461 | DF->setLinkerRelaxable(); |
462 | getCurrentSectionOnly()->setLinkerRelaxable(); |
463 | } |
464 | } |
465 | |
466 | DF->setHasInstructions(STI); |
467 | } |
468 | |
469 | void MCELFStreamer::emitBundleAlignMode(Align Alignment) { |
470 | assert(Log2(Alignment) <= 30 && "Invalid bundle alignment" ); |
471 | MCAssembler &Assembler = getAssembler(); |
472 | if (Alignment > 1 && (Assembler.getBundleAlignSize() == 0 || |
473 | Assembler.getBundleAlignSize() == Alignment.value())) |
474 | Assembler.setBundleAlignSize(Alignment.value()); |
475 | else |
476 | report_fatal_error(reason: ".bundle_align_mode cannot be changed once set" ); |
477 | } |
478 | |
479 | void MCELFStreamer::emitBundleLock(bool AlignToEnd) { |
480 | MCSection &Sec = *getCurrentSectionOnly(); |
481 | |
482 | if (!getAssembler().isBundlingEnabled()) |
483 | report_fatal_error(reason: ".bundle_lock forbidden when bundling is disabled" ); |
484 | |
485 | if (!isBundleLocked()) |
486 | Sec.setBundleGroupBeforeFirstInst(true); |
487 | |
488 | Sec.setBundleLockState(AlignToEnd ? MCSection::BundleLockedAlignToEnd |
489 | : MCSection::BundleLocked); |
490 | } |
491 | |
492 | void MCELFStreamer::emitBundleUnlock() { |
493 | MCSection &Sec = *getCurrentSectionOnly(); |
494 | |
495 | if (!getAssembler().isBundlingEnabled()) |
496 | report_fatal_error(reason: ".bundle_unlock forbidden when bundling is disabled" ); |
497 | else if (!isBundleLocked()) |
498 | report_fatal_error(reason: ".bundle_unlock without matching lock" ); |
499 | else if (Sec.isBundleGroupBeforeFirstInst()) |
500 | report_fatal_error(reason: "Empty bundle-locked group is forbidden" ); |
501 | |
502 | Sec.setBundleLockState(MCSection::NotBundleLocked); |
503 | } |
504 | |
505 | void MCELFStreamer::finishImpl() { |
506 | // Emit the .gnu attributes section if any attributes have been added. |
507 | if (!GNUAttributes.empty()) { |
508 | MCSection *DummyAttributeSection = nullptr; |
509 | createAttributesSection(Vendor: "gnu" , Section: ".gnu.attributes" , Type: ELF::SHT_GNU_ATTRIBUTES, |
510 | AttributeSection&: DummyAttributeSection, AttrsVec&: GNUAttributes); |
511 | } |
512 | |
513 | // Ensure the last section gets aligned if necessary. |
514 | if (MCFragment *F = getCurrentFragment()) |
515 | setSectionAlignmentForBundling(Assembler: getAssembler(), Section: F->getParent()); |
516 | |
517 | finalizeCGProfile(); |
518 | emitFrames(MAB: nullptr); |
519 | |
520 | this->MCObjectStreamer::finishImpl(); |
521 | } |
522 | |
523 | void MCELFStreamer::setAttributeItem(unsigned Attribute, unsigned Value, |
524 | bool OverwriteExisting) { |
525 | // Look for existing attribute item |
526 | if (AttributeItem *Item = getAttributeItem(Attribute)) { |
527 | if (!OverwriteExisting) |
528 | return; |
529 | Item->Type = AttributeItem::NumericAttribute; |
530 | Item->IntValue = Value; |
531 | return; |
532 | } |
533 | |
534 | // Create new attribute item |
535 | AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value, |
536 | std::string(StringRef("" ))}; |
537 | Contents.push_back(Elt: Item); |
538 | } |
539 | |
540 | void MCELFStreamer::setAttributeItem(unsigned Attribute, StringRef Value, |
541 | bool OverwriteExisting) { |
542 | // Look for existing attribute item |
543 | if (AttributeItem *Item = getAttributeItem(Attribute)) { |
544 | if (!OverwriteExisting) |
545 | return; |
546 | Item->Type = AttributeItem::TextAttribute; |
547 | Item->StringValue = std::string(Value); |
548 | return; |
549 | } |
550 | |
551 | // Create new attribute item |
552 | AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, |
553 | std::string(Value)}; |
554 | Contents.push_back(Elt: Item); |
555 | } |
556 | |
557 | void MCELFStreamer::setAttributeItems(unsigned Attribute, unsigned IntValue, |
558 | StringRef StringValue, |
559 | bool OverwriteExisting) { |
560 | // Look for existing attribute item |
561 | if (AttributeItem *Item = getAttributeItem(Attribute)) { |
562 | if (!OverwriteExisting) |
563 | return; |
564 | Item->Type = AttributeItem::NumericAndTextAttributes; |
565 | Item->IntValue = IntValue; |
566 | Item->StringValue = std::string(StringValue); |
567 | return; |
568 | } |
569 | |
570 | // Create new attribute item |
571 | AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, |
572 | IntValue, std::string(StringValue)}; |
573 | Contents.push_back(Elt: Item); |
574 | } |
575 | |
576 | MCELFStreamer::AttributeItem * |
577 | MCELFStreamer::getAttributeItem(unsigned Attribute) { |
578 | for (AttributeItem &Item : Contents) |
579 | if (Item.Tag == Attribute) |
580 | return &Item; |
581 | return nullptr; |
582 | } |
583 | |
584 | size_t MCELFStreamer::calculateContentSize( |
585 | SmallVector<AttributeItem, 64> &AttrsVec) const { |
586 | size_t Result = 0; |
587 | for (const AttributeItem &Item : AttrsVec) { |
588 | switch (Item.Type) { |
589 | case AttributeItem::HiddenAttribute: |
590 | break; |
591 | case AttributeItem::NumericAttribute: |
592 | Result += getULEB128Size(Value: Item.Tag); |
593 | Result += getULEB128Size(Value: Item.IntValue); |
594 | break; |
595 | case AttributeItem::TextAttribute: |
596 | Result += getULEB128Size(Value: Item.Tag); |
597 | Result += Item.StringValue.size() + 1; // string + '\0' |
598 | break; |
599 | case AttributeItem::NumericAndTextAttributes: |
600 | Result += getULEB128Size(Value: Item.Tag); |
601 | Result += getULEB128Size(Value: Item.IntValue); |
602 | Result += Item.StringValue.size() + 1; // string + '\0'; |
603 | break; |
604 | } |
605 | } |
606 | return Result; |
607 | } |
608 | |
609 | void MCELFStreamer::createAttributesSection( |
610 | StringRef Vendor, const Twine &Section, unsigned Type, |
611 | MCSection *&AttributeSection, SmallVector<AttributeItem, 64> &AttrsVec) { |
612 | // <format-version> |
613 | // [ <section-length> "vendor-name" |
614 | // [ <file-tag> <size> <attribute>* |
615 | // | <section-tag> <size> <section-number>* 0 <attribute>* |
616 | // | <symbol-tag> <size> <symbol-number>* 0 <attribute>* |
617 | // ]+ |
618 | // ]* |
619 | |
620 | // Switch section to AttributeSection or get/create the section. |
621 | if (AttributeSection) { |
622 | switchSection(Section: AttributeSection); |
623 | } else { |
624 | AttributeSection = getContext().getELFSection(Section, Type, Flags: 0); |
625 | switchSection(Section: AttributeSection); |
626 | |
627 | // Format version |
628 | emitInt8(Value: 0x41); |
629 | } |
630 | |
631 | // Vendor size + Vendor name + '\0' |
632 | const size_t = 4 + Vendor.size() + 1; |
633 | |
634 | // Tag + Tag Size |
635 | const size_t = 1 + 4; |
636 | |
637 | const size_t ContentsSize = calculateContentSize(AttrsVec); |
638 | |
639 | emitInt32(Value: VendorHeaderSize + TagHeaderSize + ContentsSize); |
640 | emitBytes(Data: Vendor); |
641 | emitInt8(Value: 0); // '\0' |
642 | |
643 | emitInt8(Value: ARMBuildAttrs::File); |
644 | emitInt32(Value: TagHeaderSize + ContentsSize); |
645 | |
646 | // Size should have been accounted for already, now |
647 | // emit each field as its type (ULEB or String) |
648 | for (const AttributeItem &Item : AttrsVec) { |
649 | emitULEB128IntValue(Value: Item.Tag); |
650 | switch (Item.Type) { |
651 | default: |
652 | llvm_unreachable("Invalid attribute type" ); |
653 | case AttributeItem::NumericAttribute: |
654 | emitULEB128IntValue(Value: Item.IntValue); |
655 | break; |
656 | case AttributeItem::TextAttribute: |
657 | emitBytes(Data: Item.StringValue); |
658 | emitInt8(Value: 0); // '\0' |
659 | break; |
660 | case AttributeItem::NumericAndTextAttributes: |
661 | emitULEB128IntValue(Value: Item.IntValue); |
662 | emitBytes(Data: Item.StringValue); |
663 | emitInt8(Value: 0); // '\0' |
664 | break; |
665 | } |
666 | } |
667 | |
668 | AttrsVec.clear(); |
669 | } |
670 | |
671 | void MCELFStreamer::createAttributesWithSubsection( |
672 | MCSection *&AttributeSection, const Twine &Section, unsigned Type, |
673 | SmallVector<AttributeSubSection, 64> &SubSectionVec) { |
674 | // <format-version: 'A'> |
675 | // [ <uint32: subsection-length> NTBS: vendor-name |
676 | // <bytes: vendor-data> |
677 | // ]* |
678 | // vendor-data expends to: |
679 | // <uint8: optional> <uint8: parameter type> <attribute>* |
680 | if (0 == SubSectionVec.size()) { |
681 | return; |
682 | } |
683 | |
684 | // Switch section to AttributeSection or get/create the section. |
685 | if (AttributeSection) { |
686 | switchSection(Section: AttributeSection); |
687 | } else { |
688 | AttributeSection = getContext().getELFSection(Section, Type, Flags: 0); |
689 | switchSection(Section: AttributeSection); |
690 | |
691 | // Format version |
692 | emitInt8(Value: 0x41); |
693 | } |
694 | |
695 | for (AttributeSubSection &SubSection : SubSectionVec) { |
696 | // subsection-length + vendor-name + '\0' |
697 | const size_t = 4 + SubSection.VendorName.size() + 1; |
698 | // optional + parameter-type |
699 | const size_t VendorParameters = 1 + 1; |
700 | const size_t ContentsSize = calculateContentSize(AttrsVec&: SubSection.Content); |
701 | |
702 | emitInt32(Value: VendorHeaderSize + VendorParameters + ContentsSize); |
703 | emitBytes(Data: SubSection.VendorName); |
704 | emitInt8(Value: 0); // '\0' |
705 | emitInt8(Value: SubSection.IsOptional); |
706 | emitInt8(Value: SubSection.ParameterType); |
707 | |
708 | for (AttributeItem &Item : SubSection.Content) { |
709 | emitULEB128IntValue(Value: Item.Tag); |
710 | switch (Item.Type) { |
711 | default: |
712 | assert(0 && "Invalid attribute type" ); |
713 | break; |
714 | case AttributeItem::NumericAttribute: |
715 | emitULEB128IntValue(Value: Item.IntValue); |
716 | break; |
717 | case AttributeItem::TextAttribute: |
718 | emitBytes(Data: Item.StringValue); |
719 | emitInt8(Value: 0); // '\0' |
720 | break; |
721 | case AttributeItem::NumericAndTextAttributes: |
722 | emitULEB128IntValue(Value: Item.IntValue); |
723 | emitBytes(Data: Item.StringValue); |
724 | emitInt8(Value: 0); // '\0' |
725 | break; |
726 | } |
727 | } |
728 | } |
729 | SubSectionVec.clear(); |
730 | } |
731 | |
732 | MCStreamer *llvm::createELFStreamer(MCContext &Context, |
733 | std::unique_ptr<MCAsmBackend> &&MAB, |
734 | std::unique_ptr<MCObjectWriter> &&OW, |
735 | std::unique_ptr<MCCodeEmitter> &&CE) { |
736 | MCELFStreamer *S = |
737 | new MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); |
738 | return S; |
739 | } |
740 | |