| //===- lib/MC/MCELFStreamer.cpp - ELF Object Output -----------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file assembles .s files and emits ELF .o object files. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/MC/MCELFStreamer.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/BinaryFormat/ELF.h" |
| #include "llvm/MC/MCAsmBackend.h" |
| #include "llvm/MC/MCAsmInfo.h" |
| #include "llvm/MC/MCAssembler.h" |
| #include "llvm/MC/MCCodeEmitter.h" |
| #include "llvm/MC/MCContext.h" |
| #include "llvm/MC/MCExpr.h" |
| #include "llvm/MC/MCFixup.h" |
| #include "llvm/MC/MCFragment.h" |
| #include "llvm/MC/MCObjectFileInfo.h" |
| #include "llvm/MC/MCObjectWriter.h" |
| #include "llvm/MC/MCSection.h" |
| #include "llvm/MC/MCSectionELF.h" |
| #include "llvm/MC/MCStreamer.h" |
| #include "llvm/MC/MCSymbol.h" |
| #include "llvm/MC/MCSymbolELF.h" |
| #include "llvm/MC/TargetRegistry.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/LEB128.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <cassert> |
| #include <cstdint> |
| |
| using namespace llvm; |
| |
| MCELFStreamer::MCELFStreamer(MCContext &Context, |
| std::unique_ptr<MCAsmBackend> TAB, |
| std::unique_ptr<MCObjectWriter> OW, |
| std::unique_ptr<MCCodeEmitter> Emitter) |
| : MCObjectStreamer(Context, std::move(TAB), std::move(OW), |
| std::move(Emitter)) {} |
| |
| bool MCELFStreamer::isBundleLocked() const { |
| return getCurrentSectionOnly()->isBundleLocked(); |
| } |
| |
| void MCELFStreamer::mergeFragment(MCDataFragment *DF, |
| MCDataFragment *EF) { |
| MCAssembler &Assembler = getAssembler(); |
| |
| if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { |
| uint64_t FSize = EF->getContents().size(); |
| |
| if (FSize > Assembler.getBundleAlignSize()) |
| report_fatal_error("Fragment can't be larger than a bundle size"); |
| |
| uint64_t RequiredBundlePadding = computeBundlePadding( |
| Assembler, EF, DF->getContents().size(), FSize); |
| |
| if (RequiredBundlePadding > UINT8_MAX) |
| report_fatal_error("Padding cannot exceed 255 bytes"); |
| |
| if (RequiredBundlePadding > 0) { |
| SmallString<256> Code; |
| raw_svector_ostream VecOS(Code); |
| EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); |
| Assembler.writeFragmentPadding(VecOS, *EF, FSize); |
| |
| DF->getContents().append(Code.begin(), Code.end()); |
| } |
| } |
| |
| flushPendingLabels(DF, DF->getContents().size()); |
| |
| for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) { |
| EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() + |
| DF->getContents().size()); |
| DF->getFixups().push_back(EF->getFixups()[i]); |
| } |
| if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo()) |
| DF->setHasInstructions(*EF->getSubtargetInfo()); |
| DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); |
| } |
| |
| void MCELFStreamer::initSections(bool NoExecStack, const MCSubtargetInfo &STI) { |
| MCContext &Ctx = getContext(); |
| switchSection(Ctx.getObjectFileInfo()->getTextSection()); |
| emitCodeAlignment(Align(Ctx.getObjectFileInfo()->getTextSectionAlignment()), |
| &STI); |
| |
| if (NoExecStack) |
| switchSection(Ctx.getAsmInfo()->getNonexecutableStackSection(Ctx)); |
| } |
| |
| void MCELFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) { |
| auto *Symbol = cast<MCSymbolELF>(S); |
| MCObjectStreamer::emitLabel(Symbol, Loc); |
| |
| const MCSectionELF &Section = |
| static_cast<const MCSectionELF &>(*getCurrentSectionOnly()); |
| if (Section.getFlags() & ELF::SHF_TLS) |
| Symbol->setType(ELF::STT_TLS); |
| } |
| |
| void MCELFStreamer::emitLabelAtPos(MCSymbol *S, SMLoc Loc, MCFragment *F, |
| uint64_t Offset) { |
| auto *Symbol = cast<MCSymbolELF>(S); |
| MCObjectStreamer::emitLabelAtPos(Symbol, Loc, F, Offset); |
| |
| const MCSectionELF &Section = |
| static_cast<const MCSectionELF &>(*getCurrentSectionOnly()); |
| if (Section.getFlags() & ELF::SHF_TLS) |
| Symbol->setType(ELF::STT_TLS); |
| } |
| |
| void MCELFStreamer::emitAssemblerFlag(MCAssemblerFlag Flag) { |
| // Let the target do whatever target specific stuff it needs to do. |
| getAssembler().getBackend().handleAssemblerFlag(Flag); |
| // Do any generic stuff we need to do. |
| switch (Flag) { |
| case MCAF_SyntaxUnified: return; // no-op here. |
| case MCAF_Code16: return; // Change parsing mode; no-op here. |
| case MCAF_Code32: return; // Change parsing mode; no-op here. |
| case MCAF_Code64: return; // Change parsing mode; no-op here. |
| case MCAF_SubsectionsViaSymbols: |
| getAssembler().setSubsectionsViaSymbols(true); |
| return; |
| } |
| |
| llvm_unreachable("invalid assembler flag!"); |
| } |
| |
| // If bundle alignment is used and there are any instructions in the section, it |
| // needs to be aligned to at least the bundle size. |
| static void setSectionAlignmentForBundling(const MCAssembler &Assembler, |
| MCSection *Section) { |
| if (Section && Assembler.isBundlingEnabled() && Section->hasInstructions()) |
| Section->ensureMinAlignment(Align(Assembler.getBundleAlignSize())); |
| } |
| |
| void MCELFStreamer::changeSection(MCSection *Section, |
| const MCExpr *Subsection) { |
| MCSection *CurSection = getCurrentSectionOnly(); |
| if (CurSection && isBundleLocked()) |
| report_fatal_error("Unterminated .bundle_lock when changing a section"); |
| |
| MCAssembler &Asm = getAssembler(); |
| // Ensure the previous section gets aligned if necessary. |
| setSectionAlignmentForBundling(Asm, CurSection); |
| auto *SectionELF = static_cast<const MCSectionELF *>(Section); |
| const MCSymbol *Grp = SectionELF->getGroup(); |
| if (Grp) |
| Asm.registerSymbol(*Grp); |
| if (SectionELF->getFlags() & ELF::SHF_GNU_RETAIN) |
| Asm.getWriter().markGnuAbi(); |
| |
| changeSectionImpl(Section, Subsection); |
| Asm.registerSymbol(*Section->getBeginSymbol()); |
| } |
| |
| void MCELFStreamer::emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { |
| getAssembler().registerSymbol(*Symbol); |
| const MCExpr *Value = MCSymbolRefExpr::create( |
| Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext()); |
| Alias->setVariableValue(Value); |
| } |
| |
| // When GNU as encounters more than one .type declaration for an object it seems |
| // to use a mechanism similar to the one below to decide which type is actually |
| // used in the object file. The greater of T1 and T2 is selected based on the |
| // following ordering: |
| // STT_NOTYPE < STT_OBJECT < STT_FUNC < STT_GNU_IFUNC < STT_TLS < anything else |
| // If neither T1 < T2 nor T2 < T1 according to this ordering, use T2 (the user |
| // provided type). |
| static unsigned CombineSymbolTypes(unsigned T1, unsigned T2) { |
| for (unsigned Type : {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC, |
| ELF::STT_GNU_IFUNC, ELF::STT_TLS}) { |
| if (T1 == Type) |
| return T2; |
| if (T2 == Type) |
| return T1; |
| } |
| |
| return T2; |
| } |
| |
| bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { |
| auto *Symbol = cast<MCSymbolELF>(S); |
| |
| // Adding a symbol attribute always introduces the symbol, note that an |
| // important side effect of calling registerSymbol here is to register |
| // the symbol with the assembler. |
| getAssembler().registerSymbol(*Symbol); |
| |
| // The implementation of symbol attributes is designed to match 'as', but it |
| // leaves much to desired. It doesn't really make sense to arbitrarily add and |
| // remove flags, but 'as' allows this (in particular, see .desc). |
| // |
| // In the future it might be worth trying to make these operations more well |
| // defined. |
| switch (Attribute) { |
| case MCSA_Cold: |
| case MCSA_Extern: |
| case MCSA_LazyReference: |
| case MCSA_Reference: |
| case MCSA_SymbolResolver: |
| case MCSA_PrivateExtern: |
| case MCSA_WeakDefinition: |
| case MCSA_WeakDefAutoPrivate: |
| case MCSA_Invalid: |
| case MCSA_IndirectSymbol: |
| case MCSA_Exported: |
| return false; |
| |
| case MCSA_NoDeadStrip: |
| // Ignore for now. |
| break; |
| |
| case MCSA_ELF_TypeGnuUniqueObject: |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT)); |
| Symbol->setBinding(ELF::STB_GNU_UNIQUE); |
| getAssembler().getWriter().markGnuAbi(); |
| break; |
| |
| case MCSA_Global: |
| // For `.weak x; .global x`, GNU as sets the binding to STB_WEAK while we |
| // traditionally set the binding to STB_GLOBAL. This is error-prone, so we |
| // error on such cases. Note, we also disallow changed binding from .local. |
| if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_GLOBAL) |
| getContext().reportError(getStartTokLoc(), |
| Symbol->getName() + |
| " changed binding to STB_GLOBAL"); |
| Symbol->setBinding(ELF::STB_GLOBAL); |
| break; |
| |
| case MCSA_WeakReference: |
| case MCSA_Weak: |
| // For `.global x; .weak x`, both MC and GNU as set the binding to STB_WEAK. |
| // We emit a warning for now but may switch to an error in the future. |
| if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_WEAK) |
| getContext().reportWarning( |
| getStartTokLoc(), Symbol->getName() + " changed binding to STB_WEAK"); |
| Symbol->setBinding(ELF::STB_WEAK); |
| break; |
| |
| case MCSA_Local: |
| if (Symbol->isBindingSet() && Symbol->getBinding() != ELF::STB_LOCAL) |
| getContext().reportError(getStartTokLoc(), |
| Symbol->getName() + |
| " changed binding to STB_LOCAL"); |
| Symbol->setBinding(ELF::STB_LOCAL); |
| break; |
| |
| case MCSA_ELF_TypeFunction: |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_FUNC)); |
| break; |
| |
| case MCSA_ELF_TypeIndFunction: |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_GNU_IFUNC)); |
| getAssembler().getWriter().markGnuAbi(); |
| break; |
| |
| case MCSA_ELF_TypeObject: |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT)); |
| break; |
| |
| case MCSA_ELF_TypeTLS: |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_TLS)); |
| break; |
| |
| case MCSA_ELF_TypeCommon: |
| // TODO: Emit these as a common symbol. |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_OBJECT)); |
| break; |
| |
| case MCSA_ELF_TypeNoType: |
| Symbol->setType(CombineSymbolTypes(Symbol->getType(), ELF::STT_NOTYPE)); |
| break; |
| |
| case MCSA_Protected: |
| Symbol->setVisibility(ELF::STV_PROTECTED); |
| break; |
| |
| case MCSA_Memtag: |
| Symbol->setMemtag(true); |
| break; |
| |
| case MCSA_Hidden: |
| Symbol->setVisibility(ELF::STV_HIDDEN); |
| break; |
| |
| case MCSA_Internal: |
| Symbol->setVisibility(ELF::STV_INTERNAL); |
| break; |
| |
| case MCSA_AltEntry: |
| llvm_unreachable("ELF doesn't support the .alt_entry attribute"); |
| |
| case MCSA_LGlobal: |
| llvm_unreachable("ELF doesn't support the .lglobl attribute"); |
| } |
| |
| return true; |
| } |
| |
| void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size, |
| Align ByteAlignment) { |
| auto *Symbol = cast<MCSymbolELF>(S); |
| getAssembler().registerSymbol(*Symbol); |
| |
| if (!Symbol->isBindingSet()) |
| Symbol->setBinding(ELF::STB_GLOBAL); |
| |
| Symbol->setType(ELF::STT_OBJECT); |
| |
| if (Symbol->getBinding() == ELF::STB_LOCAL) { |
| MCSection &Section = *getAssembler().getContext().getELFSection( |
| ".bss", ELF::SHT_NOBITS, ELF::SHF_WRITE | ELF::SHF_ALLOC); |
| MCSectionSubPair P = getCurrentSection(); |
| switchSection(&Section); |
| |
| emitValueToAlignment(ByteAlignment, 0, 1, 0); |
| emitLabel(Symbol); |
| emitZeros(Size); |
| |
| switchSection(P.first, P.second); |
| } else { |
| if (Symbol->declareCommon(Size, ByteAlignment)) |
| report_fatal_error(Twine("Symbol: ") + Symbol->getName() + |
| " redeclared as different type"); |
| } |
| |
| cast<MCSymbolELF>(Symbol) |
| ->setSize(MCConstantExpr::create(Size, getContext())); |
| } |
| |
| void MCELFStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { |
| cast<MCSymbolELF>(Symbol)->setSize(Value); |
| } |
| |
| void MCELFStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym, |
| StringRef Name, |
| bool KeepOriginalSym) { |
| getAssembler().Symvers.push_back(MCAssembler::Symver{ |
| getStartTokLoc(), OriginalSym, Name, KeepOriginalSym}); |
| } |
| |
| void MCELFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size, |
| Align ByteAlignment) { |
| auto *Symbol = cast<MCSymbolELF>(S); |
| // FIXME: Should this be caught and done earlier? |
| getAssembler().registerSymbol(*Symbol); |
| Symbol->setBinding(ELF::STB_LOCAL); |
| emitCommonSymbol(Symbol, Size, ByteAlignment); |
| } |
| |
| void MCELFStreamer::emitValueImpl(const MCExpr *Value, unsigned Size, |
| SMLoc Loc) { |
| if (isBundleLocked()) |
| report_fatal_error("Emitting values inside a locked bundle is forbidden"); |
| fixSymbolsInTLSFixups(Value); |
| MCObjectStreamer::emitValueImpl(Value, Size, Loc); |
| } |
| |
| void MCELFStreamer::emitValueToAlignment(Align Alignment, int64_t Value, |
| unsigned ValueSize, |
| unsigned MaxBytesToEmit) { |
| if (isBundleLocked()) |
| report_fatal_error("Emitting values inside a locked bundle is forbidden"); |
| MCObjectStreamer::emitValueToAlignment(Alignment, Value, ValueSize, |
| MaxBytesToEmit); |
| } |
| |
| void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From, |
| const MCSymbolRefExpr *To, |
| uint64_t Count) { |
| getAssembler().CGProfile.push_back({From, To, Count}); |
| } |
| |
| void MCELFStreamer::emitIdent(StringRef IdentString) { |
| MCSection *Comment = getAssembler().getContext().getELFSection( |
| ".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, 1); |
| pushSection(); |
| switchSection(Comment); |
| if (!SeenIdent) { |
| emitInt8(0); |
| SeenIdent = true; |
| } |
| emitBytes(IdentString); |
| emitInt8(0); |
| popSection(); |
| } |
| |
| void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { |
| switch (expr->getKind()) { |
| case MCExpr::Target: |
| cast<MCTargetExpr>(expr)->fixELFSymbolsInTLSFixups(getAssembler()); |
| break; |
| case MCExpr::Constant: |
| break; |
| |
| case MCExpr::Binary: { |
| const MCBinaryExpr *be = cast<MCBinaryExpr>(expr); |
| fixSymbolsInTLSFixups(be->getLHS()); |
| fixSymbolsInTLSFixups(be->getRHS()); |
| break; |
| } |
| |
| case MCExpr::SymbolRef: { |
| const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(expr); |
| switch (symRef.getKind()) { |
| default: |
| return; |
| case MCSymbolRefExpr::VK_GOTTPOFF: |
| case MCSymbolRefExpr::VK_INDNTPOFF: |
| case MCSymbolRefExpr::VK_NTPOFF: |
| case MCSymbolRefExpr::VK_GOTNTPOFF: |
| case MCSymbolRefExpr::VK_TLSCALL: |
| case MCSymbolRefExpr::VK_TLSDESC: |
| case MCSymbolRefExpr::VK_TLSGD: |
| case MCSymbolRefExpr::VK_TLSLD: |
| case MCSymbolRefExpr::VK_TLSLDM: |
| case MCSymbolRefExpr::VK_TPOFF: |
| case MCSymbolRefExpr::VK_TPREL: |
| case MCSymbolRefExpr::VK_DTPOFF: |
| case MCSymbolRefExpr::VK_DTPREL: |
| case MCSymbolRefExpr::VK_PPC_DTPMOD: |
| case MCSymbolRefExpr::VK_PPC_TPREL_LO: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HI: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HA: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HIGH: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HIGHA: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HIGHER: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HIGHERA: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HIGHEST: |
| case MCSymbolRefExpr::VK_PPC_TPREL_HIGHESTA: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_LO: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HI: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HA: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HIGH: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHA: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHER: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHERA: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHEST: |
| case MCSymbolRefExpr::VK_PPC_DTPREL_HIGHESTA: |
| case MCSymbolRefExpr::VK_PPC_GOT_TPREL: |
| case MCSymbolRefExpr::VK_PPC_GOT_TPREL_LO: |
| case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HI: |
| case MCSymbolRefExpr::VK_PPC_GOT_TPREL_HA: |
| case MCSymbolRefExpr::VK_PPC_GOT_TPREL_PCREL: |
| case MCSymbolRefExpr::VK_PPC_GOT_DTPREL: |
| case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_LO: |
| case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HI: |
| case MCSymbolRefExpr::VK_PPC_GOT_DTPREL_HA: |
| case MCSymbolRefExpr::VK_PPC_TLS: |
| case MCSymbolRefExpr::VK_PPC_TLS_PCREL: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSGD: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_LO: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HI: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_HA: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSGD_PCREL: |
| case MCSymbolRefExpr::VK_PPC_TLSGD: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSLD: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_LO: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HI: |
| case MCSymbolRefExpr::VK_PPC_GOT_TLSLD_HA: |
| case MCSymbolRefExpr::VK_PPC_TLSLD: |
| break; |
| } |
| getAssembler().registerSymbol(symRef.getSymbol()); |
| cast<MCSymbolELF>(symRef.getSymbol()).setType(ELF::STT_TLS); |
| break; |
| } |
| |
| case MCExpr::Unary: |
| fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr()); |
| break; |
| } |
| } |
| |
| void MCELFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE, |
| uint64_t Offset) { |
| const MCSymbol *S = &SRE->getSymbol(); |
| if (S->isTemporary()) { |
| if (!S->isInSection()) { |
| getContext().reportError( |
| SRE->getLoc(), Twine("Reference to undefined temporary symbol ") + |
| "`" + S->getName() + "`"); |
| return; |
| } |
| S = S->getSection().getBeginSymbol(); |
| S->setUsedInReloc(); |
| SRE = MCSymbolRefExpr::create(S, MCSymbolRefExpr::VK_None, getContext(), |
| SRE->getLoc()); |
| } |
| const MCConstantExpr *MCOffset = MCConstantExpr::create(Offset, getContext()); |
| MCObjectStreamer::visitUsedExpr(*SRE); |
| if (std::optional<std::pair<bool, std::string>> Err = |
| MCObjectStreamer::emitRelocDirective( |
| *MCOffset, "BFD_RELOC_NONE", SRE, SRE->getLoc(), |
| *getContext().getSubtargetInfo())) |
| report_fatal_error("Relocation for CG Profile could not be created: " + |
| Twine(Err->second)); |
| } |
| |
| void MCELFStreamer::finalizeCGProfile() { |
| MCAssembler &Asm = getAssembler(); |
| if (Asm.CGProfile.empty()) |
| return; |
| MCSection *CGProfile = getAssembler().getContext().getELFSection( |
| ".llvm.call-graph-profile", ELF::SHT_LLVM_CALL_GRAPH_PROFILE, |
| ELF::SHF_EXCLUDE, /*sizeof(Elf_CGProfile_Impl<>)=*/8); |
| pushSection(); |
| switchSection(CGProfile); |
| uint64_t Offset = 0; |
| for (MCAssembler::CGProfileEntry &E : Asm.CGProfile) { |
| finalizeCGProfileEntry(E.From, Offset); |
| finalizeCGProfileEntry(E.To, Offset); |
| emitIntValue(E.Count, sizeof(uint64_t)); |
| Offset += sizeof(uint64_t); |
| } |
| popSection(); |
| } |
| |
| void MCELFStreamer::emitInstToFragment(const MCInst &Inst, |
| const MCSubtargetInfo &STI) { |
| this->MCObjectStreamer::emitInstToFragment(Inst, STI); |
| MCRelaxableFragment &F = *cast<MCRelaxableFragment>(getCurrentFragment()); |
| |
| for (auto &Fixup : F.getFixups()) |
| fixSymbolsInTLSFixups(Fixup.getValue()); |
| } |
| |
| // A fragment can only have one Subtarget, and when bundling is enabled we |
| // sometimes need to use the same fragment. We give an error if there |
| // are conflicting Subtargets. |
| static void CheckBundleSubtargets(const MCSubtargetInfo *OldSTI, |
| const MCSubtargetInfo *NewSTI) { |
| if (OldSTI && NewSTI && OldSTI != NewSTI) |
| report_fatal_error("A Bundle can only have one Subtarget."); |
| } |
| |
| void MCELFStreamer::emitInstToData(const MCInst &Inst, |
| const MCSubtargetInfo &STI) { |
| MCAssembler &Assembler = getAssembler(); |
| SmallVector<MCFixup, 4> Fixups; |
| SmallString<256> Code; |
| raw_svector_ostream VecOS(Code); |
| Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); |
| |
| for (auto &Fixup : Fixups) |
| fixSymbolsInTLSFixups(Fixup.getValue()); |
| |
| // There are several possibilities here: |
| // |
| // If bundling is disabled, append the encoded instruction to the current data |
| // fragment (or create a new such fragment if the current fragment is not a |
| // data fragment, or the Subtarget has changed). |
| // |
| // If bundling is enabled: |
| // - If we're not in a bundle-locked group, emit the instruction into a |
| // fragment of its own. If there are no fixups registered for the |
| // instruction, emit a MCCompactEncodedInstFragment. Otherwise, emit a |
| // MCDataFragment. |
| // - If we're in a bundle-locked group, append the instruction to the current |
| // data fragment because we want all the instructions in a group to get into |
| // the same fragment. Be careful not to do that for the first instruction in |
| // the group, though. |
| MCDataFragment *DF; |
| |
| if (Assembler.isBundlingEnabled()) { |
| MCSection &Sec = *getCurrentSectionOnly(); |
| if (Assembler.getRelaxAll() && isBundleLocked()) { |
| // If the -mc-relax-all flag is used and we are bundle-locked, we re-use |
| // the current bundle group. |
| DF = BundleGroups.back(); |
| CheckBundleSubtargets(DF->getSubtargetInfo(), &STI); |
| } |
| else if (Assembler.getRelaxAll() && !isBundleLocked()) |
| // When not in a bundle-locked group and the -mc-relax-all flag is used, |
| // we create a new temporary fragment which will be later merged into |
| // the current fragment. |
| DF = new MCDataFragment(); |
| else if (isBundleLocked() && !Sec.isBundleGroupBeforeFirstInst()) { |
| // If we are bundle-locked, we re-use the current fragment. |
| // The bundle-locking directive ensures this is a new data fragment. |
| DF = cast<MCDataFragment>(getCurrentFragment()); |
| CheckBundleSubtargets(DF->getSubtargetInfo(), &STI); |
| } |
| else if (!isBundleLocked() && Fixups.size() == 0) { |
| // Optimize memory usage by emitting the instruction to a |
| // MCCompactEncodedInstFragment when not in a bundle-locked group and |
| // there are no fixups registered. |
| MCCompactEncodedInstFragment *CEIF = new MCCompactEncodedInstFragment(); |
| insert(CEIF); |
| CEIF->getContents().append(Code.begin(), Code.end()); |
| CEIF->setHasInstructions(STI); |
| return; |
| } else { |
| DF = new MCDataFragment(); |
| insert(DF); |
| } |
| if (Sec.getBundleLockState() == MCSection::BundleLockedAlignToEnd) { |
| // If this fragment is for a group marked "align_to_end", set a flag |
| // in the fragment. This can happen after the fragment has already been |
| // created if there are nested bundle_align groups and an inner one |
| // is the one marked align_to_end. |
| DF->setAlignToBundleEnd(true); |
| } |
| |
| // We're now emitting an instruction in a bundle group, so this flag has |
| // to be turned off. |
| Sec.setBundleGroupBeforeFirstInst(false); |
| } else { |
| DF = getOrCreateDataFragment(&STI); |
| } |
| |
| // Add the fixups and data. |
| for (auto &Fixup : Fixups) { |
| Fixup.setOffset(Fixup.getOffset() + DF->getContents().size()); |
| DF->getFixups().push_back(Fixup); |
| } |
| |
| DF->setHasInstructions(STI); |
| DF->getContents().append(Code.begin(), Code.end()); |
| |
| if (Assembler.isBundlingEnabled() && Assembler.getRelaxAll()) { |
| if (!isBundleLocked()) { |
| mergeFragment(getOrCreateDataFragment(&STI), DF); |
| delete DF; |
| } |
| } |
| } |
| |
| void MCELFStreamer::emitBundleAlignMode(Align Alignment) { |
| assert(Log2(Alignment) <= 30 && "Invalid bundle alignment"); |
| MCAssembler &Assembler = getAssembler(); |
| if (Alignment > 1 && (Assembler.getBundleAlignSize() == 0 || |
| Assembler.getBundleAlignSize() == Alignment.value())) |
| Assembler.setBundleAlignSize(Alignment.value()); |
| else |
| report_fatal_error(".bundle_align_mode cannot be changed once set"); |
| } |
| |
| void MCELFStreamer::emitBundleLock(bool AlignToEnd) { |
| MCSection &Sec = *getCurrentSectionOnly(); |
| |
| if (!getAssembler().isBundlingEnabled()) |
| report_fatal_error(".bundle_lock forbidden when bundling is disabled"); |
| |
| if (!isBundleLocked()) |
| Sec.setBundleGroupBeforeFirstInst(true); |
| |
| if (getAssembler().getRelaxAll() && !isBundleLocked()) { |
| // TODO: drop the lock state and set directly in the fragment |
| MCDataFragment *DF = new MCDataFragment(); |
| BundleGroups.push_back(DF); |
| } |
| |
| Sec.setBundleLockState(AlignToEnd ? MCSection::BundleLockedAlignToEnd |
| : MCSection::BundleLocked); |
| } |
| |
| void MCELFStreamer::emitBundleUnlock() { |
| MCSection &Sec = *getCurrentSectionOnly(); |
| |
| if (!getAssembler().isBundlingEnabled()) |
| report_fatal_error(".bundle_unlock forbidden when bundling is disabled"); |
| else if (!isBundleLocked()) |
| report_fatal_error(".bundle_unlock without matching lock"); |
| else if (Sec.isBundleGroupBeforeFirstInst()) |
| report_fatal_error("Empty bundle-locked group is forbidden"); |
| |
| // When the -mc-relax-all flag is used, we emit instructions to fragments |
| // stored on a stack. When the bundle unlock is emitted, we pop a fragment |
| // from the stack a merge it to the one below. |
| if (getAssembler().getRelaxAll()) { |
| assert(!BundleGroups.empty() && "There are no bundle groups"); |
| MCDataFragment *DF = BundleGroups.back(); |
| |
| // FIXME: Use BundleGroups to track the lock state instead. |
| Sec.setBundleLockState(MCSection::NotBundleLocked); |
| |
| // FIXME: Use more separate fragments for nested groups. |
| if (!isBundleLocked()) { |
| mergeFragment(getOrCreateDataFragment(DF->getSubtargetInfo()), DF); |
| BundleGroups.pop_back(); |
| delete DF; |
| } |
| |
| if (Sec.getBundleLockState() != MCSection::BundleLockedAlignToEnd) |
| getOrCreateDataFragment()->setAlignToBundleEnd(false); |
| } else |
| Sec.setBundleLockState(MCSection::NotBundleLocked); |
| } |
| |
| void MCELFStreamer::finishImpl() { |
| // Emit the .gnu attributes section if any attributes have been added. |
| if (!GNUAttributes.empty()) { |
| MCSection *DummyAttributeSection = nullptr; |
| createAttributesSection("gnu", ".gnu.attributes", ELF::SHT_GNU_ATTRIBUTES, |
| DummyAttributeSection, GNUAttributes); |
| } |
| |
| // Ensure the last section gets aligned if necessary. |
| MCSection *CurSection = getCurrentSectionOnly(); |
| setSectionAlignmentForBundling(getAssembler(), CurSection); |
| |
| finalizeCGProfile(); |
| emitFrames(nullptr); |
| |
| this->MCObjectStreamer::finishImpl(); |
| } |
| |
| void MCELFStreamer::emitThumbFunc(MCSymbol *Func) { |
| llvm_unreachable("Generic ELF doesn't support this directive"); |
| } |
| |
| void MCELFStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { |
| llvm_unreachable("ELF doesn't support this directive"); |
| } |
| |
| void MCELFStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol, |
| uint64_t Size, Align ByteAlignment, |
| SMLoc Loc) { |
| llvm_unreachable("ELF doesn't support this directive"); |
| } |
| |
| void MCELFStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, |
| uint64_t Size, Align ByteAlignment) { |
| llvm_unreachable("ELF doesn't support this directive"); |
| } |
| |
| void MCELFStreamer::setAttributeItem(unsigned Attribute, unsigned Value, |
| bool OverwriteExisting) { |
| // Look for existing attribute item |
| if (AttributeItem *Item = getAttributeItem(Attribute)) { |
| if (!OverwriteExisting) |
| return; |
| Item->Type = AttributeItem::NumericAttribute; |
| Item->IntValue = Value; |
| return; |
| } |
| |
| // Create new attribute item |
| AttributeItem Item = {AttributeItem::NumericAttribute, Attribute, Value, |
| std::string(StringRef(""))}; |
| Contents.push_back(Item); |
| } |
| |
| void MCELFStreamer::setAttributeItem(unsigned Attribute, StringRef Value, |
| bool OverwriteExisting) { |
| // Look for existing attribute item |
| if (AttributeItem *Item = getAttributeItem(Attribute)) { |
| if (!OverwriteExisting) |
| return; |
| Item->Type = AttributeItem::TextAttribute; |
| Item->StringValue = std::string(Value); |
| return; |
| } |
| |
| // Create new attribute item |
| AttributeItem Item = {AttributeItem::TextAttribute, Attribute, 0, |
| std::string(Value)}; |
| Contents.push_back(Item); |
| } |
| |
| void MCELFStreamer::setAttributeItems(unsigned Attribute, unsigned IntValue, |
| StringRef StringValue, |
| bool OverwriteExisting) { |
| // Look for existing attribute item |
| if (AttributeItem *Item = getAttributeItem(Attribute)) { |
| if (!OverwriteExisting) |
| return; |
| Item->Type = AttributeItem::NumericAndTextAttributes; |
| Item->IntValue = IntValue; |
| Item->StringValue = std::string(StringValue); |
| return; |
| } |
| |
| // Create new attribute item |
| AttributeItem Item = {AttributeItem::NumericAndTextAttributes, Attribute, |
| IntValue, std::string(StringValue)}; |
| Contents.push_back(Item); |
| } |
| |
| MCELFStreamer::AttributeItem * |
| MCELFStreamer::getAttributeItem(unsigned Attribute) { |
| for (size_t I = 0; I < Contents.size(); ++I) |
| if (Contents[I].Tag == Attribute) |
| return &Contents[I]; |
| return nullptr; |
| } |
| |
| size_t |
| MCELFStreamer::calculateContentSize(SmallVector<AttributeItem, 64> &AttrsVec) { |
| size_t Result = 0; |
| for (size_t I = 0; I < AttrsVec.size(); ++I) { |
| AttributeItem Item = AttrsVec[I]; |
| switch (Item.Type) { |
| case AttributeItem::HiddenAttribute: |
| break; |
| case AttributeItem::NumericAttribute: |
| Result += getULEB128Size(Item.Tag); |
| Result += getULEB128Size(Item.IntValue); |
| break; |
| case AttributeItem::TextAttribute: |
| Result += getULEB128Size(Item.Tag); |
| Result += Item.StringValue.size() + 1; // string + '\0' |
| break; |
| case AttributeItem::NumericAndTextAttributes: |
| Result += getULEB128Size(Item.Tag); |
| Result += getULEB128Size(Item.IntValue); |
| Result += Item.StringValue.size() + 1; // string + '\0'; |
| break; |
| } |
| } |
| return Result; |
| } |
| |
| void MCELFStreamer::createAttributesSection( |
| StringRef Vendor, const Twine &Section, unsigned Type, |
| MCSection *&AttributeSection, SmallVector<AttributeItem, 64> &AttrsVec) { |
| // <format-version> |
| // [ <section-length> "vendor-name" |
| // [ <file-tag> <size> <attribute>* |
| // | <section-tag> <size> <section-number>* 0 <attribute>* |
| // | <symbol-tag> <size> <symbol-number>* 0 <attribute>* |
| // ]+ |
| // ]* |
| |
| // Switch section to AttributeSection or get/create the section. |
| if (AttributeSection) { |
| switchSection(AttributeSection); |
| } else { |
| AttributeSection = getContext().getELFSection(Section, Type, 0); |
| switchSection(AttributeSection); |
| |
| // Format version |
| emitInt8(0x41); |
| } |
| |
| // Vendor size + Vendor name + '\0' |
| const size_t VendorHeaderSize = 4 + Vendor.size() + 1; |
| |
| // Tag + Tag Size |
| const size_t TagHeaderSize = 1 + 4; |
| |
| const size_t ContentsSize = calculateContentSize(AttrsVec); |
| |
| emitInt32(VendorHeaderSize + TagHeaderSize + ContentsSize); |
| emitBytes(Vendor); |
| emitInt8(0); // '\0' |
| |
| emitInt8(ARMBuildAttrs::File); |
| emitInt32(TagHeaderSize + ContentsSize); |
| |
| // Size should have been accounted for already, now |
| // emit each field as its type (ULEB or String) |
| for (size_t I = 0; I < AttrsVec.size(); ++I) { |
| AttributeItem Item = AttrsVec[I]; |
| emitULEB128IntValue(Item.Tag); |
| switch (Item.Type) { |
| default: |
| llvm_unreachable("Invalid attribute type"); |
| case AttributeItem::NumericAttribute: |
| emitULEB128IntValue(Item.IntValue); |
| break; |
| case AttributeItem::TextAttribute: |
| emitBytes(Item.StringValue); |
| emitInt8(0); // '\0' |
| break; |
| case AttributeItem::NumericAndTextAttributes: |
| emitULEB128IntValue(Item.IntValue); |
| emitBytes(Item.StringValue); |
| emitInt8(0); // '\0' |
| break; |
| } |
| } |
| |
| AttrsVec.clear(); |
| } |
| |
| MCStreamer *llvm::createELFStreamer(MCContext &Context, |
| std::unique_ptr<MCAsmBackend> &&MAB, |
| std::unique_ptr<MCObjectWriter> &&OW, |
| std::unique_ptr<MCCodeEmitter> &&CE, |
| bool RelaxAll) { |
| MCELFStreamer *S = |
| new MCELFStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); |
| if (RelaxAll) |
| S->getAssembler().setRelaxAll(true); |
| return S; |
| } |