aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/MC/MCObjectStreamer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/llvm/lib/MC/MCObjectStreamer.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/MC/MCObjectStreamer.cpp936
1 files changed, 936 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/MC/MCObjectStreamer.cpp b/contrib/llvm-project/llvm/lib/MC/MCObjectStreamer.cpp
new file mode 100644
index 000000000000..ac90325bcc52
--- /dev/null
+++ b/contrib/llvm-project/llvm/lib/MC/MCObjectStreamer.cpp
@@ -0,0 +1,936 @@
+//===- lib/MC/MCObjectStreamer.cpp - Object File MCStreamer Interface -----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/SourceMgr.h"
+using namespace llvm;
+
+MCObjectStreamer::MCObjectStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> TAB,
+ std::unique_ptr<MCObjectWriter> OW,
+ std::unique_ptr<MCCodeEmitter> Emitter)
+ : MCStreamer(Context),
+ Assembler(std::make_unique<MCAssembler>(
+ Context, std::move(TAB), std::move(Emitter), std::move(OW))),
+ EmitEHFrame(true), EmitDebugFrame(false) {
+ if (Assembler->getBackendPtr())
+ setAllowAutoPadding(Assembler->getBackend().allowAutoPadding());
+}
+
+MCObjectStreamer::~MCObjectStreamer() = default;
+
+// AssemblerPtr is used for evaluation of expressions and causes
+// difference between asm and object outputs. Return nullptr to in
+// inline asm mode to limit divergence to assembly inputs.
+MCAssembler *MCObjectStreamer::getAssemblerPtr() {
+ if (getUseAssemblerInfoForParsing())
+ return Assembler.get();
+ return nullptr;
+}
+
+void MCObjectStreamer::addPendingLabel(MCSymbol* S) {
+ MCSection *CurSection = getCurrentSectionOnly();
+ if (CurSection) {
+ // Register labels that have not yet been assigned to a Section.
+ if (!PendingLabels.empty()) {
+ for (MCSymbol* Sym : PendingLabels)
+ CurSection->addPendingLabel(Sym);
+ PendingLabels.clear();
+ }
+
+ // Add this label to the current Section / Subsection.
+ CurSection->addPendingLabel(S, CurSubsectionIdx);
+
+ // Add this Section to the list of PendingLabelSections.
+ PendingLabelSections.insert(CurSection);
+ } else
+ // There is no Section / Subsection for this label yet.
+ PendingLabels.push_back(S);
+}
+
+void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
+ MCSection *CurSection = getCurrentSectionOnly();
+ if (!CurSection) {
+ assert(PendingLabels.empty());
+ return;
+ }
+ // Register labels that have not yet been assigned to a Section.
+ if (!PendingLabels.empty()) {
+ for (MCSymbol* Sym : PendingLabels)
+ CurSection->addPendingLabel(Sym, CurSubsectionIdx);
+ PendingLabels.clear();
+ }
+
+ // Associate a fragment with this label, either the supplied fragment
+ // or an empty data fragment.
+ if (F)
+ CurSection->flushPendingLabels(F, FOffset, CurSubsectionIdx);
+ else
+ CurSection->flushPendingLabels(nullptr, 0, CurSubsectionIdx);
+}
+
+void MCObjectStreamer::flushPendingLabels() {
+ // Register labels that have not yet been assigned to a Section.
+ if (!PendingLabels.empty()) {
+ MCSection *CurSection = getCurrentSectionOnly();
+ assert(CurSection);
+ for (MCSymbol* Sym : PendingLabels)
+ CurSection->addPendingLabel(Sym, CurSubsectionIdx);
+ PendingLabels.clear();
+ }
+
+ // Assign an empty data fragment to all remaining pending labels.
+ for (MCSection* Section : PendingLabelSections)
+ Section->flushPendingLabels();
+}
+
+// When fixup's offset is a forward declared label, e.g.:
+//
+// .reloc 1f, R_MIPS_JALR, foo
+// 1: nop
+//
+// postpone adding it to Fixups vector until the label is defined and its offset
+// is known.
+void MCObjectStreamer::resolvePendingFixups() {
+ for (PendingMCFixup &PendingFixup : PendingFixups) {
+ if (!PendingFixup.Sym || PendingFixup.Sym->isUndefined ()) {
+ getContext().reportError(PendingFixup.Fixup.getLoc(),
+ "unresolved relocation offset");
+ continue;
+ }
+ flushPendingLabels(PendingFixup.DF, PendingFixup.DF->getContents().size());
+ PendingFixup.Fixup.setOffset(PendingFixup.Sym->getOffset() +
+ PendingFixup.Fixup.getOffset());
+
+ // If the location symbol to relocate is in MCEncodedFragmentWithFixups,
+ // put the Fixup into location symbol's fragment. Otherwise
+ // put into PendingFixup.DF
+ MCFragment *SymFragment = PendingFixup.Sym->getFragment();
+ switch (SymFragment->getKind()) {
+ case MCFragment::FT_Relaxable:
+ case MCFragment::FT_Dwarf:
+ case MCFragment::FT_PseudoProbe:
+ cast<MCEncodedFragmentWithFixups<8, 1>>(SymFragment)
+ ->getFixups()
+ .push_back(PendingFixup.Fixup);
+ break;
+ case MCFragment::FT_Data:
+ case MCFragment::FT_CVDefRange:
+ cast<MCEncodedFragmentWithFixups<32, 4>>(SymFragment)
+ ->getFixups()
+ .push_back(PendingFixup.Fixup);
+ break;
+ default:
+ PendingFixup.DF->getFixups().push_back(PendingFixup.Fixup);
+ break;
+ }
+ }
+ PendingFixups.clear();
+}
+
+// As a compile-time optimization, avoid allocating and evaluating an MCExpr
+// tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment.
+static std::optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
+ const MCSymbol *Lo) {
+ assert(Hi && Lo);
+ if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
+ Hi->isVariable() || Lo->isVariable())
+ return std::nullopt;
+
+ return Hi->getOffset() - Lo->getOffset();
+}
+
+void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
+ const MCSymbol *Lo,
+ unsigned Size) {
+ if (!getAssembler().getContext().getTargetTriple().isRISCV())
+ if (std::optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo))
+ return emitIntValue(*Diff, Size);
+ MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
+}
+
+void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
+ const MCSymbol *Lo) {
+ if (!getAssembler().getContext().getTargetTriple().isRISCV())
+ if (std::optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) {
+ emitULEB128IntValue(*Diff);
+ return;
+ }
+ MCStreamer::emitAbsoluteSymbolDiffAsULEB128(Hi, Lo);
+}
+
+void MCObjectStreamer::reset() {
+ if (Assembler)
+ Assembler->reset();
+ CurInsertionPoint = MCSection::iterator();
+ EmitEHFrame = true;
+ EmitDebugFrame = false;
+ PendingLabels.clear();
+ PendingLabelSections.clear();
+ MCStreamer::reset();
+}
+
+void MCObjectStreamer::emitFrames(MCAsmBackend *MAB) {
+ if (!getNumFrameInfos())
+ return;
+
+ if (EmitEHFrame)
+ MCDwarfFrameEmitter::Emit(*this, MAB, true);
+
+ if (EmitDebugFrame)
+ MCDwarfFrameEmitter::Emit(*this, MAB, false);
+}
+
+MCFragment *MCObjectStreamer::getCurrentFragment() const {
+ assert(getCurrentSectionOnly() && "No current section!");
+
+ if (CurInsertionPoint != getCurrentSectionOnly()->getFragmentList().begin())
+ return &*std::prev(CurInsertionPoint);
+
+ return nullptr;
+}
+
+static bool canReuseDataFragment(const MCDataFragment &F,
+ const MCAssembler &Assembler,
+ const MCSubtargetInfo *STI) {
+ if (!F.hasInstructions())
+ return true;
+ // When bundling is enabled, we don't want to add data to a fragment that
+ // already has instructions (see MCELFStreamer::emitInstToData for details)
+ if (Assembler.isBundlingEnabled())
+ return Assembler.getRelaxAll();
+ // If the subtarget is changed mid fragment we start a new fragment to record
+ // the new STI.
+ return !STI || F.getSubtargetInfo() == STI;
+}
+
+MCDataFragment *
+MCObjectStreamer::getOrCreateDataFragment(const MCSubtargetInfo *STI) {
+ MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+ if (!F || !canReuseDataFragment(*F, *Assembler, STI)) {
+ F = new MCDataFragment();
+ insert(F);
+ }
+ return F;
+}
+
+void MCObjectStreamer::visitUsedSymbol(const MCSymbol &Sym) {
+ Assembler->registerSymbol(Sym);
+}
+
+void MCObjectStreamer::emitCFISections(bool EH, bool Debug) {
+ MCStreamer::emitCFISections(EH, Debug);
+ EmitEHFrame = EH;
+ EmitDebugFrame = Debug;
+}
+
+void MCObjectStreamer::emitValueImpl(const MCExpr *Value, unsigned Size,
+ SMLoc Loc) {
+ MCStreamer::emitValueImpl(Value, Size, Loc);
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+
+ // Avoid fixups when possible.
+ int64_t AbsValue;
+ if (Value->evaluateAsAbsolute(AbsValue, getAssemblerPtr())) {
+ if (!isUIntN(8 * Size, AbsValue) && !isIntN(8 * Size, AbsValue)) {
+ getContext().reportError(
+ Loc, "value evaluated as " + Twine(AbsValue) + " is out of range.");
+ return;
+ }
+ emitIntValue(AbsValue, Size);
+ return;
+ }
+ DF->getFixups().push_back(
+ MCFixup::create(DF->getContents().size(), Value,
+ MCFixup::getKindForSize(Size, false), Loc));
+ DF->getContents().resize(DF->getContents().size() + Size, 0);
+}
+
+MCSymbol *MCObjectStreamer::emitCFILabel() {
+ MCSymbol *Label = getContext().createTempSymbol("cfi");
+ emitLabel(Label);
+ return Label;
+}
+
+void MCObjectStreamer::emitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+ // We need to create a local symbol to avoid relocations.
+ Frame.Begin = getContext().createTempSymbol();
+ emitLabel(Frame.Begin);
+}
+
+void MCObjectStreamer::emitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
+ Frame.End = getContext().createTempSymbol();
+ emitLabel(Frame.End);
+}
+
+void MCObjectStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
+ MCStreamer::emitLabel(Symbol, Loc);
+
+ getAssembler().registerSymbol(*Symbol);
+
+ // If there is a current fragment, mark the symbol as pointing into it.
+ // Otherwise queue the label and set its fragment pointer when we emit the
+ // next fragment.
+ auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+ if (F && !(getAssembler().isBundlingEnabled() &&
+ getAssembler().getRelaxAll())) {
+ Symbol->setFragment(F);
+ Symbol->setOffset(F->getContents().size());
+ } else {
+ // Assign all pending labels to offset 0 within the dummy "pending"
+ // fragment. (They will all be reassigned to a real fragment in
+ // flushPendingLabels())
+ Symbol->setOffset(0);
+ addPendingLabel(Symbol);
+ }
+
+ emitPendingAssignments(Symbol);
+}
+
+void MCObjectStreamer::emitPendingAssignments(MCSymbol *Symbol) {
+ auto Assignments = pendingAssignments.find(Symbol);
+ if (Assignments != pendingAssignments.end()) {
+ for (const PendingAssignment &A : Assignments->second)
+ emitAssignment(A.Symbol, A.Value);
+
+ pendingAssignments.erase(Assignments);
+ }
+}
+
+// Emit a label at a previously emitted fragment/offset position. This must be
+// within the currently-active section.
+void MCObjectStreamer::emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc,
+ MCFragment *F, uint64_t Offset) {
+ assert(F->getParent() == getCurrentSectionOnly());
+
+ MCStreamer::emitLabel(Symbol, Loc);
+ getAssembler().registerSymbol(*Symbol);
+ auto *DF = dyn_cast_or_null<MCDataFragment>(F);
+ Symbol->setOffset(Offset);
+ if (DF) {
+ Symbol->setFragment(F);
+ } else {
+ assert(isa<MCDummyFragment>(F) &&
+ "F must either be an MCDataFragment or the pending MCDummyFragment");
+ assert(Offset == 0);
+ addPendingLabel(Symbol);
+ }
+}
+
+void MCObjectStreamer::emitULEB128Value(const MCExpr *Value) {
+ int64_t IntValue;
+ if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) {
+ emitULEB128IntValue(IntValue);
+ return;
+ }
+ insert(new MCLEBFragment(*Value, false));
+}
+
+void MCObjectStreamer::emitSLEB128Value(const MCExpr *Value) {
+ int64_t IntValue;
+ if (Value->evaluateAsAbsolute(IntValue, getAssemblerPtr())) {
+ emitSLEB128IntValue(IntValue);
+ return;
+ }
+ insert(new MCLEBFragment(*Value, true));
+}
+
+void MCObjectStreamer::emitWeakReference(MCSymbol *Alias,
+ const MCSymbol *Symbol) {
+ report_fatal_error("This file format doesn't support weak aliases.");
+}
+
+void MCObjectStreamer::changeSection(MCSection *Section,
+ const MCExpr *Subsection) {
+ changeSectionImpl(Section, Subsection);
+}
+
+bool MCObjectStreamer::changeSectionImpl(MCSection *Section,
+ const MCExpr *Subsection) {
+ assert(Section && "Cannot switch to a null section!");
+ getContext().clearDwarfLocSeen();
+
+ bool Created = getAssembler().registerSection(*Section);
+
+ int64_t IntSubsection = 0;
+ if (Subsection &&
+ !Subsection->evaluateAsAbsolute(IntSubsection, getAssemblerPtr()))
+ report_fatal_error("Cannot evaluate subsection number");
+ if (IntSubsection < 0 || IntSubsection > 8192)
+ report_fatal_error("Subsection number out of range");
+ CurSubsectionIdx = unsigned(IntSubsection);
+ CurInsertionPoint =
+ Section->getSubsectionInsertionPoint(CurSubsectionIdx);
+ return Created;
+}
+
+void MCObjectStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ getAssembler().registerSymbol(*Symbol);
+ MCStreamer::emitAssignment(Symbol, Value);
+ emitPendingAssignments(Symbol);
+}
+
+void MCObjectStreamer::emitConditionalAssignment(MCSymbol *Symbol,
+ const MCExpr *Value) {
+ const MCSymbol *Target = &cast<MCSymbolRefExpr>(*Value).getSymbol();
+
+ // If the symbol already exists, emit the assignment. Otherwise, emit it
+ // later only if the symbol is also emitted.
+ if (Target->isRegistered())
+ emitAssignment(Symbol, Value);
+ else
+ pendingAssignments[Target].push_back({Symbol, Value});
+}
+
+bool MCObjectStreamer::mayHaveInstructions(MCSection &Sec) const {
+ return Sec.hasInstructions();
+}
+
+void MCObjectStreamer::emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ const MCSection &Sec = *getCurrentSectionOnly();
+ if (Sec.isVirtualSection()) {
+ getContext().reportError(Inst.getLoc(), Twine(Sec.getVirtualSectionKind()) +
+ " section '" + Sec.getName() +
+ "' cannot have instructions");
+ return;
+ }
+ getAssembler().getBackend().emitInstructionBegin(*this, Inst, STI);
+ emitInstructionImpl(Inst, STI);
+ getAssembler().getBackend().emitInstructionEnd(*this, Inst);
+}
+
+void MCObjectStreamer::emitInstructionImpl(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ MCStreamer::emitInstruction(Inst, STI);
+
+ MCSection *Sec = getCurrentSectionOnly();
+ Sec->setHasInstructions(true);
+
+ // Now that a machine instruction has been assembled into this section, make
+ // a line entry for any .loc directive that has been seen.
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+
+ // If this instruction doesn't need relaxation, just emit it as data.
+ MCAssembler &Assembler = getAssembler();
+ MCAsmBackend &Backend = Assembler.getBackend();
+ if (!(Backend.mayNeedRelaxation(Inst, STI) ||
+ Backend.allowEnhancedRelaxation())) {
+ emitInstToData(Inst, STI);
+ return;
+ }
+
+ // Otherwise, relax and emit it as data if either:
+ // - The RelaxAll flag was passed
+ // - Bundling is enabled and this instruction is inside a bundle-locked
+ // group. We want to emit all such instructions into the same data
+ // fragment.
+ if (Assembler.getRelaxAll() ||
+ (Assembler.isBundlingEnabled() && Sec->isBundleLocked())) {
+ MCInst Relaxed = Inst;
+ while (Backend.mayNeedRelaxation(Relaxed, STI))
+ Backend.relaxInstruction(Relaxed, STI);
+ emitInstToData(Relaxed, STI);
+ return;
+ }
+
+ // Otherwise emit to a separate fragment.
+ emitInstToFragment(Inst, STI);
+}
+
+void MCObjectStreamer::emitInstToFragment(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ if (getAssembler().getRelaxAll() && getAssembler().isBundlingEnabled())
+ llvm_unreachable("All instructions should have already been relaxed");
+
+ // Always create a new, separate fragment here, because its size can change
+ // during relaxation.
+ MCRelaxableFragment *IF = new MCRelaxableFragment(Inst, STI);
+ insert(IF);
+
+ SmallString<128> Code;
+ raw_svector_ostream VecOS(Code);
+ getAssembler().getEmitter().encodeInstruction(Inst, VecOS, IF->getFixups(),
+ STI);
+ IF->getContents().append(Code.begin(), Code.end());
+}
+
+#ifndef NDEBUG
+static const char *const BundlingNotImplementedMsg =
+ "Aligned bundling is not implemented for this object format";
+#endif
+
+void MCObjectStreamer::emitBundleAlignMode(Align Alignment) {
+ llvm_unreachable(BundlingNotImplementedMsg);
+}
+
+void MCObjectStreamer::emitBundleLock(bool AlignToEnd) {
+ llvm_unreachable(BundlingNotImplementedMsg);
+}
+
+void MCObjectStreamer::emitBundleUnlock() {
+ llvm_unreachable(BundlingNotImplementedMsg);
+}
+
+void MCObjectStreamer::emitDwarfLocDirective(unsigned FileNo, unsigned Line,
+ unsigned Column, unsigned Flags,
+ unsigned Isa,
+ unsigned Discriminator,
+ StringRef FileName) {
+ // In case we see two .loc directives in a row, make sure the
+ // first one gets a line entry.
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+
+ this->MCStreamer::emitDwarfLocDirective(FileNo, Line, Column, Flags, Isa,
+ Discriminator, FileName);
+}
+
+static const MCExpr *buildSymbolDiff(MCObjectStreamer &OS, const MCSymbol *A,
+ const MCSymbol *B) {
+ MCContext &Context = OS.getContext();
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+ const MCExpr *ARef = MCSymbolRefExpr::create(A, Variant, Context);
+ const MCExpr *BRef = MCSymbolRefExpr::create(B, Variant, Context);
+ const MCExpr *AddrDelta =
+ MCBinaryExpr::create(MCBinaryExpr::Sub, ARef, BRef, Context);
+ return AddrDelta;
+}
+
+static void emitDwarfSetLineAddr(MCObjectStreamer &OS,
+ MCDwarfLineTableParams Params,
+ int64_t LineDelta, const MCSymbol *Label,
+ int PointerSize) {
+ // emit the sequence to set the address
+ OS.emitIntValue(dwarf::DW_LNS_extended_op, 1);
+ OS.emitULEB128IntValue(PointerSize + 1);
+ OS.emitIntValue(dwarf::DW_LNE_set_address, 1);
+ OS.emitSymbolValue(Label, PointerSize);
+
+ // emit the sequence for the LineDelta (from 1) and a zero address delta.
+ MCDwarfLineAddr::Emit(&OS, Params, LineDelta, 0);
+}
+
+void MCObjectStreamer::emitDwarfAdvanceLineAddr(int64_t LineDelta,
+ const MCSymbol *LastLabel,
+ const MCSymbol *Label,
+ unsigned PointerSize) {
+ if (!LastLabel) {
+ emitDwarfSetLineAddr(*this, Assembler->getDWARFLinetableParams(), LineDelta,
+ Label, PointerSize);
+ return;
+ }
+ const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel);
+ int64_t Res;
+ if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) {
+ MCDwarfLineAddr::Emit(this, Assembler->getDWARFLinetableParams(), LineDelta,
+ Res);
+ return;
+ }
+ insert(new MCDwarfLineAddrFragment(LineDelta, *AddrDelta));
+}
+
+void MCObjectStreamer::emitDwarfLineEndEntry(MCSection *Section,
+ MCSymbol *LastLabel) {
+ // Emit a DW_LNE_end_sequence for the end of the section.
+ // Use the section end label to compute the address delta and use INT64_MAX
+ // as the line delta which is the signal that this is actually a
+ // DW_LNE_end_sequence.
+ MCSymbol *SectionEnd = endSection(Section);
+
+ // Switch back the dwarf line section, in case endSection had to switch the
+ // section.
+ MCContext &Ctx = getContext();
+ switchSection(Ctx.getObjectFileInfo()->getDwarfLineSection());
+
+ const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
+ emitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
+ AsmInfo->getCodePointerSize());
+}
+
+void MCObjectStreamer::emitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel,
+ const MCSymbol *Label) {
+ const MCExpr *AddrDelta = buildSymbolDiff(*this, Label, LastLabel);
+ int64_t Res;
+ if (AddrDelta->evaluateAsAbsolute(Res, getAssemblerPtr())) {
+ MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res);
+ return;
+ }
+ insert(new MCDwarfCallFrameFragment(*AddrDelta));
+}
+
+void MCObjectStreamer::emitCVLocDirective(unsigned FunctionId, unsigned FileNo,
+ unsigned Line, unsigned Column,
+ bool PrologueEnd, bool IsStmt,
+ StringRef FileName, SMLoc Loc) {
+ // Validate the directive.
+ if (!checkCVLocSection(FunctionId, FileNo, Loc))
+ return;
+
+ // Emit a label at the current position and record it in the CodeViewContext.
+ MCSymbol *LineSym = getContext().createTempSymbol();
+ emitLabel(LineSym);
+ getContext().getCVContext().recordCVLoc(getContext(), LineSym, FunctionId,
+ FileNo, Line, Column, PrologueEnd,
+ IsStmt);
+}
+
+void MCObjectStreamer::emitCVLinetableDirective(unsigned FunctionId,
+ const MCSymbol *Begin,
+ const MCSymbol *End) {
+ getContext().getCVContext().emitLineTableForFunction(*this, FunctionId, Begin,
+ End);
+ this->MCStreamer::emitCVLinetableDirective(FunctionId, Begin, End);
+}
+
+void MCObjectStreamer::emitCVInlineLinetableDirective(
+ unsigned PrimaryFunctionId, unsigned SourceFileId, unsigned SourceLineNum,
+ const MCSymbol *FnStartSym, const MCSymbol *FnEndSym) {
+ getContext().getCVContext().emitInlineLineTableForFunction(
+ *this, PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym,
+ FnEndSym);
+ this->MCStreamer::emitCVInlineLinetableDirective(
+ PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
+}
+
+void MCObjectStreamer::emitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ StringRef FixedSizePortion) {
+ MCFragment *Frag =
+ getContext().getCVContext().emitDefRange(*this, Ranges, FixedSizePortion);
+ // Attach labels that were pending before we created the defrange fragment to
+ // the beginning of the new fragment.
+ flushPendingLabels(Frag, 0);
+ this->MCStreamer::emitCVDefRangeDirective(Ranges, FixedSizePortion);
+}
+
+void MCObjectStreamer::emitCVStringTableDirective() {
+ getContext().getCVContext().emitStringTable(*this);
+}
+void MCObjectStreamer::emitCVFileChecksumsDirective() {
+ getContext().getCVContext().emitFileChecksums(*this);
+}
+
+void MCObjectStreamer::emitCVFileChecksumOffsetDirective(unsigned FileNo) {
+ getContext().getCVContext().emitFileChecksumOffset(*this, FileNo);
+}
+
+void MCObjectStreamer::emitBytes(StringRef Data) {
+ MCDwarfLineEntry::make(this, getCurrentSectionOnly());
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+ DF->getContents().append(Data.begin(), Data.end());
+}
+
+void MCObjectStreamer::emitValueToAlignment(Align Alignment, int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ if (MaxBytesToEmit == 0)
+ MaxBytesToEmit = Alignment.value();
+ insert(new MCAlignFragment(Alignment, Value, ValueSize, MaxBytesToEmit));
+
+ // Update the maximum alignment on the current section if necessary.
+ MCSection *CurSec = getCurrentSectionOnly();
+ CurSec->ensureMinAlignment(Alignment);
+}
+
+void MCObjectStreamer::emitCodeAlignment(Align Alignment,
+ const MCSubtargetInfo *STI,
+ unsigned MaxBytesToEmit) {
+ emitValueToAlignment(Alignment, 0, 1, MaxBytesToEmit);
+ cast<MCAlignFragment>(getCurrentFragment())->setEmitNops(true, STI);
+}
+
+void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
+ unsigned char Value,
+ SMLoc Loc) {
+ insert(new MCOrgFragment(*Offset, Value, Loc));
+}
+
+// Associate DTPRel32 fixup with data and resize data area
+void MCObjectStreamer::emitDTPRel32Value(const MCExpr *Value) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ DF->getFixups().push_back(MCFixup::create(DF->getContents().size(),
+ Value, FK_DTPRel_4));
+ DF->getContents().resize(DF->getContents().size() + 4, 0);
+}
+
+// Associate DTPRel64 fixup with data and resize data area
+void MCObjectStreamer::emitDTPRel64Value(const MCExpr *Value) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ DF->getFixups().push_back(MCFixup::create(DF->getContents().size(),
+ Value, FK_DTPRel_8));
+ DF->getContents().resize(DF->getContents().size() + 8, 0);
+}
+
+// Associate TPRel32 fixup with data and resize data area
+void MCObjectStreamer::emitTPRel32Value(const MCExpr *Value) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ DF->getFixups().push_back(MCFixup::create(DF->getContents().size(),
+ Value, FK_TPRel_4));
+ DF->getContents().resize(DF->getContents().size() + 4, 0);
+}
+
+// Associate TPRel64 fixup with data and resize data area
+void MCObjectStreamer::emitTPRel64Value(const MCExpr *Value) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ DF->getFixups().push_back(MCFixup::create(DF->getContents().size(),
+ Value, FK_TPRel_8));
+ DF->getContents().resize(DF->getContents().size() + 8, 0);
+}
+
+// Associate GPRel32 fixup with data and resize data area
+void MCObjectStreamer::emitGPRel32Value(const MCExpr *Value) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ DF->getFixups().push_back(
+ MCFixup::create(DF->getContents().size(), Value, FK_GPRel_4));
+ DF->getContents().resize(DF->getContents().size() + 4, 0);
+}
+
+// Associate GPRel64 fixup with data and resize data area
+void MCObjectStreamer::emitGPRel64Value(const MCExpr *Value) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ DF->getFixups().push_back(
+ MCFixup::create(DF->getContents().size(), Value, FK_GPRel_4));
+ DF->getContents().resize(DF->getContents().size() + 8, 0);
+}
+
+static std::optional<std::pair<bool, std::string>>
+getOffsetAndDataFragment(const MCSymbol &Symbol, uint32_t &RelocOffset,
+ MCDataFragment *&DF) {
+ if (Symbol.isVariable()) {
+ const MCExpr *SymbolExpr = Symbol.getVariableValue();
+ MCValue OffsetVal;
+ if(!SymbolExpr->evaluateAsRelocatable(OffsetVal, nullptr, nullptr))
+ return std::make_pair(false,
+ std::string("symbol in .reloc offset is not "
+ "relocatable"));
+ if (OffsetVal.isAbsolute()) {
+ RelocOffset = OffsetVal.getConstant();
+ MCFragment *Fragment = Symbol.getFragment();
+ // FIXME Support symbols with no DF. For example:
+ // .reloc .data, ENUM_VALUE, <some expr>
+ if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
+ return std::make_pair(false,
+ std::string("symbol in offset has no data "
+ "fragment"));
+ DF = cast<MCDataFragment>(Fragment);
+ return std::nullopt;
+ }
+
+ if (OffsetVal.getSymB())
+ return std::make_pair(false,
+ std::string(".reloc symbol offset is not "
+ "representable"));
+
+ const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA());
+ if (!SRE.getSymbol().isDefined())
+ return std::make_pair(false,
+ std::string("symbol used in the .reloc offset is "
+ "not defined"));
+
+ if (SRE.getSymbol().isVariable())
+ return std::make_pair(false,
+ std::string("symbol used in the .reloc offset is "
+ "variable"));
+
+ MCFragment *Fragment = SRE.getSymbol().getFragment();
+ // FIXME Support symbols with no DF. For example:
+ // .reloc .data, ENUM_VALUE, <some expr>
+ if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
+ return std::make_pair(false,
+ std::string("symbol in offset has no data "
+ "fragment"));
+ RelocOffset = SRE.getSymbol().getOffset() + OffsetVal.getConstant();
+ DF = cast<MCDataFragment>(Fragment);
+ } else {
+ RelocOffset = Symbol.getOffset();
+ MCFragment *Fragment = Symbol.getFragment();
+ // FIXME Support symbols with no DF. For example:
+ // .reloc .data, ENUM_VALUE, <some expr>
+ if (!Fragment || Fragment->getKind() != MCFragment::FT_Data)
+ return std::make_pair(false,
+ std::string("symbol in offset has no data "
+ "fragment"));
+ DF = cast<MCDataFragment>(Fragment);
+ }
+ return std::nullopt;
+}
+
+std::optional<std::pair<bool, std::string>>
+MCObjectStreamer::emitRelocDirective(const MCExpr &Offset, StringRef Name,
+ const MCExpr *Expr, SMLoc Loc,
+ const MCSubtargetInfo &STI) {
+ std::optional<MCFixupKind> MaybeKind =
+ Assembler->getBackend().getFixupKind(Name);
+ if (!MaybeKind)
+ return std::make_pair(true, std::string("unknown relocation name"));
+
+ MCFixupKind Kind = *MaybeKind;
+
+ if (Expr == nullptr)
+ Expr =
+ MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext());
+
+ MCDataFragment *DF = getOrCreateDataFragment(&STI);
+ flushPendingLabels(DF, DF->getContents().size());
+
+ MCValue OffsetVal;
+ if (!Offset.evaluateAsRelocatable(OffsetVal, nullptr, nullptr))
+ return std::make_pair(false,
+ std::string(".reloc offset is not relocatable"));
+ if (OffsetVal.isAbsolute()) {
+ if (OffsetVal.getConstant() < 0)
+ return std::make_pair(false, std::string(".reloc offset is negative"));
+ DF->getFixups().push_back(
+ MCFixup::create(OffsetVal.getConstant(), Expr, Kind, Loc));
+ return std::nullopt;
+ }
+ if (OffsetVal.getSymB())
+ return std::make_pair(false,
+ std::string(".reloc offset is not representable"));
+
+ const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*OffsetVal.getSymA());
+ const MCSymbol &Symbol = SRE.getSymbol();
+ if (Symbol.isDefined()) {
+ uint32_t SymbolOffset = 0;
+ std::optional<std::pair<bool, std::string>> Error =
+ getOffsetAndDataFragment(Symbol, SymbolOffset, DF);
+
+ if (Error != std::nullopt)
+ return Error;
+
+ DF->getFixups().push_back(
+ MCFixup::create(SymbolOffset + OffsetVal.getConstant(),
+ Expr, Kind, Loc));
+ return std::nullopt;
+ }
+
+ PendingFixups.emplace_back(
+ &SRE.getSymbol(), DF,
+ MCFixup::create(OffsetVal.getConstant(), Expr, Kind, Loc));
+ return std::nullopt;
+}
+
+void MCObjectStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
+ SMLoc Loc) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ assert(getCurrentSectionOnly() && "need a section");
+ insert(new MCFillFragment(FillValue, 1, NumBytes, Loc));
+}
+
+void MCObjectStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
+ int64_t Expr, SMLoc Loc) {
+ int64_t IntNumValues;
+ // Do additional checking now if we can resolve the value.
+ if (NumValues.evaluateAsAbsolute(IntNumValues, getAssemblerPtr())) {
+ if (IntNumValues < 0) {
+ getContext().getSourceManager()->PrintMessage(
+ Loc, SourceMgr::DK_Warning,
+ "'.fill' directive with negative repeat count has no effect");
+ return;
+ }
+ // Emit now if we can for better errors.
+ int64_t NonZeroSize = Size > 4 ? 4 : Size;
+ Expr &= ~0ULL >> (64 - NonZeroSize * 8);
+ for (uint64_t i = 0, e = IntNumValues; i != e; ++i) {
+ emitIntValue(Expr, NonZeroSize);
+ if (NonZeroSize < Size)
+ emitIntValue(0, Size - NonZeroSize);
+ }
+ return;
+ }
+
+ // Otherwise emit as fragment.
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ assert(getCurrentSectionOnly() && "need a section");
+ insert(new MCFillFragment(Expr, Size, NumValues, Loc));
+}
+
+void MCObjectStreamer::emitNops(int64_t NumBytes, int64_t ControlledNopLength,
+ SMLoc Loc, const MCSubtargetInfo &STI) {
+ // Emit an NOP fragment.
+ MCDataFragment *DF = getOrCreateDataFragment();
+ flushPendingLabels(DF, DF->getContents().size());
+
+ assert(getCurrentSectionOnly() && "need a section");
+
+ insert(new MCNopsFragment(NumBytes, ControlledNopLength, Loc, STI));
+}
+
+void MCObjectStreamer::emitFileDirective(StringRef Filename) {
+ getAssembler().addFileName(Filename);
+}
+
+void MCObjectStreamer::emitFileDirective(StringRef Filename,
+ StringRef CompilerVerion,
+ StringRef TimeStamp,
+ StringRef Description) {
+ getAssembler().addFileName(Filename);
+ // TODO: add additional info to integrated assembler.
+}
+
+void MCObjectStreamer::emitAddrsig() {
+ getAssembler().getWriter().emitAddrsigSection();
+}
+
+void MCObjectStreamer::emitAddrsigSym(const MCSymbol *Sym) {
+ getAssembler().getWriter().addAddrsigSymbol(Sym);
+}
+
+void MCObjectStreamer::finishImpl() {
+ getContext().RemapDebugPaths();
+
+ // If we are generating dwarf for assembly source files dump out the sections.
+ if (getContext().getGenDwarfForAssembly())
+ MCGenDwarfInfo::Emit(this);
+
+ // Dump out the dwarf file & directory tables and line tables.
+ MCDwarfLineTable::emit(this, getAssembler().getDWARFLinetableParams());
+
+ // Emit pseudo probes for the current module.
+ MCPseudoProbeTable::emit(this);
+
+ // Update any remaining pending labels with empty data fragments.
+ flushPendingLabels();
+
+ resolvePendingFixups();
+ getAssembler().Finish();
+}