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