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/MCDirectives.h"
22#include "llvm/MC/MCELFObjectWriter.h"
23#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCFixup.h"
25#include "llvm/MC/MCLFI.h"
26#include "llvm/MC/MCObjectFileInfo.h"
27#include "llvm/MC/MCObjectWriter.h"
28#include "llvm/MC/MCSection.h"
29#include "llvm/MC/MCSectionELF.h"
30#include "llvm/MC/MCStreamer.h"
31#include "llvm/MC/MCSymbol.h"
32#include "llvm/MC/MCSymbolELF.h"
33#include "llvm/MC/MCTargetOptions.h"
34#include "llvm/MC/TargetRegistry.h"
35#include "llvm/Support/ErrorHandling.h"
36#include "llvm/Support/LEB128.h"
37#include <cassert>
38#include <cstdint>
39
40using namespace llvm;
41
42MCELFStreamer::MCELFStreamer(MCContext &Context,
43 std::unique_ptr<MCAsmBackend> TAB,
44 std::unique_ptr<MCObjectWriter> OW,
45 std::unique_ptr<MCCodeEmitter> Emitter)
46 : MCObjectStreamer(Context, std::move(TAB), std::move(OW),
47 std::move(Emitter)) {}
48
49ELFObjectWriter &MCELFStreamer::getWriter() {
50 return static_cast<ELFObjectWriter &>(getAssembler().getWriter());
51}
52
53void MCELFStreamer::initSections(const MCSubtargetInfo &STI) {
54 MCContext &Ctx = getContext();
55 switchSection(Section: Ctx.getObjectFileInfo()->getTextSection());
56 emitCodeAlignment(ByteAlignment: Align(Ctx.getObjectFileInfo()->getTextSectionAlignment()),
57 STI: &STI);
58}
59
60void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
61 auto *Symbol = static_cast<MCSymbolELF *>(S);
62 MCObjectStreamer::emitLabel(Symbol, Loc);
63
64 const MCSectionELF &Section =
65 static_cast<const MCSectionELF &>(*getCurrentSectionOnly());
66 if (Section.getFlags() & ELF::SHF_TLS)
67 Symbol->setType(ELF::STT_TLS);
68}
69
70void MCELFStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment &F,
71 uint64_t Offset) {
72 auto *Symbol = static_cast<MCSymbolELF *>(S);
73 MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset);
74
75 const MCSectionELF &Section =
76 static_cast<const MCSectionELF &>(*getCurrentSectionOnly());
77 if (Section.getFlags() & ELF::SHF_TLS)
78 Symbol->setType(ELF::STT_TLS);
79}
80
81void MCELFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
82 MCAssembler &Asm = getAssembler();
83 auto *SectionELF = static_cast<const MCSectionELF *>(Section);
84 const MCSymbol *Grp = SectionELF->getGroup();
85 if (Grp)
86 Asm.registerSymbol(Symbol: *Grp);
87 if (SectionELF->getFlags() & ELF::SHF_GNU_RETAIN)
88 getWriter().markGnuAbi();
89
90 MCObjectStreamer::changeSection(Section, Subsection);
91 auto *Sym = static_cast<MCSymbolELF *>(Section->getBeginSymbol());
92 Sym->setBinding(ELF::STB_LOCAL);
93 Sym->setType(ELF::STT_SECTION);
94}
95
96void MCELFStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) {
97 auto *A = static_cast<MCSymbolELF *>(Alias);
98 if (A->isDefined()) {
99 getContext().reportError(L: getStartTokLoc(), Msg: "symbol '" + A->getName() +
100 "' is already defined");
101 return;
102 }
103 A->setVariableValue(MCSymbolRefExpr::create(Symbol: Target, Ctx&: getContext()));
104 A->setIsWeakref();
105 getWriter().Weakrefs.push_back(Elt: A);
106}
107
108// When GNU as encounters more than one .type declaration for an object it seems
109// to use a mechanism similar to the one below to decide which type is actually
110// used in the object file. The greater of T1 and T2 is selected based on the
111// following ordering:
112// STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else
113// If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user
114// provided type).
115static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) {
116 for (unsigned Type : {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC,
117 ELF::STT_GNU_IFUNC, ELF::STT_TLS}) {
118 if (T1 == Type)
119 return T2;
120 if (T2 == Type)
121 return T1;
122 }
123
124 return T2;
125}
126
127bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
128 auto *Symbol = static_cast<MCSymbolELF *>(S);
129
130 // Adding a symbol attribute always introduces the symbol, note that an
131 // important side effect of calling registerSymbol here is to register
132 // the symbol with the assembler.
133 getAssembler().registerSymbol(Symbol: *Symbol);
134
135 // The implementation of symbol attributes is designed to match 'as', but it
136 // leaves much to desired. It doesn't really make sense to arbitrarily add and
137 // remove flags, but 'as' allows this (in particular, see .desc).
138 //
139 // In the future it might be worth trying to make these operations more well
140 // defined.
141 switch (Attribute) {
142 case MCSA_Cold:
143 case MCSA_Extern:
144 case MCSA_LazyReference:
145 case MCSA_Reference:
146 case MCSA_SymbolResolver:
147 case MCSA_PrivateExtern:
148 case MCSA_WeakDefinition:
149 case MCSA_WeakDefAutoPrivate:
150 case MCSA_Invalid:
151 case MCSA_IndirectSymbol:
152 case MCSA_Exported:
153 case MCSA_WeakAntiDep:
154 case MCSA_OSLinkage:
155 case MCSA_XPLinkage:
156 return false;
157
158 case MCSA_NoDeadStrip:
159 // Ignore for now.
160 break;
161
162 case MCSA_ELF_TypeGnuUniqueObject:
163 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_OBJECT));
164 Symbol->setBinding(ELF::STB_GNU_UNIQUE);
165 getWriter().markGnuAbi();
166 break;
167
168 case MCSA_Global:
169 // For `.weak x; .global x`, GNU as sets the binding to STB_WEAK while we
170 // traditionally set the binding to STB_GLOBAL. This is error-prone, so we
171 // error on such cases. Note, we also disallow changed binding from .local.
172 if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_GLOBAL)
173 getContext().reportError(L: getStartTokLoc(),
174 Msg: Symbol->getName() +
175 " changed binding to STB_GLOBAL");
176 Symbol->setBinding(ELF::STB_GLOBAL);
177 break;
178
179 case MCSA_WeakReference:
180 case MCSA_Weak:
181 // For `.global x; .weak x`, both MC and GNU as set the binding to STB_WEAK.
182 // We emit a warning for now but may switch to an error in the future.
183 if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_WEAK)
184 getContext().reportWarning(
185 L: getStartTokLoc(), Msg: Symbol->getName() + " changed binding to STB_WEAK");
186 Symbol->setBinding(ELF::STB_WEAK);
187 break;
188
189 case MCSA_Local:
190 if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_LOCAL)
191 getContext().reportError(L: getStartTokLoc(),
192 Msg: Symbol->getName() +
193 " changed binding to STB_LOCAL");
194 Symbol->setBinding(ELF::STB_LOCAL);
195 break;
196
197 case MCSA_ELF_TypeFunction:
198 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_FUNC));
199 break;
200
201 case MCSA_ELF_TypeIndFunction:
202 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_GNU_IFUNC));
203 getWriter().markGnuAbi();
204 break;
205
206 case MCSA_ELF_TypeObject:
207 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_OBJECT));
208 break;
209
210 case MCSA_ELF_TypeTLS:
211 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_TLS));
212 break;
213
214 case MCSA_ELF_TypeCommon:
215 // TODO: Emit these as a common symbol.
216 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_OBJECT));
217 break;
218
219 case MCSA_ELF_TypeNoType:
220 Symbol->setType(CombineSymbolTypes(T1: Symbol->getType(), T2: ELF::STT_NOTYPE));
221 break;
222
223 case MCSA_Protected:
224 Symbol->setVisibility(ELF::STV_PROTECTED);
225 break;
226
227 case MCSA_Memtag:
228 Symbol->setMemtag(true);
229 break;
230
231 case MCSA_Hidden:
232 Symbol->setVisibility(ELF::STV_HIDDEN);
233 break;
234
235 case MCSA_Internal:
236 Symbol->setVisibility(ELF::STV_INTERNAL);
237 break;
238
239 case MCSA_AltEntry:
240 llvm_unreachable("ELF doesn't support the .alt_entry attribute");
241
242 case MCSA_LGlobal:
243 llvm_unreachable("ELF doesn't support the .lglobl attribute");
244 }
245
246 return true;
247}
248
249void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
250 Align ByteAlignment) {
251 auto *Symbol = static_cast<MCSymbolELF *>(S);
252 getAssembler().registerSymbol(Symbol: *Symbol);
253
254 if (!Symbol->isBindingSet())
255 Symbol->setBinding(ELF::STB_GLOBAL);
256
257 Symbol->setType(ELF::STT_OBJECT);
258
259 if (Symbol->getBinding() == ELF::STB_LOCAL) {
260 MCSection &Section = *getAssembler().getContext().getELFSection(
261 Section: ".bss", Type: ELF::SHT_NOBITS, Flags: ELF::SHF_WRITE | ELF::SHF_ALLOC);
262 MCSectionSubPair P = getCurrentSection();
263 switchSection(Section: &Section);
264
265 emitValueToAlignment(Alignment: ByteAlignment, Fill: 0, FillLen: 1, MaxBytesToEmit: 0);
266 emitLabel(S: Symbol);
267 emitZeros(NumBytes: Size);
268
269 switchSection(Section: P.first, Subsec: P.second);
270 } else {
271 if (Symbol->declareCommon(Size, Alignment: ByteAlignment))
272 report_fatal_error(reason: Twine("Symbol: ") + Symbol->getName() +
273 " redeclared as different type");
274 }
275
276 Symbol->setSize(MCConstantExpr::create(Value: Size, Ctx&: getContext()));
277}
278
279void MCELFStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
280 static_cast<MCSymbolELF *>(Symbol)->setSize(Value);
281}
282
283void MCELFStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
284 StringRef Name,
285 bool KeepOriginalSym) {
286 getWriter().Symvers.push_back(Elt: ELFObjectWriter::Symver{
287 .Loc: getStartTokLoc(), .Sym: OriginalSym, .Name: Name, .KeepOriginalSym: KeepOriginalSym});
288}
289
290void MCELFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
291 Align ByteAlignment) {
292 auto *Symbol = static_cast<MCSymbolELF *>(S);
293 // FIXME: Should this be caught and done earlier?
294 getAssembler().registerSymbol(Symbol: *Symbol);
295 Symbol->setBinding(ELF::STB_LOCAL);
296 emitCommonSymbol(S: Symbol, Size, ByteAlignment);
297}
298
299void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
300 const MCSymbolRefExpr *To,
301 uint64_t Count) {
302 getWriter().getCGProfile().push_back(Elt: {.From: From, .To: To, .Count: Count});
303}
304
305void MCELFStreamer::emitIdent(StringRef IdentString) {
306 MCSection *Comment = getAssembler().getContext().getELFSection(
307 Section: ".comment", Type: ELF::SHT_PROGBITS, Flags: ELF::SHF_MERGE | ELF::SHF_STRINGS, EntrySize: 1);
308 pushSection();
309 switchSection(Section: Comment);
310 if (!SeenIdent) {
311 emitInt8(Value: 0);
312 SeenIdent = true;
313 }
314 emitBytes(Data: IdentString);
315 emitInt8(Value: 0);
316 popSection();
317}
318
319void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *Sym,
320 uint64_t Offset,
321 const MCSymbolRefExpr *&SRE) {
322 const MCSymbol *S = &SRE->getSymbol();
323 if (S->isTemporary()) {
324 if (!S->isInSection()) {
325 getContext().reportError(
326 L: SRE->getLoc(), Msg: Twine("Reference to undefined temporary symbol ") +
327 "`" + S->getName() + "`");
328 return;
329 }
330 S = S->getSection().getBeginSymbol();
331 S->setUsedInReloc();
332 SRE = MCSymbolRefExpr::create(Symbol: S, Ctx&: getContext(), Loc: SRE->getLoc());
333 }
334 auto *O = MCBinaryExpr::createAdd(
335 LHS: Sym, RHS: MCConstantExpr::create(Value: Offset, Ctx&: getContext()), Ctx&: getContext());
336 MCObjectStreamer::emitRelocDirective(Offset: *O, Name: "BFD_RELOC_NONE", Expr: SRE);
337}
338
339void MCELFStreamer::finalizeCGProfile() {
340 ELFObjectWriter &W = getWriter();
341 if (W.getCGProfile().empty())
342 return;
343 MCSection *CGProfile = getAssembler().getContext().getELFSection(
344 Section: ".llvm.call-graph-profile", Type: ELF::SHT_LLVM_CALL_GRAPH_PROFILE,
345 Flags: ELF::SHF_EXCLUDE, /*sizeof(Elf_CGProfile_Impl<>)=*/EntrySize: 8);
346 pushSection();
347 switchSection(Section: CGProfile);
348 uint64_t Offset = 0;
349 auto *Sym =
350 MCSymbolRefExpr::create(Symbol: CGProfile->getBeginSymbol(), Ctx&: getContext());
351 for (auto &E : W.getCGProfile()) {
352 finalizeCGProfileEntry(Sym, Offset, SRE&: E.From);
353 finalizeCGProfileEntry(Sym, Offset, SRE&: E.To);
354 emitIntValue(Value: E.Count, Size: sizeof(uint64_t));
355 Offset += sizeof(uint64_t);
356 }
357 popSection();
358}
359
360void MCELFStreamer::finishImpl() {
361 // Emit .note.GNU-stack, similar to AsmPrinter::doFinalization.
362 MCContext &Ctx = getContext();
363 if (const MCTargetOptions *TO = Ctx.getTargetOptions()) {
364 auto *StackSec = Ctx.getAsmInfo()->getStackSection(Ctx,
365 /*Exec=*/false);
366 if (StackSec && TO->MCNoExecStack)
367 switchSection(Section: StackSec);
368 }
369
370 // Emit the .gnu attributes section if any attributes have been added.
371 if (!GNUAttributes.empty()) {
372 MCSection *DummyAttributeSection = nullptr;
373 createAttributesSection(Vendor: "gnu", Section: ".gnu.attributes", Type: ELF::SHT_GNU_ATTRIBUTES,
374 AttributeSection&: DummyAttributeSection, AttrsVec&: GNUAttributes);
375 }
376
377 if (Ctx.getTargetTriple().isLFI())
378 emitLFINoteSection(Streamer&: *this, Ctx);
379
380 finalizeCGProfile();
381 emitFrames();
382
383 this->MCObjectStreamer::finishImpl();
384}
385
386void MCELFStreamer::setAttributeItem(unsigned Attribute, unsigned Value,
387 bool OverwriteExisting) {
388 // Look for existing attribute item
389 if (AttributeItem *Item = getAttributeItem(Attribute)) {
390 if (!OverwriteExisting)
391 return;
392 Item->Type = AttributeItem::NumericAttribute;
393 Item->IntValue = Value;
394 return;
395 }
396
397 // Create new attribute item
398 AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value,
399 std::string(StringRef(""))};
400 Contents.push_back(Elt: Item);
401}
402
403void MCELFStreamer::setAttributeItem(unsigned Attribute, StringRef Value,
404 bool OverwriteExisting) {
405 // Look for existing attribute item
406 if (AttributeItem *Item = getAttributeItem(Attribute)) {
407 if (!OverwriteExisting)
408 return;
409 Item->Type = AttributeItem::TextAttribute;
410 Item->StringValue = std::string(Value);
411 return;
412 }
413
414 // Create new attribute item
415 AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0,
416 std::string(Value)};
417 Contents.push_back(Elt: Item);
418}
419
420void MCELFStreamer::setAttributeItems(unsigned Attribute, unsigned IntValue,
421 StringRef StringValue,
422 bool OverwriteExisting) {
423 // Look for existing attribute item
424 if (AttributeItem *Item = getAttributeItem(Attribute)) {
425 if (!OverwriteExisting)
426 return;
427 Item->Type = AttributeItem::NumericAndTextAttributes;
428 Item->IntValue = IntValue;
429 Item->StringValue = std::string(StringValue);
430 return;
431 }
432
433 // Create new attribute item
434 AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute,
435 IntValue, std::string(StringValue)};
436 Contents.push_back(Elt: Item);
437}
438
439MCELFStreamer::AttributeItem *
440MCELFStreamer::getAttributeItem(unsigned Attribute) {
441 for (AttributeItem &Item : Contents)
442 if (Item.Tag == Attribute)
443 return &Item;
444 return nullptr;
445}
446
447size_t MCELFStreamer::calculateContentSize(
448 SmallVector<AttributeItem, 64> &AttrsVec) const {
449 size_t Result = 0;
450 for (const AttributeItem &Item : AttrsVec) {
451 switch (Item.Type) {
452 case AttributeItem::HiddenAttribute:
453 break;
454 case AttributeItem::NumericAttribute:
455 Result += getULEB128Size(Value: Item.Tag);
456 Result += getULEB128Size(Value: Item.IntValue);
457 break;
458 case AttributeItem::TextAttribute:
459 Result += getULEB128Size(Value: Item.Tag);
460 Result += Item.StringValue.size() + 1; // string + '\0'
461 break;
462 case AttributeItem::NumericAndTextAttributes:
463 Result += getULEB128Size(Value: Item.Tag);
464 Result += getULEB128Size(Value: Item.IntValue);
465 Result += Item.StringValue.size() + 1; // string + '\0';
466 break;
467 }
468 }
469 return Result;
470}
471
472void MCELFStreamer::createAttributesSection(
473 StringRef Vendor, const Twine &Section, unsigned Type,
474 MCSection *&AttributeSection, SmallVector<AttributeItem, 64> &AttrsVec) {
475 // <format-version>
476 // [ <section-length> "vendor-name"
477 // [ <file-tag> <size> <attribute>*
478 // | <section-tag> <size> <section-number>* 0 <attribute>*
479 // | <symbol-tag> <size> <symbol-number>* 0 <attribute>*
480 // ]+
481 // ]*
482
483 // Switch section to AttributeSection or get/create the section.
484 if (AttributeSection) {
485 switchSection(Section: AttributeSection);
486 } else {
487 AttributeSection = getContext().getELFSection(Section, Type, Flags: 0);
488 switchSection(Section: AttributeSection);
489
490 // Format version
491 emitInt8(Value: 0x41);
492 }
493
494 // Vendor size + Vendor name + '\0'
495 const size_t VendorHeaderSize = 4 + Vendor.size() + 1;
496
497 // Tag + Tag Size
498 const size_t TagHeaderSize = 1 + 4;
499
500 const size_t ContentsSize = calculateContentSize(AttrsVec);
501
502 emitInt32(Value: VendorHeaderSize + TagHeaderSize + ContentsSize);
503 emitBytes(Data: Vendor);
504 emitInt8(Value: 0); // '\0'
505
506 emitInt8(Value: ARMBuildAttrs::File);
507 emitInt32(Value: TagHeaderSize + ContentsSize);
508
509 // Size should have been accounted for already, now
510 // emit each field as its type (ULEB or String)
511 for (const AttributeItem &Item : AttrsVec) {
512 emitULEB128IntValue(Value: Item.Tag);
513 switch (Item.Type) {
514 default:
515 llvm_unreachable("Invalid attribute type");
516 case AttributeItem::NumericAttribute:
517 emitULEB128IntValue(Value: Item.IntValue);
518 break;
519 case AttributeItem::TextAttribute:
520 emitBytes(Data: Item.StringValue);
521 emitInt8(Value: 0); // '\0'
522 break;
523 case AttributeItem::NumericAndTextAttributes:
524 emitULEB128IntValue(Value: Item.IntValue);
525 emitBytes(Data: Item.StringValue);
526 emitInt8(Value: 0); // '\0'
527 break;
528 }
529 }
530
531 AttrsVec.clear();
532}
533
534void MCELFStreamer::createAttributesWithSubsection(
535 MCSection *&AttributeSection, const Twine &Section, unsigned Type,
536 SmallVector<AttributeSubSection, 64> &SubSectionVec) {
537 // <format-version: 'A'>
538 // [ <uint32: subsection-length> NTBS: vendor-name
539 // <bytes: vendor-data>
540 // ]*
541 // vendor-data expends to:
542 // <uint8: optional> <uint8: parameter type> <attribute>*
543 if (0 == SubSectionVec.size()) {
544 return;
545 }
546
547 // Switch section to AttributeSection or get/create the section.
548 if (AttributeSection) {
549 switchSection(Section: AttributeSection);
550 } else {
551 AttributeSection = getContext().getELFSection(Section, Type, Flags: 0);
552 switchSection(Section: AttributeSection);
553
554 // Format version
555 emitInt8(Value: 0x41);
556 }
557
558 for (AttributeSubSection &SubSection : SubSectionVec) {
559 // subsection-length + vendor-name + '\0'
560 const size_t VendorHeaderSize = 4 + SubSection.VendorName.size() + 1;
561 // optional + parameter-type
562 const size_t VendorParameters = 1 + 1;
563 const size_t ContentsSize = calculateContentSize(AttrsVec&: SubSection.Content);
564
565 emitInt32(Value: VendorHeaderSize + VendorParameters + ContentsSize);
566 emitBytes(Data: SubSection.VendorName);
567 emitInt8(Value: 0); // '\0'
568 emitInt8(Value: SubSection.IsOptional);
569 emitInt8(Value: SubSection.ParameterType);
570
571 for (AttributeItem &Item : SubSection.Content) {
572 emitULEB128IntValue(Value: Item.Tag);
573 switch (Item.Type) {
574 default:
575 assert(0 && "Invalid attribute type");
576 break;
577 case AttributeItem::NumericAttribute:
578 emitULEB128IntValue(Value: Item.IntValue);
579 break;
580 case AttributeItem::TextAttribute:
581 emitBytes(Data: Item.StringValue);
582 emitInt8(Value: 0); // '\0'
583 break;
584 case AttributeItem::NumericAndTextAttributes:
585 emitULEB128IntValue(Value: Item.IntValue);
586 emitBytes(Data: Item.StringValue);
587 emitInt8(Value: 0); // '\0'
588 break;
589 }
590 }
591 }
592 SubSectionVec.clear();
593}
594
595MCStreamer *llvm::createELFStreamer(MCContext &Context,
596 std::unique_ptr<MCAsmBackend> &&MAB,
597 std::unique_ptr<MCObjectWriter> &&OW,
598 std::unique_ptr<MCCodeEmitter> &&CE) {
599 MCELFStreamer *S =
600 new MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
601 return S;
602}
603