aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/MC
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/MC')
-rw-r--r--llvm/lib/MC/ConstantPools.cpp115
-rw-r--r--llvm/lib/MC/ELFObjectWriter.cpp1560
-rw-r--r--llvm/lib/MC/MCAsmBackend.cpp137
-rw-r--r--llvm/lib/MC/MCAsmInfo.cpp126
-rw-r--r--llvm/lib/MC/MCAsmInfoCOFF.cpp68
-rw-r--r--llvm/lib/MC/MCAsmInfoDarwin.cpp97
-rw-r--r--llvm/lib/MC/MCAsmInfoELF.cpp34
-rw-r--r--llvm/lib/MC/MCAsmInfoWasm.cpp25
-rw-r--r--llvm/lib/MC/MCAsmInfoXCOFF.cpp35
-rw-r--r--llvm/lib/MC/MCAsmMacro.cpp43
-rw-r--r--llvm/lib/MC/MCAsmStreamer.cpp2035
-rw-r--r--llvm/lib/MC/MCAssembler.cpp1155
-rw-r--r--llvm/lib/MC/MCCodeEmitter.cpp15
-rw-r--r--llvm/lib/MC/MCCodePadder.cpp370
-rw-r--r--llvm/lib/MC/MCCodeView.cpp696
-rw-r--r--llvm/lib/MC/MCContext.cpp724
-rw-r--r--llvm/lib/MC/MCDisassembler/Disassembler.cpp343
-rw-r--r--llvm/lib/MC/MCDisassembler/Disassembler.h124
-rw-r--r--llvm/lib/MC/MCDisassembler/MCDisassembler.cpp46
-rw-r--r--llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp199
-rw-r--r--llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp30
-rw-r--r--llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp13
-rw-r--r--llvm/lib/MC/MCDwarf.cpp1950
-rw-r--r--llvm/lib/MC/MCELFObjectTargetWriter.cpp31
-rw-r--r--llvm/lib/MC/MCELFStreamer.cpp711
-rw-r--r--llvm/lib/MC/MCExpr.cpp928
-rw-r--r--llvm/lib/MC/MCFragment.cpp467
-rw-r--r--llvm/lib/MC/MCInst.cpp98
-rw-r--r--llvm/lib/MC/MCInstPrinter.cpp120
-rw-r--r--llvm/lib/MC/MCInstrAnalysis.cpp41
-rw-r--r--llvm/lib/MC/MCInstrDesc.cpp65
-rw-r--r--llvm/lib/MC/MCLabel.cpp25
-rw-r--r--llvm/lib/MC/MCLinkerOptimizationHint.cpp59
-rw-r--r--llvm/lib/MC/MCMachOStreamer.cpp520
-rw-r--r--llvm/lib/MC/MCMachObjectTargetWriter.cpp18
-rw-r--r--llvm/lib/MC/MCNullStreamer.cpp49
-rw-r--r--llvm/lib/MC/MCObjectFileInfo.cpp873
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp731
-rw-r--r--llvm/lib/MC/MCObjectWriter.cpp52
-rw-r--r--llvm/lib/MC/MCParser/AsmLexer.cpp755
-rw-r--r--llvm/lib/MC/MCParser/AsmParser.cpp6082
-rw-r--r--llvm/lib/MC/MCParser/COFFAsmParser.cpp712
-rw-r--r--llvm/lib/MC/MCParser/DarwinAsmParser.cpp1208
-rw-r--r--llvm/lib/MC/MCParser/ELFAsmParser.cpp899
-rw-r--r--llvm/lib/MC/MCParser/MCAsmLexer.cpp129
-rw-r--r--llvm/lib/MC/MCParser/MCAsmParser.cpp136
-rw-r--r--llvm/lib/MC/MCParser/MCAsmParserExtension.cpp19
-rw-r--r--llvm/lib/MC/MCParser/MCTargetAsmParser.cpp29
-rw-r--r--llvm/lib/MC/MCParser/WasmAsmParser.cpp256
-rw-r--r--llvm/lib/MC/MCRegisterInfo.cpp124
-rw-r--r--llvm/lib/MC/MCSchedule.cpp167
-rw-r--r--llvm/lib/MC/MCSection.cpp102
-rw-r--r--llvm/lib/MC/MCSectionCOFF.cpp113
-rw-r--r--llvm/lib/MC/MCSectionELF.cpp198
-rw-r--r--llvm/lib/MC/MCSectionMachO.cpp281
-rw-r--r--llvm/lib/MC/MCSectionWasm.cpp94
-rw-r--r--llvm/lib/MC/MCSectionXCOFF.cpp79
-rw-r--r--llvm/lib/MC/MCStreamer.cpp1164
-rw-r--r--llvm/lib/MC/MCSubtargetInfo.cpp342
-rw-r--r--llvm/lib/MC/MCSymbol.cpp88
-rw-r--r--llvm/lib/MC/MCSymbolELF.cpp201
-rw-r--r--llvm/lib/MC/MCTargetOptions.cpp23
-rw-r--r--llvm/lib/MC/MCValue.cpp61
-rw-r--r--llvm/lib/MC/MCWasmObjectTargetWriter.cpp18
-rw-r--r--llvm/lib/MC/MCWasmStreamer.cpp229
-rw-r--r--llvm/lib/MC/MCWin64EH.cpp680
-rw-r--r--llvm/lib/MC/MCWinCOFFStreamer.cpp337
-rw-r--r--llvm/lib/MC/MCWinEH.cpp25
-rw-r--r--llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp16
-rw-r--r--llvm/lib/MC/MCXCOFFStreamer.cpp101
-rw-r--r--llvm/lib/MC/MachObjectWriter.cpp1052
-rw-r--r--llvm/lib/MC/StringTableBuilder.cpp199
-rw-r--r--llvm/lib/MC/SubtargetFeature.cpp82
-rw-r--r--llvm/lib/MC/WasmObjectWriter.cpp1599
-rw-r--r--llvm/lib/MC/WinCOFFObjectWriter.cpp1102
-rw-r--r--llvm/lib/MC/XCOFFObjectWriter.cpp603
76 files changed, 34033 insertions, 0 deletions
diff --git a/llvm/lib/MC/ConstantPools.cpp b/llvm/lib/MC/ConstantPools.cpp
new file mode 100644
index 000000000000..8cba6b3281a5
--- /dev/null
+++ b/llvm/lib/MC/ConstantPools.cpp
@@ -0,0 +1,115 @@
+//===- ConstantPools.cpp - ConstantPool class -----------------------------===//
+//
+// 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 implements the ConstantPool and AssemblerConstantPools classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/ConstantPools.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/Casting.h"
+
+using namespace llvm;
+
+//
+// ConstantPool implementation
+//
+// Emit the contents of the constant pool using the provided streamer.
+void ConstantPool::emitEntries(MCStreamer &Streamer) {
+ if (Entries.empty())
+ return;
+ Streamer.EmitDataRegion(MCDR_DataRegion);
+ for (const ConstantPoolEntry &Entry : Entries) {
+ Streamer.EmitCodeAlignment(Entry.Size); // align naturally
+ Streamer.EmitLabel(Entry.Label);
+ Streamer.EmitValue(Entry.Value, Entry.Size, Entry.Loc);
+ }
+ Streamer.EmitDataRegion(MCDR_DataRegionEnd);
+ Entries.clear();
+}
+
+const MCExpr *ConstantPool::addEntry(const MCExpr *Value, MCContext &Context,
+ unsigned Size, SMLoc Loc) {
+ const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Value);
+
+ // Check if there is existing entry for the same constant. If so, reuse it.
+ auto Itr = C ? CachedEntries.find(C->getValue()) : CachedEntries.end();
+ if (Itr != CachedEntries.end())
+ return Itr->second;
+
+ MCSymbol *CPEntryLabel = Context.createTempSymbol();
+
+ Entries.push_back(ConstantPoolEntry(CPEntryLabel, Value, Size, Loc));
+ const auto SymRef = MCSymbolRefExpr::create(CPEntryLabel, Context);
+ if (C)
+ CachedEntries[C->getValue()] = SymRef;
+ return SymRef;
+}
+
+bool ConstantPool::empty() { return Entries.empty(); }
+
+void ConstantPool::clearCache() {
+ CachedEntries.clear();
+}
+
+//
+// AssemblerConstantPools implementation
+//
+ConstantPool *AssemblerConstantPools::getConstantPool(MCSection *Section) {
+ ConstantPoolMapTy::iterator CP = ConstantPools.find(Section);
+ if (CP == ConstantPools.end())
+ return nullptr;
+
+ return &CP->second;
+}
+
+ConstantPool &
+AssemblerConstantPools::getOrCreateConstantPool(MCSection *Section) {
+ return ConstantPools[Section];
+}
+
+static void emitConstantPool(MCStreamer &Streamer, MCSection *Section,
+ ConstantPool &CP) {
+ if (!CP.empty()) {
+ Streamer.SwitchSection(Section);
+ CP.emitEntries(Streamer);
+ }
+}
+
+void AssemblerConstantPools::emitAll(MCStreamer &Streamer) {
+ // Dump contents of assembler constant pools.
+ for (auto &CPI : ConstantPools) {
+ MCSection *Section = CPI.first;
+ ConstantPool &CP = CPI.second;
+
+ emitConstantPool(Streamer, Section, CP);
+ }
+}
+
+void AssemblerConstantPools::emitForCurrentSection(MCStreamer &Streamer) {
+ MCSection *Section = Streamer.getCurrentSectionOnly();
+ if (ConstantPool *CP = getConstantPool(Section))
+ emitConstantPool(Streamer, Section, *CP);
+}
+
+void AssemblerConstantPools::clearCacheForCurrentSection(MCStreamer &Streamer) {
+ MCSection *Section = Streamer.getCurrentSectionOnly();
+ if (ConstantPool *CP = getConstantPool(Section))
+ CP->clearCache();
+}
+
+const MCExpr *AssemblerConstantPools::addEntry(MCStreamer &Streamer,
+ const MCExpr *Expr,
+ unsigned Size, SMLoc Loc) {
+ MCSection *Section = Streamer.getCurrentSectionOnly();
+ return getOrCreateConstantPool(Section).addEntry(Expr, Streamer.getContext(),
+ Size, Loc);
+}
diff --git a/llvm/lib/MC/ELFObjectWriter.cpp b/llvm/lib/MC/ELFObjectWriter.cpp
new file mode 100644
index 000000000000..6f160e491cea
--- /dev/null
+++ b/llvm/lib/MC/ELFObjectWriter.cpp
@@ -0,0 +1,1560 @@
+//===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -----------------------===//
+//
+// 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 implements ELF object file writer information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCFixupKindInfo.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/MCSymbol.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+#undef DEBUG_TYPE
+#define DEBUG_TYPE "reloc-info"
+
+namespace {
+
+using SectionIndexMapTy = DenseMap<const MCSectionELF *, uint32_t>;
+
+class ELFObjectWriter;
+struct ELFWriter;
+
+bool isDwoSection(const MCSectionELF &Sec) {
+ return Sec.getSectionName().endswith(".dwo");
+}
+
+class SymbolTableWriter {
+ ELFWriter &EWriter;
+ bool Is64Bit;
+
+ // indexes we are going to write to .symtab_shndx.
+ std::vector<uint32_t> ShndxIndexes;
+
+ // The numbel of symbols written so far.
+ unsigned NumWritten;
+
+ void createSymtabShndx();
+
+ template <typename T> void write(T Value);
+
+public:
+ SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit);
+
+ void writeSymbol(uint32_t name, uint8_t info, uint64_t value, uint64_t size,
+ uint8_t other, uint32_t shndx, bool Reserved);
+
+ ArrayRef<uint32_t> getShndxIndexes() const { return ShndxIndexes; }
+};
+
+struct ELFWriter {
+ ELFObjectWriter &OWriter;
+ support::endian::Writer W;
+
+ enum DwoMode {
+ AllSections,
+ NonDwoOnly,
+ DwoOnly,
+ } Mode;
+
+ static uint64_t SymbolValue(const MCSymbol &Sym, const MCAsmLayout &Layout);
+ static bool isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol,
+ bool Used, bool Renamed);
+
+ /// Helper struct for containing some precomputed information on symbols.
+ struct ELFSymbolData {
+ const MCSymbolELF *Symbol;
+ uint32_t SectionIndex;
+ StringRef Name;
+
+ // Support lexicographic sorting.
+ bool operator<(const ELFSymbolData &RHS) const {
+ unsigned LHSType = Symbol->getType();
+ unsigned RHSType = RHS.Symbol->getType();
+ if (LHSType == ELF::STT_SECTION && RHSType != ELF::STT_SECTION)
+ return false;
+ if (LHSType != ELF::STT_SECTION && RHSType == ELF::STT_SECTION)
+ return true;
+ if (LHSType == ELF::STT_SECTION && RHSType == ELF::STT_SECTION)
+ return SectionIndex < RHS.SectionIndex;
+ return Name < RHS.Name;
+ }
+ };
+
+ /// @}
+ /// @name Symbol Table Data
+ /// @{
+
+ StringTableBuilder StrTabBuilder{StringTableBuilder::ELF};
+
+ /// @}
+
+ // This holds the symbol table index of the last local symbol.
+ unsigned LastLocalSymbolIndex;
+ // This holds the .strtab section index.
+ unsigned StringTableIndex;
+ // This holds the .symtab section index.
+ unsigned SymbolTableIndex;
+
+ // Sections in the order they are to be output in the section table.
+ std::vector<const MCSectionELF *> SectionTable;
+ unsigned addToSectionTable(const MCSectionELF *Sec);
+
+ // TargetObjectWriter wrappers.
+ bool is64Bit() const;
+ bool hasRelocationAddend() const;
+
+ void align(unsigned Alignment);
+
+ bool maybeWriteCompression(uint64_t Size,
+ SmallVectorImpl<char> &CompressedContents,
+ bool ZLibStyle, unsigned Alignment);
+
+public:
+ ELFWriter(ELFObjectWriter &OWriter, raw_pwrite_stream &OS,
+ bool IsLittleEndian, DwoMode Mode)
+ : OWriter(OWriter),
+ W(OS, IsLittleEndian ? support::little : support::big), Mode(Mode) {}
+
+ void WriteWord(uint64_t Word) {
+ if (is64Bit())
+ W.write<uint64_t>(Word);
+ else
+ W.write<uint32_t>(Word);
+ }
+
+ template <typename T> void write(T Val) {
+ W.write(Val);
+ }
+
+ void writeHeader(const MCAssembler &Asm);
+
+ void writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
+ ELFSymbolData &MSD, const MCAsmLayout &Layout);
+
+ // Start and end offset of each section
+ using SectionOffsetsTy =
+ std::map<const MCSectionELF *, std::pair<uint64_t, uint64_t>>;
+
+ // Map from a signature symbol to the group section index
+ using RevGroupMapTy = DenseMap<const MCSymbol *, unsigned>;
+
+ /// Compute the symbol table data
+ ///
+ /// \param Asm - The assembler.
+ /// \param SectionIndexMap - Maps a section to its index.
+ /// \param RevGroupMap - Maps a signature symbol to the group section.
+ void computeSymbolTable(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const SectionIndexMapTy &SectionIndexMap,
+ const RevGroupMapTy &RevGroupMap,
+ SectionOffsetsTy &SectionOffsets);
+
+ void writeAddrsigSection();
+
+ MCSectionELF *createRelocationSection(MCContext &Ctx,
+ const MCSectionELF &Sec);
+
+ const MCSectionELF *createStringTable(MCContext &Ctx);
+
+ void writeSectionHeader(const MCAsmLayout &Layout,
+ const SectionIndexMapTy &SectionIndexMap,
+ const SectionOffsetsTy &SectionOffsets);
+
+ void writeSectionData(const MCAssembler &Asm, MCSection &Sec,
+ const MCAsmLayout &Layout);
+
+ void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
+ uint64_t Address, uint64_t Offset, uint64_t Size,
+ uint32_t Link, uint32_t Info, uint64_t Alignment,
+ uint64_t EntrySize);
+
+ void writeRelocations(const MCAssembler &Asm, const MCSectionELF &Sec);
+
+ uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout);
+ void writeSection(const SectionIndexMapTy &SectionIndexMap,
+ uint32_t GroupSymbolIndex, uint64_t Offset, uint64_t Size,
+ const MCSectionELF &Section);
+};
+
+class ELFObjectWriter : public MCObjectWriter {
+ /// The target specific ELF writer instance.
+ std::unique_ptr<MCELFObjectTargetWriter> TargetObjectWriter;
+
+ DenseMap<const MCSectionELF *, std::vector<ELFRelocationEntry>> Relocations;
+
+ DenseMap<const MCSymbolELF *, const MCSymbolELF *> Renames;
+
+ bool EmitAddrsigSection = false;
+ std::vector<const MCSymbol *> AddrsigSyms;
+
+ bool hasRelocationAddend() const;
+
+ bool shouldRelocateWithSymbol(const MCAssembler &Asm,
+ const MCSymbolRefExpr *RefA,
+ const MCSymbolELF *Sym, uint64_t C,
+ unsigned Type) const;
+
+public:
+ ELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW)
+ : TargetObjectWriter(std::move(MOTW)) {}
+
+ void reset() override {
+ Relocations.clear();
+ Renames.clear();
+ MCObjectWriter::reset();
+ }
+
+ bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
+ const MCSymbol &SymA,
+ const MCFragment &FB, bool InSet,
+ bool IsPCRel) const override;
+
+ virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
+ const MCSectionELF *From,
+ const MCSectionELF *To) {
+ return true;
+ }
+
+ void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, uint64_t &FixedValue) override;
+
+ void executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) override;
+
+ void emitAddrsigSection() override { EmitAddrsigSection = true; }
+ void addAddrsigSymbol(const MCSymbol *Sym) override {
+ AddrsigSyms.push_back(Sym);
+ }
+
+ friend struct ELFWriter;
+};
+
+class ELFSingleObjectWriter : public ELFObjectWriter {
+ raw_pwrite_stream &OS;
+ bool IsLittleEndian;
+
+public:
+ ELFSingleObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS, bool IsLittleEndian)
+ : ELFObjectWriter(std::move(MOTW)), OS(OS),
+ IsLittleEndian(IsLittleEndian) {}
+
+ uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override {
+ return ELFWriter(*this, OS, IsLittleEndian, ELFWriter::AllSections)
+ .writeObject(Asm, Layout);
+ }
+
+ friend struct ELFWriter;
+};
+
+class ELFDwoObjectWriter : public ELFObjectWriter {
+ raw_pwrite_stream &OS, &DwoOS;
+ bool IsLittleEndian;
+
+public:
+ ELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
+ bool IsLittleEndian)
+ : ELFObjectWriter(std::move(MOTW)), OS(OS), DwoOS(DwoOS),
+ IsLittleEndian(IsLittleEndian) {}
+
+ virtual bool checkRelocation(MCContext &Ctx, SMLoc Loc,
+ const MCSectionELF *From,
+ const MCSectionELF *To) override {
+ if (isDwoSection(*From)) {
+ Ctx.reportError(Loc, "A dwo section may not contain relocations");
+ return false;
+ }
+ if (To && isDwoSection(*To)) {
+ Ctx.reportError(Loc, "A relocation may not refer to a dwo section");
+ return false;
+ }
+ return true;
+ }
+
+ uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override {
+ uint64_t Size = ELFWriter(*this, OS, IsLittleEndian, ELFWriter::NonDwoOnly)
+ .writeObject(Asm, Layout);
+ Size += ELFWriter(*this, DwoOS, IsLittleEndian, ELFWriter::DwoOnly)
+ .writeObject(Asm, Layout);
+ return Size;
+ }
+};
+
+} // end anonymous namespace
+
+void ELFWriter::align(unsigned Alignment) {
+ uint64_t Padding = offsetToAlignment(W.OS.tell(), Align(Alignment));
+ W.OS.write_zeros(Padding);
+}
+
+unsigned ELFWriter::addToSectionTable(const MCSectionELF *Sec) {
+ SectionTable.push_back(Sec);
+ StrTabBuilder.add(Sec->getSectionName());
+ return SectionTable.size();
+}
+
+void SymbolTableWriter::createSymtabShndx() {
+ if (!ShndxIndexes.empty())
+ return;
+
+ ShndxIndexes.resize(NumWritten);
+}
+
+template <typename T> void SymbolTableWriter::write(T Value) {
+ EWriter.write(Value);
+}
+
+SymbolTableWriter::SymbolTableWriter(ELFWriter &EWriter, bool Is64Bit)
+ : EWriter(EWriter), Is64Bit(Is64Bit), NumWritten(0) {}
+
+void SymbolTableWriter::writeSymbol(uint32_t name, uint8_t info, uint64_t value,
+ uint64_t size, uint8_t other,
+ uint32_t shndx, bool Reserved) {
+ bool LargeIndex = shndx >= ELF::SHN_LORESERVE && !Reserved;
+
+ if (LargeIndex)
+ createSymtabShndx();
+
+ if (!ShndxIndexes.empty()) {
+ if (LargeIndex)
+ ShndxIndexes.push_back(shndx);
+ else
+ ShndxIndexes.push_back(0);
+ }
+
+ uint16_t Index = LargeIndex ? uint16_t(ELF::SHN_XINDEX) : shndx;
+
+ if (Is64Bit) {
+ write(name); // st_name
+ write(info); // st_info
+ write(other); // st_other
+ write(Index); // st_shndx
+ write(value); // st_value
+ write(size); // st_size
+ } else {
+ write(name); // st_name
+ write(uint32_t(value)); // st_value
+ write(uint32_t(size)); // st_size
+ write(info); // st_info
+ write(other); // st_other
+ write(Index); // st_shndx
+ }
+
+ ++NumWritten;
+}
+
+bool ELFWriter::is64Bit() const {
+ return OWriter.TargetObjectWriter->is64Bit();
+}
+
+bool ELFWriter::hasRelocationAddend() const {
+ return OWriter.hasRelocationAddend();
+}
+
+// Emit the ELF header.
+void ELFWriter::writeHeader(const MCAssembler &Asm) {
+ // ELF Header
+ // ----------
+ //
+ // Note
+ // ----
+ // emitWord method behaves differently for ELF32 and ELF64, writing
+ // 4 bytes in the former and 8 in the latter.
+
+ W.OS << ELF::ElfMagic; // e_ident[EI_MAG0] to e_ident[EI_MAG3]
+
+ W.OS << char(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS]
+
+ // e_ident[EI_DATA]
+ W.OS << char(W.Endian == support::little ? ELF::ELFDATA2LSB
+ : ELF::ELFDATA2MSB);
+
+ W.OS << char(ELF::EV_CURRENT); // e_ident[EI_VERSION]
+ // e_ident[EI_OSABI]
+ W.OS << char(OWriter.TargetObjectWriter->getOSABI());
+ // e_ident[EI_ABIVERSION]
+ W.OS << char(OWriter.TargetObjectWriter->getABIVersion());
+
+ W.OS.write_zeros(ELF::EI_NIDENT - ELF::EI_PAD);
+
+ W.write<uint16_t>(ELF::ET_REL); // e_type
+
+ W.write<uint16_t>(OWriter.TargetObjectWriter->getEMachine()); // e_machine = target
+
+ W.write<uint32_t>(ELF::EV_CURRENT); // e_version
+ WriteWord(0); // e_entry, no entry point in .o file
+ WriteWord(0); // e_phoff, no program header for .o
+ WriteWord(0); // e_shoff = sec hdr table off in bytes
+
+ // e_flags = whatever the target wants
+ W.write<uint32_t>(Asm.getELFHeaderEFlags());
+
+ // e_ehsize = ELF header size
+ W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Ehdr)
+ : sizeof(ELF::Elf32_Ehdr));
+
+ W.write<uint16_t>(0); // e_phentsize = prog header entry size
+ W.write<uint16_t>(0); // e_phnum = # prog header entries = 0
+
+ // e_shentsize = Section header entry size
+ W.write<uint16_t>(is64Bit() ? sizeof(ELF::Elf64_Shdr)
+ : sizeof(ELF::Elf32_Shdr));
+
+ // e_shnum = # of section header ents
+ W.write<uint16_t>(0);
+
+ // e_shstrndx = Section # of '.shstrtab'
+ assert(StringTableIndex < ELF::SHN_LORESERVE);
+ W.write<uint16_t>(StringTableIndex);
+}
+
+uint64_t ELFWriter::SymbolValue(const MCSymbol &Sym,
+ const MCAsmLayout &Layout) {
+ if (Sym.isCommon() && (Sym.isTargetCommon() || Sym.isExternal()))
+ return Sym.getCommonAlignment();
+
+ uint64_t Res;
+ if (!Layout.getSymbolOffset(Sym, Res))
+ return 0;
+
+ if (Layout.getAssembler().isThumbFunc(&Sym))
+ Res |= 1;
+
+ return Res;
+}
+
+static uint8_t mergeTypeForSet(uint8_t origType, uint8_t newType) {
+ uint8_t Type = newType;
+
+ // Propagation rules:
+ // IFUNC > FUNC > OBJECT > NOTYPE
+ // TLS_OBJECT > OBJECT > NOTYPE
+ //
+ // dont let the new type degrade the old type
+ switch (origType) {
+ default:
+ break;
+ case ELF::STT_GNU_IFUNC:
+ if (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT ||
+ Type == ELF::STT_NOTYPE || Type == ELF::STT_TLS)
+ Type = ELF::STT_GNU_IFUNC;
+ break;
+ case ELF::STT_FUNC:
+ if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
+ Type == ELF::STT_TLS)
+ Type = ELF::STT_FUNC;
+ break;
+ case ELF::STT_OBJECT:
+ if (Type == ELF::STT_NOTYPE)
+ Type = ELF::STT_OBJECT;
+ break;
+ case ELF::STT_TLS:
+ if (Type == ELF::STT_OBJECT || Type == ELF::STT_NOTYPE ||
+ Type == ELF::STT_GNU_IFUNC || Type == ELF::STT_FUNC)
+ Type = ELF::STT_TLS;
+ break;
+ }
+
+ return Type;
+}
+
+static bool isIFunc(const MCSymbolELF *Symbol) {
+ while (Symbol->getType() != ELF::STT_GNU_IFUNC) {
+ const MCSymbolRefExpr *Value;
+ if (!Symbol->isVariable() ||
+ !(Value = dyn_cast<MCSymbolRefExpr>(Symbol->getVariableValue())) ||
+ Value->getKind() != MCSymbolRefExpr::VK_None ||
+ mergeTypeForSet(Symbol->getType(), ELF::STT_GNU_IFUNC) != ELF::STT_GNU_IFUNC)
+ return false;
+ Symbol = &cast<MCSymbolELF>(Value->getSymbol());
+ }
+ return true;
+}
+
+void ELFWriter::writeSymbol(SymbolTableWriter &Writer, uint32_t StringIndex,
+ ELFSymbolData &MSD, const MCAsmLayout &Layout) {
+ const auto &Symbol = cast<MCSymbolELF>(*MSD.Symbol);
+ const MCSymbolELF *Base =
+ cast_or_null<MCSymbolELF>(Layout.getBaseSymbol(Symbol));
+
+ // This has to be in sync with when computeSymbolTable uses SHN_ABS or
+ // SHN_COMMON.
+ bool IsReserved = !Base || Symbol.isCommon();
+
+ // Binding and Type share the same byte as upper and lower nibbles
+ uint8_t Binding = Symbol.getBinding();
+ uint8_t Type = Symbol.getType();
+ if (isIFunc(&Symbol))
+ Type = ELF::STT_GNU_IFUNC;
+ if (Base) {
+ Type = mergeTypeForSet(Type, Base->getType());
+ }
+ uint8_t Info = (Binding << 4) | Type;
+
+ // Other and Visibility share the same byte with Visibility using the lower
+ // 2 bits
+ uint8_t Visibility = Symbol.getVisibility();
+ uint8_t Other = Symbol.getOther() | Visibility;
+
+ uint64_t Value = SymbolValue(*MSD.Symbol, Layout);
+ uint64_t Size = 0;
+
+ const MCExpr *ESize = MSD.Symbol->getSize();
+ if (!ESize && Base)
+ ESize = Base->getSize();
+
+ if (ESize) {
+ int64_t Res;
+ if (!ESize->evaluateKnownAbsolute(Res, Layout))
+ report_fatal_error("Size expression must be absolute.");
+ Size = Res;
+ }
+
+ // Write out the symbol table entry
+ Writer.writeSymbol(StringIndex, Info, Value, Size, Other, MSD.SectionIndex,
+ IsReserved);
+}
+
+// True if the assembler knows nothing about the final value of the symbol.
+// This doesn't cover the comdat issues, since in those cases the assembler
+// can at least know that all symbols in the section will move together.
+static bool isWeak(const MCSymbolELF &Sym) {
+ if (Sym.getType() == ELF::STT_GNU_IFUNC)
+ return true;
+
+ switch (Sym.getBinding()) {
+ default:
+ llvm_unreachable("Unknown binding");
+ case ELF::STB_LOCAL:
+ return false;
+ case ELF::STB_GLOBAL:
+ return false;
+ case ELF::STB_WEAK:
+ case ELF::STB_GNU_UNIQUE:
+ return true;
+ }
+}
+
+bool ELFWriter::isInSymtab(const MCAsmLayout &Layout, const MCSymbolELF &Symbol,
+ bool Used, bool Renamed) {
+ if (Symbol.isVariable()) {
+ const MCExpr *Expr = Symbol.getVariableValue();
+ // Target Expressions that are always inlined do not appear in the symtab
+ if (const auto *T = dyn_cast<MCTargetExpr>(Expr))
+ if (T->inlineAssignedExpr())
+ return false;
+ if (const MCSymbolRefExpr *Ref = dyn_cast<MCSymbolRefExpr>(Expr)) {
+ if (Ref->getKind() == MCSymbolRefExpr::VK_WEAKREF)
+ return false;
+ }
+ }
+
+ if (Used)
+ return true;
+
+ if (Renamed)
+ return false;
+
+ if (Symbol.isVariable() && Symbol.isUndefined()) {
+ // FIXME: this is here just to diagnose the case of a var = commmon_sym.
+ Layout.getBaseSymbol(Symbol);
+ return false;
+ }
+
+ if (Symbol.isUndefined() && !Symbol.isBindingSet())
+ return false;
+
+ if (Symbol.isTemporary())
+ return false;
+
+ if (Symbol.getType() == ELF::STT_SECTION)
+ return false;
+
+ return true;
+}
+
+void ELFWriter::computeSymbolTable(
+ MCAssembler &Asm, const MCAsmLayout &Layout,
+ const SectionIndexMapTy &SectionIndexMap, const RevGroupMapTy &RevGroupMap,
+ SectionOffsetsTy &SectionOffsets) {
+ MCContext &Ctx = Asm.getContext();
+ SymbolTableWriter Writer(*this, is64Bit());
+
+ // Symbol table
+ unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32;
+ MCSectionELF *SymtabSection =
+ Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, EntrySize, "");
+ SymtabSection->setAlignment(is64Bit() ? Align(8) : Align(4));
+ SymbolTableIndex = addToSectionTable(SymtabSection);
+
+ align(SymtabSection->getAlignment());
+ uint64_t SecStart = W.OS.tell();
+
+ // The first entry is the undefined symbol entry.
+ Writer.writeSymbol(0, 0, 0, 0, 0, 0, false);
+
+ std::vector<ELFSymbolData> LocalSymbolData;
+ std::vector<ELFSymbolData> ExternalSymbolData;
+
+ // Add the data for the symbols.
+ bool HasLargeSectionIndex = false;
+ for (const MCSymbol &S : Asm.symbols()) {
+ const auto &Symbol = cast<MCSymbolELF>(S);
+ bool Used = Symbol.isUsedInReloc();
+ bool WeakrefUsed = Symbol.isWeakrefUsedInReloc();
+ bool isSignature = Symbol.isSignature();
+
+ if (!isInSymtab(Layout, Symbol, Used || WeakrefUsed || isSignature,
+ OWriter.Renames.count(&Symbol)))
+ continue;
+
+ if (Symbol.isTemporary() && Symbol.isUndefined()) {
+ Ctx.reportError(SMLoc(), "Undefined temporary symbol");
+ continue;
+ }
+
+ ELFSymbolData MSD;
+ MSD.Symbol = cast<MCSymbolELF>(&Symbol);
+
+ bool Local = Symbol.getBinding() == ELF::STB_LOCAL;
+ assert(Local || !Symbol.isTemporary());
+
+ if (Symbol.isAbsolute()) {
+ MSD.SectionIndex = ELF::SHN_ABS;
+ } else if (Symbol.isCommon()) {
+ if (Symbol.isTargetCommon()) {
+ MSD.SectionIndex = Symbol.getIndex();
+ } else {
+ assert(!Local);
+ MSD.SectionIndex = ELF::SHN_COMMON;
+ }
+ } else if (Symbol.isUndefined()) {
+ if (isSignature && !Used) {
+ MSD.SectionIndex = RevGroupMap.lookup(&Symbol);
+ if (MSD.SectionIndex >= ELF::SHN_LORESERVE)
+ HasLargeSectionIndex = true;
+ } else {
+ MSD.SectionIndex = ELF::SHN_UNDEF;
+ }
+ } else {
+ const MCSectionELF &Section =
+ static_cast<const MCSectionELF &>(Symbol.getSection());
+
+ // We may end up with a situation when section symbol is technically
+ // defined, but should not be. That happens because we explicitly
+ // pre-create few .debug_* sections to have accessors.
+ // And if these sections were not really defined in the code, but were
+ // referenced, we simply error out.
+ if (!Section.isRegistered()) {
+ assert(static_cast<const MCSymbolELF &>(Symbol).getType() ==
+ ELF::STT_SECTION);
+ Ctx.reportError(SMLoc(),
+ "Undefined section reference: " + Symbol.getName());
+ continue;
+ }
+
+ if (Mode == NonDwoOnly && isDwoSection(Section))
+ continue;
+ MSD.SectionIndex = SectionIndexMap.lookup(&Section);
+ assert(MSD.SectionIndex && "Invalid section index!");
+ if (MSD.SectionIndex >= ELF::SHN_LORESERVE)
+ HasLargeSectionIndex = true;
+ }
+
+ StringRef Name = Symbol.getName();
+
+ // Sections have their own string table
+ if (Symbol.getType() != ELF::STT_SECTION) {
+ MSD.Name = Name;
+ StrTabBuilder.add(Name);
+ }
+
+ if (Local)
+ LocalSymbolData.push_back(MSD);
+ else
+ ExternalSymbolData.push_back(MSD);
+ }
+
+ // This holds the .symtab_shndx section index.
+ unsigned SymtabShndxSectionIndex = 0;
+
+ if (HasLargeSectionIndex) {
+ MCSectionELF *SymtabShndxSection =
+ Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, 4, "");
+ SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection);
+ SymtabShndxSection->setAlignment(Align(4));
+ }
+
+ ArrayRef<std::string> FileNames = Asm.getFileNames();
+ for (const std::string &Name : FileNames)
+ StrTabBuilder.add(Name);
+
+ StrTabBuilder.finalize();
+
+ // File symbols are emitted first and handled separately from normal symbols,
+ // i.e. a non-STT_FILE symbol with the same name may appear.
+ for (const std::string &Name : FileNames)
+ Writer.writeSymbol(StrTabBuilder.getOffset(Name),
+ ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, ELF::STV_DEFAULT,
+ ELF::SHN_ABS, true);
+
+ // Symbols are required to be in lexicographic order.
+ array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end());
+ array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end());
+
+ // Set the symbol indices. Local symbols must come before all other
+ // symbols with non-local bindings.
+ unsigned Index = FileNames.size() + 1;
+
+ for (ELFSymbolData &MSD : LocalSymbolData) {
+ unsigned StringIndex = MSD.Symbol->getType() == ELF::STT_SECTION
+ ? 0
+ : StrTabBuilder.getOffset(MSD.Name);
+ MSD.Symbol->setIndex(Index++);
+ writeSymbol(Writer, StringIndex, MSD, Layout);
+ }
+
+ // Write the symbol table entries.
+ LastLocalSymbolIndex = Index;
+
+ for (ELFSymbolData &MSD : ExternalSymbolData) {
+ unsigned StringIndex = StrTabBuilder.getOffset(MSD.Name);
+ MSD.Symbol->setIndex(Index++);
+ writeSymbol(Writer, StringIndex, MSD, Layout);
+ assert(MSD.Symbol->getBinding() != ELF::STB_LOCAL);
+ }
+
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[SymtabSection] = std::make_pair(SecStart, SecEnd);
+
+ ArrayRef<uint32_t> ShndxIndexes = Writer.getShndxIndexes();
+ if (ShndxIndexes.empty()) {
+ assert(SymtabShndxSectionIndex == 0);
+ return;
+ }
+ assert(SymtabShndxSectionIndex != 0);
+
+ SecStart = W.OS.tell();
+ const MCSectionELF *SymtabShndxSection =
+ SectionTable[SymtabShndxSectionIndex - 1];
+ for (uint32_t Index : ShndxIndexes)
+ write(Index);
+ SecEnd = W.OS.tell();
+ SectionOffsets[SymtabShndxSection] = std::make_pair(SecStart, SecEnd);
+}
+
+void ELFWriter::writeAddrsigSection() {
+ for (const MCSymbol *Sym : OWriter.AddrsigSyms)
+ encodeULEB128(Sym->getIndex(), W.OS);
+}
+
+MCSectionELF *ELFWriter::createRelocationSection(MCContext &Ctx,
+ const MCSectionELF &Sec) {
+ if (OWriter.Relocations[&Sec].empty())
+ return nullptr;
+
+ const StringRef SectionName = Sec.getSectionName();
+ std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel";
+ RelaSectionName += SectionName;
+
+ unsigned EntrySize;
+ if (hasRelocationAddend())
+ EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela);
+ else
+ EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel);
+
+ unsigned Flags = 0;
+ if (Sec.getFlags() & ELF::SHF_GROUP)
+ Flags = ELF::SHF_GROUP;
+
+ MCSectionELF *RelaSection = Ctx.createELFRelSection(
+ RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL,
+ Flags, EntrySize, Sec.getGroup(), &Sec);
+ RelaSection->setAlignment(is64Bit() ? Align(8) : Align(4));
+ return RelaSection;
+}
+
+// Include the debug info compression header.
+bool ELFWriter::maybeWriteCompression(
+ uint64_t Size, SmallVectorImpl<char> &CompressedContents, bool ZLibStyle,
+ unsigned Alignment) {
+ if (ZLibStyle) {
+ uint64_t HdrSize =
+ is64Bit() ? sizeof(ELF::Elf32_Chdr) : sizeof(ELF::Elf64_Chdr);
+ if (Size <= HdrSize + CompressedContents.size())
+ return false;
+ // Platform specific header is followed by compressed data.
+ if (is64Bit()) {
+ // Write Elf64_Chdr header.
+ write(static_cast<ELF::Elf64_Word>(ELF::ELFCOMPRESS_ZLIB));
+ write(static_cast<ELF::Elf64_Word>(0)); // ch_reserved field.
+ write(static_cast<ELF::Elf64_Xword>(Size));
+ write(static_cast<ELF::Elf64_Xword>(Alignment));
+ } else {
+ // Write Elf32_Chdr header otherwise.
+ write(static_cast<ELF::Elf32_Word>(ELF::ELFCOMPRESS_ZLIB));
+ write(static_cast<ELF::Elf32_Word>(Size));
+ write(static_cast<ELF::Elf32_Word>(Alignment));
+ }
+ return true;
+ }
+
+ // "ZLIB" followed by 8 bytes representing the uncompressed size of the section,
+ // useful for consumers to preallocate a buffer to decompress into.
+ const StringRef Magic = "ZLIB";
+ if (Size <= Magic.size() + sizeof(Size) + CompressedContents.size())
+ return false;
+ W.OS << Magic;
+ support::endian::write(W.OS, Size, support::big);
+ return true;
+}
+
+void ELFWriter::writeSectionData(const MCAssembler &Asm, MCSection &Sec,
+ const MCAsmLayout &Layout) {
+ MCSectionELF &Section = static_cast<MCSectionELF &>(Sec);
+ StringRef SectionName = Section.getSectionName();
+
+ auto &MC = Asm.getContext();
+ const auto &MAI = MC.getAsmInfo();
+
+ // Compressing debug_frame requires handling alignment fragments which is
+ // more work (possibly generalizing MCAssembler.cpp:writeFragment to allow
+ // for writing to arbitrary buffers) for little benefit.
+ bool CompressionEnabled =
+ MAI->compressDebugSections() != DebugCompressionType::None;
+ if (!CompressionEnabled || !SectionName.startswith(".debug_") ||
+ SectionName == ".debug_frame") {
+ Asm.writeSectionData(W.OS, &Section, Layout);
+ return;
+ }
+
+ assert((MAI->compressDebugSections() == DebugCompressionType::Z ||
+ MAI->compressDebugSections() == DebugCompressionType::GNU) &&
+ "expected zlib or zlib-gnu style compression");
+
+ SmallVector<char, 128> UncompressedData;
+ raw_svector_ostream VecOS(UncompressedData);
+ Asm.writeSectionData(VecOS, &Section, Layout);
+
+ SmallVector<char, 128> CompressedContents;
+ if (Error E = zlib::compress(
+ StringRef(UncompressedData.data(), UncompressedData.size()),
+ CompressedContents)) {
+ consumeError(std::move(E));
+ W.OS << UncompressedData;
+ return;
+ }
+
+ bool ZlibStyle = MAI->compressDebugSections() == DebugCompressionType::Z;
+ if (!maybeWriteCompression(UncompressedData.size(), CompressedContents,
+ ZlibStyle, Sec.getAlignment())) {
+ W.OS << UncompressedData;
+ return;
+ }
+
+ if (ZlibStyle) {
+ // Set the compressed flag. That is zlib style.
+ Section.setFlags(Section.getFlags() | ELF::SHF_COMPRESSED);
+ // Alignment field should reflect the requirements of
+ // the compressed section header.
+ Section.setAlignment(is64Bit() ? Align(8) : Align(4));
+ } else {
+ // Add "z" prefix to section name. This is zlib-gnu style.
+ MC.renameELFSection(&Section, (".z" + SectionName.drop_front(1)).str());
+ }
+ W.OS << CompressedContents;
+}
+
+void ELFWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
+ uint64_t Address, uint64_t Offset,
+ uint64_t Size, uint32_t Link, uint32_t Info,
+ uint64_t Alignment, uint64_t EntrySize) {
+ W.write<uint32_t>(Name); // sh_name: index into string table
+ W.write<uint32_t>(Type); // sh_type
+ WriteWord(Flags); // sh_flags
+ WriteWord(Address); // sh_addr
+ WriteWord(Offset); // sh_offset
+ WriteWord(Size); // sh_size
+ W.write<uint32_t>(Link); // sh_link
+ W.write<uint32_t>(Info); // sh_info
+ WriteWord(Alignment); // sh_addralign
+ WriteWord(EntrySize); // sh_entsize
+}
+
+void ELFWriter::writeRelocations(const MCAssembler &Asm,
+ const MCSectionELF &Sec) {
+ std::vector<ELFRelocationEntry> &Relocs = OWriter.Relocations[&Sec];
+
+ // We record relocations by pushing to the end of a vector. Reverse the vector
+ // to get the relocations in the order they were created.
+ // In most cases that is not important, but it can be for special sections
+ // (.eh_frame) or specific relocations (TLS optimizations on SystemZ).
+ std::reverse(Relocs.begin(), Relocs.end());
+
+ // Sort the relocation entries. MIPS needs this.
+ OWriter.TargetObjectWriter->sortRelocs(Asm, Relocs);
+
+ for (unsigned i = 0, e = Relocs.size(); i != e; ++i) {
+ const ELFRelocationEntry &Entry = Relocs[e - i - 1];
+ unsigned Index = Entry.Symbol ? Entry.Symbol->getIndex() : 0;
+
+ if (is64Bit()) {
+ write(Entry.Offset);
+ if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) {
+ write(uint32_t(Index));
+
+ write(OWriter.TargetObjectWriter->getRSsym(Entry.Type));
+ write(OWriter.TargetObjectWriter->getRType3(Entry.Type));
+ write(OWriter.TargetObjectWriter->getRType2(Entry.Type));
+ write(OWriter.TargetObjectWriter->getRType(Entry.Type));
+ } else {
+ struct ELF::Elf64_Rela ERE64;
+ ERE64.setSymbolAndType(Index, Entry.Type);
+ write(ERE64.r_info);
+ }
+ if (hasRelocationAddend())
+ write(Entry.Addend);
+ } else {
+ write(uint32_t(Entry.Offset));
+
+ struct ELF::Elf32_Rela ERE32;
+ ERE32.setSymbolAndType(Index, Entry.Type);
+ write(ERE32.r_info);
+
+ if (hasRelocationAddend())
+ write(uint32_t(Entry.Addend));
+
+ if (OWriter.TargetObjectWriter->getEMachine() == ELF::EM_MIPS) {
+ if (uint32_t RType =
+ OWriter.TargetObjectWriter->getRType2(Entry.Type)) {
+ write(uint32_t(Entry.Offset));
+
+ ERE32.setSymbolAndType(0, RType);
+ write(ERE32.r_info);
+ write(uint32_t(0));
+ }
+ if (uint32_t RType =
+ OWriter.TargetObjectWriter->getRType3(Entry.Type)) {
+ write(uint32_t(Entry.Offset));
+
+ ERE32.setSymbolAndType(0, RType);
+ write(ERE32.r_info);
+ write(uint32_t(0));
+ }
+ }
+ }
+ }
+}
+
+const MCSectionELF *ELFWriter::createStringTable(MCContext &Ctx) {
+ const MCSectionELF *StrtabSection = SectionTable[StringTableIndex - 1];
+ StrTabBuilder.write(W.OS);
+ return StrtabSection;
+}
+
+void ELFWriter::writeSection(const SectionIndexMapTy &SectionIndexMap,
+ uint32_t GroupSymbolIndex, uint64_t Offset,
+ uint64_t Size, const MCSectionELF &Section) {
+ uint64_t sh_link = 0;
+ uint64_t sh_info = 0;
+
+ switch(Section.getType()) {
+ default:
+ // Nothing to do.
+ break;
+
+ case ELF::SHT_DYNAMIC:
+ llvm_unreachable("SHT_DYNAMIC in a relocatable object");
+
+ case ELF::SHT_REL:
+ case ELF::SHT_RELA: {
+ sh_link = SymbolTableIndex;
+ assert(sh_link && ".symtab not found");
+ const MCSection *InfoSection = Section.getAssociatedSection();
+ sh_info = SectionIndexMap.lookup(cast<MCSectionELF>(InfoSection));
+ break;
+ }
+
+ case ELF::SHT_SYMTAB:
+ sh_link = StringTableIndex;
+ sh_info = LastLocalSymbolIndex;
+ break;
+
+ case ELF::SHT_SYMTAB_SHNDX:
+ case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
+ case ELF::SHT_LLVM_ADDRSIG:
+ sh_link = SymbolTableIndex;
+ break;
+
+ case ELF::SHT_GROUP:
+ sh_link = SymbolTableIndex;
+ sh_info = GroupSymbolIndex;
+ break;
+ }
+
+ if (Section.getFlags() & ELF::SHF_LINK_ORDER) {
+ const MCSymbol *Sym = Section.getAssociatedSymbol();
+ const MCSectionELF *Sec = cast<MCSectionELF>(&Sym->getSection());
+ sh_link = SectionIndexMap.lookup(Sec);
+ }
+
+ WriteSecHdrEntry(StrTabBuilder.getOffset(Section.getSectionName()),
+ Section.getType(), Section.getFlags(), 0, Offset, Size,
+ sh_link, sh_info, Section.getAlignment(),
+ Section.getEntrySize());
+}
+
+void ELFWriter::writeSectionHeader(
+ const MCAsmLayout &Layout, const SectionIndexMapTy &SectionIndexMap,
+ const SectionOffsetsTy &SectionOffsets) {
+ const unsigned NumSections = SectionTable.size();
+
+ // Null section first.
+ uint64_t FirstSectionSize =
+ (NumSections + 1) >= ELF::SHN_LORESERVE ? NumSections + 1 : 0;
+ WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, 0, 0, 0, 0);
+
+ for (const MCSectionELF *Section : SectionTable) {
+ uint32_t GroupSymbolIndex;
+ unsigned Type = Section->getType();
+ if (Type != ELF::SHT_GROUP)
+ GroupSymbolIndex = 0;
+ else
+ GroupSymbolIndex = Section->getGroup()->getIndex();
+
+ const std::pair<uint64_t, uint64_t> &Offsets =
+ SectionOffsets.find(Section)->second;
+ uint64_t Size;
+ if (Type == ELF::SHT_NOBITS)
+ Size = Layout.getSectionAddressSize(Section);
+ else
+ Size = Offsets.second - Offsets.first;
+
+ writeSection(SectionIndexMap, GroupSymbolIndex, Offsets.first, Size,
+ *Section);
+ }
+}
+
+uint64_t ELFWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) {
+ uint64_t StartOffset = W.OS.tell();
+
+ MCContext &Ctx = Asm.getContext();
+ MCSectionELF *StrtabSection =
+ Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0);
+ StringTableIndex = addToSectionTable(StrtabSection);
+
+ RevGroupMapTy RevGroupMap;
+ SectionIndexMapTy SectionIndexMap;
+
+ std::map<const MCSymbol *, std::vector<const MCSectionELF *>> GroupMembers;
+
+ // Write out the ELF header ...
+ writeHeader(Asm);
+
+ // ... then the sections ...
+ SectionOffsetsTy SectionOffsets;
+ std::vector<MCSectionELF *> Groups;
+ std::vector<MCSectionELF *> Relocations;
+ for (MCSection &Sec : Asm) {
+ MCSectionELF &Section = static_cast<MCSectionELF &>(Sec);
+ if (Mode == NonDwoOnly && isDwoSection(Section))
+ continue;
+ if (Mode == DwoOnly && !isDwoSection(Section))
+ continue;
+
+ align(Section.getAlignment());
+
+ // Remember the offset into the file for this section.
+ uint64_t SecStart = W.OS.tell();
+
+ const MCSymbolELF *SignatureSymbol = Section.getGroup();
+ writeSectionData(Asm, Section, Layout);
+
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[&Section] = std::make_pair(SecStart, SecEnd);
+
+ MCSectionELF *RelSection = createRelocationSection(Ctx, Section);
+
+ if (SignatureSymbol) {
+ Asm.registerSymbol(*SignatureSymbol);
+ unsigned &GroupIdx = RevGroupMap[SignatureSymbol];
+ if (!GroupIdx) {
+ MCSectionELF *Group = Ctx.createELFGroupSection(SignatureSymbol);
+ GroupIdx = addToSectionTable(Group);
+ Group->setAlignment(Align(4));
+ Groups.push_back(Group);
+ }
+ std::vector<const MCSectionELF *> &Members =
+ GroupMembers[SignatureSymbol];
+ Members.push_back(&Section);
+ if (RelSection)
+ Members.push_back(RelSection);
+ }
+
+ SectionIndexMap[&Section] = addToSectionTable(&Section);
+ if (RelSection) {
+ SectionIndexMap[RelSection] = addToSectionTable(RelSection);
+ Relocations.push_back(RelSection);
+ }
+
+ OWriter.TargetObjectWriter->addTargetSectionFlags(Ctx, Section);
+ }
+
+ MCSectionELF *CGProfileSection = nullptr;
+ if (!Asm.CGProfile.empty()) {
+ CGProfileSection = Ctx.getELFSection(".llvm.call-graph-profile",
+ ELF::SHT_LLVM_CALL_GRAPH_PROFILE,
+ ELF::SHF_EXCLUDE, 16, "");
+ SectionIndexMap[CGProfileSection] = addToSectionTable(CGProfileSection);
+ }
+
+ for (MCSectionELF *Group : Groups) {
+ align(Group->getAlignment());
+
+ // Remember the offset into the file for this section.
+ uint64_t SecStart = W.OS.tell();
+
+ const MCSymbol *SignatureSymbol = Group->getGroup();
+ assert(SignatureSymbol);
+ write(uint32_t(ELF::GRP_COMDAT));
+ for (const MCSectionELF *Member : GroupMembers[SignatureSymbol]) {
+ uint32_t SecIndex = SectionIndexMap.lookup(Member);
+ write(SecIndex);
+ }
+
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[Group] = std::make_pair(SecStart, SecEnd);
+ }
+
+ if (Mode == DwoOnly) {
+ // dwo files don't have symbol tables or relocations, but they do have
+ // string tables.
+ StrTabBuilder.finalize();
+ } else {
+ MCSectionELF *AddrsigSection;
+ if (OWriter.EmitAddrsigSection) {
+ AddrsigSection = Ctx.getELFSection(".llvm_addrsig", ELF::SHT_LLVM_ADDRSIG,
+ ELF::SHF_EXCLUDE);
+ addToSectionTable(AddrsigSection);
+ }
+
+ // Compute symbol table information.
+ computeSymbolTable(Asm, Layout, SectionIndexMap, RevGroupMap,
+ SectionOffsets);
+
+ for (MCSectionELF *RelSection : Relocations) {
+ align(RelSection->getAlignment());
+
+ // Remember the offset into the file for this section.
+ uint64_t SecStart = W.OS.tell();
+
+ writeRelocations(Asm,
+ cast<MCSectionELF>(*RelSection->getAssociatedSection()));
+
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[RelSection] = std::make_pair(SecStart, SecEnd);
+ }
+
+ if (OWriter.EmitAddrsigSection) {
+ uint64_t SecStart = W.OS.tell();
+ writeAddrsigSection();
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[AddrsigSection] = std::make_pair(SecStart, SecEnd);
+ }
+ }
+
+ if (CGProfileSection) {
+ uint64_t SecStart = W.OS.tell();
+ for (const MCAssembler::CGProfileEntry &CGPE : Asm.CGProfile) {
+ W.write<uint32_t>(CGPE.From->getSymbol().getIndex());
+ W.write<uint32_t>(CGPE.To->getSymbol().getIndex());
+ W.write<uint64_t>(CGPE.Count);
+ }
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[CGProfileSection] = std::make_pair(SecStart, SecEnd);
+ }
+
+ {
+ uint64_t SecStart = W.OS.tell();
+ const MCSectionELF *Sec = createStringTable(Ctx);
+ uint64_t SecEnd = W.OS.tell();
+ SectionOffsets[Sec] = std::make_pair(SecStart, SecEnd);
+ }
+
+ uint64_t NaturalAlignment = is64Bit() ? 8 : 4;
+ align(NaturalAlignment);
+
+ const uint64_t SectionHeaderOffset = W.OS.tell();
+
+ // ... then the section header table ...
+ writeSectionHeader(Layout, SectionIndexMap, SectionOffsets);
+
+ uint16_t NumSections = support::endian::byte_swap<uint16_t>(
+ (SectionTable.size() + 1 >= ELF::SHN_LORESERVE) ? (uint16_t)ELF::SHN_UNDEF
+ : SectionTable.size() + 1,
+ W.Endian);
+ unsigned NumSectionsOffset;
+
+ auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
+ if (is64Bit()) {
+ uint64_t Val =
+ support::endian::byte_swap<uint64_t>(SectionHeaderOffset, W.Endian);
+ Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
+ offsetof(ELF::Elf64_Ehdr, e_shoff));
+ NumSectionsOffset = offsetof(ELF::Elf64_Ehdr, e_shnum);
+ } else {
+ uint32_t Val =
+ support::endian::byte_swap<uint32_t>(SectionHeaderOffset, W.Endian);
+ Stream.pwrite(reinterpret_cast<char *>(&Val), sizeof(Val),
+ offsetof(ELF::Elf32_Ehdr, e_shoff));
+ NumSectionsOffset = offsetof(ELF::Elf32_Ehdr, e_shnum);
+ }
+ Stream.pwrite(reinterpret_cast<char *>(&NumSections), sizeof(NumSections),
+ NumSectionsOffset);
+
+ return W.OS.tell() - StartOffset;
+}
+
+bool ELFObjectWriter::hasRelocationAddend() const {
+ return TargetObjectWriter->hasRelocationAddend();
+}
+
+void ELFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ // The presence of symbol versions causes undefined symbols and
+ // versions declared with @@@ to be renamed.
+ for (const std::pair<StringRef, const MCSymbol *> &P : Asm.Symvers) {
+ StringRef AliasName = P.first;
+ const auto &Symbol = cast<MCSymbolELF>(*P.second);
+ size_t Pos = AliasName.find('@');
+ assert(Pos != StringRef::npos);
+
+ StringRef Prefix = AliasName.substr(0, Pos);
+ StringRef Rest = AliasName.substr(Pos);
+ StringRef Tail = Rest;
+ if (Rest.startswith("@@@"))
+ Tail = Rest.substr(Symbol.isUndefined() ? 2 : 1);
+
+ auto *Alias =
+ cast<MCSymbolELF>(Asm.getContext().getOrCreateSymbol(Prefix + Tail));
+ Asm.registerSymbol(*Alias);
+ const MCExpr *Value = MCSymbolRefExpr::create(&Symbol, Asm.getContext());
+ Alias->setVariableValue(Value);
+
+ // Aliases defined with .symvar copy the binding from the symbol they alias.
+ // This is the first place we are able to copy this information.
+ Alias->setExternal(Symbol.isExternal());
+ Alias->setBinding(Symbol.getBinding());
+ Alias->setOther(Symbol.getOther());
+
+ if (!Symbol.isUndefined() && !Rest.startswith("@@@"))
+ continue;
+
+ // FIXME: Get source locations for these errors or diagnose them earlier.
+ if (Symbol.isUndefined() && Rest.startswith("@@") &&
+ !Rest.startswith("@@@")) {
+ Asm.getContext().reportError(SMLoc(), "versioned symbol " + AliasName +
+ " must be defined");
+ continue;
+ }
+
+ if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) {
+ Asm.getContext().reportError(
+ SMLoc(), llvm::Twine("multiple symbol versions defined for ") +
+ Symbol.getName());
+ continue;
+ }
+
+ Renames.insert(std::make_pair(&Symbol, Alias));
+ }
+
+ for (const MCSymbol *&Sym : AddrsigSyms) {
+ if (const MCSymbol *R = Renames.lookup(cast<MCSymbolELF>(Sym)))
+ Sym = R;
+ if (Sym->isInSection() && Sym->getName().startswith(".L"))
+ Sym = Sym->getSection().getBeginSymbol();
+ Sym->setUsedInReloc();
+ }
+}
+
+// It is always valid to create a relocation with a symbol. It is preferable
+// to use a relocation with a section if that is possible. Using the section
+// allows us to omit some local symbols from the symbol table.
+bool ELFObjectWriter::shouldRelocateWithSymbol(const MCAssembler &Asm,
+ const MCSymbolRefExpr *RefA,
+ const MCSymbolELF *Sym,
+ uint64_t C,
+ unsigned Type) const {
+ // A PCRel relocation to an absolute value has no symbol (or section). We
+ // represent that with a relocation to a null section.
+ if (!RefA)
+ return false;
+
+ MCSymbolRefExpr::VariantKind Kind = RefA->getKind();
+ switch (Kind) {
+ default:
+ break;
+ // The .odp creation emits a relocation against the symbol ".TOC." which
+ // create a R_PPC64_TOC relocation. However the relocation symbol name
+ // in final object creation should be NULL, since the symbol does not
+ // really exist, it is just the reference to TOC base for the current
+ // object file. Since the symbol is undefined, returning false results
+ // in a relocation with a null section which is the desired result.
+ case MCSymbolRefExpr::VK_PPC_TOCBASE:
+ return false;
+
+ // These VariantKind cause the relocation to refer to something other than
+ // the symbol itself, like a linker generated table. Since the address of
+ // symbol is not relevant, we cannot replace the symbol with the
+ // section and patch the difference in the addend.
+ case MCSymbolRefExpr::VK_GOT:
+ case MCSymbolRefExpr::VK_PLT:
+ case MCSymbolRefExpr::VK_GOTPCREL:
+ case MCSymbolRefExpr::VK_PPC_GOT_LO:
+ case MCSymbolRefExpr::VK_PPC_GOT_HI:
+ case MCSymbolRefExpr::VK_PPC_GOT_HA:
+ return true;
+ }
+
+ // An undefined symbol is not in any section, so the relocation has to point
+ // to the symbol itself.
+ assert(Sym && "Expected a symbol");
+ if (Sym->isUndefined())
+ return true;
+
+ unsigned Binding = Sym->getBinding();
+ switch(Binding) {
+ default:
+ llvm_unreachable("Invalid Binding");
+ case ELF::STB_LOCAL:
+ break;
+ case ELF::STB_WEAK:
+ // If the symbol is weak, it might be overridden by a symbol in another
+ // file. The relocation has to point to the symbol so that the linker
+ // can update it.
+ return true;
+ case ELF::STB_GLOBAL:
+ // Global ELF symbols can be preempted by the dynamic linker. The relocation
+ // has to point to the symbol for a reason analogous to the STB_WEAK case.
+ return true;
+ }
+
+ // Keep symbol type for a local ifunc because it may result in an IRELATIVE
+ // reloc that the dynamic loader will use to resolve the address at startup
+ // time.
+ if (Sym->getType() == ELF::STT_GNU_IFUNC)
+ return true;
+
+ // If a relocation points to a mergeable section, we have to be careful.
+ // If the offset is zero, a relocation with the section will encode the
+ // same information. With a non-zero offset, the situation is different.
+ // For example, a relocation can point 42 bytes past the end of a string.
+ // If we change such a relocation to use the section, the linker would think
+ // that it pointed to another string and subtracting 42 at runtime will
+ // produce the wrong value.
+ if (Sym->isInSection()) {
+ auto &Sec = cast<MCSectionELF>(Sym->getSection());
+ unsigned Flags = Sec.getFlags();
+ if (Flags & ELF::SHF_MERGE) {
+ if (C != 0)
+ return true;
+
+ // It looks like gold has a bug (http://sourceware.org/PR16794) and can
+ // only handle section relocations to mergeable sections if using RELA.
+ if (!hasRelocationAddend())
+ return true;
+ }
+
+ // Most TLS relocations use a got, so they need the symbol. Even those that
+ // are just an offset (@tpoff), require a symbol in gold versions before
+ // 5efeedf61e4fe720fd3e9a08e6c91c10abb66d42 (2014-09-26) which fixed
+ // http://sourceware.org/PR16773.
+ if (Flags & ELF::SHF_TLS)
+ return true;
+ }
+
+ // If the symbol is a thumb function the final relocation must set the lowest
+ // bit. With a symbol that is done by just having the symbol have that bit
+ // set, so we would lose the bit if we relocated with the section.
+ // FIXME: We could use the section but add the bit to the relocation value.
+ if (Asm.isThumbFunc(Sym))
+ return true;
+
+ if (TargetObjectWriter->needsRelocateWithSymbol(*Sym, Type))
+ return true;
+ return false;
+}
+
+void ELFObjectWriter::recordRelocation(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ MCAsmBackend &Backend = Asm.getBackend();
+ bool IsPCRel = Backend.getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsPCRel;
+ const MCSectionELF &FixupSection = cast<MCSectionELF>(*Fragment->getParent());
+ uint64_t C = Target.getConstant();
+ uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+ MCContext &Ctx = Asm.getContext();
+
+ if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
+ const auto &SymB = cast<MCSymbolELF>(RefB->getSymbol());
+ if (SymB.isUndefined()) {
+ Ctx.reportError(Fixup.getLoc(),
+ Twine("symbol '") + SymB.getName() +
+ "' can not be undefined in a subtraction expression");
+ return;
+ }
+
+ assert(!SymB.isAbsolute() && "Should have been folded");
+ const MCSection &SecB = SymB.getSection();
+ if (&SecB != &FixupSection) {
+ Ctx.reportError(Fixup.getLoc(),
+ "Cannot represent a difference across sections");
+ return;
+ }
+
+ assert(!IsPCRel && "should have been folded");
+ IsPCRel = true;
+ C += FixupOffset - Layout.getSymbolOffset(SymB);
+ }
+
+ // We either rejected the fixup or folded B into C at this point.
+ const MCSymbolRefExpr *RefA = Target.getSymA();
+ const auto *SymA = RefA ? cast<MCSymbolELF>(&RefA->getSymbol()) : nullptr;
+
+ bool ViaWeakRef = false;
+ if (SymA && SymA->isVariable()) {
+ const MCExpr *Expr = SymA->getVariableValue();
+ if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
+ if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
+ SymA = cast<MCSymbolELF>(&Inner->getSymbol());
+ ViaWeakRef = true;
+ }
+ }
+ }
+
+ const MCSectionELF *SecA = (SymA && SymA->isInSection())
+ ? cast<MCSectionELF>(&SymA->getSection())
+ : nullptr;
+ if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA))
+ return;
+
+ unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
+ bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type);
+ uint64_t Addend = 0;
+
+ FixedValue = !RelocateWithSymbol && SymA && !SymA->isUndefined()
+ ? C + Layout.getSymbolOffset(*SymA)
+ : C;
+ if (hasRelocationAddend()) {
+ Addend = FixedValue;
+ FixedValue = 0;
+ }
+
+ if (!RelocateWithSymbol) {
+ const auto *SectionSymbol =
+ SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr;
+ if (SectionSymbol)
+ SectionSymbol->setUsedInReloc();
+ ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, C);
+ Relocations[&FixupSection].push_back(Rec);
+ return;
+ }
+
+ const MCSymbolELF *RenamedSymA = SymA;
+ if (SymA) {
+ if (const MCSymbolELF *R = Renames.lookup(SymA))
+ RenamedSymA = R;
+
+ if (ViaWeakRef)
+ RenamedSymA->setIsWeakrefUsedInReloc();
+ else
+ RenamedSymA->setUsedInReloc();
+ }
+ ELFRelocationEntry Rec(FixupOffset, RenamedSymA, Type, Addend, SymA, C);
+ Relocations[&FixupSection].push_back(Rec);
+}
+
+bool ELFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &SA, const MCFragment &FB,
+ bool InSet, bool IsPCRel) const {
+ const auto &SymA = cast<MCSymbolELF>(SA);
+ if (IsPCRel) {
+ assert(!InSet);
+ if (isWeak(SymA))
+ return false;
+ }
+ return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB,
+ InSet, IsPCRel);
+}
+
+std::unique_ptr<MCObjectWriter>
+llvm::createELFObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS, bool IsLittleEndian) {
+ return std::make_unique<ELFSingleObjectWriter>(std::move(MOTW), OS,
+ IsLittleEndian);
+}
+
+std::unique_ptr<MCObjectWriter>
+llvm::createELFDwoObjectWriter(std::unique_ptr<MCELFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS, raw_pwrite_stream &DwoOS,
+ bool IsLittleEndian) {
+ return std::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS,
+ IsLittleEndian);
+}
diff --git a/llvm/lib/MC/MCAsmBackend.cpp b/llvm/lib/MC/MCAsmBackend.cpp
new file mode 100644
index 000000000000..b800e9caee22
--- /dev/null
+++ b/llvm/lib/MC/MCAsmBackend.cpp
@@ -0,0 +1,137 @@
+//===- MCAsmBackend.cpp - Target MC Assembly Backend ----------------------===//
+//
+// 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/MCAsmBackend.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCCodePadder.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCWasmObjectWriter.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+#include "llvm/MC/MCXCOFFObjectWriter.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+
+MCAsmBackend::MCAsmBackend(support::endianness Endian)
+ : CodePadder(new MCCodePadder()), Endian(Endian) {}
+
+MCAsmBackend::~MCAsmBackend() = default;
+
+std::unique_ptr<MCObjectWriter>
+MCAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const {
+ auto TW = createObjectTargetWriter();
+ switch (TW->getFormat()) {
+ case Triple::ELF:
+ return createELFObjectWriter(cast<MCELFObjectTargetWriter>(std::move(TW)), OS,
+ Endian == support::little);
+ case Triple::MachO:
+ return createMachObjectWriter(cast<MCMachObjectTargetWriter>(std::move(TW)),
+ OS, Endian == support::little);
+ case Triple::COFF:
+ return createWinCOFFObjectWriter(
+ cast<MCWinCOFFObjectTargetWriter>(std::move(TW)), OS);
+ case Triple::Wasm:
+ return createWasmObjectWriter(cast<MCWasmObjectTargetWriter>(std::move(TW)),
+ OS);
+ case Triple::XCOFF:
+ return createXCOFFObjectWriter(
+ cast<MCXCOFFObjectTargetWriter>(std::move(TW)), OS);
+ default:
+ llvm_unreachable("unexpected object format");
+ }
+}
+
+std::unique_ptr<MCObjectWriter>
+MCAsmBackend::createDwoObjectWriter(raw_pwrite_stream &OS,
+ raw_pwrite_stream &DwoOS) const {
+ auto TW = createObjectTargetWriter();
+ if (TW->getFormat() != Triple::ELF)
+ report_fatal_error("dwo only supported with ELF");
+ return createELFDwoObjectWriter(cast<MCELFObjectTargetWriter>(std::move(TW)),
+ OS, DwoOS, Endian == support::little);
+}
+
+Optional<MCFixupKind> MCAsmBackend::getFixupKind(StringRef Name) const {
+ return None;
+}
+
+const MCFixupKindInfo &MCAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
+ static const MCFixupKindInfo Builtins[] = {
+ {"FK_NONE", 0, 0, 0},
+ {"FK_Data_1", 0, 8, 0},
+ {"FK_Data_2", 0, 16, 0},
+ {"FK_Data_4", 0, 32, 0},
+ {"FK_Data_8", 0, 64, 0},
+ {"FK_Data_6b", 0, 6, 0},
+ {"FK_PCRel_1", 0, 8, MCFixupKindInfo::FKF_IsPCRel},
+ {"FK_PCRel_2", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
+ {"FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel},
+ {"FK_PCRel_8", 0, 64, MCFixupKindInfo::FKF_IsPCRel},
+ {"FK_GPRel_1", 0, 8, 0},
+ {"FK_GPRel_2", 0, 16, 0},
+ {"FK_GPRel_4", 0, 32, 0},
+ {"FK_GPRel_8", 0, 64, 0},
+ {"FK_DTPRel_4", 0, 32, 0},
+ {"FK_DTPRel_8", 0, 64, 0},
+ {"FK_TPRel_4", 0, 32, 0},
+ {"FK_TPRel_8", 0, 64, 0},
+ {"FK_SecRel_1", 0, 8, 0},
+ {"FK_SecRel_2", 0, 16, 0},
+ {"FK_SecRel_4", 0, 32, 0},
+ {"FK_SecRel_8", 0, 64, 0},
+ {"FK_Data_Add_1", 0, 8, 0},
+ {"FK_Data_Add_2", 0, 16, 0},
+ {"FK_Data_Add_4", 0, 32, 0},
+ {"FK_Data_Add_8", 0, 64, 0},
+ {"FK_Data_Add_6b", 0, 6, 0},
+ {"FK_Data_Sub_1", 0, 8, 0},
+ {"FK_Data_Sub_2", 0, 16, 0},
+ {"FK_Data_Sub_4", 0, 32, 0},
+ {"FK_Data_Sub_8", 0, 64, 0},
+ {"FK_Data_Sub_6b", 0, 6, 0}};
+
+ assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind");
+ return Builtins[Kind];
+}
+
+bool MCAsmBackend::fixupNeedsRelaxationAdvanced(
+ const MCFixup &Fixup, bool Resolved, uint64_t Value,
+ const MCRelaxableFragment *DF, const MCAsmLayout &Layout,
+ const bool WasForced) const {
+ if (!Resolved)
+ return true;
+ return fixupNeedsRelaxation(Fixup, Value, DF, Layout);
+}
+
+void MCAsmBackend::handleCodePaddingBasicBlockStart(
+ MCObjectStreamer *OS, const MCCodePaddingContext &Context) {
+ CodePadder->handleBasicBlockStart(OS, Context);
+}
+
+void MCAsmBackend::handleCodePaddingBasicBlockEnd(
+ const MCCodePaddingContext &Context) {
+ CodePadder->handleBasicBlockEnd(Context);
+}
+
+void MCAsmBackend::handleCodePaddingInstructionBegin(const MCInst &Inst) {
+ CodePadder->handleInstructionBegin(Inst);
+}
+
+void MCAsmBackend::handleCodePaddingInstructionEnd(const MCInst &Inst) {
+ CodePadder->handleInstructionEnd(Inst);
+}
+
+bool MCAsmBackend::relaxFragment(MCPaddingFragment *PF, MCAsmLayout &Layout) {
+ return CodePadder->relaxFragment(PF, Layout);
+}
diff --git a/llvm/lib/MC/MCAsmInfo.cpp b/llvm/lib/MC/MCAsmInfo.cpp
new file mode 100644
index 000000000000..71e51e320f8b
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfo.cpp
@@ -0,0 +1,126 @@
+//===- MCAsmInfo.cpp - Asm Info -------------------------------------------===//
+//
+// 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 defines target asm properties related what form asm statements
+// should take.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/CommandLine.h"
+
+using namespace llvm;
+
+enum DefaultOnOff { Default, Enable, Disable };
+static cl::opt<DefaultOnOff> DwarfExtendedLoc(
+ "dwarf-extended-loc", cl::Hidden,
+ cl::desc("Disable emission of the extended flags in .loc directives."),
+ cl::values(clEnumVal(Default, "Default for platform"),
+ clEnumVal(Enable, "Enabled"), clEnumVal(Disable, "Disabled")),
+ cl::init(Default));
+
+MCAsmInfo::MCAsmInfo() {
+ SeparatorString = ";";
+ CommentString = "#";
+ LabelSuffix = ":";
+ PrivateGlobalPrefix = "L";
+ PrivateLabelPrefix = PrivateGlobalPrefix;
+ LinkerPrivateGlobalPrefix = "";
+ InlineAsmStart = "APP";
+ InlineAsmEnd = "NO_APP";
+ Code16Directive = ".code16";
+ Code32Directive = ".code32";
+ Code64Directive = ".code64";
+ ZeroDirective = "\t.zero\t";
+ AsciiDirective = "\t.ascii\t";
+ AscizDirective = "\t.asciz\t";
+ Data8bitsDirective = "\t.byte\t";
+ Data16bitsDirective = "\t.short\t";
+ Data32bitsDirective = "\t.long\t";
+ Data64bitsDirective = "\t.quad\t";
+ GlobalDirective = "\t.globl\t";
+ WeakDirective = "\t.weak\t";
+ if (DwarfExtendedLoc != Default)
+ SupportsExtendedDwarfLocDirective = DwarfExtendedLoc == Enable;
+
+ // FIXME: Clang's logic should be synced with the logic used to initialize
+ // this member and the two implementations should be merged.
+ // For reference:
+ // - Solaris always enables the integrated assembler by default
+ // - SparcELFMCAsmInfo and X86ELFMCAsmInfo are handling this case
+ // - Windows always enables the integrated assembler by default
+ // - MCAsmInfoCOFF is handling this case, should it be MCAsmInfoMicrosoft?
+ // - MachO targets always enables the integrated assembler by default
+ // - MCAsmInfoDarwin is handling this case
+ // - Generic_GCC toolchains enable the integrated assembler on a per
+ // architecture basis.
+ // - The target subclasses for AArch64, ARM, and X86 handle these cases
+ UseIntegratedAssembler = false;
+ PreserveAsmComments = true;
+}
+
+MCAsmInfo::~MCAsmInfo() = default;
+
+void MCAsmInfo::addInitialFrameState(const MCCFIInstruction &Inst) {
+ InitialFrameState.push_back(Inst);
+}
+
+bool MCAsmInfo::isSectionAtomizableBySymbols(const MCSection &Section) const {
+ return false;
+}
+
+const MCExpr *
+MCAsmInfo::getExprForPersonalitySymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const {
+ return getExprForFDESymbol(Sym, Encoding, Streamer);
+}
+
+const MCExpr *
+MCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const {
+ if (!(Encoding & dwarf::DW_EH_PE_pcrel))
+ return MCSymbolRefExpr::create(Sym, Streamer.getContext());
+
+ MCContext &Context = Streamer.getContext();
+ const MCExpr *Res = MCSymbolRefExpr::create(Sym, Context);
+ MCSymbol *PCSym = Context.createTempSymbol();
+ Streamer.EmitLabel(PCSym);
+ const MCExpr *PC = MCSymbolRefExpr::create(PCSym, Context);
+ return MCBinaryExpr::createSub(Res, PC, Context);
+}
+
+static bool isAcceptableChar(char C) {
+ return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
+ (C >= '0' && C <= '9') || C == '_' || C == '$' || C == '.' || C == '@';
+}
+
+bool MCAsmInfo::isValidUnquotedName(StringRef Name) const {
+ if (Name.empty())
+ return false;
+
+ // If any of the characters in the string is an unacceptable character, force
+ // quotes.
+ for (char C : Name) {
+ if (!isAcceptableChar(C))
+ return false;
+ }
+
+ return true;
+}
+
+bool MCAsmInfo::shouldOmitSectionDirective(StringRef SectionName) const {
+ // FIXME: Does .section .bss/.data/.text work everywhere??
+ return SectionName == ".text" || SectionName == ".data" ||
+ (SectionName == ".bss" && !usesELFSectionDirectiveForBSS());
+}
diff --git a/llvm/lib/MC/MCAsmInfoCOFF.cpp b/llvm/lib/MC/MCAsmInfoCOFF.cpp
new file mode 100644
index 000000000000..9f19d163f57b
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfoCOFF.cpp
@@ -0,0 +1,68 @@
+//===- MCAsmInfoCOFF.cpp - COFF asm properties ----------------------------===//
+//
+// 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 defines target asm properties related what form asm statements
+// should take in general on COFF-based targets
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmInfoCOFF.h"
+#include "llvm/MC/MCDirectives.h"
+
+using namespace llvm;
+
+void MCAsmInfoCOFF::anchor() {}
+
+MCAsmInfoCOFF::MCAsmInfoCOFF() {
+ // MingW 4.5 and later support .comm with log2 alignment, but .lcomm uses byte
+ // alignment.
+ COMMDirectiveAlignmentIsInBytes = false;
+ LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment;
+ HasDotTypeDotSizeDirective = false;
+ HasSingleParameterDotFile = true;
+ WeakRefDirective = "\t.weak\t";
+ HasLinkOnceDirective = true;
+
+ // Doesn't support visibility:
+ HiddenVisibilityAttr = HiddenDeclarationVisibilityAttr = MCSA_Invalid;
+ ProtectedVisibilityAttr = MCSA_Invalid;
+
+ // Set up DWARF directives
+ SupportsDebugInformation = true;
+ NeedsDwarfSectionOffsetDirective = true;
+
+ UseIntegratedAssembler = true;
+
+ // At least MSVC inline-asm does AShr.
+ UseLogicalShr = false;
+
+ // If this is a COFF target, assume that it supports associative comdats. It's
+ // part of the spec.
+ HasCOFFAssociativeComdats = true;
+
+ // We can generate constants in comdat sections that can be shared,
+ // but in order not to create null typed symbols, we actually need to
+ // make them global symbols as well.
+ HasCOFFComdatConstants = true;
+}
+
+void MCAsmInfoMicrosoft::anchor() {}
+
+MCAsmInfoMicrosoft::MCAsmInfoMicrosoft() = default;
+
+void MCAsmInfoGNUCOFF::anchor() {}
+
+MCAsmInfoGNUCOFF::MCAsmInfoGNUCOFF() {
+ // If this is a GNU environment (mingw or cygwin), don't use associative
+ // comdats for jump tables, unwind information, and other data associated with
+ // a function.
+ HasCOFFAssociativeComdats = false;
+
+ // We don't create constants in comdat sections for MinGW.
+ HasCOFFComdatConstants = false;
+}
diff --git a/llvm/lib/MC/MCAsmInfoDarwin.cpp b/llvm/lib/MC/MCAsmInfoDarwin.cpp
new file mode 100644
index 000000000000..62bc5b8c9418
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfoDarwin.cpp
@@ -0,0 +1,97 @@
+//===- MCAsmInfoDarwin.cpp - Darwin asm properties ------------------------===//
+//
+// 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 defines target asm properties related what form asm statements
+// should take in general on Darwin-based targets
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmInfoDarwin.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCSectionMachO.h"
+
+using namespace llvm;
+
+bool MCAsmInfoDarwin::isSectionAtomizableBySymbols(
+ const MCSection &Section) const {
+ const MCSectionMachO &SMO = static_cast<const MCSectionMachO &>(Section);
+
+ // Sections holding 1 byte strings are atomized based on the data they
+ // contain.
+ // Sections holding 2 byte strings require symbols in order to be atomized.
+ // There is no dedicated section for 4 byte strings.
+ if (SMO.getType() == MachO::S_CSTRING_LITERALS)
+ return false;
+
+ if (SMO.getSegmentName() == "__DATA" && SMO.getSectionName() == "__cfstring")
+ return false;
+
+ if (SMO.getSegmentName() == "__DATA" &&
+ SMO.getSectionName() == "__objc_classrefs")
+ return false;
+
+ switch (SMO.getType()) {
+ default:
+ return true;
+
+ // These sections are atomized at the element boundaries without using
+ // symbols.
+ case MachO::S_4BYTE_LITERALS:
+ case MachO::S_8BYTE_LITERALS:
+ case MachO::S_16BYTE_LITERALS:
+ case MachO::S_LITERAL_POINTERS:
+ case MachO::S_NON_LAZY_SYMBOL_POINTERS:
+ case MachO::S_LAZY_SYMBOL_POINTERS:
+ case MachO::S_THREAD_LOCAL_VARIABLE_POINTERS:
+ case MachO::S_MOD_INIT_FUNC_POINTERS:
+ case MachO::S_MOD_TERM_FUNC_POINTERS:
+ case MachO::S_INTERPOSING:
+ return false;
+ }
+}
+
+MCAsmInfoDarwin::MCAsmInfoDarwin() {
+ // Common settings for all Darwin targets.
+ // Syntax:
+ LinkerPrivateGlobalPrefix = "l";
+ HasSingleParameterDotFile = false;
+ HasSubsectionsViaSymbols = true;
+
+ AlignmentIsInBytes = false;
+ COMMDirectiveAlignmentIsInBytes = false;
+ LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment;
+ InlineAsmStart = " InlineAsm Start";
+ InlineAsmEnd = " InlineAsm End";
+
+ // Directives:
+ HasWeakDefDirective = true;
+ HasWeakDefCanBeHiddenDirective = true;
+ WeakRefDirective = "\t.weak_reference ";
+ ZeroDirective = "\t.space\t"; // ".space N" emits N zeros.
+ HasMachoZeroFillDirective = true; // Uses .zerofill
+ HasMachoTBSSDirective = true; // Uses .tbss
+
+ // FIXME: Change this once MC is the system assembler.
+ HasAggressiveSymbolFolding = false;
+
+ HiddenVisibilityAttr = MCSA_PrivateExtern;
+ HiddenDeclarationVisibilityAttr = MCSA_Invalid;
+
+ // Doesn't support protected visibility.
+ ProtectedVisibilityAttr = MCSA_Invalid;
+
+ HasDotTypeDotSizeDirective = false;
+ HasNoDeadStrip = true;
+ HasAltEntry = true;
+
+ DwarfUsesRelocationsAcrossSections = false;
+
+ UseIntegratedAssembler = true;
+ SetDirectiveSuppressesReloc = true;
+}
diff --git a/llvm/lib/MC/MCAsmInfoELF.cpp b/llvm/lib/MC/MCAsmInfoELF.cpp
new file mode 100644
index 000000000000..a5e8aff7f129
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfoELF.cpp
@@ -0,0 +1,34 @@
+//===- MCAsmInfoELF.cpp - ELF asm properties ------------------------------===//
+//
+// 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 defines target asm properties related what form asm statements
+// should take in general on ELF-based targets
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmInfoELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSectionELF.h"
+
+using namespace llvm;
+
+void MCAsmInfoELF::anchor() {}
+
+MCSection *MCAsmInfoELF::getNonexecutableStackSection(MCContext &Ctx) const {
+ if (!UsesNonexecutableStackSection)
+ return nullptr;
+ return Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0);
+}
+
+MCAsmInfoELF::MCAsmInfoELF() {
+ HasIdentDirective = true;
+ WeakRefDirective = "\t.weak\t";
+ PrivateGlobalPrefix = ".L";
+ PrivateLabelPrefix = ".L";
+}
diff --git a/llvm/lib/MC/MCAsmInfoWasm.cpp b/llvm/lib/MC/MCAsmInfoWasm.cpp
new file mode 100644
index 000000000000..ce6ec7ef211e
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfoWasm.cpp
@@ -0,0 +1,25 @@
+//===-- MCAsmInfoWasm.cpp - Wasm asm properties -----------------*- C++ -*-===//
+//
+// 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 defines target asm properties related what form asm statements
+// should take in general on Wasm-based targets
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmInfoWasm.h"
+using namespace llvm;
+
+void MCAsmInfoWasm::anchor() {}
+
+MCAsmInfoWasm::MCAsmInfoWasm() {
+ HasIdentDirective = true;
+ HasNoDeadStrip = true;
+ WeakRefDirective = "\t.weak\t";
+ PrivateGlobalPrefix = ".L";
+ PrivateLabelPrefix = ".L";
+}
diff --git a/llvm/lib/MC/MCAsmInfoXCOFF.cpp b/llvm/lib/MC/MCAsmInfoXCOFF.cpp
new file mode 100644
index 000000000000..65fe8848e20f
--- /dev/null
+++ b/llvm/lib/MC/MCAsmInfoXCOFF.cpp
@@ -0,0 +1,35 @@
+//===- MC/MCAsmInfoXCOFF.cpp - XCOFF asm properties ------------ *- C++ -*-===//
+//
+// 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/MCAsmInfoXCOFF.h"
+
+using namespace llvm;
+
+void MCAsmInfoXCOFF::anchor() {}
+
+MCAsmInfoXCOFF::MCAsmInfoXCOFF() {
+ IsLittleEndian = false;
+ HasDotTypeDotSizeDirective = false;
+ COMMDirectiveAlignmentIsInBytes = false;
+ LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment;
+ UseDotAlignForAlignment = true;
+ AsciiDirective = nullptr; // not supported
+ AscizDirective = nullptr; // not supported
+ NeedsFunctionDescriptors = true;
+ HasDotLGloblDirective = true;
+ Data64bitsDirective = "\t.llong\t";
+ SupportsQuotedNames = false;
+}
+
+bool MCAsmInfoXCOFF::isValidUnquotedName(StringRef Name) const {
+ // FIXME: Remove this function when we stop using "TOC[TC0]" as a symbol name.
+ if (Name.equals("TOC[TC0]"))
+ return true;
+
+ return MCAsmInfo::isValidUnquotedName(Name);
+}
diff --git a/llvm/lib/MC/MCAsmMacro.cpp b/llvm/lib/MC/MCAsmMacro.cpp
new file mode 100644
index 000000000000..186a68b02a29
--- /dev/null
+++ b/llvm/lib/MC/MCAsmMacro.cpp
@@ -0,0 +1,43 @@
+//===- MCAsmMacro.h - Assembly Macros ---------------------------*- C++ -*-===//
+//
+// 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/MCAsmMacro.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+void MCAsmMacroParameter::dump(raw_ostream &OS) const {
+ OS << "\"" << Name << "\"";
+ if (Required)
+ OS << ":req";
+ if (Vararg)
+ OS << ":vararg";
+ if (!Value.empty()) {
+ OS << " = ";
+ bool first = true;
+ for (const AsmToken &T : Value) {
+ if (!first)
+ OS << ", ";
+ first = false;
+ OS << T.getString();
+ }
+ }
+ OS << "\n";
+}
+
+void MCAsmMacro::dump(raw_ostream &OS) const {
+ OS << "Macro " << Name << ":\n";
+ OS << " Parameters:\n";
+ for (const MCAsmMacroParameter &P : Parameters) {
+ OS << " ";
+ P.dump();
+ }
+ OS << " (BEGIN BODY)" << Body << "(END BODY)\n";
+}
+#endif
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
new file mode 100644
index 000000000000..2d9c2cb21255
--- /dev/null
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -0,0 +1,2035 @@
+//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===//
+//
+// 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/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.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/MCExpr.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/TargetRegistry.h"
+#include <cctype>
+
+using namespace llvm;
+
+namespace {
+
+class MCAsmStreamer final : public MCStreamer {
+ std::unique_ptr<formatted_raw_ostream> OSOwner;
+ formatted_raw_ostream &OS;
+ const MCAsmInfo *MAI;
+ std::unique_ptr<MCInstPrinter> InstPrinter;
+ std::unique_ptr<MCAssembler> Assembler;
+
+ SmallString<128> ExplicitCommentToEmit;
+ SmallString<128> CommentToEmit;
+ raw_svector_ostream CommentStream;
+ raw_null_ostream NullStream;
+
+ unsigned IsVerboseAsm : 1;
+ unsigned ShowInst : 1;
+ unsigned UseDwarfDirectory : 1;
+
+ void EmitRegisterName(int64_t Register);
+ void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) override;
+ void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) override;
+
+public:
+ MCAsmStreamer(MCContext &Context, std::unique_ptr<formatted_raw_ostream> os,
+ bool isVerboseAsm, bool useDwarfDirectory,
+ MCInstPrinter *printer, std::unique_ptr<MCCodeEmitter> emitter,
+ std::unique_ptr<MCAsmBackend> asmbackend, bool showInst)
+ : MCStreamer(Context), OSOwner(std::move(os)), OS(*OSOwner),
+ MAI(Context.getAsmInfo()), InstPrinter(printer),
+ Assembler(std::make_unique<MCAssembler>(
+ Context, std::move(asmbackend), std::move(emitter),
+ (asmbackend) ? asmbackend->createObjectWriter(NullStream)
+ : nullptr)),
+ CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm),
+ ShowInst(showInst), UseDwarfDirectory(useDwarfDirectory) {
+ assert(InstPrinter);
+ if (IsVerboseAsm)
+ InstPrinter->setCommentStream(CommentStream);
+ }
+
+ MCAssembler &getAssembler() { return *Assembler; }
+ MCAssembler *getAssemblerPtr() override { return nullptr; }
+
+ inline void EmitEOL() {
+ // Dump Explicit Comments here.
+ emitExplicitComments();
+ // If we don't have any comments, just emit a \n.
+ if (!IsVerboseAsm) {
+ OS << '\n';
+ return;
+ }
+ EmitCommentsAndEOL();
+ }
+
+ void EmitSyntaxDirective() override;
+
+ void EmitCommentsAndEOL();
+
+ /// Return true if this streamer supports verbose assembly at all.
+ bool isVerboseAsm() const override { return IsVerboseAsm; }
+
+ /// Do we support EmitRawText?
+ bool hasRawTextSupport() const override { return true; }
+
+ /// Add a comment that can be emitted to the generated .s file to make the
+ /// output of the compiler more readable. This only affects the MCAsmStreamer
+ /// and only when verbose assembly output is enabled.
+ void AddComment(const Twine &T, bool EOL = true) override;
+
+ /// Add a comment showing the encoding of an instruction.
+ void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &);
+
+ /// Return a raw_ostream that comments can be written to.
+ /// Unlike AddComment, you are required to terminate comments with \n if you
+ /// use this method.
+ raw_ostream &GetCommentOS() override {
+ if (!IsVerboseAsm)
+ return nulls(); // Discard comments unless in verbose asm mode.
+ return CommentStream;
+ }
+
+ void emitRawComment(const Twine &T, bool TabPrefix = true) override;
+
+ void addExplicitComment(const Twine &T) override;
+ void emitExplicitComments() override;
+
+ /// Emit a blank line to a .s file to pretty it up.
+ void AddBlankLine() override {
+ EmitEOL();
+ }
+
+ /// @name MCStreamer Interface
+ /// @{
+
+ void ChangeSection(MCSection *Section, const MCExpr *Subsection) override;
+
+ void emitELFSymverDirective(StringRef AliasName,
+ const MCSymbol *Aliasee) override;
+
+ void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override;
+ void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
+
+ void EmitAssemblerFlag(MCAssemblerFlag Flag) override;
+ void EmitLinkerOptions(ArrayRef<std::string> Options) override;
+ void EmitDataRegion(MCDataRegionType Kind) override;
+ void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,
+ unsigned Update, VersionTuple SDKVersion) override;
+ void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,
+ unsigned Update, VersionTuple SDKVersion) override;
+ void EmitThumbFunc(MCSymbol *Func) override;
+
+ void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
+ void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
+ bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+
+ void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;
+ void BeginCOFFSymbolDef(const MCSymbol *Symbol) override;
+ void EmitCOFFSymbolStorageClass(int StorageClass) override;
+ void EmitCOFFSymbolType(int Type) override;
+ void EndCOFFSymbolDef() override;
+ void EmitCOFFSafeSEH(MCSymbol const *Symbol) override;
+ void EmitCOFFSymbolIndex(MCSymbol const *Symbol) override;
+ void EmitCOFFSectionIndex(MCSymbol const *Symbol) override;
+ void EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) override;
+ void EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
+ void EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlign) override;
+ void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
+ void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) override;
+
+ /// Emit a local common (.lcomm) symbol.
+ ///
+ /// @param Symbol - The common symbol to emit.
+ /// @param Size - The size of the common symbol.
+ /// @param ByteAlignment - The alignment of the common symbol in bytes.
+ void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) override;
+
+ void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+ uint64_t Size = 0, unsigned ByteAlignment = 0,
+ SMLoc Loc = SMLoc()) override;
+
+ void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment = 0) override;
+
+ void EmitBinaryData(StringRef Data) override;
+
+ void EmitBytes(StringRef Data) override;
+
+ void EmitValueImpl(const MCExpr *Value, unsigned Size,
+ SMLoc Loc = SMLoc()) override;
+ void EmitIntValue(uint64_t Value, unsigned Size) override;
+ void EmitIntValueInHex(uint64_t Value, unsigned Size) override;
+
+ void EmitULEB128Value(const MCExpr *Value) override;
+
+ void EmitSLEB128Value(const MCExpr *Value) override;
+
+ void EmitDTPRel32Value(const MCExpr *Value) override;
+ void EmitDTPRel64Value(const MCExpr *Value) override;
+ void EmitTPRel32Value(const MCExpr *Value) override;
+ void EmitTPRel64Value(const MCExpr *Value) override;
+
+ void EmitGPRel64Value(const MCExpr *Value) override;
+
+ void EmitGPRel32Value(const MCExpr *Value) override;
+
+ void emitFill(const MCExpr &NumBytes, uint64_t FillValue,
+ SMLoc Loc = SMLoc()) override;
+
+ void emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
+ SMLoc Loc = SMLoc()) override;
+
+ void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0,
+ unsigned ValueSize = 1,
+ unsigned MaxBytesToEmit = 0) override;
+
+ void EmitCodeAlignment(unsigned ByteAlignment,
+ unsigned MaxBytesToEmit = 0) override;
+
+ void emitValueToOffset(const MCExpr *Offset,
+ unsigned char Value,
+ SMLoc Loc) override;
+
+ void EmitFileDirective(StringRef Filename) override;
+ Expected<unsigned> tryEmitDwarfFileDirective(unsigned FileNo,
+ StringRef Directory,
+ StringRef Filename,
+ Optional<MD5::MD5Result> Checksum = None,
+ Optional<StringRef> Source = None,
+ unsigned CUID = 0) override;
+ void emitDwarfFile0Directive(StringRef Directory, StringRef Filename,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ unsigned CUID = 0) override;
+ void EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
+ unsigned Column, unsigned Flags,
+ unsigned Isa, unsigned Discriminator,
+ StringRef FileName) override;
+ MCSymbol *getDwarfLineTableSymbol(unsigned CUID) override;
+
+ bool EmitCVFileDirective(unsigned FileNo, StringRef Filename,
+ ArrayRef<uint8_t> Checksum,
+ unsigned ChecksumKind) override;
+ bool EmitCVFuncIdDirective(unsigned FuncId) override;
+ bool EmitCVInlineSiteIdDirective(unsigned FunctionId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol, SMLoc Loc) override;
+ void EmitCVLocDirective(unsigned FunctionId, unsigned FileNo, unsigned Line,
+ unsigned Column, bool PrologueEnd, bool IsStmt,
+ StringRef FileName, SMLoc Loc) override;
+ void EmitCVLinetableDirective(unsigned FunctionId, const MCSymbol *FnStart,
+ const MCSymbol *FnEnd) override;
+ void EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) override;
+
+ void PrintCVDefRangePrefix(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges);
+
+ void EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeRegisterRelHeader DRHdr) override;
+
+ void EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeSubfieldRegisterHeader DRHdr) override;
+
+ void EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeRegisterHeader DRHdr) override;
+
+ void EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeFramePointerRelHeader DRHdr) override;
+
+ void EmitCVStringTableDirective() override;
+ void EmitCVFileChecksumsDirective() override;
+ void EmitCVFileChecksumOffsetDirective(unsigned FileNo) override;
+ void EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) override;
+
+ void EmitIdent(StringRef IdentString) override;
+ void EmitCFIBKeyFrame() override;
+ void EmitCFISections(bool EH, bool Debug) override;
+ void EmitCFIDefCfa(int64_t Register, int64_t Offset) override;
+ void EmitCFIDefCfaOffset(int64_t Offset) override;
+ void EmitCFIDefCfaRegister(int64_t Register) override;
+ void EmitCFIOffset(int64_t Register, int64_t Offset) override;
+ void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override;
+ void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) override;
+ void EmitCFIRememberState() override;
+ void EmitCFIRestoreState() override;
+ void EmitCFIRestore(int64_t Register) override;
+ void EmitCFISameValue(int64_t Register) override;
+ void EmitCFIRelOffset(int64_t Register, int64_t Offset) override;
+ void EmitCFIAdjustCfaOffset(int64_t Adjustment) override;
+ void EmitCFIEscape(StringRef Values) override;
+ void EmitCFIGnuArgsSize(int64_t Size) override;
+ void EmitCFISignalFrame() override;
+ void EmitCFIUndefined(int64_t Register) override;
+ void EmitCFIRegister(int64_t Register1, int64_t Register2) override;
+ void EmitCFIWindowSave() override;
+ void EmitCFINegateRAState() override;
+ void EmitCFIReturnColumn(int64_t Register) override;
+
+ void EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
+ void EmitWinCFIEndProc(SMLoc Loc) override;
+ void EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) override;
+ void EmitWinCFIStartChained(SMLoc Loc) override;
+ void EmitWinCFIEndChained(SMLoc Loc) override;
+ void EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) override;
+ void EmitWinCFISetFrame(MCRegister Register, unsigned Offset,
+ SMLoc Loc) override;
+ void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) override;
+ void EmitWinCFISaveReg(MCRegister Register, unsigned Offset,
+ SMLoc Loc) override;
+ void EmitWinCFISaveXMM(MCRegister Register, unsigned Offset,
+ SMLoc Loc) override;
+ void EmitWinCFIPushFrame(bool Code, SMLoc Loc) override;
+ void EmitWinCFIEndProlog(SMLoc Loc) override;
+
+ void EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
+ SMLoc Loc) override;
+ void EmitWinEHHandlerData(SMLoc Loc) override;
+
+ void emitCGProfileEntry(const MCSymbolRefExpr *From,
+ const MCSymbolRefExpr *To, uint64_t Count) override;
+
+ void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+
+ void EmitBundleAlignMode(unsigned AlignPow2) override;
+ void EmitBundleLock(bool AlignToEnd) override;
+ void EmitBundleUnlock() override;
+
+ bool EmitRelocDirective(const MCExpr &Offset, StringRef Name,
+ const MCExpr *Expr, SMLoc Loc,
+ const MCSubtargetInfo &STI) override;
+
+ void EmitAddrsig() override;
+ void EmitAddrsigSym(const MCSymbol *Sym) override;
+
+ /// If this file is backed by an assembly streamer, this dumps the specified
+ /// string in the output .s file. This capability is indicated by the
+ /// hasRawTextSupport() predicate.
+ void EmitRawTextImpl(StringRef String) override;
+
+ void FinishImpl() override;
+};
+
+} // end anonymous namespace.
+
+void MCAsmStreamer::AddComment(const Twine &T, bool EOL) {
+ if (!IsVerboseAsm) return;
+
+ T.toVector(CommentToEmit);
+
+ if (EOL)
+ CommentToEmit.push_back('\n'); // Place comment in a new line.
+}
+
+void MCAsmStreamer::EmitCommentsAndEOL() {
+ if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) {
+ OS << '\n';
+ return;
+ }
+
+ StringRef Comments = CommentToEmit;
+
+ assert(Comments.back() == '\n' &&
+ "Comment array not newline terminated");
+ do {
+ // Emit a line of comments.
+ OS.PadToColumn(MAI->getCommentColumn());
+ size_t Position = Comments.find('\n');
+ OS << MAI->getCommentString() << ' ' << Comments.substr(0, Position) <<'\n';
+
+ Comments = Comments.substr(Position+1);
+ } while (!Comments.empty());
+
+ CommentToEmit.clear();
+}
+
+static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) {
+ assert(Bytes > 0 && Bytes <= 8 && "Invalid size!");
+ return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8));
+}
+
+void MCAsmStreamer::emitRawComment(const Twine &T, bool TabPrefix) {
+ if (TabPrefix)
+ OS << '\t';
+ OS << MAI->getCommentString() << T;
+ EmitEOL();
+}
+
+void MCAsmStreamer::addExplicitComment(const Twine &T) {
+ StringRef c = T.getSingleStringRef();
+ if (c.equals(StringRef(MAI->getSeparatorString())))
+ return;
+ if (c.startswith(StringRef("//"))) {
+ ExplicitCommentToEmit.append("\t");
+ ExplicitCommentToEmit.append(MAI->getCommentString());
+ // drop //
+ ExplicitCommentToEmit.append(c.slice(2, c.size()).str());
+ } else if (c.startswith(StringRef("/*"))) {
+ size_t p = 2, len = c.size() - 2;
+ // emit each line in comment as separate newline.
+ do {
+ size_t newp = std::min(len, c.find_first_of("\r\n", p));
+ ExplicitCommentToEmit.append("\t");
+ ExplicitCommentToEmit.append(MAI->getCommentString());
+ ExplicitCommentToEmit.append(c.slice(p, newp).str());
+ // If we have another line in this comment add line
+ if (newp < len)
+ ExplicitCommentToEmit.append("\n");
+ p = newp + 1;
+ } while (p < len);
+ } else if (c.startswith(StringRef(MAI->getCommentString()))) {
+ ExplicitCommentToEmit.append("\t");
+ ExplicitCommentToEmit.append(c.str());
+ } else if (c.front() == '#') {
+
+ ExplicitCommentToEmit.append("\t");
+ ExplicitCommentToEmit.append(MAI->getCommentString());
+ ExplicitCommentToEmit.append(c.slice(1, c.size()).str());
+ } else
+ assert(false && "Unexpected Assembly Comment");
+ // full line comments immediately output
+ if (c.back() == '\n')
+ emitExplicitComments();
+}
+
+void MCAsmStreamer::emitExplicitComments() {
+ StringRef Comments = ExplicitCommentToEmit;
+ if (!Comments.empty())
+ OS << Comments;
+ ExplicitCommentToEmit.clear();
+}
+
+void MCAsmStreamer::ChangeSection(MCSection *Section,
+ const MCExpr *Subsection) {
+ assert(Section && "Cannot switch to a null section!");
+ if (MCTargetStreamer *TS = getTargetStreamer()) {
+ TS->changeSection(getCurrentSectionOnly(), Section, Subsection, OS);
+ } else {
+ Section->PrintSwitchToSection(
+ *MAI, getContext().getObjectFileInfo()->getTargetTriple(), OS,
+ Subsection);
+ }
+}
+
+void MCAsmStreamer::emitELFSymverDirective(StringRef AliasName,
+ const MCSymbol *Aliasee) {
+ OS << ".symver ";
+ Aliasee->print(OS, MAI);
+ OS << ", " << AliasName;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) {
+ MCStreamer::EmitLabel(Symbol, Loc);
+
+ Symbol->print(OS, MAI);
+ OS << MAI->getLabelSuffix();
+
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) {
+ StringRef str = MCLOHIdToName(Kind);
+
+#ifndef NDEBUG
+ int NbArgs = MCLOHIdToNbArgs(Kind);
+ assert(NbArgs != -1 && ((size_t)NbArgs) == Args.size() && "Malformed LOH!");
+ assert(str != "" && "Invalid LOH name");
+#endif
+
+ OS << "\t" << MCLOHDirectiveName() << " " << str << "\t";
+ bool IsFirst = true;
+ for (const MCSymbol *Arg : Args) {
+ if (!IsFirst)
+ OS << ", ";
+ IsFirst = false;
+ Arg->print(OS, MAI);
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
+ switch (Flag) {
+ case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break;
+ case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break;
+ case MCAF_Code16: OS << '\t'<< MAI->getCode16Directive();break;
+ case MCAF_Code32: OS << '\t'<< MAI->getCode32Directive();break;
+ case MCAF_Code64: OS << '\t'<< MAI->getCode64Directive();break;
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitLinkerOptions(ArrayRef<std::string> Options) {
+ assert(!Options.empty() && "At least one option is required!");
+ OS << "\t.linker_option \"" << Options[0] << '"';
+ for (ArrayRef<std::string>::iterator it = Options.begin() + 1,
+ ie = Options.end(); it != ie; ++it) {
+ OS << ", " << '"' << *it << '"';
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitDataRegion(MCDataRegionType Kind) {
+ if (!MAI->doesSupportDataRegionDirectives())
+ return;
+ switch (Kind) {
+ case MCDR_DataRegion: OS << "\t.data_region"; break;
+ case MCDR_DataRegionJT8: OS << "\t.data_region jt8"; break;
+ case MCDR_DataRegionJT16: OS << "\t.data_region jt16"; break;
+ case MCDR_DataRegionJT32: OS << "\t.data_region jt32"; break;
+ case MCDR_DataRegionEnd: OS << "\t.end_data_region"; break;
+ }
+ EmitEOL();
+}
+
+static const char *getVersionMinDirective(MCVersionMinType Type) {
+ switch (Type) {
+ case MCVM_WatchOSVersionMin: return ".watchos_version_min";
+ case MCVM_TvOSVersionMin: return ".tvos_version_min";
+ case MCVM_IOSVersionMin: return ".ios_version_min";
+ case MCVM_OSXVersionMin: return ".macosx_version_min";
+ }
+ llvm_unreachable("Invalid MC version min type");
+}
+
+static void EmitSDKVersionSuffix(raw_ostream &OS,
+ const VersionTuple &SDKVersion) {
+ if (SDKVersion.empty())
+ return;
+ OS << '\t' << "sdk_version " << SDKVersion.getMajor();
+ if (auto Minor = SDKVersion.getMinor()) {
+ OS << ", " << *Minor;
+ if (auto Subminor = SDKVersion.getSubminor()) {
+ OS << ", " << *Subminor;
+ }
+ }
+}
+
+void MCAsmStreamer::EmitVersionMin(MCVersionMinType Type, unsigned Major,
+ unsigned Minor, unsigned Update,
+ VersionTuple SDKVersion) {
+ OS << '\t' << getVersionMinDirective(Type) << ' ' << Major << ", " << Minor;
+ if (Update)
+ OS << ", " << Update;
+ EmitSDKVersionSuffix(OS, SDKVersion);
+ EmitEOL();
+}
+
+static const char *getPlatformName(MachO::PlatformType Type) {
+ switch (Type) {
+ case MachO::PLATFORM_MACOS: return "macos";
+ case MachO::PLATFORM_IOS: return "ios";
+ case MachO::PLATFORM_TVOS: return "tvos";
+ case MachO::PLATFORM_WATCHOS: return "watchos";
+ case MachO::PLATFORM_BRIDGEOS: return "bridgeos";
+ case MachO::PLATFORM_MACCATALYST: return "macCatalyst";
+ case MachO::PLATFORM_IOSSIMULATOR: return "iossimulator";
+ case MachO::PLATFORM_TVOSSIMULATOR: return "tvossimulator";
+ case MachO::PLATFORM_WATCHOSSIMULATOR: return "watchossimulator";
+ }
+ llvm_unreachable("Invalid Mach-O platform type");
+}
+
+void MCAsmStreamer::EmitBuildVersion(unsigned Platform, unsigned Major,
+ unsigned Minor, unsigned Update,
+ VersionTuple SDKVersion) {
+ const char *PlatformName = getPlatformName((MachO::PlatformType)Platform);
+ OS << "\t.build_version " << PlatformName << ", " << Major << ", " << Minor;
+ if (Update)
+ OS << ", " << Update;
+ EmitSDKVersionSuffix(OS, SDKVersion);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) {
+ // This needs to emit to a temporary string to get properly quoted
+ // MCSymbols when they have spaces in them.
+ OS << "\t.thumb_func";
+ // Only Mach-O hasSubsectionsViaSymbols()
+ if (MAI->hasSubsectionsViaSymbols()) {
+ OS << '\t';
+ Func->print(OS, MAI);
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ // Do not emit a .set on inlined target assignments.
+ bool EmitSet = true;
+ if (auto *E = dyn_cast<MCTargetExpr>(Value))
+ if (E->inlineAssignedExpr())
+ EmitSet = false;
+ if (EmitSet) {
+ OS << ".set ";
+ Symbol->print(OS, MAI);
+ OS << ", ";
+ Value->print(OS, MAI);
+
+ EmitEOL();
+ }
+
+ MCStreamer::EmitAssignment(Symbol, Value);
+}
+
+void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {
+ OS << ".weakref ";
+ Alias->print(OS, MAI);
+ OS << ", ";
+ Symbol->print(OS, MAI);
+ EmitEOL();
+}
+
+bool MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
+ MCSymbolAttr Attribute) {
+ switch (Attribute) {
+ case MCSA_Invalid: llvm_unreachable("Invalid symbol attribute");
+ case MCSA_ELF_TypeFunction: /// .type _foo, STT_FUNC # aka @function
+ case MCSA_ELF_TypeIndFunction: /// .type _foo, STT_GNU_IFUNC
+ case MCSA_ELF_TypeObject: /// .type _foo, STT_OBJECT # aka @object
+ case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object
+ case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common
+ case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype
+ case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object
+ if (!MAI->hasDotTypeDotSizeDirective())
+ return false; // Symbol attribute not supported
+ OS << "\t.type\t";
+ Symbol->print(OS, MAI);
+ OS << ',' << ((MAI->getCommentString()[0] != '@') ? '@' : '%');
+ switch (Attribute) {
+ default: return false;
+ case MCSA_ELF_TypeFunction: OS << "function"; break;
+ case MCSA_ELF_TypeIndFunction: OS << "gnu_indirect_function"; break;
+ case MCSA_ELF_TypeObject: OS << "object"; break;
+ case MCSA_ELF_TypeTLS: OS << "tls_object"; break;
+ case MCSA_ELF_TypeCommon: OS << "common"; break;
+ case MCSA_ELF_TypeNoType: OS << "notype"; break;
+ case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break;
+ }
+ EmitEOL();
+ return true;
+ case MCSA_Global: // .globl/.global
+ OS << MAI->getGlobalDirective();
+ break;
+ case MCSA_LGlobal: OS << "\t.lglobl\t"; break;
+ case MCSA_Hidden: OS << "\t.hidden\t"; break;
+ case MCSA_IndirectSymbol: OS << "\t.indirect_symbol\t"; break;
+ case MCSA_Internal: OS << "\t.internal\t"; break;
+ case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break;
+ case MCSA_Local: OS << "\t.local\t"; break;
+ case MCSA_NoDeadStrip:
+ if (!MAI->hasNoDeadStrip())
+ return false;
+ OS << "\t.no_dead_strip\t";
+ break;
+ case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break;
+ case MCSA_AltEntry: OS << "\t.alt_entry\t"; break;
+ case MCSA_PrivateExtern:
+ OS << "\t.private_extern\t";
+ break;
+ case MCSA_Protected: OS << "\t.protected\t"; break;
+ case MCSA_Reference: OS << "\t.reference\t"; break;
+ case MCSA_Weak: OS << MAI->getWeakDirective(); break;
+ case MCSA_WeakDefinition:
+ OS << "\t.weak_definition\t";
+ break;
+ // .weak_reference
+ case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break;
+ case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break;
+ case MCSA_Cold:
+ // Assemblers currently do not support a .cold directive.
+ return false;
+ }
+
+ Symbol->print(OS, MAI);
+ EmitEOL();
+
+ return true;
+}
+
+void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
+ OS << ".desc" << ' ';
+ Symbol->print(OS, MAI);
+ OS << ',' << DescValue;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitSyntaxDirective() {
+ if (MAI->getAssemblerDialect() == 1) {
+ OS << "\t.intel_syntax noprefix";
+ EmitEOL();
+ }
+ // FIXME: Currently emit unprefix'ed registers.
+ // The intel_syntax directive has one optional argument
+ // with may have a value of prefix or noprefix.
+}
+
+void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) {
+ OS << "\t.def\t ";
+ Symbol->print(OS, MAI);
+ OS << ';';
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSymbolStorageClass (int StorageClass) {
+ OS << "\t.scl\t" << StorageClass << ';';
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSymbolType (int Type) {
+ OS << "\t.type\t" << Type << ';';
+ EmitEOL();
+}
+
+void MCAsmStreamer::EndCOFFSymbolDef() {
+ OS << "\t.endef";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) {
+ OS << "\t.safeseh\t";
+ Symbol->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) {
+ OS << "\t.symidx\t";
+ Symbol->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {
+ OS << "\t.secidx\t";
+ Symbol->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {
+ OS << "\t.secrel32\t";
+ Symbol->print(OS, MAI);
+ if (Offset != 0)
+ OS << '+' << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {
+ OS << "\t.rva\t";
+ Symbol->print(OS, MAI);
+ if (Offset > 0)
+ OS << '+' << Offset;
+ else if (Offset < 0)
+ OS << '-' << -Offset;
+ EmitEOL();
+}
+
+// We need an XCOFF-specific version of this directive as the AIX syntax
+// requires a QualName argument identifying the csect name and storage mapping
+// class to appear before the alignment if we are specifying it.
+void MCAsmStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ assert(MAI->getLCOMMDirectiveAlignmentType() == LCOMM::Log2Alignment &&
+ "We only support writing log base-2 alignment format with XCOFF.");
+ assert(isPowerOf2_32(ByteAlignment) && "Alignment must be a power of 2.");
+
+ OS << "\t.lcomm\t";
+ Symbol->print(OS, MAI);
+ OS << ',' << Size;
+ OS << ',' << Symbol->getName();
+ OS << ',' << Log2_32(ByteAlignment);
+
+ EmitEOL();
+}
+
+void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
+ assert(MAI->hasDotTypeDotSizeDirective());
+ OS << "\t.size\t";
+ Symbol->print(OS, MAI);
+ OS << ", ";
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ OS << "\t.comm\t";
+ Symbol->print(OS, MAI);
+ OS << ',' << Size;
+
+ if (ByteAlignment != 0) {
+ if (MAI->getCOMMDirectiveAlignmentIsInBytes())
+ OS << ',' << ByteAlignment;
+ else
+ OS << ',' << Log2_32(ByteAlignment);
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlign) {
+ OS << "\t.lcomm\t";
+ Symbol->print(OS, MAI);
+ OS << ',' << Size;
+
+ if (ByteAlign > 1) {
+ switch (MAI->getLCOMMDirectiveAlignmentType()) {
+ case LCOMM::NoAlignment:
+ llvm_unreachable("alignment not supported on .lcomm!");
+ case LCOMM::ByteAlignment:
+ OS << ',' << ByteAlign;
+ break;
+ case LCOMM::Log2Alignment:
+ assert(isPowerOf2_32(ByteAlign) && "alignment must be a power of 2");
+ OS << ',' << Log2_32(ByteAlign);
+ break;
+ }
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment,
+ SMLoc Loc) {
+ if (Symbol)
+ AssignFragment(Symbol, &Section->getDummyFragment());
+
+ // Note: a .zerofill directive does not switch sections.
+ OS << ".zerofill ";
+
+ assert(Section->getVariant() == MCSection::SV_MachO &&
+ ".zerofill is a Mach-O specific directive");
+ // This is a mach-o specific directive.
+
+ const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section);
+ OS << MOSection->getSegmentName() << "," << MOSection->getSectionName();
+
+ if (Symbol) {
+ OS << ',';
+ Symbol->print(OS, MAI);
+ OS << ',' << Size;
+ if (ByteAlignment != 0)
+ OS << ',' << Log2_32(ByteAlignment);
+ }
+ EmitEOL();
+}
+
+// .tbss sym, size, align
+// This depends that the symbol has already been mangled from the original,
+// e.g. _a.
+void MCAsmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ AssignFragment(Symbol, &Section->getDummyFragment());
+
+ assert(Symbol && "Symbol shouldn't be NULL!");
+ // Instead of using the Section we'll just use the shortcut.
+
+ assert(Section->getVariant() == MCSection::SV_MachO &&
+ ".zerofill is a Mach-O specific directive");
+ // This is a mach-o specific directive and section.
+
+ OS << ".tbss ";
+ Symbol->print(OS, MAI);
+ OS << ", " << Size;
+
+ // Output align if we have it. We default to 1 so don't bother printing
+ // that.
+ if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment);
+
+ EmitEOL();
+}
+
+static inline char toOctal(int X) { return (X&7)+'0'; }
+
+static void PrintQuotedString(StringRef Data, raw_ostream &OS) {
+ OS << '"';
+
+ for (unsigned i = 0, e = Data.size(); i != e; ++i) {
+ unsigned char C = Data[i];
+ if (C == '"' || C == '\\') {
+ OS << '\\' << (char)C;
+ continue;
+ }
+
+ if (isPrint((unsigned char)C)) {
+ OS << (char)C;
+ continue;
+ }
+
+ switch (C) {
+ case '\b': OS << "\\b"; break;
+ case '\f': OS << "\\f"; break;
+ case '\n': OS << "\\n"; break;
+ case '\r': OS << "\\r"; break;
+ case '\t': OS << "\\t"; break;
+ default:
+ OS << '\\';
+ OS << toOctal(C >> 6);
+ OS << toOctal(C >> 3);
+ OS << toOctal(C >> 0);
+ break;
+ }
+ }
+
+ OS << '"';
+}
+
+void MCAsmStreamer::EmitBytes(StringRef Data) {
+ assert(getCurrentSectionOnly() &&
+ "Cannot emit contents before setting section!");
+ if (Data.empty()) return;
+
+ // If only single byte is provided or no ascii or asciz directives is
+ // supported, emit as vector of 8bits data.
+ if (Data.size() == 1 ||
+ !(MAI->getAscizDirective() || MAI->getAsciiDirective())) {
+ if (MCTargetStreamer *TS = getTargetStreamer()) {
+ TS->emitRawBytes(Data);
+ } else {
+ const char *Directive = MAI->getData8bitsDirective();
+ for (const unsigned char C : Data.bytes()) {
+ OS << Directive << (unsigned)C;
+ EmitEOL();
+ }
+ }
+ return;
+ }
+
+ // If the data ends with 0 and the target supports .asciz, use it, otherwise
+ // use .ascii
+ if (MAI->getAscizDirective() && Data.back() == 0) {
+ OS << MAI->getAscizDirective();
+ Data = Data.substr(0, Data.size()-1);
+ } else {
+ OS << MAI->getAsciiDirective();
+ }
+
+ PrintQuotedString(Data, OS);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitBinaryData(StringRef Data) {
+ // This is binary data. Print it in a grid of hex bytes for readability.
+ const size_t Cols = 4;
+ for (size_t I = 0, EI = alignTo(Data.size(), Cols); I < EI; I += Cols) {
+ size_t J = I, EJ = std::min(I + Cols, Data.size());
+ assert(EJ > 0);
+ OS << MAI->getData8bitsDirective();
+ for (; J < EJ - 1; ++J)
+ OS << format("0x%02x", uint8_t(Data[J])) << ", ";
+ OS << format("0x%02x", uint8_t(Data[J]));
+ EmitEOL();
+ }
+}
+
+void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size) {
+ EmitValue(MCConstantExpr::create(Value, getContext()), Size);
+}
+
+void MCAsmStreamer::EmitIntValueInHex(uint64_t Value, unsigned Size) {
+ EmitValue(MCConstantExpr::create(Value, getContext(), true), Size);
+}
+
+void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
+ SMLoc Loc) {
+ assert(Size <= 8 && "Invalid size");
+ assert(getCurrentSectionOnly() &&
+ "Cannot emit contents before setting section!");
+ const char *Directive = nullptr;
+ switch (Size) {
+ default: break;
+ case 1: Directive = MAI->getData8bitsDirective(); break;
+ case 2: Directive = MAI->getData16bitsDirective(); break;
+ case 4: Directive = MAI->getData32bitsDirective(); break;
+ case 8: Directive = MAI->getData64bitsDirective(); break;
+ }
+
+ if (!Directive) {
+ int64_t IntValue;
+ if (!Value->evaluateAsAbsolute(IntValue))
+ report_fatal_error("Don't know how to emit this value.");
+
+ // We couldn't handle the requested integer size so we fallback by breaking
+ // the request down into several, smaller, integers.
+ // Since sizes greater or equal to "Size" are invalid, we use the greatest
+ // power of 2 that is less than "Size" as our largest piece of granularity.
+ bool IsLittleEndian = MAI->isLittleEndian();
+ for (unsigned Emitted = 0; Emitted != Size;) {
+ unsigned Remaining = Size - Emitted;
+ // The size of our partial emission must be a power of two less than
+ // Size.
+ unsigned EmissionSize = PowerOf2Floor(std::min(Remaining, Size - 1));
+ // Calculate the byte offset of our partial emission taking into account
+ // the endianness of the target.
+ unsigned ByteOffset =
+ IsLittleEndian ? Emitted : (Remaining - EmissionSize);
+ uint64_t ValueToEmit = IntValue >> (ByteOffset * 8);
+ // We truncate our partial emission to fit within the bounds of the
+ // emission domain. This produces nicer output and silences potential
+ // truncation warnings when round tripping through another assembler.
+ uint64_t Shift = 64 - EmissionSize * 8;
+ assert(Shift < static_cast<uint64_t>(
+ std::numeric_limits<unsigned long long>::digits) &&
+ "undefined behavior");
+ ValueToEmit &= ~0ULL >> Shift;
+ EmitIntValue(ValueToEmit, EmissionSize);
+ Emitted += EmissionSize;
+ }
+ return;
+ }
+
+ assert(Directive && "Invalid size for machine code value!");
+ OS << Directive;
+ if (MCTargetStreamer *TS = getTargetStreamer()) {
+ TS->emitValue(Value);
+ } else {
+ Value->print(OS, MAI);
+ EmitEOL();
+ }
+}
+
+void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) {
+ int64_t IntValue;
+ if (Value->evaluateAsAbsolute(IntValue)) {
+ EmitULEB128IntValue(IntValue);
+ return;
+ }
+ OS << "\t.uleb128 ";
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) {
+ int64_t IntValue;
+ if (Value->evaluateAsAbsolute(IntValue)) {
+ EmitSLEB128IntValue(IntValue);
+ return;
+ }
+ OS << "\t.sleb128 ";
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitDTPRel64Value(const MCExpr *Value) {
+ assert(MAI->getDTPRel64Directive() != nullptr);
+ OS << MAI->getDTPRel64Directive();
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitDTPRel32Value(const MCExpr *Value) {
+ assert(MAI->getDTPRel32Directive() != nullptr);
+ OS << MAI->getDTPRel32Directive();
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitTPRel64Value(const MCExpr *Value) {
+ assert(MAI->getTPRel64Directive() != nullptr);
+ OS << MAI->getTPRel64Directive();
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitTPRel32Value(const MCExpr *Value) {
+ assert(MAI->getTPRel32Directive() != nullptr);
+ OS << MAI->getTPRel32Directive();
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) {
+ assert(MAI->getGPRel64Directive() != nullptr);
+ OS << MAI->getGPRel64Directive();
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) {
+ assert(MAI->getGPRel32Directive() != nullptr);
+ OS << MAI->getGPRel32Directive();
+ Value->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::emitFill(const MCExpr &NumBytes, uint64_t FillValue,
+ SMLoc Loc) {
+ int64_t IntNumBytes;
+ if (NumBytes.evaluateAsAbsolute(IntNumBytes) && IntNumBytes == 0)
+ return;
+
+ if (const char *ZeroDirective = MAI->getZeroDirective()) {
+ // FIXME: Emit location directives
+ OS << ZeroDirective;
+ NumBytes.print(OS, MAI);
+ if (FillValue != 0)
+ OS << ',' << (int)FillValue;
+ EmitEOL();
+ return;
+ }
+
+ MCStreamer::emitFill(NumBytes, FillValue);
+}
+
+void MCAsmStreamer::emitFill(const MCExpr &NumValues, int64_t Size,
+ int64_t Expr, SMLoc Loc) {
+ // FIXME: Emit location directives
+ OS << "\t.fill\t";
+ NumValues.print(OS, MAI);
+ OS << ", " << Size << ", 0x";
+ OS.write_hex(truncateToSize(Expr, 4));
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ if (MAI->useDotAlignForAlignment()) {
+ if (!isPowerOf2_32(ByteAlignment))
+ report_fatal_error("Only power-of-two alignments are supported "
+ "with .align.");
+ OS << "\t.align\t";
+ OS << Log2_32(ByteAlignment);
+ EmitEOL();
+ return;
+ }
+
+ // Some assemblers don't support non-power of two alignments, so we always
+ // emit alignments as a power of two if possible.
+ if (isPowerOf2_32(ByteAlignment)) {
+ switch (ValueSize) {
+ default:
+ llvm_unreachable("Invalid size for machine code value!");
+ case 1:
+ OS << "\t.p2align\t";
+ break;
+ case 2:
+ OS << ".p2alignw ";
+ break;
+ case 4:
+ OS << ".p2alignl ";
+ break;
+ case 8:
+ llvm_unreachable("Unsupported alignment size!");
+ }
+
+ OS << Log2_32(ByteAlignment);
+
+ if (Value || MaxBytesToEmit) {
+ OS << ", 0x";
+ OS.write_hex(truncateToSize(Value, ValueSize));
+
+ if (MaxBytesToEmit)
+ OS << ", " << MaxBytesToEmit;
+ }
+ EmitEOL();
+ return;
+ }
+
+ // Non-power of two alignment. This is not widely supported by assemblers.
+ // FIXME: Parameterize this based on MAI.
+ switch (ValueSize) {
+ default: llvm_unreachable("Invalid size for machine code value!");
+ case 1: OS << ".balign"; break;
+ case 2: OS << ".balignw"; break;
+ case 4: OS << ".balignl"; break;
+ case 8: llvm_unreachable("Unsupported alignment size!");
+ }
+
+ OS << ' ' << ByteAlignment;
+ OS << ", " << truncateToSize(Value, ValueSize);
+ if (MaxBytesToEmit)
+ OS << ", " << MaxBytesToEmit;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment,
+ unsigned MaxBytesToEmit) {
+ // Emit with a text fill value.
+ EmitValueToAlignment(ByteAlignment, MAI->getTextAlignFillValue(),
+ 1, MaxBytesToEmit);
+}
+
+void MCAsmStreamer::emitValueToOffset(const MCExpr *Offset,
+ unsigned char Value,
+ SMLoc Loc) {
+ // FIXME: Verify that Offset is associated with the current section.
+ OS << ".org ";
+ Offset->print(OS, MAI);
+ OS << ", " << (unsigned)Value;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitFileDirective(StringRef Filename) {
+ assert(MAI->hasSingleParameterDotFile());
+ OS << "\t.file\t";
+ PrintQuotedString(Filename, OS);
+ EmitEOL();
+}
+
+static void printDwarfFileDirective(unsigned FileNo, StringRef Directory,
+ StringRef Filename,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ bool UseDwarfDirectory,
+ raw_svector_ostream &OS) {
+ SmallString<128> FullPathName;
+
+ if (!UseDwarfDirectory && !Directory.empty()) {
+ if (sys::path::is_absolute(Filename))
+ Directory = "";
+ else {
+ FullPathName = Directory;
+ sys::path::append(FullPathName, Filename);
+ Directory = "";
+ Filename = FullPathName;
+ }
+ }
+
+ OS << "\t.file\t" << FileNo << ' ';
+ if (!Directory.empty()) {
+ PrintQuotedString(Directory, OS);
+ OS << ' ';
+ }
+ PrintQuotedString(Filename, OS);
+ if (Checksum)
+ OS << " md5 0x" << Checksum->digest();
+ if (Source) {
+ OS << " source ";
+ PrintQuotedString(*Source, OS);
+ }
+}
+
+Expected<unsigned> MCAsmStreamer::tryEmitDwarfFileDirective(
+ unsigned FileNo, StringRef Directory, StringRef Filename,
+ Optional<MD5::MD5Result> Checksum, Optional<StringRef> Source, unsigned CUID) {
+ assert(CUID == 0 && "multiple CUs not supported by MCAsmStreamer");
+
+ MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
+ unsigned NumFiles = Table.getMCDwarfFiles().size();
+ Expected<unsigned> FileNoOrErr =
+ Table.tryGetFile(Directory, Filename, Checksum, Source,
+ getContext().getDwarfVersion(), FileNo);
+ if (!FileNoOrErr)
+ return FileNoOrErr.takeError();
+ FileNo = FileNoOrErr.get();
+ if (NumFiles == Table.getMCDwarfFiles().size())
+ return FileNo;
+
+ SmallString<128> Str;
+ raw_svector_ostream OS1(Str);
+ printDwarfFileDirective(FileNo, Directory, Filename, Checksum, Source,
+ UseDwarfDirectory, OS1);
+
+ if (MCTargetStreamer *TS = getTargetStreamer())
+ TS->emitDwarfFileDirective(OS1.str());
+ else
+ EmitRawText(OS1.str());
+
+ return FileNo;
+}
+
+void MCAsmStreamer::emitDwarfFile0Directive(StringRef Directory,
+ StringRef Filename,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ unsigned CUID) {
+ assert(CUID == 0);
+ // .file 0 is new for DWARF v5.
+ if (getContext().getDwarfVersion() < 5)
+ return;
+ // Inform MCDwarf about the root file.
+ getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,
+ Source);
+
+ SmallString<128> Str;
+ raw_svector_ostream OS1(Str);
+ printDwarfFileDirective(0, Directory, Filename, Checksum, Source,
+ UseDwarfDirectory, OS1);
+
+ if (MCTargetStreamer *TS = getTargetStreamer())
+ TS->emitDwarfFileDirective(OS1.str());
+ else
+ EmitRawText(OS1.str());
+}
+
+void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
+ unsigned Column, unsigned Flags,
+ unsigned Isa,
+ unsigned Discriminator,
+ StringRef FileName) {
+ OS << "\t.loc\t" << FileNo << " " << Line << " " << Column;
+ if (MAI->supportsExtendedDwarfLocDirective()) {
+ if (Flags & DWARF2_FLAG_BASIC_BLOCK)
+ OS << " basic_block";
+ if (Flags & DWARF2_FLAG_PROLOGUE_END)
+ OS << " prologue_end";
+ if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN)
+ OS << " epilogue_begin";
+
+ unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags();
+ if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) {
+ OS << " is_stmt ";
+
+ if (Flags & DWARF2_FLAG_IS_STMT)
+ OS << "1";
+ else
+ OS << "0";
+ }
+
+ if (Isa)
+ OS << " isa " << Isa;
+ if (Discriminator)
+ OS << " discriminator " << Discriminator;
+ }
+
+ if (IsVerboseAsm) {
+ OS.PadToColumn(MAI->getCommentColumn());
+ OS << MAI->getCommentString() << ' ' << FileName << ':'
+ << Line << ':' << Column;
+ }
+ EmitEOL();
+ this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags,
+ Isa, Discriminator, FileName);
+}
+
+MCSymbol *MCAsmStreamer::getDwarfLineTableSymbol(unsigned CUID) {
+ // Always use the zeroth line table, since asm syntax only supports one line
+ // table for now.
+ return MCStreamer::getDwarfLineTableSymbol(0);
+}
+
+bool MCAsmStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename,
+ ArrayRef<uint8_t> Checksum,
+ unsigned ChecksumKind) {
+ if (!getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum,
+ ChecksumKind))
+ return false;
+
+ OS << "\t.cv_file\t" << FileNo << ' ';
+ PrintQuotedString(Filename, OS);
+
+ if (!ChecksumKind) {
+ EmitEOL();
+ return true;
+ }
+
+ OS << ' ';
+ PrintQuotedString(toHex(Checksum), OS);
+ OS << ' ' << ChecksumKind;
+
+ EmitEOL();
+ return true;
+}
+
+bool MCAsmStreamer::EmitCVFuncIdDirective(unsigned FuncId) {
+ OS << "\t.cv_func_id " << FuncId << '\n';
+ return MCStreamer::EmitCVFuncIdDirective(FuncId);
+}
+
+bool MCAsmStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId,
+ unsigned IAFunc,
+ unsigned IAFile,
+ unsigned IALine, unsigned IACol,
+ SMLoc Loc) {
+ OS << "\t.cv_inline_site_id " << FunctionId << " within " << IAFunc
+ << " inlined_at " << IAFile << ' ' << IALine << ' ' << IACol << '\n';
+ return MCStreamer::EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
+ IALine, IACol, Loc);
+}
+
+void MCAsmStreamer::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;
+
+ OS << "\t.cv_loc\t" << FunctionId << " " << FileNo << " " << Line << " "
+ << Column;
+ if (PrologueEnd)
+ OS << " prologue_end";
+
+ if (IsStmt)
+ OS << " is_stmt 1";
+
+ if (IsVerboseAsm) {
+ OS.PadToColumn(MAI->getCommentColumn());
+ OS << MAI->getCommentString() << ' ' << FileName << ':' << Line << ':'
+ << Column;
+ }
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVLinetableDirective(unsigned FunctionId,
+ const MCSymbol *FnStart,
+ const MCSymbol *FnEnd) {
+ OS << "\t.cv_linetable\t" << FunctionId << ", ";
+ FnStart->print(OS, MAI);
+ OS << ", ";
+ FnEnd->print(OS, MAI);
+ EmitEOL();
+ this->MCStreamer::EmitCVLinetableDirective(FunctionId, FnStart, FnEnd);
+}
+
+void MCAsmStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {
+ OS << "\t.cv_inline_linetable\t" << PrimaryFunctionId << ' ' << SourceFileId
+ << ' ' << SourceLineNum << ' ';
+ FnStartSym->print(OS, MAI);
+ OS << ' ';
+ FnEndSym->print(OS, MAI);
+ EmitEOL();
+ this->MCStreamer::EmitCVInlineLinetableDirective(
+ PrimaryFunctionId, SourceFileId, SourceLineNum, FnStartSym, FnEndSym);
+}
+
+void MCAsmStreamer::PrintCVDefRangePrefix(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges) {
+ OS << "\t.cv_def_range\t";
+ for (std::pair<const MCSymbol *, const MCSymbol *> Range : Ranges) {
+ OS << ' ';
+ Range.first->print(OS, MAI);
+ OS << ' ';
+ Range.second->print(OS, MAI);
+ }
+}
+
+void MCAsmStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeRegisterRelHeader DRHdr) {
+ PrintCVDefRangePrefix(Ranges);
+ OS << ", reg_rel, ";
+ OS << DRHdr.Register << ", " << DRHdr.Flags << ", "
+ << DRHdr.BasePointerOffset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeSubfieldRegisterHeader DRHdr) {
+ PrintCVDefRangePrefix(Ranges);
+ OS << ", subfield_reg, ";
+ OS << DRHdr.Register << ", " << DRHdr.OffsetInParent;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeRegisterHeader DRHdr) {
+ PrintCVDefRangePrefix(Ranges);
+ OS << ", reg, ";
+ OS << DRHdr.Register;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeFramePointerRelHeader DRHdr) {
+ PrintCVDefRangePrefix(Ranges);
+ OS << ", frame_ptr_rel, ";
+ OS << DRHdr.Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVStringTableDirective() {
+ OS << "\t.cv_stringtable";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVFileChecksumsDirective() {
+ OS << "\t.cv_filechecksums";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVFileChecksumOffsetDirective(unsigned FileNo) {
+ OS << "\t.cv_filechecksumoffset\t" << FileNo;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCVFPOData(const MCSymbol *ProcSym, SMLoc L) {
+ OS << "\t.cv_fpo_data\t";
+ ProcSym->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitIdent(StringRef IdentString) {
+ assert(MAI->hasIdentDirective() && ".ident directive not supported");
+ OS << "\t.ident\t";
+ PrintQuotedString(IdentString, OS);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFISections(bool EH, bool Debug) {
+ MCStreamer::EmitCFISections(EH, Debug);
+ OS << "\t.cfi_sections ";
+ if (EH) {
+ OS << ".eh_frame";
+ if (Debug)
+ OS << ", .debug_frame";
+ } else if (Debug) {
+ OS << ".debug_frame";
+ }
+
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+ OS << "\t.cfi_startproc";
+ if (Frame.IsSimple)
+ OS << " simple";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
+ MCStreamer::EmitCFIEndProcImpl(Frame);
+ OS << "\t.cfi_endproc";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitRegisterName(int64_t Register) {
+ if (!MAI->useDwarfRegNumForCFI()) {
+ // User .cfi_* directives can use arbitrary DWARF register numbers, not
+ // just ones that map to LLVM register numbers and have known names.
+ // Fall back to using the original number directly if no name is known.
+ const MCRegisterInfo *MRI = getContext().getRegisterInfo();
+ if (Optional<unsigned> LLVMRegister = MRI->getLLVMRegNum(Register, true)) {
+ InstPrinter->printRegName(OS, *LLVMRegister);
+ return;
+ }
+ }
+ OS << Register;
+}
+
+void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) {
+ MCStreamer::EmitCFIDefCfa(Register, Offset);
+ OS << "\t.cfi_def_cfa ";
+ EmitRegisterName(Register);
+ OS << ", " << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) {
+ MCStreamer::EmitCFIDefCfaOffset(Offset);
+ OS << "\t.cfi_def_cfa_offset " << Offset;
+ EmitEOL();
+}
+
+static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) {
+ OS << "\t.cfi_escape ";
+ if (!Values.empty()) {
+ size_t e = Values.size() - 1;
+ for (size_t i = 0; i < e; ++i)
+ OS << format("0x%02x", uint8_t(Values[i])) << ", ";
+ OS << format("0x%02x", uint8_t(Values[e]));
+ }
+}
+
+void MCAsmStreamer::EmitCFIEscape(StringRef Values) {
+ MCStreamer::EmitCFIEscape(Values);
+ PrintCFIEscape(OS, Values);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIGnuArgsSize(int64_t Size) {
+ MCStreamer::EmitCFIGnuArgsSize(Size);
+
+ uint8_t Buffer[16] = { dwarf::DW_CFA_GNU_args_size };
+ unsigned Len = encodeULEB128(Size, Buffer + 1) + 1;
+
+ PrintCFIEscape(OS, StringRef((const char *)&Buffer[0], Len));
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) {
+ MCStreamer::EmitCFIDefCfaRegister(Register);
+ OS << "\t.cfi_def_cfa_register ";
+ EmitRegisterName(Register);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) {
+ this->MCStreamer::EmitCFIOffset(Register, Offset);
+ OS << "\t.cfi_offset ";
+ EmitRegisterName(Register);
+ OS << ", " << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym,
+ unsigned Encoding) {
+ MCStreamer::EmitCFIPersonality(Sym, Encoding);
+ OS << "\t.cfi_personality " << Encoding << ", ";
+ Sym->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
+ MCStreamer::EmitCFILsda(Sym, Encoding);
+ OS << "\t.cfi_lsda " << Encoding << ", ";
+ Sym->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIRememberState() {
+ MCStreamer::EmitCFIRememberState();
+ OS << "\t.cfi_remember_state";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIRestoreState() {
+ MCStreamer::EmitCFIRestoreState();
+ OS << "\t.cfi_restore_state";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIRestore(int64_t Register) {
+ MCStreamer::EmitCFIRestore(Register);
+ OS << "\t.cfi_restore ";
+ EmitRegisterName(Register);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFISameValue(int64_t Register) {
+ MCStreamer::EmitCFISameValue(Register);
+ OS << "\t.cfi_same_value ";
+ EmitRegisterName(Register);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) {
+ MCStreamer::EmitCFIRelOffset(Register, Offset);
+ OS << "\t.cfi_rel_offset ";
+ EmitRegisterName(Register);
+ OS << ", " << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) {
+ MCStreamer::EmitCFIAdjustCfaOffset(Adjustment);
+ OS << "\t.cfi_adjust_cfa_offset " << Adjustment;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFISignalFrame() {
+ MCStreamer::EmitCFISignalFrame();
+ OS << "\t.cfi_signal_frame";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIUndefined(int64_t Register) {
+ MCStreamer::EmitCFIUndefined(Register);
+ OS << "\t.cfi_undefined " << Register;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) {
+ MCStreamer::EmitCFIRegister(Register1, Register2);
+ OS << "\t.cfi_register " << Register1 << ", " << Register2;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIWindowSave() {
+ MCStreamer::EmitCFIWindowSave();
+ OS << "\t.cfi_window_save";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFINegateRAState() {
+ MCStreamer::EmitCFINegateRAState();
+ OS << "\t.cfi_negate_ra_state";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIReturnColumn(int64_t Register) {
+ MCStreamer::EmitCFIReturnColumn(Register);
+ OS << "\t.cfi_return_column " << Register;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitCFIBKeyFrame() {
+ MCStreamer::EmitCFIBKeyFrame();
+ OS << "\t.cfi_b_key_frame";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
+ MCStreamer::EmitWinCFIStartProc(Symbol, Loc);
+
+ OS << ".seh_proc ";
+ Symbol->print(OS, MAI);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIEndProc(SMLoc Loc) {
+ MCStreamer::EmitWinCFIEndProc(Loc);
+
+ OS << "\t.seh_endproc";
+ EmitEOL();
+}
+
+// TODO: Implement
+void MCAsmStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
+}
+
+void MCAsmStreamer::EmitWinCFIStartChained(SMLoc Loc) {
+ MCStreamer::EmitWinCFIStartChained(Loc);
+
+ OS << "\t.seh_startchained";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIEndChained(SMLoc Loc) {
+ MCStreamer::EmitWinCFIEndChained(Loc);
+
+ OS << "\t.seh_endchained";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind,
+ bool Except, SMLoc Loc) {
+ MCStreamer::EmitWinEHHandler(Sym, Unwind, Except, Loc);
+
+ OS << "\t.seh_handler ";
+ Sym->print(OS, MAI);
+ if (Unwind)
+ OS << ", @unwind";
+ if (Except)
+ OS << ", @except";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinEHHandlerData(SMLoc Loc) {
+ MCStreamer::EmitWinEHHandlerData(Loc);
+
+ // Switch sections. Don't call SwitchSection directly, because that will
+ // cause the section switch to be visible in the emitted assembly.
+ // We only do this so the section switch that terminates the handler
+ // data block is visible.
+ WinEH::FrameInfo *CurFrame = getCurrentWinFrameInfo();
+
+ // Do nothing if no frame is open. MCStreamer should've already reported an
+ // error.
+ if (!CurFrame)
+ return;
+
+ MCSection *TextSec = &CurFrame->Function->getSection();
+ MCSection *XData = getAssociatedXDataSection(TextSec);
+ SwitchSectionNoChange(XData);
+
+ OS << "\t.seh_handlerdata";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) {
+ MCStreamer::EmitWinCFIPushReg(Register, Loc);
+
+ OS << "\t.seh_pushreg ";
+ InstPrinter->printRegName(OS, Register);
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFISetFrame(MCRegister Register, unsigned Offset,
+ SMLoc Loc) {
+ MCStreamer::EmitWinCFISetFrame(Register, Offset, Loc);
+
+ OS << "\t.seh_setframe ";
+ InstPrinter->printRegName(OS, Register);
+ OS << ", " << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) {
+ MCStreamer::EmitWinCFIAllocStack(Size, Loc);
+
+ OS << "\t.seh_stackalloc " << Size;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFISaveReg(MCRegister Register, unsigned Offset,
+ SMLoc Loc) {
+ MCStreamer::EmitWinCFISaveReg(Register, Offset, Loc);
+
+ OS << "\t.seh_savereg ";
+ InstPrinter->printRegName(OS, Register);
+ OS << ", " << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFISaveXMM(MCRegister Register, unsigned Offset,
+ SMLoc Loc) {
+ MCStreamer::EmitWinCFISaveXMM(Register, Offset, Loc);
+
+ OS << "\t.seh_savexmm ";
+ InstPrinter->printRegName(OS, Register);
+ OS << ", " << Offset;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIPushFrame(bool Code, SMLoc Loc) {
+ MCStreamer::EmitWinCFIPushFrame(Code, Loc);
+
+ OS << "\t.seh_pushframe";
+ if (Code)
+ OS << " @code";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitWinCFIEndProlog(SMLoc Loc) {
+ MCStreamer::EmitWinCFIEndProlog(Loc);
+
+ OS << "\t.seh_endprologue";
+ EmitEOL();
+}
+
+void MCAsmStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
+ const MCSymbolRefExpr *To,
+ uint64_t Count) {
+ OS << "\t.cg_profile ";
+ From->getSymbol().print(OS, MAI);
+ OS << ", ";
+ To->getSymbol().print(OS, MAI);
+ OS << ", " << Count;
+ EmitEOL();
+}
+
+void MCAsmStreamer::AddEncodingComment(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ raw_ostream &OS = GetCommentOS();
+ SmallString<256> Code;
+ SmallVector<MCFixup, 4> Fixups;
+ raw_svector_ostream VecOS(Code);
+
+ // If we have no code emitter, don't emit code.
+ if (!getAssembler().getEmitterPtr())
+ return;
+
+ getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
+
+ // If we are showing fixups, create symbolic markers in the encoded
+ // representation. We do this by making a per-bit map to the fixup item index,
+ // then trying to display it as nicely as possible.
+ SmallVector<uint8_t, 64> FixupMap;
+ FixupMap.resize(Code.size() * 8);
+ for (unsigned i = 0, e = Code.size() * 8; i != e; ++i)
+ FixupMap[i] = 0;
+
+ for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
+ MCFixup &F = Fixups[i];
+ const MCFixupKindInfo &Info =
+ getAssembler().getBackend().getFixupKindInfo(F.getKind());
+ for (unsigned j = 0; j != Info.TargetSize; ++j) {
+ unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j;
+ assert(Index < Code.size() * 8 && "Invalid offset in fixup!");
+ FixupMap[Index] = 1 + i;
+ }
+ }
+
+ // FIXME: Note the fixup comments for Thumb2 are completely bogus since the
+ // high order halfword of a 32-bit Thumb2 instruction is emitted first.
+ OS << "encoding: [";
+ for (unsigned i = 0, e = Code.size(); i != e; ++i) {
+ if (i)
+ OS << ',';
+
+ // See if all bits are the same map entry.
+ uint8_t MapEntry = FixupMap[i * 8 + 0];
+ for (unsigned j = 1; j != 8; ++j) {
+ if (FixupMap[i * 8 + j] == MapEntry)
+ continue;
+
+ MapEntry = uint8_t(~0U);
+ break;
+ }
+
+ if (MapEntry != uint8_t(~0U)) {
+ if (MapEntry == 0) {
+ OS << format("0x%02x", uint8_t(Code[i]));
+ } else {
+ if (Code[i]) {
+ // FIXME: Some of the 8 bits require fix up.
+ OS << format("0x%02x", uint8_t(Code[i])) << '\''
+ << char('A' + MapEntry - 1) << '\'';
+ } else
+ OS << char('A' + MapEntry - 1);
+ }
+ } else {
+ // Otherwise, write out in binary.
+ OS << "0b";
+ for (unsigned j = 8; j--;) {
+ unsigned Bit = (Code[i] >> j) & 1;
+
+ unsigned FixupBit;
+ if (MAI->isLittleEndian())
+ FixupBit = i * 8 + j;
+ else
+ FixupBit = i * 8 + (7-j);
+
+ if (uint8_t MapEntry = FixupMap[FixupBit]) {
+ assert(Bit == 0 && "Encoder wrote into fixed up bit!");
+ OS << char('A' + MapEntry - 1);
+ } else
+ OS << Bit;
+ }
+ }
+ }
+ OS << "]\n";
+
+ for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
+ MCFixup &F = Fixups[i];
+ const MCFixupKindInfo &Info =
+ getAssembler().getBackend().getFixupKindInfo(F.getKind());
+ OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset()
+ << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n";
+ }
+}
+
+void MCAsmStreamer::EmitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ assert(getCurrentSectionOnly() &&
+ "Cannot emit contents before setting section!");
+
+ // Show the encoding in a comment if we have a code emitter.
+ AddEncodingComment(Inst, STI);
+
+ // Show the MCInst if enabled.
+ if (ShowInst) {
+ Inst.dump_pretty(GetCommentOS(), InstPrinter.get(), "\n ");
+ GetCommentOS() << "\n";
+ }
+
+ if(getTargetStreamer())
+ getTargetStreamer()->prettyPrintAsm(*InstPrinter, OS, Inst, STI);
+ else
+ InstPrinter->printInst(&Inst, OS, "", STI);
+
+ StringRef Comments = CommentToEmit;
+ if (Comments.size() && Comments.back() != '\n')
+ GetCommentOS() << "\n";
+
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitBundleAlignMode(unsigned AlignPow2) {
+ OS << "\t.bundle_align_mode " << AlignPow2;
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitBundleLock(bool AlignToEnd) {
+ OS << "\t.bundle_lock";
+ if (AlignToEnd)
+ OS << " align_to_end";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitBundleUnlock() {
+ OS << "\t.bundle_unlock";
+ EmitEOL();
+}
+
+bool MCAsmStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
+ const MCExpr *Expr, SMLoc,
+ const MCSubtargetInfo &STI) {
+ OS << "\t.reloc ";
+ Offset.print(OS, MAI);
+ OS << ", " << Name;
+ if (Expr) {
+ OS << ", ";
+ Expr->print(OS, MAI);
+ }
+ EmitEOL();
+ return false;
+}
+
+void MCAsmStreamer::EmitAddrsig() {
+ OS << "\t.addrsig";
+ EmitEOL();
+}
+
+void MCAsmStreamer::EmitAddrsigSym(const MCSymbol *Sym) {
+ OS << "\t.addrsig_sym ";
+ Sym->print(OS, MAI);
+ EmitEOL();
+}
+
+/// EmitRawText - If this file is backed by an assembly streamer, this dumps
+/// the specified string in the output .s file. This capability is
+/// indicated by the hasRawTextSupport() predicate.
+void MCAsmStreamer::EmitRawTextImpl(StringRef String) {
+ if (!String.empty() && String.back() == '\n')
+ String = String.substr(0, String.size()-1);
+ OS << String;
+ EmitEOL();
+}
+
+void MCAsmStreamer::FinishImpl() {
+ // If we are generating dwarf for assembly source files dump out the sections.
+ if (getContext().getGenDwarfForAssembly())
+ MCGenDwarfInfo::Emit(this);
+
+ // Emit the label for the line table, if requested - since the rest of the
+ // line table will be defined by .loc/.file directives, and not emitted
+ // directly, the label is the only work required here.
+ const auto &Tables = getContext().getMCDwarfLineTables();
+ if (!Tables.empty()) {
+ assert(Tables.size() == 1 && "asm output only supports one line table");
+ if (auto *Label = Tables.begin()->second.getLabel()) {
+ SwitchSection(getContext().getObjectFileInfo()->getDwarfLineSection());
+ EmitLabel(Label);
+ }
+ }
+}
+
+MCStreamer *llvm::createAsmStreamer(MCContext &Context,
+ std::unique_ptr<formatted_raw_ostream> OS,
+ bool isVerboseAsm, bool useDwarfDirectory,
+ MCInstPrinter *IP,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ std::unique_ptr<MCAsmBackend> &&MAB,
+ bool ShowInst) {
+ return new MCAsmStreamer(Context, std::move(OS), isVerboseAsm,
+ useDwarfDirectory, IP, std::move(CE), std::move(MAB),
+ ShowInst);
+}
diff --git a/llvm/lib/MC/MCAssembler.cpp b/llvm/lib/MC/MCAssembler.cpp
new file mode 100644
index 000000000000..cf42fe85b8e5
--- /dev/null
+++ b/llvm/lib/MC/MCAssembler.cpp
@@ -0,0 +1,1155 @@
+//===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===//
+//
+// 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/MCAssembler.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAsmLayout.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/MCFixup.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <tuple>
+#include <utility>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "assembler"
+
+namespace {
+namespace stats {
+
+STATISTIC(EmittedFragments, "Number of emitted assembler fragments - total");
+STATISTIC(EmittedRelaxableFragments,
+ "Number of emitted assembler fragments - relaxable");
+STATISTIC(EmittedDataFragments,
+ "Number of emitted assembler fragments - data");
+STATISTIC(EmittedCompactEncodedInstFragments,
+ "Number of emitted assembler fragments - compact encoded inst");
+STATISTIC(EmittedAlignFragments,
+ "Number of emitted assembler fragments - align");
+STATISTIC(EmittedFillFragments,
+ "Number of emitted assembler fragments - fill");
+STATISTIC(EmittedOrgFragments,
+ "Number of emitted assembler fragments - org");
+STATISTIC(evaluateFixup, "Number of evaluated fixups");
+STATISTIC(FragmentLayouts, "Number of fragment layouts");
+STATISTIC(ObjectBytes, "Number of emitted object file bytes");
+STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps");
+STATISTIC(RelaxedInstructions, "Number of relaxed instructions");
+STATISTIC(PaddingFragmentsRelaxations,
+ "Number of Padding Fragments relaxations");
+STATISTIC(PaddingFragmentsBytes,
+ "Total size of all padding from adding Fragments");
+
+} // end namespace stats
+} // end anonymous namespace
+
+// FIXME FIXME FIXME: There are number of places in this file where we convert
+// what is a 64-bit assembler value used for computation into a value in the
+// object file, which may truncate it. We should detect that truncation where
+// invalid and report errors back.
+
+/* *** */
+
+MCAssembler::MCAssembler(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> Backend,
+ std::unique_ptr<MCCodeEmitter> Emitter,
+ std::unique_ptr<MCObjectWriter> Writer)
+ : Context(Context), Backend(std::move(Backend)),
+ Emitter(std::move(Emitter)), Writer(std::move(Writer)),
+ BundleAlignSize(0), RelaxAll(false), SubsectionsViaSymbols(false),
+ IncrementalLinkerCompatible(false), ELFHeaderEFlags(0) {
+ VersionInfo.Major = 0; // Major version == 0 for "none specified"
+}
+
+MCAssembler::~MCAssembler() = default;
+
+void MCAssembler::reset() {
+ Sections.clear();
+ Symbols.clear();
+ IndirectSymbols.clear();
+ DataRegions.clear();
+ LinkerOptions.clear();
+ FileNames.clear();
+ ThumbFuncs.clear();
+ BundleAlignSize = 0;
+ RelaxAll = false;
+ SubsectionsViaSymbols = false;
+ IncrementalLinkerCompatible = false;
+ ELFHeaderEFlags = 0;
+ LOHContainer.reset();
+ VersionInfo.Major = 0;
+ VersionInfo.SDKVersion = VersionTuple();
+
+ // reset objects owned by us
+ if (getBackendPtr())
+ getBackendPtr()->reset();
+ if (getEmitterPtr())
+ getEmitterPtr()->reset();
+ if (getWriterPtr())
+ getWriterPtr()->reset();
+ getLOHContainer().reset();
+}
+
+bool MCAssembler::registerSection(MCSection &Section) {
+ if (Section.isRegistered())
+ return false;
+ Sections.push_back(&Section);
+ Section.setIsRegistered(true);
+ return true;
+}
+
+bool MCAssembler::isThumbFunc(const MCSymbol *Symbol) const {
+ if (ThumbFuncs.count(Symbol))
+ return true;
+
+ if (!Symbol->isVariable())
+ return false;
+
+ const MCExpr *Expr = Symbol->getVariableValue();
+
+ MCValue V;
+ if (!Expr->evaluateAsRelocatable(V, nullptr, nullptr))
+ return false;
+
+ if (V.getSymB() || V.getRefKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ const MCSymbolRefExpr *Ref = V.getSymA();
+ if (!Ref)
+ return false;
+
+ if (Ref->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ const MCSymbol &Sym = Ref->getSymbol();
+ if (!isThumbFunc(&Sym))
+ return false;
+
+ ThumbFuncs.insert(Symbol); // Cache it.
+ return true;
+}
+
+bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const {
+ // Non-temporary labels should always be visible to the linker.
+ if (!Symbol.isTemporary())
+ return true;
+
+ // Absolute temporary labels are never visible.
+ if (!Symbol.isInSection())
+ return false;
+
+ if (Symbol.isUsedInReloc())
+ return true;
+
+ return false;
+}
+
+const MCSymbol *MCAssembler::getAtom(const MCSymbol &S) const {
+ // Linker visible symbols define atoms.
+ if (isSymbolLinkerVisible(S))
+ return &S;
+
+ // Absolute and undefined symbols have no defining atom.
+ if (!S.isInSection())
+ return nullptr;
+
+ // Non-linker visible symbols in sections which can't be atomized have no
+ // defining atom.
+ if (!getContext().getAsmInfo()->isSectionAtomizableBySymbols(
+ *S.getFragment()->getParent()))
+ return nullptr;
+
+ // Otherwise, return the atom for the containing fragment.
+ return S.getFragment()->getAtom();
+}
+
+bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ MCValue &Target, uint64_t &Value,
+ bool &WasForced) const {
+ ++stats::evaluateFixup;
+
+ // FIXME: This code has some duplication with recordRelocation. We should
+ // probably merge the two into a single callback that tries to evaluate a
+ // fixup and records a relocation if one is needed.
+
+ // On error claim to have completely evaluated the fixup, to prevent any
+ // further processing from being done.
+ const MCExpr *Expr = Fixup.getValue();
+ MCContext &Ctx = getContext();
+ Value = 0;
+ WasForced = false;
+ if (!Expr->evaluateAsRelocatable(Target, &Layout, &Fixup)) {
+ Ctx.reportError(Fixup.getLoc(), "expected relocatable expression");
+ return true;
+ }
+ if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
+ if (RefB->getKind() != MCSymbolRefExpr::VK_None) {
+ Ctx.reportError(Fixup.getLoc(),
+ "unsupported subtraction of qualified symbol");
+ return true;
+ }
+ }
+
+ assert(getBackendPtr() && "Expected assembler backend");
+ bool IsPCRel = getBackendPtr()->getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsPCRel;
+
+ bool IsResolved = false;
+ if (IsPCRel) {
+ if (Target.getSymB()) {
+ IsResolved = false;
+ } else if (!Target.getSymA()) {
+ IsResolved = false;
+ } else {
+ const MCSymbolRefExpr *A = Target.getSymA();
+ const MCSymbol &SA = A->getSymbol();
+ if (A->getKind() != MCSymbolRefExpr::VK_None || SA.isUndefined()) {
+ IsResolved = false;
+ } else if (auto *Writer = getWriterPtr()) {
+ IsResolved = Writer->isSymbolRefDifferenceFullyResolvedImpl(
+ *this, SA, *DF, false, true);
+ }
+ }
+ } else {
+ IsResolved = Target.isAbsolute();
+ }
+
+ Value = Target.getConstant();
+
+ if (const MCSymbolRefExpr *A = Target.getSymA()) {
+ const MCSymbol &Sym = A->getSymbol();
+ if (Sym.isDefined())
+ Value += Layout.getSymbolOffset(Sym);
+ }
+ if (const MCSymbolRefExpr *B = Target.getSymB()) {
+ const MCSymbol &Sym = B->getSymbol();
+ if (Sym.isDefined())
+ Value -= Layout.getSymbolOffset(Sym);
+ }
+
+ bool ShouldAlignPC = getBackend().getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsAlignedDownTo32Bits;
+ assert((ShouldAlignPC ? IsPCRel : true) &&
+ "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!");
+
+ if (IsPCRel) {
+ uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset();
+
+ // A number of ARM fixups in Thumb mode require that the effective PC
+ // address be determined as the 32-bit aligned version of the actual offset.
+ if (ShouldAlignPC) Offset &= ~0x3;
+ Value -= Offset;
+ }
+
+ // Let the backend force a relocation if needed.
+ if (IsResolved && getBackend().shouldForceRelocation(*this, Fixup, Target)) {
+ IsResolved = false;
+ WasForced = true;
+ }
+
+ return IsResolved;
+}
+
+uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout,
+ const MCFragment &F) const {
+ assert(getBackendPtr() && "Requires assembler backend");
+ switch (F.getKind()) {
+ case MCFragment::FT_Data:
+ return cast<MCDataFragment>(F).getContents().size();
+ case MCFragment::FT_Relaxable:
+ return cast<MCRelaxableFragment>(F).getContents().size();
+ case MCFragment::FT_CompactEncodedInst:
+ return cast<MCCompactEncodedInstFragment>(F).getContents().size();
+ case MCFragment::FT_Fill: {
+ auto &FF = cast<MCFillFragment>(F);
+ int64_t NumValues = 0;
+ if (!FF.getNumValues().evaluateAsAbsolute(NumValues, Layout)) {
+ getContext().reportError(FF.getLoc(),
+ "expected assembly-time absolute expression");
+ return 0;
+ }
+ int64_t Size = NumValues * FF.getValueSize();
+ if (Size < 0) {
+ getContext().reportError(FF.getLoc(), "invalid number of bytes");
+ return 0;
+ }
+ return Size;
+ }
+
+ case MCFragment::FT_LEB:
+ return cast<MCLEBFragment>(F).getContents().size();
+
+ case MCFragment::FT_Padding:
+ return cast<MCPaddingFragment>(F).getSize();
+
+ case MCFragment::FT_SymbolId:
+ return 4;
+
+ case MCFragment::FT_Align: {
+ const MCAlignFragment &AF = cast<MCAlignFragment>(F);
+ unsigned Offset = Layout.getFragmentOffset(&AF);
+ unsigned Size = offsetToAlignment(Offset, Align(AF.getAlignment()));
+
+ // Insert extra Nops for code alignment if the target define
+ // shouldInsertExtraNopBytesForCodeAlign target hook.
+ if (AF.getParent()->UseCodeAlign() && AF.hasEmitNops() &&
+ getBackend().shouldInsertExtraNopBytesForCodeAlign(AF, Size))
+ return Size;
+
+ // If we are padding with nops, force the padding to be larger than the
+ // minimum nop size.
+ if (Size > 0 && AF.hasEmitNops()) {
+ while (Size % getBackend().getMinimumNopSize())
+ Size += AF.getAlignment();
+ }
+ if (Size > AF.getMaxBytesToEmit())
+ return 0;
+ return Size;
+ }
+
+ case MCFragment::FT_Org: {
+ const MCOrgFragment &OF = cast<MCOrgFragment>(F);
+ MCValue Value;
+ if (!OF.getOffset().evaluateAsValue(Value, Layout)) {
+ getContext().reportError(OF.getLoc(),
+ "expected assembly-time absolute expression");
+ return 0;
+ }
+
+ uint64_t FragmentOffset = Layout.getFragmentOffset(&OF);
+ int64_t TargetLocation = Value.getConstant();
+ if (const MCSymbolRefExpr *A = Value.getSymA()) {
+ uint64_t Val;
+ if (!Layout.getSymbolOffset(A->getSymbol(), Val)) {
+ getContext().reportError(OF.getLoc(), "expected absolute expression");
+ return 0;
+ }
+ TargetLocation += Val;
+ }
+ int64_t Size = TargetLocation - FragmentOffset;
+ if (Size < 0 || Size >= 0x40000000) {
+ getContext().reportError(
+ OF.getLoc(), "invalid .org offset '" + Twine(TargetLocation) +
+ "' (at offset '" + Twine(FragmentOffset) + "')");
+ return 0;
+ }
+ return Size;
+ }
+
+ case MCFragment::FT_Dwarf:
+ return cast<MCDwarfLineAddrFragment>(F).getContents().size();
+ case MCFragment::FT_DwarfFrame:
+ return cast<MCDwarfCallFrameFragment>(F).getContents().size();
+ case MCFragment::FT_CVInlineLines:
+ return cast<MCCVInlineLineTableFragment>(F).getContents().size();
+ case MCFragment::FT_CVDefRange:
+ return cast<MCCVDefRangeFragment>(F).getContents().size();
+ case MCFragment::FT_Dummy:
+ llvm_unreachable("Should not have been added");
+ }
+
+ llvm_unreachable("invalid fragment kind");
+}
+
+void MCAsmLayout::layoutFragment(MCFragment *F) {
+ MCFragment *Prev = F->getPrevNode();
+
+ // We should never try to recompute something which is valid.
+ assert(!isFragmentValid(F) && "Attempt to recompute a valid fragment!");
+ // We should never try to compute the fragment layout if its predecessor
+ // isn't valid.
+ assert((!Prev || isFragmentValid(Prev)) &&
+ "Attempt to compute fragment before its predecessor!");
+
+ ++stats::FragmentLayouts;
+
+ // Compute fragment offset and size.
+ if (Prev)
+ F->Offset = Prev->Offset + getAssembler().computeFragmentSize(*this, *Prev);
+ else
+ F->Offset = 0;
+ LastValidFragment[F->getParent()] = F;
+
+ // If bundling is enabled and this fragment has instructions in it, it has to
+ // obey the bundling restrictions. With padding, we'll have:
+ //
+ //
+ // BundlePadding
+ // |||
+ // -------------------------------------
+ // Prev |##########| F |
+ // -------------------------------------
+ // ^
+ // |
+ // F->Offset
+ //
+ // The fragment's offset will point to after the padding, and its computed
+ // size won't include the padding.
+ //
+ // When the -mc-relax-all flag is used, we optimize bundling by writting the
+ // padding directly into fragments when the instructions are emitted inside
+ // the streamer. When the fragment is larger than the bundle size, we need to
+ // ensure that it's bundle aligned. This means that if we end up with
+ // multiple fragments, we must emit bundle padding between fragments.
+ //
+ // ".align N" is an example of a directive that introduces multiple
+ // fragments. We could add a special case to handle ".align N" by emitting
+ // within-fragment padding (which would produce less padding when N is less
+ // than the bundle size), but for now we don't.
+ //
+ if (Assembler.isBundlingEnabled() && F->hasInstructions()) {
+ assert(isa<MCEncodedFragment>(F) &&
+ "Only MCEncodedFragment implementations have instructions");
+ MCEncodedFragment *EF = cast<MCEncodedFragment>(F);
+ uint64_t FSize = Assembler.computeFragmentSize(*this, *EF);
+
+ if (!Assembler.getRelaxAll() && FSize > Assembler.getBundleAlignSize())
+ report_fatal_error("Fragment can't be larger than a bundle size");
+
+ uint64_t RequiredBundlePadding =
+ computeBundlePadding(Assembler, EF, EF->Offset, FSize);
+ if (RequiredBundlePadding > UINT8_MAX)
+ report_fatal_error("Padding cannot exceed 255 bytes");
+ EF->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding));
+ EF->Offset += RequiredBundlePadding;
+ }
+}
+
+void MCAssembler::registerSymbol(const MCSymbol &Symbol, bool *Created) {
+ bool New = !Symbol.isRegistered();
+ if (Created)
+ *Created = New;
+ if (New) {
+ Symbol.setIsRegistered(true);
+ Symbols.push_back(&Symbol);
+ }
+}
+
+void MCAssembler::writeFragmentPadding(raw_ostream &OS,
+ const MCEncodedFragment &EF,
+ uint64_t FSize) const {
+ assert(getBackendPtr() && "Expected assembler backend");
+ // Should NOP padding be written out before this fragment?
+ unsigned BundlePadding = EF.getBundlePadding();
+ if (BundlePadding > 0) {
+ assert(isBundlingEnabled() &&
+ "Writing bundle padding with disabled bundling");
+ assert(EF.hasInstructions() &&
+ "Writing bundle padding for a fragment without instructions");
+
+ unsigned TotalLength = BundlePadding + static_cast<unsigned>(FSize);
+ if (EF.alignToBundleEnd() && TotalLength > getBundleAlignSize()) {
+ // If the padding itself crosses a bundle boundary, it must be emitted
+ // in 2 pieces, since even nop instructions must not cross boundaries.
+ // v--------------v <- BundleAlignSize
+ // v---------v <- BundlePadding
+ // ----------------------------
+ // | Prev |####|####| F |
+ // ----------------------------
+ // ^-------------------^ <- TotalLength
+ unsigned DistanceToBoundary = TotalLength - getBundleAlignSize();
+ if (!getBackend().writeNopData(OS, DistanceToBoundary))
+ report_fatal_error("unable to write NOP sequence of " +
+ Twine(DistanceToBoundary) + " bytes");
+ BundlePadding -= DistanceToBoundary;
+ }
+ if (!getBackend().writeNopData(OS, BundlePadding))
+ report_fatal_error("unable to write NOP sequence of " +
+ Twine(BundlePadding) + " bytes");
+ }
+}
+
+/// Write the fragment \p F to the output file.
+static void writeFragment(raw_ostream &OS, const MCAssembler &Asm,
+ const MCAsmLayout &Layout, const MCFragment &F) {
+ // FIXME: Embed in fragments instead?
+ uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F);
+
+ support::endianness Endian = Asm.getBackend().Endian;
+
+ if (const MCEncodedFragment *EF = dyn_cast<MCEncodedFragment>(&F))
+ Asm.writeFragmentPadding(OS, *EF, FragmentSize);
+
+ // This variable (and its dummy usage) is to participate in the assert at
+ // the end of the function.
+ uint64_t Start = OS.tell();
+ (void) Start;
+
+ ++stats::EmittedFragments;
+
+ switch (F.getKind()) {
+ case MCFragment::FT_Align: {
+ ++stats::EmittedAlignFragments;
+ const MCAlignFragment &AF = cast<MCAlignFragment>(F);
+ assert(AF.getValueSize() && "Invalid virtual align in concrete fragment!");
+
+ uint64_t Count = FragmentSize / AF.getValueSize();
+
+ // FIXME: This error shouldn't actually occur (the front end should emit
+ // multiple .align directives to enforce the semantics it wants), but is
+ // severe enough that we want to report it. How to handle this?
+ if (Count * AF.getValueSize() != FragmentSize)
+ report_fatal_error("undefined .align directive, value size '" +
+ Twine(AF.getValueSize()) +
+ "' is not a divisor of padding size '" +
+ Twine(FragmentSize) + "'");
+
+ // See if we are aligning with nops, and if so do that first to try to fill
+ // the Count bytes. Then if that did not fill any bytes or there are any
+ // bytes left to fill use the Value and ValueSize to fill the rest.
+ // If we are aligning with nops, ask that target to emit the right data.
+ if (AF.hasEmitNops()) {
+ if (!Asm.getBackend().writeNopData(OS, Count))
+ report_fatal_error("unable to write nop sequence of " +
+ Twine(Count) + " bytes");
+ break;
+ }
+
+ // Otherwise, write out in multiples of the value size.
+ for (uint64_t i = 0; i != Count; ++i) {
+ switch (AF.getValueSize()) {
+ default: llvm_unreachable("Invalid size!");
+ case 1: OS << char(AF.getValue()); break;
+ case 2:
+ support::endian::write<uint16_t>(OS, AF.getValue(), Endian);
+ break;
+ case 4:
+ support::endian::write<uint32_t>(OS, AF.getValue(), Endian);
+ break;
+ case 8:
+ support::endian::write<uint64_t>(OS, AF.getValue(), Endian);
+ break;
+ }
+ }
+ break;
+ }
+
+ case MCFragment::FT_Data:
+ ++stats::EmittedDataFragments;
+ OS << cast<MCDataFragment>(F).getContents();
+ break;
+
+ case MCFragment::FT_Relaxable:
+ ++stats::EmittedRelaxableFragments;
+ OS << cast<MCRelaxableFragment>(F).getContents();
+ break;
+
+ case MCFragment::FT_CompactEncodedInst:
+ ++stats::EmittedCompactEncodedInstFragments;
+ OS << cast<MCCompactEncodedInstFragment>(F).getContents();
+ break;
+
+ case MCFragment::FT_Fill: {
+ ++stats::EmittedFillFragments;
+ const MCFillFragment &FF = cast<MCFillFragment>(F);
+ uint64_t V = FF.getValue();
+ unsigned VSize = FF.getValueSize();
+ const unsigned MaxChunkSize = 16;
+ char Data[MaxChunkSize];
+ // Duplicate V into Data as byte vector to reduce number of
+ // writes done. As such, do endian conversion here.
+ for (unsigned I = 0; I != VSize; ++I) {
+ unsigned index = Endian == support::little ? I : (VSize - I - 1);
+ Data[I] = uint8_t(V >> (index * 8));
+ }
+ for (unsigned I = VSize; I < MaxChunkSize; ++I)
+ Data[I] = Data[I - VSize];
+
+ // Set to largest multiple of VSize in Data.
+ const unsigned NumPerChunk = MaxChunkSize / VSize;
+ // Set ChunkSize to largest multiple of VSize in Data
+ const unsigned ChunkSize = VSize * NumPerChunk;
+
+ // Do copies by chunk.
+ StringRef Ref(Data, ChunkSize);
+ for (uint64_t I = 0, E = FragmentSize / ChunkSize; I != E; ++I)
+ OS << Ref;
+
+ // do remainder if needed.
+ unsigned TrailingCount = FragmentSize % ChunkSize;
+ if (TrailingCount)
+ OS.write(Data, TrailingCount);
+ break;
+ }
+
+ case MCFragment::FT_LEB: {
+ const MCLEBFragment &LF = cast<MCLEBFragment>(F);
+ OS << LF.getContents();
+ break;
+ }
+
+ case MCFragment::FT_Padding: {
+ if (!Asm.getBackend().writeNopData(OS, FragmentSize))
+ report_fatal_error("unable to write nop sequence of " +
+ Twine(FragmentSize) + " bytes");
+ break;
+ }
+
+ case MCFragment::FT_SymbolId: {
+ const MCSymbolIdFragment &SF = cast<MCSymbolIdFragment>(F);
+ support::endian::write<uint32_t>(OS, SF.getSymbol()->getIndex(), Endian);
+ break;
+ }
+
+ case MCFragment::FT_Org: {
+ ++stats::EmittedOrgFragments;
+ const MCOrgFragment &OF = cast<MCOrgFragment>(F);
+
+ for (uint64_t i = 0, e = FragmentSize; i != e; ++i)
+ OS << char(OF.getValue());
+
+ break;
+ }
+
+ case MCFragment::FT_Dwarf: {
+ const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F);
+ OS << OF.getContents();
+ break;
+ }
+ case MCFragment::FT_DwarfFrame: {
+ const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F);
+ OS << CF.getContents();
+ break;
+ }
+ case MCFragment::FT_CVInlineLines: {
+ const auto &OF = cast<MCCVInlineLineTableFragment>(F);
+ OS << OF.getContents();
+ break;
+ }
+ case MCFragment::FT_CVDefRange: {
+ const auto &DRF = cast<MCCVDefRangeFragment>(F);
+ OS << DRF.getContents();
+ break;
+ }
+ case MCFragment::FT_Dummy:
+ llvm_unreachable("Should not have been added");
+ }
+
+ assert(OS.tell() - Start == FragmentSize &&
+ "The stream should advance by fragment size");
+}
+
+void MCAssembler::writeSectionData(raw_ostream &OS, const MCSection *Sec,
+ const MCAsmLayout &Layout) const {
+ assert(getBackendPtr() && "Expected assembler backend");
+
+ // Ignore virtual sections.
+ if (Sec->isVirtualSection()) {
+ assert(Layout.getSectionFileSize(Sec) == 0 && "Invalid size for section!");
+
+ // Check that contents are only things legal inside a virtual section.
+ for (const MCFragment &F : *Sec) {
+ switch (F.getKind()) {
+ default: llvm_unreachable("Invalid fragment in virtual section!");
+ case MCFragment::FT_Data: {
+ // Check that we aren't trying to write a non-zero contents (or fixups)
+ // into a virtual section. This is to support clients which use standard
+ // directives to fill the contents of virtual sections.
+ const MCDataFragment &DF = cast<MCDataFragment>(F);
+ if (DF.fixup_begin() != DF.fixup_end())
+ report_fatal_error("cannot have fixups in virtual section!");
+ for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i)
+ if (DF.getContents()[i]) {
+ if (auto *ELFSec = dyn_cast<const MCSectionELF>(Sec))
+ report_fatal_error("non-zero initializer found in section '" +
+ ELFSec->getSectionName() + "'");
+ else
+ report_fatal_error("non-zero initializer found in virtual section");
+ }
+ break;
+ }
+ case MCFragment::FT_Align:
+ // Check that we aren't trying to write a non-zero value into a virtual
+ // section.
+ assert((cast<MCAlignFragment>(F).getValueSize() == 0 ||
+ cast<MCAlignFragment>(F).getValue() == 0) &&
+ "Invalid align in virtual section!");
+ break;
+ case MCFragment::FT_Fill:
+ assert((cast<MCFillFragment>(F).getValue() == 0) &&
+ "Invalid fill in virtual section!");
+ break;
+ }
+ }
+
+ return;
+ }
+
+ uint64_t Start = OS.tell();
+ (void)Start;
+
+ for (const MCFragment &F : *Sec)
+ writeFragment(OS, *this, Layout, F);
+
+ assert(OS.tell() - Start == Layout.getSectionAddressSize(Sec));
+}
+
+std::tuple<MCValue, uint64_t, bool>
+MCAssembler::handleFixup(const MCAsmLayout &Layout, MCFragment &F,
+ const MCFixup &Fixup) {
+ // Evaluate the fixup.
+ MCValue Target;
+ uint64_t FixedValue;
+ bool WasForced;
+ bool IsResolved = evaluateFixup(Layout, Fixup, &F, Target, FixedValue,
+ WasForced);
+ if (!IsResolved) {
+ // The fixup was unresolved, we need a relocation. Inform the object
+ // writer of the relocation, and give it an opportunity to adjust the
+ // fixup value if need be.
+ if (Target.getSymA() && Target.getSymB() &&
+ getBackend().requiresDiffExpressionRelocations()) {
+ // The fixup represents the difference between two symbols, which the
+ // backend has indicated must be resolved at link time. Split up the fixup
+ // into two relocations, one for the add, and one for the sub, and emit
+ // both of these. The constant will be associated with the add half of the
+ // expression.
+ MCFixup FixupAdd = MCFixup::createAddFor(Fixup);
+ MCValue TargetAdd =
+ MCValue::get(Target.getSymA(), nullptr, Target.getConstant());
+ getWriter().recordRelocation(*this, Layout, &F, FixupAdd, TargetAdd,
+ FixedValue);
+ MCFixup FixupSub = MCFixup::createSubFor(Fixup);
+ MCValue TargetSub = MCValue::get(Target.getSymB());
+ getWriter().recordRelocation(*this, Layout, &F, FixupSub, TargetSub,
+ FixedValue);
+ } else {
+ getWriter().recordRelocation(*this, Layout, &F, Fixup, Target,
+ FixedValue);
+ }
+ }
+ return std::make_tuple(Target, FixedValue, IsResolved);
+}
+
+void MCAssembler::layout(MCAsmLayout &Layout) {
+ assert(getBackendPtr() && "Expected assembler backend");
+ DEBUG_WITH_TYPE("mc-dump", {
+ errs() << "assembler backend - pre-layout\n--\n";
+ dump(); });
+
+ // Create dummy fragments and assign section ordinals.
+ unsigned SectionIndex = 0;
+ for (MCSection &Sec : *this) {
+ // Create dummy fragments to eliminate any empty sections, this simplifies
+ // layout.
+ if (Sec.getFragmentList().empty())
+ new MCDataFragment(&Sec);
+
+ Sec.setOrdinal(SectionIndex++);
+ }
+
+ // Assign layout order indices to sections and fragments.
+ for (unsigned i = 0, e = Layout.getSectionOrder().size(); i != e; ++i) {
+ MCSection *Sec = Layout.getSectionOrder()[i];
+ Sec->setLayoutOrder(i);
+
+ unsigned FragmentIndex = 0;
+ for (MCFragment &Frag : *Sec)
+ Frag.setLayoutOrder(FragmentIndex++);
+ }
+
+ // Layout until everything fits.
+ while (layoutOnce(Layout))
+ if (getContext().hadError())
+ return;
+
+ DEBUG_WITH_TYPE("mc-dump", {
+ errs() << "assembler backend - post-relaxation\n--\n";
+ dump(); });
+
+ // Finalize the layout, including fragment lowering.
+ finishLayout(Layout);
+
+ DEBUG_WITH_TYPE("mc-dump", {
+ errs() << "assembler backend - final-layout\n--\n";
+ dump(); });
+
+ // Allow the object writer a chance to perform post-layout binding (for
+ // example, to set the index fields in the symbol data).
+ getWriter().executePostLayoutBinding(*this, Layout);
+
+ // Evaluate and apply the fixups, generating relocation entries as necessary.
+ for (MCSection &Sec : *this) {
+ for (MCFragment &Frag : Sec) {
+ // Data and relaxable fragments both have fixups. So only process
+ // those here.
+ // FIXME: Is there a better way to do this? MCEncodedFragmentWithFixups
+ // being templated makes this tricky.
+ if (isa<MCEncodedFragment>(&Frag) &&
+ isa<MCCompactEncodedInstFragment>(&Frag))
+ continue;
+ if (!isa<MCEncodedFragment>(&Frag) && !isa<MCCVDefRangeFragment>(&Frag) &&
+ !isa<MCAlignFragment>(&Frag))
+ continue;
+ ArrayRef<MCFixup> Fixups;
+ MutableArrayRef<char> Contents;
+ const MCSubtargetInfo *STI = nullptr;
+ if (auto *FragWithFixups = dyn_cast<MCDataFragment>(&Frag)) {
+ Fixups = FragWithFixups->getFixups();
+ Contents = FragWithFixups->getContents();
+ STI = FragWithFixups->getSubtargetInfo();
+ assert(!FragWithFixups->hasInstructions() || STI != nullptr);
+ } else if (auto *FragWithFixups = dyn_cast<MCRelaxableFragment>(&Frag)) {
+ Fixups = FragWithFixups->getFixups();
+ Contents = FragWithFixups->getContents();
+ STI = FragWithFixups->getSubtargetInfo();
+ assert(!FragWithFixups->hasInstructions() || STI != nullptr);
+ } else if (auto *FragWithFixups = dyn_cast<MCCVDefRangeFragment>(&Frag)) {
+ Fixups = FragWithFixups->getFixups();
+ Contents = FragWithFixups->getContents();
+ } else if (auto *FragWithFixups = dyn_cast<MCDwarfLineAddrFragment>(&Frag)) {
+ Fixups = FragWithFixups->getFixups();
+ Contents = FragWithFixups->getContents();
+ } else if (auto *AF = dyn_cast<MCAlignFragment>(&Frag)) {
+ // Insert fixup type for code alignment if the target define
+ // shouldInsertFixupForCodeAlign target hook.
+ if (Sec.UseCodeAlign() && AF->hasEmitNops()) {
+ getBackend().shouldInsertFixupForCodeAlign(*this, Layout, *AF);
+ }
+ continue;
+ } else if (auto *FragWithFixups =
+ dyn_cast<MCDwarfCallFrameFragment>(&Frag)) {
+ Fixups = FragWithFixups->getFixups();
+ Contents = FragWithFixups->getContents();
+ } else
+ llvm_unreachable("Unknown fragment with fixups!");
+ for (const MCFixup &Fixup : Fixups) {
+ uint64_t FixedValue;
+ bool IsResolved;
+ MCValue Target;
+ std::tie(Target, FixedValue, IsResolved) =
+ handleFixup(Layout, Frag, Fixup);
+ getBackend().applyFixup(*this, Fixup, Target, Contents, FixedValue,
+ IsResolved, STI);
+ }
+ }
+ }
+}
+
+void MCAssembler::Finish() {
+ // Create the layout object.
+ MCAsmLayout Layout(*this);
+ layout(Layout);
+
+ // Write the object file.
+ stats::ObjectBytes += getWriter().writeObject(*this, Layout);
+}
+
+bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const {
+ assert(getBackendPtr() && "Expected assembler backend");
+ MCValue Target;
+ uint64_t Value;
+ bool WasForced;
+ bool Resolved = evaluateFixup(Layout, Fixup, DF, Target, Value, WasForced);
+ if (Target.getSymA() &&
+ Target.getSymA()->getKind() == MCSymbolRefExpr::VK_X86_ABS8 &&
+ Fixup.getKind() == FK_Data_1)
+ return false;
+ return getBackend().fixupNeedsRelaxationAdvanced(Fixup, Resolved, Value, DF,
+ Layout, WasForced);
+}
+
+bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F,
+ const MCAsmLayout &Layout) const {
+ assert(getBackendPtr() && "Expected assembler backend");
+ // If this inst doesn't ever need relaxation, ignore it. This occurs when we
+ // are intentionally pushing out inst fragments, or because we relaxed a
+ // previous instruction to one that doesn't need relaxation.
+ if (!getBackend().mayNeedRelaxation(F->getInst(), *F->getSubtargetInfo()))
+ return false;
+
+ for (const MCFixup &Fixup : F->getFixups())
+ if (fixupNeedsRelaxation(Fixup, F, Layout))
+ return true;
+
+ return false;
+}
+
+bool MCAssembler::relaxInstruction(MCAsmLayout &Layout,
+ MCRelaxableFragment &F) {
+ assert(getEmitterPtr() &&
+ "Expected CodeEmitter defined for relaxInstruction");
+ if (!fragmentNeedsRelaxation(&F, Layout))
+ return false;
+
+ ++stats::RelaxedInstructions;
+
+ // FIXME-PERF: We could immediately lower out instructions if we can tell
+ // they are fully resolved, to avoid retesting on later passes.
+
+ // Relax the fragment.
+
+ MCInst Relaxed;
+ getBackend().relaxInstruction(F.getInst(), *F.getSubtargetInfo(), Relaxed);
+
+ // Encode the new instruction.
+ //
+ // FIXME-PERF: If it matters, we could let the target do this. It can
+ // probably do so more efficiently in many cases.
+ SmallVector<MCFixup, 4> Fixups;
+ SmallString<256> Code;
+ raw_svector_ostream VecOS(Code);
+ getEmitter().encodeInstruction(Relaxed, VecOS, Fixups, *F.getSubtargetInfo());
+
+ // Update the fragment.
+ F.setInst(Relaxed);
+ F.getContents() = Code;
+ F.getFixups() = Fixups;
+
+ return true;
+}
+
+bool MCAssembler::relaxPaddingFragment(MCAsmLayout &Layout,
+ MCPaddingFragment &PF) {
+ assert(getBackendPtr() && "Expected assembler backend");
+ uint64_t OldSize = PF.getSize();
+ if (!getBackend().relaxFragment(&PF, Layout))
+ return false;
+ uint64_t NewSize = PF.getSize();
+
+ ++stats::PaddingFragmentsRelaxations;
+ stats::PaddingFragmentsBytes += NewSize;
+ stats::PaddingFragmentsBytes -= OldSize;
+ return true;
+}
+
+bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) {
+ uint64_t OldSize = LF.getContents().size();
+ int64_t Value;
+ bool Abs = LF.getValue().evaluateKnownAbsolute(Value, Layout);
+ if (!Abs)
+ report_fatal_error("sleb128 and uleb128 expressions must be absolute");
+ SmallString<8> &Data = LF.getContents();
+ Data.clear();
+ raw_svector_ostream OSE(Data);
+ // The compiler can generate EH table assembly that is impossible to assemble
+ // without either adding padding to an LEB fragment or adding extra padding
+ // to a later alignment fragment. To accommodate such tables, relaxation can
+ // only increase an LEB fragment size here, not decrease it. See PR35809.
+ if (LF.isSigned())
+ encodeSLEB128(Value, OSE, OldSize);
+ else
+ encodeULEB128(Value, OSE, OldSize);
+ return OldSize != LF.getContents().size();
+}
+
+bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout,
+ MCDwarfLineAddrFragment &DF) {
+ MCContext &Context = Layout.getAssembler().getContext();
+ uint64_t OldSize = DF.getContents().size();
+ int64_t AddrDelta;
+ bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout);
+ assert(Abs && "We created a line delta with an invalid expression");
+ (void)Abs;
+ int64_t LineDelta;
+ LineDelta = DF.getLineDelta();
+ SmallVectorImpl<char> &Data = DF.getContents();
+ Data.clear();
+ raw_svector_ostream OSE(Data);
+ DF.getFixups().clear();
+
+ if (!getBackend().requiresDiffExpressionRelocations()) {
+ MCDwarfLineAddr::Encode(Context, getDWARFLinetableParams(), LineDelta,
+ AddrDelta, OSE);
+ } else {
+ uint32_t Offset;
+ uint32_t Size;
+ bool SetDelta = MCDwarfLineAddr::FixedEncode(Context,
+ getDWARFLinetableParams(),
+ LineDelta, AddrDelta,
+ OSE, &Offset, &Size);
+ // Add Fixups for address delta or new address.
+ const MCExpr *FixupExpr;
+ if (SetDelta) {
+ FixupExpr = &DF.getAddrDelta();
+ } else {
+ const MCBinaryExpr *ABE = cast<MCBinaryExpr>(&DF.getAddrDelta());
+ FixupExpr = ABE->getLHS();
+ }
+ DF.getFixups().push_back(
+ MCFixup::create(Offset, FixupExpr,
+ MCFixup::getKindForSize(Size, false /*isPCRel*/)));
+ }
+
+ return OldSize != Data.size();
+}
+
+bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout,
+ MCDwarfCallFrameFragment &DF) {
+ MCContext &Context = Layout.getAssembler().getContext();
+ uint64_t OldSize = DF.getContents().size();
+ int64_t AddrDelta;
+ bool Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout);
+ assert(Abs && "We created call frame with an invalid expression");
+ (void) Abs;
+ SmallVectorImpl<char> &Data = DF.getContents();
+ Data.clear();
+ raw_svector_ostream OSE(Data);
+ DF.getFixups().clear();
+
+ if (getBackend().requiresDiffExpressionRelocations()) {
+ uint32_t Offset;
+ uint32_t Size;
+ MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE, &Offset,
+ &Size);
+ if (Size) {
+ DF.getFixups().push_back(MCFixup::create(
+ Offset, &DF.getAddrDelta(),
+ MCFixup::getKindForSizeInBits(Size /*In bits.*/, false /*isPCRel*/)));
+ }
+ } else {
+ MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE);
+ }
+
+ return OldSize != Data.size();
+}
+
+bool MCAssembler::relaxCVInlineLineTable(MCAsmLayout &Layout,
+ MCCVInlineLineTableFragment &F) {
+ unsigned OldSize = F.getContents().size();
+ getContext().getCVContext().encodeInlineLineTable(Layout, F);
+ return OldSize != F.getContents().size();
+}
+
+bool MCAssembler::relaxCVDefRange(MCAsmLayout &Layout,
+ MCCVDefRangeFragment &F) {
+ unsigned OldSize = F.getContents().size();
+ getContext().getCVContext().encodeDefRange(Layout, F);
+ return OldSize != F.getContents().size();
+}
+
+bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSection &Sec) {
+ // Holds the first fragment which needed relaxing during this layout. It will
+ // remain NULL if none were relaxed.
+ // When a fragment is relaxed, all the fragments following it should get
+ // invalidated because their offset is going to change.
+ MCFragment *FirstRelaxedFragment = nullptr;
+
+ // Attempt to relax all the fragments in the section.
+ for (MCSection::iterator I = Sec.begin(), IE = Sec.end(); I != IE; ++I) {
+ // Check if this is a fragment that needs relaxation.
+ bool RelaxedFrag = false;
+ switch(I->getKind()) {
+ default:
+ break;
+ case MCFragment::FT_Relaxable:
+ assert(!getRelaxAll() &&
+ "Did not expect a MCRelaxableFragment in RelaxAll mode");
+ RelaxedFrag = relaxInstruction(Layout, *cast<MCRelaxableFragment>(I));
+ break;
+ case MCFragment::FT_Dwarf:
+ RelaxedFrag = relaxDwarfLineAddr(Layout,
+ *cast<MCDwarfLineAddrFragment>(I));
+ break;
+ case MCFragment::FT_DwarfFrame:
+ RelaxedFrag =
+ relaxDwarfCallFrameFragment(Layout,
+ *cast<MCDwarfCallFrameFragment>(I));
+ break;
+ case MCFragment::FT_LEB:
+ RelaxedFrag = relaxLEB(Layout, *cast<MCLEBFragment>(I));
+ break;
+ case MCFragment::FT_Padding:
+ RelaxedFrag = relaxPaddingFragment(Layout, *cast<MCPaddingFragment>(I));
+ break;
+ case MCFragment::FT_CVInlineLines:
+ RelaxedFrag =
+ relaxCVInlineLineTable(Layout, *cast<MCCVInlineLineTableFragment>(I));
+ break;
+ case MCFragment::FT_CVDefRange:
+ RelaxedFrag = relaxCVDefRange(Layout, *cast<MCCVDefRangeFragment>(I));
+ break;
+ }
+ if (RelaxedFrag && !FirstRelaxedFragment)
+ FirstRelaxedFragment = &*I;
+ }
+ if (FirstRelaxedFragment) {
+ Layout.invalidateFragmentsFrom(FirstRelaxedFragment);
+ return true;
+ }
+ return false;
+}
+
+bool MCAssembler::layoutOnce(MCAsmLayout &Layout) {
+ ++stats::RelaxationSteps;
+
+ bool WasRelaxed = false;
+ for (iterator it = begin(), ie = end(); it != ie; ++it) {
+ MCSection &Sec = *it;
+ while (layoutSectionOnce(Layout, Sec))
+ WasRelaxed = true;
+ }
+
+ return WasRelaxed;
+}
+
+void MCAssembler::finishLayout(MCAsmLayout &Layout) {
+ assert(getBackendPtr() && "Expected assembler backend");
+ // The layout is done. Mark every fragment as valid.
+ for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) {
+ MCSection &Section = *Layout.getSectionOrder()[i];
+ Layout.getFragmentOffset(&*Section.rbegin());
+ computeFragmentSize(Layout, *Section.rbegin());
+ }
+ getBackend().finishLayout(*this, Layout);
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCAssembler::dump() const{
+ raw_ostream &OS = errs();
+
+ OS << "<MCAssembler\n";
+ OS << " Sections:[\n ";
+ for (const_iterator it = begin(), ie = end(); it != ie; ++it) {
+ if (it != begin()) OS << ",\n ";
+ it->dump();
+ }
+ OS << "],\n";
+ OS << " Symbols:[";
+
+ for (const_symbol_iterator it = symbol_begin(), ie = symbol_end(); it != ie; ++it) {
+ if (it != symbol_begin()) OS << ",\n ";
+ OS << "(";
+ it->dump();
+ OS << ", Index:" << it->getIndex() << ", ";
+ OS << ")";
+ }
+ OS << "]>\n";
+}
+#endif
diff --git a/llvm/lib/MC/MCCodeEmitter.cpp b/llvm/lib/MC/MCCodeEmitter.cpp
new file mode 100644
index 000000000000..0d114f12d58c
--- /dev/null
+++ b/llvm/lib/MC/MCCodeEmitter.cpp
@@ -0,0 +1,15 @@
+//===- MCCodeEmitter.cpp - Instruction Encoding ---------------------------===//
+//
+// 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/MCCodeEmitter.h"
+
+using namespace llvm;
+
+MCCodeEmitter::MCCodeEmitter() = default;
+
+MCCodeEmitter::~MCCodeEmitter() = default;
diff --git a/llvm/lib/MC/MCCodePadder.cpp b/llvm/lib/MC/MCCodePadder.cpp
new file mode 100644
index 000000000000..27a62f95a529
--- /dev/null
+++ b/llvm/lib/MC/MCCodePadder.cpp
@@ -0,0 +1,370 @@
+//===- MCCodePadder.cpp - Target MC Code Padder ---------------------------===//
+//
+// 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/MCAsmLayout.h"
+#include "llvm/MC/MCCodePadder.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include <algorithm>
+#include <limits>
+#include <numeric>
+
+using namespace llvm;
+
+//---------------------------------------------------------------------------
+// MCCodePadder
+//
+
+MCCodePadder::~MCCodePadder() {
+ for (auto *Policy : CodePaddingPolicies)
+ delete Policy;
+}
+
+bool MCCodePadder::addPolicy(MCCodePaddingPolicy *Policy) {
+ assert(Policy && "Policy must be valid");
+ return CodePaddingPolicies.insert(Policy).second;
+}
+
+void MCCodePadder::handleBasicBlockStart(MCObjectStreamer *OS,
+ const MCCodePaddingContext &Context) {
+ assert(OS != nullptr && "OS must be valid");
+ assert(this->OS == nullptr && "Still handling another basic block");
+ this->OS = OS;
+
+ ArePoliciesActive = usePoliciesForBasicBlock(Context);
+
+ bool InsertionPoint = basicBlockRequiresInsertionPoint(Context);
+ assert((!InsertionPoint ||
+ OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) &&
+ "Cannot insert padding nops right after an alignment fragment as it "
+ "will ruin the alignment");
+
+ uint64_t PoliciesMask = MCPaddingFragment::PFK_None;
+ if (ArePoliciesActive) {
+ PoliciesMask = std::accumulate(
+ CodePaddingPolicies.begin(), CodePaddingPolicies.end(),
+ MCPaddingFragment::PFK_None,
+ [&Context](uint64_t Mask,
+ const MCCodePaddingPolicy *Policy) -> uint64_t {
+ return Policy->basicBlockRequiresPaddingFragment(Context)
+ ? (Mask | Policy->getKindMask())
+ : Mask;
+ });
+ }
+
+ if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None) {
+ MCPaddingFragment *PaddingFragment = OS->getOrCreatePaddingFragment();
+ if (InsertionPoint)
+ PaddingFragment->setAsInsertionPoint();
+ PaddingFragment->setPaddingPoliciesMask(
+ PaddingFragment->getPaddingPoliciesMask() | PoliciesMask);
+ }
+}
+
+void MCCodePadder::handleBasicBlockEnd(const MCCodePaddingContext &Context) {
+ assert(this->OS != nullptr && "Not handling a basic block");
+ OS = nullptr;
+}
+
+void MCCodePadder::handleInstructionBegin(const MCInst &Inst) {
+ if (!OS)
+ return; // instruction was emitted outside a function
+
+ assert(CurrHandledInstFragment == nullptr && "Can't start handling an "
+ "instruction while still "
+ "handling another instruction");
+
+ bool InsertionPoint = instructionRequiresInsertionPoint(Inst);
+ assert((!InsertionPoint ||
+ OS->getCurrentFragment()->getKind() != MCFragment::FT_Align) &&
+ "Cannot insert padding nops right after an alignment fragment as it "
+ "will ruin the alignment");
+
+ uint64_t PoliciesMask = MCPaddingFragment::PFK_None;
+ if (ArePoliciesActive) {
+ PoliciesMask = std::accumulate(
+ CodePaddingPolicies.begin(), CodePaddingPolicies.end(),
+ MCPaddingFragment::PFK_None,
+ [&Inst](uint64_t Mask, const MCCodePaddingPolicy *Policy) -> uint64_t {
+ return Policy->instructionRequiresPaddingFragment(Inst)
+ ? (Mask | Policy->getKindMask())
+ : Mask;
+ });
+ }
+ MCFragment *CurrFragment = OS->getCurrentFragment();
+ // CurrFragment can be a previously created MCPaddingFragment. If so, let's
+ // update it with the information we have, such as the instruction that it
+ // should point to.
+ bool needToUpdateCurrFragment =
+ CurrFragment != nullptr &&
+ CurrFragment->getKind() == MCFragment::FT_Padding;
+ if (InsertionPoint || PoliciesMask != MCPaddingFragment::PFK_None ||
+ needToUpdateCurrFragment) {
+ // temporarily holding the fragment as CurrHandledInstFragment, to be
+ // updated after the instruction will be written
+ CurrHandledInstFragment = OS->getOrCreatePaddingFragment();
+ if (InsertionPoint)
+ CurrHandledInstFragment->setAsInsertionPoint();
+ CurrHandledInstFragment->setPaddingPoliciesMask(
+ CurrHandledInstFragment->getPaddingPoliciesMask() | PoliciesMask);
+ }
+}
+
+void MCCodePadder::handleInstructionEnd(const MCInst &Inst) {
+ if (!OS)
+ return; // instruction was emitted outside a function
+ if (CurrHandledInstFragment == nullptr)
+ return;
+
+ MCFragment *InstFragment = OS->getCurrentFragment();
+ if (MCDataFragment *InstDataFragment =
+ dyn_cast_or_null<MCDataFragment>(InstFragment))
+ // Inst is a fixed size instruction and was encoded into a MCDataFragment.
+ // Let the fragment hold it and its size. Its size is the current size of
+ // the data fragment, as the padding fragment was inserted right before it
+ // and nothing was written yet except Inst
+ CurrHandledInstFragment->setInstAndInstSize(
+ Inst, InstDataFragment->getContents().size());
+ else if (MCRelaxableFragment *InstRelaxableFragment =
+ dyn_cast_or_null<MCRelaxableFragment>(InstFragment))
+ // Inst may be relaxed and its size may vary.
+ // Let the fragment hold the instruction and the MCRelaxableFragment
+ // that's holding it.
+ CurrHandledInstFragment->setInstAndInstFragment(Inst,
+ InstRelaxableFragment);
+ else
+ llvm_unreachable("After encoding an instruction current fragment must be "
+ "either a MCDataFragment or a MCRelaxableFragment");
+
+ CurrHandledInstFragment = nullptr;
+}
+
+MCPFRange &MCCodePadder::getJurisdiction(MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) {
+ auto JurisdictionLocation = FragmentToJurisdiction.find(Fragment);
+ if (JurisdictionLocation != FragmentToJurisdiction.end())
+ return JurisdictionLocation->second;
+
+ MCPFRange Jurisdiction;
+
+ // Forward scanning the fragments in this section, starting from the given
+ // fragments, and adding relevant MCPaddingFragments to the Jurisdiction
+ for (MCFragment *CurrFragment = Fragment; CurrFragment != nullptr;
+ CurrFragment = CurrFragment->getNextNode()) {
+
+ MCPaddingFragment *CurrPaddingFragment =
+ dyn_cast<MCPaddingFragment>(CurrFragment);
+ if (CurrPaddingFragment == nullptr)
+ continue;
+
+ if (CurrPaddingFragment != Fragment &&
+ CurrPaddingFragment->isInsertionPoint())
+ // Found next insertion point Fragment. From now on it's its jurisdiction.
+ break;
+ for (const auto *Policy : CodePaddingPolicies) {
+ if (CurrPaddingFragment->hasPaddingPolicy(Policy->getKindMask())) {
+ Jurisdiction.push_back(CurrPaddingFragment);
+ break;
+ }
+ }
+ }
+
+ auto InsertionResult =
+ FragmentToJurisdiction.insert(std::make_pair(Fragment, Jurisdiction));
+ assert(InsertionResult.second &&
+ "Insertion to FragmentToJurisdiction failed");
+ return InsertionResult.first->second;
+}
+
+uint64_t MCCodePadder::getMaxWindowSize(MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) {
+ auto MaxFragmentSizeLocation = FragmentToMaxWindowSize.find(Fragment);
+ if (MaxFragmentSizeLocation != FragmentToMaxWindowSize.end())
+ return MaxFragmentSizeLocation->second;
+
+ MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout);
+ uint64_t JurisdictionMask = MCPaddingFragment::PFK_None;
+ for (const auto *Protege : Jurisdiction)
+ JurisdictionMask |= Protege->getPaddingPoliciesMask();
+
+ uint64_t MaxFragmentSize = UINT64_C(0);
+ for (const auto *Policy : CodePaddingPolicies)
+ if ((JurisdictionMask & Policy->getKindMask()) !=
+ MCPaddingFragment::PFK_None)
+ MaxFragmentSize = std::max(MaxFragmentSize, Policy->getWindowSize());
+
+ auto InsertionResult =
+ FragmentToMaxWindowSize.insert(std::make_pair(Fragment, MaxFragmentSize));
+ assert(InsertionResult.second &&
+ "Insertion to FragmentToMaxWindowSize failed");
+ return InsertionResult.first->second;
+}
+
+bool MCCodePadder::relaxFragment(MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) {
+ if (!Fragment->isInsertionPoint())
+ return false;
+ uint64_t OldSize = Fragment->getSize();
+
+ uint64_t MaxWindowSize = getMaxWindowSize(Fragment, Layout);
+ if (MaxWindowSize == UINT64_C(0))
+ return false;
+ assert(isPowerOf2_64(MaxWindowSize) &&
+ "MaxWindowSize must be an integer power of 2");
+ uint64_t SectionAlignment = Fragment->getParent()->getAlignment();
+ assert(isPowerOf2_64(SectionAlignment) &&
+ "SectionAlignment must be an integer power of 2");
+
+ MCPFRange &Jurisdiction = getJurisdiction(Fragment, Layout);
+ uint64_t OptimalSize = UINT64_C(0);
+ double OptimalWeight = std::numeric_limits<double>::max();
+ uint64_t MaxFragmentSize = MaxWindowSize - UINT16_C(1);
+ for (uint64_t Size = UINT64_C(0); Size <= MaxFragmentSize; ++Size) {
+ Fragment->setSize(Size);
+ Layout.invalidateFragmentsFrom(Fragment);
+ double SizeWeight = 0.0;
+ // The section is guaranteed to be aligned to SectionAlignment, but that
+ // doesn't guarantee the exact section offset w.r.t. the policies window
+ // size.
+ // As a concrete example, the section could be aligned to 16B, but a
+ // policy's window size can be 32B. That means that the section actual start
+ // address can either be 0mod32 or 16mod32. The said policy will act
+ // differently for each case, so we need to take both into consideration.
+ for (uint64_t Offset = UINT64_C(0); Offset < MaxWindowSize;
+ Offset += SectionAlignment) {
+ double OffsetWeight = std::accumulate(
+ CodePaddingPolicies.begin(), CodePaddingPolicies.end(), 0.0,
+ [&Jurisdiction, &Offset, &Layout](
+ double Weight, const MCCodePaddingPolicy *Policy) -> double {
+ double PolicyWeight =
+ Policy->computeRangePenaltyWeight(Jurisdiction, Offset, Layout);
+ assert(PolicyWeight >= 0.0 && "A penalty weight must be positive");
+ return Weight + PolicyWeight;
+ });
+ SizeWeight = std::max(SizeWeight, OffsetWeight);
+ }
+ if (SizeWeight < OptimalWeight) {
+ OptimalWeight = SizeWeight;
+ OptimalSize = Size;
+ }
+ if (OptimalWeight == 0.0)
+ break;
+ }
+
+ Fragment->setSize(OptimalSize);
+ Layout.invalidateFragmentsFrom(Fragment);
+ return OldSize != OptimalSize;
+}
+
+//---------------------------------------------------------------------------
+// MCCodePaddingPolicy
+//
+
+uint64_t MCCodePaddingPolicy::getNextFragmentOffset(const MCFragment *Fragment,
+ const MCAsmLayout &Layout) {
+ assert(Fragment != nullptr && "Fragment cannot be null");
+ MCFragment const *NextFragment = Fragment->getNextNode();
+ return NextFragment == nullptr
+ ? Layout.getSectionAddressSize(Fragment->getParent())
+ : Layout.getFragmentOffset(NextFragment);
+}
+
+uint64_t
+MCCodePaddingPolicy::getFragmentInstByte(const MCPaddingFragment *Fragment,
+ MCAsmLayout &Layout) const {
+ uint64_t InstByte = getNextFragmentOffset(Fragment, Layout);
+ if (InstByteIsLastByte)
+ InstByte += Fragment->getInstSize() - UINT64_C(1);
+ return InstByte;
+}
+
+uint64_t
+MCCodePaddingPolicy::computeWindowEndAddress(const MCPaddingFragment *Fragment,
+ uint64_t Offset,
+ MCAsmLayout &Layout) const {
+ uint64_t InstByte = getFragmentInstByte(Fragment, Layout);
+ return alignTo(InstByte + UINT64_C(1) + Offset, WindowSize) - Offset;
+}
+
+double MCCodePaddingPolicy::computeRangePenaltyWeight(
+ const MCPFRange &Range, uint64_t Offset, MCAsmLayout &Layout) const {
+
+ SmallVector<MCPFRange, 8> Windows;
+ SmallVector<MCPFRange, 8>::iterator CurrWindowLocation = Windows.end();
+ for (const MCPaddingFragment *Fragment : Range) {
+ if (!Fragment->hasPaddingPolicy(getKindMask()))
+ continue;
+ uint64_t FragmentWindowEndAddress =
+ computeWindowEndAddress(Fragment, Offset, Layout);
+ if (CurrWindowLocation == Windows.end() ||
+ FragmentWindowEndAddress !=
+ computeWindowEndAddress(*CurrWindowLocation->begin(), Offset,
+ Layout)) {
+ // next window is starting
+ Windows.push_back(MCPFRange());
+ CurrWindowLocation = Windows.end() - 1;
+ }
+ CurrWindowLocation->push_back(Fragment);
+ }
+
+ if (Windows.empty())
+ return 0.0;
+
+ double RangeWeight = 0.0;
+ SmallVector<MCPFRange, 8>::iterator I = Windows.begin();
+ RangeWeight += computeFirstWindowPenaltyWeight(*I, Offset, Layout);
+ ++I;
+ RangeWeight += std::accumulate(
+ I, Windows.end(), 0.0,
+ [this, &Layout, &Offset](double Weight, MCPFRange &Window) -> double {
+ return Weight += computeWindowPenaltyWeight(Window, Offset, Layout);
+ });
+ return RangeWeight;
+}
+
+double MCCodePaddingPolicy::computeFirstWindowPenaltyWeight(
+ const MCPFRange &Window, uint64_t Offset, MCAsmLayout &Layout) const {
+ if (Window.empty())
+ return 0.0;
+ uint64_t WindowEndAddress =
+ computeWindowEndAddress(*Window.begin(), Offset, Layout);
+
+ MCPFRange FullWindowFirstPart; // will hold all the fragments that are in the
+ // same window as the fragments in the given
+ // window but their penalty weight should not
+ // be added
+ for (const MCFragment *Fragment = (*Window.begin())->getPrevNode();
+ Fragment != nullptr; Fragment = Fragment->getPrevNode()) {
+ const MCPaddingFragment *PaddingNopFragment =
+ dyn_cast<MCPaddingFragment>(Fragment);
+ if (PaddingNopFragment == nullptr ||
+ !PaddingNopFragment->hasPaddingPolicy(getKindMask()))
+ continue;
+ if (WindowEndAddress !=
+ computeWindowEndAddress(PaddingNopFragment, Offset, Layout))
+ break;
+
+ FullWindowFirstPart.push_back(PaddingNopFragment);
+ }
+
+ std::reverse(FullWindowFirstPart.begin(), FullWindowFirstPart.end());
+ double FullWindowFirstPartWeight =
+ computeWindowPenaltyWeight(FullWindowFirstPart, Offset, Layout);
+
+ MCPFRange FullWindow(
+ FullWindowFirstPart); // will hold all the fragments that are in the
+ // same window as the fragments in the given
+ // window, whether their weight should be added
+ // or not
+ FullWindow.append(Window.begin(), Window.end());
+ double FullWindowWeight =
+ computeWindowPenaltyWeight(FullWindow, Offset, Layout);
+
+ assert(FullWindowWeight >= FullWindowFirstPartWeight &&
+ "More fragments necessarily means bigger weight");
+ return FullWindowWeight - FullWindowFirstPartWeight;
+}
diff --git a/llvm/lib/MC/MCCodeView.cpp b/llvm/lib/MC/MCCodeView.cpp
new file mode 100644
index 000000000000..1a71b542bd06
--- /dev/null
+++ b/llvm/lib/MC/MCCodeView.cpp
@@ -0,0 +1,696 @@
+//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Holds state from .cv_file and .cv_loc directives for later emission.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/EndianStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+CodeViewContext::CodeViewContext() {}
+
+CodeViewContext::~CodeViewContext() {
+ // If someone inserted strings into the string table but never actually
+ // emitted them somewhere, clean up the fragment.
+ if (!InsertedStrTabFragment)
+ delete StrTabFragment;
+}
+
+/// This is a valid number for use with .cv_loc if we've already seen a .cv_file
+/// for it.
+bool CodeViewContext::isValidFileNumber(unsigned FileNumber) const {
+ unsigned Idx = FileNumber - 1;
+ if (Idx < Files.size())
+ return Files[Idx].Assigned;
+ return false;
+}
+
+bool CodeViewContext::addFile(MCStreamer &OS, unsigned FileNumber,
+ StringRef Filename,
+ ArrayRef<uint8_t> ChecksumBytes,
+ uint8_t ChecksumKind) {
+ assert(FileNumber > 0);
+ auto FilenameOffset = addToStringTable(Filename);
+ Filename = FilenameOffset.first;
+ unsigned Idx = FileNumber - 1;
+ if (Idx >= Files.size())
+ Files.resize(Idx + 1);
+
+ if (Filename.empty())
+ Filename = "<stdin>";
+
+ if (Files[Idx].Assigned)
+ return false;
+
+ FilenameOffset = addToStringTable(Filename);
+ Filename = FilenameOffset.first;
+ unsigned Offset = FilenameOffset.second;
+
+ auto ChecksumOffsetSymbol =
+ OS.getContext().createTempSymbol("checksum_offset", false);
+ Files[Idx].StringTableOffset = Offset;
+ Files[Idx].ChecksumTableOffset = ChecksumOffsetSymbol;
+ Files[Idx].Assigned = true;
+ Files[Idx].Checksum = ChecksumBytes;
+ Files[Idx].ChecksumKind = ChecksumKind;
+
+ return true;
+}
+
+MCCVFunctionInfo *CodeViewContext::getCVFunctionInfo(unsigned FuncId) {
+ if (FuncId >= Functions.size())
+ return nullptr;
+ if (Functions[FuncId].isUnallocatedFunctionInfo())
+ return nullptr;
+ return &Functions[FuncId];
+}
+
+bool CodeViewContext::recordFunctionId(unsigned FuncId) {
+ if (FuncId >= Functions.size())
+ Functions.resize(FuncId + 1);
+
+ // Return false if this function info was already allocated.
+ if (!Functions[FuncId].isUnallocatedFunctionInfo())
+ return false;
+
+ // Mark this as an allocated normal function, and leave the rest alone.
+ Functions[FuncId].ParentFuncIdPlusOne = MCCVFunctionInfo::FunctionSentinel;
+ return true;
+}
+
+bool CodeViewContext::recordInlinedCallSiteId(unsigned FuncId, unsigned IAFunc,
+ unsigned IAFile, unsigned IALine,
+ unsigned IACol) {
+ if (FuncId >= Functions.size())
+ Functions.resize(FuncId + 1);
+
+ // Return false if this function info was already allocated.
+ if (!Functions[FuncId].isUnallocatedFunctionInfo())
+ return false;
+
+ MCCVFunctionInfo::LineInfo InlinedAt;
+ InlinedAt.File = IAFile;
+ InlinedAt.Line = IALine;
+ InlinedAt.Col = IACol;
+
+ // Mark this as an inlined call site and record call site line info.
+ MCCVFunctionInfo *Info = &Functions[FuncId];
+ Info->ParentFuncIdPlusOne = IAFunc + 1;
+ Info->InlinedAt = InlinedAt;
+
+ // Walk up the call chain adding this function id to the InlinedAtMap of all
+ // transitive callers until we hit a real function.
+ while (Info->isInlinedCallSite()) {
+ InlinedAt = Info->InlinedAt;
+ Info = getCVFunctionInfo(Info->getParentFuncId());
+ Info->InlinedAtMap[FuncId] = InlinedAt;
+ }
+
+ return true;
+}
+
+void CodeViewContext::recordCVLoc(MCContext &Ctx, const MCSymbol *Label,
+ unsigned FunctionId, unsigned FileNo,
+ unsigned Line, unsigned Column,
+ bool PrologueEnd, bool IsStmt) {
+ addLineEntry(MCCVLoc{
+ Label, FunctionId, FileNo, Line, Column, PrologueEnd, IsStmt});
+}
+
+MCDataFragment *CodeViewContext::getStringTableFragment() {
+ if (!StrTabFragment) {
+ StrTabFragment = new MCDataFragment();
+ // Start a new string table out with a null byte.
+ StrTabFragment->getContents().push_back('\0');
+ }
+ return StrTabFragment;
+}
+
+std::pair<StringRef, unsigned> CodeViewContext::addToStringTable(StringRef S) {
+ SmallVectorImpl<char> &Contents = getStringTableFragment()->getContents();
+ auto Insertion =
+ StringTable.insert(std::make_pair(S, unsigned(Contents.size())));
+ // Return the string from the table, since it is stable.
+ std::pair<StringRef, unsigned> Ret =
+ std::make_pair(Insertion.first->first(), Insertion.first->second);
+ if (Insertion.second) {
+ // The string map key is always null terminated.
+ Contents.append(Ret.first.begin(), Ret.first.end() + 1);
+ }
+ return Ret;
+}
+
+unsigned CodeViewContext::getStringTableOffset(StringRef S) {
+ // A string table offset of zero is always the empty string.
+ if (S.empty())
+ return 0;
+ auto I = StringTable.find(S);
+ assert(I != StringTable.end());
+ return I->second;
+}
+
+void CodeViewContext::emitStringTable(MCObjectStreamer &OS) {
+ MCContext &Ctx = OS.getContext();
+ MCSymbol *StringBegin = Ctx.createTempSymbol("strtab_begin", false),
+ *StringEnd = Ctx.createTempSymbol("strtab_end", false);
+
+ OS.EmitIntValue(unsigned(DebugSubsectionKind::StringTable), 4);
+ OS.emitAbsoluteSymbolDiff(StringEnd, StringBegin, 4);
+ OS.EmitLabel(StringBegin);
+
+ // Put the string table data fragment here, if we haven't already put it
+ // somewhere else. If somebody wants two string tables in their .s file, one
+ // will just be empty.
+ if (!InsertedStrTabFragment) {
+ OS.insert(getStringTableFragment());
+ InsertedStrTabFragment = true;
+ }
+
+ OS.EmitValueToAlignment(4, 0);
+
+ OS.EmitLabel(StringEnd);
+}
+
+void CodeViewContext::emitFileChecksums(MCObjectStreamer &OS) {
+ // Do nothing if there are no file checksums. Microsoft's linker rejects empty
+ // CodeView substreams.
+ if (Files.empty())
+ return;
+
+ MCContext &Ctx = OS.getContext();
+ MCSymbol *FileBegin = Ctx.createTempSymbol("filechecksums_begin", false),
+ *FileEnd = Ctx.createTempSymbol("filechecksums_end", false);
+
+ OS.EmitIntValue(unsigned(DebugSubsectionKind::FileChecksums), 4);
+ OS.emitAbsoluteSymbolDiff(FileEnd, FileBegin, 4);
+ OS.EmitLabel(FileBegin);
+
+ unsigned CurrentOffset = 0;
+
+ // Emit an array of FileChecksum entries. We index into this table using the
+ // user-provided file number. Each entry may be a variable number of bytes
+ // determined by the checksum kind and size.
+ for (auto File : Files) {
+ OS.EmitAssignment(File.ChecksumTableOffset,
+ MCConstantExpr::create(CurrentOffset, Ctx));
+ CurrentOffset += 4; // String table offset.
+ if (!File.ChecksumKind) {
+ CurrentOffset +=
+ 4; // One byte each for checksum size and kind, then align to 4 bytes.
+ } else {
+ CurrentOffset += 2; // One byte each for checksum size and kind.
+ CurrentOffset += File.Checksum.size();
+ CurrentOffset = alignTo(CurrentOffset, 4);
+ }
+
+ OS.EmitIntValue(File.StringTableOffset, 4);
+
+ if (!File.ChecksumKind) {
+ // There is no checksum. Therefore zero the next two fields and align
+ // back to 4 bytes.
+ OS.EmitIntValue(0, 4);
+ continue;
+ }
+ OS.EmitIntValue(static_cast<uint8_t>(File.Checksum.size()), 1);
+ OS.EmitIntValue(File.ChecksumKind, 1);
+ OS.EmitBytes(toStringRef(File.Checksum));
+ OS.EmitValueToAlignment(4);
+ }
+
+ OS.EmitLabel(FileEnd);
+
+ ChecksumOffsetsAssigned = true;
+}
+
+// Output checksum table offset of the given file number. It is possible that
+// not all files have been registered yet, and so the offset cannot be
+// calculated. In this case a symbol representing the offset is emitted, and
+// the value of this symbol will be fixed up at a later time.
+void CodeViewContext::emitFileChecksumOffset(MCObjectStreamer &OS,
+ unsigned FileNo) {
+ unsigned Idx = FileNo - 1;
+
+ if (Idx >= Files.size())
+ Files.resize(Idx + 1);
+
+ if (ChecksumOffsetsAssigned) {
+ OS.EmitSymbolValue(Files[Idx].ChecksumTableOffset, 4);
+ return;
+ }
+
+ const MCSymbolRefExpr *SRE =
+ MCSymbolRefExpr::create(Files[Idx].ChecksumTableOffset, OS.getContext());
+
+ OS.EmitValueImpl(SRE, 4);
+}
+
+void CodeViewContext::addLineEntry(const MCCVLoc &LineEntry) {
+ size_t Offset = MCCVLines.size();
+ auto I = MCCVLineStartStop.insert(
+ {LineEntry.getFunctionId(), {Offset, Offset + 1}});
+ if (!I.second)
+ I.first->second.second = Offset + 1;
+ MCCVLines.push_back(LineEntry);
+}
+
+std::vector<MCCVLoc>
+CodeViewContext::getFunctionLineEntries(unsigned FuncId) {
+ std::vector<MCCVLoc> FilteredLines;
+ auto I = MCCVLineStartStop.find(FuncId);
+ if (I != MCCVLineStartStop.end()) {
+ MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(FuncId);
+ for (size_t Idx = I->second.first, End = I->second.second; Idx != End;
+ ++Idx) {
+ unsigned LocationFuncId = MCCVLines[Idx].getFunctionId();
+ if (LocationFuncId == FuncId) {
+ // This was a .cv_loc directly for FuncId, so record it.
+ FilteredLines.push_back(MCCVLines[Idx]);
+ } else {
+ // Check if the current location is inlined in this function. If it is,
+ // synthesize a statement .cv_loc at the original inlined call site.
+ auto I = SiteInfo->InlinedAtMap.find(LocationFuncId);
+ if (I != SiteInfo->InlinedAtMap.end()) {
+ MCCVFunctionInfo::LineInfo &IA = I->second;
+ // Only add the location if it differs from the previous location.
+ // Large inlined calls will have many .cv_loc entries and we only need
+ // one line table entry in the parent function.
+ if (FilteredLines.empty() ||
+ FilteredLines.back().getFileNum() != IA.File ||
+ FilteredLines.back().getLine() != IA.Line ||
+ FilteredLines.back().getColumn() != IA.Col) {
+ FilteredLines.push_back(MCCVLoc(
+ MCCVLines[Idx].getLabel(),
+ FuncId, IA.File, IA.Line, IA.Col, false, false));
+ }
+ }
+ }
+ }
+ }
+ return FilteredLines;
+}
+
+std::pair<size_t, size_t> CodeViewContext::getLineExtent(unsigned FuncId) {
+ auto I = MCCVLineStartStop.find(FuncId);
+ // Return an empty extent if there are no cv_locs for this function id.
+ if (I == MCCVLineStartStop.end())
+ return {~0ULL, 0};
+ return I->second;
+}
+
+ArrayRef<MCCVLoc> CodeViewContext::getLinesForExtent(size_t L, size_t R) {
+ if (R <= L)
+ return None;
+ if (L >= MCCVLines.size())
+ return None;
+ return makeArrayRef(&MCCVLines[L], R - L);
+}
+
+void CodeViewContext::emitLineTableForFunction(MCObjectStreamer &OS,
+ unsigned FuncId,
+ const MCSymbol *FuncBegin,
+ const MCSymbol *FuncEnd) {
+ MCContext &Ctx = OS.getContext();
+ MCSymbol *LineBegin = Ctx.createTempSymbol("linetable_begin", false),
+ *LineEnd = Ctx.createTempSymbol("linetable_end", false);
+
+ OS.EmitIntValue(unsigned(DebugSubsectionKind::Lines), 4);
+ OS.emitAbsoluteSymbolDiff(LineEnd, LineBegin, 4);
+ OS.EmitLabel(LineBegin);
+ OS.EmitCOFFSecRel32(FuncBegin, /*Offset=*/0);
+ OS.EmitCOFFSectionIndex(FuncBegin);
+
+ // Actual line info.
+ std::vector<MCCVLoc> Locs = getFunctionLineEntries(FuncId);
+ bool HaveColumns = any_of(Locs, [](const MCCVLoc &LineEntry) {
+ return LineEntry.getColumn() != 0;
+ });
+ OS.EmitIntValue(HaveColumns ? int(LF_HaveColumns) : 0, 2);
+ OS.emitAbsoluteSymbolDiff(FuncEnd, FuncBegin, 4);
+
+ for (auto I = Locs.begin(), E = Locs.end(); I != E;) {
+ // Emit a file segment for the run of locations that share a file id.
+ unsigned CurFileNum = I->getFileNum();
+ auto FileSegEnd =
+ std::find_if(I, E, [CurFileNum](const MCCVLoc &Loc) {
+ return Loc.getFileNum() != CurFileNum;
+ });
+ unsigned EntryCount = FileSegEnd - I;
+ OS.AddComment(
+ "Segment for file '" +
+ Twine(getStringTableFragment()
+ ->getContents()[Files[CurFileNum - 1].StringTableOffset]) +
+ "' begins");
+ OS.EmitCVFileChecksumOffsetDirective(CurFileNum);
+ OS.EmitIntValue(EntryCount, 4);
+ uint32_t SegmentSize = 12;
+ SegmentSize += 8 * EntryCount;
+ if (HaveColumns)
+ SegmentSize += 4 * EntryCount;
+ OS.EmitIntValue(SegmentSize, 4);
+
+ for (auto J = I; J != FileSegEnd; ++J) {
+ OS.emitAbsoluteSymbolDiff(J->getLabel(), FuncBegin, 4);
+ unsigned LineData = J->getLine();
+ if (J->isStmt())
+ LineData |= LineInfo::StatementFlag;
+ OS.EmitIntValue(LineData, 4);
+ }
+ if (HaveColumns) {
+ for (auto J = I; J != FileSegEnd; ++J) {
+ OS.EmitIntValue(J->getColumn(), 2);
+ OS.EmitIntValue(0, 2);
+ }
+ }
+ I = FileSegEnd;
+ }
+ OS.EmitLabel(LineEnd);
+}
+
+static bool compressAnnotation(uint32_t Data, SmallVectorImpl<char> &Buffer) {
+ if (isUInt<7>(Data)) {
+ Buffer.push_back(Data);
+ return true;
+ }
+
+ if (isUInt<14>(Data)) {
+ Buffer.push_back((Data >> 8) | 0x80);
+ Buffer.push_back(Data & 0xff);
+ return true;
+ }
+
+ if (isUInt<29>(Data)) {
+ Buffer.push_back((Data >> 24) | 0xC0);
+ Buffer.push_back((Data >> 16) & 0xff);
+ Buffer.push_back((Data >> 8) & 0xff);
+ Buffer.push_back(Data & 0xff);
+ return true;
+ }
+
+ return false;
+}
+
+static bool compressAnnotation(BinaryAnnotationsOpCode Annotation,
+ SmallVectorImpl<char> &Buffer) {
+ return compressAnnotation(static_cast<uint32_t>(Annotation), Buffer);
+}
+
+static uint32_t encodeSignedNumber(uint32_t Data) {
+ if (Data >> 31)
+ return ((-Data) << 1) | 1;
+ return Data << 1;
+}
+
+void CodeViewContext::emitInlineLineTableForFunction(MCObjectStreamer &OS,
+ unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {
+ // Create and insert a fragment into the current section that will be encoded
+ // later.
+ new MCCVInlineLineTableFragment(PrimaryFunctionId, SourceFileId,
+ SourceLineNum, FnStartSym, FnEndSym,
+ OS.getCurrentSectionOnly());
+}
+
+MCFragment *CodeViewContext::emitDefRange(
+ MCObjectStreamer &OS,
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ StringRef FixedSizePortion) {
+ // Create and insert a fragment into the current section that will be encoded
+ // later.
+ return new MCCVDefRangeFragment(Ranges, FixedSizePortion,
+ OS.getCurrentSectionOnly());
+}
+
+static unsigned computeLabelDiff(MCAsmLayout &Layout, const MCSymbol *Begin,
+ const MCSymbol *End) {
+ MCContext &Ctx = Layout.getAssembler().getContext();
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+ const MCExpr *BeginRef = MCSymbolRefExpr::create(Begin, Variant, Ctx),
+ *EndRef = MCSymbolRefExpr::create(End, Variant, Ctx);
+ const MCExpr *AddrDelta =
+ MCBinaryExpr::create(MCBinaryExpr::Sub, EndRef, BeginRef, Ctx);
+ int64_t Result;
+ bool Success = AddrDelta->evaluateKnownAbsolute(Result, Layout);
+ assert(Success && "failed to evaluate label difference as absolute");
+ (void)Success;
+ assert(Result >= 0 && "negative label difference requested");
+ assert(Result < UINT_MAX && "label difference greater than 2GB");
+ return unsigned(Result);
+}
+
+void CodeViewContext::encodeInlineLineTable(MCAsmLayout &Layout,
+ MCCVInlineLineTableFragment &Frag) {
+ size_t LocBegin;
+ size_t LocEnd;
+ std::tie(LocBegin, LocEnd) = getLineExtent(Frag.SiteFuncId);
+
+ // Include all child inline call sites in our .cv_loc extent.
+ MCCVFunctionInfo *SiteInfo = getCVFunctionInfo(Frag.SiteFuncId);
+ for (auto &KV : SiteInfo->InlinedAtMap) {
+ unsigned ChildId = KV.first;
+ auto Extent = getLineExtent(ChildId);
+ LocBegin = std::min(LocBegin, Extent.first);
+ LocEnd = std::max(LocEnd, Extent.second);
+ }
+
+ if (LocBegin >= LocEnd)
+ return;
+ ArrayRef<MCCVLoc> Locs = getLinesForExtent(LocBegin, LocEnd);
+ if (Locs.empty())
+ return;
+
+ // Check that the locations are all in the same section.
+#ifndef NDEBUG
+ const MCSection *FirstSec = &Locs.front().getLabel()->getSection();
+ for (const MCCVLoc &Loc : Locs) {
+ if (&Loc.getLabel()->getSection() != FirstSec) {
+ errs() << ".cv_loc " << Loc.getFunctionId() << ' ' << Loc.getFileNum()
+ << ' ' << Loc.getLine() << ' ' << Loc.getColumn()
+ << " is in the wrong section\n";
+ llvm_unreachable(".cv_loc crosses sections");
+ }
+ }
+#endif
+
+ // Make an artificial start location using the function start and the inlinee
+ // lines start location information. All deltas start relative to this
+ // location.
+ MCCVLoc StartLoc = Locs.front();
+ StartLoc.setLabel(Frag.getFnStartSym());
+ StartLoc.setFileNum(Frag.StartFileId);
+ StartLoc.setLine(Frag.StartLineNum);
+ bool HaveOpenRange = false;
+
+ const MCSymbol *LastLabel = Frag.getFnStartSym();
+ MCCVFunctionInfo::LineInfo LastSourceLoc, CurSourceLoc;
+ LastSourceLoc.File = Frag.StartFileId;
+ LastSourceLoc.Line = Frag.StartLineNum;
+
+ SmallVectorImpl<char> &Buffer = Frag.getContents();
+ Buffer.clear(); // Clear old contents if we went through relaxation.
+ for (const MCCVLoc &Loc : Locs) {
+ // Exit early if our line table would produce an oversized InlineSiteSym
+ // record. Account for the ChangeCodeLength annotation emitted after the
+ // loop ends.
+ constexpr uint32_t InlineSiteSize = 12;
+ constexpr uint32_t AnnotationSize = 8;
+ size_t MaxBufferSize = MaxRecordLength - InlineSiteSize - AnnotationSize;
+ if (Buffer.size() >= MaxBufferSize)
+ break;
+
+ if (Loc.getFunctionId() == Frag.SiteFuncId) {
+ CurSourceLoc.File = Loc.getFileNum();
+ CurSourceLoc.Line = Loc.getLine();
+ } else {
+ auto I = SiteInfo->InlinedAtMap.find(Loc.getFunctionId());
+ if (I != SiteInfo->InlinedAtMap.end()) {
+ // This .cv_loc is from a child inline call site. Use the source
+ // location of the inlined call site instead of the .cv_loc directive
+ // source location.
+ CurSourceLoc = I->second;
+ } else {
+ // We've hit a cv_loc not attributed to this inline call site. Use this
+ // label to end the PC range.
+ if (HaveOpenRange) {
+ unsigned Length = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
+ compressAnnotation(Length, Buffer);
+ LastLabel = Loc.getLabel();
+ }
+ HaveOpenRange = false;
+ continue;
+ }
+ }
+
+ // Skip this .cv_loc if we have an open range and this isn't a meaningful
+ // source location update. The current table format does not support column
+ // info, so we can skip updates for those.
+ if (HaveOpenRange && CurSourceLoc.File == LastSourceLoc.File &&
+ CurSourceLoc.Line == LastSourceLoc.Line)
+ continue;
+
+ HaveOpenRange = true;
+
+ if (CurSourceLoc.File != LastSourceLoc.File) {
+ unsigned FileOffset = static_cast<const MCConstantExpr *>(
+ Files[CurSourceLoc.File - 1]
+ .ChecksumTableOffset->getVariableValue())
+ ->getValue();
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeFile, Buffer);
+ compressAnnotation(FileOffset, Buffer);
+ }
+
+ int LineDelta = CurSourceLoc.Line - LastSourceLoc.Line;
+ unsigned EncodedLineDelta = encodeSignedNumber(LineDelta);
+ unsigned CodeDelta = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ if (CodeDelta == 0 && LineDelta != 0) {
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
+ compressAnnotation(EncodedLineDelta, Buffer);
+ } else if (EncodedLineDelta < 0x8 && CodeDelta <= 0xf) {
+ // The ChangeCodeOffsetAndLineOffset combination opcode is used when the
+ // encoded line delta uses 3 or fewer set bits and the code offset fits
+ // in one nibble.
+ unsigned Operand = (EncodedLineDelta << 4) | CodeDelta;
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset,
+ Buffer);
+ compressAnnotation(Operand, Buffer);
+ } else {
+ // Otherwise use the separate line and code deltas.
+ if (LineDelta != 0) {
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeLineOffset, Buffer);
+ compressAnnotation(EncodedLineDelta, Buffer);
+ }
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeOffset, Buffer);
+ compressAnnotation(CodeDelta, Buffer);
+ }
+
+ LastLabel = Loc.getLabel();
+ LastSourceLoc = CurSourceLoc;
+ }
+
+ assert(HaveOpenRange);
+
+ unsigned EndSymLength =
+ computeLabelDiff(Layout, LastLabel, Frag.getFnEndSym());
+ unsigned LocAfterLength = ~0U;
+ ArrayRef<MCCVLoc> LocAfter = getLinesForExtent(LocEnd, LocEnd + 1);
+ if (!LocAfter.empty()) {
+ // Only try to compute this difference if we're in the same section.
+ const MCCVLoc &Loc = LocAfter[0];
+ if (&Loc.getLabel()->getSection() == &LastLabel->getSection())
+ LocAfterLength = computeLabelDiff(Layout, LastLabel, Loc.getLabel());
+ }
+
+ compressAnnotation(BinaryAnnotationsOpCode::ChangeCodeLength, Buffer);
+ compressAnnotation(std::min(EndSymLength, LocAfterLength), Buffer);
+}
+
+void CodeViewContext::encodeDefRange(MCAsmLayout &Layout,
+ MCCVDefRangeFragment &Frag) {
+ MCContext &Ctx = Layout.getAssembler().getContext();
+ SmallVectorImpl<char> &Contents = Frag.getContents();
+ Contents.clear();
+ SmallVectorImpl<MCFixup> &Fixups = Frag.getFixups();
+ Fixups.clear();
+ raw_svector_ostream OS(Contents);
+
+ // Compute all the sizes up front.
+ SmallVector<std::pair<unsigned, unsigned>, 4> GapAndRangeSizes;
+ const MCSymbol *LastLabel = nullptr;
+ for (std::pair<const MCSymbol *, const MCSymbol *> Range : Frag.getRanges()) {
+ unsigned GapSize =
+ LastLabel ? computeLabelDiff(Layout, LastLabel, Range.first) : 0;
+ unsigned RangeSize = computeLabelDiff(Layout, Range.first, Range.second);
+ GapAndRangeSizes.push_back({GapSize, RangeSize});
+ LastLabel = Range.second;
+ }
+
+ // Write down each range where the variable is defined.
+ for (size_t I = 0, E = Frag.getRanges().size(); I != E;) {
+ // If the range size of multiple consecutive ranges is under the max,
+ // combine the ranges and emit some gaps.
+ const MCSymbol *RangeBegin = Frag.getRanges()[I].first;
+ unsigned RangeSize = GapAndRangeSizes[I].second;
+ size_t J = I + 1;
+ for (; J != E; ++J) {
+ unsigned GapAndRangeSize = GapAndRangeSizes[J].first + GapAndRangeSizes[J].second;
+ if (RangeSize + GapAndRangeSize > MaxDefRange)
+ break;
+ RangeSize += GapAndRangeSize;
+ }
+ unsigned NumGaps = J - I - 1;
+
+ support::endian::Writer LEWriter(OS, support::little);
+
+ unsigned Bias = 0;
+ // We must split the range into chunks of MaxDefRange, this is a fundamental
+ // limitation of the file format.
+ do {
+ uint16_t Chunk = std::min((uint32_t)MaxDefRange, RangeSize);
+
+ const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(RangeBegin, Ctx);
+ const MCBinaryExpr *BE =
+ MCBinaryExpr::createAdd(SRE, MCConstantExpr::create(Bias, Ctx), Ctx);
+ MCValue Res;
+ BE->evaluateAsRelocatable(Res, &Layout, /*Fixup=*/nullptr);
+
+ // Each record begins with a 2-byte number indicating how large the record
+ // is.
+ StringRef FixedSizePortion = Frag.getFixedSizePortion();
+ // Our record is a fixed sized prefix and a LocalVariableAddrRange that we
+ // are artificially constructing.
+ size_t RecordSize = FixedSizePortion.size() +
+ sizeof(LocalVariableAddrRange) + 4 * NumGaps;
+ // Write out the record size.
+ LEWriter.write<uint16_t>(RecordSize);
+ // Write out the fixed size prefix.
+ OS << FixedSizePortion;
+ // Make space for a fixup that will eventually have a section relative
+ // relocation pointing at the offset where the variable becomes live.
+ Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_4));
+ LEWriter.write<uint32_t>(0); // Fixup for code start.
+ // Make space for a fixup that will record the section index for the code.
+ Fixups.push_back(MCFixup::create(Contents.size(), BE, FK_SecRel_2));
+ LEWriter.write<uint16_t>(0); // Fixup for section index.
+ // Write down the range's extent.
+ LEWriter.write<uint16_t>(Chunk);
+
+ // Move on to the next range.
+ Bias += Chunk;
+ RangeSize -= Chunk;
+ } while (RangeSize > 0);
+
+ // Emit the gaps afterwards.
+ assert((NumGaps == 0 || Bias <= MaxDefRange) &&
+ "large ranges should not have gaps");
+ unsigned GapStartOffset = GapAndRangeSizes[I].second;
+ for (++I; I != J; ++I) {
+ unsigned GapSize, RangeSize;
+ assert(I < GapAndRangeSizes.size());
+ std::tie(GapSize, RangeSize) = GapAndRangeSizes[I];
+ LEWriter.write<uint16_t>(GapStartOffset);
+ LEWriter.write<uint16_t>(GapSize);
+ GapStartOffset += GapSize + RangeSize;
+ }
+ }
+}
diff --git a/llvm/lib/MC/MCContext.cpp b/llvm/lib/MC/MCContext.cpp
new file mode 100644
index 000000000000..a69ee19e1a1a
--- /dev/null
+++ b/llvm/lib/MC/MCContext.cpp
@@ -0,0 +1,724 @@
+//===- lib/MC/MCContext.cpp - Machine Code Context ------------------------===//
+//
+// 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/MCContext.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCLabel.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCSectionXCOFF.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolCOFF.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSymbolMachO.h"
+#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/MC/MCSymbolXCOFF.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdlib>
+#include <tuple>
+#include <utility>
+
+using namespace llvm;
+
+static cl::opt<char*>
+AsSecureLogFileName("as-secure-log-file-name",
+ cl::desc("As secure log file name (initialized from "
+ "AS_SECURE_LOG_FILE env variable)"),
+ cl::init(getenv("AS_SECURE_LOG_FILE")), cl::Hidden);
+
+MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri,
+ const MCObjectFileInfo *mofi, const SourceMgr *mgr,
+ MCTargetOptions const *TargetOpts, bool DoAutoReset)
+ : SrcMgr(mgr), InlineSrcMgr(nullptr), MAI(mai), MRI(mri), MOFI(mofi),
+ Symbols(Allocator), UsedNames(Allocator),
+ InlineAsmUsedLabelNames(Allocator),
+ CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0),
+ AutoReset(DoAutoReset), TargetOptions(TargetOpts) {
+ SecureLogFile = AsSecureLogFileName;
+
+ if (SrcMgr && SrcMgr->getNumBuffers())
+ MainFileName =
+ SrcMgr->getMemoryBuffer(SrcMgr->getMainFileID())->getBufferIdentifier();
+}
+
+MCContext::~MCContext() {
+ if (AutoReset)
+ reset();
+
+ // NOTE: The symbols are all allocated out of a bump pointer allocator,
+ // we don't need to free them here.
+}
+
+//===----------------------------------------------------------------------===//
+// Module Lifetime Management
+//===----------------------------------------------------------------------===//
+
+void MCContext::reset() {
+ // Call the destructors so the fragments are freed
+ COFFAllocator.DestroyAll();
+ ELFAllocator.DestroyAll();
+ MachOAllocator.DestroyAll();
+ XCOFFAllocator.DestroyAll();
+
+ MCSubtargetAllocator.DestroyAll();
+ InlineAsmUsedLabelNames.clear();
+ UsedNames.clear();
+ Symbols.clear();
+ Allocator.Reset();
+ Instances.clear();
+ CompilationDir.clear();
+ MainFileName.clear();
+ MCDwarfLineTablesCUMap.clear();
+ SectionsForRanges.clear();
+ MCGenDwarfLabelEntries.clear();
+ DwarfDebugFlags = StringRef();
+ DwarfCompileUnitID = 0;
+ CurrentDwarfLoc = MCDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0);
+
+ CVContext.reset();
+
+ MachOUniquingMap.clear();
+ ELFUniquingMap.clear();
+ COFFUniquingMap.clear();
+ WasmUniquingMap.clear();
+ XCOFFUniquingMap.clear();
+
+ NextID.clear();
+ AllowTemporaryLabels = true;
+ DwarfLocSeen = false;
+ GenDwarfForAssembly = false;
+ GenDwarfFileNumber = 0;
+
+ HadError = false;
+}
+
+//===----------------------------------------------------------------------===//
+// Symbol Manipulation
+//===----------------------------------------------------------------------===//
+
+MCSymbol *MCContext::getOrCreateSymbol(const Twine &Name) {
+ SmallString<128> NameSV;
+ StringRef NameRef = Name.toStringRef(NameSV);
+
+ assert(!NameRef.empty() && "Normal symbols cannot be unnamed!");
+
+ MCSymbol *&Sym = Symbols[NameRef];
+ if (!Sym)
+ Sym = createSymbol(NameRef, false, false);
+
+ return Sym;
+}
+
+MCSymbol *MCContext::getOrCreateFrameAllocSymbol(StringRef FuncName,
+ unsigned Idx) {
+ return getOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + FuncName +
+ "$frame_escape_" + Twine(Idx));
+}
+
+MCSymbol *MCContext::getOrCreateParentFrameOffsetSymbol(StringRef FuncName) {
+ return getOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + FuncName +
+ "$parent_frame_offset");
+}
+
+MCSymbol *MCContext::getOrCreateLSDASymbol(StringRef FuncName) {
+ return getOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + "__ehtable$" +
+ FuncName);
+}
+
+MCSymbol *MCContext::createSymbolImpl(const StringMapEntry<bool> *Name,
+ bool IsTemporary) {
+ if (MOFI) {
+ switch (MOFI->getObjectFileType()) {
+ case MCObjectFileInfo::IsCOFF:
+ return new (Name, *this) MCSymbolCOFF(Name, IsTemporary);
+ case MCObjectFileInfo::IsELF:
+ return new (Name, *this) MCSymbolELF(Name, IsTemporary);
+ case MCObjectFileInfo::IsMachO:
+ return new (Name, *this) MCSymbolMachO(Name, IsTemporary);
+ case MCObjectFileInfo::IsWasm:
+ return new (Name, *this) MCSymbolWasm(Name, IsTemporary);
+ case MCObjectFileInfo::IsXCOFF:
+ return new (Name, *this) MCSymbolXCOFF(Name, IsTemporary);
+ }
+ }
+ return new (Name, *this) MCSymbol(MCSymbol::SymbolKindUnset, Name,
+ IsTemporary);
+}
+
+MCSymbol *MCContext::createSymbol(StringRef Name, bool AlwaysAddSuffix,
+ bool CanBeUnnamed) {
+ if (CanBeUnnamed && !UseNamesOnTempLabels)
+ return createSymbolImpl(nullptr, true);
+
+ // Determine whether this is a user written assembler temporary or normal
+ // label, if used.
+ bool IsTemporary = CanBeUnnamed;
+ if (AllowTemporaryLabels && !IsTemporary)
+ IsTemporary = Name.startswith(MAI->getPrivateGlobalPrefix());
+
+ SmallString<128> NewName = Name;
+ bool AddSuffix = AlwaysAddSuffix;
+ unsigned &NextUniqueID = NextID[Name];
+ while (true) {
+ if (AddSuffix) {
+ NewName.resize(Name.size());
+ raw_svector_ostream(NewName) << NextUniqueID++;
+ }
+ auto NameEntry = UsedNames.insert(std::make_pair(NewName, true));
+ if (NameEntry.second || !NameEntry.first->second) {
+ // Ok, we found a name.
+ // Mark it as used for a non-section symbol.
+ NameEntry.first->second = true;
+ // Have the MCSymbol object itself refer to the copy of the string that is
+ // embedded in the UsedNames entry.
+ return createSymbolImpl(&*NameEntry.first, IsTemporary);
+ }
+ assert(IsTemporary && "Cannot rename non-temporary symbols");
+ AddSuffix = true;
+ }
+ llvm_unreachable("Infinite loop");
+}
+
+MCSymbol *MCContext::createTempSymbol(const Twine &Name, bool AlwaysAddSuffix,
+ bool CanBeUnnamed) {
+ SmallString<128> NameSV;
+ raw_svector_ostream(NameSV) << MAI->getPrivateGlobalPrefix() << Name;
+ return createSymbol(NameSV, AlwaysAddSuffix, CanBeUnnamed);
+}
+
+MCSymbol *MCContext::createLinkerPrivateTempSymbol() {
+ SmallString<128> NameSV;
+ raw_svector_ostream(NameSV) << MAI->getLinkerPrivateGlobalPrefix() << "tmp";
+ return createSymbol(NameSV, true, false);
+}
+
+MCSymbol *MCContext::createTempSymbol(bool CanBeUnnamed) {
+ return createTempSymbol("tmp", true, CanBeUnnamed);
+}
+
+unsigned MCContext::NextInstance(unsigned LocalLabelVal) {
+ MCLabel *&Label = Instances[LocalLabelVal];
+ if (!Label)
+ Label = new (*this) MCLabel(0);
+ return Label->incInstance();
+}
+
+unsigned MCContext::GetInstance(unsigned LocalLabelVal) {
+ MCLabel *&Label = Instances[LocalLabelVal];
+ if (!Label)
+ Label = new (*this) MCLabel(0);
+ return Label->getInstance();
+}
+
+MCSymbol *MCContext::getOrCreateDirectionalLocalSymbol(unsigned LocalLabelVal,
+ unsigned Instance) {
+ MCSymbol *&Sym = LocalSymbols[std::make_pair(LocalLabelVal, Instance)];
+ if (!Sym)
+ Sym = createTempSymbol(false);
+ return Sym;
+}
+
+MCSymbol *MCContext::createDirectionalLocalSymbol(unsigned LocalLabelVal) {
+ unsigned Instance = NextInstance(LocalLabelVal);
+ return getOrCreateDirectionalLocalSymbol(LocalLabelVal, Instance);
+}
+
+MCSymbol *MCContext::getDirectionalLocalSymbol(unsigned LocalLabelVal,
+ bool Before) {
+ unsigned Instance = GetInstance(LocalLabelVal);
+ if (!Before)
+ ++Instance;
+ return getOrCreateDirectionalLocalSymbol(LocalLabelVal, Instance);
+}
+
+MCSymbol *MCContext::lookupSymbol(const Twine &Name) const {
+ SmallString<128> NameSV;
+ StringRef NameRef = Name.toStringRef(NameSV);
+ return Symbols.lookup(NameRef);
+}
+
+void MCContext::setSymbolValue(MCStreamer &Streamer,
+ StringRef Sym,
+ uint64_t Val) {
+ auto Symbol = getOrCreateSymbol(Sym);
+ Streamer.EmitAssignment(Symbol, MCConstantExpr::create(Val, *this));
+}
+
+void MCContext::registerInlineAsmLabel(MCSymbol *Sym) {
+ InlineAsmUsedLabelNames[Sym->getName()] = Sym;
+}
+
+//===----------------------------------------------------------------------===//
+// Section Management
+//===----------------------------------------------------------------------===//
+
+MCSectionMachO *MCContext::getMachOSection(StringRef Segment, StringRef Section,
+ unsigned TypeAndAttributes,
+ unsigned Reserved2, SectionKind Kind,
+ const char *BeginSymName) {
+ // We unique sections by their segment/section pair. The returned section
+ // may not have the same flags as the requested section, if so this should be
+ // diagnosed by the client as an error.
+
+ // Form the name to look up.
+ SmallString<64> Name;
+ Name += Segment;
+ Name.push_back(',');
+ Name += Section;
+
+ // Do the lookup, if we have a hit, return it.
+ MCSectionMachO *&Entry = MachOUniquingMap[Name];
+ if (Entry)
+ return Entry;
+
+ MCSymbol *Begin = nullptr;
+ if (BeginSymName)
+ Begin = createTempSymbol(BeginSymName, false);
+
+ // Otherwise, return a new section.
+ return Entry = new (MachOAllocator.Allocate()) MCSectionMachO(
+ Segment, Section, TypeAndAttributes, Reserved2, Kind, Begin);
+}
+
+void MCContext::renameELFSection(MCSectionELF *Section, StringRef Name) {
+ StringRef GroupName;
+ if (const MCSymbol *Group = Section->getGroup())
+ GroupName = Group->getName();
+
+ unsigned UniqueID = Section->getUniqueID();
+ ELFUniquingMap.erase(
+ ELFSectionKey{Section->getSectionName(), GroupName, UniqueID});
+ auto I = ELFUniquingMap.insert(std::make_pair(
+ ELFSectionKey{Name, GroupName, UniqueID},
+ Section))
+ .first;
+ StringRef CachedName = I->first.SectionName;
+ const_cast<MCSectionELF *>(Section)->setSectionName(CachedName);
+}
+
+MCSectionELF *MCContext::createELFSectionImpl(StringRef Section, unsigned Type,
+ unsigned Flags, SectionKind K,
+ unsigned EntrySize,
+ const MCSymbolELF *Group,
+ unsigned UniqueID,
+ const MCSymbolELF *Associated) {
+ MCSymbolELF *R;
+ MCSymbol *&Sym = Symbols[Section];
+ // A section symbol can not redefine regular symbols. There may be multiple
+ // sections with the same name, in which case the first such section wins.
+ if (Sym && Sym->isDefined() &&
+ (!Sym->isInSection() || Sym->getSection().getBeginSymbol() != Sym))
+ reportError(SMLoc(), "invalid symbol redefinition");
+ if (Sym && Sym->isUndefined()) {
+ R = cast<MCSymbolELF>(Sym);
+ } else {
+ auto NameIter = UsedNames.insert(std::make_pair(Section, false)).first;
+ R = new (&*NameIter, *this) MCSymbolELF(&*NameIter, /*isTemporary*/ false);
+ if (!Sym)
+ Sym = R;
+ }
+ R->setBinding(ELF::STB_LOCAL);
+ R->setType(ELF::STT_SECTION);
+
+ auto *Ret = new (ELFAllocator.Allocate()) MCSectionELF(
+ Section, Type, Flags, K, EntrySize, Group, UniqueID, R, Associated);
+
+ auto *F = new MCDataFragment();
+ Ret->getFragmentList().insert(Ret->begin(), F);
+ F->setParent(Ret);
+ R->setFragment(F);
+
+ return Ret;
+}
+
+MCSectionELF *MCContext::createELFRelSection(const Twine &Name, unsigned Type,
+ unsigned Flags, unsigned EntrySize,
+ const MCSymbolELF *Group,
+ const MCSectionELF *RelInfoSection) {
+ StringMap<bool>::iterator I;
+ bool Inserted;
+ std::tie(I, Inserted) =
+ RelSecNames.insert(std::make_pair(Name.str(), true));
+
+ return createELFSectionImpl(
+ I->getKey(), Type, Flags, SectionKind::getReadOnly(), EntrySize, Group,
+ true, cast<MCSymbolELF>(RelInfoSection->getBeginSymbol()));
+}
+
+MCSectionELF *MCContext::getELFNamedSection(const Twine &Prefix,
+ const Twine &Suffix, unsigned Type,
+ unsigned Flags,
+ unsigned EntrySize) {
+ return getELFSection(Prefix + "." + Suffix, Type, Flags, EntrySize, Suffix);
+}
+
+MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type,
+ unsigned Flags, unsigned EntrySize,
+ const Twine &Group, unsigned UniqueID,
+ const MCSymbolELF *Associated) {
+ MCSymbolELF *GroupSym = nullptr;
+ if (!Group.isTriviallyEmpty() && !Group.str().empty())
+ GroupSym = cast<MCSymbolELF>(getOrCreateSymbol(Group));
+
+ return getELFSection(Section, Type, Flags, EntrySize, GroupSym, UniqueID,
+ Associated);
+}
+
+MCSectionELF *MCContext::getELFSection(const Twine &Section, unsigned Type,
+ unsigned Flags, unsigned EntrySize,
+ const MCSymbolELF *GroupSym,
+ unsigned UniqueID,
+ const MCSymbolELF *Associated) {
+ StringRef Group = "";
+ if (GroupSym)
+ Group = GroupSym->getName();
+ // Do the lookup, if we have a hit, return it.
+ auto IterBool = ELFUniquingMap.insert(
+ std::make_pair(ELFSectionKey{Section.str(), Group, UniqueID}, nullptr));
+ auto &Entry = *IterBool.first;
+ if (!IterBool.second)
+ return Entry.second;
+
+ StringRef CachedName = Entry.first.SectionName;
+
+ SectionKind Kind;
+ if (Flags & ELF::SHF_ARM_PURECODE)
+ Kind = SectionKind::getExecuteOnly();
+ else if (Flags & ELF::SHF_EXECINSTR)
+ Kind = SectionKind::getText();
+ else
+ Kind = SectionKind::getReadOnly();
+
+ MCSectionELF *Result = createELFSectionImpl(
+ CachedName, Type, Flags, Kind, EntrySize, GroupSym, UniqueID, Associated);
+ Entry.second = Result;
+ return Result;
+}
+
+MCSectionELF *MCContext::createELFGroupSection(const MCSymbolELF *Group) {
+ return createELFSectionImpl(".group", ELF::SHT_GROUP, 0,
+ SectionKind::getReadOnly(), 4, Group, ~0,
+ nullptr);
+}
+
+MCSectionCOFF *MCContext::getCOFFSection(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind,
+ StringRef COMDATSymName, int Selection,
+ unsigned UniqueID,
+ const char *BeginSymName) {
+ MCSymbol *COMDATSymbol = nullptr;
+ if (!COMDATSymName.empty()) {
+ COMDATSymbol = getOrCreateSymbol(COMDATSymName);
+ COMDATSymName = COMDATSymbol->getName();
+ }
+
+
+ // Do the lookup, if we have a hit, return it.
+ COFFSectionKey T{Section, COMDATSymName, Selection, UniqueID};
+ auto IterBool = COFFUniquingMap.insert(std::make_pair(T, nullptr));
+ auto Iter = IterBool.first;
+ if (!IterBool.second)
+ return Iter->second;
+
+ MCSymbol *Begin = nullptr;
+ if (BeginSymName)
+ Begin = createTempSymbol(BeginSymName, false);
+
+ StringRef CachedName = Iter->first.SectionName;
+ MCSectionCOFF *Result = new (COFFAllocator.Allocate()) MCSectionCOFF(
+ CachedName, Characteristics, COMDATSymbol, Selection, Kind, Begin);
+
+ Iter->second = Result;
+ return Result;
+}
+
+MCSectionCOFF *MCContext::getCOFFSection(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind,
+ const char *BeginSymName) {
+ return getCOFFSection(Section, Characteristics, Kind, "", 0, GenericSectionID,
+ BeginSymName);
+}
+
+MCSectionCOFF *MCContext::getAssociativeCOFFSection(MCSectionCOFF *Sec,
+ const MCSymbol *KeySym,
+ unsigned UniqueID) {
+ // Return the normal section if we don't have to be associative or unique.
+ if (!KeySym && UniqueID == GenericSectionID)
+ return Sec;
+
+ // If we have a key symbol, make an associative section with the same name and
+ // kind as the normal section.
+ unsigned Characteristics = Sec->getCharacteristics();
+ if (KeySym) {
+ Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT;
+ return getCOFFSection(Sec->getSectionName(), Characteristics,
+ Sec->getKind(), KeySym->getName(),
+ COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE, UniqueID);
+ }
+
+ return getCOFFSection(Sec->getSectionName(), Characteristics, Sec->getKind(),
+ "", 0, UniqueID);
+}
+
+MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind K,
+ const Twine &Group, unsigned UniqueID,
+ const char *BeginSymName) {
+ MCSymbolWasm *GroupSym = nullptr;
+ if (!Group.isTriviallyEmpty() && !Group.str().empty()) {
+ GroupSym = cast<MCSymbolWasm>(getOrCreateSymbol(Group));
+ GroupSym->setComdat(true);
+ }
+
+ return getWasmSection(Section, K, GroupSym, UniqueID, BeginSymName);
+}
+
+MCSectionWasm *MCContext::getWasmSection(const Twine &Section, SectionKind Kind,
+ const MCSymbolWasm *GroupSym,
+ unsigned UniqueID,
+ const char *BeginSymName) {
+ StringRef Group = "";
+ if (GroupSym)
+ Group = GroupSym->getName();
+ // Do the lookup, if we have a hit, return it.
+ auto IterBool = WasmUniquingMap.insert(
+ std::make_pair(WasmSectionKey{Section.str(), Group, UniqueID}, nullptr));
+ auto &Entry = *IterBool.first;
+ if (!IterBool.second)
+ return Entry.second;
+
+ StringRef CachedName = Entry.first.SectionName;
+
+ MCSymbol *Begin = createSymbol(CachedName, false, false);
+ cast<MCSymbolWasm>(Begin)->setType(wasm::WASM_SYMBOL_TYPE_SECTION);
+
+ MCSectionWasm *Result = new (WasmAllocator.Allocate())
+ MCSectionWasm(CachedName, Kind, GroupSym, UniqueID, Begin);
+ Entry.second = Result;
+
+ auto *F = new MCDataFragment();
+ Result->getFragmentList().insert(Result->begin(), F);
+ F->setParent(Result);
+ Begin->setFragment(F);
+
+ return Result;
+}
+
+MCSectionXCOFF *MCContext::getXCOFFSection(StringRef Section,
+ XCOFF::StorageMappingClass SMC,
+ XCOFF::SymbolType Type,
+ XCOFF::StorageClass SC,
+ SectionKind Kind,
+ const char *BeginSymName) {
+ // Do the lookup. If we have a hit, return it.
+ auto IterBool = XCOFFUniquingMap.insert(
+ std::make_pair(XCOFFSectionKey{Section.str(), SMC}, nullptr));
+ auto &Entry = *IterBool.first;
+ if (!IterBool.second)
+ return Entry.second;
+
+ // Otherwise, return a new section.
+ StringRef CachedName = Entry.first.SectionName;
+
+ MCSymbol *Begin = nullptr;
+ if (BeginSymName)
+ Begin = createTempSymbol(BeginSymName, false);
+
+ MCSectionXCOFF *Result = new (XCOFFAllocator.Allocate())
+ MCSectionXCOFF(CachedName, SMC, Type, SC, Kind, Begin);
+ Entry.second = Result;
+
+ auto *F = new MCDataFragment();
+ Result->getFragmentList().insert(Result->begin(), F);
+ F->setParent(Result);
+
+ if (Begin)
+ Begin->setFragment(F);
+
+ return Result;
+}
+
+MCSubtargetInfo &MCContext::getSubtargetCopy(const MCSubtargetInfo &STI) {
+ return *new (MCSubtargetAllocator.Allocate()) MCSubtargetInfo(STI);
+}
+
+void MCContext::addDebugPrefixMapEntry(const std::string &From,
+ const std::string &To) {
+ DebugPrefixMap.insert(std::make_pair(From, To));
+}
+
+void MCContext::RemapDebugPaths() {
+ const auto &DebugPrefixMap = this->DebugPrefixMap;
+ const auto RemapDebugPath = [&DebugPrefixMap](std::string &Path) {
+ for (const auto &Entry : DebugPrefixMap)
+ if (StringRef(Path).startswith(Entry.first)) {
+ std::string RemappedPath =
+ (Twine(Entry.second) + Path.substr(Entry.first.size())).str();
+ Path.swap(RemappedPath);
+ }
+ };
+
+ // Remap compilation directory.
+ std::string CompDir = CompilationDir.str();
+ RemapDebugPath(CompDir);
+ CompilationDir = CompDir;
+
+ // Remap MCDwarfDirs in all compilation units.
+ for (auto &CUIDTablePair : MCDwarfLineTablesCUMap)
+ for (auto &Dir : CUIDTablePair.second.getMCDwarfDirs())
+ RemapDebugPath(Dir);
+}
+
+//===----------------------------------------------------------------------===//
+// Dwarf Management
+//===----------------------------------------------------------------------===//
+
+void MCContext::setGenDwarfRootFile(StringRef InputFileName, StringRef Buffer) {
+ // MCDwarf needs the root file as well as the compilation directory.
+ // If we find a '.file 0' directive that will supersede these values.
+ Optional<MD5::MD5Result> Cksum;
+ if (getDwarfVersion() >= 5) {
+ MD5 Hash;
+ MD5::MD5Result Sum;
+ Hash.update(Buffer);
+ Hash.final(Sum);
+ Cksum = Sum;
+ }
+ // Canonicalize the root filename. It cannot be empty, and should not
+ // repeat the compilation dir.
+ // The MCContext ctor initializes MainFileName to the name associated with
+ // the SrcMgr's main file ID, which might be the same as InputFileName (and
+ // possibly include directory components).
+ // Or, MainFileName might have been overridden by a -main-file-name option,
+ // which is supposed to be just a base filename with no directory component.
+ // So, if the InputFileName and MainFileName are not equal, assume
+ // MainFileName is a substitute basename and replace the last component.
+ SmallString<1024> FileNameBuf = InputFileName;
+ if (FileNameBuf.empty() || FileNameBuf == "-")
+ FileNameBuf = "<stdin>";
+ if (!getMainFileName().empty() && FileNameBuf != getMainFileName()) {
+ llvm::sys::path::remove_filename(FileNameBuf);
+ llvm::sys::path::append(FileNameBuf, getMainFileName());
+ }
+ StringRef FileName = FileNameBuf;
+ if (FileName.consume_front(getCompilationDir()))
+ if (llvm::sys::path::is_separator(FileName.front()))
+ FileName = FileName.drop_front();
+ assert(!FileName.empty());
+ setMCLineTableRootFile(
+ /*CUID=*/0, getCompilationDir(), FileName, Cksum, None);
+}
+
+/// getDwarfFile - takes a file name and number to place in the dwarf file and
+/// directory tables. If the file number has already been allocated it is an
+/// error and zero is returned and the client reports the error, else the
+/// allocated file number is returned. The file numbers may be in any order.
+Expected<unsigned> MCContext::getDwarfFile(StringRef Directory,
+ StringRef FileName,
+ unsigned FileNumber,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ unsigned CUID) {
+ MCDwarfLineTable &Table = MCDwarfLineTablesCUMap[CUID];
+ return Table.tryGetFile(Directory, FileName, Checksum, Source, DwarfVersion,
+ FileNumber);
+}
+
+/// isValidDwarfFileNumber - takes a dwarf file number and returns true if it
+/// currently is assigned and false otherwise.
+bool MCContext::isValidDwarfFileNumber(unsigned FileNumber, unsigned CUID) {
+ const MCDwarfLineTable &LineTable = getMCDwarfLineTable(CUID);
+ if (FileNumber == 0)
+ return getDwarfVersion() >= 5;
+ if (FileNumber >= LineTable.getMCDwarfFiles().size())
+ return false;
+
+ return !LineTable.getMCDwarfFiles()[FileNumber].Name.empty();
+}
+
+/// Remove empty sections from SectionsForRanges, to avoid generating
+/// useless debug info for them.
+void MCContext::finalizeDwarfSections(MCStreamer &MCOS) {
+ SectionsForRanges.remove_if(
+ [&](MCSection *Sec) { return !MCOS.mayHaveInstructions(*Sec); });
+}
+
+CodeViewContext &MCContext::getCVContext() {
+ if (!CVContext.get())
+ CVContext.reset(new CodeViewContext);
+ return *CVContext.get();
+}
+
+//===----------------------------------------------------------------------===//
+// Error Reporting
+//===----------------------------------------------------------------------===//
+
+void MCContext::reportError(SMLoc Loc, const Twine &Msg) {
+ HadError = true;
+
+ // If we have a source manager use it. Otherwise, try using the inline source
+ // manager.
+ // If that fails, use the generic report_fatal_error().
+ if (SrcMgr)
+ SrcMgr->PrintMessage(Loc, SourceMgr::DK_Error, Msg);
+ else if (InlineSrcMgr)
+ InlineSrcMgr->PrintMessage(Loc, SourceMgr::DK_Error, Msg);
+ else
+ report_fatal_error(Msg, false);
+}
+
+void MCContext::reportWarning(SMLoc Loc, const Twine &Msg) {
+ if (TargetOptions && TargetOptions->MCNoWarn)
+ return;
+ if (TargetOptions && TargetOptions->MCFatalWarnings)
+ reportError(Loc, Msg);
+ else {
+ // If we have a source manager use it. Otherwise, try using the inline
+ // source manager.
+ if (SrcMgr)
+ SrcMgr->PrintMessage(Loc, SourceMgr::DK_Warning, Msg);
+ else if (InlineSrcMgr)
+ InlineSrcMgr->PrintMessage(Loc, SourceMgr::DK_Warning, Msg);
+ }
+}
+
+void MCContext::reportFatalError(SMLoc Loc, const Twine &Msg) {
+ reportError(Loc, Msg);
+
+ // If we reached here, we are failing ungracefully. Run the interrupt handlers
+ // to make sure any special cleanups get done, in particular that we remove
+ // files registered with RemoveFileOnSignal.
+ sys::RunInterruptHandlers();
+ exit(1);
+}
diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
new file mode 100644
index 000000000000..21bdc2eaea3e
--- /dev/null
+++ b/llvm/lib/MC/MCDisassembler/Disassembler.cpp
@@ -0,0 +1,343 @@
+//===-- lib/MC/Disassembler.cpp - Disassembler Public C 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 "Disassembler.h"
+#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCDisassembler/MCRelocationInfo.h"
+#include "llvm/MC/MCDisassembler/MCSymbolizer.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSchedule.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+
+using namespace llvm;
+
+// LLVMCreateDisasm() creates a disassembler for the TripleName. Symbolic
+// disassembly is supported by passing a block of information in the DisInfo
+// parameter and specifying the TagType and callback functions as described in
+// the header llvm-c/Disassembler.h . The pointer to the block and the
+// functions can all be passed as NULL. If successful, this returns a
+// disassembler context. If not, it returns NULL.
+//
+LLVMDisasmContextRef
+LLVMCreateDisasmCPUFeatures(const char *TT, const char *CPU,
+ const char *Features, void *DisInfo, int TagType,
+ LLVMOpInfoCallback GetOpInfo,
+ LLVMSymbolLookupCallback SymbolLookUp) {
+ // Get the target.
+ std::string Error;
+ const Target *TheTarget = TargetRegistry::lookupTarget(TT, Error);
+ if (!TheTarget)
+ return nullptr;
+
+ std::unique_ptr<const MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT));
+ if (!MRI)
+ return nullptr;
+
+ // Get the assembler info needed to setup the MCContext.
+ std::unique_ptr<const MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT));
+ if (!MAI)
+ return nullptr;
+
+ std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
+ if (!MII)
+ return nullptr;
+
+ std::unique_ptr<const MCSubtargetInfo> STI(
+ TheTarget->createMCSubtargetInfo(TT, CPU, Features));
+ if (!STI)
+ return nullptr;
+
+ // Set up the MCContext for creating symbols and MCExpr's.
+ std::unique_ptr<MCContext> Ctx(new MCContext(MAI.get(), MRI.get(), nullptr));
+ if (!Ctx)
+ return nullptr;
+
+ // Set up disassembler.
+ std::unique_ptr<MCDisassembler> DisAsm(
+ TheTarget->createMCDisassembler(*STI, *Ctx));
+ if (!DisAsm)
+ return nullptr;
+
+ std::unique_ptr<MCRelocationInfo> RelInfo(
+ TheTarget->createMCRelocationInfo(TT, *Ctx));
+ if (!RelInfo)
+ return nullptr;
+
+ std::unique_ptr<MCSymbolizer> Symbolizer(TheTarget->createMCSymbolizer(
+ TT, GetOpInfo, SymbolLookUp, DisInfo, Ctx.get(), std::move(RelInfo)));
+ DisAsm->setSymbolizer(std::move(Symbolizer));
+
+ // Set up the instruction printer.
+ int AsmPrinterVariant = MAI->getAssemblerDialect();
+ std::unique_ptr<MCInstPrinter> IP(TheTarget->createMCInstPrinter(
+ Triple(TT), AsmPrinterVariant, *MAI, *MII, *MRI));
+ if (!IP)
+ return nullptr;
+
+ LLVMDisasmContext *DC = new LLVMDisasmContext(
+ TT, DisInfo, TagType, GetOpInfo, SymbolLookUp, TheTarget, std::move(MAI),
+ std::move(MRI), std::move(STI), std::move(MII), std::move(Ctx),
+ std::move(DisAsm), std::move(IP));
+ if (!DC)
+ return nullptr;
+
+ DC->setCPU(CPU);
+ return DC;
+}
+
+LLVMDisasmContextRef
+LLVMCreateDisasmCPU(const char *TT, const char *CPU, void *DisInfo, int TagType,
+ LLVMOpInfoCallback GetOpInfo,
+ LLVMSymbolLookupCallback SymbolLookUp) {
+ return LLVMCreateDisasmCPUFeatures(TT, CPU, "", DisInfo, TagType, GetOpInfo,
+ SymbolLookUp);
+}
+
+LLVMDisasmContextRef LLVMCreateDisasm(const char *TT, void *DisInfo,
+ int TagType, LLVMOpInfoCallback GetOpInfo,
+ LLVMSymbolLookupCallback SymbolLookUp) {
+ return LLVMCreateDisasmCPUFeatures(TT, "", "", DisInfo, TagType, GetOpInfo,
+ SymbolLookUp);
+}
+
+//
+// LLVMDisasmDispose() disposes of the disassembler specified by the context.
+//
+void LLVMDisasmDispose(LLVMDisasmContextRef DCR){
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ delete DC;
+}
+
+/// Emits the comments that are stored in \p DC comment stream.
+/// Each comment in the comment stream must end with a newline.
+static void emitComments(LLVMDisasmContext *DC,
+ formatted_raw_ostream &FormattedOS) {
+ // Flush the stream before taking its content.
+ StringRef Comments = DC->CommentsToEmit.str();
+ // Get the default information for printing a comment.
+ const MCAsmInfo *MAI = DC->getAsmInfo();
+ StringRef CommentBegin = MAI->getCommentString();
+ unsigned CommentColumn = MAI->getCommentColumn();
+ bool IsFirst = true;
+ while (!Comments.empty()) {
+ if (!IsFirst)
+ FormattedOS << '\n';
+ // Emit a line of comments.
+ FormattedOS.PadToColumn(CommentColumn);
+ size_t Position = Comments.find('\n');
+ FormattedOS << CommentBegin << ' ' << Comments.substr(0, Position);
+ // Move after the newline character.
+ Comments = Comments.substr(Position+1);
+ IsFirst = false;
+ }
+ FormattedOS.flush();
+
+ // Tell the comment stream that the vector changed underneath it.
+ DC->CommentsToEmit.clear();
+}
+
+/// Gets latency information for \p Inst from the itinerary
+/// scheduling model, based on \p DC information.
+/// \return The maximum expected latency over all the operands or -1
+/// if no information is available.
+static int getItineraryLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
+ const int NoInformationAvailable = -1;
+
+ // Check if we have a CPU to get the itinerary information.
+ if (DC->getCPU().empty())
+ return NoInformationAvailable;
+
+ // Get itinerary information.
+ const MCSubtargetInfo *STI = DC->getSubtargetInfo();
+ InstrItineraryData IID = STI->getInstrItineraryForCPU(DC->getCPU());
+ // Get the scheduling class of the requested instruction.
+ const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
+ unsigned SCClass = Desc.getSchedClass();
+
+ int Latency = 0;
+ for (unsigned OpIdx = 0, OpIdxEnd = Inst.getNumOperands(); OpIdx != OpIdxEnd;
+ ++OpIdx)
+ Latency = std::max(Latency, IID.getOperandCycle(SCClass, OpIdx));
+
+ return Latency;
+}
+
+/// Gets latency information for \p Inst, based on \p DC information.
+/// \return The maximum expected latency over all the definitions or -1
+/// if no information is available.
+static int getLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
+ // Try to compute scheduling information.
+ const MCSubtargetInfo *STI = DC->getSubtargetInfo();
+ const MCSchedModel SCModel = STI->getSchedModel();
+ const int NoInformationAvailable = -1;
+
+ // Check if we have a scheduling model for instructions.
+ if (!SCModel.hasInstrSchedModel())
+ // Try to fall back to the itinerary model if the scheduling model doesn't
+ // have a scheduling table. Note the default does not have a table.
+ return getItineraryLatency(DC, Inst);
+
+ // Get the scheduling class of the requested instruction.
+ const MCInstrDesc& Desc = DC->getInstrInfo()->get(Inst.getOpcode());
+ unsigned SCClass = Desc.getSchedClass();
+ const MCSchedClassDesc *SCDesc = SCModel.getSchedClassDesc(SCClass);
+ // Resolving the variant SchedClass requires an MI to pass to
+ // SubTargetInfo::resolveSchedClass.
+ if (!SCDesc || !SCDesc->isValid() || SCDesc->isVariant())
+ return NoInformationAvailable;
+
+ // Compute output latency.
+ int16_t Latency = 0;
+ for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries;
+ DefIdx != DefEnd; ++DefIdx) {
+ // Lookup the definition's write latency in SubtargetInfo.
+ const MCWriteLatencyEntry *WLEntry = STI->getWriteLatencyEntry(SCDesc,
+ DefIdx);
+ Latency = std::max(Latency, WLEntry->Cycles);
+ }
+
+ return Latency;
+}
+
+/// Emits latency information in DC->CommentStream for \p Inst, based
+/// on the information available in \p DC.
+static void emitLatency(LLVMDisasmContext *DC, const MCInst &Inst) {
+ int Latency = getLatency(DC, Inst);
+
+ // Report only interesting latencies.
+ if (Latency < 2)
+ return;
+
+ DC->CommentStream << "Latency: " << Latency << '\n';
+}
+
+//
+// LLVMDisasmInstruction() disassembles a single instruction using the
+// disassembler context specified in the parameter DC. The bytes of the
+// instruction are specified in the parameter Bytes, and contains at least
+// BytesSize number of bytes. The instruction is at the address specified by
+// the PC parameter. If a valid instruction can be disassembled its string is
+// returned indirectly in OutString which whos size is specified in the
+// parameter OutStringSize. This function returns the number of bytes in the
+// instruction or zero if there was no valid instruction. If this function
+// returns zero the caller will have to pick how many bytes they want to step
+// over by printing a .byte, .long etc. to continue.
+//
+size_t LLVMDisasmInstruction(LLVMDisasmContextRef DCR, uint8_t *Bytes,
+ uint64_t BytesSize, uint64_t PC, char *OutString,
+ size_t OutStringSize){
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject.
+ ArrayRef<uint8_t> Data(Bytes, BytesSize);
+
+ uint64_t Size;
+ MCInst Inst;
+ const MCDisassembler *DisAsm = DC->getDisAsm();
+ MCInstPrinter *IP = DC->getIP();
+ MCDisassembler::DecodeStatus S;
+ SmallVector<char, 64> InsnStr;
+ raw_svector_ostream Annotations(InsnStr);
+ S = DisAsm->getInstruction(Inst, Size, Data, PC,
+ /*REMOVE*/ nulls(), Annotations);
+ switch (S) {
+ case MCDisassembler::Fail:
+ case MCDisassembler::SoftFail:
+ // FIXME: Do something different for soft failure modes?
+ return 0;
+
+ case MCDisassembler::Success: {
+ StringRef AnnotationsStr = Annotations.str();
+
+ SmallVector<char, 64> InsnStr;
+ raw_svector_ostream OS(InsnStr);
+ formatted_raw_ostream FormattedOS(OS);
+ IP->printInst(&Inst, FormattedOS, AnnotationsStr, *DC->getSubtargetInfo());
+
+ if (DC->getOptions() & LLVMDisassembler_Option_PrintLatency)
+ emitLatency(DC, Inst);
+
+ emitComments(DC, FormattedOS);
+
+ assert(OutStringSize != 0 && "Output buffer cannot be zero size");
+ size_t OutputSize = std::min(OutStringSize-1, InsnStr.size());
+ std::memcpy(OutString, InsnStr.data(), OutputSize);
+ OutString[OutputSize] = '\0'; // Terminate string.
+
+ return Size;
+ }
+ }
+ llvm_unreachable("Invalid DecodeStatus!");
+}
+
+//
+// LLVMSetDisasmOptions() sets the disassembler's options. It returns 1 if it
+// can set all the Options and 0 otherwise.
+//
+int LLVMSetDisasmOptions(LLVMDisasmContextRef DCR, uint64_t Options){
+ if (Options & LLVMDisassembler_Option_UseMarkup){
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ MCInstPrinter *IP = DC->getIP();
+ IP->setUseMarkup(true);
+ DC->addOptions(LLVMDisassembler_Option_UseMarkup);
+ Options &= ~LLVMDisassembler_Option_UseMarkup;
+ }
+ if (Options & LLVMDisassembler_Option_PrintImmHex){
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ MCInstPrinter *IP = DC->getIP();
+ IP->setPrintImmHex(true);
+ DC->addOptions(LLVMDisassembler_Option_PrintImmHex);
+ Options &= ~LLVMDisassembler_Option_PrintImmHex;
+ }
+ if (Options & LLVMDisassembler_Option_AsmPrinterVariant){
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ // Try to set up the new instruction printer.
+ const MCAsmInfo *MAI = DC->getAsmInfo();
+ const MCInstrInfo *MII = DC->getInstrInfo();
+ const MCRegisterInfo *MRI = DC->getRegisterInfo();
+ int AsmPrinterVariant = MAI->getAssemblerDialect();
+ AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0;
+ MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter(
+ Triple(DC->getTripleName()), AsmPrinterVariant, *MAI, *MII, *MRI);
+ if (IP) {
+ DC->setIP(IP);
+ DC->addOptions(LLVMDisassembler_Option_AsmPrinterVariant);
+ Options &= ~LLVMDisassembler_Option_AsmPrinterVariant;
+ }
+ }
+ if (Options & LLVMDisassembler_Option_SetInstrComments) {
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ MCInstPrinter *IP = DC->getIP();
+ IP->setCommentStream(DC->CommentStream);
+ DC->addOptions(LLVMDisassembler_Option_SetInstrComments);
+ Options &= ~LLVMDisassembler_Option_SetInstrComments;
+ }
+ if (Options & LLVMDisassembler_Option_PrintLatency) {
+ LLVMDisasmContext *DC = static_cast<LLVMDisasmContext *>(DCR);
+ DC->addOptions(LLVMDisassembler_Option_PrintLatency);
+ Options &= ~LLVMDisassembler_Option_PrintLatency;
+ }
+ return (Options == 0);
+}
diff --git a/llvm/lib/MC/MCDisassembler/Disassembler.h b/llvm/lib/MC/MCDisassembler/Disassembler.h
new file mode 100644
index 000000000000..e5aab53a7613
--- /dev/null
+++ b/llvm/lib/MC/MCDisassembler/Disassembler.h
@@ -0,0 +1,124 @@
+//===------------- Disassembler.h - LLVM Disassembler -----------*- C++ -*-===//
+//
+// 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 defines the interface for the Disassembly library's disassembler
+// context. The disassembler is responsible for producing strings for
+// individual instructions according to a given architecture and disassembly
+// syntax.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_MC_MCDISASSEMBLER_DISASSEMBLER_H
+#define LLVM_LIB_MC_MCDISASSEMBLER_DISASSEMBLER_H
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler/MCDisassembler.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+#include <utility>
+
+namespace llvm {
+class Target;
+
+//
+// This is the disassembler context returned by LLVMCreateDisasm().
+//
+class LLVMDisasmContext {
+private:
+ //
+ // The passed parameters when the disassembler context is created.
+ //
+ // The TripleName for this disassembler.
+ std::string TripleName;
+ // The pointer to the caller's block of symbolic information.
+ void *DisInfo;
+ // The Triple specific symbolic information type returned by GetOpInfo.
+ int TagType;
+ // The function to get the symbolic information for operands.
+ LLVMOpInfoCallback GetOpInfo;
+ // The function to look up a symbol name.
+ LLVMSymbolLookupCallback SymbolLookUp;
+ //
+ // The objects created and saved by LLVMCreateDisasm() then used by
+ // LLVMDisasmInstruction().
+ //
+ // The LLVM target corresponding to the disassembler.
+ // FIXME: using std::unique_ptr<const llvm::Target> causes a malloc error
+ // when this LLVMDisasmContext is deleted.
+ const Target *TheTarget;
+ // The assembly information for the target architecture.
+ std::unique_ptr<const llvm::MCAsmInfo> MAI;
+ // The register information for the target architecture.
+ std::unique_ptr<const llvm::MCRegisterInfo> MRI;
+ // The subtarget information for the target architecture.
+ std::unique_ptr<const llvm::MCSubtargetInfo> MSI;
+ // The instruction information for the target architecture.
+ std::unique_ptr<const llvm::MCInstrInfo> MII;
+ // The assembly context for creating symbols and MCExprs.
+ std::unique_ptr<const llvm::MCContext> Ctx;
+ // The disassembler for the target architecture.
+ std::unique_ptr<const llvm::MCDisassembler> DisAsm;
+ // The instruction printer for the target architecture.
+ std::unique_ptr<llvm::MCInstPrinter> IP;
+ // The options used to set up the disassembler.
+ uint64_t Options;
+ // The CPU string.
+ std::string CPU;
+
+public:
+ // Comment stream and backing vector.
+ SmallString<128> CommentsToEmit;
+ raw_svector_ostream CommentStream;
+
+ LLVMDisasmContext(std::string TripleName, void *DisInfo, int TagType,
+ LLVMOpInfoCallback GetOpInfo,
+ LLVMSymbolLookupCallback SymbolLookUp,
+ const Target *TheTarget,
+ std::unique_ptr<const MCAsmInfo> &&MAI,
+ std::unique_ptr<const MCRegisterInfo> &&MRI,
+ std::unique_ptr<const MCSubtargetInfo> &&MSI,
+ std::unique_ptr<const MCInstrInfo> &&MII,
+ std::unique_ptr<const llvm::MCContext> &&Ctx,
+ std::unique_ptr<const MCDisassembler> &&DisAsm,
+ std::unique_ptr<MCInstPrinter> &&IP)
+ : TripleName(std::move(TripleName)), DisInfo(DisInfo), TagType(TagType),
+ GetOpInfo(GetOpInfo), SymbolLookUp(SymbolLookUp), TheTarget(TheTarget),
+ MAI(std::move(MAI)), MRI(std::move(MRI)), MSI(std::move(MSI)),
+ MII(std::move(MII)), Ctx(std::move(Ctx)), DisAsm(std::move(DisAsm)),
+ IP(std::move(IP)), Options(0), CommentStream(CommentsToEmit) {}
+ const std::string &getTripleName() const { return TripleName; }
+ void *getDisInfo() const { return DisInfo; }
+ int getTagType() const { return TagType; }
+ LLVMOpInfoCallback getGetOpInfo() const { return GetOpInfo; }
+ LLVMSymbolLookupCallback getSymbolLookupCallback() const {
+ return SymbolLookUp;
+ }
+ const Target *getTarget() const { return TheTarget; }
+ const MCDisassembler *getDisAsm() const { return DisAsm.get(); }
+ const MCAsmInfo *getAsmInfo() const { return MAI.get(); }
+ const MCInstrInfo *getInstrInfo() const { return MII.get(); }
+ const MCRegisterInfo *getRegisterInfo() const { return MRI.get(); }
+ const MCSubtargetInfo *getSubtargetInfo() const { return MSI.get(); }
+ MCInstPrinter *getIP() { return IP.get(); }
+ void setIP(MCInstPrinter *NewIP) { IP.reset(NewIP); }
+ uint64_t getOptions() const { return Options; }
+ void addOptions(uint64_t Options) { this->Options |= Options; }
+ StringRef getCPU() const { return CPU; }
+ void setCPU(const char *CPU) { this->CPU = CPU; }
+};
+
+} // namespace llvm
+
+#endif
diff --git a/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp b/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp
new file mode 100644
index 000000000000..063f7e706024
--- /dev/null
+++ b/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp
@@ -0,0 +1,46 @@
+//===- MCDisassembler.cpp - Disassembler 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/MCDisassembler/MCDisassembler.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+
+using namespace llvm;
+
+MCDisassembler::~MCDisassembler() = default;
+
+MCDisassembler::DecodeStatus MCDisassembler::onSymbolStart(
+ StringRef Name, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream, raw_ostream &CStream) const {
+ Size = 0;
+ return MCDisassembler::Success;
+}
+
+bool MCDisassembler::tryAddingSymbolicOperand(MCInst &Inst, int64_t Value,
+ uint64_t Address, bool IsBranch,
+ uint64_t Offset,
+ uint64_t InstSize) const {
+ raw_ostream &cStream = CommentStream ? *CommentStream : nulls();
+ if (Symbolizer)
+ return Symbolizer->tryAddingSymbolicOperand(Inst, cStream, Value, Address,
+ IsBranch, Offset, InstSize);
+ return false;
+}
+
+void MCDisassembler::tryAddingPcLoadReferenceComment(int64_t Value,
+ uint64_t Address) const {
+ raw_ostream &cStream = CommentStream ? *CommentStream : nulls();
+ if (Symbolizer)
+ Symbolizer->tryAddingPcLoadReferenceComment(cStream, Value, Address);
+}
+
+void MCDisassembler::setSymbolizer(std::unique_ptr<MCSymbolizer> Symzer) {
+ Symbolizer = std::move(Symzer);
+}
diff --git a/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp b/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp
new file mode 100644
index 000000000000..7befef86303c
--- /dev/null
+++ b/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp
@@ -0,0 +1,199 @@
+//===-- MCExternalSymbolizer.cpp - External symbolizer --------------------===//
+//
+// 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/MCDisassembler/MCExternalSymbolizer.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+
+using namespace llvm;
+
+namespace llvm {
+class Triple;
+}
+
+// This function tries to add a symbolic operand in place of the immediate
+// Value in the MCInst. The immediate Value has had any PC adjustment made by
+// the caller. If the instruction is a branch instruction then IsBranch is true,
+// else false. If the getOpInfo() function was set as part of the
+// setupForSymbolicDisassembly() call then that function is called to get any
+// symbolic information at the Address for this instruction. If that returns
+// non-zero then the symbolic information it returns is used to create an MCExpr
+// and that is added as an operand to the MCInst. If getOpInfo() returns zero
+// and IsBranch is true then a symbol look up for Value is done and if a symbol
+// is found an MCExpr is created with that, else an MCExpr with Value is
+// created. This function returns true if it adds an operand to the MCInst and
+// false otherwise.
+bool MCExternalSymbolizer::tryAddingSymbolicOperand(MCInst &MI,
+ raw_ostream &cStream,
+ int64_t Value,
+ uint64_t Address,
+ bool IsBranch,
+ uint64_t Offset,
+ uint64_t InstSize) {
+ struct LLVMOpInfo1 SymbolicOp;
+ std::memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
+ SymbolicOp.Value = Value;
+
+ if (!GetOpInfo ||
+ !GetOpInfo(DisInfo, Address, Offset, InstSize, 1, &SymbolicOp)) {
+ // Clear SymbolicOp.Value from above and also all other fields.
+ std::memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
+
+ // At this point, GetOpInfo() did not find any relocation information about
+ // this operand and we are left to use the SymbolLookUp() call back to guess
+ // if the Value is the address of a symbol. In the case this is a branch
+ // that always makes sense to guess. But in the case of an immediate it is
+ // a bit more questionable if it is an address of a symbol or some other
+ // reference. So if the immediate Value comes from a width of 1 byte,
+ // InstSize, we will not guess it is an address of a symbol. Because in
+ // object files assembled starting at address 0 this usually leads to
+ // incorrect symbolication.
+ if (!SymbolLookUp || (InstSize == 1 && !IsBranch))
+ return false;
+
+ uint64_t ReferenceType;
+ if (IsBranch)
+ ReferenceType = LLVMDisassembler_ReferenceType_In_Branch;
+ else
+ ReferenceType = LLVMDisassembler_ReferenceType_InOut_None;
+ const char *ReferenceName;
+ const char *Name = SymbolLookUp(DisInfo, Value, &ReferenceType, Address,
+ &ReferenceName);
+ if (Name) {
+ SymbolicOp.AddSymbol.Name = Name;
+ SymbolicOp.AddSymbol.Present = true;
+ // If Name is a C++ symbol name put the human readable name in a comment.
+ if(ReferenceType == LLVMDisassembler_ReferenceType_DeMangled_Name)
+ cStream << ReferenceName;
+ }
+ // For branches always create an MCExpr so it gets printed as hex address.
+ else if (IsBranch) {
+ SymbolicOp.Value = Value;
+ }
+ if(ReferenceType == LLVMDisassembler_ReferenceType_Out_SymbolStub)
+ cStream << "symbol stub for: " << ReferenceName;
+ else if(ReferenceType == LLVMDisassembler_ReferenceType_Out_Objc_Message)
+ cStream << "Objc message: " << ReferenceName;
+ if (!Name && !IsBranch)
+ return false;
+ }
+
+ const MCExpr *Add = nullptr;
+ if (SymbolicOp.AddSymbol.Present) {
+ if (SymbolicOp.AddSymbol.Name) {
+ StringRef Name(SymbolicOp.AddSymbol.Name);
+ MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
+ Add = MCSymbolRefExpr::create(Sym, Ctx);
+ } else {
+ Add = MCConstantExpr::create((int)SymbolicOp.AddSymbol.Value, Ctx);
+ }
+ }
+
+ const MCExpr *Sub = nullptr;
+ if (SymbolicOp.SubtractSymbol.Present) {
+ if (SymbolicOp.SubtractSymbol.Name) {
+ StringRef Name(SymbolicOp.SubtractSymbol.Name);
+ MCSymbol *Sym = Ctx.getOrCreateSymbol(Name);
+ Sub = MCSymbolRefExpr::create(Sym, Ctx);
+ } else {
+ Sub = MCConstantExpr::create((int)SymbolicOp.SubtractSymbol.Value, Ctx);
+ }
+ }
+
+ const MCExpr *Off = nullptr;
+ if (SymbolicOp.Value != 0)
+ Off = MCConstantExpr::create(SymbolicOp.Value, Ctx);
+
+ const MCExpr *Expr;
+ if (Sub) {
+ const MCExpr *LHS;
+ if (Add)
+ LHS = MCBinaryExpr::createSub(Add, Sub, Ctx);
+ else
+ LHS = MCUnaryExpr::createMinus(Sub, Ctx);
+ if (Off)
+ Expr = MCBinaryExpr::createAdd(LHS, Off, Ctx);
+ else
+ Expr = LHS;
+ } else if (Add) {
+ if (Off)
+ Expr = MCBinaryExpr::createAdd(Add, Off, Ctx);
+ else
+ Expr = Add;
+ } else {
+ if (Off)
+ Expr = Off;
+ else
+ Expr = MCConstantExpr::create(0, Ctx);
+ }
+
+ Expr = RelInfo->createExprForCAPIVariantKind(Expr, SymbolicOp.VariantKind);
+ if (!Expr)
+ return false;
+
+ MI.addOperand(MCOperand::createExpr(Expr));
+ return true;
+}
+
+// This function tries to add a comment as to what is being referenced by a load
+// instruction with the base register that is the Pc. These can often be values
+// in a literal pool near the Address of the instruction. The Address of the
+// instruction and its immediate Value are used as a possible literal pool entry.
+// The SymbolLookUp call back will return the name of a symbol referenced by the
+// literal pool's entry if the referenced address is that of a symbol. Or it
+// will return a pointer to a literal 'C' string if the referenced address of
+// the literal pool's entry is an address into a section with C string literals.
+// Or if the reference is to an Objective-C data structure it will return a
+// specific reference type for it and a string.
+void MCExternalSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &cStream,
+ int64_t Value,
+ uint64_t Address) {
+ if (SymbolLookUp) {
+ uint64_t ReferenceType = LLVMDisassembler_ReferenceType_In_PCrel_Load;
+ const char *ReferenceName;
+ (void)SymbolLookUp(DisInfo, Value, &ReferenceType, Address, &ReferenceName);
+ if(ReferenceType == LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr)
+ cStream << "literal pool symbol address: " << ReferenceName;
+ else if(ReferenceType ==
+ LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr) {
+ cStream << "literal pool for: \"";
+ cStream.write_escaped(ReferenceName);
+ cStream << "\"";
+ }
+ else if(ReferenceType ==
+ LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref)
+ cStream << "Objc cfstring ref: @\"" << ReferenceName << "\"";
+ else if(ReferenceType ==
+ LLVMDisassembler_ReferenceType_Out_Objc_Message)
+ cStream << "Objc message: " << ReferenceName;
+ else if(ReferenceType ==
+ LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref)
+ cStream << "Objc message ref: " << ReferenceName;
+ else if(ReferenceType ==
+ LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref)
+ cStream << "Objc selector ref: " << ReferenceName;
+ else if(ReferenceType ==
+ LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref)
+ cStream << "Objc class ref: " << ReferenceName;
+ }
+}
+
+namespace llvm {
+MCSymbolizer *createMCSymbolizer(const Triple &TT, LLVMOpInfoCallback GetOpInfo,
+ LLVMSymbolLookupCallback SymbolLookUp,
+ void *DisInfo, MCContext *Ctx,
+ std::unique_ptr<MCRelocationInfo> &&RelInfo) {
+ assert(Ctx && "No MCContext given for symbolic disassembly");
+
+ return new MCExternalSymbolizer(*Ctx, std::move(RelInfo), GetOpInfo,
+ SymbolLookUp, DisInfo);
+}
+}
diff --git a/llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp b/llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp
new file mode 100644
index 000000000000..64e216e0051d
--- /dev/null
+++ b/llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp
@@ -0,0 +1,30 @@
+//===-- MCRelocationInfo.cpp ----------------------------------------------===//
+//
+// 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/MCDisassembler/MCRelocationInfo.h"
+#include "llvm-c/Disassembler.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+MCRelocationInfo::MCRelocationInfo(MCContext &Ctx) : Ctx(Ctx) {}
+
+MCRelocationInfo::~MCRelocationInfo() = default;
+
+const MCExpr *
+MCRelocationInfo::createExprForCAPIVariantKind(const MCExpr *SubExpr,
+ unsigned VariantKind) {
+ if (VariantKind != LLVMDisassembler_VariantKind_None)
+ return nullptr;
+ return SubExpr;
+}
+
+MCRelocationInfo *llvm::createMCRelocationInfo(const Triple &TT,
+ MCContext &Ctx) {
+ return new MCRelocationInfo(Ctx);
+}
diff --git a/llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp b/llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp
new file mode 100644
index 000000000000..8214a196afb1
--- /dev/null
+++ b/llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp
@@ -0,0 +1,13 @@
+//===-- llvm/MC/MCSymbolizer.cpp - MCSymbolizer class ---------------------===//
+//
+// 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/MCDisassembler/MCSymbolizer.h"
+
+using namespace llvm;
+
+MCSymbolizer::~MCSymbolizer() = default;
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
new file mode 100644
index 000000000000..bcc7c45afc01
--- /dev/null
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -0,0 +1,1950 @@
+//===- lib/MC/MCDwarf.cpp - MCDwarf implementation ------------------------===//
+//
+// 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/MCDwarf.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Config/config.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+/// Manage the .debug_line_str section contents, if we use it.
+class llvm::MCDwarfLineStr {
+ MCSymbol *LineStrLabel = nullptr;
+ StringTableBuilder LineStrings{StringTableBuilder::DWARF};
+ bool UseRelocs = false;
+
+public:
+ /// Construct an instance that can emit .debug_line_str (for use in a normal
+ /// v5 line table).
+ explicit MCDwarfLineStr(MCContext &Ctx) {
+ UseRelocs = Ctx.getAsmInfo()->doesDwarfUseRelocationsAcrossSections();
+ if (UseRelocs)
+ LineStrLabel =
+ Ctx.getObjectFileInfo()->getDwarfLineStrSection()->getBeginSymbol();
+ }
+
+ /// Emit a reference to the string.
+ void emitRef(MCStreamer *MCOS, StringRef Path);
+
+ /// Emit the .debug_line_str section if appropriate.
+ void emitSection(MCStreamer *MCOS);
+};
+
+static inline uint64_t ScaleAddrDelta(MCContext &Context, uint64_t AddrDelta) {
+ unsigned MinInsnLength = Context.getAsmInfo()->getMinInstAlignment();
+ if (MinInsnLength == 1)
+ return AddrDelta;
+ if (AddrDelta % MinInsnLength != 0) {
+ // TODO: report this error, but really only once.
+ ;
+ }
+ return AddrDelta / MinInsnLength;
+}
+
+//
+// This is called when an instruction is assembled into the specified section
+// and if there is information from the last .loc directive that has yet to have
+// a line entry made for it is made.
+//
+void MCDwarfLineEntry::Make(MCObjectStreamer *MCOS, MCSection *Section) {
+ if (!MCOS->getContext().getDwarfLocSeen())
+ return;
+
+ // Create a symbol at in the current section for use in the line entry.
+ MCSymbol *LineSym = MCOS->getContext().createTempSymbol();
+ // Set the value of the symbol to use for the MCDwarfLineEntry.
+ MCOS->EmitLabel(LineSym);
+
+ // Get the current .loc info saved in the context.
+ const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc();
+
+ // Create a (local) line entry with the symbol and the current .loc info.
+ MCDwarfLineEntry LineEntry(LineSym, DwarfLoc);
+
+ // clear DwarfLocSeen saying the current .loc info is now used.
+ MCOS->getContext().clearDwarfLocSeen();
+
+ // Add the line entry to this section's entries.
+ MCOS->getContext()
+ .getMCDwarfLineTable(MCOS->getContext().getDwarfCompileUnitID())
+ .getMCLineSections()
+ .addLineEntry(LineEntry, Section);
+}
+
+//
+// This helper routine returns an expression of End - Start + IntVal .
+//
+static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS,
+ const MCSymbol &Start,
+ const MCSymbol &End,
+ int IntVal) {
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+ const MCExpr *Res =
+ MCSymbolRefExpr::create(&End, Variant, MCOS.getContext());
+ const MCExpr *RHS =
+ MCSymbolRefExpr::create(&Start, Variant, MCOS.getContext());
+ const MCExpr *Res1 =
+ MCBinaryExpr::create(MCBinaryExpr::Sub, Res, RHS, MCOS.getContext());
+ const MCExpr *Res2 =
+ MCConstantExpr::create(IntVal, MCOS.getContext());
+ const MCExpr *Res3 =
+ MCBinaryExpr::create(MCBinaryExpr::Sub, Res1, Res2, MCOS.getContext());
+ return Res3;
+}
+
+//
+// This helper routine returns an expression of Start + IntVal .
+//
+static inline const MCExpr *
+makeStartPlusIntExpr(MCContext &Ctx, const MCSymbol &Start, int IntVal) {
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+ const MCExpr *LHS = MCSymbolRefExpr::create(&Start, Variant, Ctx);
+ const MCExpr *RHS = MCConstantExpr::create(IntVal, Ctx);
+ const MCExpr *Res = MCBinaryExpr::create(MCBinaryExpr::Add, LHS, RHS, Ctx);
+ return Res;
+}
+
+//
+// This emits the Dwarf line table for the specified section from the entries
+// in the LineSection.
+//
+static inline void
+EmitDwarfLineTable(MCObjectStreamer *MCOS, MCSection *Section,
+ const MCLineSection::MCDwarfLineEntryCollection &LineEntries) {
+ unsigned FileNum = 1;
+ unsigned LastLine = 1;
+ unsigned Column = 0;
+ unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
+ unsigned Isa = 0;
+ unsigned Discriminator = 0;
+ MCSymbol *LastLabel = nullptr;
+
+ // Loop through each MCDwarfLineEntry and encode the dwarf line number table.
+ for (const MCDwarfLineEntry &LineEntry : LineEntries) {
+ int64_t LineDelta = static_cast<int64_t>(LineEntry.getLine()) - LastLine;
+
+ if (FileNum != LineEntry.getFileNum()) {
+ FileNum = LineEntry.getFileNum();
+ MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1);
+ MCOS->EmitULEB128IntValue(FileNum);
+ }
+ if (Column != LineEntry.getColumn()) {
+ Column = LineEntry.getColumn();
+ MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1);
+ MCOS->EmitULEB128IntValue(Column);
+ }
+ if (Discriminator != LineEntry.getDiscriminator() &&
+ MCOS->getContext().getDwarfVersion() >= 4) {
+ Discriminator = LineEntry.getDiscriminator();
+ unsigned Size = getULEB128Size(Discriminator);
+ MCOS->EmitIntValue(dwarf::DW_LNS_extended_op, 1);
+ MCOS->EmitULEB128IntValue(Size + 1);
+ MCOS->EmitIntValue(dwarf::DW_LNE_set_discriminator, 1);
+ MCOS->EmitULEB128IntValue(Discriminator);
+ }
+ if (Isa != LineEntry.getIsa()) {
+ Isa = LineEntry.getIsa();
+ MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1);
+ MCOS->EmitULEB128IntValue(Isa);
+ }
+ if ((LineEntry.getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) {
+ Flags = LineEntry.getFlags();
+ MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1);
+ }
+ if (LineEntry.getFlags() & DWARF2_FLAG_BASIC_BLOCK)
+ MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1);
+ if (LineEntry.getFlags() & DWARF2_FLAG_PROLOGUE_END)
+ MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1);
+ if (LineEntry.getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN)
+ MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1);
+
+ MCSymbol *Label = LineEntry.getLabel();
+
+ // At this point we want to emit/create the sequence to encode the delta in
+ // line numbers and the increment of the address from the previous Label
+ // and the current Label.
+ const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo();
+ MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label,
+ asmInfo->getCodePointerSize());
+
+ Discriminator = 0;
+ LastLine = LineEntry.getLine();
+ LastLabel = Label;
+ }
+
+ // 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 = MCOS->endSection(Section);
+
+ // Switch back the dwarf line section, in case endSection had to switch the
+ // section.
+ MCContext &Ctx = MCOS->getContext();
+ MCOS->SwitchSection(Ctx.getObjectFileInfo()->getDwarfLineSection());
+
+ const MCAsmInfo *AsmInfo = Ctx.getAsmInfo();
+ MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd,
+ AsmInfo->getCodePointerSize());
+}
+
+//
+// This emits the Dwarf file and the line tables.
+//
+void MCDwarfLineTable::Emit(MCObjectStreamer *MCOS,
+ MCDwarfLineTableParams Params) {
+ MCContext &context = MCOS->getContext();
+
+ auto &LineTables = context.getMCDwarfLineTables();
+
+ // Bail out early so we don't switch to the debug_line section needlessly and
+ // in doing so create an unnecessary (if empty) section.
+ if (LineTables.empty())
+ return;
+
+ // In a v5 non-split line table, put the strings in a separate section.
+ Optional<MCDwarfLineStr> LineStr;
+ if (context.getDwarfVersion() >= 5)
+ LineStr = MCDwarfLineStr(context);
+
+ // Switch to the section where the table will be emitted into.
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection());
+
+ // Handle the rest of the Compile Units.
+ for (const auto &CUIDTablePair : LineTables) {
+ CUIDTablePair.second.EmitCU(MCOS, Params, LineStr);
+ }
+
+ if (LineStr)
+ LineStr->emitSection(MCOS);
+}
+
+void MCDwarfDwoLineTable::Emit(MCStreamer &MCOS, MCDwarfLineTableParams Params,
+ MCSection *Section) const {
+ if (!HasSplitLineTable)
+ return;
+ Optional<MCDwarfLineStr> NoLineStr(None);
+ MCOS.SwitchSection(Section);
+ MCOS.EmitLabel(Header.Emit(&MCOS, Params, None, NoLineStr).second);
+}
+
+std::pair<MCSymbol *, MCSymbol *>
+MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
+ Optional<MCDwarfLineStr> &LineStr) const {
+ static const char StandardOpcodeLengths[] = {
+ 0, // length of DW_LNS_copy
+ 1, // length of DW_LNS_advance_pc
+ 1, // length of DW_LNS_advance_line
+ 1, // length of DW_LNS_set_file
+ 1, // length of DW_LNS_set_column
+ 0, // length of DW_LNS_negate_stmt
+ 0, // length of DW_LNS_set_basic_block
+ 0, // length of DW_LNS_const_add_pc
+ 1, // length of DW_LNS_fixed_advance_pc
+ 0, // length of DW_LNS_set_prologue_end
+ 0, // length of DW_LNS_set_epilogue_begin
+ 1 // DW_LNS_set_isa
+ };
+ assert(array_lengthof(StandardOpcodeLengths) >=
+ (Params.DWARF2LineOpcodeBase - 1U));
+ return Emit(
+ MCOS, Params,
+ makeArrayRef(StandardOpcodeLengths, Params.DWARF2LineOpcodeBase - 1),
+ LineStr);
+}
+
+static const MCExpr *forceExpAbs(MCStreamer &OS, const MCExpr* Expr) {
+ MCContext &Context = OS.getContext();
+ assert(!isa<MCSymbolRefExpr>(Expr));
+ if (Context.getAsmInfo()->hasAggressiveSymbolFolding())
+ return Expr;
+
+ MCSymbol *ABS = Context.createTempSymbol();
+ OS.EmitAssignment(ABS, Expr);
+ return MCSymbolRefExpr::create(ABS, Context);
+}
+
+static void emitAbsValue(MCStreamer &OS, const MCExpr *Value, unsigned Size) {
+ const MCExpr *ABS = forceExpAbs(OS, Value);
+ OS.EmitValue(ABS, Size);
+}
+
+void MCDwarfLineStr::emitSection(MCStreamer *MCOS) {
+ // Switch to the .debug_line_str section.
+ MCOS->SwitchSection(
+ MCOS->getContext().getObjectFileInfo()->getDwarfLineStrSection());
+ // Emit the strings without perturbing the offsets we used.
+ LineStrings.finalizeInOrder();
+ SmallString<0> Data;
+ Data.resize(LineStrings.getSize());
+ LineStrings.write((uint8_t *)Data.data());
+ MCOS->EmitBinaryData(Data.str());
+}
+
+void MCDwarfLineStr::emitRef(MCStreamer *MCOS, StringRef Path) {
+ int RefSize = 4; // FIXME: Support DWARF-64
+ size_t Offset = LineStrings.add(Path);
+ if (UseRelocs) {
+ MCContext &Ctx = MCOS->getContext();
+ MCOS->EmitValue(makeStartPlusIntExpr(Ctx, *LineStrLabel, Offset), RefSize);
+ } else
+ MCOS->EmitIntValue(Offset, RefSize);
+}
+
+void MCDwarfLineTableHeader::emitV2FileDirTables(MCStreamer *MCOS) const {
+ // First the directory table.
+ for (auto &Dir : MCDwarfDirs) {
+ MCOS->EmitBytes(Dir); // The DirectoryName, and...
+ MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
+ }
+ MCOS->EmitIntValue(0, 1); // Terminate the directory list.
+
+ // Second the file table.
+ for (unsigned i = 1; i < MCDwarfFiles.size(); i++) {
+ assert(!MCDwarfFiles[i].Name.empty());
+ MCOS->EmitBytes(MCDwarfFiles[i].Name); // FileName and...
+ MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
+ MCOS->EmitULEB128IntValue(MCDwarfFiles[i].DirIndex); // Directory number.
+ MCOS->EmitIntValue(0, 1); // Last modification timestamp (always 0).
+ MCOS->EmitIntValue(0, 1); // File size (always 0).
+ }
+ MCOS->EmitIntValue(0, 1); // Terminate the file list.
+}
+
+static void emitOneV5FileEntry(MCStreamer *MCOS, const MCDwarfFile &DwarfFile,
+ bool EmitMD5, bool HasSource,
+ Optional<MCDwarfLineStr> &LineStr) {
+ assert(!DwarfFile.Name.empty());
+ if (LineStr)
+ LineStr->emitRef(MCOS, DwarfFile.Name);
+ else {
+ MCOS->EmitBytes(DwarfFile.Name); // FileName and...
+ MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
+ }
+ MCOS->EmitULEB128IntValue(DwarfFile.DirIndex); // Directory number.
+ if (EmitMD5) {
+ const MD5::MD5Result &Cksum = *DwarfFile.Checksum;
+ MCOS->EmitBinaryData(
+ StringRef(reinterpret_cast<const char *>(Cksum.Bytes.data()),
+ Cksum.Bytes.size()));
+ }
+ if (HasSource) {
+ if (LineStr)
+ LineStr->emitRef(MCOS, DwarfFile.Source.getValueOr(StringRef()));
+ else {
+ MCOS->EmitBytes(
+ DwarfFile.Source.getValueOr(StringRef())); // Source and...
+ MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
+ }
+ }
+}
+
+void MCDwarfLineTableHeader::emitV5FileDirTables(
+ MCStreamer *MCOS, Optional<MCDwarfLineStr> &LineStr) const {
+ // The directory format, which is just a list of the directory paths. In a
+ // non-split object, these are references to .debug_line_str; in a split
+ // object, they are inline strings.
+ MCOS->EmitIntValue(1, 1);
+ MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path);
+ MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp
+ : dwarf::DW_FORM_string);
+ MCOS->EmitULEB128IntValue(MCDwarfDirs.size() + 1);
+ // Try not to emit an empty compilation directory.
+ const StringRef CompDir = CompilationDir.empty()
+ ? MCOS->getContext().getCompilationDir()
+ : StringRef(CompilationDir);
+ if (LineStr) {
+ // Record path strings, emit references here.
+ LineStr->emitRef(MCOS, CompDir);
+ for (const auto &Dir : MCDwarfDirs)
+ LineStr->emitRef(MCOS, Dir);
+ } else {
+ // The list of directory paths. Compilation directory comes first.
+ MCOS->EmitBytes(CompDir);
+ MCOS->EmitBytes(StringRef("\0", 1));
+ for (const auto &Dir : MCDwarfDirs) {
+ MCOS->EmitBytes(Dir); // The DirectoryName, and...
+ MCOS->EmitBytes(StringRef("\0", 1)); // its null terminator.
+ }
+ }
+
+ // The file format, which is the inline null-terminated filename and a
+ // directory index. We don't track file size/timestamp so don't emit them
+ // in the v5 table. Emit MD5 checksums and source if we have them.
+ uint64_t Entries = 2;
+ if (HasAllMD5)
+ Entries += 1;
+ if (HasSource)
+ Entries += 1;
+ MCOS->EmitIntValue(Entries, 1);
+ MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_path);
+ MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp
+ : dwarf::DW_FORM_string);
+ MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_directory_index);
+ MCOS->EmitULEB128IntValue(dwarf::DW_FORM_udata);
+ if (HasAllMD5) {
+ MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_MD5);
+ MCOS->EmitULEB128IntValue(dwarf::DW_FORM_data16);
+ }
+ if (HasSource) {
+ MCOS->EmitULEB128IntValue(dwarf::DW_LNCT_LLVM_source);
+ MCOS->EmitULEB128IntValue(LineStr ? dwarf::DW_FORM_line_strp
+ : dwarf::DW_FORM_string);
+ }
+ // Then the counted list of files. The root file is file #0, then emit the
+ // files as provide by .file directives.
+ // MCDwarfFiles has an unused element [0] so use size() not size()+1.
+ // But sometimes MCDwarfFiles is empty, in which case we still emit one file.
+ MCOS->EmitULEB128IntValue(MCDwarfFiles.empty() ? 1 : MCDwarfFiles.size());
+ // To accommodate assembler source written for DWARF v4 but trying to emit
+ // v5: If we didn't see a root file explicitly, replicate file #1.
+ assert((!RootFile.Name.empty() || MCDwarfFiles.size() >= 1) &&
+ "No root file and no .file directives");
+ emitOneV5FileEntry(MCOS, RootFile.Name.empty() ? MCDwarfFiles[1] : RootFile,
+ HasAllMD5, HasSource, LineStr);
+ for (unsigned i = 1; i < MCDwarfFiles.size(); ++i)
+ emitOneV5FileEntry(MCOS, MCDwarfFiles[i], HasAllMD5, HasSource, LineStr);
+}
+
+std::pair<MCSymbol *, MCSymbol *>
+MCDwarfLineTableHeader::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
+ ArrayRef<char> StandardOpcodeLengths,
+ Optional<MCDwarfLineStr> &LineStr) const {
+ MCContext &context = MCOS->getContext();
+
+ // Create a symbol at the beginning of the line table.
+ MCSymbol *LineStartSym = Label;
+ if (!LineStartSym)
+ LineStartSym = context.createTempSymbol();
+ // Set the value of the symbol, as we are at the start of the line table.
+ MCOS->EmitLabel(LineStartSym);
+
+ // Create a symbol for the end of the section (to be set when we get there).
+ MCSymbol *LineEndSym = context.createTempSymbol();
+
+ // The first 4 bytes is the total length of the information for this
+ // compilation unit (not including these 4 bytes for the length).
+ emitAbsValue(*MCOS,
+ MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym, 4), 4);
+
+ // Next 2 bytes is the Version.
+ unsigned LineTableVersion = context.getDwarfVersion();
+ MCOS->EmitIntValue(LineTableVersion, 2);
+
+ // Keep track of the bytes between the very start and where the header length
+ // comes out.
+ unsigned PreHeaderLengthBytes = 4 + 2;
+
+ // In v5, we get address info next.
+ if (LineTableVersion >= 5) {
+ MCOS->EmitIntValue(context.getAsmInfo()->getCodePointerSize(), 1);
+ MCOS->EmitIntValue(0, 1); // Segment selector; same as EmitGenDwarfAranges.
+ PreHeaderLengthBytes += 2;
+ }
+
+ // Create a symbol for the end of the prologue (to be set when we get there).
+ MCSymbol *ProEndSym = context.createTempSymbol(); // Lprologue_end
+
+ // Length of the prologue, is the next 4 bytes. This is actually the length
+ // from after the length word, to the end of the prologue.
+ emitAbsValue(*MCOS,
+ MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym,
+ (PreHeaderLengthBytes + 4)),
+ 4);
+
+ // Parameters of the state machine, are next.
+ MCOS->EmitIntValue(context.getAsmInfo()->getMinInstAlignment(), 1);
+ // maximum_operations_per_instruction
+ // For non-VLIW architectures this field is always 1.
+ // FIXME: VLIW architectures need to update this field accordingly.
+ if (LineTableVersion >= 4)
+ MCOS->EmitIntValue(1, 1);
+ MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1);
+ MCOS->EmitIntValue(Params.DWARF2LineBase, 1);
+ MCOS->EmitIntValue(Params.DWARF2LineRange, 1);
+ MCOS->EmitIntValue(StandardOpcodeLengths.size() + 1, 1);
+
+ // Standard opcode lengths
+ for (char Length : StandardOpcodeLengths)
+ MCOS->EmitIntValue(Length, 1);
+
+ // Put out the directory and file tables. The formats vary depending on
+ // the version.
+ if (LineTableVersion >= 5)
+ emitV5FileDirTables(MCOS, LineStr);
+ else
+ emitV2FileDirTables(MCOS);
+
+ // This is the end of the prologue, so set the value of the symbol at the
+ // end of the prologue (that was used in a previous expression).
+ MCOS->EmitLabel(ProEndSym);
+
+ return std::make_pair(LineStartSym, LineEndSym);
+}
+
+void MCDwarfLineTable::EmitCU(MCObjectStreamer *MCOS,
+ MCDwarfLineTableParams Params,
+ Optional<MCDwarfLineStr> &LineStr) const {
+ MCSymbol *LineEndSym = Header.Emit(MCOS, Params, LineStr).second;
+
+ // Put out the line tables.
+ for (const auto &LineSec : MCLineSections.getMCLineEntries())
+ EmitDwarfLineTable(MCOS, LineSec.first, LineSec.second);
+
+ // This is the end of the section, so set the value of the symbol at the end
+ // of this section (that was used in a previous expression).
+ MCOS->EmitLabel(LineEndSym);
+}
+
+Expected<unsigned> MCDwarfLineTable::tryGetFile(StringRef &Directory,
+ StringRef &FileName,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ uint16_t DwarfVersion,
+ unsigned FileNumber) {
+ return Header.tryGetFile(Directory, FileName, Checksum, Source, DwarfVersion,
+ FileNumber);
+}
+
+static bool isRootFile(const MCDwarfFile &RootFile, StringRef &Directory,
+ StringRef &FileName, Optional<MD5::MD5Result> Checksum) {
+ if (RootFile.Name.empty() || RootFile.Name != FileName.data())
+ return false;
+ return RootFile.Checksum == Checksum;
+}
+
+Expected<unsigned>
+MCDwarfLineTableHeader::tryGetFile(StringRef &Directory,
+ StringRef &FileName,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ uint16_t DwarfVersion,
+ unsigned FileNumber) {
+ if (Directory == CompilationDir)
+ Directory = "";
+ if (FileName.empty()) {
+ FileName = "<stdin>";
+ Directory = "";
+ }
+ assert(!FileName.empty());
+ // Keep track of whether any or all files have an MD5 checksum.
+ // If any files have embedded source, they all must.
+ if (MCDwarfFiles.empty()) {
+ trackMD5Usage(Checksum.hasValue());
+ HasSource = (Source != None);
+ }
+ if (isRootFile(RootFile, Directory, FileName, Checksum) && DwarfVersion >= 5)
+ return 0;
+ if (FileNumber == 0) {
+ // File numbers start with 1 and/or after any file numbers
+ // allocated by inline-assembler .file directives.
+ FileNumber = MCDwarfFiles.empty() ? 1 : MCDwarfFiles.size();
+ SmallString<256> Buffer;
+ auto IterBool = SourceIdMap.insert(
+ std::make_pair((Directory + Twine('\0') + FileName).toStringRef(Buffer),
+ FileNumber));
+ if (!IterBool.second)
+ return IterBool.first->second;
+ }
+ // Make space for this FileNumber in the MCDwarfFiles vector if needed.
+ if (FileNumber >= MCDwarfFiles.size())
+ MCDwarfFiles.resize(FileNumber + 1);
+
+ // Get the new MCDwarfFile slot for this FileNumber.
+ MCDwarfFile &File = MCDwarfFiles[FileNumber];
+
+ // It is an error to see the same number more than once.
+ if (!File.Name.empty())
+ return make_error<StringError>("file number already allocated",
+ inconvertibleErrorCode());
+
+ // If any files have embedded source, they all must.
+ if (HasSource != (Source != None))
+ return make_error<StringError>("inconsistent use of embedded source",
+ inconvertibleErrorCode());
+
+ if (Directory.empty()) {
+ // Separate the directory part from the basename of the FileName.
+ StringRef tFileName = sys::path::filename(FileName);
+ if (!tFileName.empty()) {
+ Directory = sys::path::parent_path(FileName);
+ if (!Directory.empty())
+ FileName = tFileName;
+ }
+ }
+
+ // Find or make an entry in the MCDwarfDirs vector for this Directory.
+ // Capture directory name.
+ unsigned DirIndex;
+ if (Directory.empty()) {
+ // For FileNames with no directories a DirIndex of 0 is used.
+ DirIndex = 0;
+ } else {
+ DirIndex = llvm::find(MCDwarfDirs, Directory) - MCDwarfDirs.begin();
+ if (DirIndex >= MCDwarfDirs.size())
+ MCDwarfDirs.push_back(Directory);
+ // The DirIndex is one based, as DirIndex of 0 is used for FileNames with
+ // no directories. MCDwarfDirs[] is unlike MCDwarfFiles[] in that the
+ // directory names are stored at MCDwarfDirs[DirIndex-1] where FileNames
+ // are stored at MCDwarfFiles[FileNumber].Name .
+ DirIndex++;
+ }
+
+ File.Name = FileName;
+ File.DirIndex = DirIndex;
+ File.Checksum = Checksum;
+ trackMD5Usage(Checksum.hasValue());
+ File.Source = Source;
+ if (Source)
+ HasSource = true;
+
+ // return the allocated FileNumber.
+ return FileNumber;
+}
+
+/// Utility function to emit the encoding to a streamer.
+void MCDwarfLineAddr::Emit(MCStreamer *MCOS, MCDwarfLineTableParams Params,
+ int64_t LineDelta, uint64_t AddrDelta) {
+ MCContext &Context = MCOS->getContext();
+ SmallString<256> Tmp;
+ raw_svector_ostream OS(Tmp);
+ MCDwarfLineAddr::Encode(Context, Params, LineDelta, AddrDelta, OS);
+ MCOS->EmitBytes(OS.str());
+}
+
+/// Given a special op, return the address skip amount (in units of
+/// DWARF2_LINE_MIN_INSN_LENGTH).
+static uint64_t SpecialAddr(MCDwarfLineTableParams Params, uint64_t op) {
+ return (op - Params.DWARF2LineOpcodeBase) / Params.DWARF2LineRange;
+}
+
+/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas.
+void MCDwarfLineAddr::Encode(MCContext &Context, MCDwarfLineTableParams Params,
+ int64_t LineDelta, uint64_t AddrDelta,
+ raw_ostream &OS) {
+ uint64_t Temp, Opcode;
+ bool NeedCopy = false;
+
+ // The maximum address skip amount that can be encoded with a special op.
+ uint64_t MaxSpecialAddrDelta = SpecialAddr(Params, 255);
+
+ // Scale the address delta by the minimum instruction length.
+ AddrDelta = ScaleAddrDelta(Context, AddrDelta);
+
+ // A LineDelta of INT64_MAX is a signal that this is actually a
+ // DW_LNE_end_sequence. We cannot use special opcodes here, since we want the
+ // end_sequence to emit the matrix entry.
+ if (LineDelta == INT64_MAX) {
+ if (AddrDelta == MaxSpecialAddrDelta)
+ OS << char(dwarf::DW_LNS_const_add_pc);
+ else if (AddrDelta) {
+ OS << char(dwarf::DW_LNS_advance_pc);
+ encodeULEB128(AddrDelta, OS);
+ }
+ OS << char(dwarf::DW_LNS_extended_op);
+ OS << char(1);
+ OS << char(dwarf::DW_LNE_end_sequence);
+ return;
+ }
+
+ // Bias the line delta by the base.
+ Temp = LineDelta - Params.DWARF2LineBase;
+
+ // If the line increment is out of range of a special opcode, we must encode
+ // it with DW_LNS_advance_line.
+ if (Temp >= Params.DWARF2LineRange ||
+ Temp + Params.DWARF2LineOpcodeBase > 255) {
+ OS << char(dwarf::DW_LNS_advance_line);
+ encodeSLEB128(LineDelta, OS);
+
+ LineDelta = 0;
+ Temp = 0 - Params.DWARF2LineBase;
+ NeedCopy = true;
+ }
+
+ // Use DW_LNS_copy instead of a "line +0, addr +0" special opcode.
+ if (LineDelta == 0 && AddrDelta == 0) {
+ OS << char(dwarf::DW_LNS_copy);
+ return;
+ }
+
+ // Bias the opcode by the special opcode base.
+ Temp += Params.DWARF2LineOpcodeBase;
+
+ // Avoid overflow when addr_delta is large.
+ if (AddrDelta < 256 + MaxSpecialAddrDelta) {
+ // Try using a special opcode.
+ Opcode = Temp + AddrDelta * Params.DWARF2LineRange;
+ if (Opcode <= 255) {
+ OS << char(Opcode);
+ return;
+ }
+
+ // Try using DW_LNS_const_add_pc followed by special op.
+ Opcode = Temp + (AddrDelta - MaxSpecialAddrDelta) * Params.DWARF2LineRange;
+ if (Opcode <= 255) {
+ OS << char(dwarf::DW_LNS_const_add_pc);
+ OS << char(Opcode);
+ return;
+ }
+ }
+
+ // Otherwise use DW_LNS_advance_pc.
+ OS << char(dwarf::DW_LNS_advance_pc);
+ encodeULEB128(AddrDelta, OS);
+
+ if (NeedCopy)
+ OS << char(dwarf::DW_LNS_copy);
+ else {
+ assert(Temp <= 255 && "Buggy special opcode encoding.");
+ OS << char(Temp);
+ }
+}
+
+bool MCDwarfLineAddr::FixedEncode(MCContext &Context,
+ MCDwarfLineTableParams Params,
+ int64_t LineDelta, uint64_t AddrDelta,
+ raw_ostream &OS,
+ uint32_t *Offset, uint32_t *Size) {
+ if (LineDelta != INT64_MAX) {
+ OS << char(dwarf::DW_LNS_advance_line);
+ encodeSLEB128(LineDelta, OS);
+ }
+
+ // Use address delta to adjust address or use absolute address to adjust
+ // address.
+ bool SetDelta;
+ // According to DWARF spec., the DW_LNS_fixed_advance_pc opcode takes a
+ // single uhalf (unencoded) operand. So, the maximum value of AddrDelta
+ // is 65535. We set a conservative upper bound for it for relaxation.
+ if (AddrDelta > 60000) {
+ const MCAsmInfo *asmInfo = Context.getAsmInfo();
+ unsigned AddrSize = asmInfo->getCodePointerSize();
+
+ OS << char(dwarf::DW_LNS_extended_op);
+ encodeULEB128(1 + AddrSize, OS);
+ OS << char(dwarf::DW_LNE_set_address);
+ // Generate fixup for the address.
+ *Offset = OS.tell();
+ *Size = AddrSize;
+ SetDelta = false;
+ OS.write_zeros(AddrSize);
+ } else {
+ OS << char(dwarf::DW_LNS_fixed_advance_pc);
+ // Generate fixup for 2-bytes address delta.
+ *Offset = OS.tell();
+ *Size = 2;
+ SetDelta = true;
+ OS << char(0);
+ OS << char(0);
+ }
+
+ if (LineDelta == INT64_MAX) {
+ OS << char(dwarf::DW_LNS_extended_op);
+ OS << char(1);
+ OS << char(dwarf::DW_LNE_end_sequence);
+ } else {
+ OS << char(dwarf::DW_LNS_copy);
+ }
+
+ return SetDelta;
+}
+
+// Utility function to write a tuple for .debug_abbrev.
+static void EmitAbbrev(MCStreamer *MCOS, uint64_t Name, uint64_t Form) {
+ MCOS->EmitULEB128IntValue(Name);
+ MCOS->EmitULEB128IntValue(Form);
+}
+
+// When generating dwarf for assembly source files this emits
+// the data for .debug_abbrev section which contains three DIEs.
+static void EmitGenDwarfAbbrev(MCStreamer *MCOS) {
+ MCContext &context = MCOS->getContext();
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection());
+
+ // DW_TAG_compile_unit DIE abbrev (1).
+ MCOS->EmitULEB128IntValue(1);
+ MCOS->EmitULEB128IntValue(dwarf::DW_TAG_compile_unit);
+ MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
+ EmitAbbrev(MCOS, dwarf::DW_AT_stmt_list, context.getDwarfVersion() >= 4
+ ? dwarf::DW_FORM_sec_offset
+ : dwarf::DW_FORM_data4);
+ if (context.getGenDwarfSectionSyms().size() > 1 &&
+ context.getDwarfVersion() >= 3) {
+ EmitAbbrev(MCOS, dwarf::DW_AT_ranges, context.getDwarfVersion() >= 4
+ ? dwarf::DW_FORM_sec_offset
+ : dwarf::DW_FORM_data4);
+ } else {
+ EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
+ EmitAbbrev(MCOS, dwarf::DW_AT_high_pc, dwarf::DW_FORM_addr);
+ }
+ EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
+ if (!context.getCompilationDir().empty())
+ EmitAbbrev(MCOS, dwarf::DW_AT_comp_dir, dwarf::DW_FORM_string);
+ StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
+ if (!DwarfDebugFlags.empty())
+ EmitAbbrev(MCOS, dwarf::DW_AT_APPLE_flags, dwarf::DW_FORM_string);
+ EmitAbbrev(MCOS, dwarf::DW_AT_producer, dwarf::DW_FORM_string);
+ EmitAbbrev(MCOS, dwarf::DW_AT_language, dwarf::DW_FORM_data2);
+ EmitAbbrev(MCOS, 0, 0);
+
+ // DW_TAG_label DIE abbrev (2).
+ MCOS->EmitULEB128IntValue(2);
+ MCOS->EmitULEB128IntValue(dwarf::DW_TAG_label);
+ MCOS->EmitIntValue(dwarf::DW_CHILDREN_yes, 1);
+ EmitAbbrev(MCOS, dwarf::DW_AT_name, dwarf::DW_FORM_string);
+ EmitAbbrev(MCOS, dwarf::DW_AT_decl_file, dwarf::DW_FORM_data4);
+ EmitAbbrev(MCOS, dwarf::DW_AT_decl_line, dwarf::DW_FORM_data4);
+ EmitAbbrev(MCOS, dwarf::DW_AT_low_pc, dwarf::DW_FORM_addr);
+ EmitAbbrev(MCOS, dwarf::DW_AT_prototyped, dwarf::DW_FORM_flag);
+ EmitAbbrev(MCOS, 0, 0);
+
+ // DW_TAG_unspecified_parameters DIE abbrev (3).
+ MCOS->EmitULEB128IntValue(3);
+ MCOS->EmitULEB128IntValue(dwarf::DW_TAG_unspecified_parameters);
+ MCOS->EmitIntValue(dwarf::DW_CHILDREN_no, 1);
+ EmitAbbrev(MCOS, 0, 0);
+
+ // Terminate the abbreviations for this compilation unit.
+ MCOS->EmitIntValue(0, 1);
+}
+
+// When generating dwarf for assembly source files this emits the data for
+// .debug_aranges section. This section contains a header and a table of pairs
+// of PointerSize'ed values for the address and size of section(s) with line
+// table entries.
+static void EmitGenDwarfAranges(MCStreamer *MCOS,
+ const MCSymbol *InfoSectionSymbol) {
+ MCContext &context = MCOS->getContext();
+
+ auto &Sections = context.getGenDwarfSectionSyms();
+
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
+
+ // This will be the length of the .debug_aranges section, first account for
+ // the size of each item in the header (see below where we emit these items).
+ int Length = 4 + 2 + 4 + 1 + 1;
+
+ // Figure the padding after the header before the table of address and size
+ // pairs who's values are PointerSize'ed.
+ const MCAsmInfo *asmInfo = context.getAsmInfo();
+ int AddrSize = asmInfo->getCodePointerSize();
+ int Pad = 2 * AddrSize - (Length & (2 * AddrSize - 1));
+ if (Pad == 2 * AddrSize)
+ Pad = 0;
+ Length += Pad;
+
+ // Add the size of the pair of PointerSize'ed values for the address and size
+ // of each section we have in the table.
+ Length += 2 * AddrSize * Sections.size();
+ // And the pair of terminating zeros.
+ Length += 2 * AddrSize;
+
+ // Emit the header for this section.
+ // The 4 byte length not including the 4 byte value for the length.
+ MCOS->EmitIntValue(Length - 4, 4);
+ // The 2 byte version, which is 2.
+ MCOS->EmitIntValue(2, 2);
+ // The 4 byte offset to the compile unit in the .debug_info from the start
+ // of the .debug_info.
+ if (InfoSectionSymbol)
+ MCOS->EmitSymbolValue(InfoSectionSymbol, 4,
+ asmInfo->needsDwarfSectionOffsetDirective());
+ else
+ MCOS->EmitIntValue(0, 4);
+ // The 1 byte size of an address.
+ MCOS->EmitIntValue(AddrSize, 1);
+ // The 1 byte size of a segment descriptor, we use a value of zero.
+ MCOS->EmitIntValue(0, 1);
+ // Align the header with the padding if needed, before we put out the table.
+ for(int i = 0; i < Pad; i++)
+ MCOS->EmitIntValue(0, 1);
+
+ // Now emit the table of pairs of PointerSize'ed values for the section
+ // addresses and sizes.
+ for (MCSection *Sec : Sections) {
+ const MCSymbol *StartSymbol = Sec->getBeginSymbol();
+ MCSymbol *EndSymbol = Sec->getEndSymbol(context);
+ assert(StartSymbol && "StartSymbol must not be NULL");
+ assert(EndSymbol && "EndSymbol must not be NULL");
+
+ const MCExpr *Addr = MCSymbolRefExpr::create(
+ StartSymbol, MCSymbolRefExpr::VK_None, context);
+ const MCExpr *Size = MakeStartMinusEndExpr(*MCOS,
+ *StartSymbol, *EndSymbol, 0);
+ MCOS->EmitValue(Addr, AddrSize);
+ emitAbsValue(*MCOS, Size, AddrSize);
+ }
+
+ // And finally the pair of terminating zeros.
+ MCOS->EmitIntValue(0, AddrSize);
+ MCOS->EmitIntValue(0, AddrSize);
+}
+
+// When generating dwarf for assembly source files this emits the data for
+// .debug_info section which contains three parts. The header, the compile_unit
+// DIE and a list of label DIEs.
+static void EmitGenDwarfInfo(MCStreamer *MCOS,
+ const MCSymbol *AbbrevSectionSymbol,
+ const MCSymbol *LineSectionSymbol,
+ const MCSymbol *RangesSectionSymbol) {
+ MCContext &context = MCOS->getContext();
+
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
+
+ // Create a symbol at the start and end of this section used in here for the
+ // expression to calculate the length in the header.
+ MCSymbol *InfoStart = context.createTempSymbol();
+ MCOS->EmitLabel(InfoStart);
+ MCSymbol *InfoEnd = context.createTempSymbol();
+
+ // First part: the header.
+
+ // The 4 byte total length of the information for this compilation unit, not
+ // including these 4 bytes.
+ const MCExpr *Length = MakeStartMinusEndExpr(*MCOS, *InfoStart, *InfoEnd, 4);
+ emitAbsValue(*MCOS, Length, 4);
+
+ // The 2 byte DWARF version.
+ MCOS->EmitIntValue(context.getDwarfVersion(), 2);
+
+ // The DWARF v5 header has unit type, address size, abbrev offset.
+ // Earlier versions have abbrev offset, address size.
+ const MCAsmInfo &AsmInfo = *context.getAsmInfo();
+ int AddrSize = AsmInfo.getCodePointerSize();
+ if (context.getDwarfVersion() >= 5) {
+ MCOS->EmitIntValue(dwarf::DW_UT_compile, 1);
+ MCOS->EmitIntValue(AddrSize, 1);
+ }
+ // The 4 byte offset to the debug abbrevs from the start of the .debug_abbrev,
+ // it is at the start of that section so this is zero.
+ if (AbbrevSectionSymbol == nullptr)
+ MCOS->EmitIntValue(0, 4);
+ else
+ MCOS->EmitSymbolValue(AbbrevSectionSymbol, 4,
+ AsmInfo.needsDwarfSectionOffsetDirective());
+ if (context.getDwarfVersion() <= 4)
+ MCOS->EmitIntValue(AddrSize, 1);
+
+ // Second part: the compile_unit DIE.
+
+ // The DW_TAG_compile_unit DIE abbrev (1).
+ MCOS->EmitULEB128IntValue(1);
+
+ // DW_AT_stmt_list, a 4 byte offset from the start of the .debug_line section,
+ // which is at the start of that section so this is zero.
+ if (LineSectionSymbol)
+ MCOS->EmitSymbolValue(LineSectionSymbol, 4,
+ AsmInfo.needsDwarfSectionOffsetDirective());
+ else
+ MCOS->EmitIntValue(0, 4);
+
+ if (RangesSectionSymbol) {
+ // There are multiple sections containing code, so we must use the
+ // .debug_ranges sections.
+
+ // AT_ranges, the 4 byte offset from the start of the .debug_ranges section
+ // to the address range list for this compilation unit.
+ MCOS->EmitSymbolValue(RangesSectionSymbol, 4);
+ } else {
+ // If we only have one non-empty code section, we can use the simpler
+ // AT_low_pc and AT_high_pc attributes.
+
+ // Find the first (and only) non-empty text section
+ auto &Sections = context.getGenDwarfSectionSyms();
+ const auto TextSection = Sections.begin();
+ assert(TextSection != Sections.end() && "No text section found");
+
+ MCSymbol *StartSymbol = (*TextSection)->getBeginSymbol();
+ MCSymbol *EndSymbol = (*TextSection)->getEndSymbol(context);
+ assert(StartSymbol && "StartSymbol must not be NULL");
+ assert(EndSymbol && "EndSymbol must not be NULL");
+
+ // AT_low_pc, the first address of the default .text section.
+ const MCExpr *Start = MCSymbolRefExpr::create(
+ StartSymbol, MCSymbolRefExpr::VK_None, context);
+ MCOS->EmitValue(Start, AddrSize);
+
+ // AT_high_pc, the last address of the default .text section.
+ const MCExpr *End = MCSymbolRefExpr::create(
+ EndSymbol, MCSymbolRefExpr::VK_None, context);
+ MCOS->EmitValue(End, AddrSize);
+ }
+
+ // AT_name, the name of the source file. Reconstruct from the first directory
+ // and file table entries.
+ const SmallVectorImpl<std::string> &MCDwarfDirs = context.getMCDwarfDirs();
+ if (MCDwarfDirs.size() > 0) {
+ MCOS->EmitBytes(MCDwarfDirs[0]);
+ MCOS->EmitBytes(sys::path::get_separator());
+ }
+ const SmallVectorImpl<MCDwarfFile> &MCDwarfFiles = context.getMCDwarfFiles();
+ // MCDwarfFiles might be empty if we have an empty source file.
+ // If it's not empty, [0] is unused and [1] is the first actual file.
+ assert(MCDwarfFiles.empty() || MCDwarfFiles.size() >= 2);
+ const MCDwarfFile &RootFile =
+ MCDwarfFiles.empty()
+ ? context.getMCDwarfLineTable(/*CUID=*/0).getRootFile()
+ : MCDwarfFiles[1];
+ MCOS->EmitBytes(RootFile.Name);
+ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+ // AT_comp_dir, the working directory the assembly was done in.
+ if (!context.getCompilationDir().empty()) {
+ MCOS->EmitBytes(context.getCompilationDir());
+ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+ }
+
+ // AT_APPLE_flags, the command line arguments of the assembler tool.
+ StringRef DwarfDebugFlags = context.getDwarfDebugFlags();
+ if (!DwarfDebugFlags.empty()){
+ MCOS->EmitBytes(DwarfDebugFlags);
+ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+ }
+
+ // AT_producer, the version of the assembler tool.
+ StringRef DwarfDebugProducer = context.getDwarfDebugProducer();
+ if (!DwarfDebugProducer.empty())
+ MCOS->EmitBytes(DwarfDebugProducer);
+ else
+ MCOS->EmitBytes(StringRef("llvm-mc (based on LLVM " PACKAGE_VERSION ")"));
+ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+ // AT_language, a 4 byte value. We use DW_LANG_Mips_Assembler as the dwarf2
+ // draft has no standard code for assembler.
+ MCOS->EmitIntValue(dwarf::DW_LANG_Mips_Assembler, 2);
+
+ // Third part: the list of label DIEs.
+
+ // Loop on saved info for dwarf labels and create the DIEs for them.
+ const std::vector<MCGenDwarfLabelEntry> &Entries =
+ MCOS->getContext().getMCGenDwarfLabelEntries();
+ for (const auto &Entry : Entries) {
+ // The DW_TAG_label DIE abbrev (2).
+ MCOS->EmitULEB128IntValue(2);
+
+ // AT_name, of the label without any leading underbar.
+ MCOS->EmitBytes(Entry.getName());
+ MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string.
+
+ // AT_decl_file, index into the file table.
+ MCOS->EmitIntValue(Entry.getFileNumber(), 4);
+
+ // AT_decl_line, source line number.
+ MCOS->EmitIntValue(Entry.getLineNumber(), 4);
+
+ // AT_low_pc, start address of the label.
+ const MCExpr *AT_low_pc = MCSymbolRefExpr::create(Entry.getLabel(),
+ MCSymbolRefExpr::VK_None, context);
+ MCOS->EmitValue(AT_low_pc, AddrSize);
+
+ // DW_AT_prototyped, a one byte flag value of 0 saying we have no prototype.
+ MCOS->EmitIntValue(0, 1);
+
+ // The DW_TAG_unspecified_parameters DIE abbrev (3).
+ MCOS->EmitULEB128IntValue(3);
+
+ // Add the NULL DIE terminating the DW_TAG_unspecified_parameters DIE's.
+ MCOS->EmitIntValue(0, 1);
+ }
+
+ // Add the NULL DIE terminating the Compile Unit DIE's.
+ MCOS->EmitIntValue(0, 1);
+
+ // Now set the value of the symbol at the end of the info section.
+ MCOS->EmitLabel(InfoEnd);
+}
+
+// When generating dwarf for assembly source files this emits the data for
+// .debug_ranges section. We only emit one range list, which spans all of the
+// executable sections of this file.
+static void EmitGenDwarfRanges(MCStreamer *MCOS) {
+ MCContext &context = MCOS->getContext();
+ auto &Sections = context.getGenDwarfSectionSyms();
+
+ const MCAsmInfo *AsmInfo = context.getAsmInfo();
+ int AddrSize = AsmInfo->getCodePointerSize();
+
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection());
+
+ for (MCSection *Sec : Sections) {
+ const MCSymbol *StartSymbol = Sec->getBeginSymbol();
+ MCSymbol *EndSymbol = Sec->getEndSymbol(context);
+ assert(StartSymbol && "StartSymbol must not be NULL");
+ assert(EndSymbol && "EndSymbol must not be NULL");
+
+ // Emit a base address selection entry for the start of this section
+ const MCExpr *SectionStartAddr = MCSymbolRefExpr::create(
+ StartSymbol, MCSymbolRefExpr::VK_None, context);
+ MCOS->emitFill(AddrSize, 0xFF);
+ MCOS->EmitValue(SectionStartAddr, AddrSize);
+
+ // Emit a range list entry spanning this section
+ const MCExpr *SectionSize = MakeStartMinusEndExpr(*MCOS,
+ *StartSymbol, *EndSymbol, 0);
+ MCOS->EmitIntValue(0, AddrSize);
+ emitAbsValue(*MCOS, SectionSize, AddrSize);
+ }
+
+ // Emit end of list entry
+ MCOS->EmitIntValue(0, AddrSize);
+ MCOS->EmitIntValue(0, AddrSize);
+}
+
+//
+// When generating dwarf for assembly source files this emits the Dwarf
+// sections.
+//
+void MCGenDwarfInfo::Emit(MCStreamer *MCOS) {
+ MCContext &context = MCOS->getContext();
+
+ // Create the dwarf sections in this order (.debug_line already created).
+ const MCAsmInfo *AsmInfo = context.getAsmInfo();
+ bool CreateDwarfSectionSymbols =
+ AsmInfo->doesDwarfUseRelocationsAcrossSections();
+ MCSymbol *LineSectionSymbol = nullptr;
+ if (CreateDwarfSectionSymbols)
+ LineSectionSymbol = MCOS->getDwarfLineTableSymbol(0);
+ MCSymbol *AbbrevSectionSymbol = nullptr;
+ MCSymbol *InfoSectionSymbol = nullptr;
+ MCSymbol *RangesSectionSymbol = nullptr;
+
+ // Create end symbols for each section, and remove empty sections
+ MCOS->getContext().finalizeDwarfSections(*MCOS);
+
+ // If there are no sections to generate debug info for, we don't need
+ // to do anything
+ if (MCOS->getContext().getGenDwarfSectionSyms().empty())
+ return;
+
+ // We only use the .debug_ranges section if we have multiple code sections,
+ // and we are emitting a DWARF version which supports it.
+ const bool UseRangesSection =
+ MCOS->getContext().getGenDwarfSectionSyms().size() > 1 &&
+ MCOS->getContext().getDwarfVersion() >= 3;
+ CreateDwarfSectionSymbols |= UseRangesSection;
+
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfInfoSection());
+ if (CreateDwarfSectionSymbols) {
+ InfoSectionSymbol = context.createTempSymbol();
+ MCOS->EmitLabel(InfoSectionSymbol);
+ }
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfAbbrevSection());
+ if (CreateDwarfSectionSymbols) {
+ AbbrevSectionSymbol = context.createTempSymbol();
+ MCOS->EmitLabel(AbbrevSectionSymbol);
+ }
+ if (UseRangesSection) {
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfRangesSection());
+ if (CreateDwarfSectionSymbols) {
+ RangesSectionSymbol = context.createTempSymbol();
+ MCOS->EmitLabel(RangesSectionSymbol);
+ }
+ }
+
+ assert((RangesSectionSymbol != nullptr) || !UseRangesSection);
+
+ MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection());
+
+ // Output the data for .debug_aranges section.
+ EmitGenDwarfAranges(MCOS, InfoSectionSymbol);
+
+ if (UseRangesSection)
+ EmitGenDwarfRanges(MCOS);
+
+ // Output the data for .debug_abbrev section.
+ EmitGenDwarfAbbrev(MCOS);
+
+ // Output the data for .debug_info section.
+ EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol,
+ RangesSectionSymbol);
+}
+
+//
+// When generating dwarf for assembly source files this is called when symbol
+// for a label is created. If this symbol is not a temporary and is in the
+// section that dwarf is being generated for, save the needed info to create
+// a dwarf label.
+//
+void MCGenDwarfLabelEntry::Make(MCSymbol *Symbol, MCStreamer *MCOS,
+ SourceMgr &SrcMgr, SMLoc &Loc) {
+ // We won't create dwarf labels for temporary symbols.
+ if (Symbol->isTemporary())
+ return;
+ MCContext &context = MCOS->getContext();
+ // We won't create dwarf labels for symbols in sections that we are not
+ // generating debug info for.
+ if (!context.getGenDwarfSectionSyms().count(MCOS->getCurrentSectionOnly()))
+ return;
+
+ // The dwarf label's name does not have the symbol name's leading
+ // underbar if any.
+ StringRef Name = Symbol->getName();
+ if (Name.startswith("_"))
+ Name = Name.substr(1, Name.size()-1);
+
+ // Get the dwarf file number to be used for the dwarf label.
+ unsigned FileNumber = context.getGenDwarfFileNumber();
+
+ // Finding the line number is the expensive part which is why we just don't
+ // pass it in as for some symbols we won't create a dwarf label.
+ unsigned CurBuffer = SrcMgr.FindBufferContainingLoc(Loc);
+ unsigned LineNumber = SrcMgr.FindLineNumber(Loc, CurBuffer);
+
+ // We create a temporary symbol for use for the AT_high_pc and AT_low_pc
+ // values so that they don't have things like an ARM thumb bit from the
+ // original symbol. So when used they won't get a low bit set after
+ // relocation.
+ MCSymbol *Label = context.createTempSymbol();
+ MCOS->EmitLabel(Label);
+
+ // Create and entry for the info and add it to the other entries.
+ MCOS->getContext().addMCGenDwarfLabelEntry(
+ MCGenDwarfLabelEntry(Name, FileNumber, LineNumber, Label));
+}
+
+static int getDataAlignmentFactor(MCStreamer &streamer) {
+ MCContext &context = streamer.getContext();
+ const MCAsmInfo *asmInfo = context.getAsmInfo();
+ int size = asmInfo->getCalleeSaveStackSlotSize();
+ if (asmInfo->isStackGrowthDirectionUp())
+ return size;
+ else
+ return -size;
+}
+
+static unsigned getSizeForEncoding(MCStreamer &streamer,
+ unsigned symbolEncoding) {
+ MCContext &context = streamer.getContext();
+ unsigned format = symbolEncoding & 0x0f;
+ switch (format) {
+ default: llvm_unreachable("Unknown Encoding");
+ case dwarf::DW_EH_PE_absptr:
+ case dwarf::DW_EH_PE_signed:
+ return context.getAsmInfo()->getCodePointerSize();
+ case dwarf::DW_EH_PE_udata2:
+ case dwarf::DW_EH_PE_sdata2:
+ return 2;
+ case dwarf::DW_EH_PE_udata4:
+ case dwarf::DW_EH_PE_sdata4:
+ return 4;
+ case dwarf::DW_EH_PE_udata8:
+ case dwarf::DW_EH_PE_sdata8:
+ return 8;
+ }
+}
+
+static void emitFDESymbol(MCObjectStreamer &streamer, const MCSymbol &symbol,
+ unsigned symbolEncoding, bool isEH) {
+ MCContext &context = streamer.getContext();
+ const MCAsmInfo *asmInfo = context.getAsmInfo();
+ const MCExpr *v = asmInfo->getExprForFDESymbol(&symbol,
+ symbolEncoding,
+ streamer);
+ unsigned size = getSizeForEncoding(streamer, symbolEncoding);
+ if (asmInfo->doDwarfFDESymbolsUseAbsDiff() && isEH)
+ emitAbsValue(streamer, v, size);
+ else
+ streamer.EmitValue(v, size);
+}
+
+static void EmitPersonality(MCStreamer &streamer, const MCSymbol &symbol,
+ unsigned symbolEncoding) {
+ MCContext &context = streamer.getContext();
+ const MCAsmInfo *asmInfo = context.getAsmInfo();
+ const MCExpr *v = asmInfo->getExprForPersonalitySymbol(&symbol,
+ symbolEncoding,
+ streamer);
+ unsigned size = getSizeForEncoding(streamer, symbolEncoding);
+ streamer.EmitValue(v, size);
+}
+
+namespace {
+
+class FrameEmitterImpl {
+ int CFAOffset = 0;
+ int InitialCFAOffset = 0;
+ bool IsEH;
+ MCObjectStreamer &Streamer;
+
+public:
+ FrameEmitterImpl(bool IsEH, MCObjectStreamer &Streamer)
+ : IsEH(IsEH), Streamer(Streamer) {}
+
+ /// Emit the unwind information in a compact way.
+ void EmitCompactUnwind(const MCDwarfFrameInfo &frame);
+
+ const MCSymbol &EmitCIE(const MCDwarfFrameInfo &F);
+ void EmitFDE(const MCSymbol &cieStart, const MCDwarfFrameInfo &frame,
+ bool LastInSection, const MCSymbol &SectionStart);
+ void EmitCFIInstructions(ArrayRef<MCCFIInstruction> Instrs,
+ MCSymbol *BaseLabel);
+ void EmitCFIInstruction(const MCCFIInstruction &Instr);
+};
+
+} // end anonymous namespace
+
+static void emitEncodingByte(MCObjectStreamer &Streamer, unsigned Encoding) {
+ Streamer.EmitIntValue(Encoding, 1);
+}
+
+void FrameEmitterImpl::EmitCFIInstruction(const MCCFIInstruction &Instr) {
+ int dataAlignmentFactor = getDataAlignmentFactor(Streamer);
+ auto *MRI = Streamer.getContext().getRegisterInfo();
+
+ switch (Instr.getOperation()) {
+ case MCCFIInstruction::OpRegister: {
+ unsigned Reg1 = Instr.getRegister();
+ unsigned Reg2 = Instr.getRegister2();
+ if (!IsEH) {
+ Reg1 = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg1);
+ Reg2 = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg2);
+ }
+ Streamer.EmitIntValue(dwarf::DW_CFA_register, 1);
+ Streamer.EmitULEB128IntValue(Reg1);
+ Streamer.EmitULEB128IntValue(Reg2);
+ return;
+ }
+ case MCCFIInstruction::OpWindowSave:
+ Streamer.EmitIntValue(dwarf::DW_CFA_GNU_window_save, 1);
+ return;
+
+ case MCCFIInstruction::OpNegateRAState:
+ Streamer.EmitIntValue(dwarf::DW_CFA_AARCH64_negate_ra_state, 1);
+ return;
+
+ case MCCFIInstruction::OpUndefined: {
+ unsigned Reg = Instr.getRegister();
+ Streamer.EmitIntValue(dwarf::DW_CFA_undefined, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+ return;
+ }
+ case MCCFIInstruction::OpAdjustCfaOffset:
+ case MCCFIInstruction::OpDefCfaOffset: {
+ const bool IsRelative =
+ Instr.getOperation() == MCCFIInstruction::OpAdjustCfaOffset;
+
+ Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1);
+
+ if (IsRelative)
+ CFAOffset += Instr.getOffset();
+ else
+ CFAOffset = -Instr.getOffset();
+
+ Streamer.EmitULEB128IntValue(CFAOffset);
+
+ return;
+ }
+ case MCCFIInstruction::OpDefCfa: {
+ unsigned Reg = Instr.getRegister();
+ if (!IsEH)
+ Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);
+ Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+ CFAOffset = -Instr.getOffset();
+ Streamer.EmitULEB128IntValue(CFAOffset);
+
+ return;
+ }
+ case MCCFIInstruction::OpDefCfaRegister: {
+ unsigned Reg = Instr.getRegister();
+ if (!IsEH)
+ Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);
+ Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+
+ return;
+ }
+ case MCCFIInstruction::OpOffset:
+ case MCCFIInstruction::OpRelOffset: {
+ const bool IsRelative =
+ Instr.getOperation() == MCCFIInstruction::OpRelOffset;
+
+ unsigned Reg = Instr.getRegister();
+ if (!IsEH)
+ Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);
+
+ int Offset = Instr.getOffset();
+ if (IsRelative)
+ Offset -= CFAOffset;
+ Offset = Offset / dataAlignmentFactor;
+
+ if (Offset < 0) {
+ Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+ Streamer.EmitSLEB128IntValue(Offset);
+ } else if (Reg < 64) {
+ Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1);
+ Streamer.EmitULEB128IntValue(Offset);
+ } else {
+ Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+ Streamer.EmitULEB128IntValue(Offset);
+ }
+ return;
+ }
+ case MCCFIInstruction::OpRememberState:
+ Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1);
+ return;
+ case MCCFIInstruction::OpRestoreState:
+ Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1);
+ return;
+ case MCCFIInstruction::OpSameValue: {
+ unsigned Reg = Instr.getRegister();
+ Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+ return;
+ }
+ case MCCFIInstruction::OpRestore: {
+ unsigned Reg = Instr.getRegister();
+ if (!IsEH)
+ Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);
+ if (Reg < 64) {
+ Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1);
+ } else {
+ Streamer.EmitIntValue(dwarf::DW_CFA_restore_extended, 1);
+ Streamer.EmitULEB128IntValue(Reg);
+ }
+ return;
+ }
+ case MCCFIInstruction::OpGnuArgsSize:
+ Streamer.EmitIntValue(dwarf::DW_CFA_GNU_args_size, 1);
+ Streamer.EmitULEB128IntValue(Instr.getOffset());
+ return;
+
+ case MCCFIInstruction::OpEscape:
+ Streamer.EmitBytes(Instr.getValues());
+ return;
+ }
+ llvm_unreachable("Unhandled case in switch");
+}
+
+/// Emit frame instructions to describe the layout of the frame.
+void FrameEmitterImpl::EmitCFIInstructions(ArrayRef<MCCFIInstruction> Instrs,
+ MCSymbol *BaseLabel) {
+ for (const MCCFIInstruction &Instr : Instrs) {
+ MCSymbol *Label = Instr.getLabel();
+ // Throw out move if the label is invalid.
+ if (Label && !Label->isDefined()) continue; // Not emitted, in dead code.
+
+ // Advance row if new location.
+ if (BaseLabel && Label) {
+ MCSymbol *ThisSym = Label;
+ if (ThisSym != BaseLabel) {
+ Streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym);
+ BaseLabel = ThisSym;
+ }
+ }
+
+ EmitCFIInstruction(Instr);
+ }
+}
+
+/// Emit the unwind information in a compact way.
+void FrameEmitterImpl::EmitCompactUnwind(const MCDwarfFrameInfo &Frame) {
+ MCContext &Context = Streamer.getContext();
+ const MCObjectFileInfo *MOFI = Context.getObjectFileInfo();
+
+ // range-start range-length compact-unwind-enc personality-func lsda
+ // _foo LfooEnd-_foo 0x00000023 0 0
+ // _bar LbarEnd-_bar 0x00000025 __gxx_personality except_tab1
+ //
+ // .section __LD,__compact_unwind,regular,debug
+ //
+ // # compact unwind for _foo
+ // .quad _foo
+ // .set L1,LfooEnd-_foo
+ // .long L1
+ // .long 0x01010001
+ // .quad 0
+ // .quad 0
+ //
+ // # compact unwind for _bar
+ // .quad _bar
+ // .set L2,LbarEnd-_bar
+ // .long L2
+ // .long 0x01020011
+ // .quad __gxx_personality
+ // .quad except_tab1
+
+ uint32_t Encoding = Frame.CompactUnwindEncoding;
+ if (!Encoding) return;
+ bool DwarfEHFrameOnly = (Encoding == MOFI->getCompactUnwindDwarfEHFrameOnly());
+
+ // The encoding needs to know we have an LSDA.
+ if (!DwarfEHFrameOnly && Frame.Lsda)
+ Encoding |= 0x40000000;
+
+ // Range Start
+ unsigned FDEEncoding = MOFI->getFDEEncoding();
+ unsigned Size = getSizeForEncoding(Streamer, FDEEncoding);
+ Streamer.EmitSymbolValue(Frame.Begin, Size);
+
+ // Range Length
+ const MCExpr *Range = MakeStartMinusEndExpr(Streamer, *Frame.Begin,
+ *Frame.End, 0);
+ emitAbsValue(Streamer, Range, 4);
+
+ // Compact Encoding
+ Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_udata4);
+ Streamer.EmitIntValue(Encoding, Size);
+
+ // Personality Function
+ Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_absptr);
+ if (!DwarfEHFrameOnly && Frame.Personality)
+ Streamer.EmitSymbolValue(Frame.Personality, Size);
+ else
+ Streamer.EmitIntValue(0, Size); // No personality fn
+
+ // LSDA
+ Size = getSizeForEncoding(Streamer, Frame.LsdaEncoding);
+ if (!DwarfEHFrameOnly && Frame.Lsda)
+ Streamer.EmitSymbolValue(Frame.Lsda, Size);
+ else
+ Streamer.EmitIntValue(0, Size); // No LSDA
+}
+
+static unsigned getCIEVersion(bool IsEH, unsigned DwarfVersion) {
+ if (IsEH)
+ return 1;
+ switch (DwarfVersion) {
+ case 2:
+ return 1;
+ case 3:
+ return 3;
+ case 4:
+ case 5:
+ return 4;
+ }
+ llvm_unreachable("Unknown version");
+}
+
+const MCSymbol &FrameEmitterImpl::EmitCIE(const MCDwarfFrameInfo &Frame) {
+ MCContext &context = Streamer.getContext();
+ const MCRegisterInfo *MRI = context.getRegisterInfo();
+ const MCObjectFileInfo *MOFI = context.getObjectFileInfo();
+
+ MCSymbol *sectionStart = context.createTempSymbol();
+ Streamer.EmitLabel(sectionStart);
+
+ MCSymbol *sectionEnd = context.createTempSymbol();
+
+ // Length
+ const MCExpr *Length =
+ MakeStartMinusEndExpr(Streamer, *sectionStart, *sectionEnd, 4);
+ emitAbsValue(Streamer, Length, 4);
+
+ // CIE ID
+ unsigned CIE_ID = IsEH ? 0 : -1;
+ Streamer.EmitIntValue(CIE_ID, 4);
+
+ // Version
+ uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion());
+ Streamer.EmitIntValue(CIEVersion, 1);
+
+ if (IsEH) {
+ SmallString<8> Augmentation;
+ Augmentation += "z";
+ if (Frame.Personality)
+ Augmentation += "P";
+ if (Frame.Lsda)
+ Augmentation += "L";
+ Augmentation += "R";
+ if (Frame.IsSignalFrame)
+ Augmentation += "S";
+ if (Frame.IsBKeyFrame)
+ Augmentation += "B";
+ Streamer.EmitBytes(Augmentation);
+ }
+ Streamer.EmitIntValue(0, 1);
+
+ if (CIEVersion >= 4) {
+ // Address Size
+ Streamer.EmitIntValue(context.getAsmInfo()->getCodePointerSize(), 1);
+
+ // Segment Descriptor Size
+ Streamer.EmitIntValue(0, 1);
+ }
+
+ // Code Alignment Factor
+ Streamer.EmitULEB128IntValue(context.getAsmInfo()->getMinInstAlignment());
+
+ // Data Alignment Factor
+ Streamer.EmitSLEB128IntValue(getDataAlignmentFactor(Streamer));
+
+ // Return Address Register
+ unsigned RAReg = Frame.RAReg;
+ if (RAReg == static_cast<unsigned>(INT_MAX))
+ RAReg = MRI->getDwarfRegNum(MRI->getRARegister(), IsEH);
+
+ if (CIEVersion == 1) {
+ assert(RAReg <= 255 &&
+ "DWARF 2 encodes return_address_register in one byte");
+ Streamer.EmitIntValue(RAReg, 1);
+ } else {
+ Streamer.EmitULEB128IntValue(RAReg);
+ }
+
+ // Augmentation Data Length (optional)
+ unsigned augmentationLength = 0;
+ if (IsEH) {
+ if (Frame.Personality) {
+ // Personality Encoding
+ augmentationLength += 1;
+ // Personality
+ augmentationLength +=
+ getSizeForEncoding(Streamer, Frame.PersonalityEncoding);
+ }
+ if (Frame.Lsda)
+ augmentationLength += 1;
+ // Encoding of the FDE pointers
+ augmentationLength += 1;
+
+ Streamer.EmitULEB128IntValue(augmentationLength);
+
+ // Augmentation Data (optional)
+ if (Frame.Personality) {
+ // Personality Encoding
+ emitEncodingByte(Streamer, Frame.PersonalityEncoding);
+ // Personality
+ EmitPersonality(Streamer, *Frame.Personality, Frame.PersonalityEncoding);
+ }
+
+ if (Frame.Lsda)
+ emitEncodingByte(Streamer, Frame.LsdaEncoding);
+
+ // Encoding of the FDE pointers
+ emitEncodingByte(Streamer, MOFI->getFDEEncoding());
+ }
+
+ // Initial Instructions
+
+ const MCAsmInfo *MAI = context.getAsmInfo();
+ if (!Frame.IsSimple) {
+ const std::vector<MCCFIInstruction> &Instructions =
+ MAI->getInitialFrameState();
+ EmitCFIInstructions(Instructions, nullptr);
+ }
+
+ InitialCFAOffset = CFAOffset;
+
+ // Padding
+ Streamer.EmitValueToAlignment(IsEH ? 4 : MAI->getCodePointerSize());
+
+ Streamer.EmitLabel(sectionEnd);
+ return *sectionStart;
+}
+
+void FrameEmitterImpl::EmitFDE(const MCSymbol &cieStart,
+ const MCDwarfFrameInfo &frame,
+ bool LastInSection,
+ const MCSymbol &SectionStart) {
+ MCContext &context = Streamer.getContext();
+ MCSymbol *fdeStart = context.createTempSymbol();
+ MCSymbol *fdeEnd = context.createTempSymbol();
+ const MCObjectFileInfo *MOFI = context.getObjectFileInfo();
+
+ CFAOffset = InitialCFAOffset;
+
+ // Length
+ const MCExpr *Length = MakeStartMinusEndExpr(Streamer, *fdeStart, *fdeEnd, 0);
+ emitAbsValue(Streamer, Length, 4);
+
+ Streamer.EmitLabel(fdeStart);
+
+ // CIE Pointer
+ const MCAsmInfo *asmInfo = context.getAsmInfo();
+ if (IsEH) {
+ const MCExpr *offset =
+ MakeStartMinusEndExpr(Streamer, cieStart, *fdeStart, 0);
+ emitAbsValue(Streamer, offset, 4);
+ } else if (!asmInfo->doesDwarfUseRelocationsAcrossSections()) {
+ const MCExpr *offset =
+ MakeStartMinusEndExpr(Streamer, SectionStart, cieStart, 0);
+ emitAbsValue(Streamer, offset, 4);
+ } else {
+ Streamer.EmitSymbolValue(&cieStart, 4);
+ }
+
+ // PC Begin
+ unsigned PCEncoding =
+ IsEH ? MOFI->getFDEEncoding() : (unsigned)dwarf::DW_EH_PE_absptr;
+ unsigned PCSize = getSizeForEncoding(Streamer, PCEncoding);
+ emitFDESymbol(Streamer, *frame.Begin, PCEncoding, IsEH);
+
+ // PC Range
+ const MCExpr *Range =
+ MakeStartMinusEndExpr(Streamer, *frame.Begin, *frame.End, 0);
+ emitAbsValue(Streamer, Range, PCSize);
+
+ if (IsEH) {
+ // Augmentation Data Length
+ unsigned augmentationLength = 0;
+
+ if (frame.Lsda)
+ augmentationLength += getSizeForEncoding(Streamer, frame.LsdaEncoding);
+
+ Streamer.EmitULEB128IntValue(augmentationLength);
+
+ // Augmentation Data
+ if (frame.Lsda)
+ emitFDESymbol(Streamer, *frame.Lsda, frame.LsdaEncoding, true);
+ }
+
+ // Call Frame Instructions
+ EmitCFIInstructions(frame.Instructions, frame.Begin);
+
+ // Padding
+ // The size of a .eh_frame section has to be a multiple of the alignment
+ // since a null CIE is interpreted as the end. Old systems overaligned
+ // .eh_frame, so we do too and account for it in the last FDE.
+ unsigned Align = LastInSection ? asmInfo->getCodePointerSize() : PCSize;
+ Streamer.EmitValueToAlignment(Align);
+
+ Streamer.EmitLabel(fdeEnd);
+}
+
+namespace {
+
+struct CIEKey {
+ static const CIEKey getEmptyKey() {
+ return CIEKey(nullptr, 0, -1, false, false, static_cast<unsigned>(INT_MAX),
+ false);
+ }
+
+ static const CIEKey getTombstoneKey() {
+ return CIEKey(nullptr, -1, 0, false, false, static_cast<unsigned>(INT_MAX),
+ false);
+ }
+
+ CIEKey(const MCSymbol *Personality, unsigned PersonalityEncoding,
+ unsigned LSDAEncoding, bool IsSignalFrame, bool IsSimple,
+ unsigned RAReg, bool IsBKeyFrame)
+ : Personality(Personality), PersonalityEncoding(PersonalityEncoding),
+ LsdaEncoding(LSDAEncoding), IsSignalFrame(IsSignalFrame),
+ IsSimple(IsSimple), RAReg(RAReg), IsBKeyFrame(IsBKeyFrame) {}
+
+ explicit CIEKey(const MCDwarfFrameInfo &Frame)
+ : Personality(Frame.Personality),
+ PersonalityEncoding(Frame.PersonalityEncoding),
+ LsdaEncoding(Frame.LsdaEncoding), IsSignalFrame(Frame.IsSignalFrame),
+ IsSimple(Frame.IsSimple), RAReg(Frame.RAReg),
+ IsBKeyFrame(Frame.IsBKeyFrame) {}
+
+ StringRef PersonalityName() const {
+ if (!Personality)
+ return StringRef();
+ return Personality->getName();
+ }
+
+ bool operator<(const CIEKey &Other) const {
+ return std::make_tuple(PersonalityName(), PersonalityEncoding, LsdaEncoding,
+ IsSignalFrame, IsSimple, RAReg) <
+ std::make_tuple(Other.PersonalityName(), Other.PersonalityEncoding,
+ Other.LsdaEncoding, Other.IsSignalFrame,
+ Other.IsSimple, Other.RAReg);
+ }
+
+ const MCSymbol *Personality;
+ unsigned PersonalityEncoding;
+ unsigned LsdaEncoding;
+ bool IsSignalFrame;
+ bool IsSimple;
+ unsigned RAReg;
+ bool IsBKeyFrame;
+};
+
+} // end anonymous namespace
+
+namespace llvm {
+
+template <> struct DenseMapInfo<CIEKey> {
+ static CIEKey getEmptyKey() { return CIEKey::getEmptyKey(); }
+ static CIEKey getTombstoneKey() { return CIEKey::getTombstoneKey(); }
+
+ static unsigned getHashValue(const CIEKey &Key) {
+ return static_cast<unsigned>(hash_combine(
+ Key.Personality, Key.PersonalityEncoding, Key.LsdaEncoding,
+ Key.IsSignalFrame, Key.IsSimple, Key.RAReg, Key.IsBKeyFrame));
+ }
+
+ static bool isEqual(const CIEKey &LHS, const CIEKey &RHS) {
+ return LHS.Personality == RHS.Personality &&
+ LHS.PersonalityEncoding == RHS.PersonalityEncoding &&
+ LHS.LsdaEncoding == RHS.LsdaEncoding &&
+ LHS.IsSignalFrame == RHS.IsSignalFrame &&
+ LHS.IsSimple == RHS.IsSimple && LHS.RAReg == RHS.RAReg &&
+ LHS.IsBKeyFrame == RHS.IsBKeyFrame;
+ }
+};
+
+} // end namespace llvm
+
+void MCDwarfFrameEmitter::Emit(MCObjectStreamer &Streamer, MCAsmBackend *MAB,
+ bool IsEH) {
+ Streamer.generateCompactUnwindEncodings(MAB);
+
+ MCContext &Context = Streamer.getContext();
+ const MCObjectFileInfo *MOFI = Context.getObjectFileInfo();
+ const MCAsmInfo *AsmInfo = Context.getAsmInfo();
+ FrameEmitterImpl Emitter(IsEH, Streamer);
+ ArrayRef<MCDwarfFrameInfo> FrameArray = Streamer.getDwarfFrameInfos();
+
+ // Emit the compact unwind info if available.
+ bool NeedsEHFrameSection = !MOFI->getSupportsCompactUnwindWithoutEHFrame();
+ if (IsEH && MOFI->getCompactUnwindSection()) {
+ bool SectionEmitted = false;
+ for (const MCDwarfFrameInfo &Frame : FrameArray) {
+ if (Frame.CompactUnwindEncoding == 0) continue;
+ if (!SectionEmitted) {
+ Streamer.SwitchSection(MOFI->getCompactUnwindSection());
+ Streamer.EmitValueToAlignment(AsmInfo->getCodePointerSize());
+ SectionEmitted = true;
+ }
+ NeedsEHFrameSection |=
+ Frame.CompactUnwindEncoding ==
+ MOFI->getCompactUnwindDwarfEHFrameOnly();
+ Emitter.EmitCompactUnwind(Frame);
+ }
+ }
+
+ if (!NeedsEHFrameSection) return;
+
+ MCSection &Section =
+ IsEH ? *const_cast<MCObjectFileInfo *>(MOFI)->getEHFrameSection()
+ : *MOFI->getDwarfFrameSection();
+
+ Streamer.SwitchSection(&Section);
+ MCSymbol *SectionStart = Context.createTempSymbol();
+ Streamer.EmitLabel(SectionStart);
+
+ DenseMap<CIEKey, const MCSymbol *> CIEStarts;
+
+ const MCSymbol *DummyDebugKey = nullptr;
+ bool CanOmitDwarf = MOFI->getOmitDwarfIfHaveCompactUnwind();
+ // Sort the FDEs by their corresponding CIE before we emit them.
+ // This isn't technically necessary according to the DWARF standard,
+ // but the Android libunwindstack rejects eh_frame sections where
+ // an FDE refers to a CIE other than the closest previous CIE.
+ std::vector<MCDwarfFrameInfo> FrameArrayX(FrameArray.begin(), FrameArray.end());
+ llvm::stable_sort(FrameArrayX,
+ [](const MCDwarfFrameInfo &X, const MCDwarfFrameInfo &Y) {
+ return CIEKey(X) < CIEKey(Y);
+ });
+ for (auto I = FrameArrayX.begin(), E = FrameArrayX.end(); I != E;) {
+ const MCDwarfFrameInfo &Frame = *I;
+ ++I;
+ if (CanOmitDwarf && Frame.CompactUnwindEncoding !=
+ MOFI->getCompactUnwindDwarfEHFrameOnly())
+ // Don't generate an EH frame if we don't need one. I.e., it's taken care
+ // of by the compact unwind encoding.
+ continue;
+
+ CIEKey Key(Frame);
+ const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey;
+ if (!CIEStart)
+ CIEStart = &Emitter.EmitCIE(Frame);
+
+ Emitter.EmitFDE(*CIEStart, Frame, I == E, *SectionStart);
+ }
+}
+
+void MCDwarfFrameEmitter::EmitAdvanceLoc(MCObjectStreamer &Streamer,
+ uint64_t AddrDelta) {
+ MCContext &Context = Streamer.getContext();
+ SmallString<256> Tmp;
+ raw_svector_ostream OS(Tmp);
+ MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OS);
+ Streamer.EmitBytes(OS.str());
+}
+
+void MCDwarfFrameEmitter::EncodeAdvanceLoc(MCContext &Context,
+ uint64_t AddrDelta, raw_ostream &OS,
+ uint32_t *Offset, uint32_t *Size) {
+ // Scale the address delta by the minimum instruction length.
+ AddrDelta = ScaleAddrDelta(Context, AddrDelta);
+
+ bool WithFixups = false;
+ if (Offset && Size)
+ WithFixups = true;
+
+ support::endianness E =
+ Context.getAsmInfo()->isLittleEndian() ? support::little : support::big;
+ if (AddrDelta == 0) {
+ if (WithFixups) {
+ *Offset = 0;
+ *Size = 0;
+ }
+ } else if (isUIntN(6, AddrDelta)) {
+ uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta;
+ if (WithFixups) {
+ *Offset = OS.tell();
+ *Size = 6;
+ OS << uint8_t(dwarf::DW_CFA_advance_loc);
+ } else
+ OS << Opcode;
+ } else if (isUInt<8>(AddrDelta)) {
+ OS << uint8_t(dwarf::DW_CFA_advance_loc1);
+ if (WithFixups) {
+ *Offset = OS.tell();
+ *Size = 8;
+ OS.write_zeros(1);
+ } else
+ OS << uint8_t(AddrDelta);
+ } else if (isUInt<16>(AddrDelta)) {
+ OS << uint8_t(dwarf::DW_CFA_advance_loc2);
+ if (WithFixups) {
+ *Offset = OS.tell();
+ *Size = 16;
+ OS.write_zeros(2);
+ } else
+ support::endian::write<uint16_t>(OS, AddrDelta, E);
+ } else {
+ assert(isUInt<32>(AddrDelta));
+ OS << uint8_t(dwarf::DW_CFA_advance_loc4);
+ if (WithFixups) {
+ *Offset = OS.tell();
+ *Size = 32;
+ OS.write_zeros(4);
+ } else
+ support::endian::write<uint32_t>(OS, AddrDelta, E);
+ }
+}
diff --git a/llvm/lib/MC/MCELFObjectTargetWriter.cpp b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
new file mode 100644
index 000000000000..a81eab9ca296
--- /dev/null
+++ b/llvm/lib/MC/MCELFObjectTargetWriter.cpp
@@ -0,0 +1,31 @@
+//===-- MCELFObjectTargetWriter.cpp - ELF Target Writer Subclass ----------===//
+//
+// 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/MCELFObjectWriter.h"
+
+using namespace llvm;
+
+MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_,
+ uint16_t EMachine_,
+ bool HasRelocationAddend_,
+ uint8_t ABIVersion_)
+ : OSABI(OSABI_), ABIVersion(ABIVersion_), EMachine(EMachine_),
+ HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) {}
+
+bool MCELFObjectTargetWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
+ unsigned Type) const {
+ return false;
+}
+
+void
+MCELFObjectTargetWriter::sortRelocs(const MCAssembler &Asm,
+ std::vector<ELFRelocationEntry> &Relocs) {
+}
+
+void MCELFObjectTargetWriter::addTargetSectionFlags(MCContext &Ctx,
+ MCSectionELF &Sec) {}
diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp
new file mode 100644
index 000000000000..fa2133078bfe
--- /dev/null
+++ b/llvm/lib/MC/MCELFStreamer.cpp
@@ -0,0 +1,711 @@
+//===- 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/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.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) {
+ MCContext &Ctx = getContext();
+ SwitchSection(Ctx.getObjectFileInfo()->getTextSection());
+ EmitCodeAlignment(4);
+
+ 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::EmitLabel(MCSymbol *S, SMLoc Loc, MCFragment *F) {
+ auto *Symbol = cast<MCSymbolELF>(S);
+ MCObjectStreamer::EmitLabel(Symbol, Loc, F);
+
+ 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->getAlignment() < Assembler.getBundleAlignSize())
+ Section->setAlignment(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);
+
+ 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_LazyReference:
+ case MCSA_Reference:
+ case MCSA_SymbolResolver:
+ case MCSA_PrivateExtern:
+ case MCSA_WeakDefinition:
+ case MCSA_WeakDefAutoPrivate:
+ case MCSA_Invalid:
+ case MCSA_IndirectSymbol:
+ 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);
+ Symbol->setExternal(true);
+ break;
+
+ case MCSA_Global:
+ Symbol->setBinding(ELF::STB_GLOBAL);
+ Symbol->setExternal(true);
+ break;
+
+ case MCSA_WeakReference:
+ case MCSA_Weak:
+ Symbol->setBinding(ELF::STB_WEAK);
+ Symbol->setExternal(true);
+ break;
+
+ case MCSA_Local:
+ Symbol->setBinding(ELF::STB_LOCAL);
+ Symbol->setExternal(false);
+ 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));
+ 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_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,
+ unsigned ByteAlignment) {
+ auto *Symbol = cast<MCSymbolELF>(S);
+ getAssembler().registerSymbol(*Symbol);
+
+ if (!Symbol->isBindingSet()) {
+ Symbol->setBinding(ELF::STB_GLOBAL);
+ Symbol->setExternal(true);
+ }
+
+ 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);
+
+ // Update the maximum alignment of the section if necessary.
+ if (ByteAlignment > Section.getAlignment())
+ Section.setAlignment(Align(ByteAlignment));
+
+ SwitchSection(P.first, P.second);
+ } else {
+ if(Symbol->declareCommon(Size, ByteAlignment))
+ report_fatal_error("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(StringRef AliasName,
+ const MCSymbol *Aliasee) {
+ getAssembler().Symvers.push_back({AliasName, Aliasee});
+}
+
+void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
+ unsigned ByteAlignment) {
+ auto *Symbol = cast<MCSymbolELF>(S);
+ // FIXME: Should this be caught and done earlier?
+ getAssembler().registerSymbol(*Symbol);
+ Symbol->setBinding(ELF::STB_LOCAL);
+ Symbol->setExternal(false);
+ 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(unsigned ByteAlignment,
+ int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ if (isBundleLocked())
+ report_fatal_error("Emitting values inside a locked bundle is forbidden");
+ MCObjectStreamer::EmitValueToAlignment(ByteAlignment, 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) {
+ EmitIntValue(0, 1);
+ SeenIdent = true;
+ }
+ EmitBytes(IdentString);
+ EmitIntValue(0, 1);
+ 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_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_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_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) {
+ 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, SRE->getKind(), getContext(), SRE->getLoc());
+ return;
+ }
+ // Not a temporary, referece it as a weak undefined.
+ bool Created;
+ getAssembler().registerSymbol(*S, &Created);
+ if (Created) {
+ cast<MCSymbolELF>(S)->setBinding(ELF::STB_WEAK);
+ cast<MCSymbolELF>(S)->setExternal(true);
+ }
+}
+
+void MCELFStreamer::finalizeCGProfile() {
+ for (MCAssembler::CGProfileEntry &E : getAssembler().CGProfile) {
+ finalizeCGProfileEntry(E.From);
+ finalizeCGProfileEntry(E.To);
+ }
+}
+
+void MCELFStreamer::EmitInstToFragment(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ this->MCObjectStreamer::EmitInstToFragment(Inst, STI);
+ MCRelaxableFragment &F = *cast<MCRelaxableFragment>(getCurrentFragment());
+
+ for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i)
+ fixSymbolsInTLSFixups(F.getFixups()[i].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 (unsigned i = 0, e = Fixups.size(); i != e; ++i)
+ fixSymbolsInTLSFixups(Fixups[i].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 (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
+ Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
+ DF->getFixups().push_back(Fixups[i]);
+ }
+ 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(unsigned AlignPow2) {
+ assert(AlignPow2 <= 30 && "Invalid bundle alignment");
+ MCAssembler &Assembler = getAssembler();
+ if (AlignPow2 > 0 && (Assembler.getBundleAlignSize() == 0 ||
+ Assembler.getBundleAlignSize() == 1U << AlignPow2))
+ Assembler.setBundleAlignSize(1U << AlignPow2);
+ else
+ report_fatal_error(".bundle_align_mode cannot be changed once set");
+}
+
+void MCELFStreamer::EmitBundleLock(bool AlignToEnd) {
+ MCSection &Sec = *getCurrentSectionOnly();
+
+ // Sanity checks
+ //
+ 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();
+
+ // Sanity checks
+ 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() {
+ // 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, unsigned ByteAlignment,
+ SMLoc Loc) {
+ llvm_unreachable("ELF doesn't support this directive");
+}
+
+void MCELFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ llvm_unreachable("ELF doesn't support this directive");
+}
+
+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;
+}
diff --git a/llvm/lib/MC/MCExpr.cpp b/llvm/lib/MC/MCExpr.cpp
new file mode 100644
index 000000000000..813c00f6f3bb
--- /dev/null
+++ b/llvm/lib/MC/MCExpr.cpp
@@ -0,0 +1,928 @@
+//===- MCExpr.cpp - Assembly Level Expression Implementation --------------===//
+//
+// 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/MCExpr.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mcexpr"
+
+namespace {
+namespace stats {
+
+STATISTIC(MCExprEvaluate, "Number of MCExpr evaluations");
+
+} // end namespace stats
+} // end anonymous namespace
+
+void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI, bool InParens) const {
+ switch (getKind()) {
+ case MCExpr::Target:
+ return cast<MCTargetExpr>(this)->printImpl(OS, MAI);
+ case MCExpr::Constant: {
+ auto Value = cast<MCConstantExpr>(*this).getValue();
+ auto PrintInHex = cast<MCConstantExpr>(*this).useHexFormat();
+ if (PrintInHex)
+ OS << "0x" << Twine::utohexstr(Value);
+ else
+ OS << Value;
+ return;
+ }
+ case MCExpr::SymbolRef: {
+ const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this);
+ const MCSymbol &Sym = SRE.getSymbol();
+ // Parenthesize names that start with $ so that they don't look like
+ // absolute names.
+ bool UseParens =
+ !InParens && !Sym.getName().empty() && Sym.getName()[0] == '$';
+ if (UseParens) {
+ OS << '(';
+ Sym.print(OS, MAI);
+ OS << ')';
+ } else
+ Sym.print(OS, MAI);
+
+ if (SRE.getKind() != MCSymbolRefExpr::VK_None)
+ SRE.printVariantKind(OS);
+
+ return;
+ }
+
+ case MCExpr::Unary: {
+ const MCUnaryExpr &UE = cast<MCUnaryExpr>(*this);
+ switch (UE.getOpcode()) {
+ case MCUnaryExpr::LNot: OS << '!'; break;
+ case MCUnaryExpr::Minus: OS << '-'; break;
+ case MCUnaryExpr::Not: OS << '~'; break;
+ case MCUnaryExpr::Plus: OS << '+'; break;
+ }
+ bool Binary = UE.getSubExpr()->getKind() == MCExpr::Binary;
+ if (Binary) OS << "(";
+ UE.getSubExpr()->print(OS, MAI);
+ if (Binary) OS << ")";
+ return;
+ }
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr &BE = cast<MCBinaryExpr>(*this);
+
+ // Only print parens around the LHS if it is non-trivial.
+ if (isa<MCConstantExpr>(BE.getLHS()) || isa<MCSymbolRefExpr>(BE.getLHS())) {
+ BE.getLHS()->print(OS, MAI);
+ } else {
+ OS << '(';
+ BE.getLHS()->print(OS, MAI);
+ OS << ')';
+ }
+
+ switch (BE.getOpcode()) {
+ case MCBinaryExpr::Add:
+ // Print "X-42" instead of "X+-42".
+ if (const MCConstantExpr *RHSC = dyn_cast<MCConstantExpr>(BE.getRHS())) {
+ if (RHSC->getValue() < 0) {
+ OS << RHSC->getValue();
+ return;
+ }
+ }
+
+ OS << '+';
+ break;
+ case MCBinaryExpr::AShr: OS << ">>"; break;
+ case MCBinaryExpr::And: OS << '&'; break;
+ case MCBinaryExpr::Div: OS << '/'; break;
+ case MCBinaryExpr::EQ: OS << "=="; break;
+ case MCBinaryExpr::GT: OS << '>'; break;
+ case MCBinaryExpr::GTE: OS << ">="; break;
+ case MCBinaryExpr::LAnd: OS << "&&"; break;
+ case MCBinaryExpr::LOr: OS << "||"; break;
+ case MCBinaryExpr::LShr: OS << ">>"; break;
+ case MCBinaryExpr::LT: OS << '<'; break;
+ case MCBinaryExpr::LTE: OS << "<="; break;
+ case MCBinaryExpr::Mod: OS << '%'; break;
+ case MCBinaryExpr::Mul: OS << '*'; break;
+ case MCBinaryExpr::NE: OS << "!="; break;
+ case MCBinaryExpr::Or: OS << '|'; break;
+ case MCBinaryExpr::Shl: OS << "<<"; break;
+ case MCBinaryExpr::Sub: OS << '-'; break;
+ case MCBinaryExpr::Xor: OS << '^'; break;
+ }
+
+ // Only print parens around the LHS if it is non-trivial.
+ if (isa<MCConstantExpr>(BE.getRHS()) || isa<MCSymbolRefExpr>(BE.getRHS())) {
+ BE.getRHS()->print(OS, MAI);
+ } else {
+ OS << '(';
+ BE.getRHS()->print(OS, MAI);
+ OS << ')';
+ }
+ return;
+ }
+ }
+
+ llvm_unreachable("Invalid expression kind!");
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCExpr::dump() const {
+ dbgs() << *this;
+ dbgs() << '\n';
+}
+#endif
+
+/* *** */
+
+const MCBinaryExpr *MCBinaryExpr::create(Opcode Opc, const MCExpr *LHS,
+ const MCExpr *RHS, MCContext &Ctx,
+ SMLoc Loc) {
+ return new (Ctx) MCBinaryExpr(Opc, LHS, RHS, Loc);
+}
+
+const MCUnaryExpr *MCUnaryExpr::create(Opcode Opc, const MCExpr *Expr,
+ MCContext &Ctx, SMLoc Loc) {
+ return new (Ctx) MCUnaryExpr(Opc, Expr, Loc);
+}
+
+const MCConstantExpr *MCConstantExpr::create(int64_t Value, MCContext &Ctx,
+ bool PrintInHex) {
+ return new (Ctx) MCConstantExpr(Value, PrintInHex);
+}
+
+/* *** */
+
+MCSymbolRefExpr::MCSymbolRefExpr(const MCSymbol *Symbol, VariantKind Kind,
+ const MCAsmInfo *MAI, SMLoc Loc)
+ : MCExpr(MCExpr::SymbolRef, Loc), Kind(Kind),
+ UseParensForSymbolVariant(MAI->useParensForSymbolVariant()),
+ HasSubsectionsViaSymbols(MAI->hasSubsectionsViaSymbols()),
+ Symbol(Symbol) {
+ assert(Symbol);
+}
+
+const MCSymbolRefExpr *MCSymbolRefExpr::create(const MCSymbol *Sym,
+ VariantKind Kind,
+ MCContext &Ctx, SMLoc Loc) {
+ return new (Ctx) MCSymbolRefExpr(Sym, Kind, Ctx.getAsmInfo(), Loc);
+}
+
+const MCSymbolRefExpr *MCSymbolRefExpr::create(StringRef Name, VariantKind Kind,
+ MCContext &Ctx) {
+ return create(Ctx.getOrCreateSymbol(Name), Kind, Ctx);
+}
+
+StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) {
+ switch (Kind) {
+ case VK_Invalid: return "<<invalid>>";
+ case VK_None: return "<<none>>";
+
+ case VK_DTPOFF: return "DTPOFF";
+ case VK_DTPREL: return "DTPREL";
+ case VK_GOT: return "GOT";
+ case VK_GOTOFF: return "GOTOFF";
+ case VK_GOTREL: return "GOTREL";
+ case VK_GOTPCREL: return "GOTPCREL";
+ case VK_GOTTPOFF: return "GOTTPOFF";
+ case VK_INDNTPOFF: return "INDNTPOFF";
+ case VK_NTPOFF: return "NTPOFF";
+ case VK_GOTNTPOFF: return "GOTNTPOFF";
+ case VK_PLT: return "PLT";
+ case VK_TLSGD: return "TLSGD";
+ case VK_TLSLD: return "TLSLD";
+ case VK_TLSLDM: return "TLSLDM";
+ case VK_TPOFF: return "TPOFF";
+ case VK_TPREL: return "TPREL";
+ case VK_TLSCALL: return "tlscall";
+ case VK_TLSDESC: return "tlsdesc";
+ case VK_TLVP: return "TLVP";
+ case VK_TLVPPAGE: return "TLVPPAGE";
+ case VK_TLVPPAGEOFF: return "TLVPPAGEOFF";
+ case VK_PAGE: return "PAGE";
+ case VK_PAGEOFF: return "PAGEOFF";
+ case VK_GOTPAGE: return "GOTPAGE";
+ case VK_GOTPAGEOFF: return "GOTPAGEOFF";
+ case VK_SECREL: return "SECREL32";
+ case VK_SIZE: return "SIZE";
+ case VK_WEAKREF: return "WEAKREF";
+ case VK_X86_ABS8: return "ABS8";
+ case VK_ARM_NONE: return "none";
+ case VK_ARM_GOT_PREL: return "GOT_PREL";
+ case VK_ARM_TARGET1: return "target1";
+ case VK_ARM_TARGET2: return "target2";
+ case VK_ARM_PREL31: return "prel31";
+ case VK_ARM_SBREL: return "sbrel";
+ case VK_ARM_TLSLDO: return "tlsldo";
+ case VK_ARM_TLSDESCSEQ: return "tlsdescseq";
+ case VK_AVR_NONE: return "none";
+ case VK_AVR_LO8: return "lo8";
+ case VK_AVR_HI8: return "hi8";
+ case VK_AVR_HLO8: return "hlo8";
+ case VK_AVR_DIFF8: return "diff8";
+ case VK_AVR_DIFF16: return "diff16";
+ case VK_AVR_DIFF32: return "diff32";
+ case VK_PPC_LO: return "l";
+ case VK_PPC_HI: return "h";
+ case VK_PPC_HA: return "ha";
+ case VK_PPC_HIGH: return "high";
+ case VK_PPC_HIGHA: return "higha";
+ case VK_PPC_HIGHER: return "higher";
+ case VK_PPC_HIGHERA: return "highera";
+ case VK_PPC_HIGHEST: return "highest";
+ case VK_PPC_HIGHESTA: return "highesta";
+ case VK_PPC_GOT_LO: return "got@l";
+ case VK_PPC_GOT_HI: return "got@h";
+ case VK_PPC_GOT_HA: return "got@ha";
+ case VK_PPC_TOCBASE: return "tocbase";
+ case VK_PPC_TOC: return "toc";
+ case VK_PPC_TOC_LO: return "toc@l";
+ case VK_PPC_TOC_HI: return "toc@h";
+ case VK_PPC_TOC_HA: return "toc@ha";
+ case VK_PPC_U: return "u";
+ case VK_PPC_L: return "l";
+ case VK_PPC_DTPMOD: return "dtpmod";
+ case VK_PPC_TPREL_LO: return "tprel@l";
+ case VK_PPC_TPREL_HI: return "tprel@h";
+ case VK_PPC_TPREL_HA: return "tprel@ha";
+ case VK_PPC_TPREL_HIGH: return "tprel@high";
+ case VK_PPC_TPREL_HIGHA: return "tprel@higha";
+ case VK_PPC_TPREL_HIGHER: return "tprel@higher";
+ case VK_PPC_TPREL_HIGHERA: return "tprel@highera";
+ case VK_PPC_TPREL_HIGHEST: return "tprel@highest";
+ case VK_PPC_TPREL_HIGHESTA: return "tprel@highesta";
+ case VK_PPC_DTPREL_LO: return "dtprel@l";
+ case VK_PPC_DTPREL_HI: return "dtprel@h";
+ case VK_PPC_DTPREL_HA: return "dtprel@ha";
+ case VK_PPC_DTPREL_HIGH: return "dtprel@high";
+ case VK_PPC_DTPREL_HIGHA: return "dtprel@higha";
+ case VK_PPC_DTPREL_HIGHER: return "dtprel@higher";
+ case VK_PPC_DTPREL_HIGHERA: return "dtprel@highera";
+ case VK_PPC_DTPREL_HIGHEST: return "dtprel@highest";
+ case VK_PPC_DTPREL_HIGHESTA: return "dtprel@highesta";
+ case VK_PPC_GOT_TPREL: return "got@tprel";
+ case VK_PPC_GOT_TPREL_LO: return "got@tprel@l";
+ case VK_PPC_GOT_TPREL_HI: return "got@tprel@h";
+ case VK_PPC_GOT_TPREL_HA: return "got@tprel@ha";
+ case VK_PPC_GOT_DTPREL: return "got@dtprel";
+ case VK_PPC_GOT_DTPREL_LO: return "got@dtprel@l";
+ case VK_PPC_GOT_DTPREL_HI: return "got@dtprel@h";
+ case VK_PPC_GOT_DTPREL_HA: return "got@dtprel@ha";
+ case VK_PPC_TLS: return "tls";
+ case VK_PPC_GOT_TLSGD: return "got@tlsgd";
+ case VK_PPC_GOT_TLSGD_LO: return "got@tlsgd@l";
+ case VK_PPC_GOT_TLSGD_HI: return "got@tlsgd@h";
+ case VK_PPC_GOT_TLSGD_HA: return "got@tlsgd@ha";
+ case VK_PPC_TLSGD: return "tlsgd";
+ case VK_PPC_GOT_TLSLD: return "got@tlsld";
+ case VK_PPC_GOT_TLSLD_LO: return "got@tlsld@l";
+ case VK_PPC_GOT_TLSLD_HI: return "got@tlsld@h";
+ case VK_PPC_GOT_TLSLD_HA: return "got@tlsld@ha";
+ case VK_PPC_TLSLD: return "tlsld";
+ case VK_PPC_LOCAL: return "local";
+ case VK_COFF_IMGREL32: return "IMGREL";
+ case VK_Hexagon_PCREL: return "PCREL";
+ case VK_Hexagon_LO16: return "LO16";
+ case VK_Hexagon_HI16: return "HI16";
+ case VK_Hexagon_GPREL: return "GPREL";
+ case VK_Hexagon_GD_GOT: return "GDGOT";
+ case VK_Hexagon_LD_GOT: return "LDGOT";
+ case VK_Hexagon_GD_PLT: return "GDPLT";
+ case VK_Hexagon_LD_PLT: return "LDPLT";
+ case VK_Hexagon_IE: return "IE";
+ case VK_Hexagon_IE_GOT: return "IEGOT";
+ case VK_WASM_TYPEINDEX: return "TYPEINDEX";
+ case VK_WASM_MBREL: return "MBREL";
+ case VK_WASM_TBREL: return "TBREL";
+ case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32@lo";
+ case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32@hi";
+ case VK_AMDGPU_REL32_LO: return "rel32@lo";
+ case VK_AMDGPU_REL32_HI: return "rel32@hi";
+ case VK_AMDGPU_REL64: return "rel64";
+ case VK_AMDGPU_ABS32_LO: return "abs32@lo";
+ case VK_AMDGPU_ABS32_HI: return "abs32@hi";
+ }
+ llvm_unreachable("Invalid variant kind");
+}
+
+MCSymbolRefExpr::VariantKind
+MCSymbolRefExpr::getVariantKindForName(StringRef Name) {
+ return StringSwitch<VariantKind>(Name.lower())
+ .Case("dtprel", VK_DTPREL)
+ .Case("dtpoff", VK_DTPOFF)
+ .Case("got", VK_GOT)
+ .Case("gotoff", VK_GOTOFF)
+ .Case("gotrel", VK_GOTREL)
+ .Case("gotpcrel", VK_GOTPCREL)
+ .Case("gottpoff", VK_GOTTPOFF)
+ .Case("indntpoff", VK_INDNTPOFF)
+ .Case("ntpoff", VK_NTPOFF)
+ .Case("gotntpoff", VK_GOTNTPOFF)
+ .Case("plt", VK_PLT)
+ .Case("tlscall", VK_TLSCALL)
+ .Case("tlsdesc", VK_TLSDESC)
+ .Case("tlsgd", VK_TLSGD)
+ .Case("tlsld", VK_TLSLD)
+ .Case("tlsldm", VK_TLSLDM)
+ .Case("tpoff", VK_TPOFF)
+ .Case("tprel", VK_TPREL)
+ .Case("tlvp", VK_TLVP)
+ .Case("tlvppage", VK_TLVPPAGE)
+ .Case("tlvppageoff", VK_TLVPPAGEOFF)
+ .Case("page", VK_PAGE)
+ .Case("pageoff", VK_PAGEOFF)
+ .Case("gotpage", VK_GOTPAGE)
+ .Case("gotpageoff", VK_GOTPAGEOFF)
+ .Case("imgrel", VK_COFF_IMGREL32)
+ .Case("secrel32", VK_SECREL)
+ .Case("size", VK_SIZE)
+ .Case("abs8", VK_X86_ABS8)
+ .Case("l", VK_PPC_LO)
+ .Case("h", VK_PPC_HI)
+ .Case("ha", VK_PPC_HA)
+ .Case("high", VK_PPC_HIGH)
+ .Case("higha", VK_PPC_HIGHA)
+ .Case("higher", VK_PPC_HIGHER)
+ .Case("highera", VK_PPC_HIGHERA)
+ .Case("highest", VK_PPC_HIGHEST)
+ .Case("highesta", VK_PPC_HIGHESTA)
+ .Case("got@l", VK_PPC_GOT_LO)
+ .Case("got@h", VK_PPC_GOT_HI)
+ .Case("got@ha", VK_PPC_GOT_HA)
+ .Case("local", VK_PPC_LOCAL)
+ .Case("tocbase", VK_PPC_TOCBASE)
+ .Case("toc", VK_PPC_TOC)
+ .Case("toc@l", VK_PPC_TOC_LO)
+ .Case("toc@h", VK_PPC_TOC_HI)
+ .Case("toc@ha", VK_PPC_TOC_HA)
+ .Case("u", VK_PPC_U)
+ .Case("l", VK_PPC_L)
+ .Case("tls", VK_PPC_TLS)
+ .Case("dtpmod", VK_PPC_DTPMOD)
+ .Case("tprel@l", VK_PPC_TPREL_LO)
+ .Case("tprel@h", VK_PPC_TPREL_HI)
+ .Case("tprel@ha", VK_PPC_TPREL_HA)
+ .Case("tprel@high", VK_PPC_TPREL_HIGH)
+ .Case("tprel@higha", VK_PPC_TPREL_HIGHA)
+ .Case("tprel@higher", VK_PPC_TPREL_HIGHER)
+ .Case("tprel@highera", VK_PPC_TPREL_HIGHERA)
+ .Case("tprel@highest", VK_PPC_TPREL_HIGHEST)
+ .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA)
+ .Case("dtprel@l", VK_PPC_DTPREL_LO)
+ .Case("dtprel@h", VK_PPC_DTPREL_HI)
+ .Case("dtprel@ha", VK_PPC_DTPREL_HA)
+ .Case("dtprel@high", VK_PPC_DTPREL_HIGH)
+ .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA)
+ .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER)
+ .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA)
+ .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST)
+ .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA)
+ .Case("got@tprel", VK_PPC_GOT_TPREL)
+ .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO)
+ .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI)
+ .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA)
+ .Case("got@dtprel", VK_PPC_GOT_DTPREL)
+ .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO)
+ .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI)
+ .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA)
+ .Case("got@tlsgd", VK_PPC_GOT_TLSGD)
+ .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO)
+ .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI)
+ .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA)
+ .Case("got@tlsld", VK_PPC_GOT_TLSLD)
+ .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO)
+ .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI)
+ .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA)
+ .Case("gdgot", VK_Hexagon_GD_GOT)
+ .Case("gdplt", VK_Hexagon_GD_PLT)
+ .Case("iegot", VK_Hexagon_IE_GOT)
+ .Case("ie", VK_Hexagon_IE)
+ .Case("ldgot", VK_Hexagon_LD_GOT)
+ .Case("ldplt", VK_Hexagon_LD_PLT)
+ .Case("pcrel", VK_Hexagon_PCREL)
+ .Case("none", VK_ARM_NONE)
+ .Case("got_prel", VK_ARM_GOT_PREL)
+ .Case("target1", VK_ARM_TARGET1)
+ .Case("target2", VK_ARM_TARGET2)
+ .Case("prel31", VK_ARM_PREL31)
+ .Case("sbrel", VK_ARM_SBREL)
+ .Case("tlsldo", VK_ARM_TLSLDO)
+ .Case("lo8", VK_AVR_LO8)
+ .Case("hi8", VK_AVR_HI8)
+ .Case("hlo8", VK_AVR_HLO8)
+ .Case("typeindex", VK_WASM_TYPEINDEX)
+ .Case("tbrel", VK_WASM_TBREL)
+ .Case("mbrel", VK_WASM_MBREL)
+ .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO)
+ .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI)
+ .Case("rel32@lo", VK_AMDGPU_REL32_LO)
+ .Case("rel32@hi", VK_AMDGPU_REL32_HI)
+ .Case("rel64", VK_AMDGPU_REL64)
+ .Case("abs32@lo", VK_AMDGPU_ABS32_LO)
+ .Case("abs32@hi", VK_AMDGPU_ABS32_HI)
+ .Default(VK_Invalid);
+}
+
+void MCSymbolRefExpr::printVariantKind(raw_ostream &OS) const {
+ if (UseParensForSymbolVariant)
+ OS << '(' << MCSymbolRefExpr::getVariantKindName(getKind()) << ')';
+ else
+ OS << '@' << MCSymbolRefExpr::getVariantKindName(getKind());
+}
+
+/* *** */
+
+void MCTargetExpr::anchor() {}
+
+/* *** */
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res) const {
+ return evaluateAsAbsolute(Res, nullptr, nullptr, nullptr, false);
+}
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res,
+ const MCAsmLayout &Layout) const {
+ return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr, false);
+}
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res,
+ const MCAsmLayout &Layout,
+ const SectionAddrMap &Addrs) const {
+ // Setting InSet causes us to absolutize differences across sections and that
+ // is what the MachO writer uses Addrs for.
+ return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs, true);
+}
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const {
+ return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr, false);
+}
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const {
+ return evaluateAsAbsolute(Res, Asm, nullptr, nullptr, false);
+}
+
+bool MCExpr::evaluateKnownAbsolute(int64_t &Res,
+ const MCAsmLayout &Layout) const {
+ return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr,
+ true);
+}
+
+bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm,
+ const MCAsmLayout *Layout,
+ const SectionAddrMap *Addrs, bool InSet) const {
+ MCValue Value;
+
+ // Fast path constants.
+ if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(this)) {
+ Res = CE->getValue();
+ return true;
+ }
+
+ bool IsRelocatable =
+ evaluateAsRelocatableImpl(Value, Asm, Layout, nullptr, Addrs, InSet);
+
+ // Record the current value.
+ Res = Value.getConstant();
+
+ return IsRelocatable && Value.isAbsolute();
+}
+
+/// Helper method for \see EvaluateSymbolAdd().
+static void AttemptToFoldSymbolOffsetDifference(
+ const MCAssembler *Asm, const MCAsmLayout *Layout,
+ const SectionAddrMap *Addrs, bool InSet, const MCSymbolRefExpr *&A,
+ const MCSymbolRefExpr *&B, int64_t &Addend) {
+ if (!A || !B)
+ return;
+
+ const MCSymbol &SA = A->getSymbol();
+ const MCSymbol &SB = B->getSymbol();
+
+ if (SA.isUndefined() || SB.isUndefined())
+ return;
+
+ if (!Asm->getWriter().isSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet))
+ return;
+
+ if (SA.getFragment() == SB.getFragment() && !SA.isVariable() &&
+ !SA.isUnset() && !SB.isVariable() && !SB.isUnset()) {
+ Addend += (SA.getOffset() - SB.getOffset());
+
+ // Pointers to Thumb symbols need to have their low-bit set to allow
+ // for interworking.
+ if (Asm->isThumbFunc(&SA))
+ Addend |= 1;
+
+ // If symbol is labeled as micromips, we set low-bit to ensure
+ // correct offset in .gcc_except_table
+ if (Asm->getBackend().isMicroMips(&SA))
+ Addend |= 1;
+
+ // Clear the symbol expr pointers to indicate we have folded these
+ // operands.
+ A = B = nullptr;
+ return;
+ }
+
+ if (!Layout)
+ return;
+
+ const MCSection &SecA = *SA.getFragment()->getParent();
+ const MCSection &SecB = *SB.getFragment()->getParent();
+
+ if ((&SecA != &SecB) && !Addrs)
+ return;
+
+ // Eagerly evaluate.
+ Addend += Layout->getSymbolOffset(A->getSymbol()) -
+ Layout->getSymbolOffset(B->getSymbol());
+ if (Addrs && (&SecA != &SecB))
+ Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB));
+
+ // Pointers to Thumb symbols need to have their low-bit set to allow
+ // for interworking.
+ if (Asm->isThumbFunc(&SA))
+ Addend |= 1;
+
+ // If symbol is labeled as micromips, we set low-bit to ensure
+ // correct offset in .gcc_except_table
+ if (Asm->getBackend().isMicroMips(&SA))
+ Addend |= 1;
+
+ // Clear the symbol expr pointers to indicate we have folded these
+ // operands.
+ A = B = nullptr;
+}
+
+static bool canFold(const MCAssembler *Asm, const MCSymbolRefExpr *A,
+ const MCSymbolRefExpr *B, bool InSet) {
+ if (InSet)
+ return true;
+
+ if (!Asm->getBackend().requiresDiffExpressionRelocations())
+ return true;
+
+ const MCSymbol &CheckSym = A ? A->getSymbol() : B->getSymbol();
+ if (!CheckSym.isInSection())
+ return true;
+
+ if (!CheckSym.getSection().hasInstructions())
+ return true;
+
+ return false;
+}
+
+/// Evaluate the result of an add between (conceptually) two MCValues.
+///
+/// This routine conceptually attempts to construct an MCValue:
+/// Result = (Result_A - Result_B + Result_Cst)
+/// from two MCValue's LHS and RHS where
+/// Result = LHS + RHS
+/// and
+/// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
+///
+/// This routine attempts to aggresively fold the operands such that the result
+/// is representable in an MCValue, but may not always succeed.
+///
+/// \returns True on success, false if the result is not representable in an
+/// MCValue.
+
+/// NOTE: It is really important to have both the Asm and Layout arguments.
+/// They might look redundant, but this function can be used before layout
+/// is done (see the object streamer for example) and having the Asm argument
+/// lets us avoid relaxations early.
+static bool
+EvaluateSymbolicAdd(const MCAssembler *Asm, const MCAsmLayout *Layout,
+ const SectionAddrMap *Addrs, bool InSet, const MCValue &LHS,
+ const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B,
+ int64_t RHS_Cst, MCValue &Res) {
+ // FIXME: This routine (and other evaluation parts) are *incredibly* sloppy
+ // about dealing with modifiers. This will ultimately bite us, one day.
+ const MCSymbolRefExpr *LHS_A = LHS.getSymA();
+ const MCSymbolRefExpr *LHS_B = LHS.getSymB();
+ int64_t LHS_Cst = LHS.getConstant();
+
+ // Fold the result constant immediately.
+ int64_t Result_Cst = LHS_Cst + RHS_Cst;
+
+ assert((!Layout || Asm) &&
+ "Must have an assembler object if layout is given!");
+
+ // If we have a layout, we can fold resolved differences. Do not do this if
+ // the backend requires this to be emitted as individual relocations, unless
+ // the InSet flag is set to get the current difference anyway (used for
+ // example to calculate symbol sizes).
+ if (Asm && canFold(Asm, LHS_A, LHS_B, InSet)) {
+ // First, fold out any differences which are fully resolved. By
+ // reassociating terms in
+ // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst).
+ // we have the four possible differences:
+ // (LHS_A - LHS_B),
+ // (LHS_A - RHS_B),
+ // (RHS_A - LHS_B),
+ // (RHS_A - RHS_B).
+ // Since we are attempting to be as aggressive as possible about folding, we
+ // attempt to evaluate each possible alternative.
+ AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B,
+ Result_Cst);
+ AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B,
+ Result_Cst);
+ AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B,
+ Result_Cst);
+ AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B,
+ Result_Cst);
+ }
+
+ // We can't represent the addition or subtraction of two symbols.
+ if ((LHS_A && RHS_A) || (LHS_B && RHS_B))
+ return false;
+
+ // At this point, we have at most one additive symbol and one subtractive
+ // symbol -- find them.
+ const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A;
+ const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B;
+
+ Res = MCValue::get(A, B, Result_Cst);
+ return true;
+}
+
+bool MCExpr::evaluateAsRelocatable(MCValue &Res,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ MCAssembler *Assembler = Layout ? &Layout->getAssembler() : nullptr;
+ return evaluateAsRelocatableImpl(Res, Assembler, Layout, Fixup, nullptr,
+ false);
+}
+
+bool MCExpr::evaluateAsValue(MCValue &Res, const MCAsmLayout &Layout) const {
+ MCAssembler *Assembler = &Layout.getAssembler();
+ return evaluateAsRelocatableImpl(Res, Assembler, &Layout, nullptr, nullptr,
+ true);
+}
+
+static bool canExpand(const MCSymbol &Sym, bool InSet) {
+ const MCExpr *Expr = Sym.getVariableValue();
+ const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr);
+ if (Inner) {
+ if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
+ return false;
+ }
+
+ if (InSet)
+ return true;
+ return !Sym.isInSection();
+}
+
+bool MCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup,
+ const SectionAddrMap *Addrs,
+ bool InSet) const {
+ ++stats::MCExprEvaluate;
+
+ switch (getKind()) {
+ case Target:
+ return cast<MCTargetExpr>(this)->evaluateAsRelocatableImpl(Res, Layout,
+ Fixup);
+
+ case Constant:
+ Res = MCValue::get(cast<MCConstantExpr>(this)->getValue());
+ return true;
+
+ case SymbolRef: {
+ const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
+ const MCSymbol &Sym = SRE->getSymbol();
+
+ // Evaluate recursively if this is a variable.
+ if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None &&
+ canExpand(Sym, InSet)) {
+ bool IsMachO = SRE->hasSubsectionsViaSymbols();
+ if (Sym.getVariableValue()->evaluateAsRelocatableImpl(
+ Res, Asm, Layout, Fixup, Addrs, InSet || IsMachO)) {
+ if (!IsMachO)
+ return true;
+
+ const MCSymbolRefExpr *A = Res.getSymA();
+ const MCSymbolRefExpr *B = Res.getSymB();
+ // FIXME: This is small hack. Given
+ // a = b + 4
+ // .long a
+ // the OS X assembler will completely drop the 4. We should probably
+ // include it in the relocation or produce an error if that is not
+ // possible.
+ // Allow constant expressions.
+ if (!A && !B)
+ return true;
+ // Allows aliases with zero offset.
+ if (Res.getConstant() == 0 && (!A || !B))
+ return true;
+ }
+ }
+
+ Res = MCValue::get(SRE, nullptr, 0);
+ return true;
+ }
+
+ case Unary: {
+ const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this);
+ MCValue Value;
+
+ if (!AUE->getSubExpr()->evaluateAsRelocatableImpl(Value, Asm, Layout, Fixup,
+ Addrs, InSet))
+ return false;
+
+ switch (AUE->getOpcode()) {
+ case MCUnaryExpr::LNot:
+ if (!Value.isAbsolute())
+ return false;
+ Res = MCValue::get(!Value.getConstant());
+ break;
+ case MCUnaryExpr::Minus:
+ /// -(a - b + const) ==> (b - a - const)
+ if (Value.getSymA() && !Value.getSymB())
+ return false;
+
+ // The cast avoids undefined behavior if the constant is INT64_MIN.
+ Res = MCValue::get(Value.getSymB(), Value.getSymA(),
+ -(uint64_t)Value.getConstant());
+ break;
+ case MCUnaryExpr::Not:
+ if (!Value.isAbsolute())
+ return false;
+ Res = MCValue::get(~Value.getConstant());
+ break;
+ case MCUnaryExpr::Plus:
+ Res = Value;
+ break;
+ }
+
+ return true;
+ }
+
+ case Binary: {
+ const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this);
+ MCValue LHSValue, RHSValue;
+
+ if (!ABE->getLHS()->evaluateAsRelocatableImpl(LHSValue, Asm, Layout, Fixup,
+ Addrs, InSet) ||
+ !ABE->getRHS()->evaluateAsRelocatableImpl(RHSValue, Asm, Layout, Fixup,
+ Addrs, InSet)) {
+ // Check if both are Target Expressions, see if we can compare them.
+ if (const MCTargetExpr *L = dyn_cast<MCTargetExpr>(ABE->getLHS()))
+ if (const MCTargetExpr *R = cast<MCTargetExpr>(ABE->getRHS())) {
+ switch (ABE->getOpcode()) {
+ case MCBinaryExpr::EQ:
+ Res = MCValue::get((L->isEqualTo(R)) ? -1 : 0);
+ return true;
+ case MCBinaryExpr::NE:
+ Res = MCValue::get((R->isEqualTo(R)) ? 0 : -1);
+ return true;
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ // We only support a few operations on non-constant expressions, handle
+ // those first.
+ if (!LHSValue.isAbsolute() || !RHSValue.isAbsolute()) {
+ switch (ABE->getOpcode()) {
+ default:
+ return false;
+ case MCBinaryExpr::Sub:
+ // Negate RHS and add.
+ // The cast avoids undefined behavior if the constant is INT64_MIN.
+ return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue,
+ RHSValue.getSymB(), RHSValue.getSymA(),
+ -(uint64_t)RHSValue.getConstant(), Res);
+
+ case MCBinaryExpr::Add:
+ return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue,
+ RHSValue.getSymA(), RHSValue.getSymB(),
+ RHSValue.getConstant(), Res);
+ }
+ }
+
+ // FIXME: We need target hooks for the evaluation. It may be limited in
+ // width, and gas defines the result of comparisons differently from
+ // Apple as.
+ int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant();
+ int64_t Result = 0;
+ auto Op = ABE->getOpcode();
+ switch (Op) {
+ case MCBinaryExpr::AShr: Result = LHS >> RHS; break;
+ case MCBinaryExpr::Add: Result = LHS + RHS; break;
+ case MCBinaryExpr::And: Result = LHS & RHS; break;
+ case MCBinaryExpr::Div:
+ case MCBinaryExpr::Mod:
+ // Handle division by zero. gas just emits a warning and keeps going,
+ // we try to be stricter.
+ // FIXME: Currently the caller of this function has no way to understand
+ // we're bailing out because of 'division by zero'. Therefore, it will
+ // emit a 'expected relocatable expression' error. It would be nice to
+ // change this code to emit a better diagnostic.
+ if (RHS == 0)
+ return false;
+ if (ABE->getOpcode() == MCBinaryExpr::Div)
+ Result = LHS / RHS;
+ else
+ Result = LHS % RHS;
+ break;
+ case MCBinaryExpr::EQ: Result = LHS == RHS; break;
+ case MCBinaryExpr::GT: Result = LHS > RHS; break;
+ case MCBinaryExpr::GTE: Result = LHS >= RHS; break;
+ case MCBinaryExpr::LAnd: Result = LHS && RHS; break;
+ case MCBinaryExpr::LOr: Result = LHS || RHS; break;
+ case MCBinaryExpr::LShr: Result = uint64_t(LHS) >> uint64_t(RHS); break;
+ case MCBinaryExpr::LT: Result = LHS < RHS; break;
+ case MCBinaryExpr::LTE: Result = LHS <= RHS; break;
+ case MCBinaryExpr::Mul: Result = LHS * RHS; break;
+ case MCBinaryExpr::NE: Result = LHS != RHS; break;
+ case MCBinaryExpr::Or: Result = LHS | RHS; break;
+ case MCBinaryExpr::Shl: Result = uint64_t(LHS) << uint64_t(RHS); break;
+ case MCBinaryExpr::Sub: Result = LHS - RHS; break;
+ case MCBinaryExpr::Xor: Result = LHS ^ RHS; break;
+ }
+
+ switch (Op) {
+ default:
+ Res = MCValue::get(Result);
+ break;
+ case MCBinaryExpr::EQ:
+ case MCBinaryExpr::GT:
+ case MCBinaryExpr::GTE:
+ case MCBinaryExpr::LT:
+ case MCBinaryExpr::LTE:
+ case MCBinaryExpr::NE:
+ // A comparison operator returns a -1 if true and 0 if false.
+ Res = MCValue::get(Result ? -1 : 0);
+ break;
+ }
+
+ return true;
+ }
+ }
+
+ llvm_unreachable("Invalid assembly expression kind!");
+}
+
+MCFragment *MCExpr::findAssociatedFragment() const {
+ switch (getKind()) {
+ case Target:
+ // We never look through target specific expressions.
+ return cast<MCTargetExpr>(this)->findAssociatedFragment();
+
+ case Constant:
+ return MCSymbol::AbsolutePseudoFragment;
+
+ case SymbolRef: {
+ const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this);
+ const MCSymbol &Sym = SRE->getSymbol();
+ return Sym.getFragment();
+ }
+
+ case Unary:
+ return cast<MCUnaryExpr>(this)->getSubExpr()->findAssociatedFragment();
+
+ case Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(this);
+ MCFragment *LHS_F = BE->getLHS()->findAssociatedFragment();
+ MCFragment *RHS_F = BE->getRHS()->findAssociatedFragment();
+
+ // If either is absolute, return the other.
+ if (LHS_F == MCSymbol::AbsolutePseudoFragment)
+ return RHS_F;
+ if (RHS_F == MCSymbol::AbsolutePseudoFragment)
+ return LHS_F;
+
+ // Not always correct, but probably the best we can do without more context.
+ if (BE->getOpcode() == MCBinaryExpr::Sub)
+ return MCSymbol::AbsolutePseudoFragment;
+
+ // Otherwise, return the first non-null fragment.
+ return LHS_F ? LHS_F : RHS_F;
+ }
+ }
+
+ llvm_unreachable("Invalid assembly expression kind!");
+}
diff --git a/llvm/lib/MC/MCFragment.cpp b/llvm/lib/MC/MCFragment.cpp
new file mode 100644
index 000000000000..ae5bd65507bc
--- /dev/null
+++ b/llvm/lib/MC/MCFragment.cpp
@@ -0,0 +1,467 @@
+//===- lib/MC/MCFragment.cpp - Assembler Fragment Implementation ----------===//
+//
+// 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/MCFragment.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+MCAsmLayout::MCAsmLayout(MCAssembler &Asm) : Assembler(Asm) {
+ // Compute the section layout order. Virtual sections must go last.
+ for (MCSection &Sec : Asm)
+ if (!Sec.isVirtualSection())
+ SectionOrder.push_back(&Sec);
+ for (MCSection &Sec : Asm)
+ if (Sec.isVirtualSection())
+ SectionOrder.push_back(&Sec);
+}
+
+bool MCAsmLayout::isFragmentValid(const MCFragment *F) const {
+ const MCSection *Sec = F->getParent();
+ const MCFragment *LastValid = LastValidFragment.lookup(Sec);
+ if (!LastValid)
+ return false;
+ assert(LastValid->getParent() == Sec);
+ return F->getLayoutOrder() <= LastValid->getLayoutOrder();
+}
+
+void MCAsmLayout::invalidateFragmentsFrom(MCFragment *F) {
+ // If this fragment wasn't already valid, we don't need to do anything.
+ if (!isFragmentValid(F))
+ return;
+
+ // Otherwise, reset the last valid fragment to the previous fragment
+ // (if this is the first fragment, it will be NULL).
+ LastValidFragment[F->getParent()] = F->getPrevNode();
+}
+
+void MCAsmLayout::ensureValid(const MCFragment *F) const {
+ MCSection *Sec = F->getParent();
+ MCSection::iterator I;
+ if (MCFragment *Cur = LastValidFragment[Sec])
+ I = ++MCSection::iterator(Cur);
+ else
+ I = Sec->begin();
+
+ // Advance the layout position until the fragment is valid.
+ while (!isFragmentValid(F)) {
+ assert(I != Sec->end() && "Layout bookkeeping error");
+ const_cast<MCAsmLayout *>(this)->layoutFragment(&*I);
+ ++I;
+ }
+}
+
+uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const {
+ ensureValid(F);
+ assert(F->Offset != ~UINT64_C(0) && "Address not set!");
+ return F->Offset;
+}
+
+// Simple getSymbolOffset helper for the non-variable case.
+static bool getLabelOffset(const MCAsmLayout &Layout, const MCSymbol &S,
+ bool ReportError, uint64_t &Val) {
+ if (!S.getFragment()) {
+ if (ReportError)
+ report_fatal_error("unable to evaluate offset to undefined symbol '" +
+ S.getName() + "'");
+ return false;
+ }
+ Val = Layout.getFragmentOffset(S.getFragment()) + S.getOffset();
+ return true;
+}
+
+static bool getSymbolOffsetImpl(const MCAsmLayout &Layout, const MCSymbol &S,
+ bool ReportError, uint64_t &Val) {
+ if (!S.isVariable())
+ return getLabelOffset(Layout, S, ReportError, Val);
+
+ // If SD is a variable, evaluate it.
+ MCValue Target;
+ if (!S.getVariableValue()->evaluateAsValue(Target, Layout))
+ report_fatal_error("unable to evaluate offset for variable '" +
+ S.getName() + "'");
+
+ uint64_t Offset = Target.getConstant();
+
+ const MCSymbolRefExpr *A = Target.getSymA();
+ if (A) {
+ uint64_t ValA;
+ if (!getLabelOffset(Layout, A->getSymbol(), ReportError, ValA))
+ return false;
+ Offset += ValA;
+ }
+
+ const MCSymbolRefExpr *B = Target.getSymB();
+ if (B) {
+ uint64_t ValB;
+ if (!getLabelOffset(Layout, B->getSymbol(), ReportError, ValB))
+ return false;
+ Offset -= ValB;
+ }
+
+ Val = Offset;
+ return true;
+}
+
+bool MCAsmLayout::getSymbolOffset(const MCSymbol &S, uint64_t &Val) const {
+ return getSymbolOffsetImpl(*this, S, false, Val);
+}
+
+uint64_t MCAsmLayout::getSymbolOffset(const MCSymbol &S) const {
+ uint64_t Val;
+ getSymbolOffsetImpl(*this, S, true, Val);
+ return Val;
+}
+
+const MCSymbol *MCAsmLayout::getBaseSymbol(const MCSymbol &Symbol) const {
+ if (!Symbol.isVariable())
+ return &Symbol;
+
+ const MCExpr *Expr = Symbol.getVariableValue();
+ MCValue Value;
+ if (!Expr->evaluateAsValue(Value, *this)) {
+ Assembler.getContext().reportError(
+ Expr->getLoc(), "expression could not be evaluated");
+ return nullptr;
+ }
+
+ const MCSymbolRefExpr *RefB = Value.getSymB();
+ if (RefB) {
+ Assembler.getContext().reportError(
+ Expr->getLoc(), Twine("symbol '") + RefB->getSymbol().getName() +
+ "' could not be evaluated in a subtraction expression");
+ return nullptr;
+ }
+
+ const MCSymbolRefExpr *A = Value.getSymA();
+ if (!A)
+ return nullptr;
+
+ const MCSymbol &ASym = A->getSymbol();
+ const MCAssembler &Asm = getAssembler();
+ if (ASym.isCommon()) {
+ Asm.getContext().reportError(Expr->getLoc(),
+ "Common symbol '" + ASym.getName() +
+ "' cannot be used in assignment expr");
+ return nullptr;
+ }
+
+ return &ASym;
+}
+
+uint64_t MCAsmLayout::getSectionAddressSize(const MCSection *Sec) const {
+ // The size is the last fragment's end offset.
+ const MCFragment &F = Sec->getFragmentList().back();
+ return getFragmentOffset(&F) + getAssembler().computeFragmentSize(*this, F);
+}
+
+uint64_t MCAsmLayout::getSectionFileSize(const MCSection *Sec) const {
+ // Virtual sections have no file size.
+ if (Sec->isVirtualSection())
+ return 0;
+
+ // Otherwise, the file size is the same as the address space size.
+ return getSectionAddressSize(Sec);
+}
+
+uint64_t llvm::computeBundlePadding(const MCAssembler &Assembler,
+ const MCEncodedFragment *F,
+ uint64_t FOffset, uint64_t FSize) {
+ uint64_t BundleSize = Assembler.getBundleAlignSize();
+ assert(BundleSize > 0 &&
+ "computeBundlePadding should only be called if bundling is enabled");
+ uint64_t BundleMask = BundleSize - 1;
+ uint64_t OffsetInBundle = FOffset & BundleMask;
+ uint64_t EndOfFragment = OffsetInBundle + FSize;
+
+ // There are two kinds of bundling restrictions:
+ //
+ // 1) For alignToBundleEnd(), add padding to ensure that the fragment will
+ // *end* on a bundle boundary.
+ // 2) Otherwise, check if the fragment would cross a bundle boundary. If it
+ // would, add padding until the end of the bundle so that the fragment
+ // will start in a new one.
+ if (F->alignToBundleEnd()) {
+ // Three possibilities here:
+ //
+ // A) The fragment just happens to end at a bundle boundary, so we're good.
+ // B) The fragment ends before the current bundle boundary: pad it just
+ // enough to reach the boundary.
+ // C) The fragment ends after the current bundle boundary: pad it until it
+ // reaches the end of the next bundle boundary.
+ //
+ // Note: this code could be made shorter with some modulo trickery, but it's
+ // intentionally kept in its more explicit form for simplicity.
+ if (EndOfFragment == BundleSize)
+ return 0;
+ else if (EndOfFragment < BundleSize)
+ return BundleSize - EndOfFragment;
+ else { // EndOfFragment > BundleSize
+ return 2 * BundleSize - EndOfFragment;
+ }
+ } else if (OffsetInBundle > 0 && EndOfFragment > BundleSize)
+ return BundleSize - OffsetInBundle;
+ else
+ return 0;
+}
+
+/* *** */
+
+void ilist_alloc_traits<MCFragment>::deleteNode(MCFragment *V) { V->destroy(); }
+
+MCFragment::~MCFragment() = default;
+
+MCFragment::MCFragment(FragmentType Kind, bool HasInstructions,
+ MCSection *Parent)
+ : Kind(Kind), HasInstructions(HasInstructions), LayoutOrder(0),
+ Parent(Parent), Atom(nullptr), Offset(~UINT64_C(0)) {
+ if (Parent && !isDummy())
+ Parent->getFragmentList().push_back(this);
+}
+
+void MCFragment::destroy() {
+ // First check if we are the sentinal.
+ if (Kind == FragmentType(~0)) {
+ delete this;
+ return;
+ }
+
+ switch (Kind) {
+ case FT_Align:
+ delete cast<MCAlignFragment>(this);
+ return;
+ case FT_Data:
+ delete cast<MCDataFragment>(this);
+ return;
+ case FT_CompactEncodedInst:
+ delete cast<MCCompactEncodedInstFragment>(this);
+ return;
+ case FT_Fill:
+ delete cast<MCFillFragment>(this);
+ return;
+ case FT_Relaxable:
+ delete cast<MCRelaxableFragment>(this);
+ return;
+ case FT_Org:
+ delete cast<MCOrgFragment>(this);
+ return;
+ case FT_Dwarf:
+ delete cast<MCDwarfLineAddrFragment>(this);
+ return;
+ case FT_DwarfFrame:
+ delete cast<MCDwarfCallFrameFragment>(this);
+ return;
+ case FT_LEB:
+ delete cast<MCLEBFragment>(this);
+ return;
+ case FT_Padding:
+ delete cast<MCPaddingFragment>(this);
+ return;
+ case FT_SymbolId:
+ delete cast<MCSymbolIdFragment>(this);
+ return;
+ case FT_CVInlineLines:
+ delete cast<MCCVInlineLineTableFragment>(this);
+ return;
+ case FT_CVDefRange:
+ delete cast<MCCVDefRangeFragment>(this);
+ return;
+ case FT_Dummy:
+ delete cast<MCDummyFragment>(this);
+ return;
+ }
+}
+
+// Debugging methods
+
+namespace llvm {
+
+raw_ostream &operator<<(raw_ostream &OS, const MCFixup &AF) {
+ OS << "<MCFixup" << " Offset:" << AF.getOffset()
+ << " Value:" << *AF.getValue()
+ << " Kind:" << AF.getKind() << ">";
+ return OS;
+}
+
+} // end namespace llvm
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCFragment::dump() const {
+ raw_ostream &OS = errs();
+
+ OS << "<";
+ switch (getKind()) {
+ case MCFragment::FT_Align: OS << "MCAlignFragment"; break;
+ case MCFragment::FT_Data: OS << "MCDataFragment"; break;
+ case MCFragment::FT_CompactEncodedInst:
+ OS << "MCCompactEncodedInstFragment"; break;
+ case MCFragment::FT_Fill: OS << "MCFillFragment"; break;
+ case MCFragment::FT_Relaxable: OS << "MCRelaxableFragment"; break;
+ case MCFragment::FT_Org: OS << "MCOrgFragment"; break;
+ case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break;
+ case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break;
+ case MCFragment::FT_LEB: OS << "MCLEBFragment"; break;
+ case MCFragment::FT_Padding: OS << "MCPaddingFragment"; break;
+ case MCFragment::FT_SymbolId: OS << "MCSymbolIdFragment"; break;
+ case MCFragment::FT_CVInlineLines: OS << "MCCVInlineLineTableFragment"; break;
+ case MCFragment::FT_CVDefRange: OS << "MCCVDefRangeTableFragment"; break;
+ case MCFragment::FT_Dummy: OS << "MCDummyFragment"; break;
+ }
+
+ OS << "<MCFragment " << (const void *)this << " LayoutOrder:" << LayoutOrder
+ << " Offset:" << Offset << " HasInstructions:" << hasInstructions();
+ if (const MCEncodedFragment *EF = dyn_cast<MCEncodedFragment>(this))
+ OS << " BundlePadding:" << static_cast<unsigned>(EF->getBundlePadding());
+ OS << ">";
+
+ switch (getKind()) {
+ case MCFragment::FT_Align: {
+ const MCAlignFragment *AF = cast<MCAlignFragment>(this);
+ if (AF->hasEmitNops())
+ OS << " (emit nops)";
+ OS << "\n ";
+ OS << " Alignment:" << AF->getAlignment()
+ << " Value:" << AF->getValue() << " ValueSize:" << AF->getValueSize()
+ << " MaxBytesToEmit:" << AF->getMaxBytesToEmit() << ">";
+ break;
+ }
+ case MCFragment::FT_Data: {
+ const MCDataFragment *DF = cast<MCDataFragment>(this);
+ OS << "\n ";
+ OS << " Contents:[";
+ const SmallVectorImpl<char> &Contents = DF->getContents();
+ for (unsigned i = 0, e = Contents.size(); i != e; ++i) {
+ if (i) OS << ",";
+ OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF);
+ }
+ OS << "] (" << Contents.size() << " bytes)";
+
+ if (DF->fixup_begin() != DF->fixup_end()) {
+ OS << ",\n ";
+ OS << " Fixups:[";
+ for (MCDataFragment::const_fixup_iterator it = DF->fixup_begin(),
+ ie = DF->fixup_end(); it != ie; ++it) {
+ if (it != DF->fixup_begin()) OS << ",\n ";
+ OS << *it;
+ }
+ OS << "]";
+ }
+ break;
+ }
+ case MCFragment::FT_CompactEncodedInst: {
+ const MCCompactEncodedInstFragment *CEIF =
+ cast<MCCompactEncodedInstFragment>(this);
+ OS << "\n ";
+ OS << " Contents:[";
+ const SmallVectorImpl<char> &Contents = CEIF->getContents();
+ for (unsigned i = 0, e = Contents.size(); i != e; ++i) {
+ if (i) OS << ",";
+ OS << hexdigit((Contents[i] >> 4) & 0xF) << hexdigit(Contents[i] & 0xF);
+ }
+ OS << "] (" << Contents.size() << " bytes)";
+ break;
+ }
+ case MCFragment::FT_Fill: {
+ const MCFillFragment *FF = cast<MCFillFragment>(this);
+ OS << " Value:" << static_cast<unsigned>(FF->getValue())
+ << " ValueSize:" << static_cast<unsigned>(FF->getValueSize())
+ << " NumValues:" << FF->getNumValues();
+ break;
+ }
+ case MCFragment::FT_Relaxable: {
+ const MCRelaxableFragment *F = cast<MCRelaxableFragment>(this);
+ OS << "\n ";
+ OS << " Inst:";
+ F->getInst().dump_pretty(OS);
+ break;
+ }
+ case MCFragment::FT_Org: {
+ const MCOrgFragment *OF = cast<MCOrgFragment>(this);
+ OS << "\n ";
+ OS << " Offset:" << OF->getOffset()
+ << " Value:" << static_cast<unsigned>(OF->getValue());
+ break;
+ }
+ case MCFragment::FT_Dwarf: {
+ const MCDwarfLineAddrFragment *OF = cast<MCDwarfLineAddrFragment>(this);
+ OS << "\n ";
+ OS << " AddrDelta:" << OF->getAddrDelta()
+ << " LineDelta:" << OF->getLineDelta();
+ break;
+ }
+ case MCFragment::FT_DwarfFrame: {
+ const MCDwarfCallFrameFragment *CF = cast<MCDwarfCallFrameFragment>(this);
+ OS << "\n ";
+ OS << " AddrDelta:" << CF->getAddrDelta();
+ break;
+ }
+ case MCFragment::FT_LEB: {
+ const MCLEBFragment *LF = cast<MCLEBFragment>(this);
+ OS << "\n ";
+ OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned();
+ break;
+ }
+ case MCFragment::FT_Padding: {
+ const MCPaddingFragment *F = cast<MCPaddingFragment>(this);
+ OS << "\n ";
+ OS << " PaddingPoliciesMask:" << F->getPaddingPoliciesMask()
+ << " IsInsertionPoint:" << F->isInsertionPoint()
+ << " Size:" << F->getSize();
+ OS << "\n ";
+ OS << " Inst:";
+ F->getInst().dump_pretty(OS);
+ OS << " InstSize:" << F->getInstSize();
+ OS << "\n ";
+ break;
+ }
+ case MCFragment::FT_SymbolId: {
+ const MCSymbolIdFragment *F = cast<MCSymbolIdFragment>(this);
+ OS << "\n ";
+ OS << " Sym:" << F->getSymbol();
+ break;
+ }
+ case MCFragment::FT_CVInlineLines: {
+ const auto *F = cast<MCCVInlineLineTableFragment>(this);
+ OS << "\n ";
+ OS << " Sym:" << *F->getFnStartSym();
+ break;
+ }
+ case MCFragment::FT_CVDefRange: {
+ const auto *F = cast<MCCVDefRangeFragment>(this);
+ OS << "\n ";
+ for (std::pair<const MCSymbol *, const MCSymbol *> RangeStartEnd :
+ F->getRanges()) {
+ OS << " RangeStart:" << RangeStartEnd.first;
+ OS << " RangeEnd:" << RangeStartEnd.second;
+ }
+ break;
+ }
+ case MCFragment::FT_Dummy:
+ break;
+ }
+ OS << ">";
+}
+#endif
diff --git a/llvm/lib/MC/MCInst.cpp b/llvm/lib/MC/MCInst.cpp
new file mode 100644
index 000000000000..f6f6edee5822
--- /dev/null
+++ b/llvm/lib/MC/MCInst.cpp
@@ -0,0 +1,98 @@
+//===- lib/MC/MCInst.cpp - MCInst implementation --------------------------===//
+//
+// 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/MCInst.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void MCOperand::print(raw_ostream &OS) const {
+ OS << "<MCOperand ";
+ if (!isValid())
+ OS << "INVALID";
+ else if (isReg())
+ OS << "Reg:" << getReg();
+ else if (isImm())
+ OS << "Imm:" << getImm();
+ else if (isFPImm())
+ OS << "FPImm:" << getFPImm();
+ else if (isExpr()) {
+ OS << "Expr:(" << *getExpr() << ")";
+ } else if (isInst()) {
+ OS << "Inst:(" << *getInst() << ")";
+ } else
+ OS << "UNDEFINED";
+ OS << ">";
+}
+
+bool MCOperand::evaluateAsConstantImm(int64_t &Imm) const {
+ if (isImm()) {
+ Imm = getImm();
+ return true;
+ }
+ return false;
+}
+
+bool MCOperand::isBareSymbolRef() const {
+ assert(isExpr() &&
+ "isBareSymbolRef expects only expressions");
+ const MCExpr *Expr = getExpr();
+ MCExpr::ExprKind Kind = getExpr()->getKind();
+ return Kind == MCExpr::SymbolRef &&
+ cast<MCSymbolRefExpr>(Expr)->getKind() == MCSymbolRefExpr::VK_None;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCOperand::dump() const {
+ print(dbgs());
+ dbgs() << "\n";
+}
+#endif
+
+void MCInst::print(raw_ostream &OS) const {
+ OS << "<MCInst " << getOpcode();
+ for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
+ OS << " ";
+ getOperand(i).print(OS);
+ }
+ OS << ">";
+}
+
+void MCInst::dump_pretty(raw_ostream &OS, const MCInstPrinter *Printer,
+ StringRef Separator) const {
+ StringRef InstName = Printer ? Printer->getOpcodeName(getOpcode()) : "";
+ dump_pretty(OS, InstName, Separator);
+}
+
+void MCInst::dump_pretty(raw_ostream &OS, StringRef Name,
+ StringRef Separator) const {
+ OS << "<MCInst #" << getOpcode();
+
+ // Show the instruction opcode name if we have it.
+ if (!Name.empty())
+ OS << ' ' << Name;
+
+ for (unsigned i = 0, e = getNumOperands(); i != e; ++i) {
+ OS << Separator;
+ getOperand(i).print(OS);
+ }
+ OS << ">";
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCInst::dump() const {
+ print(dbgs());
+ dbgs() << "\n";
+}
+#endif
diff --git a/llvm/lib/MC/MCInstPrinter.cpp b/llvm/lib/MC/MCInstPrinter.cpp
new file mode 100644
index 000000000000..c5c06f323e68
--- /dev/null
+++ b/llvm/lib/MC/MCInstPrinter.cpp
@@ -0,0 +1,120 @@
+//===- MCInstPrinter.cpp - Convert an MCInst to target assembly syntax ----===//
+//
+// 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/MCInstPrinter.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+void llvm::dumpBytes(ArrayRef<uint8_t> bytes, raw_ostream &OS) {
+ static const char hex_rep[] = "0123456789abcdef";
+ bool First = true;
+ for (char i: bytes) {
+ if (First)
+ First = false;
+ else
+ OS << ' ';
+ OS << hex_rep[(i & 0xF0) >> 4];
+ OS << hex_rep[i & 0xF];
+ }
+}
+
+MCInstPrinter::~MCInstPrinter() = default;
+
+/// getOpcodeName - Return the name of the specified opcode enum (e.g.
+/// "MOV32ri") or empty if we can't resolve it.
+StringRef MCInstPrinter::getOpcodeName(unsigned Opcode) const {
+ return MII.getName(Opcode);
+}
+
+void MCInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const {
+ llvm_unreachable("Target should implement this");
+}
+
+void MCInstPrinter::printAnnotation(raw_ostream &OS, StringRef Annot) {
+ if (!Annot.empty()) {
+ if (CommentStream) {
+ (*CommentStream) << Annot;
+ // By definition (see MCInstPrinter.h), CommentStream must end with
+ // a newline after each comment.
+ if (Annot.back() != '\n')
+ (*CommentStream) << '\n';
+ } else
+ OS << " " << MAI.getCommentString() << " " << Annot;
+ }
+}
+
+/// Utility functions to make adding mark ups simpler.
+StringRef MCInstPrinter::markup(StringRef s) const {
+ if (getUseMarkup())
+ return s;
+ else
+ return "";
+}
+
+// For asm-style hex (e.g. 0ffh) the first digit always has to be a number.
+static bool needsLeadingZero(uint64_t Value)
+{
+ while (Value)
+ {
+ uint64_t digit = (Value >> 60) & 0xf;
+ if (digit != 0)
+ return (digit >= 0xa);
+ Value <<= 4;
+ }
+ return false;
+}
+
+format_object<int64_t> MCInstPrinter::formatDec(int64_t Value) const {
+ return format("%" PRId64, Value);
+}
+
+format_object<int64_t> MCInstPrinter::formatHex(int64_t Value) const {
+ switch (PrintHexStyle) {
+ case HexStyle::C:
+ if (Value < 0) {
+ if (Value == std::numeric_limits<int64_t>::min())
+ return format<int64_t>("-0x8000000000000000", Value);
+ return format("-0x%" PRIx64, -Value);
+ }
+ return format("0x%" PRIx64, Value);
+ case HexStyle::Asm:
+ if (Value < 0) {
+ if (Value == std::numeric_limits<int64_t>::min())
+ return format<int64_t>("-8000000000000000h", Value);
+ if (needsLeadingZero(-(uint64_t)(Value)))
+ return format("-0%" PRIx64 "h", -Value);
+ return format("-%" PRIx64 "h", -Value);
+ }
+ if (needsLeadingZero((uint64_t)(Value)))
+ return format("0%" PRIx64 "h", Value);
+ return format("%" PRIx64 "h", Value);
+ }
+ llvm_unreachable("unsupported print style");
+}
+
+format_object<uint64_t> MCInstPrinter::formatHex(uint64_t Value) const {
+ switch(PrintHexStyle) {
+ case HexStyle::C:
+ return format("0x%" PRIx64, Value);
+ case HexStyle::Asm:
+ if (needsLeadingZero(Value))
+ return format("0%" PRIx64 "h", Value);
+ else
+ return format("%" PRIx64 "h", Value);
+ }
+ llvm_unreachable("unsupported print style");
+}
diff --git a/llvm/lib/MC/MCInstrAnalysis.cpp b/llvm/lib/MC/MCInstrAnalysis.cpp
new file mode 100644
index 000000000000..54741fdd686d
--- /dev/null
+++ b/llvm/lib/MC/MCInstrAnalysis.cpp
@@ -0,0 +1,41 @@
+//===- MCInstrAnalysis.cpp - InstrDesc target hooks -----------------------===//
+//
+// 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/MCInstrAnalysis.h"
+
+#include "llvm/ADT/APInt.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include <cstdint>
+
+using namespace llvm;
+
+bool MCInstrAnalysis::clearsSuperRegisters(const MCRegisterInfo &MRI,
+ const MCInst &Inst,
+ APInt &Writes) const {
+ Writes.clearAllBits();
+ return false;
+}
+
+bool MCInstrAnalysis::evaluateBranch(const MCInst &Inst, uint64_t Addr,
+ uint64_t Size, uint64_t &Target) const {
+ if (Inst.getNumOperands() == 0 ||
+ Info->get(Inst.getOpcode()).OpInfo[0].OperandType != MCOI::OPERAND_PCREL)
+ return false;
+
+ int64_t Imm = Inst.getOperand(0).getImm();
+ Target = Addr+Size+Imm;
+ return true;
+}
+
+Optional<uint64_t>
+MCInstrAnalysis::evaluateMemoryOperandAddress(const MCInst &Inst, uint64_t Addr,
+ uint64_t Size) const {
+ return None;
+}
diff --git a/llvm/lib/MC/MCInstrDesc.cpp b/llvm/lib/MC/MCInstrDesc.cpp
new file mode 100644
index 000000000000..d54aeba89edc
--- /dev/null
+++ b/llvm/lib/MC/MCInstrDesc.cpp
@@ -0,0 +1,65 @@
+//===------ llvm/MC/MCInstrDesc.cpp- Instruction Descriptors --------------===//
+//
+// 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 defines methods on the MCOperandInfo and MCInstrDesc classes, which
+// are used to describe target instructions and their operands.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+
+using namespace llvm;
+
+bool MCInstrDesc::getDeprecatedInfo(MCInst &MI, const MCSubtargetInfo &STI,
+ std::string &Info) const {
+ if (ComplexDeprecationInfo)
+ return ComplexDeprecationInfo(MI, STI, Info);
+ if (DeprecatedFeature != -1 && STI.getFeatureBits()[DeprecatedFeature]) {
+ // FIXME: it would be nice to include the subtarget feature here.
+ Info = "deprecated";
+ return true;
+ }
+ return false;
+}
+bool MCInstrDesc::mayAffectControlFlow(const MCInst &MI,
+ const MCRegisterInfo &RI) const {
+ if (isBranch() || isCall() || isReturn() || isIndirectBranch())
+ return true;
+ unsigned PC = RI.getProgramCounter();
+ if (PC == 0)
+ return false;
+ if (hasDefOfPhysReg(MI, PC, RI))
+ return true;
+ return false;
+}
+
+bool MCInstrDesc::hasImplicitDefOfPhysReg(unsigned Reg,
+ const MCRegisterInfo *MRI) const {
+ if (const MCPhysReg *ImpDefs = ImplicitDefs)
+ for (; *ImpDefs; ++ImpDefs)
+ if (*ImpDefs == Reg || (MRI && MRI->isSubRegister(Reg, *ImpDefs)))
+ return true;
+ return false;
+}
+
+bool MCInstrDesc::hasDefOfPhysReg(const MCInst &MI, unsigned Reg,
+ const MCRegisterInfo &RI) const {
+ for (int i = 0, e = NumDefs; i != e; ++i)
+ if (MI.getOperand(i).isReg() &&
+ RI.isSubRegisterEq(Reg, MI.getOperand(i).getReg()))
+ return true;
+ if (variadicOpsAreDefs())
+ for (int i = NumOperands - 1, e = MI.getNumOperands(); i != e; ++i)
+ if (MI.getOperand(i).isReg() &&
+ RI.isSubRegisterEq(Reg, MI.getOperand(i).getReg()))
+ return true;
+ return hasImplicitDefOfPhysReg(Reg, &RI);
+}
diff --git a/llvm/lib/MC/MCLabel.cpp b/llvm/lib/MC/MCLabel.cpp
new file mode 100644
index 000000000000..66ee73c5bbb3
--- /dev/null
+++ b/llvm/lib/MC/MCLabel.cpp
@@ -0,0 +1,25 @@
+//===- lib/MC/MCLabel.cpp - MCLabel implementation ------------------------===//
+//
+// 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/MCLabel.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void MCLabel::print(raw_ostream &OS) const {
+ OS << '"' << getInstance() << '"';
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCLabel::dump() const {
+ print(dbgs());
+}
+#endif
diff --git a/llvm/lib/MC/MCLinkerOptimizationHint.cpp b/llvm/lib/MC/MCLinkerOptimizationHint.cpp
new file mode 100644
index 000000000000..9ab321872b11
--- /dev/null
+++ b/llvm/lib/MC/MCLinkerOptimizationHint.cpp
@@ -0,0 +1,59 @@
+//===- llvm/MC/MCLinkerOptimizationHint.cpp ----- LOH handling ------------===//
+//
+// 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/MCLinkerOptimizationHint.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+
+// Each LOH is composed by, in this order (each field is encoded using ULEB128):
+// - Its kind.
+// - Its number of arguments (let say N).
+// - Its arg1.
+// - ...
+// - Its argN.
+// <arg1> to <argN> are absolute addresses in the object file, i.e.,
+// relative addresses from the beginning of the object file.
+void MCLOHDirective::emit_impl(raw_ostream &OutStream,
+ const MachObjectWriter &ObjWriter,
+ const MCAsmLayout &Layout) const {
+ encodeULEB128(Kind, OutStream);
+ encodeULEB128(Args.size(), OutStream);
+ for (const MCSymbol *Arg : Args)
+ encodeULEB128(ObjWriter.getSymbolAddress(*Arg, Layout), OutStream);
+}
+
+void MCLOHDirective::emit(MachObjectWriter &ObjWriter,
+ const MCAsmLayout &Layout) const {
+ raw_ostream &OutStream = ObjWriter.W.OS;
+ emit_impl(OutStream, ObjWriter, Layout);
+}
+
+uint64_t MCLOHDirective::getEmitSize(const MachObjectWriter &ObjWriter,
+ const MCAsmLayout &Layout) const {
+ class raw_counting_ostream : public raw_ostream {
+ uint64_t Count = 0;
+
+ void write_impl(const char *, size_t size) override { Count += size; }
+
+ uint64_t current_pos() const override { return Count; }
+
+ public:
+ raw_counting_ostream() = default;
+ ~raw_counting_ostream() override { flush(); }
+ };
+
+ raw_counting_ostream OutStream;
+ emit_impl(OutStream, ObjWriter, Layout);
+ return OutStream.tell();
+}
diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp
new file mode 100644
index 000000000000..8e558a36b7a1
--- /dev/null
+++ b/llvm/lib/MC/MCMachOStreamer.cpp
@@ -0,0 +1,520 @@
+//===- MCMachOStreamer.cpp - MachO Streamer -------------------------------===//
+//
+// 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/ADT/DenseMap.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCLinkerOptimizationHint.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolMachO.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+class MCMachOStreamer : public MCObjectStreamer {
+private:
+ /// LabelSections - true if each section change should emit a linker local
+ /// label for use in relocations for assembler local references. Obviates the
+ /// need for local relocations. False by default.
+ bool LabelSections;
+
+ bool DWARFMustBeAtTheEnd;
+ bool CreatedADWARFSection;
+
+ /// HasSectionLabel - map of which sections have already had a non-local
+ /// label emitted to them. Used so we don't emit extraneous linker local
+ /// labels in the middle of the section.
+ DenseMap<const MCSection*, bool> HasSectionLabel;
+
+ void EmitInstToData(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+
+ void EmitDataRegion(DataRegionData::KindTy Kind);
+ void EmitDataRegionEnd();
+
+public:
+ MCMachOStreamer(MCContext &Context, std::unique_ptr<MCAsmBackend> MAB,
+ std::unique_ptr<MCObjectWriter> OW,
+ std::unique_ptr<MCCodeEmitter> Emitter,
+ bool DWARFMustBeAtTheEnd, bool label)
+ : MCObjectStreamer(Context, std::move(MAB), std::move(OW),
+ std::move(Emitter)),
+ LabelSections(label), DWARFMustBeAtTheEnd(DWARFMustBeAtTheEnd),
+ CreatedADWARFSection(false) {}
+
+ /// state management
+ void reset() override {
+ CreatedADWARFSection = false;
+ HasSectionLabel.clear();
+ MCObjectStreamer::reset();
+ }
+
+ /// @name MCStreamer Interface
+ /// @{
+
+ void ChangeSection(MCSection *Sect, const MCExpr *Subsect) override;
+ void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
+ void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
+ void EmitEHSymAttributes(const MCSymbol *Symbol, MCSymbol *EHSymbol) override;
+ void EmitAssemblerFlag(MCAssemblerFlag Flag) override;
+ void EmitLinkerOptions(ArrayRef<std::string> Options) override;
+ void EmitDataRegion(MCDataRegionType Kind) override;
+ void EmitVersionMin(MCVersionMinType Kind, unsigned Major, unsigned Minor,
+ unsigned Update, VersionTuple SDKVersion) override;
+ void EmitBuildVersion(unsigned Platform, unsigned Major, unsigned Minor,
+ unsigned Update, VersionTuple SDKVersion) override;
+ void EmitThumbFunc(MCSymbol *Func) override;
+ bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+ void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;
+ void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) override;
+
+ void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) override;
+ void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+ uint64_t Size = 0, unsigned ByteAlignment = 0,
+ SMLoc Loc = SMLoc()) override;
+ void EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment = 0) override;
+
+ void EmitIdent(StringRef IdentString) override {
+ llvm_unreachable("macho doesn't support this directive");
+ }
+
+ void EmitLOHDirective(MCLOHType Kind, const MCLOHArgs &Args) override {
+ getAssembler().getLOHContainer().addDirective(Kind, Args);
+ }
+
+ void FinishImpl() override;
+};
+
+} // end anonymous namespace.
+
+static bool canGoAfterDWARF(const MCSectionMachO &MSec) {
+ // These sections are created by the assembler itself after the end of
+ // the .s file.
+ StringRef SegName = MSec.getSegmentName();
+ StringRef SecName = MSec.getSectionName();
+
+ if (SegName == "__LD" && SecName == "__compact_unwind")
+ return true;
+
+ if (SegName == "__IMPORT") {
+ if (SecName == "__jump_table")
+ return true;
+
+ if (SecName == "__pointers")
+ return true;
+ }
+
+ if (SegName == "__TEXT" && SecName == "__eh_frame")
+ return true;
+
+ if (SegName == "__DATA" && (SecName == "__nl_symbol_ptr" ||
+ SecName == "__thread_ptr"))
+ return true;
+
+ return false;
+}
+
+void MCMachOStreamer::ChangeSection(MCSection *Section,
+ const MCExpr *Subsection) {
+ // Change the section normally.
+ bool Created = changeSectionImpl(Section, Subsection);
+ const MCSectionMachO &MSec = *cast<MCSectionMachO>(Section);
+ StringRef SegName = MSec.getSegmentName();
+ if (SegName == "__DWARF")
+ CreatedADWARFSection = true;
+ else if (Created && DWARFMustBeAtTheEnd && !canGoAfterDWARF(MSec))
+ assert(!CreatedADWARFSection && "Creating regular section after DWARF");
+
+ // Output a linker-local symbol so we don't need section-relative local
+ // relocations. The linker hates us when we do that.
+ if (LabelSections && !HasSectionLabel[Section] &&
+ !Section->getBeginSymbol()) {
+ MCSymbol *Label = getContext().createLinkerPrivateTempSymbol();
+ Section->setBeginSymbol(Label);
+ HasSectionLabel[Section] = true;
+ }
+}
+
+void MCMachOStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
+ MCSymbol *EHSymbol) {
+ getAssembler().registerSymbol(*Symbol);
+ if (Symbol->isExternal())
+ EmitSymbolAttribute(EHSymbol, MCSA_Global);
+ if (cast<MCSymbolMachO>(Symbol)->isWeakDefinition())
+ EmitSymbolAttribute(EHSymbol, MCSA_WeakDefinition);
+ if (Symbol->isPrivateExtern())
+ EmitSymbolAttribute(EHSymbol, MCSA_PrivateExtern);
+}
+
+void MCMachOStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) {
+ // We have to create a new fragment if this is an atom defining symbol,
+ // fragments cannot span atoms.
+ if (getAssembler().isSymbolLinkerVisible(*Symbol))
+ insert(new MCDataFragment());
+
+ MCObjectStreamer::EmitLabel(Symbol, Loc);
+
+ // This causes the reference type flag to be cleared. Darwin 'as' was "trying"
+ // to clear the weak reference and weak definition bits too, but the
+ // implementation was buggy. For now we just try to match 'as', for
+ // diffability.
+ //
+ // FIXME: Cleanup this code, these bits should be emitted based on semantic
+ // properties, not on the order of definition, etc.
+ cast<MCSymbolMachO>(Symbol)->clearReferenceType();
+}
+
+void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ MCValue Res;
+
+ if (Value->evaluateAsRelocatable(Res, nullptr, nullptr)) {
+ if (const MCSymbolRefExpr *SymAExpr = Res.getSymA()) {
+ const MCSymbol &SymA = SymAExpr->getSymbol();
+ if (!Res.getSymB() && (SymA.getName() == "" || Res.getConstant() != 0))
+ cast<MCSymbolMachO>(Symbol)->setAltEntry();
+ }
+ }
+ MCObjectStreamer::EmitAssignment(Symbol, Value);
+}
+
+void MCMachOStreamer::EmitDataRegion(DataRegionData::KindTy Kind) {
+ // Create a temporary label to mark the start of the data region.
+ MCSymbol *Start = getContext().createTempSymbol();
+ EmitLabel(Start);
+ // Record the region for the object writer to use.
+ DataRegionData Data = { Kind, Start, nullptr };
+ std::vector<DataRegionData> &Regions = getAssembler().getDataRegions();
+ Regions.push_back(Data);
+}
+
+void MCMachOStreamer::EmitDataRegionEnd() {
+ std::vector<DataRegionData> &Regions = getAssembler().getDataRegions();
+ assert(!Regions.empty() && "Mismatched .end_data_region!");
+ DataRegionData &Data = Regions.back();
+ assert(!Data.End && "Mismatched .end_data_region!");
+ // Create a temporary label to mark the end of the data region.
+ Data.End = getContext().createTempSymbol();
+ EmitLabel(Data.End);
+}
+
+void MCMachOStreamer::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;
+ }
+}
+
+void MCMachOStreamer::EmitLinkerOptions(ArrayRef<std::string> Options) {
+ getAssembler().getLinkerOptions().push_back(Options);
+}
+
+void MCMachOStreamer::EmitDataRegion(MCDataRegionType Kind) {
+ switch (Kind) {
+ case MCDR_DataRegion:
+ EmitDataRegion(DataRegionData::Data);
+ return;
+ case MCDR_DataRegionJT8:
+ EmitDataRegion(DataRegionData::JumpTable8);
+ return;
+ case MCDR_DataRegionJT16:
+ EmitDataRegion(DataRegionData::JumpTable16);
+ return;
+ case MCDR_DataRegionJT32:
+ EmitDataRegion(DataRegionData::JumpTable32);
+ return;
+ case MCDR_DataRegionEnd:
+ EmitDataRegionEnd();
+ return;
+ }
+}
+
+void MCMachOStreamer::EmitVersionMin(MCVersionMinType Kind, unsigned Major,
+ unsigned Minor, unsigned Update,
+ VersionTuple SDKVersion) {
+ getAssembler().setVersionMin(Kind, Major, Minor, Update, SDKVersion);
+}
+
+void MCMachOStreamer::EmitBuildVersion(unsigned Platform, unsigned Major,
+ unsigned Minor, unsigned Update,
+ VersionTuple SDKVersion) {
+ getAssembler().setBuildVersion((MachO::PlatformType)Platform, Major, Minor,
+ Update, SDKVersion);
+}
+
+void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) {
+ // Remember that the function is a thumb function. Fixup and relocation
+ // values will need adjusted.
+ getAssembler().setIsThumbFunc(Symbol);
+ cast<MCSymbolMachO>(Symbol)->setThumbFunc();
+}
+
+bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Sym,
+ MCSymbolAttr Attribute) {
+ MCSymbolMachO *Symbol = cast<MCSymbolMachO>(Sym);
+
+ // Indirect symbols are handled differently, to match how 'as' handles
+ // them. This makes writing matching .o files easier.
+ if (Attribute == MCSA_IndirectSymbol) {
+ // Note that we intentionally cannot use the symbol data here; this is
+ // important for matching the string table that 'as' generates.
+ IndirectSymbolData ISD;
+ ISD.Symbol = Symbol;
+ ISD.Section = getCurrentSectionOnly();
+ getAssembler().getIndirectSymbols().push_back(ISD);
+ return true;
+ }
+
+ // 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_Invalid:
+ case MCSA_ELF_TypeFunction:
+ case MCSA_ELF_TypeIndFunction:
+ case MCSA_ELF_TypeObject:
+ case MCSA_ELF_TypeTLS:
+ case MCSA_ELF_TypeCommon:
+ case MCSA_ELF_TypeNoType:
+ case MCSA_ELF_TypeGnuUniqueObject:
+ case MCSA_Hidden:
+ case MCSA_IndirectSymbol:
+ case MCSA_Internal:
+ case MCSA_Protected:
+ case MCSA_Weak:
+ case MCSA_Local:
+ case MCSA_LGlobal:
+ return false;
+
+ case MCSA_Global:
+ Symbol->setExternal(true);
+ // This effectively clears the undefined lazy bit, in Darwin 'as', although
+ // it isn't very consistent because it implements this as part of symbol
+ // lookup.
+ //
+ // FIXME: Cleanup this code, these bits should be emitted based on semantic
+ // properties, not on the order of definition, etc.
+ Symbol->setReferenceTypeUndefinedLazy(false);
+ break;
+
+ case MCSA_LazyReference:
+ // FIXME: This requires -dynamic.
+ Symbol->setNoDeadStrip();
+ if (Symbol->isUndefined())
+ Symbol->setReferenceTypeUndefinedLazy(true);
+ break;
+
+ // Since .reference sets the no dead strip bit, it is equivalent to
+ // .no_dead_strip in practice.
+ case MCSA_Reference:
+ case MCSA_NoDeadStrip:
+ Symbol->setNoDeadStrip();
+ break;
+
+ case MCSA_SymbolResolver:
+ Symbol->setSymbolResolver();
+ break;
+
+ case MCSA_AltEntry:
+ Symbol->setAltEntry();
+ break;
+
+ case MCSA_PrivateExtern:
+ Symbol->setExternal(true);
+ Symbol->setPrivateExtern(true);
+ break;
+
+ case MCSA_WeakReference:
+ // FIXME: This requires -dynamic.
+ if (Symbol->isUndefined())
+ Symbol->setWeakReference();
+ break;
+
+ case MCSA_WeakDefinition:
+ // FIXME: 'as' enforces that this is defined and global. The manual claims
+ // it has to be in a coalesced section, but this isn't enforced.
+ Symbol->setWeakDefinition();
+ break;
+
+ case MCSA_WeakDefAutoPrivate:
+ Symbol->setWeakDefinition();
+ Symbol->setWeakReference();
+ break;
+
+ case MCSA_Cold:
+ Symbol->setCold();
+ break;
+ }
+
+ return true;
+}
+
+void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
+ // Encode the 'desc' value into the lowest implementation defined bits.
+ getAssembler().registerSymbol(*Symbol);
+ cast<MCSymbolMachO>(Symbol)->setDesc(DescValue);
+}
+
+void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
+ assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
+
+ getAssembler().registerSymbol(*Symbol);
+ Symbol->setExternal(true);
+ Symbol->setCommon(Size, ByteAlignment);
+}
+
+void MCMachOStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ // '.lcomm' is equivalent to '.zerofill'.
+ return EmitZerofill(getContext().getObjectFileInfo()->getDataBSSSection(),
+ Symbol, Size, ByteAlignment);
+}
+
+void MCMachOStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment,
+ SMLoc Loc) {
+ // On darwin all virtual sections have zerofill type. Disallow the usage of
+ // .zerofill in non-virtual functions. If something similar is needed, use
+ // .space or .zero.
+ if (!Section->isVirtualSection()) {
+ getContext().reportError(
+ Loc, "The usage of .zerofill is restricted to sections of "
+ "ZEROFILL type. Use .zero or .space instead.");
+ return; // Early returning here shouldn't harm. EmitZeros should work on any
+ // section.
+ }
+
+ PushSection();
+ SwitchSection(Section);
+
+ // The symbol may not be present, which only creates the section.
+ if (Symbol) {
+ EmitValueToAlignment(ByteAlignment, 0, 1, 0);
+ EmitLabel(Symbol);
+ EmitZeros(Size);
+ }
+ PopSection();
+}
+
+// This should always be called with the thread local bss section. Like the
+// .zerofill directive this doesn't actually switch sections on us.
+void MCMachOStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ EmitZerofill(Section, Symbol, Size, ByteAlignment);
+}
+
+void MCMachOStreamer::EmitInstToData(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+
+ SmallVector<MCFixup, 4> Fixups;
+ SmallString<256> Code;
+ raw_svector_ostream VecOS(Code);
+ getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
+
+ // Add the fixups and data.
+ for (MCFixup &Fixup : Fixups) {
+ Fixup.setOffset(Fixup.getOffset() + DF->getContents().size());
+ DF->getFixups().push_back(Fixup);
+ }
+ DF->setHasInstructions(STI);
+ DF->getContents().append(Code.begin(), Code.end());
+}
+
+void MCMachOStreamer::FinishImpl() {
+ EmitFrames(&getAssembler().getBackend());
+
+ // We have to set the fragment atom associations so we can relax properly for
+ // Mach-O.
+
+ // First, scan the symbol table to build a lookup table from fragments to
+ // defining symbols.
+ DenseMap<const MCFragment *, const MCSymbol *> DefiningSymbolMap;
+ for (const MCSymbol &Symbol : getAssembler().symbols()) {
+ if (getAssembler().isSymbolLinkerVisible(Symbol) && Symbol.isInSection() &&
+ !Symbol.isVariable()) {
+ // An atom defining symbol should never be internal to a fragment.
+ assert(Symbol.getOffset() == 0 &&
+ "Invalid offset in atom defining symbol!");
+ DefiningSymbolMap[Symbol.getFragment()] = &Symbol;
+ }
+ }
+
+ // Set the fragment atom associations by tracking the last seen atom defining
+ // symbol.
+ for (MCSection &Sec : getAssembler()) {
+ const MCSymbol *CurrentAtom = nullptr;
+ for (MCFragment &Frag : Sec) {
+ if (const MCSymbol *Symbol = DefiningSymbolMap.lookup(&Frag))
+ CurrentAtom = Symbol;
+ Frag.setAtom(CurrentAtom);
+ }
+ }
+
+ this->MCObjectStreamer::FinishImpl();
+}
+
+MCStreamer *llvm::createMachOStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> &&MAB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ bool RelaxAll, bool DWARFMustBeAtTheEnd,
+ bool LabelSections) {
+ MCMachOStreamer *S =
+ new MCMachOStreamer(Context, std::move(MAB), std::move(OW), std::move(CE),
+ DWARFMustBeAtTheEnd, LabelSections);
+ const Triple &Target = Context.getObjectFileInfo()->getTargetTriple();
+ S->EmitVersionForTarget(Target, Context.getObjectFileInfo()->getSDKVersion());
+ if (RelaxAll)
+ S->getAssembler().setRelaxAll(true);
+ return S;
+}
diff --git a/llvm/lib/MC/MCMachObjectTargetWriter.cpp b/llvm/lib/MC/MCMachObjectTargetWriter.cpp
new file mode 100644
index 000000000000..a57b8a7ac0ff
--- /dev/null
+++ b/llvm/lib/MC/MCMachObjectTargetWriter.cpp
@@ -0,0 +1,18 @@
+//===- MCMachObjectTargetWriter.cpp - Mach-O Target Writer Subclass -------===//
+//
+// 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/MCMachObjectWriter.h"
+
+using namespace llvm;
+
+MCMachObjectTargetWriter::MCMachObjectTargetWriter(bool Is64Bit_,
+ uint32_t CPUType_,
+ uint32_t CPUSubtype_)
+ : Is64Bit(Is64Bit_), CPUType(CPUType_), CPUSubtype(CPUSubtype_) {}
+
+MCMachObjectTargetWriter::~MCMachObjectTargetWriter() = default;
diff --git a/llvm/lib/MC/MCNullStreamer.cpp b/llvm/lib/MC/MCNullStreamer.cpp
new file mode 100644
index 000000000000..8452317c8c6b
--- /dev/null
+++ b/llvm/lib/MC/MCNullStreamer.cpp
@@ -0,0 +1,49 @@
+//===- lib/MC/MCNullStreamer.cpp - Dummy Streamer Implementation ----------===//
+//
+// 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/ADT/StringRef.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+
+using namespace llvm;
+
+namespace {
+
+ class MCNullStreamer : public MCStreamer {
+ public:
+ MCNullStreamer(MCContext &Context) : MCStreamer(Context) {}
+
+ /// @name MCStreamer Interface
+ /// @{
+
+ bool hasRawTextSupport() const override { return true; }
+ void EmitRawTextImpl(StringRef String) override {}
+
+ bool EmitSymbolAttribute(MCSymbol *Symbol,
+ MCSymbolAttr Attribute) override {
+ return true;
+ }
+
+ void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) override {}
+ void EmitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
+ uint64_t Size = 0, unsigned ByteAlignment = 0,
+ SMLoc Loc = SMLoc()) override {}
+ void EmitGPRel32Value(const MCExpr *Value) override {}
+ void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+ void EmitCOFFSymbolStorageClass(int StorageClass) override {}
+ void EmitCOFFSymbolType(int Type) override {}
+ void EndCOFFSymbolDef() override {}
+ };
+
+}
+
+MCStreamer *llvm::createNullStreamer(MCContext &Context) {
+ return new MCNullStreamer(Context);
+}
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
new file mode 100644
index 000000000000..70c0409ece7a
--- /dev/null
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -0,0 +1,873 @@
+//===-- MCObjectFileInfo.cpp - Object File Information --------------------===//
+//
+// 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/MCObjectFileInfo.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCSectionELF.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCSectionXCOFF.h"
+
+using namespace llvm;
+
+static bool useCompactUnwind(const Triple &T) {
+ // Only on darwin.
+ if (!T.isOSDarwin())
+ return false;
+
+ // aarch64 always has it.
+ if (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32)
+ return true;
+
+ // armv7k always has it.
+ if (T.isWatchABI())
+ return true;
+
+ // Use it on newer version of OS X.
+ if (T.isMacOSX() && !T.isMacOSXVersionLT(10, 6))
+ return true;
+
+ // And the iOS simulator.
+ if (T.isiOS() &&
+ (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86))
+ return true;
+
+ return false;
+}
+
+void MCObjectFileInfo::initMachOMCObjectFileInfo(const Triple &T) {
+ // MachO
+ SupportsWeakOmittedEHFrame = false;
+
+ EHFrameSection = Ctx->getMachOSection(
+ "__TEXT", "__eh_frame",
+ MachO::S_COALESCED | MachO::S_ATTR_NO_TOC |
+ MachO::S_ATTR_STRIP_STATIC_SYMS | MachO::S_ATTR_LIVE_SUPPORT,
+ SectionKind::getReadOnly());
+
+ if (T.isOSDarwin() &&
+ (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32))
+ SupportsCompactUnwindWithoutEHFrame = true;
+
+ if (T.isWatchABI())
+ OmitDwarfIfHaveCompactUnwind = true;
+
+ FDECFIEncoding = dwarf::DW_EH_PE_pcrel;
+
+ // .comm doesn't support alignment before Leopard.
+ if (T.isMacOSX() && T.isMacOSXVersionLT(10, 5))
+ CommDirectiveSupportsAlignment = false;
+
+ TextSection // .text
+ = Ctx->getMachOSection("__TEXT", "__text",
+ MachO::S_ATTR_PURE_INSTRUCTIONS,
+ SectionKind::getText());
+ DataSection // .data
+ = Ctx->getMachOSection("__DATA", "__data", 0, SectionKind::getData());
+
+ // BSSSection might not be expected initialized on msvc.
+ BSSSection = nullptr;
+
+ TLSDataSection // .tdata
+ = Ctx->getMachOSection("__DATA", "__thread_data",
+ MachO::S_THREAD_LOCAL_REGULAR,
+ SectionKind::getData());
+ TLSBSSSection // .tbss
+ = Ctx->getMachOSection("__DATA", "__thread_bss",
+ MachO::S_THREAD_LOCAL_ZEROFILL,
+ SectionKind::getThreadBSS());
+
+ // TODO: Verify datarel below.
+ TLSTLVSection // .tlv
+ = Ctx->getMachOSection("__DATA", "__thread_vars",
+ MachO::S_THREAD_LOCAL_VARIABLES,
+ SectionKind::getData());
+
+ TLSThreadInitSection = Ctx->getMachOSection(
+ "__DATA", "__thread_init", MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS,
+ SectionKind::getData());
+
+ CStringSection // .cstring
+ = Ctx->getMachOSection("__TEXT", "__cstring",
+ MachO::S_CSTRING_LITERALS,
+ SectionKind::getMergeable1ByteCString());
+ UStringSection
+ = Ctx->getMachOSection("__TEXT","__ustring", 0,
+ SectionKind::getMergeable2ByteCString());
+ FourByteConstantSection // .literal4
+ = Ctx->getMachOSection("__TEXT", "__literal4",
+ MachO::S_4BYTE_LITERALS,
+ SectionKind::getMergeableConst4());
+ EightByteConstantSection // .literal8
+ = Ctx->getMachOSection("__TEXT", "__literal8",
+ MachO::S_8BYTE_LITERALS,
+ SectionKind::getMergeableConst8());
+
+ SixteenByteConstantSection // .literal16
+ = Ctx->getMachOSection("__TEXT", "__literal16",
+ MachO::S_16BYTE_LITERALS,
+ SectionKind::getMergeableConst16());
+
+ ReadOnlySection // .const
+ = Ctx->getMachOSection("__TEXT", "__const", 0,
+ SectionKind::getReadOnly());
+
+ // If the target is not powerpc, map the coal sections to the non-coal
+ // sections.
+ //
+ // "__TEXT/__textcoal_nt" => section "__TEXT/__text"
+ // "__TEXT/__const_coal" => section "__TEXT/__const"
+ // "__DATA/__datacoal_nt" => section "__DATA/__data"
+ Triple::ArchType ArchTy = T.getArch();
+
+ ConstDataSection // .const_data
+ = Ctx->getMachOSection("__DATA", "__const", 0,
+ SectionKind::getReadOnlyWithRel());
+
+ if (ArchTy == Triple::ppc || ArchTy == Triple::ppc64) {
+ TextCoalSection
+ = Ctx->getMachOSection("__TEXT", "__textcoal_nt",
+ MachO::S_COALESCED |
+ MachO::S_ATTR_PURE_INSTRUCTIONS,
+ SectionKind::getText());
+ ConstTextCoalSection
+ = Ctx->getMachOSection("__TEXT", "__const_coal",
+ MachO::S_COALESCED,
+ SectionKind::getReadOnly());
+ DataCoalSection = Ctx->getMachOSection(
+ "__DATA", "__datacoal_nt", MachO::S_COALESCED, SectionKind::getData());
+ ConstDataCoalSection = DataCoalSection;
+ } else {
+ TextCoalSection = TextSection;
+ ConstTextCoalSection = ReadOnlySection;
+ DataCoalSection = DataSection;
+ ConstDataCoalSection = ConstDataSection;
+ }
+
+ DataCommonSection
+ = Ctx->getMachOSection("__DATA","__common",
+ MachO::S_ZEROFILL,
+ SectionKind::getBSS());
+ DataBSSSection
+ = Ctx->getMachOSection("__DATA","__bss", MachO::S_ZEROFILL,
+ SectionKind::getBSS());
+
+
+ LazySymbolPointerSection
+ = Ctx->getMachOSection("__DATA", "__la_symbol_ptr",
+ MachO::S_LAZY_SYMBOL_POINTERS,
+ SectionKind::getMetadata());
+ NonLazySymbolPointerSection
+ = Ctx->getMachOSection("__DATA", "__nl_symbol_ptr",
+ MachO::S_NON_LAZY_SYMBOL_POINTERS,
+ SectionKind::getMetadata());
+
+ ThreadLocalPointerSection
+ = Ctx->getMachOSection("__DATA", "__thread_ptr",
+ MachO::S_THREAD_LOCAL_VARIABLE_POINTERS,
+ SectionKind::getMetadata());
+
+ // Exception Handling.
+ LSDASection = Ctx->getMachOSection("__TEXT", "__gcc_except_tab", 0,
+ SectionKind::getReadOnlyWithRel());
+
+ COFFDebugSymbolsSection = nullptr;
+ COFFDebugTypesSection = nullptr;
+ COFFGlobalTypeHashesSection = nullptr;
+
+ if (useCompactUnwind(T)) {
+ CompactUnwindSection =
+ Ctx->getMachOSection("__LD", "__compact_unwind", MachO::S_ATTR_DEBUG,
+ SectionKind::getReadOnly());
+
+ if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86)
+ CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_X86_64_MODE_DWARF
+ else if (T.getArch() == Triple::aarch64 || T.getArch() == Triple::aarch64_32)
+ CompactUnwindDwarfEHFrameOnly = 0x03000000; // UNWIND_ARM64_MODE_DWARF
+ else if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
+ CompactUnwindDwarfEHFrameOnly = 0x04000000; // UNWIND_ARM_MODE_DWARF
+ }
+
+ // Debug Information.
+ DwarfDebugNamesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_names", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "debug_names_begin");
+ DwarfAccelNamesSection =
+ Ctx->getMachOSection("__DWARF", "__apple_names", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "names_begin");
+ DwarfAccelObjCSection =
+ Ctx->getMachOSection("__DWARF", "__apple_objc", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "objc_begin");
+ // 16 character section limit...
+ DwarfAccelNamespaceSection =
+ Ctx->getMachOSection("__DWARF", "__apple_namespac", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "namespac_begin");
+ DwarfAccelTypesSection =
+ Ctx->getMachOSection("__DWARF", "__apple_types", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "types_begin");
+
+ DwarfSwiftASTSection =
+ Ctx->getMachOSection("__DWARF", "__swift_ast", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+
+ DwarfAbbrevSection =
+ Ctx->getMachOSection("__DWARF", "__debug_abbrev", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_abbrev");
+ DwarfInfoSection =
+ Ctx->getMachOSection("__DWARF", "__debug_info", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_info");
+ DwarfLineSection =
+ Ctx->getMachOSection("__DWARF", "__debug_line", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_line");
+ DwarfLineStrSection =
+ Ctx->getMachOSection("__DWARF", "__debug_line_str", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_line_str");
+ DwarfFrameSection =
+ Ctx->getMachOSection("__DWARF", "__debug_frame", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfPubNamesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_pubnames", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfPubTypesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_pubtypes", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfGnuPubNamesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_gnu_pubn", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfGnuPubTypesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_gnu_pubt", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfStrSection =
+ Ctx->getMachOSection("__DWARF", "__debug_str", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "info_string");
+ DwarfStrOffSection =
+ Ctx->getMachOSection("__DWARF", "__debug_str_offs", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_str_off");
+ DwarfAddrSection =
+ Ctx->getMachOSection("__DWARF", "__debug_addr", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_info");
+ DwarfLocSection =
+ Ctx->getMachOSection("__DWARF", "__debug_loc", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_debug_loc");
+ DwarfLoclistsSection =
+ Ctx->getMachOSection("__DWARF", "__debug_loclists", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "section_debug_loc");
+
+ DwarfARangesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_aranges", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfRangesSection =
+ Ctx->getMachOSection("__DWARF", "__debug_ranges", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "debug_range");
+ DwarfRnglistsSection =
+ Ctx->getMachOSection("__DWARF", "__debug_rnglists", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "debug_range");
+ DwarfMacinfoSection =
+ Ctx->getMachOSection("__DWARF", "__debug_macinfo", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata(), "debug_macinfo");
+ DwarfDebugInlineSection =
+ Ctx->getMachOSection("__DWARF", "__debug_inlined", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfCUIndexSection =
+ Ctx->getMachOSection("__DWARF", "__debug_cu_index", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ DwarfTUIndexSection =
+ Ctx->getMachOSection("__DWARF", "__debug_tu_index", MachO::S_ATTR_DEBUG,
+ SectionKind::getMetadata());
+ StackMapSection = Ctx->getMachOSection("__LLVM_STACKMAPS", "__llvm_stackmaps",
+ 0, SectionKind::getMetadata());
+
+ FaultMapSection = Ctx->getMachOSection("__LLVM_FAULTMAPS", "__llvm_faultmaps",
+ 0, SectionKind::getMetadata());
+
+ RemarksSection = Ctx->getMachOSection(
+ "__LLVM", "__remarks", MachO::S_ATTR_DEBUG, SectionKind::getMetadata());
+
+ TLSExtraDataSection = TLSTLVSection;
+}
+
+void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
+ switch (T.getArch()) {
+ case Triple::mips:
+ case Triple::mipsel:
+ case Triple::mips64:
+ case Triple::mips64el:
+ FDECFIEncoding = Ctx->getAsmInfo()->getCodePointerSize() == 4
+ ? dwarf::DW_EH_PE_sdata4
+ : dwarf::DW_EH_PE_sdata8;
+ break;
+ case Triple::ppc64:
+ case Triple::ppc64le:
+ case Triple::x86_64:
+ FDECFIEncoding = dwarf::DW_EH_PE_pcrel |
+ (Large ? dwarf::DW_EH_PE_sdata8 : dwarf::DW_EH_PE_sdata4);
+ break;
+ case Triple::bpfel:
+ case Triple::bpfeb:
+ FDECFIEncoding = dwarf::DW_EH_PE_sdata8;
+ break;
+ case Triple::hexagon:
+ FDECFIEncoding =
+ PositionIndependent ? dwarf::DW_EH_PE_pcrel : dwarf::DW_EH_PE_absptr;
+ break;
+ default:
+ FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
+ break;
+ }
+
+ unsigned EHSectionType = T.getArch() == Triple::x86_64
+ ? ELF::SHT_X86_64_UNWIND
+ : ELF::SHT_PROGBITS;
+
+ // Solaris requires different flags for .eh_frame to seemingly every other
+ // platform.
+ unsigned EHSectionFlags = ELF::SHF_ALLOC;
+ if (T.isOSSolaris() && T.getArch() != Triple::x86_64)
+ EHSectionFlags |= ELF::SHF_WRITE;
+
+ // ELF
+ BSSSection = Ctx->getELFSection(".bss", ELF::SHT_NOBITS,
+ ELF::SHF_WRITE | ELF::SHF_ALLOC);
+
+ TextSection = Ctx->getELFSection(".text", ELF::SHT_PROGBITS,
+ ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
+
+ DataSection = Ctx->getELFSection(".data", ELF::SHT_PROGBITS,
+ ELF::SHF_WRITE | ELF::SHF_ALLOC);
+
+ ReadOnlySection =
+ Ctx->getELFSection(".rodata", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+
+ TLSDataSection =
+ Ctx->getELFSection(".tdata", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_TLS | ELF::SHF_WRITE);
+
+ TLSBSSSection = Ctx->getELFSection(
+ ".tbss", ELF::SHT_NOBITS, ELF::SHF_ALLOC | ELF::SHF_TLS | ELF::SHF_WRITE);
+
+ DataRelROSection = Ctx->getELFSection(".data.rel.ro", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_WRITE);
+
+ MergeableConst4Section =
+ Ctx->getELFSection(".rodata.cst4", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_MERGE, 4, "");
+
+ MergeableConst8Section =
+ Ctx->getELFSection(".rodata.cst8", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_MERGE, 8, "");
+
+ MergeableConst16Section =
+ Ctx->getELFSection(".rodata.cst16", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_MERGE, 16, "");
+
+ MergeableConst32Section =
+ Ctx->getELFSection(".rodata.cst32", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_MERGE, 32, "");
+
+ // Exception Handling Sections.
+
+ // FIXME: We're emitting LSDA info into a readonly section on ELF, even though
+ // it contains relocatable pointers. In PIC mode, this is probably a big
+ // runtime hit for C++ apps. Either the contents of the LSDA need to be
+ // adjusted or this should be a data section.
+ LSDASection = Ctx->getELFSection(".gcc_except_table", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC);
+
+ COFFDebugSymbolsSection = nullptr;
+ COFFDebugTypesSection = nullptr;
+
+ unsigned DebugSecType = ELF::SHT_PROGBITS;
+
+ // MIPS .debug_* sections should have SHT_MIPS_DWARF section type
+ // to distinguish among sections contain DWARF and ECOFF debug formats.
+ // Sections with ECOFF debug format are obsoleted and marked by SHT_PROGBITS.
+ if (T.isMIPS())
+ DebugSecType = ELF::SHT_MIPS_DWARF;
+
+ // Debug Info Sections.
+ DwarfAbbrevSection =
+ Ctx->getELFSection(".debug_abbrev", DebugSecType, 0);
+ DwarfInfoSection = Ctx->getELFSection(".debug_info", DebugSecType, 0);
+ DwarfLineSection = Ctx->getELFSection(".debug_line", DebugSecType, 0);
+ DwarfLineStrSection =
+ Ctx->getELFSection(".debug_line_str", DebugSecType,
+ ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, "");
+ DwarfFrameSection = Ctx->getELFSection(".debug_frame", DebugSecType, 0);
+ DwarfPubNamesSection =
+ Ctx->getELFSection(".debug_pubnames", DebugSecType, 0);
+ DwarfPubTypesSection =
+ Ctx->getELFSection(".debug_pubtypes", DebugSecType, 0);
+ DwarfGnuPubNamesSection =
+ Ctx->getELFSection(".debug_gnu_pubnames", DebugSecType, 0);
+ DwarfGnuPubTypesSection =
+ Ctx->getELFSection(".debug_gnu_pubtypes", DebugSecType, 0);
+ DwarfStrSection =
+ Ctx->getELFSection(".debug_str", DebugSecType,
+ ELF::SHF_MERGE | ELF::SHF_STRINGS, 1, "");
+ DwarfLocSection = Ctx->getELFSection(".debug_loc", DebugSecType, 0);
+ DwarfARangesSection =
+ Ctx->getELFSection(".debug_aranges", DebugSecType, 0);
+ DwarfRangesSection =
+ Ctx->getELFSection(".debug_ranges", DebugSecType, 0);
+ DwarfMacinfoSection =
+ Ctx->getELFSection(".debug_macinfo", DebugSecType, 0);
+
+ // DWARF5 Experimental Debug Info
+
+ // Accelerator Tables
+ DwarfDebugNamesSection =
+ Ctx->getELFSection(".debug_names", ELF::SHT_PROGBITS, 0);
+ DwarfAccelNamesSection =
+ Ctx->getELFSection(".apple_names", ELF::SHT_PROGBITS, 0);
+ DwarfAccelObjCSection =
+ Ctx->getELFSection(".apple_objc", ELF::SHT_PROGBITS, 0);
+ DwarfAccelNamespaceSection =
+ Ctx->getELFSection(".apple_namespaces", ELF::SHT_PROGBITS, 0);
+ DwarfAccelTypesSection =
+ Ctx->getELFSection(".apple_types", ELF::SHT_PROGBITS, 0);
+
+ // String Offset and Address Sections
+ DwarfStrOffSection =
+ Ctx->getELFSection(".debug_str_offsets", DebugSecType, 0);
+ DwarfAddrSection = Ctx->getELFSection(".debug_addr", DebugSecType, 0);
+ DwarfRnglistsSection = Ctx->getELFSection(".debug_rnglists", DebugSecType, 0);
+ DwarfLoclistsSection = Ctx->getELFSection(".debug_loclists", DebugSecType, 0);
+
+ // Fission Sections
+ DwarfInfoDWOSection =
+ Ctx->getELFSection(".debug_info.dwo", DebugSecType, ELF::SHF_EXCLUDE);
+ DwarfTypesDWOSection =
+ Ctx->getELFSection(".debug_types.dwo", DebugSecType, ELF::SHF_EXCLUDE);
+ DwarfAbbrevDWOSection =
+ Ctx->getELFSection(".debug_abbrev.dwo", DebugSecType, ELF::SHF_EXCLUDE);
+ DwarfStrDWOSection = Ctx->getELFSection(
+ ".debug_str.dwo", DebugSecType,
+ ELF::SHF_MERGE | ELF::SHF_STRINGS | ELF::SHF_EXCLUDE, 1, "");
+ DwarfLineDWOSection =
+ Ctx->getELFSection(".debug_line.dwo", DebugSecType, ELF::SHF_EXCLUDE);
+ DwarfLocDWOSection =
+ Ctx->getELFSection(".debug_loc.dwo", DebugSecType, ELF::SHF_EXCLUDE);
+ DwarfStrOffDWOSection = Ctx->getELFSection(".debug_str_offsets.dwo",
+ DebugSecType, ELF::SHF_EXCLUDE);
+ DwarfRnglistsDWOSection =
+ Ctx->getELFSection(".debug_rnglists.dwo", DebugSecType, ELF::SHF_EXCLUDE);
+
+ // DWP Sections
+ DwarfCUIndexSection =
+ Ctx->getELFSection(".debug_cu_index", DebugSecType, 0);
+ DwarfTUIndexSection =
+ Ctx->getELFSection(".debug_tu_index", DebugSecType, 0);
+
+ StackMapSection =
+ Ctx->getELFSection(".llvm_stackmaps", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+
+ FaultMapSection =
+ Ctx->getELFSection(".llvm_faultmaps", ELF::SHT_PROGBITS, ELF::SHF_ALLOC);
+
+ EHFrameSection =
+ Ctx->getELFSection(".eh_frame", EHSectionType, EHSectionFlags);
+
+ StackSizesSection = Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, 0);
+
+ RemarksSection =
+ Ctx->getELFSection(".remarks", ELF::SHT_PROGBITS, ELF::SHF_EXCLUDE);
+}
+
+void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) {
+ EHFrameSection =
+ Ctx->getCOFFSection(".eh_frame", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getData());
+
+ // Set the `IMAGE_SCN_MEM_16BIT` flag when compiling for thumb mode. This is
+ // used to indicate to the linker that the text segment contains thumb instructions
+ // and to set the ISA selection bit for calls accordingly.
+ const bool IsThumb = T.getArch() == Triple::thumb;
+
+ CommDirectiveSupportsAlignment = true;
+
+ // COFF
+ BSSSection = Ctx->getCOFFSection(
+ ".bss", COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ | COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getBSS());
+ TextSection = Ctx->getCOFFSection(
+ ".text",
+ (IsThumb ? COFF::IMAGE_SCN_MEM_16BIT : (COFF::SectionCharacteristics)0) |
+ COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getText());
+ DataSection = Ctx->getCOFFSection(
+ ".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ |
+ COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getData());
+ ReadOnlySection = Ctx->getCOFFSection(
+ ".rdata", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getReadOnly());
+
+ if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::aarch64) {
+ // On Windows 64 with SEH, the LSDA is emitted into the .xdata section
+ LSDASection = nullptr;
+ } else {
+ LSDASection = Ctx->getCOFFSection(".gcc_except_table",
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getReadOnly());
+ }
+
+ // Debug info.
+ COFFDebugSymbolsSection =
+ Ctx->getCOFFSection(".debug$S", (COFF::IMAGE_SCN_MEM_DISCARDABLE |
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ),
+ SectionKind::getMetadata());
+ COFFDebugTypesSection =
+ Ctx->getCOFFSection(".debug$T", (COFF::IMAGE_SCN_MEM_DISCARDABLE |
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ),
+ SectionKind::getMetadata());
+ COFFGlobalTypeHashesSection = Ctx->getCOFFSection(
+ ".debug$H",
+ (COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ),
+ SectionKind::getMetadata());
+
+ DwarfAbbrevSection = Ctx->getCOFFSection(
+ ".debug_abbrev",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_abbrev");
+ DwarfInfoSection = Ctx->getCOFFSection(
+ ".debug_info",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_info");
+ DwarfLineSection = Ctx->getCOFFSection(
+ ".debug_line",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_line");
+ DwarfLineStrSection = Ctx->getCOFFSection(
+ ".debug_line_str",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_line_str");
+ DwarfFrameSection = Ctx->getCOFFSection(
+ ".debug_frame",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfPubNamesSection = Ctx->getCOFFSection(
+ ".debug_pubnames",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfPubTypesSection = Ctx->getCOFFSection(
+ ".debug_pubtypes",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfGnuPubNamesSection = Ctx->getCOFFSection(
+ ".debug_gnu_pubnames",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfGnuPubTypesSection = Ctx->getCOFFSection(
+ ".debug_gnu_pubtypes",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfStrSection = Ctx->getCOFFSection(
+ ".debug_str",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "info_string");
+ DwarfStrOffSection = Ctx->getCOFFSection(
+ ".debug_str_offsets",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_str_off");
+ DwarfLocSection = Ctx->getCOFFSection(
+ ".debug_loc",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_debug_loc");
+ DwarfARangesSection = Ctx->getCOFFSection(
+ ".debug_aranges",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfRangesSection = Ctx->getCOFFSection(
+ ".debug_ranges",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "debug_range");
+ DwarfMacinfoSection = Ctx->getCOFFSection(
+ ".debug_macinfo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "debug_macinfo");
+ DwarfInfoDWOSection = Ctx->getCOFFSection(
+ ".debug_info.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_info_dwo");
+ DwarfTypesDWOSection = Ctx->getCOFFSection(
+ ".debug_types.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_types_dwo");
+ DwarfAbbrevDWOSection = Ctx->getCOFFSection(
+ ".debug_abbrev.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_abbrev_dwo");
+ DwarfStrDWOSection = Ctx->getCOFFSection(
+ ".debug_str.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "skel_string");
+ DwarfLineDWOSection = Ctx->getCOFFSection(
+ ".debug_line.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfLocDWOSection = Ctx->getCOFFSection(
+ ".debug_loc.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "skel_loc");
+ DwarfStrOffDWOSection = Ctx->getCOFFSection(
+ ".debug_str_offsets.dwo",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "section_str_off_dwo");
+ DwarfAddrSection = Ctx->getCOFFSection(
+ ".debug_addr",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "addr_sec");
+ DwarfCUIndexSection = Ctx->getCOFFSection(
+ ".debug_cu_index",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfTUIndexSection = Ctx->getCOFFSection(
+ ".debug_tu_index",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+ DwarfDebugNamesSection = Ctx->getCOFFSection(
+ ".debug_names",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "debug_names_begin");
+ DwarfAccelNamesSection = Ctx->getCOFFSection(
+ ".apple_names",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "names_begin");
+ DwarfAccelNamespaceSection = Ctx->getCOFFSection(
+ ".apple_namespaces",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "namespac_begin");
+ DwarfAccelTypesSection = Ctx->getCOFFSection(
+ ".apple_types",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "types_begin");
+ DwarfAccelObjCSection = Ctx->getCOFFSection(
+ ".apple_objc",
+ COFF::IMAGE_SCN_MEM_DISCARDABLE | COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata(), "objc_begin");
+
+ DrectveSection = Ctx->getCOFFSection(
+ ".drectve", COFF::IMAGE_SCN_LNK_INFO | COFF::IMAGE_SCN_LNK_REMOVE,
+ SectionKind::getMetadata());
+
+ PDataSection = Ctx->getCOFFSection(
+ ".pdata", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getData());
+
+ XDataSection = Ctx->getCOFFSection(
+ ".xdata", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getData());
+
+ SXDataSection = Ctx->getCOFFSection(".sxdata", COFF::IMAGE_SCN_LNK_INFO,
+ SectionKind::getMetadata());
+
+ GFIDsSection = Ctx->getCOFFSection(".gfids$y",
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getMetadata());
+
+ TLSDataSection = Ctx->getCOFFSection(
+ ".tls$", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | COFF::IMAGE_SCN_MEM_READ |
+ COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getData());
+
+ StackMapSection = Ctx->getCOFFSection(".llvm_stackmaps",
+ COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getReadOnly());
+}
+
+void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
+ TextSection = Ctx->getWasmSection(".text", SectionKind::getText());
+ DataSection = Ctx->getWasmSection(".data", SectionKind::getData());
+
+ DwarfLineSection =
+ Ctx->getWasmSection(".debug_line", SectionKind::getMetadata());
+ DwarfLineStrSection =
+ Ctx->getWasmSection(".debug_line_str", SectionKind::getMetadata());
+ DwarfStrSection =
+ Ctx->getWasmSection(".debug_str", SectionKind::getMetadata());
+ DwarfLocSection =
+ Ctx->getWasmSection(".debug_loc", SectionKind::getMetadata());
+ DwarfAbbrevSection =
+ Ctx->getWasmSection(".debug_abbrev", SectionKind::getMetadata());
+ DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", SectionKind::getMetadata());
+ DwarfRangesSection =
+ Ctx->getWasmSection(".debug_ranges", SectionKind::getMetadata());
+ DwarfMacinfoSection =
+ Ctx->getWasmSection(".debug_macinfo", SectionKind::getMetadata());
+ DwarfAddrSection = Ctx->getWasmSection(".debug_addr", SectionKind::getMetadata());
+ DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", SectionKind::getMetadata());
+ DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", SectionKind::getMetadata());
+ DwarfInfoSection =
+ Ctx->getWasmSection(".debug_info", SectionKind::getMetadata());
+ DwarfFrameSection = Ctx->getWasmSection(".debug_frame", SectionKind::getMetadata());
+ DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", SectionKind::getMetadata());
+ DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", SectionKind::getMetadata());
+
+ // Wasm use data section for LSDA.
+ // TODO Consider putting each function's exception table in a separate
+ // section, as in -function-sections, to facilitate lld's --gc-section.
+ LSDASection = Ctx->getWasmSection(".rodata.gcc_except_table",
+ SectionKind::getReadOnlyWithRel());
+
+ // TODO: Define more sections.
+}
+
+void MCObjectFileInfo::initXCOFFMCObjectFileInfo(const Triple &T) {
+ // The default csect for program code. Functions without a specified section
+ // get placed into this csect. The choice of csect name is not a property of
+ // the ABI or object file format. For example, the XL compiler uses an unnamed
+ // csect for program code.
+ TextSection = Ctx->getXCOFFSection(
+ ".text", XCOFF::StorageMappingClass::XMC_PR, XCOFF::XTY_SD,
+ XCOFF::C_HIDEXT, SectionKind::getText());
+
+ DataSection = Ctx->getXCOFFSection(
+ ".data", XCOFF::StorageMappingClass::XMC_RW, XCOFF::XTY_SD,
+ XCOFF::C_HIDEXT, SectionKind::getData());
+}
+
+void MCObjectFileInfo::InitMCObjectFileInfo(const Triple &TheTriple, bool PIC,
+ MCContext &ctx,
+ bool LargeCodeModel) {
+ PositionIndependent = PIC;
+ Ctx = &ctx;
+
+ // Common.
+ CommDirectiveSupportsAlignment = true;
+ SupportsWeakOmittedEHFrame = true;
+ SupportsCompactUnwindWithoutEHFrame = false;
+ OmitDwarfIfHaveCompactUnwind = false;
+
+ FDECFIEncoding = dwarf::DW_EH_PE_absptr;
+
+ CompactUnwindDwarfEHFrameOnly = 0;
+
+ EHFrameSection = nullptr; // Created on demand.
+ CompactUnwindSection = nullptr; // Used only by selected targets.
+ DwarfAccelNamesSection = nullptr; // Used only by selected targets.
+ DwarfAccelObjCSection = nullptr; // Used only by selected targets.
+ DwarfAccelNamespaceSection = nullptr; // Used only by selected targets.
+ DwarfAccelTypesSection = nullptr; // Used only by selected targets.
+
+ TT = TheTriple;
+
+ switch (TT.getObjectFormat()) {
+ case Triple::MachO:
+ Env = IsMachO;
+ initMachOMCObjectFileInfo(TT);
+ break;
+ case Triple::COFF:
+ if (!TT.isOSWindows())
+ report_fatal_error(
+ "Cannot initialize MC for non-Windows COFF object files.");
+
+ Env = IsCOFF;
+ initCOFFMCObjectFileInfo(TT);
+ break;
+ case Triple::ELF:
+ Env = IsELF;
+ initELFMCObjectFileInfo(TT, LargeCodeModel);
+ break;
+ case Triple::Wasm:
+ Env = IsWasm;
+ initWasmMCObjectFileInfo(TT);
+ break;
+ case Triple::XCOFF:
+ Env = IsXCOFF;
+ initXCOFFMCObjectFileInfo(TT);
+ break;
+ case Triple::UnknownObjectFormat:
+ report_fatal_error("Cannot initialize MC for unknown object file format.");
+ break;
+ }
+}
+
+MCSection *MCObjectFileInfo::getDwarfComdatSection(const char *Name,
+ uint64_t Hash) const {
+ switch (TT.getObjectFormat()) {
+ case Triple::ELF:
+ return Ctx->getELFSection(Name, ELF::SHT_PROGBITS, ELF::SHF_GROUP, 0,
+ utostr(Hash));
+ case Triple::MachO:
+ case Triple::COFF:
+ case Triple::Wasm:
+ case Triple::XCOFF:
+ case Triple::UnknownObjectFormat:
+ report_fatal_error("Cannot get DWARF comdat section for this object file "
+ "format: not implemented.");
+ break;
+ }
+ llvm_unreachable("Unknown ObjectFormatType");
+}
+
+MCSection *
+MCObjectFileInfo::getStackSizesSection(const MCSection &TextSec) const {
+ if (Env != IsELF)
+ return StackSizesSection;
+
+ const MCSectionELF &ElfSec = static_cast<const MCSectionELF &>(TextSec);
+ unsigned Flags = ELF::SHF_LINK_ORDER;
+ StringRef GroupName;
+ if (const MCSymbol *Group = ElfSec.getGroup()) {
+ GroupName = Group->getName();
+ Flags |= ELF::SHF_GROUP;
+ }
+
+ const MCSymbol *Link = TextSec.getBeginSymbol();
+ auto It = StackSizesUniquing.insert({Link, StackSizesUniquing.size()});
+ unsigned UniqueID = It.first->second;
+
+ return Ctx->getELFSection(".stack_sizes", ELF::SHT_PROGBITS, Flags, 0,
+ GroupName, UniqueID, cast<MCSymbolELF>(Link));
+}
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
new file mode 100644
index 000000000000..83f6ab8fe332
--- /dev/null
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -0,0 +1,731 @@
+//===- 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/ADT/STLExtras.h"
+#include "llvm/MC/MCAsmBackend.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/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSymbol.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) {}
+
+MCObjectStreamer::~MCObjectStreamer() {}
+
+// 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::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
+ if (PendingLabels.empty())
+ return;
+ if (!F) {
+ F = new MCDataFragment();
+ MCSection *CurSection = getCurrentSectionOnly();
+ CurSection->getFragmentList().insert(CurInsertionPoint, F);
+ F->setParent(CurSection);
+ }
+ for (MCSymbol *Sym : PendingLabels) {
+ Sym->setFragment(F);
+ Sym->setOffset(FOffset);
+ }
+ PendingLabels.clear();
+}
+
+// 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.DF->getFixups().push_back(PendingFixup.Fixup);
+ }
+ 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 Optional<uint64_t>
+absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) {
+ assert(Hi && Lo);
+ if (Asm.getBackendPtr()->requiresDiffExpressionRelocations())
+ return None;
+
+ if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
+ Hi->isVariable() || Lo->isVariable())
+ return None;
+
+ return Hi->getOffset() - Lo->getOffset();
+}
+
+void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
+ const MCSymbol *Lo,
+ unsigned Size) {
+ if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
+ EmitIntValue(*Diff, Size);
+ return;
+ }
+ MCStreamer::emitAbsoluteSymbolDiff(Hi, Lo, Size);
+}
+
+void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
+ const MCSymbol *Lo) {
+ if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), 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();
+ 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;
+}
+
+MCPaddingFragment *MCObjectStreamer::getOrCreatePaddingFragment() {
+ MCPaddingFragment *F =
+ dyn_cast_or_null<MCPaddingFragment>(getCurrentFragment());
+ if (!F) {
+ F = new MCPaddingFragment();
+ 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", true);
+ 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 {
+ PendingLabels.push_back(Symbol);
+ }
+}
+
+void MCObjectStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc, MCFragment *F) {
+ MCStreamer::EmitLabel(Symbol, Loc);
+ getAssembler().registerSymbol(*Symbol);
+ auto *DF = dyn_cast_or_null<MCDataFragment>(F);
+ if (DF)
+ Symbol->setFragment(F);
+ else
+ PendingLabels.push_back(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!");
+ flushPendingLabels(nullptr);
+ 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");
+ CurInsertionPoint =
+ Section->getSubsectionInsertionPoint(unsigned(IntSubsection));
+ return Created;
+}
+
+void MCObjectStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ getAssembler().registerSymbol(*Symbol);
+ MCStreamer::EmitAssignment(Symbol, Value);
+}
+
+bool MCObjectStreamer::mayHaveInstructions(MCSection &Sec) const {
+ return Sec.hasInstructions();
+}
+
+void MCObjectStreamer::EmitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ getAssembler().getBackend().handleCodePaddingInstructionBegin(Inst);
+ EmitInstructionImpl(Inst, STI);
+ getAssembler().getBackend().handleCodePaddingInstructionEnd(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();
+ if (!Assembler.getBackend().mayNeedRelaxation(Inst, STI)) {
+ 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;
+ getAssembler().getBackend().relaxInstruction(Inst, STI, Relaxed);
+ while (getAssembler().getBackend().mayNeedRelaxation(Relaxed, STI))
+ getAssembler().getBackend().relaxInstruction(Relaxed, STI, Relaxed);
+ 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(unsigned AlignPow2) {
+ 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::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());
+
+ // EmitBytes might not cover all possible ways we emit data (or could be used
+ // to emit executable code in some cases), but is the best method we have
+ // right now for checking this.
+ MCSection *Sec = getCurrentSectionOnly();
+ Sec->setHasData(true);
+}
+
+void MCObjectStreamer::EmitValueToAlignment(unsigned ByteAlignment,
+ int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ if (MaxBytesToEmit == 0)
+ MaxBytesToEmit = ByteAlignment;
+ insert(new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit));
+
+ // Update the maximum alignment on the current section if necessary.
+ MCSection *CurSec = getCurrentSectionOnly();
+ if (ByteAlignment > CurSec->getAlignment())
+ CurSec->setAlignment(Align(ByteAlignment));
+}
+
+void MCObjectStreamer::EmitCodeAlignment(unsigned ByteAlignment,
+ unsigned MaxBytesToEmit) {
+ EmitValueToAlignment(ByteAlignment, 0, 1, MaxBytesToEmit);
+ cast<MCAlignFragment>(getCurrentFragment())->setEmitNops(true);
+}
+
+void MCObjectStreamer::emitValueToOffset(const MCExpr *Offset,
+ unsigned char Value,
+ SMLoc Loc) {
+ insert(new MCOrgFragment(*Offset, Value, Loc));
+}
+
+void MCObjectStreamer::EmitCodePaddingBasicBlockStart(
+ const MCCodePaddingContext &Context) {
+ getAssembler().getBackend().handleCodePaddingBasicBlockStart(this, Context);
+}
+
+void MCObjectStreamer::EmitCodePaddingBasicBlockEnd(
+ const MCCodePaddingContext &Context) {
+ getAssembler().getBackend().handleCodePaddingBasicBlockEnd(Context);
+}
+
+// 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);
+}
+
+bool MCObjectStreamer::EmitRelocDirective(const MCExpr &Offset, StringRef Name,
+ const MCExpr *Expr, SMLoc Loc,
+ const MCSubtargetInfo &STI) {
+ Optional<MCFixupKind> MaybeKind = Assembler->getBackend().getFixupKind(Name);
+ if (!MaybeKind.hasValue())
+ return true;
+
+ MCFixupKind Kind = *MaybeKind;
+
+ if (Expr == nullptr)
+ Expr =
+ MCSymbolRefExpr::create(getContext().createTempSymbol(), getContext());
+
+ MCDataFragment *DF = getOrCreateDataFragment(&STI);
+ flushPendingLabels(DF, DF->getContents().size());
+
+ int64_t OffsetValue;
+ if (Offset.evaluateAsAbsolute(OffsetValue)) {
+ if (OffsetValue < 0)
+ llvm_unreachable(".reloc offset is negative");
+ DF->getFixups().push_back(MCFixup::create(OffsetValue, Expr, Kind, Loc));
+ return false;
+ }
+
+ if (Offset.getKind() != llvm::MCExpr::SymbolRef)
+ llvm_unreachable(".reloc offset is not absolute nor a label");
+
+ const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(Offset);
+ if (SRE.getSymbol().isDefined()) {
+ DF->getFixups().push_back(MCFixup::create(SRE.getSymbol().getOffset(),
+ Expr, Kind, Loc));
+ return false;
+ }
+
+ PendingFixups.emplace_back(&SRE.getSymbol(), DF,
+ MCFixup::create(-1, Expr, Kind, Loc));
+ return false;
+}
+
+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::EmitFileDirective(StringRef Filename) {
+ getAssembler().addFileName(Filename);
+}
+
+void MCObjectStreamer::EmitAddrsig() {
+ getAssembler().getWriter().emitAddrsigSection();
+}
+
+void MCObjectStreamer::EmitAddrsigSym(const MCSymbol *Sym) {
+ getAssembler().registerSymbol(*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());
+
+ flushPendingLabels();
+ resolvePendingFixups();
+ getAssembler().Finish();
+}
diff --git a/llvm/lib/MC/MCObjectWriter.cpp b/llvm/lib/MC/MCObjectWriter.cpp
new file mode 100644
index 000000000000..a058bbe0ba0b
--- /dev/null
+++ b/llvm/lib/MC/MCObjectWriter.cpp
@@ -0,0 +1,52 @@
+//===- lib/MC/MCObjectWriter.cpp - MCObjectWriter implementation ----------===//
+//
+// 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/MCObjectWriter.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCSymbol.h"
+
+using namespace llvm;
+
+MCObjectWriter::~MCObjectWriter() = default;
+
+bool MCObjectWriter::isSymbolRefDifferenceFullyResolved(
+ const MCAssembler &Asm, const MCSymbolRefExpr *A, const MCSymbolRefExpr *B,
+ bool InSet) const {
+ // Modified symbol references cannot be resolved.
+ if (A->getKind() != MCSymbolRefExpr::VK_None ||
+ B->getKind() != MCSymbolRefExpr::VK_None)
+ return false;
+
+ const MCSymbol &SA = A->getSymbol();
+ const MCSymbol &SB = B->getSymbol();
+ if (SA.isUndefined() || SB.isUndefined())
+ return false;
+
+ if (!SA.getFragment() || !SB.getFragment())
+ return false;
+
+ return isSymbolRefDifferenceFullyResolvedImpl(Asm, SA, SB, InSet);
+}
+
+bool MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &A, const MCSymbol &B,
+ bool InSet) const {
+ return isSymbolRefDifferenceFullyResolvedImpl(Asm, A, *B.getFragment(), InSet,
+ false);
+}
+
+bool MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB,
+ bool InSet, bool IsPCRel) const {
+ const MCSection &SecA = SymA.getSection();
+ const MCSection &SecB = *FB.getParent();
+ // On ELF and COFF A - B is absolute if A and B are in the same section.
+ return &SecA == &SecB;
+}
diff --git a/llvm/lib/MC/MCParser/AsmLexer.cpp b/llvm/lib/MC/MCParser/AsmLexer.cpp
new file mode 100644
index 000000000000..9155ae05d29d
--- /dev/null
+++ b/llvm/lib/MC/MCParser/AsmLexer.cpp
@@ -0,0 +1,755 @@
+//===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===//
+//
+// 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 class implements the lexer for assembly files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCParser/AsmLexer.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SaveAndRestore.h"
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include <tuple>
+#include <utility>
+
+using namespace llvm;
+
+AsmLexer::AsmLexer(const MCAsmInfo &MAI) : MAI(MAI) {
+ AllowAtInIdentifier = !StringRef(MAI.getCommentString()).startswith("@");
+}
+
+AsmLexer::~AsmLexer() = default;
+
+void AsmLexer::setBuffer(StringRef Buf, const char *ptr) {
+ CurBuf = Buf;
+
+ if (ptr)
+ CurPtr = ptr;
+ else
+ CurPtr = CurBuf.begin();
+
+ TokStart = nullptr;
+}
+
+/// ReturnError - Set the error to the specified string at the specified
+/// location. This is defined to always return AsmToken::Error.
+AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) {
+ SetError(SMLoc::getFromPointer(Loc), Msg);
+
+ return AsmToken(AsmToken::Error, StringRef(Loc, CurPtr - Loc));
+}
+
+int AsmLexer::getNextChar() {
+ if (CurPtr == CurBuf.end())
+ return EOF;
+ return (unsigned char)*CurPtr++;
+}
+
+/// The leading integral digit sequence and dot should have already been
+/// consumed, some or all of the fractional digit sequence *can* have been
+/// consumed.
+AsmToken AsmLexer::LexFloatLiteral() {
+ // Skip the fractional digit sequence.
+ while (isDigit(*CurPtr))
+ ++CurPtr;
+
+ if (*CurPtr == '-' || *CurPtr == '+')
+ return ReturnError(CurPtr, "Invalid sign in float literal");
+
+ // Check for exponent
+ if ((*CurPtr == 'e' || *CurPtr == 'E')) {
+ ++CurPtr;
+
+ if (*CurPtr == '-' || *CurPtr == '+')
+ ++CurPtr;
+
+ while (isDigit(*CurPtr))
+ ++CurPtr;
+ }
+
+ return AsmToken(AsmToken::Real,
+ StringRef(TokStart, CurPtr - TokStart));
+}
+
+/// LexHexFloatLiteral matches essentially (.[0-9a-fA-F]*)?[pP][+-]?[0-9a-fA-F]+
+/// while making sure there are enough actual digits around for the constant to
+/// be valid.
+///
+/// The leading "0x[0-9a-fA-F]*" (i.e. integer part) has already been consumed
+/// before we get here.
+AsmToken AsmLexer::LexHexFloatLiteral(bool NoIntDigits) {
+ assert((*CurPtr == 'p' || *CurPtr == 'P' || *CurPtr == '.') &&
+ "unexpected parse state in floating hex");
+ bool NoFracDigits = true;
+
+ // Skip the fractional part if there is one
+ if (*CurPtr == '.') {
+ ++CurPtr;
+
+ const char *FracStart = CurPtr;
+ while (isHexDigit(*CurPtr))
+ ++CurPtr;
+
+ NoFracDigits = CurPtr == FracStart;
+ }
+
+ if (NoIntDigits && NoFracDigits)
+ return ReturnError(TokStart, "invalid hexadecimal floating-point constant: "
+ "expected at least one significand digit");
+
+ // Make sure we do have some kind of proper exponent part
+ if (*CurPtr != 'p' && *CurPtr != 'P')
+ return ReturnError(TokStart, "invalid hexadecimal floating-point constant: "
+ "expected exponent part 'p'");
+ ++CurPtr;
+
+ if (*CurPtr == '+' || *CurPtr == '-')
+ ++CurPtr;
+
+ // N.b. exponent digits are *not* hex
+ const char *ExpStart = CurPtr;
+ while (isDigit(*CurPtr))
+ ++CurPtr;
+
+ if (CurPtr == ExpStart)
+ return ReturnError(TokStart, "invalid hexadecimal floating-point constant: "
+ "expected at least one exponent digit");
+
+ return AsmToken(AsmToken::Real, StringRef(TokStart, CurPtr - TokStart));
+}
+
+/// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@?]*
+static bool IsIdentifierChar(char c, bool AllowAt) {
+ return isAlnum(c) || c == '_' || c == '$' || c == '.' ||
+ (c == '@' && AllowAt) || c == '?';
+}
+
+AsmToken AsmLexer::LexIdentifier() {
+ // Check for floating point literals.
+ if (CurPtr[-1] == '.' && isDigit(*CurPtr)) {
+ // Disambiguate a .1243foo identifier from a floating literal.
+ while (isDigit(*CurPtr))
+ ++CurPtr;
+
+ if (!IsIdentifierChar(*CurPtr, AllowAtInIdentifier) ||
+ *CurPtr == 'e' || *CurPtr == 'E')
+ return LexFloatLiteral();
+ }
+
+ while (IsIdentifierChar(*CurPtr, AllowAtInIdentifier))
+ ++CurPtr;
+
+ // Handle . as a special case.
+ if (CurPtr == TokStart+1 && TokStart[0] == '.')
+ return AsmToken(AsmToken::Dot, StringRef(TokStart, 1));
+
+ return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart));
+}
+
+/// LexSlash: Slash: /
+/// C-Style Comment: /* ... */
+AsmToken AsmLexer::LexSlash() {
+ switch (*CurPtr) {
+ case '*':
+ IsAtStartOfStatement = false;
+ break; // C style comment.
+ case '/':
+ ++CurPtr;
+ return LexLineComment();
+ default:
+ IsAtStartOfStatement = false;
+ return AsmToken(AsmToken::Slash, StringRef(TokStart, 1));
+ }
+
+ // C Style comment.
+ ++CurPtr; // skip the star.
+ const char *CommentTextStart = CurPtr;
+ while (CurPtr != CurBuf.end()) {
+ switch (*CurPtr++) {
+ case '*':
+ // End of the comment?
+ if (*CurPtr != '/')
+ break;
+ // If we have a CommentConsumer, notify it about the comment.
+ if (CommentConsumer) {
+ CommentConsumer->HandleComment(
+ SMLoc::getFromPointer(CommentTextStart),
+ StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart));
+ }
+ ++CurPtr; // End the */.
+ return AsmToken(AsmToken::Comment,
+ StringRef(TokStart, CurPtr - TokStart));
+ }
+ }
+ return ReturnError(TokStart, "unterminated comment");
+}
+
+/// LexLineComment: Comment: #[^\n]*
+/// : //[^\n]*
+AsmToken AsmLexer::LexLineComment() {
+ // Mark This as an end of statement with a body of the
+ // comment. While it would be nicer to leave this two tokens,
+ // backwards compatability with TargetParsers makes keeping this in this form
+ // better.
+ const char *CommentTextStart = CurPtr;
+ int CurChar = getNextChar();
+ while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF)
+ CurChar = getNextChar();
+ if (CurChar == '\r' && CurPtr != CurBuf.end() && *CurPtr == '\n')
+ ++CurPtr;
+
+ // If we have a CommentConsumer, notify it about the comment.
+ if (CommentConsumer) {
+ CommentConsumer->HandleComment(
+ SMLoc::getFromPointer(CommentTextStart),
+ StringRef(CommentTextStart, CurPtr - 1 - CommentTextStart));
+ }
+
+ IsAtStartOfLine = true;
+ // This is a whole line comment. leave newline
+ if (IsAtStartOfStatement)
+ return AsmToken(AsmToken::EndOfStatement,
+ StringRef(TokStart, CurPtr - TokStart));
+ IsAtStartOfStatement = true;
+
+ return AsmToken(AsmToken::EndOfStatement,
+ StringRef(TokStart, CurPtr - 1 - TokStart));
+}
+
+static void SkipIgnoredIntegerSuffix(const char *&CurPtr) {
+ // Skip ULL, UL, U, L and LL suffices.
+ if (CurPtr[0] == 'U')
+ ++CurPtr;
+ if (CurPtr[0] == 'L')
+ ++CurPtr;
+ if (CurPtr[0] == 'L')
+ ++CurPtr;
+}
+
+// Look ahead to search for first non-hex digit, if it's [hH], then we treat the
+// integer as a hexadecimal, possibly with leading zeroes.
+static unsigned doHexLookAhead(const char *&CurPtr, unsigned DefaultRadix,
+ bool LexHex) {
+ const char *FirstNonDec = nullptr;
+ const char *LookAhead = CurPtr;
+ while (true) {
+ if (isDigit(*LookAhead)) {
+ ++LookAhead;
+ } else {
+ if (!FirstNonDec)
+ FirstNonDec = LookAhead;
+
+ // Keep going if we are looking for a 'h' suffix.
+ if (LexHex && isHexDigit(*LookAhead))
+ ++LookAhead;
+ else
+ break;
+ }
+ }
+ bool isHex = LexHex && (*LookAhead == 'h' || *LookAhead == 'H');
+ CurPtr = isHex || !FirstNonDec ? LookAhead : FirstNonDec;
+ if (isHex)
+ return 16;
+ return DefaultRadix;
+}
+
+static AsmToken intToken(StringRef Ref, APInt &Value)
+{
+ if (Value.isIntN(64))
+ return AsmToken(AsmToken::Integer, Ref, Value);
+ return AsmToken(AsmToken::BigNum, Ref, Value);
+}
+
+/// LexDigit: First character is [0-9].
+/// Local Label: [0-9][:]
+/// Forward/Backward Label: [0-9][fb]
+/// Binary integer: 0b[01]+
+/// Octal integer: 0[0-7]+
+/// Hex integer: 0x[0-9a-fA-F]+ or [0x]?[0-9][0-9a-fA-F]*[hH]
+/// Decimal integer: [1-9][0-9]*
+AsmToken AsmLexer::LexDigit() {
+ // MASM-flavor binary integer: [01]+[bB]
+ // MASM-flavor hexadecimal integer: [0-9][0-9a-fA-F]*[hH]
+ if (LexMasmIntegers && isdigit(CurPtr[-1])) {
+ const char *FirstNonBinary = (CurPtr[-1] != '0' && CurPtr[-1] != '1') ?
+ CurPtr - 1 : nullptr;
+ const char *OldCurPtr = CurPtr;
+ while (isHexDigit(*CurPtr)) {
+ if (*CurPtr != '0' && *CurPtr != '1' && !FirstNonBinary)
+ FirstNonBinary = CurPtr;
+ ++CurPtr;
+ }
+
+ unsigned Radix = 0;
+ if (*CurPtr == 'h' || *CurPtr == 'H') {
+ // hexadecimal number
+ ++CurPtr;
+ Radix = 16;
+ } else if (FirstNonBinary && FirstNonBinary + 1 == CurPtr &&
+ (*FirstNonBinary == 'b' || *FirstNonBinary == 'B'))
+ Radix = 2;
+
+ if (Radix == 2 || Radix == 16) {
+ StringRef Result(TokStart, CurPtr - TokStart);
+ APInt Value(128, 0, true);
+
+ if (Result.drop_back().getAsInteger(Radix, Value))
+ return ReturnError(TokStart, Radix == 2 ? "invalid binary number" :
+ "invalid hexdecimal number");
+
+ // MSVC accepts and ignores type suffices on integer literals.
+ SkipIgnoredIntegerSuffix(CurPtr);
+
+ return intToken(Result, Value);
+ }
+
+ // octal/decimal integers, or floating point numbers, fall through
+ CurPtr = OldCurPtr;
+ }
+
+ // Decimal integer: [1-9][0-9]*
+ if (CurPtr[-1] != '0' || CurPtr[0] == '.') {
+ unsigned Radix = doHexLookAhead(CurPtr, 10, LexMasmIntegers);
+ bool isHex = Radix == 16;
+ // Check for floating point literals.
+ if (!isHex && (*CurPtr == '.' || *CurPtr == 'e' || *CurPtr == 'E')) {
+ if (*CurPtr == '.')
+ ++CurPtr;
+ return LexFloatLiteral();
+ }
+
+ StringRef Result(TokStart, CurPtr - TokStart);
+
+ APInt Value(128, 0, true);
+ if (Result.getAsInteger(Radix, Value))
+ return ReturnError(TokStart, !isHex ? "invalid decimal number" :
+ "invalid hexdecimal number");
+
+ // Consume the [hH].
+ if (LexMasmIntegers && Radix == 16)
+ ++CurPtr;
+
+ // The darwin/x86 (and x86-64) assembler accepts and ignores type
+ // suffices on integer literals.
+ SkipIgnoredIntegerSuffix(CurPtr);
+
+ return intToken(Result, Value);
+ }
+
+ if (!LexMasmIntegers && ((*CurPtr == 'b') || (*CurPtr == 'B'))) {
+ ++CurPtr;
+ // See if we actually have "0b" as part of something like "jmp 0b\n"
+ if (!isDigit(CurPtr[0])) {
+ --CurPtr;
+ StringRef Result(TokStart, CurPtr - TokStart);
+ return AsmToken(AsmToken::Integer, Result, 0);
+ }
+ const char *NumStart = CurPtr;
+ while (CurPtr[0] == '0' || CurPtr[0] == '1')
+ ++CurPtr;
+
+ // Requires at least one binary digit.
+ if (CurPtr == NumStart)
+ return ReturnError(TokStart, "invalid binary number");
+
+ StringRef Result(TokStart, CurPtr - TokStart);
+
+ APInt Value(128, 0, true);
+ if (Result.substr(2).getAsInteger(2, Value))
+ return ReturnError(TokStart, "invalid binary number");
+
+ // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL
+ // suffixes on integer literals.
+ SkipIgnoredIntegerSuffix(CurPtr);
+
+ return intToken(Result, Value);
+ }
+
+ if ((*CurPtr == 'x') || (*CurPtr == 'X')) {
+ ++CurPtr;
+ const char *NumStart = CurPtr;
+ while (isHexDigit(CurPtr[0]))
+ ++CurPtr;
+
+ // "0x.0p0" is valid, and "0x0p0" (but not "0xp0" for example, which will be
+ // diagnosed by LexHexFloatLiteral).
+ if (CurPtr[0] == '.' || CurPtr[0] == 'p' || CurPtr[0] == 'P')
+ return LexHexFloatLiteral(NumStart == CurPtr);
+
+ // Otherwise requires at least one hex digit.
+ if (CurPtr == NumStart)
+ return ReturnError(CurPtr-2, "invalid hexadecimal number");
+
+ APInt Result(128, 0);
+ if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result))
+ return ReturnError(TokStart, "invalid hexadecimal number");
+
+ // Consume the optional [hH].
+ if (LexMasmIntegers && (*CurPtr == 'h' || *CurPtr == 'H'))
+ ++CurPtr;
+
+ // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL
+ // suffixes on integer literals.
+ SkipIgnoredIntegerSuffix(CurPtr);
+
+ return intToken(StringRef(TokStart, CurPtr - TokStart), Result);
+ }
+
+ // Either octal or hexadecimal.
+ APInt Value(128, 0, true);
+ unsigned Radix = doHexLookAhead(CurPtr, 8, LexMasmIntegers);
+ bool isHex = Radix == 16;
+ StringRef Result(TokStart, CurPtr - TokStart);
+ if (Result.getAsInteger(Radix, Value))
+ return ReturnError(TokStart, !isHex ? "invalid octal number" :
+ "invalid hexdecimal number");
+
+ // Consume the [hH].
+ if (Radix == 16)
+ ++CurPtr;
+
+ // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL
+ // suffixes on integer literals.
+ SkipIgnoredIntegerSuffix(CurPtr);
+
+ return intToken(Result, Value);
+}
+
+/// LexSingleQuote: Integer: 'b'
+AsmToken AsmLexer::LexSingleQuote() {
+ int CurChar = getNextChar();
+
+ if (CurChar == '\\')
+ CurChar = getNextChar();
+
+ if (CurChar == EOF)
+ return ReturnError(TokStart, "unterminated single quote");
+
+ CurChar = getNextChar();
+
+ if (CurChar != '\'')
+ return ReturnError(TokStart, "single quote way too long");
+
+ // The idea here being that 'c' is basically just an integral
+ // constant.
+ StringRef Res = StringRef(TokStart,CurPtr - TokStart);
+ long long Value;
+
+ if (Res.startswith("\'\\")) {
+ char theChar = Res[2];
+ switch (theChar) {
+ default: Value = theChar; break;
+ case '\'': Value = '\''; break;
+ case 't': Value = '\t'; break;
+ case 'n': Value = '\n'; break;
+ case 'b': Value = '\b'; break;
+ }
+ } else
+ Value = TokStart[1];
+
+ return AsmToken(AsmToken::Integer, Res, Value);
+}
+
+/// LexQuote: String: "..."
+AsmToken AsmLexer::LexQuote() {
+ int CurChar = getNextChar();
+ // TODO: does gas allow multiline string constants?
+ while (CurChar != '"') {
+ if (CurChar == '\\') {
+ // Allow \", etc.
+ CurChar = getNextChar();
+ }
+
+ if (CurChar == EOF)
+ return ReturnError(TokStart, "unterminated string constant");
+
+ CurChar = getNextChar();
+ }
+
+ return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart));
+}
+
+StringRef AsmLexer::LexUntilEndOfStatement() {
+ TokStart = CurPtr;
+
+ while (!isAtStartOfComment(CurPtr) && // Start of line comment.
+ !isAtStatementSeparator(CurPtr) && // End of statement marker.
+ *CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) {
+ ++CurPtr;
+ }
+ return StringRef(TokStart, CurPtr-TokStart);
+}
+
+StringRef AsmLexer::LexUntilEndOfLine() {
+ TokStart = CurPtr;
+
+ while (*CurPtr != '\n' && *CurPtr != '\r' && CurPtr != CurBuf.end()) {
+ ++CurPtr;
+ }
+ return StringRef(TokStart, CurPtr-TokStart);
+}
+
+size_t AsmLexer::peekTokens(MutableArrayRef<AsmToken> Buf,
+ bool ShouldSkipSpace) {
+ SaveAndRestore<const char *> SavedTokenStart(TokStart);
+ SaveAndRestore<const char *> SavedCurPtr(CurPtr);
+ SaveAndRestore<bool> SavedAtStartOfLine(IsAtStartOfLine);
+ SaveAndRestore<bool> SavedAtStartOfStatement(IsAtStartOfStatement);
+ SaveAndRestore<bool> SavedSkipSpace(SkipSpace, ShouldSkipSpace);
+ SaveAndRestore<bool> SavedIsPeeking(IsPeeking, true);
+ std::string SavedErr = getErr();
+ SMLoc SavedErrLoc = getErrLoc();
+
+ size_t ReadCount;
+ for (ReadCount = 0; ReadCount < Buf.size(); ++ReadCount) {
+ AsmToken Token = LexToken();
+
+ Buf[ReadCount] = Token;
+
+ if (Token.is(AsmToken::Eof))
+ break;
+ }
+
+ SetError(SavedErrLoc, SavedErr);
+ return ReadCount;
+}
+
+bool AsmLexer::isAtStartOfComment(const char *Ptr) {
+ StringRef CommentString = MAI.getCommentString();
+
+ if (CommentString.size() == 1)
+ return CommentString[0] == Ptr[0];
+
+ // Allow # preprocessor commments also be counted as comments for "##" cases
+ if (CommentString[1] == '#')
+ return CommentString[0] == Ptr[0];
+
+ return strncmp(Ptr, CommentString.data(), CommentString.size()) == 0;
+}
+
+bool AsmLexer::isAtStatementSeparator(const char *Ptr) {
+ return strncmp(Ptr, MAI.getSeparatorString(),
+ strlen(MAI.getSeparatorString())) == 0;
+}
+
+AsmToken AsmLexer::LexToken() {
+ TokStart = CurPtr;
+ // This always consumes at least one character.
+ int CurChar = getNextChar();
+
+ if (!IsPeeking && CurChar == '#' && IsAtStartOfStatement) {
+ // If this starts with a '#', this may be a cpp
+ // hash directive and otherwise a line comment.
+ AsmToken TokenBuf[2];
+ MutableArrayRef<AsmToken> Buf(TokenBuf, 2);
+ size_t num = peekTokens(Buf, true);
+ // There cannot be a space preceding this
+ if (IsAtStartOfLine && num == 2 && TokenBuf[0].is(AsmToken::Integer) &&
+ TokenBuf[1].is(AsmToken::String)) {
+ CurPtr = TokStart; // reset curPtr;
+ StringRef s = LexUntilEndOfLine();
+ UnLex(TokenBuf[1]);
+ UnLex(TokenBuf[0]);
+ return AsmToken(AsmToken::HashDirective, s);
+ }
+ return LexLineComment();
+ }
+
+ if (isAtStartOfComment(TokStart))
+ return LexLineComment();
+
+ if (isAtStatementSeparator(TokStart)) {
+ CurPtr += strlen(MAI.getSeparatorString()) - 1;
+ IsAtStartOfLine = true;
+ IsAtStartOfStatement = true;
+ return AsmToken(AsmToken::EndOfStatement,
+ StringRef(TokStart, strlen(MAI.getSeparatorString())));
+ }
+
+ // If we're missing a newline at EOF, make sure we still get an
+ // EndOfStatement token before the Eof token.
+ if (CurChar == EOF && !IsAtStartOfStatement) {
+ IsAtStartOfLine = true;
+ IsAtStartOfStatement = true;
+ return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
+ }
+ IsAtStartOfLine = false;
+ bool OldIsAtStartOfStatement = IsAtStartOfStatement;
+ IsAtStartOfStatement = false;
+ switch (CurChar) {
+ default:
+ // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]*
+ if (isalpha(CurChar) || CurChar == '_' || CurChar == '.')
+ return LexIdentifier();
+
+ // Unknown character, emit an error.
+ return ReturnError(TokStart, "invalid character in input");
+ case EOF:
+ IsAtStartOfLine = true;
+ IsAtStartOfStatement = true;
+ return AsmToken(AsmToken::Eof, StringRef(TokStart, 0));
+ case 0:
+ case ' ':
+ case '\t':
+ IsAtStartOfStatement = OldIsAtStartOfStatement;
+ while (*CurPtr == ' ' || *CurPtr == '\t')
+ CurPtr++;
+ if (SkipSpace)
+ return LexToken(); // Ignore whitespace.
+ else
+ return AsmToken(AsmToken::Space, StringRef(TokStart, CurPtr - TokStart));
+ case '\r': {
+ IsAtStartOfLine = true;
+ IsAtStartOfStatement = true;
+ // If this is a CR followed by LF, treat that as one token.
+ if (CurPtr != CurBuf.end() && *CurPtr == '\n')
+ ++CurPtr;
+ return AsmToken(AsmToken::EndOfStatement,
+ StringRef(TokStart, CurPtr - TokStart));
+ }
+ case '\n':
+ IsAtStartOfLine = true;
+ IsAtStartOfStatement = true;
+ return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1));
+ case ':': return AsmToken(AsmToken::Colon, StringRef(TokStart, 1));
+ case '+': return AsmToken(AsmToken::Plus, StringRef(TokStart, 1));
+ case '~': return AsmToken(AsmToken::Tilde, StringRef(TokStart, 1));
+ case '(': return AsmToken(AsmToken::LParen, StringRef(TokStart, 1));
+ case ')': return AsmToken(AsmToken::RParen, StringRef(TokStart, 1));
+ case '[': return AsmToken(AsmToken::LBrac, StringRef(TokStart, 1));
+ case ']': return AsmToken(AsmToken::RBrac, StringRef(TokStart, 1));
+ case '{': return AsmToken(AsmToken::LCurly, StringRef(TokStart, 1));
+ case '}': return AsmToken(AsmToken::RCurly, StringRef(TokStart, 1));
+ case '*': return AsmToken(AsmToken::Star, StringRef(TokStart, 1));
+ case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1));
+ case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1));
+ case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1));
+ case '\\': return AsmToken(AsmToken::BackSlash, StringRef(TokStart, 1));
+ case '=':
+ if (*CurPtr == '=') {
+ ++CurPtr;
+ return AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2));
+ }
+ return AsmToken(AsmToken::Equal, StringRef(TokStart, 1));
+ case '-':
+ if (*CurPtr == '>') {
+ ++CurPtr;
+ return AsmToken(AsmToken::MinusGreater, StringRef(TokStart, 2));
+ }
+ return AsmToken(AsmToken::Minus, StringRef(TokStart, 1));
+ case '|':
+ if (*CurPtr == '|') {
+ ++CurPtr;
+ return AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2));
+ }
+ return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1));
+ case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1));
+ case '&':
+ if (*CurPtr == '&') {
+ ++CurPtr;
+ return AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2));
+ }
+ return AsmToken(AsmToken::Amp, StringRef(TokStart, 1));
+ case '!':
+ if (*CurPtr == '=') {
+ ++CurPtr;
+ return AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2));
+ }
+ return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1));
+ case '%':
+ if (MAI.hasMipsExpressions()) {
+ AsmToken::TokenKind Operator;
+ unsigned OperatorLength;
+
+ std::tie(Operator, OperatorLength) =
+ StringSwitch<std::pair<AsmToken::TokenKind, unsigned>>(
+ StringRef(CurPtr))
+ .StartsWith("call16", {AsmToken::PercentCall16, 7})
+ .StartsWith("call_hi", {AsmToken::PercentCall_Hi, 8})
+ .StartsWith("call_lo", {AsmToken::PercentCall_Lo, 8})
+ .StartsWith("dtprel_hi", {AsmToken::PercentDtprel_Hi, 10})
+ .StartsWith("dtprel_lo", {AsmToken::PercentDtprel_Lo, 10})
+ .StartsWith("got_disp", {AsmToken::PercentGot_Disp, 9})
+ .StartsWith("got_hi", {AsmToken::PercentGot_Hi, 7})
+ .StartsWith("got_lo", {AsmToken::PercentGot_Lo, 7})
+ .StartsWith("got_ofst", {AsmToken::PercentGot_Ofst, 9})
+ .StartsWith("got_page", {AsmToken::PercentGot_Page, 9})
+ .StartsWith("gottprel", {AsmToken::PercentGottprel, 9})
+ .StartsWith("got", {AsmToken::PercentGot, 4})
+ .StartsWith("gp_rel", {AsmToken::PercentGp_Rel, 7})
+ .StartsWith("higher", {AsmToken::PercentHigher, 7})
+ .StartsWith("highest", {AsmToken::PercentHighest, 8})
+ .StartsWith("hi", {AsmToken::PercentHi, 3})
+ .StartsWith("lo", {AsmToken::PercentLo, 3})
+ .StartsWith("neg", {AsmToken::PercentNeg, 4})
+ .StartsWith("pcrel_hi", {AsmToken::PercentPcrel_Hi, 9})
+ .StartsWith("pcrel_lo", {AsmToken::PercentPcrel_Lo, 9})
+ .StartsWith("tlsgd", {AsmToken::PercentTlsgd, 6})
+ .StartsWith("tlsldm", {AsmToken::PercentTlsldm, 7})
+ .StartsWith("tprel_hi", {AsmToken::PercentTprel_Hi, 9})
+ .StartsWith("tprel_lo", {AsmToken::PercentTprel_Lo, 9})
+ .Default({AsmToken::Percent, 1});
+
+ if (Operator != AsmToken::Percent) {
+ CurPtr += OperatorLength - 1;
+ return AsmToken(Operator, StringRef(TokStart, OperatorLength));
+ }
+ }
+ return AsmToken(AsmToken::Percent, StringRef(TokStart, 1));
+ case '/':
+ IsAtStartOfStatement = OldIsAtStartOfStatement;
+ return LexSlash();
+ case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1));
+ case '\'': return LexSingleQuote();
+ case '"': return LexQuote();
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ return LexDigit();
+ case '<':
+ switch (*CurPtr) {
+ case '<':
+ ++CurPtr;
+ return AsmToken(AsmToken::LessLess, StringRef(TokStart, 2));
+ case '=':
+ ++CurPtr;
+ return AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2));
+ case '>':
+ ++CurPtr;
+ return AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2));
+ default:
+ return AsmToken(AsmToken::Less, StringRef(TokStart, 1));
+ }
+ case '>':
+ switch (*CurPtr) {
+ case '>':
+ ++CurPtr;
+ return AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2));
+ case '=':
+ ++CurPtr;
+ return AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2));
+ default:
+ return AsmToken(AsmToken::Greater, StringRef(TokStart, 1));
+ }
+
+ // TODO: Quoted identifiers (objc methods etc)
+ // local labels: [0-9][:]
+ // Forward/backward labels: [0-9][fb]
+ // Integers, fp constants, character constants.
+ }
+}
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp
new file mode 100644
index 000000000000..b59ac08ad6cc
--- /dev/null
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -0,0 +1,6082 @@
+//===- AsmParser.cpp - Parser for Assembly Files --------------------------===//
+//
+// 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 class implements the parser for assembly files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/APFloat.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/AsmCond.h"
+#include "llvm/MC/MCParser/AsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCParser/MCAsmParserUtils.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MD5.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cctype>
+#include <climits>
+#include <cstddef>
+#include <cstdint>
+#include <deque>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+MCAsmParserSemaCallback::~MCAsmParserSemaCallback() = default;
+
+static cl::opt<unsigned> AsmMacroMaxNestingDepth(
+ "asm-macro-max-nesting-depth", cl::init(20), cl::Hidden,
+ cl::desc("The maximum nesting depth allowed for assembly macros."));
+
+namespace {
+
+/// Helper types for tracking macro definitions.
+typedef std::vector<AsmToken> MCAsmMacroArgument;
+typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments;
+
+/// Helper class for storing information about an active macro
+/// instantiation.
+struct MacroInstantiation {
+ /// The location of the instantiation.
+ SMLoc InstantiationLoc;
+
+ /// The buffer where parsing should resume upon instantiation completion.
+ int ExitBuffer;
+
+ /// The location where parsing should resume upon instantiation completion.
+ SMLoc ExitLoc;
+
+ /// The depth of TheCondStack at the start of the instantiation.
+ size_t CondStackDepth;
+
+public:
+ MacroInstantiation(SMLoc IL, int EB, SMLoc EL, size_t CondStackDepth);
+};
+
+struct ParseStatementInfo {
+ /// The parsed operands from the last parsed statement.
+ SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> ParsedOperands;
+
+ /// The opcode from the last parsed instruction.
+ unsigned Opcode = ~0U;
+
+ /// Was there an error parsing the inline assembly?
+ bool ParseError = false;
+
+ SmallVectorImpl<AsmRewrite> *AsmRewrites = nullptr;
+
+ ParseStatementInfo() = delete;
+ ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites)
+ : AsmRewrites(rewrites) {}
+};
+
+/// The concrete assembly parser instance.
+class AsmParser : public MCAsmParser {
+private:
+ AsmLexer Lexer;
+ MCContext &Ctx;
+ MCStreamer &Out;
+ const MCAsmInfo &MAI;
+ SourceMgr &SrcMgr;
+ SourceMgr::DiagHandlerTy SavedDiagHandler;
+ void *SavedDiagContext;
+ std::unique_ptr<MCAsmParserExtension> PlatformParser;
+
+ /// This is the current buffer index we're lexing from as managed by the
+ /// SourceMgr object.
+ unsigned CurBuffer;
+
+ AsmCond TheCondState;
+ std::vector<AsmCond> TheCondStack;
+
+ /// maps directive names to handler methods in parser
+ /// extensions. Extensions register themselves in this map by calling
+ /// addDirectiveHandler.
+ StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap;
+
+ /// Stack of active macro instantiations.
+ std::vector<MacroInstantiation*> ActiveMacros;
+
+ /// List of bodies of anonymous macros.
+ std::deque<MCAsmMacro> MacroLikeBodies;
+
+ /// Boolean tracking whether macro substitution is enabled.
+ unsigned MacrosEnabledFlag : 1;
+
+ /// Keeps track of how many .macro's have been instantiated.
+ unsigned NumOfMacroInstantiations;
+
+ /// The values from the last parsed cpp hash file line comment if any.
+ struct CppHashInfoTy {
+ StringRef Filename;
+ int64_t LineNumber;
+ SMLoc Loc;
+ unsigned Buf;
+ CppHashInfoTy() : Filename(), LineNumber(0), Loc(), Buf(0) {}
+ };
+ CppHashInfoTy CppHashInfo;
+
+ /// The filename from the first cpp hash file line comment, if any.
+ StringRef FirstCppHashFilename;
+
+ /// List of forward directional labels for diagnosis at the end.
+ SmallVector<std::tuple<SMLoc, CppHashInfoTy, MCSymbol *>, 4> DirLabels;
+
+ /// AssemblerDialect. ~OU means unset value and use value provided by MAI.
+ unsigned AssemblerDialect = ~0U;
+
+ /// is Darwin compatibility enabled?
+ bool IsDarwin = false;
+
+ /// Are we parsing ms-style inline assembly?
+ bool ParsingInlineAsm = false;
+
+ /// Did we already inform the user about inconsistent MD5 usage?
+ bool ReportedInconsistentMD5 = false;
+
+ // Is alt macro mode enabled.
+ bool AltMacroMode = false;
+
+public:
+ AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
+ const MCAsmInfo &MAI, unsigned CB);
+ AsmParser(const AsmParser &) = delete;
+ AsmParser &operator=(const AsmParser &) = delete;
+ ~AsmParser() override;
+
+ bool Run(bool NoInitialTextSection, bool NoFinalize = false) override;
+
+ void addDirectiveHandler(StringRef Directive,
+ ExtensionDirectiveHandler Handler) override {
+ ExtensionDirectiveMap[Directive] = Handler;
+ }
+
+ void addAliasForDirective(StringRef Directive, StringRef Alias) override {
+ DirectiveKindMap[Directive] = DirectiveKindMap[Alias];
+ }
+
+ /// @name MCAsmParser Interface
+ /// {
+
+ SourceMgr &getSourceManager() override { return SrcMgr; }
+ MCAsmLexer &getLexer() override { return Lexer; }
+ MCContext &getContext() override { return Ctx; }
+ MCStreamer &getStreamer() override { return Out; }
+
+ CodeViewContext &getCVContext() { return Ctx.getCVContext(); }
+
+ unsigned getAssemblerDialect() override {
+ if (AssemblerDialect == ~0U)
+ return MAI.getAssemblerDialect();
+ else
+ return AssemblerDialect;
+ }
+ void setAssemblerDialect(unsigned i) override {
+ AssemblerDialect = i;
+ }
+
+ void Note(SMLoc L, const Twine &Msg, SMRange Range = None) override;
+ bool Warning(SMLoc L, const Twine &Msg, SMRange Range = None) override;
+ bool printError(SMLoc L, const Twine &Msg, SMRange Range = None) override;
+
+ const AsmToken &Lex() override;
+
+ void setParsingInlineAsm(bool V) override {
+ ParsingInlineAsm = V;
+ // When parsing MS inline asm, we must lex 0b1101 and 0ABCH as binary and
+ // hex integer literals.
+ Lexer.setLexMasmIntegers(V);
+ }
+ bool isParsingInlineAsm() override { return ParsingInlineAsm; }
+
+ bool parseMSInlineAsm(void *AsmLoc, std::string &AsmString,
+ unsigned &NumOutputs, unsigned &NumInputs,
+ SmallVectorImpl<std::pair<void *,bool>> &OpDecls,
+ SmallVectorImpl<std::string> &Constraints,
+ SmallVectorImpl<std::string> &Clobbers,
+ const MCInstrInfo *MII, const MCInstPrinter *IP,
+ MCAsmParserSemaCallback &SI) override;
+
+ bool parseExpression(const MCExpr *&Res);
+ bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
+ bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) override;
+ bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) override;
+ bool parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,
+ SMLoc &EndLoc) override;
+ bool parseAbsoluteExpression(int64_t &Res) override;
+
+ /// Parse a floating point expression using the float \p Semantics
+ /// and set \p Res to the value.
+ bool parseRealValue(const fltSemantics &Semantics, APInt &Res);
+
+ /// Parse an identifier or string (as a quoted identifier)
+ /// and set \p Res to the identifier contents.
+ bool parseIdentifier(StringRef &Res) override;
+ void eatToEndOfStatement() override;
+
+ bool checkForValidSection() override;
+
+ /// }
+
+private:
+ bool parseStatement(ParseStatementInfo &Info,
+ MCAsmParserSemaCallback *SI);
+ bool parseCurlyBlockScope(SmallVectorImpl<AsmRewrite>& AsmStrRewrites);
+ bool parseCppHashLineFilenameComment(SMLoc L);
+
+ void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body,
+ ArrayRef<MCAsmMacroParameter> Parameters);
+ bool expandMacro(raw_svector_ostream &OS, StringRef Body,
+ ArrayRef<MCAsmMacroParameter> Parameters,
+ ArrayRef<MCAsmMacroArgument> A, bool EnableAtPseudoVariable,
+ SMLoc L);
+
+ /// Are macros enabled in the parser?
+ bool areMacrosEnabled() {return MacrosEnabledFlag;}
+
+ /// Control a flag in the parser that enables or disables macros.
+ void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;}
+
+ /// Are we inside a macro instantiation?
+ bool isInsideMacroInstantiation() {return !ActiveMacros.empty();}
+
+ /// Handle entry to macro instantiation.
+ ///
+ /// \param M The macro.
+ /// \param NameLoc Instantiation location.
+ bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc);
+
+ /// Handle exit from macro instantiation.
+ void handleMacroExit();
+
+ /// Extract AsmTokens for a macro argument.
+ bool parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg);
+
+ /// Parse all macro arguments for a given macro.
+ bool parseMacroArguments(const MCAsmMacro *M, MCAsmMacroArguments &A);
+
+ void printMacroInstantiations();
+ void printMessage(SMLoc Loc, SourceMgr::DiagKind Kind, const Twine &Msg,
+ SMRange Range = None) const {
+ ArrayRef<SMRange> Ranges(Range);
+ SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges);
+ }
+ static void DiagHandler(const SMDiagnostic &Diag, void *Context);
+
+ /// Should we emit DWARF describing this assembler source? (Returns false if
+ /// the source has .file directives, which means we don't want to generate
+ /// info describing the assembler source itself.)
+ bool enabledGenDwarfForAssembly();
+
+ /// Enter the specified file. This returns true on failure.
+ bool enterIncludeFile(const std::string &Filename);
+
+ /// Process the specified file for the .incbin directive.
+ /// This returns true on failure.
+ bool processIncbinFile(const std::string &Filename, int64_t Skip = 0,
+ const MCExpr *Count = nullptr, SMLoc Loc = SMLoc());
+
+ /// Reset the current lexer position to that given by \p Loc. The
+ /// current token is not set; clients should ensure Lex() is called
+ /// subsequently.
+ ///
+ /// \param InBuffer If not 0, should be the known buffer id that contains the
+ /// location.
+ void jumpToLoc(SMLoc Loc, unsigned InBuffer = 0);
+
+ /// Parse up to the end of statement and a return the contents from the
+ /// current token until the end of the statement; the current token on exit
+ /// will be either the EndOfStatement or EOF.
+ StringRef parseStringToEndOfStatement() override;
+
+ /// Parse until the end of a statement or a comma is encountered,
+ /// return the contents from the current token up to the end or comma.
+ StringRef parseStringToComma();
+
+ bool parseAssignment(StringRef Name, bool allow_redef,
+ bool NoDeadStrip = false);
+
+ unsigned getBinOpPrecedence(AsmToken::TokenKind K,
+ MCBinaryExpr::Opcode &Kind);
+
+ bool parseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc);
+ bool parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc);
+ bool parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc);
+
+ bool parseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc);
+
+ bool parseCVFunctionId(int64_t &FunctionId, StringRef DirectiveName);
+ bool parseCVFileId(int64_t &FileId, StringRef DirectiveName);
+
+ // Generic (target and platform independent) directive parsing.
+ enum DirectiveKind {
+ DK_NO_DIRECTIVE, // Placeholder
+ DK_SET,
+ DK_EQU,
+ DK_EQUIV,
+ DK_ASCII,
+ DK_ASCIZ,
+ DK_STRING,
+ DK_BYTE,
+ DK_SHORT,
+ DK_RELOC,
+ DK_VALUE,
+ DK_2BYTE,
+ DK_LONG,
+ DK_INT,
+ DK_4BYTE,
+ DK_QUAD,
+ DK_8BYTE,
+ DK_OCTA,
+ DK_DC,
+ DK_DC_A,
+ DK_DC_B,
+ DK_DC_D,
+ DK_DC_L,
+ DK_DC_S,
+ DK_DC_W,
+ DK_DC_X,
+ DK_DCB,
+ DK_DCB_B,
+ DK_DCB_D,
+ DK_DCB_L,
+ DK_DCB_S,
+ DK_DCB_W,
+ DK_DCB_X,
+ DK_DS,
+ DK_DS_B,
+ DK_DS_D,
+ DK_DS_L,
+ DK_DS_P,
+ DK_DS_S,
+ DK_DS_W,
+ DK_DS_X,
+ DK_SINGLE,
+ DK_FLOAT,
+ DK_DOUBLE,
+ DK_ALIGN,
+ DK_ALIGN32,
+ DK_BALIGN,
+ DK_BALIGNW,
+ DK_BALIGNL,
+ DK_P2ALIGN,
+ DK_P2ALIGNW,
+ DK_P2ALIGNL,
+ DK_ORG,
+ DK_FILL,
+ DK_ENDR,
+ DK_BUNDLE_ALIGN_MODE,
+ DK_BUNDLE_LOCK,
+ DK_BUNDLE_UNLOCK,
+ DK_ZERO,
+ DK_EXTERN,
+ DK_GLOBL,
+ DK_GLOBAL,
+ DK_LAZY_REFERENCE,
+ DK_NO_DEAD_STRIP,
+ DK_SYMBOL_RESOLVER,
+ DK_PRIVATE_EXTERN,
+ DK_REFERENCE,
+ DK_WEAK_DEFINITION,
+ DK_WEAK_REFERENCE,
+ DK_WEAK_DEF_CAN_BE_HIDDEN,
+ DK_COLD,
+ DK_COMM,
+ DK_COMMON,
+ DK_LCOMM,
+ DK_ABORT,
+ DK_INCLUDE,
+ DK_INCBIN,
+ DK_CODE16,
+ DK_CODE16GCC,
+ DK_REPT,
+ DK_IRP,
+ DK_IRPC,
+ DK_IF,
+ DK_IFEQ,
+ DK_IFGE,
+ DK_IFGT,
+ DK_IFLE,
+ DK_IFLT,
+ DK_IFNE,
+ DK_IFB,
+ DK_IFNB,
+ DK_IFC,
+ DK_IFEQS,
+ DK_IFNC,
+ DK_IFNES,
+ DK_IFDEF,
+ DK_IFNDEF,
+ DK_IFNOTDEF,
+ DK_ELSEIF,
+ DK_ELSE,
+ DK_ENDIF,
+ DK_SPACE,
+ DK_SKIP,
+ DK_FILE,
+ DK_LINE,
+ DK_LOC,
+ DK_STABS,
+ DK_CV_FILE,
+ DK_CV_FUNC_ID,
+ DK_CV_INLINE_SITE_ID,
+ DK_CV_LOC,
+ DK_CV_LINETABLE,
+ DK_CV_INLINE_LINETABLE,
+ DK_CV_DEF_RANGE,
+ DK_CV_STRINGTABLE,
+ DK_CV_STRING,
+ DK_CV_FILECHECKSUMS,
+ DK_CV_FILECHECKSUM_OFFSET,
+ DK_CV_FPO_DATA,
+ DK_CFI_SECTIONS,
+ DK_CFI_STARTPROC,
+ DK_CFI_ENDPROC,
+ DK_CFI_DEF_CFA,
+ DK_CFI_DEF_CFA_OFFSET,
+ DK_CFI_ADJUST_CFA_OFFSET,
+ DK_CFI_DEF_CFA_REGISTER,
+ DK_CFI_OFFSET,
+ DK_CFI_REL_OFFSET,
+ DK_CFI_PERSONALITY,
+ DK_CFI_LSDA,
+ DK_CFI_REMEMBER_STATE,
+ DK_CFI_RESTORE_STATE,
+ DK_CFI_SAME_VALUE,
+ DK_CFI_RESTORE,
+ DK_CFI_ESCAPE,
+ DK_CFI_RETURN_COLUMN,
+ DK_CFI_SIGNAL_FRAME,
+ DK_CFI_UNDEFINED,
+ DK_CFI_REGISTER,
+ DK_CFI_WINDOW_SAVE,
+ DK_CFI_B_KEY_FRAME,
+ DK_MACROS_ON,
+ DK_MACROS_OFF,
+ DK_ALTMACRO,
+ DK_NOALTMACRO,
+ DK_MACRO,
+ DK_EXITM,
+ DK_ENDM,
+ DK_ENDMACRO,
+ DK_PURGEM,
+ DK_SLEB128,
+ DK_ULEB128,
+ DK_ERR,
+ DK_ERROR,
+ DK_WARNING,
+ DK_PRINT,
+ DK_ADDRSIG,
+ DK_ADDRSIG_SYM,
+ DK_END
+ };
+
+ /// Maps directive name --> DirectiveKind enum, for
+ /// directives parsed by this class.
+ StringMap<DirectiveKind> DirectiveKindMap;
+
+ // Codeview def_range type parsing.
+ enum CVDefRangeType {
+ CVDR_DEFRANGE = 0, // Placeholder
+ CVDR_DEFRANGE_REGISTER,
+ CVDR_DEFRANGE_FRAMEPOINTER_REL,
+ CVDR_DEFRANGE_SUBFIELD_REGISTER,
+ CVDR_DEFRANGE_REGISTER_REL
+ };
+
+ /// Maps Codeview def_range types --> CVDefRangeType enum, for
+ /// Codeview def_range types parsed by this class.
+ StringMap<CVDefRangeType> CVDefRangeTypeMap;
+
+ // ".ascii", ".asciz", ".string"
+ bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated);
+ bool parseDirectiveReloc(SMLoc DirectiveLoc); // ".reloc"
+ bool parseDirectiveValue(StringRef IDVal,
+ unsigned Size); // ".byte", ".long", ...
+ bool parseDirectiveOctaValue(StringRef IDVal); // ".octa", ...
+ bool parseDirectiveRealValue(StringRef IDVal,
+ const fltSemantics &); // ".single", ...
+ bool parseDirectiveFill(); // ".fill"
+ bool parseDirectiveZero(); // ".zero"
+ // ".set", ".equ", ".equiv"
+ bool parseDirectiveSet(StringRef IDVal, bool allow_redef);
+ bool parseDirectiveOrg(); // ".org"
+ // ".align{,32}", ".p2align{,w,l}"
+ bool parseDirectiveAlign(bool IsPow2, unsigned ValueSize);
+
+ // ".file", ".line", ".loc", ".stabs"
+ bool parseDirectiveFile(SMLoc DirectiveLoc);
+ bool parseDirectiveLine();
+ bool parseDirectiveLoc();
+ bool parseDirectiveStabs();
+
+ // ".cv_file", ".cv_func_id", ".cv_inline_site_id", ".cv_loc", ".cv_linetable",
+ // ".cv_inline_linetable", ".cv_def_range", ".cv_string"
+ bool parseDirectiveCVFile();
+ bool parseDirectiveCVFuncId();
+ bool parseDirectiveCVInlineSiteId();
+ bool parseDirectiveCVLoc();
+ bool parseDirectiveCVLinetable();
+ bool parseDirectiveCVInlineLinetable();
+ bool parseDirectiveCVDefRange();
+ bool parseDirectiveCVString();
+ bool parseDirectiveCVStringTable();
+ bool parseDirectiveCVFileChecksums();
+ bool parseDirectiveCVFileChecksumOffset();
+ bool parseDirectiveCVFPOData();
+
+ // .cfi directives
+ bool parseDirectiveCFIRegister(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIWindowSave();
+ bool parseDirectiveCFISections();
+ bool parseDirectiveCFIStartProc();
+ bool parseDirectiveCFIEndProc();
+ bool parseDirectiveCFIDefCfaOffset();
+ bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIAdjustCfaOffset();
+ bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIOffset(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality);
+ bool parseDirectiveCFIRememberState();
+ bool parseDirectiveCFIRestoreState();
+ bool parseDirectiveCFISameValue(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIRestore(SMLoc DirectiveLoc);
+ bool parseDirectiveCFIEscape();
+ bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc);
+ bool parseDirectiveCFISignalFrame();
+ bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);
+
+ // macro directives
+ bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
+ bool parseDirectiveExitMacro(StringRef Directive);
+ bool parseDirectiveEndMacro(StringRef Directive);
+ bool parseDirectiveMacro(SMLoc DirectiveLoc);
+ bool parseDirectiveMacrosOnOff(StringRef Directive);
+ // alternate macro mode directives
+ bool parseDirectiveAltmacro(StringRef Directive);
+ // ".bundle_align_mode"
+ bool parseDirectiveBundleAlignMode();
+ // ".bundle_lock"
+ bool parseDirectiveBundleLock();
+ // ".bundle_unlock"
+ bool parseDirectiveBundleUnlock();
+
+ // ".space", ".skip"
+ bool parseDirectiveSpace(StringRef IDVal);
+
+ // ".dcb"
+ bool parseDirectiveDCB(StringRef IDVal, unsigned Size);
+ bool parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &);
+ // ".ds"
+ bool parseDirectiveDS(StringRef IDVal, unsigned Size);
+
+ // .sleb128 (Signed=true) and .uleb128 (Signed=false)
+ bool parseDirectiveLEB128(bool Signed);
+
+ /// Parse a directive like ".globl" which
+ /// accepts a single symbol (which should be a label or an external).
+ bool parseDirectiveSymbolAttribute(MCSymbolAttr Attr);
+
+ bool parseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm"
+
+ bool parseDirectiveAbort(); // ".abort"
+ bool parseDirectiveInclude(); // ".include"
+ bool parseDirectiveIncbin(); // ".incbin"
+
+ // ".if", ".ifeq", ".ifge", ".ifgt" , ".ifle", ".iflt" or ".ifne"
+ bool parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind);
+ // ".ifb" or ".ifnb", depending on ExpectBlank.
+ bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank);
+ // ".ifc" or ".ifnc", depending on ExpectEqual.
+ bool parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual);
+ // ".ifeqs" or ".ifnes", depending on ExpectEqual.
+ bool parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual);
+ // ".ifdef" or ".ifndef", depending on expect_defined
+ bool parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined);
+ bool parseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif"
+ bool parseDirectiveElse(SMLoc DirectiveLoc); // ".else"
+ bool parseDirectiveEndIf(SMLoc DirectiveLoc); // .endif
+ bool parseEscapedString(std::string &Data) override;
+
+ const MCExpr *applyModifierToExpr(const MCExpr *E,
+ MCSymbolRefExpr::VariantKind Variant);
+
+ // Macro-like directives
+ MCAsmMacro *parseMacroLikeBody(SMLoc DirectiveLoc);
+ void instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
+ raw_svector_ostream &OS);
+ bool parseDirectiveRept(SMLoc DirectiveLoc, StringRef Directive);
+ bool parseDirectiveIrp(SMLoc DirectiveLoc); // ".irp"
+ bool parseDirectiveIrpc(SMLoc DirectiveLoc); // ".irpc"
+ bool parseDirectiveEndr(SMLoc DirectiveLoc); // ".endr"
+
+ // "_emit" or "__emit"
+ bool parseDirectiveMSEmit(SMLoc DirectiveLoc, ParseStatementInfo &Info,
+ size_t Len);
+
+ // "align"
+ bool parseDirectiveMSAlign(SMLoc DirectiveLoc, ParseStatementInfo &Info);
+
+ // "end"
+ bool parseDirectiveEnd(SMLoc DirectiveLoc);
+
+ // ".err" or ".error"
+ bool parseDirectiveError(SMLoc DirectiveLoc, bool WithMessage);
+
+ // ".warning"
+ bool parseDirectiveWarning(SMLoc DirectiveLoc);
+
+ // .print <double-quotes-string>
+ bool parseDirectivePrint(SMLoc DirectiveLoc);
+
+ // Directives to support address-significance tables.
+ bool parseDirectiveAddrsig();
+ bool parseDirectiveAddrsigSym();
+
+ void initializeDirectiveKindMap();
+ void initializeCVDefRangeTypeMap();
+};
+
+} // end anonymous namespace
+
+namespace llvm {
+
+extern MCAsmParserExtension *createDarwinAsmParser();
+extern MCAsmParserExtension *createELFAsmParser();
+extern MCAsmParserExtension *createCOFFAsmParser();
+extern MCAsmParserExtension *createWasmAsmParser();
+
+} // end namespace llvm
+
+enum { DEFAULT_ADDRSPACE = 0 };
+
+AsmParser::AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out,
+ const MCAsmInfo &MAI, unsigned CB = 0)
+ : Lexer(MAI), Ctx(Ctx), Out(Out), MAI(MAI), SrcMgr(SM),
+ CurBuffer(CB ? CB : SM.getMainFileID()), MacrosEnabledFlag(true) {
+ HadError = false;
+ // Save the old handler.
+ SavedDiagHandler = SrcMgr.getDiagHandler();
+ SavedDiagContext = SrcMgr.getDiagContext();
+ // Set our own handler which calls the saved handler.
+ SrcMgr.setDiagHandler(DiagHandler, this);
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
+
+ // Initialize the platform / file format parser.
+ switch (Ctx.getObjectFileInfo()->getObjectFileType()) {
+ case MCObjectFileInfo::IsCOFF:
+ PlatformParser.reset(createCOFFAsmParser());
+ break;
+ case MCObjectFileInfo::IsMachO:
+ PlatformParser.reset(createDarwinAsmParser());
+ IsDarwin = true;
+ break;
+ case MCObjectFileInfo::IsELF:
+ PlatformParser.reset(createELFAsmParser());
+ break;
+ case MCObjectFileInfo::IsWasm:
+ PlatformParser.reset(createWasmAsmParser());
+ break;
+ case MCObjectFileInfo::IsXCOFF:
+ report_fatal_error(
+ "Need to implement createXCOFFAsmParser for XCOFF format.");
+ break;
+ }
+
+ PlatformParser->Initialize(*this);
+ initializeDirectiveKindMap();
+ initializeCVDefRangeTypeMap();
+
+ NumOfMacroInstantiations = 0;
+}
+
+AsmParser::~AsmParser() {
+ assert((HadError || ActiveMacros.empty()) &&
+ "Unexpected active macro instantiation!");
+
+ // Restore the saved diagnostics handler and context for use during
+ // finalization.
+ SrcMgr.setDiagHandler(SavedDiagHandler, SavedDiagContext);
+}
+
+void AsmParser::printMacroInstantiations() {
+ // Print the active macro instantiation stack.
+ for (std::vector<MacroInstantiation *>::const_reverse_iterator
+ it = ActiveMacros.rbegin(),
+ ie = ActiveMacros.rend();
+ it != ie; ++it)
+ printMessage((*it)->InstantiationLoc, SourceMgr::DK_Note,
+ "while in macro instantiation");
+}
+
+void AsmParser::Note(SMLoc L, const Twine &Msg, SMRange Range) {
+ printPendingErrors();
+ printMessage(L, SourceMgr::DK_Note, Msg, Range);
+ printMacroInstantiations();
+}
+
+bool AsmParser::Warning(SMLoc L, const Twine &Msg, SMRange Range) {
+ if(getTargetParser().getTargetOptions().MCNoWarn)
+ return false;
+ if (getTargetParser().getTargetOptions().MCFatalWarnings)
+ return Error(L, Msg, Range);
+ printMessage(L, SourceMgr::DK_Warning, Msg, Range);
+ printMacroInstantiations();
+ return false;
+}
+
+bool AsmParser::printError(SMLoc L, const Twine &Msg, SMRange Range) {
+ HadError = true;
+ printMessage(L, SourceMgr::DK_Error, Msg, Range);
+ printMacroInstantiations();
+ return true;
+}
+
+bool AsmParser::enterIncludeFile(const std::string &Filename) {
+ std::string IncludedFile;
+ unsigned NewBuf =
+ SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);
+ if (!NewBuf)
+ return true;
+
+ CurBuffer = NewBuf;
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
+ return false;
+}
+
+/// Process the specified .incbin file by searching for it in the include paths
+/// then just emitting the byte contents of the file to the streamer. This
+/// returns true on failure.
+bool AsmParser::processIncbinFile(const std::string &Filename, int64_t Skip,
+ const MCExpr *Count, SMLoc Loc) {
+ std::string IncludedFile;
+ unsigned NewBuf =
+ SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile);
+ if (!NewBuf)
+ return true;
+
+ // Pick up the bytes from the file and emit them.
+ StringRef Bytes = SrcMgr.getMemoryBuffer(NewBuf)->getBuffer();
+ Bytes = Bytes.drop_front(Skip);
+ if (Count) {
+ int64_t Res;
+ if (!Count->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))
+ return Error(Loc, "expected absolute expression");
+ if (Res < 0)
+ return Warning(Loc, "negative count has no effect");
+ Bytes = Bytes.take_front(Res);
+ }
+ getStreamer().EmitBytes(Bytes);
+ return false;
+}
+
+void AsmParser::jumpToLoc(SMLoc Loc, unsigned InBuffer) {
+ CurBuffer = InBuffer ? InBuffer : SrcMgr.FindBufferContainingLoc(Loc);
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer(),
+ Loc.getPointer());
+}
+
+const AsmToken &AsmParser::Lex() {
+ if (Lexer.getTok().is(AsmToken::Error))
+ Error(Lexer.getErrLoc(), Lexer.getErr());
+
+ // if it's a end of statement with a comment in it
+ if (getTok().is(AsmToken::EndOfStatement)) {
+ // if this is a line comment output it.
+ if (!getTok().getString().empty() && getTok().getString().front() != '\n' &&
+ getTok().getString().front() != '\r' && MAI.preserveAsmComments())
+ Out.addExplicitComment(Twine(getTok().getString()));
+ }
+
+ const AsmToken *tok = &Lexer.Lex();
+
+ // Parse comments here to be deferred until end of next statement.
+ while (tok->is(AsmToken::Comment)) {
+ if (MAI.preserveAsmComments())
+ Out.addExplicitComment(Twine(tok->getString()));
+ tok = &Lexer.Lex();
+ }
+
+ if (tok->is(AsmToken::Eof)) {
+ // If this is the end of an included file, pop the parent file off the
+ // include stack.
+ SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer);
+ if (ParentIncludeLoc != SMLoc()) {
+ jumpToLoc(ParentIncludeLoc);
+ return Lex();
+ }
+ }
+
+ return *tok;
+}
+
+bool AsmParser::enabledGenDwarfForAssembly() {
+ // Check whether the user specified -g.
+ if (!getContext().getGenDwarfForAssembly())
+ return false;
+ // If we haven't encountered any .file directives (which would imply that
+ // the assembler source was produced with debug info already) then emit one
+ // describing the assembler source file itself.
+ if (getContext().getGenDwarfFileNumber() == 0) {
+ // Use the first #line directive for this, if any. It's preprocessed, so
+ // there is no checksum, and of course no source directive.
+ if (!FirstCppHashFilename.empty())
+ getContext().setMCLineTableRootFile(/*CUID=*/0,
+ getContext().getCompilationDir(),
+ FirstCppHashFilename,
+ /*Cksum=*/None, /*Source=*/None);
+ const MCDwarfFile &RootFile =
+ getContext().getMCDwarfLineTable(/*CUID=*/0).getRootFile();
+ getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective(
+ /*CUID=*/0, getContext().getCompilationDir(), RootFile.Name,
+ RootFile.Checksum, RootFile.Source));
+ }
+ return true;
+}
+
+bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) {
+ // Create the initial section, if requested.
+ if (!NoInitialTextSection)
+ Out.InitSections(false);
+
+ // Prime the lexer.
+ Lex();
+
+ HadError = false;
+ AsmCond StartingCondState = TheCondState;
+ SmallVector<AsmRewrite, 4> AsmStrRewrites;
+
+ // If we are generating dwarf for assembly source files save the initial text
+ // section. (Don't use enabledGenDwarfForAssembly() here, as we aren't
+ // emitting any actual debug info yet and haven't had a chance to parse any
+ // embedded .file directives.)
+ if (getContext().getGenDwarfForAssembly()) {
+ MCSection *Sec = getStreamer().getCurrentSectionOnly();
+ if (!Sec->getBeginSymbol()) {
+ MCSymbol *SectionStartSym = getContext().createTempSymbol();
+ getStreamer().EmitLabel(SectionStartSym);
+ Sec->setBeginSymbol(SectionStartSym);
+ }
+ bool InsertResult = getContext().addGenDwarfSection(Sec);
+ assert(InsertResult && ".text section should not have debug info yet");
+ (void)InsertResult;
+ }
+
+ // While we have input, parse each statement.
+ while (Lexer.isNot(AsmToken::Eof)) {
+ ParseStatementInfo Info(&AsmStrRewrites);
+ if (!parseStatement(Info, nullptr))
+ continue;
+
+ // If we have a Lexer Error we are on an Error Token. Load in Lexer Error
+ // for printing ErrMsg via Lex() only if no (presumably better) parser error
+ // exists.
+ if (!hasPendingError() && Lexer.getTok().is(AsmToken::Error)) {
+ Lex();
+ }
+
+ // parseStatement returned true so may need to emit an error.
+ printPendingErrors();
+
+ // Skipping to the next line if needed.
+ if (!getLexer().isAtStartOfStatement())
+ eatToEndOfStatement();
+ }
+
+ getTargetParser().onEndOfFile();
+ printPendingErrors();
+
+ // All errors should have been emitted.
+ assert(!hasPendingError() && "unexpected error from parseStatement");
+
+ getTargetParser().flushPendingInstructions(getStreamer());
+
+ if (TheCondState.TheCond != StartingCondState.TheCond ||
+ TheCondState.Ignore != StartingCondState.Ignore)
+ printError(getTok().getLoc(), "unmatched .ifs or .elses");
+ // Check to see there are no empty DwarfFile slots.
+ const auto &LineTables = getContext().getMCDwarfLineTables();
+ if (!LineTables.empty()) {
+ unsigned Index = 0;
+ for (const auto &File : LineTables.begin()->second.getMCDwarfFiles()) {
+ if (File.Name.empty() && Index != 0)
+ printError(getTok().getLoc(), "unassigned file number: " +
+ Twine(Index) +
+ " for .file directives");
+ ++Index;
+ }
+ }
+
+ // Check to see that all assembler local symbols were actually defined.
+ // Targets that don't do subsections via symbols may not want this, though,
+ // so conservatively exclude them. Only do this if we're finalizing, though,
+ // as otherwise we won't necessarilly have seen everything yet.
+ if (!NoFinalize) {
+ if (MAI.hasSubsectionsViaSymbols()) {
+ for (const auto &TableEntry : getContext().getSymbols()) {
+ MCSymbol *Sym = TableEntry.getValue();
+ // Variable symbols may not be marked as defined, so check those
+ // explicitly. If we know it's a variable, we have a definition for
+ // the purposes of this check.
+ if (Sym->isTemporary() && !Sym->isVariable() && !Sym->isDefined())
+ // FIXME: We would really like to refer back to where the symbol was
+ // first referenced for a source location. We need to add something
+ // to track that. Currently, we just point to the end of the file.
+ printError(getTok().getLoc(), "assembler local symbol '" +
+ Sym->getName() + "' not defined");
+ }
+ }
+
+ // Temporary symbols like the ones for directional jumps don't go in the
+ // symbol table. They also need to be diagnosed in all (final) cases.
+ for (std::tuple<SMLoc, CppHashInfoTy, MCSymbol *> &LocSym : DirLabels) {
+ if (std::get<2>(LocSym)->isUndefined()) {
+ // Reset the state of any "# line file" directives we've seen to the
+ // context as it was at the diagnostic site.
+ CppHashInfo = std::get<1>(LocSym);
+ printError(std::get<0>(LocSym), "directional label undefined");
+ }
+ }
+ }
+
+ // Finalize the output stream if there are no errors and if the client wants
+ // us to.
+ if (!HadError && !NoFinalize)
+ Out.Finish();
+
+ return HadError || getContext().hadError();
+}
+
+bool AsmParser::checkForValidSection() {
+ if (!ParsingInlineAsm && !getStreamer().getCurrentSectionOnly()) {
+ Out.InitSections(false);
+ return Error(getTok().getLoc(),
+ "expected section directive before assembly directive");
+ }
+ return false;
+}
+
+/// Throw away the rest of the line for testing purposes.
+void AsmParser::eatToEndOfStatement() {
+ while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))
+ Lexer.Lex();
+
+ // Eat EOL.
+ if (Lexer.is(AsmToken::EndOfStatement))
+ Lexer.Lex();
+}
+
+StringRef AsmParser::parseStringToEndOfStatement() {
+ const char *Start = getTok().getLoc().getPointer();
+
+ while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof))
+ Lexer.Lex();
+
+ const char *End = getTok().getLoc().getPointer();
+ return StringRef(Start, End - Start);
+}
+
+StringRef AsmParser::parseStringToComma() {
+ const char *Start = getTok().getLoc().getPointer();
+
+ while (Lexer.isNot(AsmToken::EndOfStatement) &&
+ Lexer.isNot(AsmToken::Comma) && Lexer.isNot(AsmToken::Eof))
+ Lexer.Lex();
+
+ const char *End = getTok().getLoc().getPointer();
+ return StringRef(Start, End - Start);
+}
+
+/// Parse a paren expression and return it.
+/// NOTE: This assumes the leading '(' has already been consumed.
+///
+/// parenexpr ::= expr)
+///
+bool AsmParser::parseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) {
+ if (parseExpression(Res))
+ return true;
+ if (Lexer.isNot(AsmToken::RParen))
+ return TokError("expected ')' in parentheses expression");
+ EndLoc = Lexer.getTok().getEndLoc();
+ Lex();
+ return false;
+}
+
+/// Parse a bracket expression and return it.
+/// NOTE: This assumes the leading '[' has already been consumed.
+///
+/// bracketexpr ::= expr]
+///
+bool AsmParser::parseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) {
+ if (parseExpression(Res))
+ return true;
+ EndLoc = getTok().getEndLoc();
+ if (parseToken(AsmToken::RBrac, "expected ']' in brackets expression"))
+ return true;
+ return false;
+}
+
+/// Parse a primary expression and return it.
+/// primaryexpr ::= (parenexpr
+/// primaryexpr ::= symbol
+/// primaryexpr ::= number
+/// primaryexpr ::= '.'
+/// primaryexpr ::= ~,+,- primaryexpr
+bool AsmParser::parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) {
+ SMLoc FirstTokenLoc = getLexer().getLoc();
+ AsmToken::TokenKind FirstTokenKind = Lexer.getKind();
+ switch (FirstTokenKind) {
+ default:
+ return TokError("unknown token in expression");
+ // If we have an error assume that we've already handled it.
+ case AsmToken::Error:
+ return true;
+ case AsmToken::Exclaim:
+ Lex(); // Eat the operator.
+ if (parsePrimaryExpr(Res, EndLoc))
+ return true;
+ Res = MCUnaryExpr::createLNot(Res, getContext(), FirstTokenLoc);
+ return false;
+ case AsmToken::Dollar:
+ case AsmToken::At:
+ case AsmToken::String:
+ case AsmToken::Identifier: {
+ StringRef Identifier;
+ if (parseIdentifier(Identifier)) {
+ // We may have failed but $ may be a valid token.
+ if (getTok().is(AsmToken::Dollar)) {
+ if (Lexer.getMAI().getDollarIsPC()) {
+ Lex();
+ // This is a '$' reference, which references the current PC. Emit a
+ // temporary label to the streamer and refer to it.
+ MCSymbol *Sym = Ctx.createTempSymbol();
+ Out.EmitLabel(Sym);
+ Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
+ getContext());
+ EndLoc = FirstTokenLoc;
+ return false;
+ }
+ return Error(FirstTokenLoc, "invalid token in expression");
+ }
+ }
+ // Parse symbol variant
+ std::pair<StringRef, StringRef> Split;
+ if (!MAI.useParensForSymbolVariant()) {
+ if (FirstTokenKind == AsmToken::String) {
+ if (Lexer.is(AsmToken::At)) {
+ Lex(); // eat @
+ SMLoc AtLoc = getLexer().getLoc();
+ StringRef VName;
+ if (parseIdentifier(VName))
+ return Error(AtLoc, "expected symbol variant after '@'");
+
+ Split = std::make_pair(Identifier, VName);
+ }
+ } else {
+ Split = Identifier.split('@');
+ }
+ } else if (Lexer.is(AsmToken::LParen)) {
+ Lex(); // eat '('.
+ StringRef VName;
+ parseIdentifier(VName);
+ // eat ')'.
+ if (parseToken(AsmToken::RParen,
+ "unexpected token in variant, expected ')'"))
+ return true;
+ Split = std::make_pair(Identifier, VName);
+ }
+
+ EndLoc = SMLoc::getFromPointer(Identifier.end());
+
+ // This is a symbol reference.
+ StringRef SymbolName = Identifier;
+ if (SymbolName.empty())
+ return Error(getLexer().getLoc(), "expected a symbol reference");
+
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+
+ // Lookup the symbol variant if used.
+ if (!Split.second.empty()) {
+ Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
+ if (Variant != MCSymbolRefExpr::VK_Invalid) {
+ SymbolName = Split.first;
+ } else if (MAI.doesAllowAtInName() && !MAI.useParensForSymbolVariant()) {
+ Variant = MCSymbolRefExpr::VK_None;
+ } else {
+ return Error(SMLoc::getFromPointer(Split.second.begin()),
+ "invalid variant '" + Split.second + "'");
+ }
+ }
+
+ MCSymbol *Sym = getContext().getInlineAsmLabel(SymbolName);
+ if (!Sym)
+ Sym = getContext().getOrCreateSymbol(SymbolName);
+
+ // If this is an absolute variable reference, substitute it now to preserve
+ // semantics in the face of reassignment.
+ if (Sym->isVariable()) {
+ auto V = Sym->getVariableValue(/*SetUsed*/ false);
+ bool DoInline = isa<MCConstantExpr>(V) && !Variant;
+ if (auto TV = dyn_cast<MCTargetExpr>(V))
+ DoInline = TV->inlineAssignedExpr();
+ if (DoInline) {
+ if (Variant)
+ return Error(EndLoc, "unexpected modifier on variable reference");
+ Res = Sym->getVariableValue(/*SetUsed*/ false);
+ return false;
+ }
+ }
+
+ // Otherwise create a symbol ref.
+ Res = MCSymbolRefExpr::create(Sym, Variant, getContext(), FirstTokenLoc);
+ return false;
+ }
+ case AsmToken::BigNum:
+ return TokError("literal value out of range for directive");
+ case AsmToken::Integer: {
+ SMLoc Loc = getTok().getLoc();
+ int64_t IntVal = getTok().getIntVal();
+ Res = MCConstantExpr::create(IntVal, getContext());
+ EndLoc = Lexer.getTok().getEndLoc();
+ Lex(); // Eat token.
+ // Look for 'b' or 'f' following an Integer as a directional label
+ if (Lexer.getKind() == AsmToken::Identifier) {
+ StringRef IDVal = getTok().getString();
+ // Lookup the symbol variant if used.
+ std::pair<StringRef, StringRef> Split = IDVal.split('@');
+ MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None;
+ if (Split.first.size() != IDVal.size()) {
+ Variant = MCSymbolRefExpr::getVariantKindForName(Split.second);
+ if (Variant == MCSymbolRefExpr::VK_Invalid)
+ return TokError("invalid variant '" + Split.second + "'");
+ IDVal = Split.first;
+ }
+ if (IDVal == "f" || IDVal == "b") {
+ MCSymbol *Sym =
+ Ctx.getDirectionalLocalSymbol(IntVal, IDVal == "b");
+ Res = MCSymbolRefExpr::create(Sym, Variant, getContext());
+ if (IDVal == "b" && Sym->isUndefined())
+ return Error(Loc, "directional label undefined");
+ DirLabels.push_back(std::make_tuple(Loc, CppHashInfo, Sym));
+ EndLoc = Lexer.getTok().getEndLoc();
+ Lex(); // Eat identifier.
+ }
+ }
+ return false;
+ }
+ case AsmToken::Real: {
+ APFloat RealVal(APFloat::IEEEdouble(), getTok().getString());
+ uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue();
+ Res = MCConstantExpr::create(IntVal, getContext());
+ EndLoc = Lexer.getTok().getEndLoc();
+ Lex(); // Eat token.
+ return false;
+ }
+ case AsmToken::Dot: {
+ // This is a '.' reference, which references the current PC. Emit a
+ // temporary label to the streamer and refer to it.
+ MCSymbol *Sym = Ctx.createTempSymbol();
+ Out.EmitLabel(Sym);
+ Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
+ EndLoc = Lexer.getTok().getEndLoc();
+ Lex(); // Eat identifier.
+ return false;
+ }
+ case AsmToken::LParen:
+ Lex(); // Eat the '('.
+ return parseParenExpr(Res, EndLoc);
+ case AsmToken::LBrac:
+ if (!PlatformParser->HasBracketExpressions())
+ return TokError("brackets expression not supported on this target");
+ Lex(); // Eat the '['.
+ return parseBracketExpr(Res, EndLoc);
+ case AsmToken::Minus:
+ Lex(); // Eat the operator.
+ if (parsePrimaryExpr(Res, EndLoc))
+ return true;
+ Res = MCUnaryExpr::createMinus(Res, getContext(), FirstTokenLoc);
+ return false;
+ case AsmToken::Plus:
+ Lex(); // Eat the operator.
+ if (parsePrimaryExpr(Res, EndLoc))
+ return true;
+ Res = MCUnaryExpr::createPlus(Res, getContext(), FirstTokenLoc);
+ return false;
+ case AsmToken::Tilde:
+ Lex(); // Eat the operator.
+ if (parsePrimaryExpr(Res, EndLoc))
+ return true;
+ Res = MCUnaryExpr::createNot(Res, getContext(), FirstTokenLoc);
+ return false;
+ // MIPS unary expression operators. The lexer won't generate these tokens if
+ // MCAsmInfo::HasMipsExpressions is false for the target.
+ case AsmToken::PercentCall16:
+ case AsmToken::PercentCall_Hi:
+ case AsmToken::PercentCall_Lo:
+ case AsmToken::PercentDtprel_Hi:
+ case AsmToken::PercentDtprel_Lo:
+ case AsmToken::PercentGot:
+ case AsmToken::PercentGot_Disp:
+ case AsmToken::PercentGot_Hi:
+ case AsmToken::PercentGot_Lo:
+ case AsmToken::PercentGot_Ofst:
+ case AsmToken::PercentGot_Page:
+ case AsmToken::PercentGottprel:
+ case AsmToken::PercentGp_Rel:
+ case AsmToken::PercentHi:
+ case AsmToken::PercentHigher:
+ case AsmToken::PercentHighest:
+ case AsmToken::PercentLo:
+ case AsmToken::PercentNeg:
+ case AsmToken::PercentPcrel_Hi:
+ case AsmToken::PercentPcrel_Lo:
+ case AsmToken::PercentTlsgd:
+ case AsmToken::PercentTlsldm:
+ case AsmToken::PercentTprel_Hi:
+ case AsmToken::PercentTprel_Lo:
+ Lex(); // Eat the operator.
+ if (Lexer.isNot(AsmToken::LParen))
+ return TokError("expected '(' after operator");
+ Lex(); // Eat the operator.
+ if (parseExpression(Res, EndLoc))
+ return true;
+ if (Lexer.isNot(AsmToken::RParen))
+ return TokError("expected ')'");
+ Lex(); // Eat the operator.
+ Res = getTargetParser().createTargetUnaryExpr(Res, FirstTokenKind, Ctx);
+ return !Res;
+ }
+}
+
+bool AsmParser::parseExpression(const MCExpr *&Res) {
+ SMLoc EndLoc;
+ return parseExpression(Res, EndLoc);
+}
+
+const MCExpr *
+AsmParser::applyModifierToExpr(const MCExpr *E,
+ MCSymbolRefExpr::VariantKind Variant) {
+ // Ask the target implementation about this expression first.
+ const MCExpr *NewE = getTargetParser().applyModifierToExpr(E, Variant, Ctx);
+ if (NewE)
+ return NewE;
+ // Recurse over the given expression, rebuilding it to apply the given variant
+ // if there is exactly one symbol.
+ switch (E->getKind()) {
+ case MCExpr::Target:
+ case MCExpr::Constant:
+ return nullptr;
+
+ case MCExpr::SymbolRef: {
+ const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E);
+
+ if (SRE->getKind() != MCSymbolRefExpr::VK_None) {
+ TokError("invalid variant on expression '" + getTok().getIdentifier() +
+ "' (already modified)");
+ return E;
+ }
+
+ return MCSymbolRefExpr::create(&SRE->getSymbol(), Variant, getContext());
+ }
+
+ case MCExpr::Unary: {
+ const MCUnaryExpr *UE = cast<MCUnaryExpr>(E);
+ const MCExpr *Sub = applyModifierToExpr(UE->getSubExpr(), Variant);
+ if (!Sub)
+ return nullptr;
+ return MCUnaryExpr::create(UE->getOpcode(), Sub, getContext());
+ }
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(E);
+ const MCExpr *LHS = applyModifierToExpr(BE->getLHS(), Variant);
+ const MCExpr *RHS = applyModifierToExpr(BE->getRHS(), Variant);
+
+ if (!LHS && !RHS)
+ return nullptr;
+
+ if (!LHS)
+ LHS = BE->getLHS();
+ if (!RHS)
+ RHS = BE->getRHS();
+
+ return MCBinaryExpr::create(BE->getOpcode(), LHS, RHS, getContext());
+ }
+ }
+
+ llvm_unreachable("Invalid expression kind!");
+}
+
+/// This function checks if the next token is <string> type or arithmetic.
+/// string that begin with character '<' must end with character '>'.
+/// otherwise it is arithmetics.
+/// If the function returns a 'true' value,
+/// the End argument will be filled with the last location pointed to the '>'
+/// character.
+
+/// There is a gap between the AltMacro's documentation and the single quote
+/// implementation. GCC does not fully support this feature and so we will not
+/// support it.
+/// TODO: Adding single quote as a string.
+static bool isAltmacroString(SMLoc &StrLoc, SMLoc &EndLoc) {
+ assert((StrLoc.getPointer() != nullptr) &&
+ "Argument to the function cannot be a NULL value");
+ const char *CharPtr = StrLoc.getPointer();
+ while ((*CharPtr != '>') && (*CharPtr != '\n') && (*CharPtr != '\r') &&
+ (*CharPtr != '\0')) {
+ if (*CharPtr == '!')
+ CharPtr++;
+ CharPtr++;
+ }
+ if (*CharPtr == '>') {
+ EndLoc = StrLoc.getFromPointer(CharPtr + 1);
+ return true;
+ }
+ return false;
+}
+
+/// creating a string without the escape characters '!'.
+static std::string altMacroString(StringRef AltMacroStr) {
+ std::string Res;
+ for (size_t Pos = 0; Pos < AltMacroStr.size(); Pos++) {
+ if (AltMacroStr[Pos] == '!')
+ Pos++;
+ Res += AltMacroStr[Pos];
+ }
+ return Res;
+}
+
+/// Parse an expression and return it.
+///
+/// expr ::= expr &&,|| expr -> lowest.
+/// expr ::= expr |,^,&,! expr
+/// expr ::= expr ==,!=,<>,<,<=,>,>= expr
+/// expr ::= expr <<,>> expr
+/// expr ::= expr +,- expr
+/// expr ::= expr *,/,% expr -> highest.
+/// expr ::= primaryexpr
+///
+bool AsmParser::parseExpression(const MCExpr *&Res, SMLoc &EndLoc) {
+ // Parse the expression.
+ Res = nullptr;
+ if (getTargetParser().parsePrimaryExpr(Res, EndLoc) ||
+ parseBinOpRHS(1, Res, EndLoc))
+ return true;
+
+ // As a special case, we support 'a op b @ modifier' by rewriting the
+ // expression to include the modifier. This is inefficient, but in general we
+ // expect users to use 'a@modifier op b'.
+ if (Lexer.getKind() == AsmToken::At) {
+ Lex();
+
+ if (Lexer.isNot(AsmToken::Identifier))
+ return TokError("unexpected symbol modifier following '@'");
+
+ MCSymbolRefExpr::VariantKind Variant =
+ MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier());
+ if (Variant == MCSymbolRefExpr::VK_Invalid)
+ return TokError("invalid variant '" + getTok().getIdentifier() + "'");
+
+ const MCExpr *ModifiedRes = applyModifierToExpr(Res, Variant);
+ if (!ModifiedRes) {
+ return TokError("invalid modifier '" + getTok().getIdentifier() +
+ "' (no symbols present)");
+ }
+
+ Res = ModifiedRes;
+ Lex();
+ }
+
+ // Try to constant fold it up front, if possible. Do not exploit
+ // assembler here.
+ int64_t Value;
+ if (Res->evaluateAsAbsolute(Value))
+ Res = MCConstantExpr::create(Value, getContext());
+
+ return false;
+}
+
+bool AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) {
+ Res = nullptr;
+ return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc);
+}
+
+bool AsmParser::parseParenExprOfDepth(unsigned ParenDepth, const MCExpr *&Res,
+ SMLoc &EndLoc) {
+ if (parseParenExpr(Res, EndLoc))
+ return true;
+
+ for (; ParenDepth > 0; --ParenDepth) {
+ if (parseBinOpRHS(1, Res, EndLoc))
+ return true;
+
+ // We don't Lex() the last RParen.
+ // This is the same behavior as parseParenExpression().
+ if (ParenDepth - 1 > 0) {
+ EndLoc = getTok().getEndLoc();
+ if (parseToken(AsmToken::RParen,
+ "expected ')' in parentheses expression"))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AsmParser::parseAbsoluteExpression(int64_t &Res) {
+ const MCExpr *Expr;
+
+ SMLoc StartLoc = Lexer.getLoc();
+ if (parseExpression(Expr))
+ return true;
+
+ if (!Expr->evaluateAsAbsolute(Res, getStreamer().getAssemblerPtr()))
+ return Error(StartLoc, "expected absolute expression");
+
+ return false;
+}
+
+static unsigned getDarwinBinOpPrecedence(AsmToken::TokenKind K,
+ MCBinaryExpr::Opcode &Kind,
+ bool ShouldUseLogicalShr) {
+ switch (K) {
+ default:
+ return 0; // not a binop.
+
+ // Lowest Precedence: &&, ||
+ case AsmToken::AmpAmp:
+ Kind = MCBinaryExpr::LAnd;
+ return 1;
+ case AsmToken::PipePipe:
+ Kind = MCBinaryExpr::LOr;
+ return 1;
+
+ // Low Precedence: |, &, ^
+ //
+ // FIXME: gas seems to support '!' as an infix operator?
+ case AsmToken::Pipe:
+ Kind = MCBinaryExpr::Or;
+ return 2;
+ case AsmToken::Caret:
+ Kind = MCBinaryExpr::Xor;
+ return 2;
+ case AsmToken::Amp:
+ Kind = MCBinaryExpr::And;
+ return 2;
+
+ // Low Intermediate Precedence: ==, !=, <>, <, <=, >, >=
+ case AsmToken::EqualEqual:
+ Kind = MCBinaryExpr::EQ;
+ return 3;
+ case AsmToken::ExclaimEqual:
+ case AsmToken::LessGreater:
+ Kind = MCBinaryExpr::NE;
+ return 3;
+ case AsmToken::Less:
+ Kind = MCBinaryExpr::LT;
+ return 3;
+ case AsmToken::LessEqual:
+ Kind = MCBinaryExpr::LTE;
+ return 3;
+ case AsmToken::Greater:
+ Kind = MCBinaryExpr::GT;
+ return 3;
+ case AsmToken::GreaterEqual:
+ Kind = MCBinaryExpr::GTE;
+ return 3;
+
+ // Intermediate Precedence: <<, >>
+ case AsmToken::LessLess:
+ Kind = MCBinaryExpr::Shl;
+ return 4;
+ case AsmToken::GreaterGreater:
+ Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;
+ return 4;
+
+ // High Intermediate Precedence: +, -
+ case AsmToken::Plus:
+ Kind = MCBinaryExpr::Add;
+ return 5;
+ case AsmToken::Minus:
+ Kind = MCBinaryExpr::Sub;
+ return 5;
+
+ // Highest Precedence: *, /, %
+ case AsmToken::Star:
+ Kind = MCBinaryExpr::Mul;
+ return 6;
+ case AsmToken::Slash:
+ Kind = MCBinaryExpr::Div;
+ return 6;
+ case AsmToken::Percent:
+ Kind = MCBinaryExpr::Mod;
+ return 6;
+ }
+}
+
+static unsigned getGNUBinOpPrecedence(AsmToken::TokenKind K,
+ MCBinaryExpr::Opcode &Kind,
+ bool ShouldUseLogicalShr) {
+ switch (K) {
+ default:
+ return 0; // not a binop.
+
+ // Lowest Precedence: &&, ||
+ case AsmToken::AmpAmp:
+ Kind = MCBinaryExpr::LAnd;
+ return 2;
+ case AsmToken::PipePipe:
+ Kind = MCBinaryExpr::LOr;
+ return 1;
+
+ // Low Precedence: ==, !=, <>, <, <=, >, >=
+ case AsmToken::EqualEqual:
+ Kind = MCBinaryExpr::EQ;
+ return 3;
+ case AsmToken::ExclaimEqual:
+ case AsmToken::LessGreater:
+ Kind = MCBinaryExpr::NE;
+ return 3;
+ case AsmToken::Less:
+ Kind = MCBinaryExpr::LT;
+ return 3;
+ case AsmToken::LessEqual:
+ Kind = MCBinaryExpr::LTE;
+ return 3;
+ case AsmToken::Greater:
+ Kind = MCBinaryExpr::GT;
+ return 3;
+ case AsmToken::GreaterEqual:
+ Kind = MCBinaryExpr::GTE;
+ return 3;
+
+ // Low Intermediate Precedence: +, -
+ case AsmToken::Plus:
+ Kind = MCBinaryExpr::Add;
+ return 4;
+ case AsmToken::Minus:
+ Kind = MCBinaryExpr::Sub;
+ return 4;
+
+ // High Intermediate Precedence: |, &, ^
+ //
+ // FIXME: gas seems to support '!' as an infix operator?
+ case AsmToken::Pipe:
+ Kind = MCBinaryExpr::Or;
+ return 5;
+ case AsmToken::Caret:
+ Kind = MCBinaryExpr::Xor;
+ return 5;
+ case AsmToken::Amp:
+ Kind = MCBinaryExpr::And;
+ return 5;
+
+ // Highest Precedence: *, /, %, <<, >>
+ case AsmToken::Star:
+ Kind = MCBinaryExpr::Mul;
+ return 6;
+ case AsmToken::Slash:
+ Kind = MCBinaryExpr::Div;
+ return 6;
+ case AsmToken::Percent:
+ Kind = MCBinaryExpr::Mod;
+ return 6;
+ case AsmToken::LessLess:
+ Kind = MCBinaryExpr::Shl;
+ return 6;
+ case AsmToken::GreaterGreater:
+ Kind = ShouldUseLogicalShr ? MCBinaryExpr::LShr : MCBinaryExpr::AShr;
+ return 6;
+ }
+}
+
+unsigned AsmParser::getBinOpPrecedence(AsmToken::TokenKind K,
+ MCBinaryExpr::Opcode &Kind) {
+ bool ShouldUseLogicalShr = MAI.shouldUseLogicalShr();
+ return IsDarwin ? getDarwinBinOpPrecedence(K, Kind, ShouldUseLogicalShr)
+ : getGNUBinOpPrecedence(K, Kind, ShouldUseLogicalShr);
+}
+
+/// Parse all binary operators with precedence >= 'Precedence'.
+/// Res contains the LHS of the expression on input.
+bool AsmParser::parseBinOpRHS(unsigned Precedence, const MCExpr *&Res,
+ SMLoc &EndLoc) {
+ SMLoc StartLoc = Lexer.getLoc();
+ while (true) {
+ MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add;
+ unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind);
+
+ // If the next token is lower precedence than we are allowed to eat, return
+ // successfully with what we ate already.
+ if (TokPrec < Precedence)
+ return false;
+
+ Lex();
+
+ // Eat the next primary expression.
+ const MCExpr *RHS;
+ if (getTargetParser().parsePrimaryExpr(RHS, EndLoc))
+ return true;
+
+ // If BinOp binds less tightly with RHS than the operator after RHS, let
+ // the pending operator take RHS as its LHS.
+ MCBinaryExpr::Opcode Dummy;
+ unsigned NextTokPrec = getBinOpPrecedence(Lexer.getKind(), Dummy);
+ if (TokPrec < NextTokPrec && parseBinOpRHS(TokPrec + 1, RHS, EndLoc))
+ return true;
+
+ // Merge LHS and RHS according to operator.
+ Res = MCBinaryExpr::create(Kind, Res, RHS, getContext(), StartLoc);
+ }
+}
+
+/// ParseStatement:
+/// ::= EndOfStatement
+/// ::= Label* Directive ...Operands... EndOfStatement
+/// ::= Label* Identifier OperandList* EndOfStatement
+bool AsmParser::parseStatement(ParseStatementInfo &Info,
+ MCAsmParserSemaCallback *SI) {
+ assert(!hasPendingError() && "parseStatement started with pending error");
+ // Eat initial spaces and comments
+ while (Lexer.is(AsmToken::Space))
+ Lex();
+ if (Lexer.is(AsmToken::EndOfStatement)) {
+ // if this is a line comment we can drop it safely
+ if (getTok().getString().empty() || getTok().getString().front() == '\r' ||
+ getTok().getString().front() == '\n')
+ Out.AddBlankLine();
+ Lex();
+ return false;
+ }
+ // Statements always start with an identifier.
+ AsmToken ID = getTok();
+ SMLoc IDLoc = ID.getLoc();
+ StringRef IDVal;
+ int64_t LocalLabelVal = -1;
+ if (Lexer.is(AsmToken::HashDirective))
+ return parseCppHashLineFilenameComment(IDLoc);
+ // Allow an integer followed by a ':' as a directional local label.
+ if (Lexer.is(AsmToken::Integer)) {
+ LocalLabelVal = getTok().getIntVal();
+ if (LocalLabelVal < 0) {
+ if (!TheCondState.Ignore) {
+ Lex(); // always eat a token
+ return Error(IDLoc, "unexpected token at start of statement");
+ }
+ IDVal = "";
+ } else {
+ IDVal = getTok().getString();
+ Lex(); // Consume the integer token to be used as an identifier token.
+ if (Lexer.getKind() != AsmToken::Colon) {
+ if (!TheCondState.Ignore) {
+ Lex(); // always eat a token
+ return Error(IDLoc, "unexpected token at start of statement");
+ }
+ }
+ }
+ } else if (Lexer.is(AsmToken::Dot)) {
+ // Treat '.' as a valid identifier in this context.
+ Lex();
+ IDVal = ".";
+ } else if (Lexer.is(AsmToken::LCurly)) {
+ // Treat '{' as a valid identifier in this context.
+ Lex();
+ IDVal = "{";
+
+ } else if (Lexer.is(AsmToken::RCurly)) {
+ // Treat '}' as a valid identifier in this context.
+ Lex();
+ IDVal = "}";
+ } else if (Lexer.is(AsmToken::Star) &&
+ getTargetParser().starIsStartOfStatement()) {
+ // Accept '*' as a valid start of statement.
+ Lex();
+ IDVal = "*";
+ } else if (parseIdentifier(IDVal)) {
+ if (!TheCondState.Ignore) {
+ Lex(); // always eat a token
+ return Error(IDLoc, "unexpected token at start of statement");
+ }
+ IDVal = "";
+ }
+
+ // Handle conditional assembly here before checking for skipping. We
+ // have to do this so that .endif isn't skipped in a ".if 0" block for
+ // example.
+ StringMap<DirectiveKind>::const_iterator DirKindIt =
+ DirectiveKindMap.find(IDVal);
+ DirectiveKind DirKind = (DirKindIt == DirectiveKindMap.end())
+
+ ? DK_NO_DIRECTIVE
+ : DirKindIt->getValue();
+ switch (DirKind) {
+ default:
+ break;
+ case DK_IF:
+ case DK_IFEQ:
+ case DK_IFGE:
+ case DK_IFGT:
+ case DK_IFLE:
+ case DK_IFLT:
+ case DK_IFNE:
+ return parseDirectiveIf(IDLoc, DirKind);
+ case DK_IFB:
+ return parseDirectiveIfb(IDLoc, true);
+ case DK_IFNB:
+ return parseDirectiveIfb(IDLoc, false);
+ case DK_IFC:
+ return parseDirectiveIfc(IDLoc, true);
+ case DK_IFEQS:
+ return parseDirectiveIfeqs(IDLoc, true);
+ case DK_IFNC:
+ return parseDirectiveIfc(IDLoc, false);
+ case DK_IFNES:
+ return parseDirectiveIfeqs(IDLoc, false);
+ case DK_IFDEF:
+ return parseDirectiveIfdef(IDLoc, true);
+ case DK_IFNDEF:
+ case DK_IFNOTDEF:
+ return parseDirectiveIfdef(IDLoc, false);
+ case DK_ELSEIF:
+ return parseDirectiveElseIf(IDLoc);
+ case DK_ELSE:
+ return parseDirectiveElse(IDLoc);
+ case DK_ENDIF:
+ return parseDirectiveEndIf(IDLoc);
+ }
+
+ // Ignore the statement if in the middle of inactive conditional
+ // (e.g. ".if 0").
+ if (TheCondState.Ignore) {
+ eatToEndOfStatement();
+ return false;
+ }
+
+ // FIXME: Recurse on local labels?
+
+ // See what kind of statement we have.
+ switch (Lexer.getKind()) {
+ case AsmToken::Colon: {
+ if (!getTargetParser().isLabel(ID))
+ break;
+ if (checkForValidSection())
+ return true;
+
+ // identifier ':' -> Label.
+ Lex();
+
+ // Diagnose attempt to use '.' as a label.
+ if (IDVal == ".")
+ return Error(IDLoc, "invalid use of pseudo-symbol '.' as a label");
+
+ // Diagnose attempt to use a variable as a label.
+ //
+ // FIXME: Diagnostics. Note the location of the definition as a label.
+ // FIXME: This doesn't diagnose assignment to a symbol which has been
+ // implicitly marked as external.
+ MCSymbol *Sym;
+ if (LocalLabelVal == -1) {
+ if (ParsingInlineAsm && SI) {
+ StringRef RewrittenLabel =
+ SI->LookupInlineAsmLabel(IDVal, getSourceManager(), IDLoc, true);
+ assert(!RewrittenLabel.empty() &&
+ "We should have an internal name here.");
+ Info.AsmRewrites->emplace_back(AOK_Label, IDLoc, IDVal.size(),
+ RewrittenLabel);
+ IDVal = RewrittenLabel;
+ }
+ Sym = getContext().getOrCreateSymbol(IDVal);
+ } else
+ Sym = Ctx.createDirectionalLocalSymbol(LocalLabelVal);
+ // End of Labels should be treated as end of line for lexing
+ // purposes but that information is not available to the Lexer who
+ // does not understand Labels. This may cause us to see a Hash
+ // here instead of a preprocessor line comment.
+ if (getTok().is(AsmToken::Hash)) {
+ StringRef CommentStr = parseStringToEndOfStatement();
+ Lexer.Lex();
+ Lexer.UnLex(AsmToken(AsmToken::EndOfStatement, CommentStr));
+ }
+
+ // Consume any end of statement token, if present, to avoid spurious
+ // AddBlankLine calls().
+ if (getTok().is(AsmToken::EndOfStatement)) {
+ Lex();
+ }
+
+ getTargetParser().doBeforeLabelEmit(Sym);
+
+ // Emit the label.
+ if (!getTargetParser().isParsingInlineAsm())
+ Out.EmitLabel(Sym, IDLoc);
+
+ // If we are generating dwarf for assembly source files then gather the
+ // info to make a dwarf label entry for this label if needed.
+ if (enabledGenDwarfForAssembly())
+ MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(),
+ IDLoc);
+
+ getTargetParser().onLabelParsed(Sym);
+
+ return false;
+ }
+
+ case AsmToken::Equal:
+ if (!getTargetParser().equalIsAsmAssignment())
+ break;
+ // identifier '=' ... -> assignment statement
+ Lex();
+
+ return parseAssignment(IDVal, true);
+
+ default: // Normal instruction or directive.
+ break;
+ }
+
+ // If macros are enabled, check to see if this is a macro instantiation.
+ if (areMacrosEnabled())
+ if (const MCAsmMacro *M = getContext().lookupMacro(IDVal)) {
+ return handleMacroEntry(M, IDLoc);
+ }
+
+ // Otherwise, we have a normal instruction or directive.
+
+ // Directives start with "."
+ if (IDVal.startswith(".") && IDVal != ".") {
+ // There are several entities interested in parsing directives:
+ //
+ // 1. The target-specific assembly parser. Some directives are target
+ // specific or may potentially behave differently on certain targets.
+ // 2. Asm parser extensions. For example, platform-specific parsers
+ // (like the ELF parser) register themselves as extensions.
+ // 3. The generic directive parser implemented by this class. These are
+ // all the directives that behave in a target and platform independent
+ // manner, or at least have a default behavior that's shared between
+ // all targets and platforms.
+
+ getTargetParser().flushPendingInstructions(getStreamer());
+
+ SMLoc StartTokLoc = getTok().getLoc();
+ bool TPDirectiveReturn = getTargetParser().ParseDirective(ID);
+
+ if (hasPendingError())
+ return true;
+ // Currently the return value should be true if we are
+ // uninterested but as this is at odds with the standard parsing
+ // convention (return true = error) we have instances of a parsed
+ // directive that fails returning true as an error. Catch these
+ // cases as best as possible errors here.
+ if (TPDirectiveReturn && StartTokLoc != getTok().getLoc())
+ return true;
+ // Return if we did some parsing or believe we succeeded.
+ if (!TPDirectiveReturn || StartTokLoc != getTok().getLoc())
+ return false;
+
+ // Next, check the extension directive map to see if any extension has
+ // registered itself to parse this directive.
+ std::pair<MCAsmParserExtension *, DirectiveHandler> Handler =
+ ExtensionDirectiveMap.lookup(IDVal);
+ if (Handler.first)
+ return (*Handler.second)(Handler.first, IDVal, IDLoc);
+
+ // Finally, if no one else is interested in this directive, it must be
+ // generic and familiar to this class.
+ switch (DirKind) {
+ default:
+ break;
+ case DK_SET:
+ case DK_EQU:
+ return parseDirectiveSet(IDVal, true);
+ case DK_EQUIV:
+ return parseDirectiveSet(IDVal, false);
+ case DK_ASCII:
+ return parseDirectiveAscii(IDVal, false);
+ case DK_ASCIZ:
+ case DK_STRING:
+ return parseDirectiveAscii(IDVal, true);
+ case DK_BYTE:
+ case DK_DC_B:
+ return parseDirectiveValue(IDVal, 1);
+ case DK_DC:
+ case DK_DC_W:
+ case DK_SHORT:
+ case DK_VALUE:
+ case DK_2BYTE:
+ return parseDirectiveValue(IDVal, 2);
+ case DK_LONG:
+ case DK_INT:
+ case DK_4BYTE:
+ case DK_DC_L:
+ return parseDirectiveValue(IDVal, 4);
+ case DK_QUAD:
+ case DK_8BYTE:
+ return parseDirectiveValue(IDVal, 8);
+ case DK_DC_A:
+ return parseDirectiveValue(
+ IDVal, getContext().getAsmInfo()->getCodePointerSize());
+ case DK_OCTA:
+ return parseDirectiveOctaValue(IDVal);
+ case DK_SINGLE:
+ case DK_FLOAT:
+ case DK_DC_S:
+ return parseDirectiveRealValue(IDVal, APFloat::IEEEsingle());
+ case DK_DOUBLE:
+ case DK_DC_D:
+ return parseDirectiveRealValue(IDVal, APFloat::IEEEdouble());
+ case DK_ALIGN: {
+ bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes();
+ return parseDirectiveAlign(IsPow2, /*ExprSize=*/1);
+ }
+ case DK_ALIGN32: {
+ bool IsPow2 = !getContext().getAsmInfo()->getAlignmentIsInBytes();
+ return parseDirectiveAlign(IsPow2, /*ExprSize=*/4);
+ }
+ case DK_BALIGN:
+ return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1);
+ case DK_BALIGNW:
+ return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/2);
+ case DK_BALIGNL:
+ return parseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/4);
+ case DK_P2ALIGN:
+ return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1);
+ case DK_P2ALIGNW:
+ return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/2);
+ case DK_P2ALIGNL:
+ return parseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4);
+ case DK_ORG:
+ return parseDirectiveOrg();
+ case DK_FILL:
+ return parseDirectiveFill();
+ case DK_ZERO:
+ return parseDirectiveZero();
+ case DK_EXTERN:
+ eatToEndOfStatement(); // .extern is the default, ignore it.
+ return false;
+ case DK_GLOBL:
+ case DK_GLOBAL:
+ return parseDirectiveSymbolAttribute(MCSA_Global);
+ case DK_LAZY_REFERENCE:
+ return parseDirectiveSymbolAttribute(MCSA_LazyReference);
+ case DK_NO_DEAD_STRIP:
+ return parseDirectiveSymbolAttribute(MCSA_NoDeadStrip);
+ case DK_SYMBOL_RESOLVER:
+ return parseDirectiveSymbolAttribute(MCSA_SymbolResolver);
+ case DK_PRIVATE_EXTERN:
+ return parseDirectiveSymbolAttribute(MCSA_PrivateExtern);
+ case DK_REFERENCE:
+ return parseDirectiveSymbolAttribute(MCSA_Reference);
+ case DK_WEAK_DEFINITION:
+ return parseDirectiveSymbolAttribute(MCSA_WeakDefinition);
+ case DK_WEAK_REFERENCE:
+ return parseDirectiveSymbolAttribute(MCSA_WeakReference);
+ case DK_WEAK_DEF_CAN_BE_HIDDEN:
+ return parseDirectiveSymbolAttribute(MCSA_WeakDefAutoPrivate);
+ case DK_COLD:
+ return parseDirectiveSymbolAttribute(MCSA_Cold);
+ case DK_COMM:
+ case DK_COMMON:
+ return parseDirectiveComm(/*IsLocal=*/false);
+ case DK_LCOMM:
+ return parseDirectiveComm(/*IsLocal=*/true);
+ case DK_ABORT:
+ return parseDirectiveAbort();
+ case DK_INCLUDE:
+ return parseDirectiveInclude();
+ case DK_INCBIN:
+ return parseDirectiveIncbin();
+ case DK_CODE16:
+ case DK_CODE16GCC:
+ return TokError(Twine(IDVal) +
+ " not currently supported for this target");
+ case DK_REPT:
+ return parseDirectiveRept(IDLoc, IDVal);
+ case DK_IRP:
+ return parseDirectiveIrp(IDLoc);
+ case DK_IRPC:
+ return parseDirectiveIrpc(IDLoc);
+ case DK_ENDR:
+ return parseDirectiveEndr(IDLoc);
+ case DK_BUNDLE_ALIGN_MODE:
+ return parseDirectiveBundleAlignMode();
+ case DK_BUNDLE_LOCK:
+ return parseDirectiveBundleLock();
+ case DK_BUNDLE_UNLOCK:
+ return parseDirectiveBundleUnlock();
+ case DK_SLEB128:
+ return parseDirectiveLEB128(true);
+ case DK_ULEB128:
+ return parseDirectiveLEB128(false);
+ case DK_SPACE:
+ case DK_SKIP:
+ return parseDirectiveSpace(IDVal);
+ case DK_FILE:
+ return parseDirectiveFile(IDLoc);
+ case DK_LINE:
+ return parseDirectiveLine();
+ case DK_LOC:
+ return parseDirectiveLoc();
+ case DK_STABS:
+ return parseDirectiveStabs();
+ case DK_CV_FILE:
+ return parseDirectiveCVFile();
+ case DK_CV_FUNC_ID:
+ return parseDirectiveCVFuncId();
+ case DK_CV_INLINE_SITE_ID:
+ return parseDirectiveCVInlineSiteId();
+ case DK_CV_LOC:
+ return parseDirectiveCVLoc();
+ case DK_CV_LINETABLE:
+ return parseDirectiveCVLinetable();
+ case DK_CV_INLINE_LINETABLE:
+ return parseDirectiveCVInlineLinetable();
+ case DK_CV_DEF_RANGE:
+ return parseDirectiveCVDefRange();
+ case DK_CV_STRING:
+ return parseDirectiveCVString();
+ case DK_CV_STRINGTABLE:
+ return parseDirectiveCVStringTable();
+ case DK_CV_FILECHECKSUMS:
+ return parseDirectiveCVFileChecksums();
+ case DK_CV_FILECHECKSUM_OFFSET:
+ return parseDirectiveCVFileChecksumOffset();
+ case DK_CV_FPO_DATA:
+ return parseDirectiveCVFPOData();
+ case DK_CFI_SECTIONS:
+ return parseDirectiveCFISections();
+ case DK_CFI_STARTPROC:
+ return parseDirectiveCFIStartProc();
+ case DK_CFI_ENDPROC:
+ return parseDirectiveCFIEndProc();
+ case DK_CFI_DEF_CFA:
+ return parseDirectiveCFIDefCfa(IDLoc);
+ case DK_CFI_DEF_CFA_OFFSET:
+ return parseDirectiveCFIDefCfaOffset();
+ case DK_CFI_ADJUST_CFA_OFFSET:
+ return parseDirectiveCFIAdjustCfaOffset();
+ case DK_CFI_DEF_CFA_REGISTER:
+ return parseDirectiveCFIDefCfaRegister(IDLoc);
+ case DK_CFI_OFFSET:
+ return parseDirectiveCFIOffset(IDLoc);
+ case DK_CFI_REL_OFFSET:
+ return parseDirectiveCFIRelOffset(IDLoc);
+ case DK_CFI_PERSONALITY:
+ return parseDirectiveCFIPersonalityOrLsda(true);
+ case DK_CFI_LSDA:
+ return parseDirectiveCFIPersonalityOrLsda(false);
+ case DK_CFI_REMEMBER_STATE:
+ return parseDirectiveCFIRememberState();
+ case DK_CFI_RESTORE_STATE:
+ return parseDirectiveCFIRestoreState();
+ case DK_CFI_SAME_VALUE:
+ return parseDirectiveCFISameValue(IDLoc);
+ case DK_CFI_RESTORE:
+ return parseDirectiveCFIRestore(IDLoc);
+ case DK_CFI_ESCAPE:
+ return parseDirectiveCFIEscape();
+ case DK_CFI_RETURN_COLUMN:
+ return parseDirectiveCFIReturnColumn(IDLoc);
+ case DK_CFI_SIGNAL_FRAME:
+ return parseDirectiveCFISignalFrame();
+ case DK_CFI_UNDEFINED:
+ return parseDirectiveCFIUndefined(IDLoc);
+ case DK_CFI_REGISTER:
+ return parseDirectiveCFIRegister(IDLoc);
+ case DK_CFI_WINDOW_SAVE:
+ return parseDirectiveCFIWindowSave();
+ case DK_MACROS_ON:
+ case DK_MACROS_OFF:
+ return parseDirectiveMacrosOnOff(IDVal);
+ case DK_MACRO:
+ return parseDirectiveMacro(IDLoc);
+ case DK_ALTMACRO:
+ case DK_NOALTMACRO:
+ return parseDirectiveAltmacro(IDVal);
+ case DK_EXITM:
+ return parseDirectiveExitMacro(IDVal);
+ case DK_ENDM:
+ case DK_ENDMACRO:
+ return parseDirectiveEndMacro(IDVal);
+ case DK_PURGEM:
+ return parseDirectivePurgeMacro(IDLoc);
+ case DK_END:
+ return parseDirectiveEnd(IDLoc);
+ case DK_ERR:
+ return parseDirectiveError(IDLoc, false);
+ case DK_ERROR:
+ return parseDirectiveError(IDLoc, true);
+ case DK_WARNING:
+ return parseDirectiveWarning(IDLoc);
+ case DK_RELOC:
+ return parseDirectiveReloc(IDLoc);
+ case DK_DCB:
+ case DK_DCB_W:
+ return parseDirectiveDCB(IDVal, 2);
+ case DK_DCB_B:
+ return parseDirectiveDCB(IDVal, 1);
+ case DK_DCB_D:
+ return parseDirectiveRealDCB(IDVal, APFloat::IEEEdouble());
+ case DK_DCB_L:
+ return parseDirectiveDCB(IDVal, 4);
+ case DK_DCB_S:
+ return parseDirectiveRealDCB(IDVal, APFloat::IEEEsingle());
+ case DK_DC_X:
+ case DK_DCB_X:
+ return TokError(Twine(IDVal) +
+ " not currently supported for this target");
+ case DK_DS:
+ case DK_DS_W:
+ return parseDirectiveDS(IDVal, 2);
+ case DK_DS_B:
+ return parseDirectiveDS(IDVal, 1);
+ case DK_DS_D:
+ return parseDirectiveDS(IDVal, 8);
+ case DK_DS_L:
+ case DK_DS_S:
+ return parseDirectiveDS(IDVal, 4);
+ case DK_DS_P:
+ case DK_DS_X:
+ return parseDirectiveDS(IDVal, 12);
+ case DK_PRINT:
+ return parseDirectivePrint(IDLoc);
+ case DK_ADDRSIG:
+ return parseDirectiveAddrsig();
+ case DK_ADDRSIG_SYM:
+ return parseDirectiveAddrsigSym();
+ }
+
+ return Error(IDLoc, "unknown directive");
+ }
+
+ // __asm _emit or __asm __emit
+ if (ParsingInlineAsm && (IDVal == "_emit" || IDVal == "__emit" ||
+ IDVal == "_EMIT" || IDVal == "__EMIT"))
+ return parseDirectiveMSEmit(IDLoc, Info, IDVal.size());
+
+ // __asm align
+ if (ParsingInlineAsm && (IDVal == "align" || IDVal == "ALIGN"))
+ return parseDirectiveMSAlign(IDLoc, Info);
+
+ if (ParsingInlineAsm && (IDVal == "even" || IDVal == "EVEN"))
+ Info.AsmRewrites->emplace_back(AOK_EVEN, IDLoc, 4);
+ if (checkForValidSection())
+ return true;
+
+ // Canonicalize the opcode to lower case.
+ std::string OpcodeStr = IDVal.lower();
+ ParseInstructionInfo IInfo(Info.AsmRewrites);
+ bool ParseHadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, ID,
+ Info.ParsedOperands);
+ Info.ParseError = ParseHadError;
+
+ // Dump the parsed representation, if requested.
+ if (getShowParsedOperands()) {
+ SmallString<256> Str;
+ raw_svector_ostream OS(Str);
+ OS << "parsed instruction: [";
+ for (unsigned i = 0; i != Info.ParsedOperands.size(); ++i) {
+ if (i != 0)
+ OS << ", ";
+ Info.ParsedOperands[i]->print(OS);
+ }
+ OS << "]";
+
+ printMessage(IDLoc, SourceMgr::DK_Note, OS.str());
+ }
+
+ // Fail even if ParseInstruction erroneously returns false.
+ if (hasPendingError() || ParseHadError)
+ return true;
+
+ // If we are generating dwarf for the current section then generate a .loc
+ // directive for the instruction.
+ if (!ParseHadError && enabledGenDwarfForAssembly() &&
+ getContext().getGenDwarfSectionSyms().count(
+ getStreamer().getCurrentSectionOnly())) {
+ unsigned Line;
+ if (ActiveMacros.empty())
+ Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer);
+ else
+ Line = SrcMgr.FindLineNumber(ActiveMacros.front()->InstantiationLoc,
+ ActiveMacros.front()->ExitBuffer);
+
+ // If we previously parsed a cpp hash file line comment then make sure the
+ // current Dwarf File is for the CppHashFilename if not then emit the
+ // Dwarf File table for it and adjust the line number for the .loc.
+ if (!CppHashInfo.Filename.empty()) {
+ unsigned FileNumber = getStreamer().EmitDwarfFileDirective(
+ 0, StringRef(), CppHashInfo.Filename);
+ getContext().setGenDwarfFileNumber(FileNumber);
+
+ unsigned CppHashLocLineNo =
+ SrcMgr.FindLineNumber(CppHashInfo.Loc, CppHashInfo.Buf);
+ Line = CppHashInfo.LineNumber - 1 + (Line - CppHashLocLineNo);
+ }
+
+ getStreamer().EmitDwarfLocDirective(
+ getContext().getGenDwarfFileNumber(), Line, 0,
+ DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, 0, 0,
+ StringRef());
+ }
+
+ // If parsing succeeded, match the instruction.
+ if (!ParseHadError) {
+ uint64_t ErrorInfo;
+ if (getTargetParser().MatchAndEmitInstruction(
+ IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo,
+ getTargetParser().isParsingInlineAsm()))
+ return true;
+ }
+ return false;
+}
+
+// Parse and erase curly braces marking block start/end
+bool
+AsmParser::parseCurlyBlockScope(SmallVectorImpl<AsmRewrite> &AsmStrRewrites) {
+ // Identify curly brace marking block start/end
+ if (Lexer.isNot(AsmToken::LCurly) && Lexer.isNot(AsmToken::RCurly))
+ return false;
+
+ SMLoc StartLoc = Lexer.getLoc();
+ Lex(); // Eat the brace
+ if (Lexer.is(AsmToken::EndOfStatement))
+ Lex(); // Eat EndOfStatement following the brace
+
+ // Erase the block start/end brace from the output asm string
+ AsmStrRewrites.emplace_back(AOK_Skip, StartLoc, Lexer.getLoc().getPointer() -
+ StartLoc.getPointer());
+ return true;
+}
+
+/// parseCppHashLineFilenameComment as this:
+/// ::= # number "filename"
+bool AsmParser::parseCppHashLineFilenameComment(SMLoc L) {
+ Lex(); // Eat the hash token.
+ // Lexer only ever emits HashDirective if it fully formed if it's
+ // done the checking already so this is an internal error.
+ assert(getTok().is(AsmToken::Integer) &&
+ "Lexing Cpp line comment: Expected Integer");
+ int64_t LineNumber = getTok().getIntVal();
+ Lex();
+ assert(getTok().is(AsmToken::String) &&
+ "Lexing Cpp line comment: Expected String");
+ StringRef Filename = getTok().getString();
+ Lex();
+
+ // Get rid of the enclosing quotes.
+ Filename = Filename.substr(1, Filename.size() - 2);
+
+ // Save the SMLoc, Filename and LineNumber for later use by diagnostics
+ // and possibly DWARF file info.
+ CppHashInfo.Loc = L;
+ CppHashInfo.Filename = Filename;
+ CppHashInfo.LineNumber = LineNumber;
+ CppHashInfo.Buf = CurBuffer;
+ if (FirstCppHashFilename.empty())
+ FirstCppHashFilename = Filename;
+ return false;
+}
+
+/// will use the last parsed cpp hash line filename comment
+/// for the Filename and LineNo if any in the diagnostic.
+void AsmParser::DiagHandler(const SMDiagnostic &Diag, void *Context) {
+ const AsmParser *Parser = static_cast<const AsmParser *>(Context);
+ raw_ostream &OS = errs();
+
+ const SourceMgr &DiagSrcMgr = *Diag.getSourceMgr();
+ SMLoc DiagLoc = Diag.getLoc();
+ unsigned DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);
+ unsigned CppHashBuf =
+ Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashInfo.Loc);
+
+ // Like SourceMgr::printMessage() we need to print the include stack if any
+ // before printing the message.
+ unsigned DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc);
+ if (!Parser->SavedDiagHandler && DiagCurBuffer &&
+ DiagCurBuffer != DiagSrcMgr.getMainFileID()) {
+ SMLoc ParentIncludeLoc = DiagSrcMgr.getParentIncludeLoc(DiagCurBuffer);
+ DiagSrcMgr.PrintIncludeStack(ParentIncludeLoc, OS);
+ }
+
+ // If we have not parsed a cpp hash line filename comment or the source
+ // manager changed or buffer changed (like in a nested include) then just
+ // print the normal diagnostic using its Filename and LineNo.
+ if (!Parser->CppHashInfo.LineNumber || &DiagSrcMgr != &Parser->SrcMgr ||
+ DiagBuf != CppHashBuf) {
+ if (Parser->SavedDiagHandler)
+ Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext);
+ else
+ Diag.print(nullptr, OS);
+ return;
+ }
+
+ // Use the CppHashFilename and calculate a line number based on the
+ // CppHashInfo.Loc and CppHashInfo.LineNumber relative to this Diag's SMLoc
+ // for the diagnostic.
+ const std::string &Filename = Parser->CppHashInfo.Filename;
+
+ int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf);
+ int CppHashLocLineNo =
+ Parser->SrcMgr.FindLineNumber(Parser->CppHashInfo.Loc, CppHashBuf);
+ int LineNo =
+ Parser->CppHashInfo.LineNumber - 1 + (DiagLocLineNo - CppHashLocLineNo);
+
+ SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), Filename, LineNo,
+ Diag.getColumnNo(), Diag.getKind(), Diag.getMessage(),
+ Diag.getLineContents(), Diag.getRanges());
+
+ if (Parser->SavedDiagHandler)
+ Parser->SavedDiagHandler(NewDiag, Parser->SavedDiagContext);
+ else
+ NewDiag.print(nullptr, OS);
+}
+
+// FIXME: This is mostly duplicated from the function in AsmLexer.cpp. The
+// difference being that that function accepts '@' as part of identifiers and
+// we can't do that. AsmLexer.cpp should probably be changed to handle
+// '@' as a special case when needed.
+static bool isIdentifierChar(char c) {
+ return isalnum(static_cast<unsigned char>(c)) || c == '_' || c == '$' ||
+ c == '.';
+}
+
+bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
+ ArrayRef<MCAsmMacroParameter> Parameters,
+ ArrayRef<MCAsmMacroArgument> A,
+ bool EnableAtPseudoVariable, SMLoc L) {
+ unsigned NParameters = Parameters.size();
+ bool HasVararg = NParameters ? Parameters.back().Vararg : false;
+ if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
+ return Error(L, "Wrong number of arguments");
+
+ // A macro without parameters is handled differently on Darwin:
+ // gas accepts no arguments and does no substitutions
+ while (!Body.empty()) {
+ // Scan for the next substitution.
+ std::size_t End = Body.size(), Pos = 0;
+ for (; Pos != End; ++Pos) {
+ // Check for a substitution or escape.
+ if (IsDarwin && !NParameters) {
+ // This macro has no parameters, look for $0, $1, etc.
+ if (Body[Pos] != '$' || Pos + 1 == End)
+ continue;
+
+ char Next = Body[Pos + 1];
+ if (Next == '$' || Next == 'n' ||
+ isdigit(static_cast<unsigned char>(Next)))
+ break;
+ } else {
+ // This macro has parameters, look for \foo, \bar, etc.
+ if (Body[Pos] == '\\' && Pos + 1 != End)
+ break;
+ }
+ }
+
+ // Add the prefix.
+ OS << Body.slice(0, Pos);
+
+ // Check if we reached the end.
+ if (Pos == End)
+ break;
+
+ if (IsDarwin && !NParameters) {
+ switch (Body[Pos + 1]) {
+ // $$ => $
+ case '$':
+ OS << '$';
+ break;
+
+ // $n => number of arguments
+ case 'n':
+ OS << A.size();
+ break;
+
+ // $[0-9] => argument
+ default: {
+ // Missing arguments are ignored.
+ unsigned Index = Body[Pos + 1] - '0';
+ if (Index >= A.size())
+ break;
+
+ // Otherwise substitute with the token values, with spaces eliminated.
+ for (const AsmToken &Token : A[Index])
+ OS << Token.getString();
+ break;
+ }
+ }
+ Pos += 2;
+ } else {
+ unsigned I = Pos + 1;
+
+ // Check for the \@ pseudo-variable.
+ if (EnableAtPseudoVariable && Body[I] == '@' && I + 1 != End)
+ ++I;
+ else
+ while (isIdentifierChar(Body[I]) && I + 1 != End)
+ ++I;
+
+ const char *Begin = Body.data() + Pos + 1;
+ StringRef Argument(Begin, I - (Pos + 1));
+ unsigned Index = 0;
+
+ if (Argument == "@") {
+ OS << NumOfMacroInstantiations;
+ Pos += 2;
+ } else {
+ for (; Index < NParameters; ++Index)
+ if (Parameters[Index].Name == Argument)
+ break;
+
+ if (Index == NParameters) {
+ if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')
+ Pos += 3;
+ else {
+ OS << '\\' << Argument;
+ Pos = I;
+ }
+ } else {
+ bool VarargParameter = HasVararg && Index == (NParameters - 1);
+ for (const AsmToken &Token : A[Index])
+ // For altmacro mode, you can write '%expr'.
+ // The prefix '%' evaluates the expression 'expr'
+ // and uses the result as a string (e.g. replace %(1+2) with the
+ // string "3").
+ // Here, we identify the integer token which is the result of the
+ // absolute expression evaluation and replace it with its string
+ // representation.
+ if (AltMacroMode && Token.getString().front() == '%' &&
+ Token.is(AsmToken::Integer))
+ // Emit an integer value to the buffer.
+ OS << Token.getIntVal();
+ // Only Token that was validated as a string and begins with '<'
+ // is considered altMacroString!!!
+ else if (AltMacroMode && Token.getString().front() == '<' &&
+ Token.is(AsmToken::String)) {
+ OS << altMacroString(Token.getStringContents());
+ }
+ // We expect no quotes around the string's contents when
+ // parsing for varargs.
+ else if (Token.isNot(AsmToken::String) || VarargParameter)
+ OS << Token.getString();
+ else
+ OS << Token.getStringContents();
+
+ Pos += 1 + Argument.size();
+ }
+ }
+ }
+ // Update the scan point.
+ Body = Body.substr(Pos);
+ }
+
+ return false;
+}
+
+MacroInstantiation::MacroInstantiation(SMLoc IL, int EB, SMLoc EL,
+ size_t CondStackDepth)
+ : InstantiationLoc(IL), ExitBuffer(EB), ExitLoc(EL),
+ CondStackDepth(CondStackDepth) {}
+
+static bool isOperator(AsmToken::TokenKind kind) {
+ switch (kind) {
+ default:
+ return false;
+ case AsmToken::Plus:
+ case AsmToken::Minus:
+ case AsmToken::Tilde:
+ case AsmToken::Slash:
+ case AsmToken::Star:
+ case AsmToken::Dot:
+ case AsmToken::Equal:
+ case AsmToken::EqualEqual:
+ case AsmToken::Pipe:
+ case AsmToken::PipePipe:
+ case AsmToken::Caret:
+ case AsmToken::Amp:
+ case AsmToken::AmpAmp:
+ case AsmToken::Exclaim:
+ case AsmToken::ExclaimEqual:
+ case AsmToken::Less:
+ case AsmToken::LessEqual:
+ case AsmToken::LessLess:
+ case AsmToken::LessGreater:
+ case AsmToken::Greater:
+ case AsmToken::GreaterEqual:
+ case AsmToken::GreaterGreater:
+ return true;
+ }
+}
+
+namespace {
+
+class AsmLexerSkipSpaceRAII {
+public:
+ AsmLexerSkipSpaceRAII(AsmLexer &Lexer, bool SkipSpace) : Lexer(Lexer) {
+ Lexer.setSkipSpace(SkipSpace);
+ }
+
+ ~AsmLexerSkipSpaceRAII() {
+ Lexer.setSkipSpace(true);
+ }
+
+private:
+ AsmLexer &Lexer;
+};
+
+} // end anonymous namespace
+
+bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, bool Vararg) {
+
+ if (Vararg) {
+ if (Lexer.isNot(AsmToken::EndOfStatement)) {
+ StringRef Str = parseStringToEndOfStatement();
+ MA.emplace_back(AsmToken::String, Str);
+ }
+ return false;
+ }
+
+ unsigned ParenLevel = 0;
+
+ // Darwin doesn't use spaces to delmit arguments.
+ AsmLexerSkipSpaceRAII ScopedSkipSpace(Lexer, IsDarwin);
+
+ bool SpaceEaten;
+
+ while (true) {
+ SpaceEaten = false;
+ if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal))
+ return TokError("unexpected token in macro instantiation");
+
+ if (ParenLevel == 0) {
+
+ if (Lexer.is(AsmToken::Comma))
+ break;
+
+ if (Lexer.is(AsmToken::Space)) {
+ SpaceEaten = true;
+ Lexer.Lex(); // Eat spaces
+ }
+
+ // Spaces can delimit parameters, but could also be part an expression.
+ // If the token after a space is an operator, add the token and the next
+ // one into this argument
+ if (!IsDarwin) {
+ if (isOperator(Lexer.getKind())) {
+ MA.push_back(getTok());
+ Lexer.Lex();
+
+ // Whitespace after an operator can be ignored.
+ if (Lexer.is(AsmToken::Space))
+ Lexer.Lex();
+
+ continue;
+ }
+ }
+ if (SpaceEaten)
+ break;
+ }
+
+ // handleMacroEntry relies on not advancing the lexer here
+ // to be able to fill in the remaining default parameter values
+ if (Lexer.is(AsmToken::EndOfStatement))
+ break;
+
+ // Adjust the current parentheses level.
+ if (Lexer.is(AsmToken::LParen))
+ ++ParenLevel;
+ else if (Lexer.is(AsmToken::RParen) && ParenLevel)
+ --ParenLevel;
+
+ // Append the token to the current argument list.
+ MA.push_back(getTok());
+ Lexer.Lex();
+ }
+
+ if (ParenLevel != 0)
+ return TokError("unbalanced parentheses in macro argument");
+ return false;
+}
+
+// Parse the macro instantiation arguments.
+bool AsmParser::parseMacroArguments(const MCAsmMacro *M,
+ MCAsmMacroArguments &A) {
+ const unsigned NParameters = M ? M->Parameters.size() : 0;
+ bool NamedParametersFound = false;
+ SmallVector<SMLoc, 4> FALocs;
+
+ A.resize(NParameters);
+ FALocs.resize(NParameters);
+
+ // Parse two kinds of macro invocations:
+ // - macros defined without any parameters accept an arbitrary number of them
+ // - macros defined with parameters accept at most that many of them
+ bool HasVararg = NParameters ? M->Parameters.back().Vararg : false;
+ for (unsigned Parameter = 0; !NParameters || Parameter < NParameters;
+ ++Parameter) {
+ SMLoc IDLoc = Lexer.getLoc();
+ MCAsmMacroParameter FA;
+
+ if (Lexer.is(AsmToken::Identifier) && Lexer.peekTok().is(AsmToken::Equal)) {
+ if (parseIdentifier(FA.Name))
+ return Error(IDLoc, "invalid argument identifier for formal argument");
+
+ if (Lexer.isNot(AsmToken::Equal))
+ return TokError("expected '=' after formal parameter identifier");
+
+ Lex();
+
+ NamedParametersFound = true;
+ }
+ bool Vararg = HasVararg && Parameter == (NParameters - 1);
+
+ if (NamedParametersFound && FA.Name.empty())
+ return Error(IDLoc, "cannot mix positional and keyword arguments");
+
+ SMLoc StrLoc = Lexer.getLoc();
+ SMLoc EndLoc;
+ if (AltMacroMode && Lexer.is(AsmToken::Percent)) {
+ const MCExpr *AbsoluteExp;
+ int64_t Value;
+ /// Eat '%'
+ Lex();
+ if (parseExpression(AbsoluteExp, EndLoc))
+ return false;
+ if (!AbsoluteExp->evaluateAsAbsolute(Value,
+ getStreamer().getAssemblerPtr()))
+ return Error(StrLoc, "expected absolute expression");
+ const char *StrChar = StrLoc.getPointer();
+ const char *EndChar = EndLoc.getPointer();
+ AsmToken newToken(AsmToken::Integer,
+ StringRef(StrChar, EndChar - StrChar), Value);
+ FA.Value.push_back(newToken);
+ } else if (AltMacroMode && Lexer.is(AsmToken::Less) &&
+ isAltmacroString(StrLoc, EndLoc)) {
+ const char *StrChar = StrLoc.getPointer();
+ const char *EndChar = EndLoc.getPointer();
+ jumpToLoc(EndLoc, CurBuffer);
+ /// Eat from '<' to '>'
+ Lex();
+ AsmToken newToken(AsmToken::String,
+ StringRef(StrChar, EndChar - StrChar));
+ FA.Value.push_back(newToken);
+ } else if(parseMacroArgument(FA.Value, Vararg))
+ return true;
+
+ unsigned PI = Parameter;
+ if (!FA.Name.empty()) {
+ unsigned FAI = 0;
+ for (FAI = 0; FAI < NParameters; ++FAI)
+ if (M->Parameters[FAI].Name == FA.Name)
+ break;
+
+ if (FAI >= NParameters) {
+ assert(M && "expected macro to be defined");
+ return Error(IDLoc, "parameter named '" + FA.Name +
+ "' does not exist for macro '" + M->Name + "'");
+ }
+ PI = FAI;
+ }
+
+ if (!FA.Value.empty()) {
+ if (A.size() <= PI)
+ A.resize(PI + 1);
+ A[PI] = FA.Value;
+
+ if (FALocs.size() <= PI)
+ FALocs.resize(PI + 1);
+
+ FALocs[PI] = Lexer.getLoc();
+ }
+
+ // At the end of the statement, fill in remaining arguments that have
+ // default values. If there aren't any, then the next argument is
+ // required but missing
+ if (Lexer.is(AsmToken::EndOfStatement)) {
+ bool Failure = false;
+ for (unsigned FAI = 0; FAI < NParameters; ++FAI) {
+ if (A[FAI].empty()) {
+ if (M->Parameters[FAI].Required) {
+ Error(FALocs[FAI].isValid() ? FALocs[FAI] : Lexer.getLoc(),
+ "missing value for required parameter "
+ "'" + M->Parameters[FAI].Name + "' in macro '" + M->Name + "'");
+ Failure = true;
+ }
+
+ if (!M->Parameters[FAI].Value.empty())
+ A[FAI] = M->Parameters[FAI].Value;
+ }
+ }
+ return Failure;
+ }
+
+ if (Lexer.is(AsmToken::Comma))
+ Lex();
+ }
+
+ return TokError("too many positional arguments");
+}
+
+bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) {
+ // Arbitrarily limit macro nesting depth (default matches 'as'). We can
+ // eliminate this, although we should protect against infinite loops.
+ unsigned MaxNestingDepth = AsmMacroMaxNestingDepth;
+ if (ActiveMacros.size() == MaxNestingDepth) {
+ std::ostringstream MaxNestingDepthError;
+ MaxNestingDepthError << "macros cannot be nested more than "
+ << MaxNestingDepth << " levels deep."
+ << " Use -asm-macro-max-nesting-depth to increase "
+ "this limit.";
+ return TokError(MaxNestingDepthError.str());
+ }
+
+ MCAsmMacroArguments A;
+ if (parseMacroArguments(M, A))
+ return true;
+
+ // Macro instantiation is lexical, unfortunately. We construct a new buffer
+ // to hold the macro body with substitutions.
+ SmallString<256> Buf;
+ StringRef Body = M->Body;
+ raw_svector_ostream OS(Buf);
+
+ if (expandMacro(OS, Body, M->Parameters, A, true, getTok().getLoc()))
+ return true;
+
+ // We include the .endmacro in the buffer as our cue to exit the macro
+ // instantiation.
+ OS << ".endmacro\n";
+
+ std::unique_ptr<MemoryBuffer> Instantiation =
+ MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
+
+ // Create the macro instantiation object and add to the current macro
+ // instantiation stack.
+ MacroInstantiation *MI = new MacroInstantiation(
+ NameLoc, CurBuffer, getTok().getLoc(), TheCondStack.size());
+ ActiveMacros.push_back(MI);
+
+ ++NumOfMacroInstantiations;
+
+ // Jump to the macro instantiation and prime the lexer.
+ CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
+ Lex();
+
+ return false;
+}
+
+void AsmParser::handleMacroExit() {
+ // Jump to the EndOfStatement we should return to, and consume it.
+ jumpToLoc(ActiveMacros.back()->ExitLoc, ActiveMacros.back()->ExitBuffer);
+ Lex();
+
+ // Pop the instantiation entry.
+ delete ActiveMacros.back();
+ ActiveMacros.pop_back();
+}
+
+bool AsmParser::parseAssignment(StringRef Name, bool allow_redef,
+ bool NoDeadStrip) {
+ MCSymbol *Sym;
+ const MCExpr *Value;
+ if (MCParserUtils::parseAssignmentExpression(Name, allow_redef, *this, Sym,
+ Value))
+ return true;
+
+ if (!Sym) {
+ // In the case where we parse an expression starting with a '.', we will
+ // not generate an error, nor will we create a symbol. In this case we
+ // should just return out.
+ return false;
+ }
+
+ // Do the assignment.
+ Out.EmitAssignment(Sym, Value);
+ if (NoDeadStrip)
+ Out.EmitSymbolAttribute(Sym, MCSA_NoDeadStrip);
+
+ return false;
+}
+
+/// parseIdentifier:
+/// ::= identifier
+/// ::= string
+bool AsmParser::parseIdentifier(StringRef &Res) {
+ // The assembler has relaxed rules for accepting identifiers, in particular we
+ // allow things like '.globl $foo' and '.def @feat.00', which would normally be
+ // separate tokens. At this level, we have already lexed so we cannot (currently)
+ // handle this as a context dependent token, instead we detect adjacent tokens
+ // and return the combined identifier.
+ if (Lexer.is(AsmToken::Dollar) || Lexer.is(AsmToken::At)) {
+ SMLoc PrefixLoc = getLexer().getLoc();
+
+ // Consume the prefix character, and check for a following identifier.
+
+ AsmToken Buf[1];
+ Lexer.peekTokens(Buf, false);
+
+ if (Buf[0].isNot(AsmToken::Identifier))
+ return true;
+
+ // We have a '$' or '@' followed by an identifier, make sure they are adjacent.
+ if (PrefixLoc.getPointer() + 1 != Buf[0].getLoc().getPointer())
+ return true;
+
+ // eat $ or @
+ Lexer.Lex(); // Lexer's Lex guarantees consecutive token.
+ // Construct the joined identifier and consume the token.
+ Res =
+ StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1);
+ Lex(); // Parser Lex to maintain invariants.
+ return false;
+ }
+
+ if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String))
+ return true;
+
+ Res = getTok().getIdentifier();
+
+ Lex(); // Consume the identifier token.
+
+ return false;
+}
+
+/// parseDirectiveSet:
+/// ::= .equ identifier ',' expression
+/// ::= .equiv identifier ',' expression
+/// ::= .set identifier ',' expression
+bool AsmParser::parseDirectiveSet(StringRef IDVal, bool allow_redef) {
+ StringRef Name;
+ if (check(parseIdentifier(Name), "expected identifier") ||
+ parseToken(AsmToken::Comma) || parseAssignment(Name, allow_redef, true))
+ return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+ return false;
+}
+
+bool AsmParser::parseEscapedString(std::string &Data) {
+ if (check(getTok().isNot(AsmToken::String), "expected string"))
+ return true;
+
+ Data = "";
+ StringRef Str = getTok().getStringContents();
+ for (unsigned i = 0, e = Str.size(); i != e; ++i) {
+ if (Str[i] != '\\') {
+ Data += Str[i];
+ continue;
+ }
+
+ // Recognize escaped characters. Note that this escape semantics currently
+ // loosely follows Darwin 'as'.
+ ++i;
+ if (i == e)
+ return TokError("unexpected backslash at end of string");
+
+ // Recognize hex sequences similarly to GNU 'as'.
+ if (Str[i] == 'x' || Str[i] == 'X') {
+ size_t length = Str.size();
+ if (i + 1 >= length || !isHexDigit(Str[i + 1]))
+ return TokError("invalid hexadecimal escape sequence");
+
+ // Consume hex characters. GNU 'as' reads all hexadecimal characters and
+ // then truncates to the lower 16 bits. Seems reasonable.
+ unsigned Value = 0;
+ while (i + 1 < length && isHexDigit(Str[i + 1]))
+ Value = Value * 16 + hexDigitValue(Str[++i]);
+
+ Data += (unsigned char)(Value & 0xFF);
+ continue;
+ }
+
+ // Recognize octal sequences.
+ if ((unsigned)(Str[i] - '0') <= 7) {
+ // Consume up to three octal characters.
+ unsigned Value = Str[i] - '0';
+
+ if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {
+ ++i;
+ Value = Value * 8 + (Str[i] - '0');
+
+ if (i + 1 != e && ((unsigned)(Str[i + 1] - '0')) <= 7) {
+ ++i;
+ Value = Value * 8 + (Str[i] - '0');
+ }
+ }
+
+ if (Value > 255)
+ return TokError("invalid octal escape sequence (out of range)");
+
+ Data += (unsigned char)Value;
+ continue;
+ }
+
+ // Otherwise recognize individual escapes.
+ switch (Str[i]) {
+ default:
+ // Just reject invalid escape sequences for now.
+ return TokError("invalid escape sequence (unrecognized character)");
+
+ case 'b': Data += '\b'; break;
+ case 'f': Data += '\f'; break;
+ case 'n': Data += '\n'; break;
+ case 'r': Data += '\r'; break;
+ case 't': Data += '\t'; break;
+ case '"': Data += '"'; break;
+ case '\\': Data += '\\'; break;
+ }
+ }
+
+ Lex();
+ return false;
+}
+
+/// parseDirectiveAscii:
+/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ]
+bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) {
+ auto parseOp = [&]() -> bool {
+ std::string Data;
+ if (checkForValidSection() || parseEscapedString(Data))
+ return true;
+ getStreamer().EmitBytes(Data);
+ if (ZeroTerminated)
+ getStreamer().EmitBytes(StringRef("\0", 1));
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+ return false;
+}
+
+/// parseDirectiveReloc
+/// ::= .reloc expression , identifier [ , expression ]
+bool AsmParser::parseDirectiveReloc(SMLoc DirectiveLoc) {
+ const MCExpr *Offset;
+ const MCExpr *Expr = nullptr;
+ int64_t OffsetValue;
+ SMLoc OffsetLoc = Lexer.getTok().getLoc();
+
+ if (parseExpression(Offset))
+ return true;
+
+ if ((Offset->evaluateAsAbsolute(OffsetValue,
+ getStreamer().getAssemblerPtr()) &&
+ check(OffsetValue < 0, OffsetLoc, "expression is negative")) ||
+ (check(Offset->getKind() != llvm::MCExpr::Constant &&
+ Offset->getKind() != llvm::MCExpr::SymbolRef,
+ OffsetLoc, "expected non-negative number or a label")) ||
+ (parseToken(AsmToken::Comma, "expected comma") ||
+ check(getTok().isNot(AsmToken::Identifier), "expected relocation name")))
+ return true;
+
+ SMLoc NameLoc = Lexer.getTok().getLoc();
+ StringRef Name = Lexer.getTok().getIdentifier();
+ Lex();
+
+ if (Lexer.is(AsmToken::Comma)) {
+ Lex();
+ SMLoc ExprLoc = Lexer.getLoc();
+ if (parseExpression(Expr))
+ return true;
+
+ MCValue Value;
+ if (!Expr->evaluateAsRelocatable(Value, nullptr, nullptr))
+ return Error(ExprLoc, "expression must be relocatable");
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in .reloc directive"))
+ return true;
+
+ const MCTargetAsmParser &MCT = getTargetParser();
+ const MCSubtargetInfo &STI = MCT.getSTI();
+ if (getStreamer().EmitRelocDirective(*Offset, Name, Expr, DirectiveLoc, STI))
+ return Error(NameLoc, "unknown relocation name");
+
+ return false;
+}
+
+/// parseDirectiveValue
+/// ::= (.byte | .short | ... ) [ expression (, expression)* ]
+bool AsmParser::parseDirectiveValue(StringRef IDVal, unsigned Size) {
+ auto parseOp = [&]() -> bool {
+ const MCExpr *Value;
+ SMLoc ExprLoc = getLexer().getLoc();
+ if (checkForValidSection() || parseExpression(Value))
+ return true;
+ // Special case constant expressions to match code generator.
+ if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
+ assert(Size <= 8 && "Invalid size");
+ uint64_t IntValue = MCE->getValue();
+ if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
+ return Error(ExprLoc, "out of range literal value");
+ getStreamer().EmitIntValue(IntValue, Size);
+ } else
+ getStreamer().EmitValue(Value, Size, ExprLoc);
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+ return false;
+}
+
+static bool parseHexOcta(AsmParser &Asm, uint64_t &hi, uint64_t &lo) {
+ if (Asm.getTok().isNot(AsmToken::Integer) &&
+ Asm.getTok().isNot(AsmToken::BigNum))
+ return Asm.TokError("unknown token in expression");
+ SMLoc ExprLoc = Asm.getTok().getLoc();
+ APInt IntValue = Asm.getTok().getAPIntVal();
+ Asm.Lex();
+ if (!IntValue.isIntN(128))
+ return Asm.Error(ExprLoc, "out of range literal value");
+ if (!IntValue.isIntN(64)) {
+ hi = IntValue.getHiBits(IntValue.getBitWidth() - 64).getZExtValue();
+ lo = IntValue.getLoBits(64).getZExtValue();
+ } else {
+ hi = 0;
+ lo = IntValue.getZExtValue();
+ }
+ return false;
+}
+
+/// ParseDirectiveOctaValue
+/// ::= .octa [ hexconstant (, hexconstant)* ]
+
+bool AsmParser::parseDirectiveOctaValue(StringRef IDVal) {
+ auto parseOp = [&]() -> bool {
+ if (checkForValidSection())
+ return true;
+ uint64_t hi, lo;
+ if (parseHexOcta(*this, hi, lo))
+ return true;
+ if (MAI.isLittleEndian()) {
+ getStreamer().EmitIntValue(lo, 8);
+ getStreamer().EmitIntValue(hi, 8);
+ } else {
+ getStreamer().EmitIntValue(hi, 8);
+ getStreamer().EmitIntValue(lo, 8);
+ }
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+ return false;
+}
+
+bool AsmParser::parseRealValue(const fltSemantics &Semantics, APInt &Res) {
+ // We don't truly support arithmetic on floating point expressions, so we
+ // have to manually parse unary prefixes.
+ bool IsNeg = false;
+ if (getLexer().is(AsmToken::Minus)) {
+ Lexer.Lex();
+ IsNeg = true;
+ } else if (getLexer().is(AsmToken::Plus))
+ Lexer.Lex();
+
+ if (Lexer.is(AsmToken::Error))
+ return TokError(Lexer.getErr());
+ if (Lexer.isNot(AsmToken::Integer) && Lexer.isNot(AsmToken::Real) &&
+ Lexer.isNot(AsmToken::Identifier))
+ return TokError("unexpected token in directive");
+
+ // Convert to an APFloat.
+ APFloat Value(Semantics);
+ StringRef IDVal = getTok().getString();
+ if (getLexer().is(AsmToken::Identifier)) {
+ if (!IDVal.compare_lower("infinity") || !IDVal.compare_lower("inf"))
+ Value = APFloat::getInf(Semantics);
+ else if (!IDVal.compare_lower("nan"))
+ Value = APFloat::getNaN(Semantics, false, ~0);
+ else
+ return TokError("invalid floating point literal");
+ } else if (Value.convertFromString(IDVal, APFloat::rmNearestTiesToEven) ==
+ APFloat::opInvalidOp)
+ return TokError("invalid floating point literal");
+ if (IsNeg)
+ Value.changeSign();
+
+ // Consume the numeric token.
+ Lex();
+
+ Res = Value.bitcastToAPInt();
+
+ return false;
+}
+
+/// parseDirectiveRealValue
+/// ::= (.single | .double) [ expression (, expression)* ]
+bool AsmParser::parseDirectiveRealValue(StringRef IDVal,
+ const fltSemantics &Semantics) {
+ auto parseOp = [&]() -> bool {
+ APInt AsInt;
+ if (checkForValidSection() || parseRealValue(Semantics, AsInt))
+ return true;
+ getStreamer().EmitIntValue(AsInt.getLimitedValue(),
+ AsInt.getBitWidth() / 8);
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in '" + Twine(IDVal) + "' directive");
+ return false;
+}
+
+/// parseDirectiveZero
+/// ::= .zero expression
+bool AsmParser::parseDirectiveZero() {
+ SMLoc NumBytesLoc = Lexer.getLoc();
+ const MCExpr *NumBytes;
+ if (checkForValidSection() || parseExpression(NumBytes))
+ return true;
+
+ int64_t Val = 0;
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+ if (parseAbsoluteExpression(Val))
+ return true;
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.zero' directive"))
+ return true;
+ getStreamer().emitFill(*NumBytes, Val, NumBytesLoc);
+
+ return false;
+}
+
+/// parseDirectiveFill
+/// ::= .fill expression [ , expression [ , expression ] ]
+bool AsmParser::parseDirectiveFill() {
+ SMLoc NumValuesLoc = Lexer.getLoc();
+ const MCExpr *NumValues;
+ if (checkForValidSection() || parseExpression(NumValues))
+ return true;
+
+ int64_t FillSize = 1;
+ int64_t FillExpr = 0;
+
+ SMLoc SizeLoc, ExprLoc;
+
+ if (parseOptionalToken(AsmToken::Comma)) {
+ SizeLoc = getTok().getLoc();
+ if (parseAbsoluteExpression(FillSize))
+ return true;
+ if (parseOptionalToken(AsmToken::Comma)) {
+ ExprLoc = getTok().getLoc();
+ if (parseAbsoluteExpression(FillExpr))
+ return true;
+ }
+ }
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.fill' directive"))
+ return true;
+
+ if (FillSize < 0) {
+ Warning(SizeLoc, "'.fill' directive with negative size has no effect");
+ return false;
+ }
+ if (FillSize > 8) {
+ Warning(SizeLoc, "'.fill' directive with size greater than 8 has been truncated to 8");
+ FillSize = 8;
+ }
+
+ if (!isUInt<32>(FillExpr) && FillSize > 4)
+ Warning(ExprLoc, "'.fill' directive pattern has been truncated to 32-bits");
+
+ getStreamer().emitFill(*NumValues, FillSize, FillExpr, NumValuesLoc);
+
+ return false;
+}
+
+/// parseDirectiveOrg
+/// ::= .org expression [ , expression ]
+bool AsmParser::parseDirectiveOrg() {
+ const MCExpr *Offset;
+ SMLoc OffsetLoc = Lexer.getLoc();
+ if (checkForValidSection() || parseExpression(Offset))
+ return true;
+
+ // Parse optional fill expression.
+ int64_t FillExpr = 0;
+ if (parseOptionalToken(AsmToken::Comma))
+ if (parseAbsoluteExpression(FillExpr))
+ return addErrorSuffix(" in '.org' directive");
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.org' directive");
+
+ getStreamer().emitValueToOffset(Offset, FillExpr, OffsetLoc);
+ return false;
+}
+
+/// parseDirectiveAlign
+/// ::= {.align, ...} expression [ , expression [ , expression ]]
+bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) {
+ SMLoc AlignmentLoc = getLexer().getLoc();
+ int64_t Alignment;
+ SMLoc MaxBytesLoc;
+ bool HasFillExpr = false;
+ int64_t FillExpr = 0;
+ int64_t MaxBytesToFill = 0;
+
+ auto parseAlign = [&]() -> bool {
+ if (parseAbsoluteExpression(Alignment))
+ return true;
+ if (parseOptionalToken(AsmToken::Comma)) {
+ // The fill expression can be omitted while specifying a maximum number of
+ // alignment bytes, e.g:
+ // .align 3,,4
+ if (getTok().isNot(AsmToken::Comma)) {
+ HasFillExpr = true;
+ if (parseAbsoluteExpression(FillExpr))
+ return true;
+ }
+ if (parseOptionalToken(AsmToken::Comma))
+ if (parseTokenLoc(MaxBytesLoc) ||
+ parseAbsoluteExpression(MaxBytesToFill))
+ return true;
+ }
+ return parseToken(AsmToken::EndOfStatement);
+ };
+
+ if (checkForValidSection())
+ return addErrorSuffix(" in directive");
+ // Ignore empty '.p2align' directives for GNU-as compatibility
+ if (IsPow2 && (ValueSize == 1) && getTok().is(AsmToken::EndOfStatement)) {
+ Warning(AlignmentLoc, "p2align directive with no operand(s) is ignored");
+ return parseToken(AsmToken::EndOfStatement);
+ }
+ if (parseAlign())
+ return addErrorSuffix(" in directive");
+
+ // Always emit an alignment here even if we thrown an error.
+ bool ReturnVal = false;
+
+ // Compute alignment in bytes.
+ if (IsPow2) {
+ // FIXME: Diagnose overflow.
+ if (Alignment >= 32) {
+ ReturnVal |= Error(AlignmentLoc, "invalid alignment value");
+ Alignment = 31;
+ }
+
+ Alignment = 1ULL << Alignment;
+ } else {
+ // Reject alignments that aren't either a power of two or zero,
+ // for gas compatibility. Alignment of zero is silently rounded
+ // up to one.
+ if (Alignment == 0)
+ Alignment = 1;
+ if (!isPowerOf2_64(Alignment))
+ ReturnVal |= Error(AlignmentLoc, "alignment must be a power of 2");
+ }
+
+ // Diagnose non-sensical max bytes to align.
+ if (MaxBytesLoc.isValid()) {
+ if (MaxBytesToFill < 1) {
+ ReturnVal |= Error(MaxBytesLoc,
+ "alignment directive can never be satisfied in this "
+ "many bytes, ignoring maximum bytes expression");
+ MaxBytesToFill = 0;
+ }
+
+ if (MaxBytesToFill >= Alignment) {
+ Warning(MaxBytesLoc, "maximum bytes expression exceeds alignment and "
+ "has no effect");
+ MaxBytesToFill = 0;
+ }
+ }
+
+ // Check whether we should use optimal code alignment for this .align
+ // directive.
+ const MCSection *Section = getStreamer().getCurrentSectionOnly();
+ assert(Section && "must have section to emit alignment");
+ bool UseCodeAlign = Section->UseCodeAlign();
+ if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) &&
+ ValueSize == 1 && UseCodeAlign) {
+ getStreamer().EmitCodeAlignment(Alignment, MaxBytesToFill);
+ } else {
+ // FIXME: Target specific behavior about how the "extra" bytes are filled.
+ getStreamer().EmitValueToAlignment(Alignment, FillExpr, ValueSize,
+ MaxBytesToFill);
+ }
+
+ return ReturnVal;
+}
+
+/// parseDirectiveFile
+/// ::= .file filename
+/// ::= .file number [directory] filename [md5 checksum] [source source-text]
+bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) {
+ // FIXME: I'm not sure what this is.
+ int64_t FileNumber = -1;
+ if (getLexer().is(AsmToken::Integer)) {
+ FileNumber = getTok().getIntVal();
+ Lex();
+
+ if (FileNumber < 0)
+ return TokError("negative file number");
+ }
+
+ std::string Path;
+
+ // Usually the directory and filename together, otherwise just the directory.
+ // Allow the strings to have escaped octal character sequence.
+ if (check(getTok().isNot(AsmToken::String),
+ "unexpected token in '.file' directive") ||
+ parseEscapedString(Path))
+ return true;
+
+ StringRef Directory;
+ StringRef Filename;
+ std::string FilenameData;
+ if (getLexer().is(AsmToken::String)) {
+ if (check(FileNumber == -1,
+ "explicit path specified, but no file number") ||
+ parseEscapedString(FilenameData))
+ return true;
+ Filename = FilenameData;
+ Directory = Path;
+ } else {
+ Filename = Path;
+ }
+
+ uint64_t MD5Hi, MD5Lo;
+ bool HasMD5 = false;
+
+ Optional<StringRef> Source;
+ bool HasSource = false;
+ std::string SourceString;
+
+ while (!parseOptionalToken(AsmToken::EndOfStatement)) {
+ StringRef Keyword;
+ if (check(getTok().isNot(AsmToken::Identifier),
+ "unexpected token in '.file' directive") ||
+ parseIdentifier(Keyword))
+ return true;
+ if (Keyword == "md5") {
+ HasMD5 = true;
+ if (check(FileNumber == -1,
+ "MD5 checksum specified, but no file number") ||
+ parseHexOcta(*this, MD5Hi, MD5Lo))
+ return true;
+ } else if (Keyword == "source") {
+ HasSource = true;
+ if (check(FileNumber == -1,
+ "source specified, but no file number") ||
+ check(getTok().isNot(AsmToken::String),
+ "unexpected token in '.file' directive") ||
+ parseEscapedString(SourceString))
+ return true;
+ } else {
+ return TokError("unexpected token in '.file' directive");
+ }
+ }
+
+ if (FileNumber == -1) {
+ // Ignore the directive if there is no number and the target doesn't support
+ // numberless .file directives. This allows some portability of assembler
+ // between different object file formats.
+ if (getContext().getAsmInfo()->hasSingleParameterDotFile())
+ getStreamer().EmitFileDirective(Filename);
+ } else {
+ // In case there is a -g option as well as debug info from directive .file,
+ // we turn off the -g option, directly use the existing debug info instead.
+ // Throw away any implicit file table for the assembler source.
+ if (Ctx.getGenDwarfForAssembly()) {
+ Ctx.getMCDwarfLineTable(0).resetFileTable();
+ Ctx.setGenDwarfForAssembly(false);
+ }
+
+ Optional<MD5::MD5Result> CKMem;
+ if (HasMD5) {
+ MD5::MD5Result Sum;
+ for (unsigned i = 0; i != 8; ++i) {
+ Sum.Bytes[i] = uint8_t(MD5Hi >> ((7 - i) * 8));
+ Sum.Bytes[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8));
+ }
+ CKMem = Sum;
+ }
+ if (HasSource) {
+ char *SourceBuf = static_cast<char *>(Ctx.allocate(SourceString.size()));
+ memcpy(SourceBuf, SourceString.data(), SourceString.size());
+ Source = StringRef(SourceBuf, SourceString.size());
+ }
+ if (FileNumber == 0) {
+ if (Ctx.getDwarfVersion() < 5)
+ return Warning(DirectiveLoc, "file 0 not supported prior to DWARF-5");
+ getStreamer().emitDwarfFile0Directive(Directory, Filename, CKMem, Source);
+ } else {
+ Expected<unsigned> FileNumOrErr = getStreamer().tryEmitDwarfFileDirective(
+ FileNumber, Directory, Filename, CKMem, Source);
+ if (!FileNumOrErr)
+ return Error(DirectiveLoc, toString(FileNumOrErr.takeError()));
+ }
+ // Alert the user if there are some .file directives with MD5 and some not.
+ // But only do that once.
+ if (!ReportedInconsistentMD5 && !Ctx.isDwarfMD5UsageConsistent(0)) {
+ ReportedInconsistentMD5 = true;
+ return Warning(DirectiveLoc, "inconsistent use of MD5 checksums");
+ }
+ }
+
+ return false;
+}
+
+/// parseDirectiveLine
+/// ::= .line [number]
+bool AsmParser::parseDirectiveLine() {
+ int64_t LineNumber;
+ if (getLexer().is(AsmToken::Integer)) {
+ if (parseIntToken(LineNumber, "unexpected token in '.line' directive"))
+ return true;
+ (void)LineNumber;
+ // FIXME: Do something with the .line.
+ }
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.line' directive"))
+ return true;
+
+ return false;
+}
+
+/// parseDirectiveLoc
+/// ::= .loc FileNumber [LineNumber] [ColumnPos] [basic_block] [prologue_end]
+/// [epilogue_begin] [is_stmt VALUE] [isa VALUE]
+/// The first number is a file number, must have been previously assigned with
+/// a .file directive, the second number is the line number and optionally the
+/// third number is a column position (zero if not specified). The remaining
+/// optional items are .loc sub-directives.
+bool AsmParser::parseDirectiveLoc() {
+ int64_t FileNumber = 0, LineNumber = 0;
+ SMLoc Loc = getTok().getLoc();
+ if (parseIntToken(FileNumber, "unexpected token in '.loc' directive") ||
+ check(FileNumber < 1 && Ctx.getDwarfVersion() < 5, Loc,
+ "file number less than one in '.loc' directive") ||
+ check(!getContext().isValidDwarfFileNumber(FileNumber), Loc,
+ "unassigned file number in '.loc' directive"))
+ return true;
+
+ // optional
+ if (getLexer().is(AsmToken::Integer)) {
+ LineNumber = getTok().getIntVal();
+ if (LineNumber < 0)
+ return TokError("line number less than zero in '.loc' directive");
+ Lex();
+ }
+
+ int64_t ColumnPos = 0;
+ if (getLexer().is(AsmToken::Integer)) {
+ ColumnPos = getTok().getIntVal();
+ if (ColumnPos < 0)
+ return TokError("column position less than zero in '.loc' directive");
+ Lex();
+ }
+
+ unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
+ unsigned Isa = 0;
+ int64_t Discriminator = 0;
+
+ auto parseLocOp = [&]() -> bool {
+ StringRef Name;
+ SMLoc Loc = getTok().getLoc();
+ if (parseIdentifier(Name))
+ return TokError("unexpected token in '.loc' directive");
+
+ if (Name == "basic_block")
+ Flags |= DWARF2_FLAG_BASIC_BLOCK;
+ else if (Name == "prologue_end")
+ Flags |= DWARF2_FLAG_PROLOGUE_END;
+ else if (Name == "epilogue_begin")
+ Flags |= DWARF2_FLAG_EPILOGUE_BEGIN;
+ else if (Name == "is_stmt") {
+ Loc = getTok().getLoc();
+ const MCExpr *Value;
+ if (parseExpression(Value))
+ return true;
+ // The expression must be the constant 0 or 1.
+ if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
+ int Value = MCE->getValue();
+ if (Value == 0)
+ Flags &= ~DWARF2_FLAG_IS_STMT;
+ else if (Value == 1)
+ Flags |= DWARF2_FLAG_IS_STMT;
+ else
+ return Error(Loc, "is_stmt value not 0 or 1");
+ } else {
+ return Error(Loc, "is_stmt value not the constant value of 0 or 1");
+ }
+ } else if (Name == "isa") {
+ Loc = getTok().getLoc();
+ const MCExpr *Value;
+ if (parseExpression(Value))
+ return true;
+ // The expression must be a constant greater or equal to 0.
+ if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
+ int Value = MCE->getValue();
+ if (Value < 0)
+ return Error(Loc, "isa number less than zero");
+ Isa = Value;
+ } else {
+ return Error(Loc, "isa number not a constant value");
+ }
+ } else if (Name == "discriminator") {
+ if (parseAbsoluteExpression(Discriminator))
+ return true;
+ } else {
+ return Error(Loc, "unknown sub-directive in '.loc' directive");
+ }
+ return false;
+ };
+
+ if (parseMany(parseLocOp, false /*hasComma*/))
+ return true;
+
+ getStreamer().EmitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags,
+ Isa, Discriminator, StringRef());
+
+ return false;
+}
+
+/// parseDirectiveStabs
+/// ::= .stabs string, number, number, number
+bool AsmParser::parseDirectiveStabs() {
+ return TokError("unsupported directive '.stabs'");
+}
+
+/// parseDirectiveCVFile
+/// ::= .cv_file number filename [checksum] [checksumkind]
+bool AsmParser::parseDirectiveCVFile() {
+ SMLoc FileNumberLoc = getTok().getLoc();
+ int64_t FileNumber;
+ std::string Filename;
+ std::string Checksum;
+ int64_t ChecksumKind = 0;
+
+ if (parseIntToken(FileNumber,
+ "expected file number in '.cv_file' directive") ||
+ check(FileNumber < 1, FileNumberLoc, "file number less than one") ||
+ check(getTok().isNot(AsmToken::String),
+ "unexpected token in '.cv_file' directive") ||
+ parseEscapedString(Filename))
+ return true;
+ if (!parseOptionalToken(AsmToken::EndOfStatement)) {
+ if (check(getTok().isNot(AsmToken::String),
+ "unexpected token in '.cv_file' directive") ||
+ parseEscapedString(Checksum) ||
+ parseIntToken(ChecksumKind,
+ "expected checksum kind in '.cv_file' directive") ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cv_file' directive"))
+ return true;
+ }
+
+ Checksum = fromHex(Checksum);
+ void *CKMem = Ctx.allocate(Checksum.size(), 1);
+ memcpy(CKMem, Checksum.data(), Checksum.size());
+ ArrayRef<uint8_t> ChecksumAsBytes(reinterpret_cast<const uint8_t *>(CKMem),
+ Checksum.size());
+
+ if (!getStreamer().EmitCVFileDirective(FileNumber, Filename, ChecksumAsBytes,
+ static_cast<uint8_t>(ChecksumKind)))
+ return Error(FileNumberLoc, "file number already allocated");
+
+ return false;
+}
+
+bool AsmParser::parseCVFunctionId(int64_t &FunctionId,
+ StringRef DirectiveName) {
+ SMLoc Loc;
+ return parseTokenLoc(Loc) ||
+ parseIntToken(FunctionId, "expected function id in '" + DirectiveName +
+ "' directive") ||
+ check(FunctionId < 0 || FunctionId >= UINT_MAX, Loc,
+ "expected function id within range [0, UINT_MAX)");
+}
+
+bool AsmParser::parseCVFileId(int64_t &FileNumber, StringRef DirectiveName) {
+ SMLoc Loc;
+ return parseTokenLoc(Loc) ||
+ parseIntToken(FileNumber, "expected integer in '" + DirectiveName +
+ "' directive") ||
+ check(FileNumber < 1, Loc, "file number less than one in '" +
+ DirectiveName + "' directive") ||
+ check(!getCVContext().isValidFileNumber(FileNumber), Loc,
+ "unassigned file number in '" + DirectiveName + "' directive");
+}
+
+/// parseDirectiveCVFuncId
+/// ::= .cv_func_id FunctionId
+///
+/// Introduces a function ID that can be used with .cv_loc.
+bool AsmParser::parseDirectiveCVFuncId() {
+ SMLoc FunctionIdLoc = getTok().getLoc();
+ int64_t FunctionId;
+
+ if (parseCVFunctionId(FunctionId, ".cv_func_id") ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cv_func_id' directive"))
+ return true;
+
+ if (!getStreamer().EmitCVFuncIdDirective(FunctionId))
+ return Error(FunctionIdLoc, "function id already allocated");
+
+ return false;
+}
+
+/// parseDirectiveCVInlineSiteId
+/// ::= .cv_inline_site_id FunctionId
+/// "within" IAFunc
+/// "inlined_at" IAFile IALine [IACol]
+///
+/// Introduces a function ID that can be used with .cv_loc. Includes "inlined
+/// at" source location information for use in the line table of the caller,
+/// whether the caller is a real function or another inlined call site.
+bool AsmParser::parseDirectiveCVInlineSiteId() {
+ SMLoc FunctionIdLoc = getTok().getLoc();
+ int64_t FunctionId;
+ int64_t IAFunc;
+ int64_t IAFile;
+ int64_t IALine;
+ int64_t IACol = 0;
+
+ // FunctionId
+ if (parseCVFunctionId(FunctionId, ".cv_inline_site_id"))
+ return true;
+
+ // "within"
+ if (check((getLexer().isNot(AsmToken::Identifier) ||
+ getTok().getIdentifier() != "within"),
+ "expected 'within' identifier in '.cv_inline_site_id' directive"))
+ return true;
+ Lex();
+
+ // IAFunc
+ if (parseCVFunctionId(IAFunc, ".cv_inline_site_id"))
+ return true;
+
+ // "inlined_at"
+ if (check((getLexer().isNot(AsmToken::Identifier) ||
+ getTok().getIdentifier() != "inlined_at"),
+ "expected 'inlined_at' identifier in '.cv_inline_site_id' "
+ "directive") )
+ return true;
+ Lex();
+
+ // IAFile IALine
+ if (parseCVFileId(IAFile, ".cv_inline_site_id") ||
+ parseIntToken(IALine, "expected line number after 'inlined_at'"))
+ return true;
+
+ // [IACol]
+ if (getLexer().is(AsmToken::Integer)) {
+ IACol = getTok().getIntVal();
+ Lex();
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cv_inline_site_id' directive"))
+ return true;
+
+ if (!getStreamer().EmitCVInlineSiteIdDirective(FunctionId, IAFunc, IAFile,
+ IALine, IACol, FunctionIdLoc))
+ return Error(FunctionIdLoc, "function id already allocated");
+
+ return false;
+}
+
+/// parseDirectiveCVLoc
+/// ::= .cv_loc FunctionId FileNumber [LineNumber] [ColumnPos] [prologue_end]
+/// [is_stmt VALUE]
+/// The first number is a file number, must have been previously assigned with
+/// a .file directive, the second number is the line number and optionally the
+/// third number is a column position (zero if not specified). The remaining
+/// optional items are .loc sub-directives.
+bool AsmParser::parseDirectiveCVLoc() {
+ SMLoc DirectiveLoc = getTok().getLoc();
+ int64_t FunctionId, FileNumber;
+ if (parseCVFunctionId(FunctionId, ".cv_loc") ||
+ parseCVFileId(FileNumber, ".cv_loc"))
+ return true;
+
+ int64_t LineNumber = 0;
+ if (getLexer().is(AsmToken::Integer)) {
+ LineNumber = getTok().getIntVal();
+ if (LineNumber < 0)
+ return TokError("line number less than zero in '.cv_loc' directive");
+ Lex();
+ }
+
+ int64_t ColumnPos = 0;
+ if (getLexer().is(AsmToken::Integer)) {
+ ColumnPos = getTok().getIntVal();
+ if (ColumnPos < 0)
+ return TokError("column position less than zero in '.cv_loc' directive");
+ Lex();
+ }
+
+ bool PrologueEnd = false;
+ uint64_t IsStmt = 0;
+
+ auto parseOp = [&]() -> bool {
+ StringRef Name;
+ SMLoc Loc = getTok().getLoc();
+ if (parseIdentifier(Name))
+ return TokError("unexpected token in '.cv_loc' directive");
+ if (Name == "prologue_end")
+ PrologueEnd = true;
+ else if (Name == "is_stmt") {
+ Loc = getTok().getLoc();
+ const MCExpr *Value;
+ if (parseExpression(Value))
+ return true;
+ // The expression must be the constant 0 or 1.
+ IsStmt = ~0ULL;
+ if (const auto *MCE = dyn_cast<MCConstantExpr>(Value))
+ IsStmt = MCE->getValue();
+
+ if (IsStmt > 1)
+ return Error(Loc, "is_stmt value not 0 or 1");
+ } else {
+ return Error(Loc, "unknown sub-directive in '.cv_loc' directive");
+ }
+ return false;
+ };
+
+ if (parseMany(parseOp, false /*hasComma*/))
+ return true;
+
+ getStreamer().EmitCVLocDirective(FunctionId, FileNumber, LineNumber,
+ ColumnPos, PrologueEnd, IsStmt, StringRef(),
+ DirectiveLoc);
+ return false;
+}
+
+/// parseDirectiveCVLinetable
+/// ::= .cv_linetable FunctionId, FnStart, FnEnd
+bool AsmParser::parseDirectiveCVLinetable() {
+ int64_t FunctionId;
+ StringRef FnStartName, FnEndName;
+ SMLoc Loc = getTok().getLoc();
+ if (parseCVFunctionId(FunctionId, ".cv_linetable") ||
+ parseToken(AsmToken::Comma,
+ "unexpected token in '.cv_linetable' directive") ||
+ parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
+ "expected identifier in directive") ||
+ parseToken(AsmToken::Comma,
+ "unexpected token in '.cv_linetable' directive") ||
+ parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,
+ "expected identifier in directive"))
+ return true;
+
+ MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
+ MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
+
+ getStreamer().EmitCVLinetableDirective(FunctionId, FnStartSym, FnEndSym);
+ return false;
+}
+
+/// parseDirectiveCVInlineLinetable
+/// ::= .cv_inline_linetable PrimaryFunctionId FileId LineNum FnStart FnEnd
+bool AsmParser::parseDirectiveCVInlineLinetable() {
+ int64_t PrimaryFunctionId, SourceFileId, SourceLineNum;
+ StringRef FnStartName, FnEndName;
+ SMLoc Loc = getTok().getLoc();
+ if (parseCVFunctionId(PrimaryFunctionId, ".cv_inline_linetable") ||
+ parseTokenLoc(Loc) ||
+ parseIntToken(
+ SourceFileId,
+ "expected SourceField in '.cv_inline_linetable' directive") ||
+ check(SourceFileId <= 0, Loc,
+ "File id less than zero in '.cv_inline_linetable' directive") ||
+ parseTokenLoc(Loc) ||
+ parseIntToken(
+ SourceLineNum,
+ "expected SourceLineNum in '.cv_inline_linetable' directive") ||
+ check(SourceLineNum < 0, Loc,
+ "Line number less than zero in '.cv_inline_linetable' directive") ||
+ parseTokenLoc(Loc) || check(parseIdentifier(FnStartName), Loc,
+ "expected identifier in directive") ||
+ parseTokenLoc(Loc) || check(parseIdentifier(FnEndName), Loc,
+ "expected identifier in directive"))
+ return true;
+
+ if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement"))
+ return true;
+
+ MCSymbol *FnStartSym = getContext().getOrCreateSymbol(FnStartName);
+ MCSymbol *FnEndSym = getContext().getOrCreateSymbol(FnEndName);
+ getStreamer().EmitCVInlineLinetableDirective(PrimaryFunctionId, SourceFileId,
+ SourceLineNum, FnStartSym,
+ FnEndSym);
+ return false;
+}
+
+void AsmParser::initializeCVDefRangeTypeMap() {
+ CVDefRangeTypeMap["reg"] = CVDR_DEFRANGE_REGISTER;
+ CVDefRangeTypeMap["frame_ptr_rel"] = CVDR_DEFRANGE_FRAMEPOINTER_REL;
+ CVDefRangeTypeMap["subfield_reg"] = CVDR_DEFRANGE_SUBFIELD_REGISTER;
+ CVDefRangeTypeMap["reg_rel"] = CVDR_DEFRANGE_REGISTER_REL;
+}
+
+/// parseDirectiveCVDefRange
+/// ::= .cv_def_range RangeStart RangeEnd (GapStart GapEnd)*, bytes*
+bool AsmParser::parseDirectiveCVDefRange() {
+ SMLoc Loc;
+ std::vector<std::pair<const MCSymbol *, const MCSymbol *>> Ranges;
+ while (getLexer().is(AsmToken::Identifier)) {
+ Loc = getLexer().getLoc();
+ StringRef GapStartName;
+ if (parseIdentifier(GapStartName))
+ return Error(Loc, "expected identifier in directive");
+ MCSymbol *GapStartSym = getContext().getOrCreateSymbol(GapStartName);
+
+ Loc = getLexer().getLoc();
+ StringRef GapEndName;
+ if (parseIdentifier(GapEndName))
+ return Error(Loc, "expected identifier in directive");
+ MCSymbol *GapEndSym = getContext().getOrCreateSymbol(GapEndName);
+
+ Ranges.push_back({GapStartSym, GapEndSym});
+ }
+
+ StringRef CVDefRangeTypeStr;
+ if (parseToken(
+ AsmToken::Comma,
+ "expected comma before def_range type in .cv_def_range directive") ||
+ parseIdentifier(CVDefRangeTypeStr))
+ return Error(Loc, "expected def_range type in directive");
+
+ StringMap<CVDefRangeType>::const_iterator CVTypeIt =
+ CVDefRangeTypeMap.find(CVDefRangeTypeStr);
+ CVDefRangeType CVDRType = (CVTypeIt == CVDefRangeTypeMap.end())
+ ? CVDR_DEFRANGE
+ : CVTypeIt->getValue();
+ switch (CVDRType) {
+ case CVDR_DEFRANGE_REGISTER: {
+ int64_t DRRegister;
+ if (parseToken(AsmToken::Comma, "expected comma before register number in "
+ ".cv_def_range directive") ||
+ parseAbsoluteExpression(DRRegister))
+ return Error(Loc, "expected register number");
+
+ codeview::DefRangeRegisterHeader DRHdr;
+ DRHdr.Register = DRRegister;
+ DRHdr.MayHaveNoName = 0;
+ getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
+ break;
+ }
+ case CVDR_DEFRANGE_FRAMEPOINTER_REL: {
+ int64_t DROffset;
+ if (parseToken(AsmToken::Comma,
+ "expected comma before offset in .cv_def_range directive") ||
+ parseAbsoluteExpression(DROffset))
+ return Error(Loc, "expected offset value");
+
+ codeview::DefRangeFramePointerRelHeader DRHdr;
+ DRHdr.Offset = DROffset;
+ getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
+ break;
+ }
+ case CVDR_DEFRANGE_SUBFIELD_REGISTER: {
+ int64_t DRRegister;
+ int64_t DROffsetInParent;
+ if (parseToken(AsmToken::Comma, "expected comma before register number in "
+ ".cv_def_range directive") ||
+ parseAbsoluteExpression(DRRegister))
+ return Error(Loc, "expected register number");
+ if (parseToken(AsmToken::Comma,
+ "expected comma before offset in .cv_def_range directive") ||
+ parseAbsoluteExpression(DROffsetInParent))
+ return Error(Loc, "expected offset value");
+
+ codeview::DefRangeSubfieldRegisterHeader DRHdr;
+ DRHdr.Register = DRRegister;
+ DRHdr.MayHaveNoName = 0;
+ DRHdr.OffsetInParent = DROffsetInParent;
+ getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
+ break;
+ }
+ case CVDR_DEFRANGE_REGISTER_REL: {
+ int64_t DRRegister;
+ int64_t DRFlags;
+ int64_t DRBasePointerOffset;
+ if (parseToken(AsmToken::Comma, "expected comma before register number in "
+ ".cv_def_range directive") ||
+ parseAbsoluteExpression(DRRegister))
+ return Error(Loc, "expected register value");
+ if (parseToken(
+ AsmToken::Comma,
+ "expected comma before flag value in .cv_def_range directive") ||
+ parseAbsoluteExpression(DRFlags))
+ return Error(Loc, "expected flag value");
+ if (parseToken(AsmToken::Comma, "expected comma before base pointer offset "
+ "in .cv_def_range directive") ||
+ parseAbsoluteExpression(DRBasePointerOffset))
+ return Error(Loc, "expected base pointer offset value");
+
+ codeview::DefRangeRegisterRelHeader DRHdr;
+ DRHdr.Register = DRRegister;
+ DRHdr.Flags = DRFlags;
+ DRHdr.BasePointerOffset = DRBasePointerOffset;
+ getStreamer().EmitCVDefRangeDirective(Ranges, DRHdr);
+ break;
+ }
+ default:
+ return Error(Loc, "unexpected def_range type in .cv_def_range directive");
+ }
+ return true;
+}
+
+/// parseDirectiveCVString
+/// ::= .cv_stringtable "string"
+bool AsmParser::parseDirectiveCVString() {
+ std::string Data;
+ if (checkForValidSection() || parseEscapedString(Data))
+ return addErrorSuffix(" in '.cv_string' directive");
+
+ // Put the string in the table and emit the offset.
+ std::pair<StringRef, unsigned> Insertion =
+ getCVContext().addToStringTable(Data);
+ getStreamer().EmitIntValue(Insertion.second, 4);
+ return false;
+}
+
+/// parseDirectiveCVStringTable
+/// ::= .cv_stringtable
+bool AsmParser::parseDirectiveCVStringTable() {
+ getStreamer().EmitCVStringTableDirective();
+ return false;
+}
+
+/// parseDirectiveCVFileChecksums
+/// ::= .cv_filechecksums
+bool AsmParser::parseDirectiveCVFileChecksums() {
+ getStreamer().EmitCVFileChecksumsDirective();
+ return false;
+}
+
+/// parseDirectiveCVFileChecksumOffset
+/// ::= .cv_filechecksumoffset fileno
+bool AsmParser::parseDirectiveCVFileChecksumOffset() {
+ int64_t FileNo;
+ if (parseIntToken(FileNo, "expected identifier in directive"))
+ return true;
+ if (parseToken(AsmToken::EndOfStatement, "Expected End of Statement"))
+ return true;
+ getStreamer().EmitCVFileChecksumOffsetDirective(FileNo);
+ return false;
+}
+
+/// parseDirectiveCVFPOData
+/// ::= .cv_fpo_data procsym
+bool AsmParser::parseDirectiveCVFPOData() {
+ SMLoc DirLoc = getLexer().getLoc();
+ StringRef ProcName;
+ if (parseIdentifier(ProcName))
+ return TokError("expected symbol name");
+ if (parseEOL("unexpected tokens"))
+ return addErrorSuffix(" in '.cv_fpo_data' directive");
+ MCSymbol *ProcSym = getContext().getOrCreateSymbol(ProcName);
+ getStreamer().EmitCVFPOData(ProcSym, DirLoc);
+ return false;
+}
+
+/// parseDirectiveCFISections
+/// ::= .cfi_sections section [, section]
+bool AsmParser::parseDirectiveCFISections() {
+ StringRef Name;
+ bool EH = false;
+ bool Debug = false;
+
+ if (parseIdentifier(Name))
+ return TokError("Expected an identifier");
+
+ if (Name == ".eh_frame")
+ EH = true;
+ else if (Name == ".debug_frame")
+ Debug = true;
+
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+
+ if (parseIdentifier(Name))
+ return TokError("Expected an identifier");
+
+ if (Name == ".eh_frame")
+ EH = true;
+ else if (Name == ".debug_frame")
+ Debug = true;
+ }
+
+ getStreamer().EmitCFISections(EH, Debug);
+ return false;
+}
+
+/// parseDirectiveCFIStartProc
+/// ::= .cfi_startproc [simple]
+bool AsmParser::parseDirectiveCFIStartProc() {
+ StringRef Simple;
+ if (!parseOptionalToken(AsmToken::EndOfStatement)) {
+ if (check(parseIdentifier(Simple) || Simple != "simple",
+ "unexpected token") ||
+ parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.cfi_startproc' directive");
+ }
+
+ // TODO(kristina): Deal with a corner case of incorrect diagnostic context
+ // being produced if this directive is emitted as part of preprocessor macro
+ // expansion which can *ONLY* happen if Clang's cc1as is the API consumer.
+ // Tools like llvm-mc on the other hand are not affected by it, and report
+ // correct context information.
+ getStreamer().EmitCFIStartProc(!Simple.empty(), Lexer.getLoc());
+ return false;
+}
+
+/// parseDirectiveCFIEndProc
+/// ::= .cfi_endproc
+bool AsmParser::parseDirectiveCFIEndProc() {
+ getStreamer().EmitCFIEndProc();
+ return false;
+}
+
+/// parse register name or number.
+bool AsmParser::parseRegisterOrRegisterNumber(int64_t &Register,
+ SMLoc DirectiveLoc) {
+ unsigned RegNo;
+
+ if (getLexer().isNot(AsmToken::Integer)) {
+ if (getTargetParser().ParseRegister(RegNo, DirectiveLoc, DirectiveLoc))
+ return true;
+ Register = getContext().getRegisterInfo()->getDwarfRegNum(RegNo, true);
+ } else
+ return parseAbsoluteExpression(Register);
+
+ return false;
+}
+
+/// parseDirectiveCFIDefCfa
+/// ::= .cfi_def_cfa register, offset
+bool AsmParser::parseDirectiveCFIDefCfa(SMLoc DirectiveLoc) {
+ int64_t Register = 0, Offset = 0;
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
+ parseToken(AsmToken::Comma, "unexpected token in directive") ||
+ parseAbsoluteExpression(Offset))
+ return true;
+
+ getStreamer().EmitCFIDefCfa(Register, Offset);
+ return false;
+}
+
+/// parseDirectiveCFIDefCfaOffset
+/// ::= .cfi_def_cfa_offset offset
+bool AsmParser::parseDirectiveCFIDefCfaOffset() {
+ int64_t Offset = 0;
+ if (parseAbsoluteExpression(Offset))
+ return true;
+
+ getStreamer().EmitCFIDefCfaOffset(Offset);
+ return false;
+}
+
+/// parseDirectiveCFIRegister
+/// ::= .cfi_register register, register
+bool AsmParser::parseDirectiveCFIRegister(SMLoc DirectiveLoc) {
+ int64_t Register1 = 0, Register2 = 0;
+ if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc) ||
+ parseToken(AsmToken::Comma, "unexpected token in directive") ||
+ parseRegisterOrRegisterNumber(Register2, DirectiveLoc))
+ return true;
+
+ getStreamer().EmitCFIRegister(Register1, Register2);
+ return false;
+}
+
+/// parseDirectiveCFIWindowSave
+/// ::= .cfi_window_save
+bool AsmParser::parseDirectiveCFIWindowSave() {
+ getStreamer().EmitCFIWindowSave();
+ return false;
+}
+
+/// parseDirectiveCFIAdjustCfaOffset
+/// ::= .cfi_adjust_cfa_offset adjustment
+bool AsmParser::parseDirectiveCFIAdjustCfaOffset() {
+ int64_t Adjustment = 0;
+ if (parseAbsoluteExpression(Adjustment))
+ return true;
+
+ getStreamer().EmitCFIAdjustCfaOffset(Adjustment);
+ return false;
+}
+
+/// parseDirectiveCFIDefCfaRegister
+/// ::= .cfi_def_cfa_register register
+bool AsmParser::parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc) {
+ int64_t Register = 0;
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
+ return true;
+
+ getStreamer().EmitCFIDefCfaRegister(Register);
+ return false;
+}
+
+/// parseDirectiveCFIOffset
+/// ::= .cfi_offset register, offset
+bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) {
+ int64_t Register = 0;
+ int64_t Offset = 0;
+
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
+ parseToken(AsmToken::Comma, "unexpected token in directive") ||
+ parseAbsoluteExpression(Offset))
+ return true;
+
+ getStreamer().EmitCFIOffset(Register, Offset);
+ return false;
+}
+
+/// parseDirectiveCFIRelOffset
+/// ::= .cfi_rel_offset register, offset
+bool AsmParser::parseDirectiveCFIRelOffset(SMLoc DirectiveLoc) {
+ int64_t Register = 0, Offset = 0;
+
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) ||
+ parseToken(AsmToken::Comma, "unexpected token in directive") ||
+ parseAbsoluteExpression(Offset))
+ return true;
+
+ getStreamer().EmitCFIRelOffset(Register, Offset);
+ return false;
+}
+
+static bool isValidEncoding(int64_t Encoding) {
+ if (Encoding & ~0xff)
+ return false;
+
+ if (Encoding == dwarf::DW_EH_PE_omit)
+ return true;
+
+ const unsigned Format = Encoding & 0xf;
+ if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 &&
+ Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 &&
+ Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 &&
+ Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed)
+ return false;
+
+ const unsigned Application = Encoding & 0x70;
+ if (Application != dwarf::DW_EH_PE_absptr &&
+ Application != dwarf::DW_EH_PE_pcrel)
+ return false;
+
+ return true;
+}
+
+/// parseDirectiveCFIPersonalityOrLsda
+/// IsPersonality true for cfi_personality, false for cfi_lsda
+/// ::= .cfi_personality encoding, [symbol_name]
+/// ::= .cfi_lsda encoding, [symbol_name]
+bool AsmParser::parseDirectiveCFIPersonalityOrLsda(bool IsPersonality) {
+ int64_t Encoding = 0;
+ if (parseAbsoluteExpression(Encoding))
+ return true;
+ if (Encoding == dwarf::DW_EH_PE_omit)
+ return false;
+
+ StringRef Name;
+ if (check(!isValidEncoding(Encoding), "unsupported encoding.") ||
+ parseToken(AsmToken::Comma, "unexpected token in directive") ||
+ check(parseIdentifier(Name), "expected identifier in directive"))
+ return true;
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ if (IsPersonality)
+ getStreamer().EmitCFIPersonality(Sym, Encoding);
+ else
+ getStreamer().EmitCFILsda(Sym, Encoding);
+ return false;
+}
+
+/// parseDirectiveCFIRememberState
+/// ::= .cfi_remember_state
+bool AsmParser::parseDirectiveCFIRememberState() {
+ getStreamer().EmitCFIRememberState();
+ return false;
+}
+
+/// parseDirectiveCFIRestoreState
+/// ::= .cfi_remember_state
+bool AsmParser::parseDirectiveCFIRestoreState() {
+ getStreamer().EmitCFIRestoreState();
+ return false;
+}
+
+/// parseDirectiveCFISameValue
+/// ::= .cfi_same_value register
+bool AsmParser::parseDirectiveCFISameValue(SMLoc DirectiveLoc) {
+ int64_t Register = 0;
+
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
+ return true;
+
+ getStreamer().EmitCFISameValue(Register);
+ return false;
+}
+
+/// parseDirectiveCFIRestore
+/// ::= .cfi_restore register
+bool AsmParser::parseDirectiveCFIRestore(SMLoc DirectiveLoc) {
+ int64_t Register = 0;
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
+ return true;
+
+ getStreamer().EmitCFIRestore(Register);
+ return false;
+}
+
+/// parseDirectiveCFIEscape
+/// ::= .cfi_escape expression[,...]
+bool AsmParser::parseDirectiveCFIEscape() {
+ std::string Values;
+ int64_t CurrValue;
+ if (parseAbsoluteExpression(CurrValue))
+ return true;
+
+ Values.push_back((uint8_t)CurrValue);
+
+ while (getLexer().is(AsmToken::Comma)) {
+ Lex();
+
+ if (parseAbsoluteExpression(CurrValue))
+ return true;
+
+ Values.push_back((uint8_t)CurrValue);
+ }
+
+ getStreamer().EmitCFIEscape(Values);
+ return false;
+}
+
+/// parseDirectiveCFIReturnColumn
+/// ::= .cfi_return_column register
+bool AsmParser::parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc) {
+ int64_t Register = 0;
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
+ return true;
+ getStreamer().EmitCFIReturnColumn(Register);
+ return false;
+}
+
+/// parseDirectiveCFISignalFrame
+/// ::= .cfi_signal_frame
+bool AsmParser::parseDirectiveCFISignalFrame() {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.cfi_signal_frame'"))
+ return true;
+
+ getStreamer().EmitCFISignalFrame();
+ return false;
+}
+
+/// parseDirectiveCFIUndefined
+/// ::= .cfi_undefined register
+bool AsmParser::parseDirectiveCFIUndefined(SMLoc DirectiveLoc) {
+ int64_t Register = 0;
+
+ if (parseRegisterOrRegisterNumber(Register, DirectiveLoc))
+ return true;
+
+ getStreamer().EmitCFIUndefined(Register);
+ return false;
+}
+
+/// parseDirectiveAltmacro
+/// ::= .altmacro
+/// ::= .noaltmacro
+bool AsmParser::parseDirectiveAltmacro(StringRef Directive) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '" + Directive + "' directive");
+ AltMacroMode = (Directive == ".altmacro");
+ return false;
+}
+
+/// parseDirectiveMacrosOnOff
+/// ::= .macros_on
+/// ::= .macros_off
+bool AsmParser::parseDirectiveMacrosOnOff(StringRef Directive) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Directive + "' directive"))
+ return true;
+
+ setMacrosEnabled(Directive == ".macros_on");
+ return false;
+}
+
+/// parseDirectiveMacro
+/// ::= .macro name[,] [parameters]
+bool AsmParser::parseDirectiveMacro(SMLoc DirectiveLoc) {
+ StringRef Name;
+ if (parseIdentifier(Name))
+ return TokError("expected identifier in '.macro' directive");
+
+ if (getLexer().is(AsmToken::Comma))
+ Lex();
+
+ MCAsmMacroParameters Parameters;
+ while (getLexer().isNot(AsmToken::EndOfStatement)) {
+
+ if (!Parameters.empty() && Parameters.back().Vararg)
+ return Error(Lexer.getLoc(),
+ "Vararg parameter '" + Parameters.back().Name +
+ "' should be last one in the list of parameters.");
+
+ MCAsmMacroParameter Parameter;
+ if (parseIdentifier(Parameter.Name))
+ return TokError("expected identifier in '.macro' directive");
+
+ // Emit an error if two (or more) named parameters share the same name
+ for (const MCAsmMacroParameter& CurrParam : Parameters)
+ if (CurrParam.Name.equals(Parameter.Name))
+ return TokError("macro '" + Name + "' has multiple parameters"
+ " named '" + Parameter.Name + "'");
+
+ if (Lexer.is(AsmToken::Colon)) {
+ Lex(); // consume ':'
+
+ SMLoc QualLoc;
+ StringRef Qualifier;
+
+ QualLoc = Lexer.getLoc();
+ if (parseIdentifier(Qualifier))
+ return Error(QualLoc, "missing parameter qualifier for "
+ "'" + Parameter.Name + "' in macro '" + Name + "'");
+
+ if (Qualifier == "req")
+ Parameter.Required = true;
+ else if (Qualifier == "vararg")
+ Parameter.Vararg = true;
+ else
+ return Error(QualLoc, Qualifier + " is not a valid parameter qualifier "
+ "for '" + Parameter.Name + "' in macro '" + Name + "'");
+ }
+
+ if (getLexer().is(AsmToken::Equal)) {
+ Lex();
+
+ SMLoc ParamLoc;
+
+ ParamLoc = Lexer.getLoc();
+ if (parseMacroArgument(Parameter.Value, /*Vararg=*/false ))
+ return true;
+
+ if (Parameter.Required)
+ Warning(ParamLoc, "pointless default value for required parameter "
+ "'" + Parameter.Name + "' in macro '" + Name + "'");
+ }
+
+ Parameters.push_back(std::move(Parameter));
+
+ if (getLexer().is(AsmToken::Comma))
+ Lex();
+ }
+
+ // Eat just the end of statement.
+ Lexer.Lex();
+
+ // Consuming deferred text, so use Lexer.Lex to ignore Lexing Errors
+ AsmToken EndToken, StartToken = getTok();
+ unsigned MacroDepth = 0;
+ // Lex the macro definition.
+ while (true) {
+ // Ignore Lexing errors in macros.
+ while (Lexer.is(AsmToken::Error)) {
+ Lexer.Lex();
+ }
+
+ // Check whether we have reached the end of the file.
+ if (getLexer().is(AsmToken::Eof))
+ return Error(DirectiveLoc, "no matching '.endmacro' in definition");
+
+ // Otherwise, check whether we have reach the .endmacro.
+ if (getLexer().is(AsmToken::Identifier)) {
+ if (getTok().getIdentifier() == ".endm" ||
+ getTok().getIdentifier() == ".endmacro") {
+ if (MacroDepth == 0) { // Outermost macro.
+ EndToken = getTok();
+ Lexer.Lex();
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '" + EndToken.getIdentifier() +
+ "' directive");
+ break;
+ } else {
+ // Otherwise we just found the end of an inner macro.
+ --MacroDepth;
+ }
+ } else if (getTok().getIdentifier() == ".macro") {
+ // We allow nested macros. Those aren't instantiated until the outermost
+ // macro is expanded so just ignore them for now.
+ ++MacroDepth;
+ }
+ }
+
+ // Otherwise, scan til the end of the statement.
+ eatToEndOfStatement();
+ }
+
+ if (getContext().lookupMacro(Name)) {
+ return Error(DirectiveLoc, "macro '" + Name + "' is already defined");
+ }
+
+ const char *BodyStart = StartToken.getLoc().getPointer();
+ const char *BodyEnd = EndToken.getLoc().getPointer();
+ StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
+ checkForBadMacro(DirectiveLoc, Name, Body, Parameters);
+ MCAsmMacro Macro(Name, Body, std::move(Parameters));
+ DEBUG_WITH_TYPE("asm-macros", dbgs() << "Defining new macro:\n";
+ Macro.dump());
+ getContext().defineMacro(Name, std::move(Macro));
+ return false;
+}
+
+/// checkForBadMacro
+///
+/// With the support added for named parameters there may be code out there that
+/// is transitioning from positional parameters. In versions of gas that did
+/// not support named parameters they would be ignored on the macro definition.
+/// But to support both styles of parameters this is not possible so if a macro
+/// definition has named parameters but does not use them and has what appears
+/// to be positional parameters, strings like $1, $2, ... and $n, then issue a
+/// warning that the positional parameter found in body which have no effect.
+/// Hoping the developer will either remove the named parameters from the macro
+/// definition so the positional parameters get used if that was what was
+/// intended or change the macro to use the named parameters. It is possible
+/// this warning will trigger when the none of the named parameters are used
+/// and the strings like $1 are infact to simply to be passed trough unchanged.
+void AsmParser::checkForBadMacro(SMLoc DirectiveLoc, StringRef Name,
+ StringRef Body,
+ ArrayRef<MCAsmMacroParameter> Parameters) {
+ // If this macro is not defined with named parameters the warning we are
+ // checking for here doesn't apply.
+ unsigned NParameters = Parameters.size();
+ if (NParameters == 0)
+ return;
+
+ bool NamedParametersFound = false;
+ bool PositionalParametersFound = false;
+
+ // Look at the body of the macro for use of both the named parameters and what
+ // are likely to be positional parameters. This is what expandMacro() is
+ // doing when it finds the parameters in the body.
+ while (!Body.empty()) {
+ // Scan for the next possible parameter.
+ std::size_t End = Body.size(), Pos = 0;
+ for (; Pos != End; ++Pos) {
+ // Check for a substitution or escape.
+ // This macro is defined with parameters, look for \foo, \bar, etc.
+ if (Body[Pos] == '\\' && Pos + 1 != End)
+ break;
+
+ // This macro should have parameters, but look for $0, $1, ..., $n too.
+ if (Body[Pos] != '$' || Pos + 1 == End)
+ continue;
+ char Next = Body[Pos + 1];
+ if (Next == '$' || Next == 'n' ||
+ isdigit(static_cast<unsigned char>(Next)))
+ break;
+ }
+
+ // Check if we reached the end.
+ if (Pos == End)
+ break;
+
+ if (Body[Pos] == '$') {
+ switch (Body[Pos + 1]) {
+ // $$ => $
+ case '$':
+ break;
+
+ // $n => number of arguments
+ case 'n':
+ PositionalParametersFound = true;
+ break;
+
+ // $[0-9] => argument
+ default: {
+ PositionalParametersFound = true;
+ break;
+ }
+ }
+ Pos += 2;
+ } else {
+ unsigned I = Pos + 1;
+ while (isIdentifierChar(Body[I]) && I + 1 != End)
+ ++I;
+
+ const char *Begin = Body.data() + Pos + 1;
+ StringRef Argument(Begin, I - (Pos + 1));
+ unsigned Index = 0;
+ for (; Index < NParameters; ++Index)
+ if (Parameters[Index].Name == Argument)
+ break;
+
+ if (Index == NParameters) {
+ if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')')
+ Pos += 3;
+ else {
+ Pos = I;
+ }
+ } else {
+ NamedParametersFound = true;
+ Pos += 1 + Argument.size();
+ }
+ }
+ // Update the scan point.
+ Body = Body.substr(Pos);
+ }
+
+ if (!NamedParametersFound && PositionalParametersFound)
+ Warning(DirectiveLoc, "macro defined with named parameters which are not "
+ "used in macro body, possible positional parameter "
+ "found in body which will have no effect");
+}
+
+/// parseDirectiveExitMacro
+/// ::= .exitm
+bool AsmParser::parseDirectiveExitMacro(StringRef Directive) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Directive + "' directive"))
+ return true;
+
+ if (!isInsideMacroInstantiation())
+ return TokError("unexpected '" + Directive + "' in file, "
+ "no current macro definition");
+
+ // Exit all conditionals that are active in the current macro.
+ while (TheCondStack.size() != ActiveMacros.back()->CondStackDepth) {
+ TheCondState = TheCondStack.back();
+ TheCondStack.pop_back();
+ }
+
+ handleMacroExit();
+ return false;
+}
+
+/// parseDirectiveEndMacro
+/// ::= .endm
+/// ::= .endmacro
+bool AsmParser::parseDirectiveEndMacro(StringRef Directive) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '" + Directive + "' directive");
+
+ // If we are inside a macro instantiation, terminate the current
+ // instantiation.
+ if (isInsideMacroInstantiation()) {
+ handleMacroExit();
+ return false;
+ }
+
+ // Otherwise, this .endmacro is a stray entry in the file; well formed
+ // .endmacro directives are handled during the macro definition parsing.
+ return TokError("unexpected '" + Directive + "' in file, "
+ "no current macro definition");
+}
+
+/// parseDirectivePurgeMacro
+/// ::= .purgem
+bool AsmParser::parseDirectivePurgeMacro(SMLoc DirectiveLoc) {
+ StringRef Name;
+ SMLoc Loc;
+ if (parseTokenLoc(Loc) ||
+ check(parseIdentifier(Name), Loc,
+ "expected identifier in '.purgem' directive") ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.purgem' directive"))
+ return true;
+
+ if (!getContext().lookupMacro(Name))
+ return Error(DirectiveLoc, "macro '" + Name + "' is not defined");
+
+ getContext().undefineMacro(Name);
+ DEBUG_WITH_TYPE("asm-macros", dbgs()
+ << "Un-defining macro: " << Name << "\n");
+ return false;
+}
+
+/// parseDirectiveBundleAlignMode
+/// ::= {.bundle_align_mode} expression
+bool AsmParser::parseDirectiveBundleAlignMode() {
+ // Expect a single argument: an expression that evaluates to a constant
+ // in the inclusive range 0-30.
+ SMLoc ExprLoc = getLexer().getLoc();
+ int64_t AlignSizePow2;
+ if (checkForValidSection() || parseAbsoluteExpression(AlignSizePow2) ||
+ parseToken(AsmToken::EndOfStatement, "unexpected token after expression "
+ "in '.bundle_align_mode' "
+ "directive") ||
+ check(AlignSizePow2 < 0 || AlignSizePow2 > 30, ExprLoc,
+ "invalid bundle alignment size (expected between 0 and 30)"))
+ return true;
+
+ // Because of AlignSizePow2's verified range we can safely truncate it to
+ // unsigned.
+ getStreamer().EmitBundleAlignMode(static_cast<unsigned>(AlignSizePow2));
+ return false;
+}
+
+/// parseDirectiveBundleLock
+/// ::= {.bundle_lock} [align_to_end]
+bool AsmParser::parseDirectiveBundleLock() {
+ if (checkForValidSection())
+ return true;
+ bool AlignToEnd = false;
+
+ StringRef Option;
+ SMLoc Loc = getTok().getLoc();
+ const char *kInvalidOptionError =
+ "invalid option for '.bundle_lock' directive";
+
+ if (!parseOptionalToken(AsmToken::EndOfStatement)) {
+ if (check(parseIdentifier(Option), Loc, kInvalidOptionError) ||
+ check(Option != "align_to_end", Loc, kInvalidOptionError) ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token after '.bundle_lock' directive option"))
+ return true;
+ AlignToEnd = true;
+ }
+
+ getStreamer().EmitBundleLock(AlignToEnd);
+ return false;
+}
+
+/// parseDirectiveBundleLock
+/// ::= {.bundle_lock}
+bool AsmParser::parseDirectiveBundleUnlock() {
+ if (checkForValidSection() ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.bundle_unlock' directive"))
+ return true;
+
+ getStreamer().EmitBundleUnlock();
+ return false;
+}
+
+/// parseDirectiveSpace
+/// ::= (.skip | .space) expression [ , expression ]
+bool AsmParser::parseDirectiveSpace(StringRef IDVal) {
+ SMLoc NumBytesLoc = Lexer.getLoc();
+ const MCExpr *NumBytes;
+ if (checkForValidSection() || parseExpression(NumBytes))
+ return true;
+
+ int64_t FillExpr = 0;
+ if (parseOptionalToken(AsmToken::Comma))
+ if (parseAbsoluteExpression(FillExpr))
+ return addErrorSuffix("in '" + Twine(IDVal) + "' directive");
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix("in '" + Twine(IDVal) + "' directive");
+
+ // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0.
+ getStreamer().emitFill(*NumBytes, FillExpr, NumBytesLoc);
+
+ return false;
+}
+
+/// parseDirectiveDCB
+/// ::= .dcb.{b, l, w} expression, expression
+bool AsmParser::parseDirectiveDCB(StringRef IDVal, unsigned Size) {
+ SMLoc NumValuesLoc = Lexer.getLoc();
+ int64_t NumValues;
+ if (checkForValidSection() || parseAbsoluteExpression(NumValues))
+ return true;
+
+ if (NumValues < 0) {
+ Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");
+ return false;
+ }
+
+ if (parseToken(AsmToken::Comma,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+
+ const MCExpr *Value;
+ SMLoc ExprLoc = getLexer().getLoc();
+ if (parseExpression(Value))
+ return true;
+
+ // Special case constant expressions to match code generator.
+ if (const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value)) {
+ assert(Size <= 8 && "Invalid size");
+ uint64_t IntValue = MCE->getValue();
+ if (!isUIntN(8 * Size, IntValue) && !isIntN(8 * Size, IntValue))
+ return Error(ExprLoc, "literal value out of range for directive");
+ for (uint64_t i = 0, e = NumValues; i != e; ++i)
+ getStreamer().EmitIntValue(IntValue, Size);
+ } else {
+ for (uint64_t i = 0, e = NumValues; i != e; ++i)
+ getStreamer().EmitValue(Value, Size, ExprLoc);
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+
+ return false;
+}
+
+/// parseDirectiveRealDCB
+/// ::= .dcb.{d, s} expression, expression
+bool AsmParser::parseDirectiveRealDCB(StringRef IDVal, const fltSemantics &Semantics) {
+ SMLoc NumValuesLoc = Lexer.getLoc();
+ int64_t NumValues;
+ if (checkForValidSection() || parseAbsoluteExpression(NumValues))
+ return true;
+
+ if (NumValues < 0) {
+ Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");
+ return false;
+ }
+
+ if (parseToken(AsmToken::Comma,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+
+ APInt AsInt;
+ if (parseRealValue(Semantics, AsInt))
+ return true;
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+
+ for (uint64_t i = 0, e = NumValues; i != e; ++i)
+ getStreamer().EmitIntValue(AsInt.getLimitedValue(),
+ AsInt.getBitWidth() / 8);
+
+ return false;
+}
+
+/// parseDirectiveDS
+/// ::= .ds.{b, d, l, p, s, w, x} expression
+bool AsmParser::parseDirectiveDS(StringRef IDVal, unsigned Size) {
+ SMLoc NumValuesLoc = Lexer.getLoc();
+ int64_t NumValues;
+ if (checkForValidSection() || parseAbsoluteExpression(NumValues))
+ return true;
+
+ if (NumValues < 0) {
+ Warning(NumValuesLoc, "'" + Twine(IDVal) + "' directive with negative repeat count has no effect");
+ return false;
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Twine(IDVal) + "' directive"))
+ return true;
+
+ for (uint64_t i = 0, e = NumValues; i != e; ++i)
+ getStreamer().emitFill(Size, 0);
+
+ return false;
+}
+
+/// parseDirectiveLEB128
+/// ::= (.sleb128 | .uleb128) [ expression (, expression)* ]
+bool AsmParser::parseDirectiveLEB128(bool Signed) {
+ if (checkForValidSection())
+ return true;
+
+ auto parseOp = [&]() -> bool {
+ const MCExpr *Value;
+ if (parseExpression(Value))
+ return true;
+ if (Signed)
+ getStreamer().EmitSLEB128Value(Value);
+ else
+ getStreamer().EmitULEB128Value(Value);
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in directive");
+
+ return false;
+}
+
+/// parseDirectiveSymbolAttribute
+/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ]
+bool AsmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) {
+ auto parseOp = [&]() -> bool {
+ StringRef Name;
+ SMLoc Loc = getTok().getLoc();
+ if (parseIdentifier(Name))
+ return Error(Loc, "expected identifier");
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ // Assembler local symbols don't make any sense here. Complain loudly.
+ if (Sym->isTemporary())
+ return Error(Loc, "non-local symbol required");
+
+ if (!getStreamer().EmitSymbolAttribute(Sym, Attr))
+ return Error(Loc, "unable to emit symbol attribute");
+ return false;
+ };
+
+ if (parseMany(parseOp))
+ return addErrorSuffix(" in directive");
+ return false;
+}
+
+/// parseDirectiveComm
+/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ]
+bool AsmParser::parseDirectiveComm(bool IsLocal) {
+ if (checkForValidSection())
+ return true;
+
+ SMLoc IDLoc = getLexer().getLoc();
+ StringRef Name;
+ if (parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ int64_t Size;
+ SMLoc SizeLoc = getLexer().getLoc();
+ if (parseAbsoluteExpression(Size))
+ return true;
+
+ int64_t Pow2Alignment = 0;
+ SMLoc Pow2AlignmentLoc;
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+ Pow2AlignmentLoc = getLexer().getLoc();
+ if (parseAbsoluteExpression(Pow2Alignment))
+ return true;
+
+ LCOMM::LCOMMType LCOMM = Lexer.getMAI().getLCOMMDirectiveAlignmentType();
+ if (IsLocal && LCOMM == LCOMM::NoAlignment)
+ return Error(Pow2AlignmentLoc, "alignment not supported on this target");
+
+ // If this target takes alignments in bytes (not log) validate and convert.
+ if ((!IsLocal && Lexer.getMAI().getCOMMDirectiveAlignmentIsInBytes()) ||
+ (IsLocal && LCOMM == LCOMM::ByteAlignment)) {
+ if (!isPowerOf2_64(Pow2Alignment))
+ return Error(Pow2AlignmentLoc, "alignment must be a power of 2");
+ Pow2Alignment = Log2_64(Pow2Alignment);
+ }
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.comm' or '.lcomm' directive"))
+ return true;
+
+ // NOTE: a size of zero for a .comm should create a undefined symbol
+ // but a size of .lcomm creates a bss symbol of size zero.
+ if (Size < 0)
+ return Error(SizeLoc, "invalid '.comm' or '.lcomm' directive size, can't "
+ "be less than zero");
+
+ // NOTE: The alignment in the directive is a power of 2 value, the assembler
+ // may internally end up wanting an alignment in bytes.
+ // FIXME: Diagnose overflow.
+ if (Pow2Alignment < 0)
+ return Error(Pow2AlignmentLoc, "invalid '.comm' or '.lcomm' directive "
+ "alignment, can't be less than zero");
+
+ Sym->redefineIfPossible();
+ if (!Sym->isUndefined())
+ return Error(IDLoc, "invalid symbol redefinition");
+
+ // Create the Symbol as a common or local common with Size and Pow2Alignment
+ if (IsLocal) {
+ getStreamer().EmitLocalCommonSymbol(Sym, Size, 1 << Pow2Alignment);
+ return false;
+ }
+
+ getStreamer().EmitCommonSymbol(Sym, Size, 1 << Pow2Alignment);
+ return false;
+}
+
+/// parseDirectiveAbort
+/// ::= .abort [... message ...]
+bool AsmParser::parseDirectiveAbort() {
+ // FIXME: Use loc from directive.
+ SMLoc Loc = getLexer().getLoc();
+
+ StringRef Str = parseStringToEndOfStatement();
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.abort' directive"))
+ return true;
+
+ if (Str.empty())
+ return Error(Loc, ".abort detected. Assembly stopping.");
+ else
+ return Error(Loc, ".abort '" + Str + "' detected. Assembly stopping.");
+ // FIXME: Actually abort assembly here.
+
+ return false;
+}
+
+/// parseDirectiveInclude
+/// ::= .include "filename"
+bool AsmParser::parseDirectiveInclude() {
+ // Allow the strings to have escaped octal character sequence.
+ std::string Filename;
+ SMLoc IncludeLoc = getTok().getLoc();
+
+ if (check(getTok().isNot(AsmToken::String),
+ "expected string in '.include' directive") ||
+ parseEscapedString(Filename) ||
+ check(getTok().isNot(AsmToken::EndOfStatement),
+ "unexpected token in '.include' directive") ||
+ // Attempt to switch the lexer to the included file before consuming the
+ // end of statement to avoid losing it when we switch.
+ check(enterIncludeFile(Filename), IncludeLoc,
+ "Could not find include file '" + Filename + "'"))
+ return true;
+
+ return false;
+}
+
+/// parseDirectiveIncbin
+/// ::= .incbin "filename" [ , skip [ , count ] ]
+bool AsmParser::parseDirectiveIncbin() {
+ // Allow the strings to have escaped octal character sequence.
+ std::string Filename;
+ SMLoc IncbinLoc = getTok().getLoc();
+ if (check(getTok().isNot(AsmToken::String),
+ "expected string in '.incbin' directive") ||
+ parseEscapedString(Filename))
+ return true;
+
+ int64_t Skip = 0;
+ const MCExpr *Count = nullptr;
+ SMLoc SkipLoc, CountLoc;
+ if (parseOptionalToken(AsmToken::Comma)) {
+ // The skip expression can be omitted while specifying the count, e.g:
+ // .incbin "filename",,4
+ if (getTok().isNot(AsmToken::Comma)) {
+ if (parseTokenLoc(SkipLoc) || parseAbsoluteExpression(Skip))
+ return true;
+ }
+ if (parseOptionalToken(AsmToken::Comma)) {
+ CountLoc = getTok().getLoc();
+ if (parseExpression(Count))
+ return true;
+ }
+ }
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.incbin' directive"))
+ return true;
+
+ if (check(Skip < 0, SkipLoc, "skip is negative"))
+ return true;
+
+ // Attempt to process the included file.
+ if (processIncbinFile(Filename, Skip, Count, CountLoc))
+ return Error(IncbinLoc, "Could not find incbin file '" + Filename + "'");
+ return false;
+}
+
+/// parseDirectiveIf
+/// ::= .if{,eq,ge,gt,le,lt,ne} expression
+bool AsmParser::parseDirectiveIf(SMLoc DirectiveLoc, DirectiveKind DirKind) {
+ TheCondStack.push_back(TheCondState);
+ TheCondState.TheCond = AsmCond::IfCond;
+ if (TheCondState.Ignore) {
+ eatToEndOfStatement();
+ } else {
+ int64_t ExprValue;
+ if (parseAbsoluteExpression(ExprValue) ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.if' directive"))
+ return true;
+
+ switch (DirKind) {
+ default:
+ llvm_unreachable("unsupported directive");
+ case DK_IF:
+ case DK_IFNE:
+ break;
+ case DK_IFEQ:
+ ExprValue = ExprValue == 0;
+ break;
+ case DK_IFGE:
+ ExprValue = ExprValue >= 0;
+ break;
+ case DK_IFGT:
+ ExprValue = ExprValue > 0;
+ break;
+ case DK_IFLE:
+ ExprValue = ExprValue <= 0;
+ break;
+ case DK_IFLT:
+ ExprValue = ExprValue < 0;
+ break;
+ }
+
+ TheCondState.CondMet = ExprValue;
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// parseDirectiveIfb
+/// ::= .ifb string
+bool AsmParser::parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank) {
+ TheCondStack.push_back(TheCondState);
+ TheCondState.TheCond = AsmCond::IfCond;
+
+ if (TheCondState.Ignore) {
+ eatToEndOfStatement();
+ } else {
+ StringRef Str = parseStringToEndOfStatement();
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.ifb' directive"))
+ return true;
+
+ TheCondState.CondMet = ExpectBlank == Str.empty();
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// parseDirectiveIfc
+/// ::= .ifc string1, string2
+/// ::= .ifnc string1, string2
+bool AsmParser::parseDirectiveIfc(SMLoc DirectiveLoc, bool ExpectEqual) {
+ TheCondStack.push_back(TheCondState);
+ TheCondState.TheCond = AsmCond::IfCond;
+
+ if (TheCondState.Ignore) {
+ eatToEndOfStatement();
+ } else {
+ StringRef Str1 = parseStringToComma();
+
+ if (parseToken(AsmToken::Comma, "unexpected token in '.ifc' directive"))
+ return true;
+
+ StringRef Str2 = parseStringToEndOfStatement();
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.ifc' directive"))
+ return true;
+
+ TheCondState.CondMet = ExpectEqual == (Str1.trim() == Str2.trim());
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// parseDirectiveIfeqs
+/// ::= .ifeqs string1, string2
+bool AsmParser::parseDirectiveIfeqs(SMLoc DirectiveLoc, bool ExpectEqual) {
+ if (Lexer.isNot(AsmToken::String)) {
+ if (ExpectEqual)
+ return TokError("expected string parameter for '.ifeqs' directive");
+ return TokError("expected string parameter for '.ifnes' directive");
+ }
+
+ StringRef String1 = getTok().getStringContents();
+ Lex();
+
+ if (Lexer.isNot(AsmToken::Comma)) {
+ if (ExpectEqual)
+ return TokError(
+ "expected comma after first string for '.ifeqs' directive");
+ return TokError("expected comma after first string for '.ifnes' directive");
+ }
+
+ Lex();
+
+ if (Lexer.isNot(AsmToken::String)) {
+ if (ExpectEqual)
+ return TokError("expected string parameter for '.ifeqs' directive");
+ return TokError("expected string parameter for '.ifnes' directive");
+ }
+
+ StringRef String2 = getTok().getStringContents();
+ Lex();
+
+ TheCondStack.push_back(TheCondState);
+ TheCondState.TheCond = AsmCond::IfCond;
+ TheCondState.CondMet = ExpectEqual == (String1 == String2);
+ TheCondState.Ignore = !TheCondState.CondMet;
+
+ return false;
+}
+
+/// parseDirectiveIfdef
+/// ::= .ifdef symbol
+bool AsmParser::parseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) {
+ StringRef Name;
+ TheCondStack.push_back(TheCondState);
+ TheCondState.TheCond = AsmCond::IfCond;
+
+ if (TheCondState.Ignore) {
+ eatToEndOfStatement();
+ } else {
+ if (check(parseIdentifier(Name), "expected identifier after '.ifdef'") ||
+ parseToken(AsmToken::EndOfStatement, "unexpected token in '.ifdef'"))
+ return true;
+
+ MCSymbol *Sym = getContext().lookupSymbol(Name);
+
+ if (expect_defined)
+ TheCondState.CondMet = (Sym && !Sym->isUndefined(false));
+ else
+ TheCondState.CondMet = (!Sym || Sym->isUndefined(false));
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// parseDirectiveElseIf
+/// ::= .elseif expression
+bool AsmParser::parseDirectiveElseIf(SMLoc DirectiveLoc) {
+ if (TheCondState.TheCond != AsmCond::IfCond &&
+ TheCondState.TheCond != AsmCond::ElseIfCond)
+ return Error(DirectiveLoc, "Encountered a .elseif that doesn't follow an"
+ " .if or an .elseif");
+ TheCondState.TheCond = AsmCond::ElseIfCond;
+
+ bool LastIgnoreState = false;
+ if (!TheCondStack.empty())
+ LastIgnoreState = TheCondStack.back().Ignore;
+ if (LastIgnoreState || TheCondState.CondMet) {
+ TheCondState.Ignore = true;
+ eatToEndOfStatement();
+ } else {
+ int64_t ExprValue;
+ if (parseAbsoluteExpression(ExprValue))
+ return true;
+
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.elseif' directive"))
+ return true;
+
+ TheCondState.CondMet = ExprValue;
+ TheCondState.Ignore = !TheCondState.CondMet;
+ }
+
+ return false;
+}
+
+/// parseDirectiveElse
+/// ::= .else
+bool AsmParser::parseDirectiveElse(SMLoc DirectiveLoc) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.else' directive"))
+ return true;
+
+ if (TheCondState.TheCond != AsmCond::IfCond &&
+ TheCondState.TheCond != AsmCond::ElseIfCond)
+ return Error(DirectiveLoc, "Encountered a .else that doesn't follow "
+ " an .if or an .elseif");
+ TheCondState.TheCond = AsmCond::ElseCond;
+ bool LastIgnoreState = false;
+ if (!TheCondStack.empty())
+ LastIgnoreState = TheCondStack.back().Ignore;
+ if (LastIgnoreState || TheCondState.CondMet)
+ TheCondState.Ignore = true;
+ else
+ TheCondState.Ignore = false;
+
+ return false;
+}
+
+/// parseDirectiveEnd
+/// ::= .end
+bool AsmParser::parseDirectiveEnd(SMLoc DirectiveLoc) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.end' directive"))
+ return true;
+
+ while (Lexer.isNot(AsmToken::Eof))
+ Lexer.Lex();
+
+ return false;
+}
+
+/// parseDirectiveError
+/// ::= .err
+/// ::= .error [string]
+bool AsmParser::parseDirectiveError(SMLoc L, bool WithMessage) {
+ if (!TheCondStack.empty()) {
+ if (TheCondStack.back().Ignore) {
+ eatToEndOfStatement();
+ return false;
+ }
+ }
+
+ if (!WithMessage)
+ return Error(L, ".err encountered");
+
+ StringRef Message = ".error directive invoked in source file";
+ if (Lexer.isNot(AsmToken::EndOfStatement)) {
+ if (Lexer.isNot(AsmToken::String))
+ return TokError(".error argument must be a string");
+
+ Message = getTok().getStringContents();
+ Lex();
+ }
+
+ return Error(L, Message);
+}
+
+/// parseDirectiveWarning
+/// ::= .warning [string]
+bool AsmParser::parseDirectiveWarning(SMLoc L) {
+ if (!TheCondStack.empty()) {
+ if (TheCondStack.back().Ignore) {
+ eatToEndOfStatement();
+ return false;
+ }
+ }
+
+ StringRef Message = ".warning directive invoked in source file";
+
+ if (!parseOptionalToken(AsmToken::EndOfStatement)) {
+ if (Lexer.isNot(AsmToken::String))
+ return TokError(".warning argument must be a string");
+
+ Message = getTok().getStringContents();
+ Lex();
+ if (parseToken(AsmToken::EndOfStatement,
+ "expected end of statement in '.warning' directive"))
+ return true;
+ }
+
+ return Warning(L, Message);
+}
+
+/// parseDirectiveEndIf
+/// ::= .endif
+bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) {
+ if (parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '.endif' directive"))
+ return true;
+
+ if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty())
+ return Error(DirectiveLoc, "Encountered a .endif that doesn't follow "
+ "an .if or .else");
+ if (!TheCondStack.empty()) {
+ TheCondState = TheCondStack.back();
+ TheCondStack.pop_back();
+ }
+
+ return false;
+}
+
+void AsmParser::initializeDirectiveKindMap() {
+ DirectiveKindMap[".set"] = DK_SET;
+ DirectiveKindMap[".equ"] = DK_EQU;
+ DirectiveKindMap[".equiv"] = DK_EQUIV;
+ DirectiveKindMap[".ascii"] = DK_ASCII;
+ DirectiveKindMap[".asciz"] = DK_ASCIZ;
+ DirectiveKindMap[".string"] = DK_STRING;
+ DirectiveKindMap[".byte"] = DK_BYTE;
+ DirectiveKindMap[".short"] = DK_SHORT;
+ DirectiveKindMap[".value"] = DK_VALUE;
+ DirectiveKindMap[".2byte"] = DK_2BYTE;
+ DirectiveKindMap[".long"] = DK_LONG;
+ DirectiveKindMap[".int"] = DK_INT;
+ DirectiveKindMap[".4byte"] = DK_4BYTE;
+ DirectiveKindMap[".quad"] = DK_QUAD;
+ DirectiveKindMap[".8byte"] = DK_8BYTE;
+ DirectiveKindMap[".octa"] = DK_OCTA;
+ DirectiveKindMap[".single"] = DK_SINGLE;
+ DirectiveKindMap[".float"] = DK_FLOAT;
+ DirectiveKindMap[".double"] = DK_DOUBLE;
+ DirectiveKindMap[".align"] = DK_ALIGN;
+ DirectiveKindMap[".align32"] = DK_ALIGN32;
+ DirectiveKindMap[".balign"] = DK_BALIGN;
+ DirectiveKindMap[".balignw"] = DK_BALIGNW;
+ DirectiveKindMap[".balignl"] = DK_BALIGNL;
+ DirectiveKindMap[".p2align"] = DK_P2ALIGN;
+ DirectiveKindMap[".p2alignw"] = DK_P2ALIGNW;
+ DirectiveKindMap[".p2alignl"] = DK_P2ALIGNL;
+ DirectiveKindMap[".org"] = DK_ORG;
+ DirectiveKindMap[".fill"] = DK_FILL;
+ DirectiveKindMap[".zero"] = DK_ZERO;
+ DirectiveKindMap[".extern"] = DK_EXTERN;
+ DirectiveKindMap[".globl"] = DK_GLOBL;
+ DirectiveKindMap[".global"] = DK_GLOBAL;
+ DirectiveKindMap[".lazy_reference"] = DK_LAZY_REFERENCE;
+ DirectiveKindMap[".no_dead_strip"] = DK_NO_DEAD_STRIP;
+ DirectiveKindMap[".symbol_resolver"] = DK_SYMBOL_RESOLVER;
+ DirectiveKindMap[".private_extern"] = DK_PRIVATE_EXTERN;
+ DirectiveKindMap[".reference"] = DK_REFERENCE;
+ DirectiveKindMap[".weak_definition"] = DK_WEAK_DEFINITION;
+ DirectiveKindMap[".weak_reference"] = DK_WEAK_REFERENCE;
+ DirectiveKindMap[".weak_def_can_be_hidden"] = DK_WEAK_DEF_CAN_BE_HIDDEN;
+ DirectiveKindMap[".cold"] = DK_COLD;
+ DirectiveKindMap[".comm"] = DK_COMM;
+ DirectiveKindMap[".common"] = DK_COMMON;
+ DirectiveKindMap[".lcomm"] = DK_LCOMM;
+ DirectiveKindMap[".abort"] = DK_ABORT;
+ DirectiveKindMap[".include"] = DK_INCLUDE;
+ DirectiveKindMap[".incbin"] = DK_INCBIN;
+ DirectiveKindMap[".code16"] = DK_CODE16;
+ DirectiveKindMap[".code16gcc"] = DK_CODE16GCC;
+ DirectiveKindMap[".rept"] = DK_REPT;
+ DirectiveKindMap[".rep"] = DK_REPT;
+ DirectiveKindMap[".irp"] = DK_IRP;
+ DirectiveKindMap[".irpc"] = DK_IRPC;
+ DirectiveKindMap[".endr"] = DK_ENDR;
+ DirectiveKindMap[".bundle_align_mode"] = DK_BUNDLE_ALIGN_MODE;
+ DirectiveKindMap[".bundle_lock"] = DK_BUNDLE_LOCK;
+ DirectiveKindMap[".bundle_unlock"] = DK_BUNDLE_UNLOCK;
+ DirectiveKindMap[".if"] = DK_IF;
+ DirectiveKindMap[".ifeq"] = DK_IFEQ;
+ DirectiveKindMap[".ifge"] = DK_IFGE;
+ DirectiveKindMap[".ifgt"] = DK_IFGT;
+ DirectiveKindMap[".ifle"] = DK_IFLE;
+ DirectiveKindMap[".iflt"] = DK_IFLT;
+ DirectiveKindMap[".ifne"] = DK_IFNE;
+ DirectiveKindMap[".ifb"] = DK_IFB;
+ DirectiveKindMap[".ifnb"] = DK_IFNB;
+ DirectiveKindMap[".ifc"] = DK_IFC;
+ DirectiveKindMap[".ifeqs"] = DK_IFEQS;
+ DirectiveKindMap[".ifnc"] = DK_IFNC;
+ DirectiveKindMap[".ifnes"] = DK_IFNES;
+ DirectiveKindMap[".ifdef"] = DK_IFDEF;
+ DirectiveKindMap[".ifndef"] = DK_IFNDEF;
+ DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF;
+ DirectiveKindMap[".elseif"] = DK_ELSEIF;
+ DirectiveKindMap[".else"] = DK_ELSE;
+ DirectiveKindMap[".end"] = DK_END;
+ DirectiveKindMap[".endif"] = DK_ENDIF;
+ DirectiveKindMap[".skip"] = DK_SKIP;
+ DirectiveKindMap[".space"] = DK_SPACE;
+ DirectiveKindMap[".file"] = DK_FILE;
+ DirectiveKindMap[".line"] = DK_LINE;
+ DirectiveKindMap[".loc"] = DK_LOC;
+ DirectiveKindMap[".stabs"] = DK_STABS;
+ DirectiveKindMap[".cv_file"] = DK_CV_FILE;
+ DirectiveKindMap[".cv_func_id"] = DK_CV_FUNC_ID;
+ DirectiveKindMap[".cv_loc"] = DK_CV_LOC;
+ DirectiveKindMap[".cv_linetable"] = DK_CV_LINETABLE;
+ DirectiveKindMap[".cv_inline_linetable"] = DK_CV_INLINE_LINETABLE;
+ DirectiveKindMap[".cv_inline_site_id"] = DK_CV_INLINE_SITE_ID;
+ DirectiveKindMap[".cv_def_range"] = DK_CV_DEF_RANGE;
+ DirectiveKindMap[".cv_string"] = DK_CV_STRING;
+ DirectiveKindMap[".cv_stringtable"] = DK_CV_STRINGTABLE;
+ DirectiveKindMap[".cv_filechecksums"] = DK_CV_FILECHECKSUMS;
+ DirectiveKindMap[".cv_filechecksumoffset"] = DK_CV_FILECHECKSUM_OFFSET;
+ DirectiveKindMap[".cv_fpo_data"] = DK_CV_FPO_DATA;
+ DirectiveKindMap[".sleb128"] = DK_SLEB128;
+ DirectiveKindMap[".uleb128"] = DK_ULEB128;
+ DirectiveKindMap[".cfi_sections"] = DK_CFI_SECTIONS;
+ DirectiveKindMap[".cfi_startproc"] = DK_CFI_STARTPROC;
+ DirectiveKindMap[".cfi_endproc"] = DK_CFI_ENDPROC;
+ DirectiveKindMap[".cfi_def_cfa"] = DK_CFI_DEF_CFA;
+ DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET;
+ DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET;
+ DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;
+ DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
+ DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
+ DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
+ DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;
+ DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;
+ DirectiveKindMap[".cfi_restore_state"] = DK_CFI_RESTORE_STATE;
+ DirectiveKindMap[".cfi_same_value"] = DK_CFI_SAME_VALUE;
+ DirectiveKindMap[".cfi_restore"] = DK_CFI_RESTORE;
+ DirectiveKindMap[".cfi_escape"] = DK_CFI_ESCAPE;
+ DirectiveKindMap[".cfi_return_column"] = DK_CFI_RETURN_COLUMN;
+ DirectiveKindMap[".cfi_signal_frame"] = DK_CFI_SIGNAL_FRAME;
+ DirectiveKindMap[".cfi_undefined"] = DK_CFI_UNDEFINED;
+ DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
+ DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
+ DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
+ DirectiveKindMap[".macros_on"] = DK_MACROS_ON;
+ DirectiveKindMap[".macros_off"] = DK_MACROS_OFF;
+ DirectiveKindMap[".macro"] = DK_MACRO;
+ DirectiveKindMap[".exitm"] = DK_EXITM;
+ DirectiveKindMap[".endm"] = DK_ENDM;
+ DirectiveKindMap[".endmacro"] = DK_ENDMACRO;
+ DirectiveKindMap[".purgem"] = DK_PURGEM;
+ DirectiveKindMap[".err"] = DK_ERR;
+ DirectiveKindMap[".error"] = DK_ERROR;
+ DirectiveKindMap[".warning"] = DK_WARNING;
+ DirectiveKindMap[".altmacro"] = DK_ALTMACRO;
+ DirectiveKindMap[".noaltmacro"] = DK_NOALTMACRO;
+ DirectiveKindMap[".reloc"] = DK_RELOC;
+ DirectiveKindMap[".dc"] = DK_DC;
+ DirectiveKindMap[".dc.a"] = DK_DC_A;
+ DirectiveKindMap[".dc.b"] = DK_DC_B;
+ DirectiveKindMap[".dc.d"] = DK_DC_D;
+ DirectiveKindMap[".dc.l"] = DK_DC_L;
+ DirectiveKindMap[".dc.s"] = DK_DC_S;
+ DirectiveKindMap[".dc.w"] = DK_DC_W;
+ DirectiveKindMap[".dc.x"] = DK_DC_X;
+ DirectiveKindMap[".dcb"] = DK_DCB;
+ DirectiveKindMap[".dcb.b"] = DK_DCB_B;
+ DirectiveKindMap[".dcb.d"] = DK_DCB_D;
+ DirectiveKindMap[".dcb.l"] = DK_DCB_L;
+ DirectiveKindMap[".dcb.s"] = DK_DCB_S;
+ DirectiveKindMap[".dcb.w"] = DK_DCB_W;
+ DirectiveKindMap[".dcb.x"] = DK_DCB_X;
+ DirectiveKindMap[".ds"] = DK_DS;
+ DirectiveKindMap[".ds.b"] = DK_DS_B;
+ DirectiveKindMap[".ds.d"] = DK_DS_D;
+ DirectiveKindMap[".ds.l"] = DK_DS_L;
+ DirectiveKindMap[".ds.p"] = DK_DS_P;
+ DirectiveKindMap[".ds.s"] = DK_DS_S;
+ DirectiveKindMap[".ds.w"] = DK_DS_W;
+ DirectiveKindMap[".ds.x"] = DK_DS_X;
+ DirectiveKindMap[".print"] = DK_PRINT;
+ DirectiveKindMap[".addrsig"] = DK_ADDRSIG;
+ DirectiveKindMap[".addrsig_sym"] = DK_ADDRSIG_SYM;
+}
+
+MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) {
+ AsmToken EndToken, StartToken = getTok();
+
+ unsigned NestLevel = 0;
+ while (true) {
+ // Check whether we have reached the end of the file.
+ if (getLexer().is(AsmToken::Eof)) {
+ printError(DirectiveLoc, "no matching '.endr' in definition");
+ return nullptr;
+ }
+
+ if (Lexer.is(AsmToken::Identifier) &&
+ (getTok().getIdentifier() == ".rep" ||
+ getTok().getIdentifier() == ".rept" ||
+ getTok().getIdentifier() == ".irp" ||
+ getTok().getIdentifier() == ".irpc")) {
+ ++NestLevel;
+ }
+
+ // Otherwise, check whether we have reached the .endr.
+ if (Lexer.is(AsmToken::Identifier) && getTok().getIdentifier() == ".endr") {
+ if (NestLevel == 0) {
+ EndToken = getTok();
+ Lex();
+ if (Lexer.isNot(AsmToken::EndOfStatement)) {
+ printError(getTok().getLoc(),
+ "unexpected token in '.endr' directive");
+ return nullptr;
+ }
+ break;
+ }
+ --NestLevel;
+ }
+
+ // Otherwise, scan till the end of the statement.
+ eatToEndOfStatement();
+ }
+
+ const char *BodyStart = StartToken.getLoc().getPointer();
+ const char *BodyEnd = EndToken.getLoc().getPointer();
+ StringRef Body = StringRef(BodyStart, BodyEnd - BodyStart);
+
+ // We Are Anonymous.
+ MacroLikeBodies.emplace_back(StringRef(), Body, MCAsmMacroParameters());
+ return &MacroLikeBodies.back();
+}
+
+void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc,
+ raw_svector_ostream &OS) {
+ OS << ".endr\n";
+
+ std::unique_ptr<MemoryBuffer> Instantiation =
+ MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>");
+
+ // Create the macro instantiation object and add to the current macro
+ // instantiation stack.
+ MacroInstantiation *MI = new MacroInstantiation(
+ DirectiveLoc, CurBuffer, getTok().getLoc(), TheCondStack.size());
+ ActiveMacros.push_back(MI);
+
+ // Jump to the macro instantiation and prime the lexer.
+ CurBuffer = SrcMgr.AddNewSourceBuffer(std::move(Instantiation), SMLoc());
+ Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)->getBuffer());
+ Lex();
+}
+
+/// parseDirectiveRept
+/// ::= .rep | .rept count
+bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc, StringRef Dir) {
+ const MCExpr *CountExpr;
+ SMLoc CountLoc = getTok().getLoc();
+ if (parseExpression(CountExpr))
+ return true;
+
+ int64_t Count;
+ if (!CountExpr->evaluateAsAbsolute(Count, getStreamer().getAssemblerPtr())) {
+ return Error(CountLoc, "unexpected token in '" + Dir + "' directive");
+ }
+
+ if (check(Count < 0, CountLoc, "Count is negative") ||
+ parseToken(AsmToken::EndOfStatement,
+ "unexpected token in '" + Dir + "' directive"))
+ return true;
+
+ // Lex the rept definition.
+ MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
+ if (!M)
+ return true;
+
+ // Macro instantiation is lexical, unfortunately. We construct a new buffer
+ // to hold the macro body with substitutions.
+ SmallString<256> Buf;
+ raw_svector_ostream OS(Buf);
+ while (Count--) {
+ // Note that the AtPseudoVariable is disabled for instantiations of .rep(t).
+ if (expandMacro(OS, M->Body, None, None, false, getTok().getLoc()))
+ return true;
+ }
+ instantiateMacroLikeBody(M, DirectiveLoc, OS);
+
+ return false;
+}
+
+/// parseDirectiveIrp
+/// ::= .irp symbol,values
+bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) {
+ MCAsmMacroParameter Parameter;
+ MCAsmMacroArguments A;
+ if (check(parseIdentifier(Parameter.Name),
+ "expected identifier in '.irp' directive") ||
+ parseToken(AsmToken::Comma, "expected comma in '.irp' directive") ||
+ parseMacroArguments(nullptr, A) ||
+ parseToken(AsmToken::EndOfStatement, "expected End of Statement"))
+ return true;
+
+ // Lex the irp definition.
+ MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
+ if (!M)
+ return true;
+
+ // Macro instantiation is lexical, unfortunately. We construct a new buffer
+ // to hold the macro body with substitutions.
+ SmallString<256> Buf;
+ raw_svector_ostream OS(Buf);
+
+ for (const MCAsmMacroArgument &Arg : A) {
+ // Note that the AtPseudoVariable is enabled for instantiations of .irp.
+ // This is undocumented, but GAS seems to support it.
+ if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc()))
+ return true;
+ }
+
+ instantiateMacroLikeBody(M, DirectiveLoc, OS);
+
+ return false;
+}
+
+/// parseDirectiveIrpc
+/// ::= .irpc symbol,values
+bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) {
+ MCAsmMacroParameter Parameter;
+ MCAsmMacroArguments A;
+
+ if (check(parseIdentifier(Parameter.Name),
+ "expected identifier in '.irpc' directive") ||
+ parseToken(AsmToken::Comma, "expected comma in '.irpc' directive") ||
+ parseMacroArguments(nullptr, A))
+ return true;
+
+ if (A.size() != 1 || A.front().size() != 1)
+ return TokError("unexpected token in '.irpc' directive");
+
+ // Eat the end of statement.
+ if (parseToken(AsmToken::EndOfStatement, "expected end of statement"))
+ return true;
+
+ // Lex the irpc definition.
+ MCAsmMacro *M = parseMacroLikeBody(DirectiveLoc);
+ if (!M)
+ return true;
+
+ // Macro instantiation is lexical, unfortunately. We construct a new buffer
+ // to hold the macro body with substitutions.
+ SmallString<256> Buf;
+ raw_svector_ostream OS(Buf);
+
+ StringRef Values = A.front().front().getString();
+ for (std::size_t I = 0, End = Values.size(); I != End; ++I) {
+ MCAsmMacroArgument Arg;
+ Arg.emplace_back(AsmToken::Identifier, Values.slice(I, I + 1));
+
+ // Note that the AtPseudoVariable is enabled for instantiations of .irpc.
+ // This is undocumented, but GAS seems to support it.
+ if (expandMacro(OS, M->Body, Parameter, Arg, true, getTok().getLoc()))
+ return true;
+ }
+
+ instantiateMacroLikeBody(M, DirectiveLoc, OS);
+
+ return false;
+}
+
+bool AsmParser::parseDirectiveEndr(SMLoc DirectiveLoc) {
+ if (ActiveMacros.empty())
+ return TokError("unmatched '.endr' directive");
+
+ // The only .repl that should get here are the ones created by
+ // instantiateMacroLikeBody.
+ assert(getLexer().is(AsmToken::EndOfStatement));
+
+ handleMacroExit();
+ return false;
+}
+
+bool AsmParser::parseDirectiveMSEmit(SMLoc IDLoc, ParseStatementInfo &Info,
+ size_t Len) {
+ const MCExpr *Value;
+ SMLoc ExprLoc = getLexer().getLoc();
+ if (parseExpression(Value))
+ return true;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);
+ if (!MCE)
+ return Error(ExprLoc, "unexpected expression in _emit");
+ uint64_t IntValue = MCE->getValue();
+ if (!isUInt<8>(IntValue) && !isInt<8>(IntValue))
+ return Error(ExprLoc, "literal value out of range for directive");
+
+ Info.AsmRewrites->emplace_back(AOK_Emit, IDLoc, Len);
+ return false;
+}
+
+bool AsmParser::parseDirectiveMSAlign(SMLoc IDLoc, ParseStatementInfo &Info) {
+ const MCExpr *Value;
+ SMLoc ExprLoc = getLexer().getLoc();
+ if (parseExpression(Value))
+ return true;
+ const MCConstantExpr *MCE = dyn_cast<MCConstantExpr>(Value);
+ if (!MCE)
+ return Error(ExprLoc, "unexpected expression in align");
+ uint64_t IntValue = MCE->getValue();
+ if (!isPowerOf2_64(IntValue))
+ return Error(ExprLoc, "literal value not a power of two greater then zero");
+
+ Info.AsmRewrites->emplace_back(AOK_Align, IDLoc, 5, Log2_64(IntValue));
+ return false;
+}
+
+bool AsmParser::parseDirectivePrint(SMLoc DirectiveLoc) {
+ const AsmToken StrTok = getTok();
+ Lex();
+ if (StrTok.isNot(AsmToken::String) || StrTok.getString().front() != '"')
+ return Error(DirectiveLoc, "expected double quoted string after .print");
+ if (parseToken(AsmToken::EndOfStatement, "expected end of statement"))
+ return true;
+ llvm::outs() << StrTok.getStringContents() << '\n';
+ return false;
+}
+
+bool AsmParser::parseDirectiveAddrsig() {
+ getStreamer().EmitAddrsig();
+ return false;
+}
+
+bool AsmParser::parseDirectiveAddrsigSym() {
+ StringRef Name;
+ if (check(parseIdentifier(Name),
+ "expected identifier in '.addrsig_sym' directive"))
+ return true;
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+ getStreamer().EmitAddrsigSym(Sym);
+ return false;
+}
+
+// We are comparing pointers, but the pointers are relative to a single string.
+// Thus, this should always be deterministic.
+static int rewritesSort(const AsmRewrite *AsmRewriteA,
+ const AsmRewrite *AsmRewriteB) {
+ if (AsmRewriteA->Loc.getPointer() < AsmRewriteB->Loc.getPointer())
+ return -1;
+ if (AsmRewriteB->Loc.getPointer() < AsmRewriteA->Loc.getPointer())
+ return 1;
+
+ // It's possible to have a SizeDirective, Imm/ImmPrefix and an Input/Output
+ // rewrite to the same location. Make sure the SizeDirective rewrite is
+ // performed first, then the Imm/ImmPrefix and finally the Input/Output. This
+ // ensures the sort algorithm is stable.
+ if (AsmRewritePrecedence[AsmRewriteA->Kind] >
+ AsmRewritePrecedence[AsmRewriteB->Kind])
+ return -1;
+
+ if (AsmRewritePrecedence[AsmRewriteA->Kind] <
+ AsmRewritePrecedence[AsmRewriteB->Kind])
+ return 1;
+ llvm_unreachable("Unstable rewrite sort.");
+}
+
+bool AsmParser::parseMSInlineAsm(
+ void *AsmLoc, std::string &AsmString, unsigned &NumOutputs,
+ unsigned &NumInputs, SmallVectorImpl<std::pair<void *, bool>> &OpDecls,
+ SmallVectorImpl<std::string> &Constraints,
+ SmallVectorImpl<std::string> &Clobbers, const MCInstrInfo *MII,
+ const MCInstPrinter *IP, MCAsmParserSemaCallback &SI) {
+ SmallVector<void *, 4> InputDecls;
+ SmallVector<void *, 4> OutputDecls;
+ SmallVector<bool, 4> InputDeclsAddressOf;
+ SmallVector<bool, 4> OutputDeclsAddressOf;
+ SmallVector<std::string, 4> InputConstraints;
+ SmallVector<std::string, 4> OutputConstraints;
+ SmallVector<unsigned, 4> ClobberRegs;
+
+ SmallVector<AsmRewrite, 4> AsmStrRewrites;
+
+ // Prime the lexer.
+ Lex();
+
+ // While we have input, parse each statement.
+ unsigned InputIdx = 0;
+ unsigned OutputIdx = 0;
+ while (getLexer().isNot(AsmToken::Eof)) {
+ // Parse curly braces marking block start/end
+ if (parseCurlyBlockScope(AsmStrRewrites))
+ continue;
+
+ ParseStatementInfo Info(&AsmStrRewrites);
+ bool StatementErr = parseStatement(Info, &SI);
+
+ if (StatementErr || Info.ParseError) {
+ // Emit pending errors if any exist.
+ printPendingErrors();
+ return true;
+ }
+
+ // No pending error should exist here.
+ assert(!hasPendingError() && "unexpected error from parseStatement");
+
+ if (Info.Opcode == ~0U)
+ continue;
+
+ const MCInstrDesc &Desc = MII->get(Info.Opcode);
+
+ // Build the list of clobbers, outputs and inputs.
+ for (unsigned i = 1, e = Info.ParsedOperands.size(); i != e; ++i) {
+ MCParsedAsmOperand &Operand = *Info.ParsedOperands[i];
+
+ // Immediate.
+ if (Operand.isImm())
+ continue;
+
+ // Register operand.
+ if (Operand.isReg() && !Operand.needAddressOf() &&
+ !getTargetParser().OmitRegisterFromClobberLists(Operand.getReg())) {
+ unsigned NumDefs = Desc.getNumDefs();
+ // Clobber.
+ if (NumDefs && Operand.getMCOperandNum() < NumDefs)
+ ClobberRegs.push_back(Operand.getReg());
+ continue;
+ }
+
+ // Expr/Input or Output.
+ StringRef SymName = Operand.getSymName();
+ if (SymName.empty())
+ continue;
+
+ void *OpDecl = Operand.getOpDecl();
+ if (!OpDecl)
+ continue;
+
+ bool isOutput = (i == 1) && Desc.mayStore();
+ SMLoc Start = SMLoc::getFromPointer(SymName.data());
+ if (isOutput) {
+ ++InputIdx;
+ OutputDecls.push_back(OpDecl);
+ OutputDeclsAddressOf.push_back(Operand.needAddressOf());
+ OutputConstraints.push_back(("=" + Operand.getConstraint()).str());
+ AsmStrRewrites.emplace_back(AOK_Output, Start, SymName.size());
+ } else {
+ InputDecls.push_back(OpDecl);
+ InputDeclsAddressOf.push_back(Operand.needAddressOf());
+ InputConstraints.push_back(Operand.getConstraint().str());
+ AsmStrRewrites.emplace_back(AOK_Input, Start, SymName.size());
+ }
+ }
+
+ // Consider implicit defs to be clobbers. Think of cpuid and push.
+ ArrayRef<MCPhysReg> ImpDefs(Desc.getImplicitDefs(),
+ Desc.getNumImplicitDefs());
+ ClobberRegs.insert(ClobberRegs.end(), ImpDefs.begin(), ImpDefs.end());
+ }
+
+ // Set the number of Outputs and Inputs.
+ NumOutputs = OutputDecls.size();
+ NumInputs = InputDecls.size();
+
+ // Set the unique clobbers.
+ array_pod_sort(ClobberRegs.begin(), ClobberRegs.end());
+ ClobberRegs.erase(std::unique(ClobberRegs.begin(), ClobberRegs.end()),
+ ClobberRegs.end());
+ Clobbers.assign(ClobberRegs.size(), std::string());
+ for (unsigned I = 0, E = ClobberRegs.size(); I != E; ++I) {
+ raw_string_ostream OS(Clobbers[I]);
+ IP->printRegName(OS, ClobberRegs[I]);
+ }
+
+ // Merge the various outputs and inputs. Output are expected first.
+ if (NumOutputs || NumInputs) {
+ unsigned NumExprs = NumOutputs + NumInputs;
+ OpDecls.resize(NumExprs);
+ Constraints.resize(NumExprs);
+ for (unsigned i = 0; i < NumOutputs; ++i) {
+ OpDecls[i] = std::make_pair(OutputDecls[i], OutputDeclsAddressOf[i]);
+ Constraints[i] = OutputConstraints[i];
+ }
+ for (unsigned i = 0, j = NumOutputs; i < NumInputs; ++i, ++j) {
+ OpDecls[j] = std::make_pair(InputDecls[i], InputDeclsAddressOf[i]);
+ Constraints[j] = InputConstraints[i];
+ }
+ }
+
+ // Build the IR assembly string.
+ std::string AsmStringIR;
+ raw_string_ostream OS(AsmStringIR);
+ StringRef ASMString =
+ SrcMgr.getMemoryBuffer(SrcMgr.getMainFileID())->getBuffer();
+ const char *AsmStart = ASMString.begin();
+ const char *AsmEnd = ASMString.end();
+ array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort);
+ for (const AsmRewrite &AR : AsmStrRewrites) {
+ AsmRewriteKind Kind = AR.Kind;
+
+ const char *Loc = AR.Loc.getPointer();
+ assert(Loc >= AsmStart && "Expected Loc to be at or after Start!");
+
+ // Emit everything up to the immediate/expression.
+ if (unsigned Len = Loc - AsmStart)
+ OS << StringRef(AsmStart, Len);
+
+ // Skip the original expression.
+ if (Kind == AOK_Skip) {
+ AsmStart = Loc + AR.Len;
+ continue;
+ }
+
+ unsigned AdditionalSkip = 0;
+ // Rewrite expressions in $N notation.
+ switch (Kind) {
+ default:
+ break;
+ case AOK_IntelExpr:
+ assert(AR.IntelExp.isValid() && "cannot write invalid intel expression");
+ if (AR.IntelExp.NeedBracs)
+ OS << "[";
+ if (AR.IntelExp.hasBaseReg())
+ OS << AR.IntelExp.BaseReg;
+ if (AR.IntelExp.hasIndexReg())
+ OS << (AR.IntelExp.hasBaseReg() ? " + " : "")
+ << AR.IntelExp.IndexReg;
+ if (AR.IntelExp.Scale > 1)
+ OS << " * $$" << AR.IntelExp.Scale;
+ if (AR.IntelExp.Imm || !AR.IntelExp.hasRegs())
+ OS << (AR.IntelExp.hasRegs() ? " + $$" : "$$") << AR.IntelExp.Imm;
+ if (AR.IntelExp.NeedBracs)
+ OS << "]";
+ break;
+ case AOK_Label:
+ OS << Ctx.getAsmInfo()->getPrivateLabelPrefix() << AR.Label;
+ break;
+ case AOK_Input:
+ OS << '$' << InputIdx++;
+ break;
+ case AOK_Output:
+ OS << '$' << OutputIdx++;
+ break;
+ case AOK_SizeDirective:
+ switch (AR.Val) {
+ default: break;
+ case 8: OS << "byte ptr "; break;
+ case 16: OS << "word ptr "; break;
+ case 32: OS << "dword ptr "; break;
+ case 64: OS << "qword ptr "; break;
+ case 80: OS << "xword ptr "; break;
+ case 128: OS << "xmmword ptr "; break;
+ case 256: OS << "ymmword ptr "; break;
+ }
+ break;
+ case AOK_Emit:
+ OS << ".byte";
+ break;
+ case AOK_Align: {
+ // MS alignment directives are measured in bytes. If the native assembler
+ // measures alignment in bytes, we can pass it straight through.
+ OS << ".align";
+ if (getContext().getAsmInfo()->getAlignmentIsInBytes())
+ break;
+
+ // Alignment is in log2 form, so print that instead and skip the original
+ // immediate.
+ unsigned Val = AR.Val;
+ OS << ' ' << Val;
+ assert(Val < 10 && "Expected alignment less then 2^10.");
+ AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4;
+ break;
+ }
+ case AOK_EVEN:
+ OS << ".even";
+ break;
+ case AOK_EndOfStatement:
+ OS << "\n\t";
+ break;
+ }
+
+ // Skip the original expression.
+ AsmStart = Loc + AR.Len + AdditionalSkip;
+ }
+
+ // Emit the remainder of the asm string.
+ if (AsmStart != AsmEnd)
+ OS << StringRef(AsmStart, AsmEnd - AsmStart);
+
+ AsmString = OS.str();
+ return false;
+}
+
+namespace llvm {
+namespace MCParserUtils {
+
+/// Returns whether the given symbol is used anywhere in the given expression,
+/// or subexpressions.
+static bool isSymbolUsedInExpression(const MCSymbol *Sym, const MCExpr *Value) {
+ switch (Value->getKind()) {
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value);
+ return isSymbolUsedInExpression(Sym, BE->getLHS()) ||
+ isSymbolUsedInExpression(Sym, BE->getRHS());
+ }
+ case MCExpr::Target:
+ case MCExpr::Constant:
+ return false;
+ case MCExpr::SymbolRef: {
+ const MCSymbol &S =
+ static_cast<const MCSymbolRefExpr *>(Value)->getSymbol();
+ if (S.isVariable())
+ return isSymbolUsedInExpression(Sym, S.getVariableValue());
+ return &S == Sym;
+ }
+ case MCExpr::Unary:
+ return isSymbolUsedInExpression(
+ Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr());
+ }
+
+ llvm_unreachable("Unknown expr kind!");
+}
+
+bool parseAssignmentExpression(StringRef Name, bool allow_redef,
+ MCAsmParser &Parser, MCSymbol *&Sym,
+ const MCExpr *&Value) {
+
+ // FIXME: Use better location, we should use proper tokens.
+ SMLoc EqualLoc = Parser.getTok().getLoc();
+ if (Parser.parseExpression(Value))
+ return Parser.TokError("missing expression");
+
+ // Note: we don't count b as used in "a = b". This is to allow
+ // a = b
+ // b = c
+
+ if (Parser.parseToken(AsmToken::EndOfStatement))
+ return true;
+
+ // Validate that the LHS is allowed to be a variable (either it has not been
+ // used as a symbol, or it is an absolute symbol).
+ Sym = Parser.getContext().lookupSymbol(Name);
+ if (Sym) {
+ // Diagnose assignment to a label.
+ //
+ // FIXME: Diagnostics. Note the location of the definition as a label.
+ // FIXME: Diagnose assignment to protected identifier (e.g., register name).
+ if (isSymbolUsedInExpression(Sym, Value))
+ return Parser.Error(EqualLoc, "Recursive use of '" + Name + "'");
+ else if (Sym->isUndefined(/*SetUsed*/ false) && !Sym->isUsed() &&
+ !Sym->isVariable())
+ ; // Allow redefinitions of undefined symbols only used in directives.
+ else if (Sym->isVariable() && !Sym->isUsed() && allow_redef)
+ ; // Allow redefinitions of variables that haven't yet been used.
+ else if (!Sym->isUndefined() && (!Sym->isVariable() || !allow_redef))
+ return Parser.Error(EqualLoc, "redefinition of '" + Name + "'");
+ else if (!Sym->isVariable())
+ return Parser.Error(EqualLoc, "invalid assignment to '" + Name + "'");
+ else if (!isa<MCConstantExpr>(Sym->getVariableValue()))
+ return Parser.Error(EqualLoc,
+ "invalid reassignment of non-absolute variable '" +
+ Name + "'");
+ } else if (Name == ".") {
+ Parser.getStreamer().emitValueToOffset(Value, 0, EqualLoc);
+ return false;
+ } else
+ Sym = Parser.getContext().getOrCreateSymbol(Name);
+
+ Sym->setRedefinable(allow_redef);
+
+ return false;
+}
+
+} // end namespace MCParserUtils
+} // end namespace llvm
+
+/// Create an MCAsmParser instance.
+MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C,
+ MCStreamer &Out, const MCAsmInfo &MAI,
+ unsigned CB) {
+ return new AsmParser(SM, C, Out, MAI, CB);
+}
diff --git a/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/llvm/lib/MC/MCParser/COFFAsmParser.cpp
new file mode 100644
index 000000000000..06f8310ae061
--- /dev/null
+++ b/llvm/lib/MC/MCParser/COFFAsmParser.cpp
@@ -0,0 +1,712 @@
+//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===//
+//
+// 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/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/Support/SMLoc.h"
+#include <cassert>
+#include <cstdint>
+#include <limits>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+
+class COFFAsmParser : public MCAsmParserExtension {
+ template<bool (COFFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
+ void addDirectiveHandler(StringRef Directive) {
+ MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
+ this, HandleDirective<COFFAsmParser, HandlerMethod>);
+ getParser().addDirectiveHandler(Directive, Handler);
+ }
+
+ bool ParseSectionSwitch(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind);
+
+ bool ParseSectionSwitch(StringRef Section, unsigned Characteristics,
+ SectionKind Kind, StringRef COMDATSymName,
+ COFF::COMDATType Type);
+
+ bool ParseSectionName(StringRef &SectionName);
+ bool ParseSectionFlags(StringRef SectionName, StringRef FlagsString,
+ unsigned *Flags);
+
+ void Initialize(MCAsmParser &Parser) override {
+ // Call the base implementation.
+ MCAsmParserExtension::Initialize(Parser);
+
+ addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text");
+ addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data");
+ addDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSection>(".section");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecRel32>(".secrel32");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymIdx>(".symidx");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSafeSEH>(".safeseh");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSecIdx>(".secidx");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveLinkOnce>(".linkonce");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveRVA>(".rva");
+ addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
+
+ // Win64 EH directives.
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartProc>(
+ ".seh_proc");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProc>(
+ ".seh_endproc");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveStartChained>(
+ ".seh_startchained");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndChained>(
+ ".seh_endchained");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandler>(
+ ".seh_handler");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveHandlerData>(
+ ".seh_handlerdata");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>(
+ ".seh_stackalloc");
+ addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>(
+ ".seh_endprologue");
+ }
+
+ bool ParseSectionDirectiveText(StringRef, SMLoc) {
+ return ParseSectionSwitch(".text",
+ COFF::IMAGE_SCN_CNT_CODE
+ | COFF::IMAGE_SCN_MEM_EXECUTE
+ | COFF::IMAGE_SCN_MEM_READ,
+ SectionKind::getText());
+ }
+
+ bool ParseSectionDirectiveData(StringRef, SMLoc) {
+ return ParseSectionSwitch(".data", COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ |
+ COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getData());
+ }
+
+ bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
+ return ParseSectionSwitch(".bss",
+ COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
+ | COFF::IMAGE_SCN_MEM_READ
+ | COFF::IMAGE_SCN_MEM_WRITE,
+ SectionKind::getBSS());
+ }
+
+ bool ParseDirectiveSection(StringRef, SMLoc);
+ bool ParseDirectiveDef(StringRef, SMLoc);
+ bool ParseDirectiveScl(StringRef, SMLoc);
+ bool ParseDirectiveType(StringRef, SMLoc);
+ bool ParseDirectiveEndef(StringRef, SMLoc);
+ bool ParseDirectiveSecRel32(StringRef, SMLoc);
+ bool ParseDirectiveSecIdx(StringRef, SMLoc);
+ bool ParseDirectiveSafeSEH(StringRef, SMLoc);
+ bool ParseDirectiveSymIdx(StringRef, SMLoc);
+ bool parseCOMDATType(COFF::COMDATType &Type);
+ bool ParseDirectiveLinkOnce(StringRef, SMLoc);
+ bool ParseDirectiveRVA(StringRef, SMLoc);
+
+ // Win64 EH directives.
+ bool ParseSEHDirectiveStartProc(StringRef, SMLoc);
+ bool ParseSEHDirectiveEndProc(StringRef, SMLoc);
+ bool ParseSEHDirectiveStartChained(StringRef, SMLoc);
+ bool ParseSEHDirectiveEndChained(StringRef, SMLoc);
+ bool ParseSEHDirectiveHandler(StringRef, SMLoc);
+ bool ParseSEHDirectiveHandlerData(StringRef, SMLoc);
+ bool ParseSEHDirectiveAllocStack(StringRef, SMLoc);
+ bool ParseSEHDirectiveEndProlog(StringRef, SMLoc);
+
+ bool ParseAtUnwindOrAtExcept(bool &unwind, bool &except);
+ bool ParseSEHRegisterNumber(unsigned &RegNo);
+ bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc);
+
+public:
+ COFFAsmParser() = default;
+};
+
+} // end annonomous namespace.
+
+static SectionKind computeSectionKind(unsigned Flags) {
+ if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
+ return SectionKind::getText();
+ if (Flags & COFF::IMAGE_SCN_MEM_READ &&
+ (Flags & COFF::IMAGE_SCN_MEM_WRITE) == 0)
+ return SectionKind::getReadOnly();
+ return SectionKind::getData();
+}
+
+bool COFFAsmParser::ParseSectionFlags(StringRef SectionName,
+ StringRef FlagsString, unsigned *Flags) {
+ enum {
+ None = 0,
+ Alloc = 1 << 0,
+ Code = 1 << 1,
+ Load = 1 << 2,
+ InitData = 1 << 3,
+ Shared = 1 << 4,
+ NoLoad = 1 << 5,
+ NoRead = 1 << 6,
+ NoWrite = 1 << 7,
+ Discardable = 1 << 8,
+ };
+
+ bool ReadOnlyRemoved = false;
+ unsigned SecFlags = None;
+
+ for (char FlagChar : FlagsString) {
+ switch (FlagChar) {
+ case 'a':
+ // Ignored.
+ break;
+
+ case 'b': // bss section
+ SecFlags |= Alloc;
+ if (SecFlags & InitData)
+ return TokError("conflicting section flags 'b' and 'd'.");
+ SecFlags &= ~Load;
+ break;
+
+ case 'd': // data section
+ SecFlags |= InitData;
+ if (SecFlags & Alloc)
+ return TokError("conflicting section flags 'b' and 'd'.");
+ SecFlags &= ~NoWrite;
+ if ((SecFlags & NoLoad) == 0)
+ SecFlags |= Load;
+ break;
+
+ case 'n': // section is not loaded
+ SecFlags |= NoLoad;
+ SecFlags &= ~Load;
+ break;
+
+ case 'D': // discardable
+ SecFlags |= Discardable;
+ break;
+
+ case 'r': // read-only
+ ReadOnlyRemoved = false;
+ SecFlags |= NoWrite;
+ if ((SecFlags & Code) == 0)
+ SecFlags |= InitData;
+ if ((SecFlags & NoLoad) == 0)
+ SecFlags |= Load;
+ break;
+
+ case 's': // shared section
+ SecFlags |= Shared | InitData;
+ SecFlags &= ~NoWrite;
+ if ((SecFlags & NoLoad) == 0)
+ SecFlags |= Load;
+ break;
+
+ case 'w': // writable
+ SecFlags &= ~NoWrite;
+ ReadOnlyRemoved = true;
+ break;
+
+ case 'x': // executable section
+ SecFlags |= Code;
+ if ((SecFlags & NoLoad) == 0)
+ SecFlags |= Load;
+ if (!ReadOnlyRemoved)
+ SecFlags |= NoWrite;
+ break;
+
+ case 'y': // not readable
+ SecFlags |= NoRead | NoWrite;
+ break;
+
+ default:
+ return TokError("unknown flag");
+ }
+ }
+
+ *Flags = 0;
+
+ if (SecFlags == None)
+ SecFlags = InitData;
+
+ if (SecFlags & Code)
+ *Flags |= COFF::IMAGE_SCN_CNT_CODE | COFF::IMAGE_SCN_MEM_EXECUTE;
+ if (SecFlags & InitData)
+ *Flags |= COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+ if ((SecFlags & Alloc) && (SecFlags & Load) == 0)
+ *Flags |= COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+ if (SecFlags & NoLoad)
+ *Flags |= COFF::IMAGE_SCN_LNK_REMOVE;
+ if ((SecFlags & Discardable) ||
+ MCSectionCOFF::isImplicitlyDiscardable(SectionName))
+ *Flags |= COFF::IMAGE_SCN_MEM_DISCARDABLE;
+ if ((SecFlags & NoRead) == 0)
+ *Flags |= COFF::IMAGE_SCN_MEM_READ;
+ if ((SecFlags & NoWrite) == 0)
+ *Flags |= COFF::IMAGE_SCN_MEM_WRITE;
+ if (SecFlags & Shared)
+ *Flags |= COFF::IMAGE_SCN_MEM_SHARED;
+
+ return false;
+}
+
+/// ParseDirectiveSymbolAttribute
+/// ::= { ".weak", ... } [ identifier ( , identifier )* ]
+bool COFFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
+ MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
+ .Case(".weak", MCSA_Weak)
+ .Default(MCSA_Invalid);
+ assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ while (true) {
+ StringRef Name;
+
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ getStreamer().EmitSymbolAttribute(Sym, Attr);
+
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+ }
+ }
+
+ Lex();
+ return false;
+}
+
+bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind) {
+ return ParseSectionSwitch(Section, Characteristics, Kind, "", (COFF::COMDATType)0);
+}
+
+bool COFFAsmParser::ParseSectionSwitch(StringRef Section,
+ unsigned Characteristics,
+ SectionKind Kind,
+ StringRef COMDATSymName,
+ COFF::COMDATType Type) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in section switching directive");
+ Lex();
+
+ getStreamer().SwitchSection(getContext().getCOFFSection(
+ Section, Characteristics, Kind, COMDATSymName, Type));
+
+ return false;
+}
+
+bool COFFAsmParser::ParseSectionName(StringRef &SectionName) {
+ if (!getLexer().is(AsmToken::Identifier))
+ return true;
+
+ SectionName = getTok().getIdentifier();
+ Lex();
+ return false;
+}
+
+// .section name [, "flags"] [, identifier [ identifier ], identifier]
+//
+// Supported flags:
+// a: Ignored.
+// b: BSS section (uninitialized data)
+// d: data section (initialized data)
+// n: "noload" section (removed by linker)
+// D: Discardable section
+// r: Readable section
+// s: Shared section
+// w: Writable section
+// x: Executable section
+// y: Not-readable section (clears 'r')
+//
+// Subsections are not supported.
+bool COFFAsmParser::ParseDirectiveSection(StringRef, SMLoc) {
+ StringRef SectionName;
+
+ if (ParseSectionName(SectionName))
+ return TokError("expected identifier in directive");
+
+ unsigned Flags = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ |
+ COFF::IMAGE_SCN_MEM_WRITE;
+
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("expected string in directive");
+
+ StringRef FlagsStr = getTok().getStringContents();
+ Lex();
+
+ if (ParseSectionFlags(SectionName, FlagsStr, &Flags))
+ return true;
+ }
+
+ COFF::COMDATType Type = (COFF::COMDATType)0;
+ StringRef COMDATSymName;
+ if (getLexer().is(AsmToken::Comma)) {
+ Type = COFF::IMAGE_COMDAT_SELECT_ANY;
+ Lex();
+
+ Flags |= COFF::IMAGE_SCN_LNK_COMDAT;
+
+ if (!getLexer().is(AsmToken::Identifier))
+ return TokError("expected comdat type such as 'discard' or 'largest' "
+ "after protection bits");
+
+ if (parseCOMDATType(Type))
+ return true;
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("expected comma in directive");
+ Lex();
+
+ if (getParser().parseIdentifier(COMDATSymName))
+ return TokError("expected identifier in directive");
+ }
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ SectionKind Kind = computeSectionKind(Flags);
+ if (Kind.isText()) {
+ const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
+ if (T.getArch() == Triple::arm || T.getArch() == Triple::thumb)
+ Flags |= COFF::IMAGE_SCN_MEM_16BIT;
+ }
+ ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type);
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) {
+ StringRef SymbolName;
+
+ if (getParser().parseIdentifier(SymbolName))
+ return TokError("expected identifier in directive");
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(SymbolName);
+
+ getStreamer().BeginCOFFSymbolDef(Sym);
+
+ Lex();
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) {
+ int64_t SymbolStorageClass;
+ if (getParser().parseAbsoluteExpression(SymbolStorageClass))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ Lex();
+ getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass);
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
+ int64_t Type;
+ if (getParser().parseAbsoluteExpression(Type))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ Lex();
+ getStreamer().EmitCOFFSymbolType(Type);
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) {
+ Lex();
+ getStreamer().EndCOFFSymbolDef();
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveSecRel32(StringRef, SMLoc) {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return TokError("expected identifier in directive");
+
+ int64_t Offset = 0;
+ SMLoc OffsetLoc;
+ if (getLexer().is(AsmToken::Plus)) {
+ OffsetLoc = getLexer().getLoc();
+ if (getParser().parseAbsoluteExpression(Offset))
+ return true;
+ }
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ if (Offset < 0 || Offset > std::numeric_limits<uint32_t>::max())
+ return Error(
+ OffsetLoc,
+ "invalid '.secrel32' directive offset, can't be less "
+ "than zero or greater than std::numeric_limits<uint32_t>::max()");
+
+ MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
+
+ Lex();
+ getStreamer().EmitCOFFSecRel32(Symbol, Offset);
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveRVA(StringRef, SMLoc) {
+ auto parseOp = [&]() -> bool {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return TokError("expected identifier in directive");
+
+ int64_t Offset = 0;
+ SMLoc OffsetLoc;
+ if (getLexer().is(AsmToken::Plus) || getLexer().is(AsmToken::Minus)) {
+ OffsetLoc = getLexer().getLoc();
+ if (getParser().parseAbsoluteExpression(Offset))
+ return true;
+ }
+
+ if (Offset < std::numeric_limits<int32_t>::min() ||
+ Offset > std::numeric_limits<int32_t>::max())
+ return Error(OffsetLoc, "invalid '.rva' directive offset, can't be less "
+ "than -2147483648 or greater than "
+ "2147483647");
+
+ MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
+
+ getStreamer().EmitCOFFImgRel32(Symbol, Offset);
+ return false;
+ };
+
+ if (getParser().parseMany(parseOp))
+ return addErrorSuffix(" in directive");
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveSafeSEH(StringRef, SMLoc) {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
+
+ Lex();
+ getStreamer().EmitCOFFSafeSEH(Symbol);
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveSecIdx(StringRef, SMLoc) {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
+
+ Lex();
+ getStreamer().EmitCOFFSectionIndex(Symbol);
+ return false;
+}
+
+bool COFFAsmParser::ParseDirectiveSymIdx(StringRef, SMLoc) {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
+
+ Lex();
+ getStreamer().EmitCOFFSymbolIndex(Symbol);
+ return false;
+}
+
+/// ::= [ identifier ]
+bool COFFAsmParser::parseCOMDATType(COFF::COMDATType &Type) {
+ StringRef TypeId = getTok().getIdentifier();
+
+ Type = StringSwitch<COFF::COMDATType>(TypeId)
+ .Case("one_only", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES)
+ .Case("discard", COFF::IMAGE_COMDAT_SELECT_ANY)
+ .Case("same_size", COFF::IMAGE_COMDAT_SELECT_SAME_SIZE)
+ .Case("same_contents", COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH)
+ .Case("associative", COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ .Case("largest", COFF::IMAGE_COMDAT_SELECT_LARGEST)
+ .Case("newest", COFF::IMAGE_COMDAT_SELECT_NEWEST)
+ .Default((COFF::COMDATType)0);
+
+ if (Type == 0)
+ return TokError(Twine("unrecognized COMDAT type '" + TypeId + "'"));
+
+ Lex();
+
+ return false;
+}
+
+/// ParseDirectiveLinkOnce
+/// ::= .linkonce [ identifier ]
+bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) {
+ COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY;
+ if (getLexer().is(AsmToken::Identifier))
+ if (parseCOMDATType(Type))
+ return true;
+
+ const MCSectionCOFF *Current =
+ static_cast<const MCSectionCOFF *>(getStreamer().getCurrentSectionOnly());
+
+ if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ return Error(Loc, "cannot make section associative with .linkonce");
+
+ if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)
+ return Error(Loc, Twine("section '") + Current->getSectionName() +
+ "' is already linkonce");
+
+ Current->setSelection(Type);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc Loc) {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ MCSymbol *Symbol = getContext().getOrCreateSymbol(SymbolID);
+
+ Lex();
+ getStreamer().EmitWinCFIStartProc(Symbol, Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc Loc) {
+ Lex();
+ getStreamer().EmitWinCFIEndProc(Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc Loc) {
+ Lex();
+ getStreamer().EmitWinCFIStartChained(Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc Loc) {
+ Lex();
+ getStreamer().EmitWinCFIEndChained(Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc Loc) {
+ StringRef SymbolID;
+ if (getParser().parseIdentifier(SymbolID))
+ return true;
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("you must specify one or both of @unwind or @except");
+ Lex();
+ bool unwind = false, except = false;
+ if (ParseAtUnwindOrAtExcept(unwind, except))
+ return true;
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+ if (ParseAtUnwindOrAtExcept(unwind, except))
+ return true;
+ }
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ MCSymbol *handler = getContext().getOrCreateSymbol(SymbolID);
+
+ Lex();
+ getStreamer().EmitWinEHHandler(handler, unwind, except, Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc Loc) {
+ Lex();
+ getStreamer().EmitWinEHHandlerData();
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc Loc) {
+ int64_t Size;
+ if (getParser().parseAbsoluteExpression(Size))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ Lex();
+ getStreamer().EmitWinCFIAllocStack(Size, Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc Loc) {
+ Lex();
+ getStreamer().EmitWinCFIEndProlog(Loc);
+ return false;
+}
+
+bool COFFAsmParser::ParseAtUnwindOrAtExcept(bool &unwind, bool &except) {
+ StringRef identifier;
+ if (getLexer().isNot(AsmToken::At))
+ return TokError("a handler attribute must begin with '@'");
+ SMLoc startLoc = getLexer().getLoc();
+ Lex();
+ if (getParser().parseIdentifier(identifier))
+ return Error(startLoc, "expected @unwind or @except");
+ if (identifier == "unwind")
+ unwind = true;
+ else if (identifier == "except")
+ except = true;
+ else
+ return Error(startLoc, "expected @unwind or @except");
+ return false;
+}
+
+namespace llvm {
+
+MCAsmParserExtension *createCOFFAsmParser() {
+ return new COFFAsmParser;
+}
+
+} // end namespace llvm
diff --git a/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp
new file mode 100644
index 000000000000..bd66e5f39c0d
--- /dev/null
+++ b/llvm/lib/MC/MCParser/DarwinAsmParser.cpp
@@ -0,0 +1,1208 @@
+//===- DarwinAsmParser.cpp - Darwin (Mach-O) Assembly Parser --------------===//
+//
+// 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/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/SectionKind.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+
+/// Implementation of directive handling which is shared across all
+/// Darwin targets.
+class DarwinAsmParser : public MCAsmParserExtension {
+ template<bool (DarwinAsmParser::*HandlerMethod)(StringRef, SMLoc)>
+ void addDirectiveHandler(StringRef Directive) {
+ MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
+ this, HandleDirective<DarwinAsmParser, HandlerMethod>);
+ getParser().addDirectiveHandler(Directive, Handler);
+ }
+
+ bool parseSectionSwitch(StringRef Segment, StringRef Section,
+ unsigned TAA = 0, unsigned ImplicitAlign = 0,
+ unsigned StubSize = 0);
+
+ SMLoc LastVersionDirective;
+
+public:
+ DarwinAsmParser() = default;
+
+ void Initialize(MCAsmParser &Parser) override {
+ // Call the base implementation.
+ this->MCAsmParserExtension::Initialize(Parser);
+
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveAltEntry>(".alt_entry");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveDesc>(".desc");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveIndirectSymbol>(
+ ".indirect_symbol");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveLsym>(".lsym");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveSubsectionsViaSymbols>(
+ ".subsections_via_symbols");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".dump");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveDumpOrLoad>(".load");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveSection>(".section");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectivePushSection>(
+ ".pushsection");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectivePopSection>(
+ ".popsection");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectivePrevious>(".previous");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogUnique>(
+ ".secure_log_unique");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveSecureLogReset>(
+ ".secure_log_reset");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveTBSS>(".tbss");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveZerofill>(".zerofill");
+
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegion>(
+ ".data_region");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveDataRegionEnd>(
+ ".end_data_region");
+
+ // Special section directives.
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveBss>(".bss");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConst>(".const");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstData>(
+ ".const_data");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveConstructor>(
+ ".constructor");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveCString>(
+ ".cstring");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveData>(".data");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDestructor>(
+ ".destructor");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveDyld>(".dyld");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit0>(
+ ".fvmlib_init0");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveFVMLibInit1>(
+ ".fvmlib_init1");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveLazySymbolPointers>(
+ ".lazy_symbol_pointer");
+ addDirectiveHandler<&DarwinAsmParser::parseDirectiveLinkerOption>(
+ ".linker_option");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral16>(
+ ".literal16");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral4>(
+ ".literal4");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveLiteral8>(
+ ".literal8");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModInitFunc>(
+ ".mod_init_func");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveModTermFunc>(
+ ".mod_term_func");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveNonLazySymbolPointers>(
+ ".non_lazy_symbol_pointer");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveThreadLocalVariablePointers>(
+ ".thread_local_variable_pointer");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatClsMeth>(
+ ".objc_cat_cls_meth");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCatInstMeth>(
+ ".objc_cat_inst_meth");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCCategory>(
+ ".objc_category");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClass>(
+ ".objc_class");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassNames>(
+ ".objc_class_names");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClassVars>(
+ ".objc_class_vars");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsMeth>(
+ ".objc_cls_meth");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCClsRefs>(
+ ".objc_cls_refs");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCInstMeth>(
+ ".objc_inst_meth");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveObjCInstanceVars>(
+ ".objc_instance_vars");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMessageRefs>(
+ ".objc_message_refs");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCMetaClass>(
+ ".objc_meta_class");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveObjCMethVarNames>(
+ ".objc_meth_var_names");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveObjCMethVarTypes>(
+ ".objc_meth_var_types");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCModuleInfo>(
+ ".objc_module_info");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCProtocol>(
+ ".objc_protocol");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveObjCSelectorStrs>(
+ ".objc_selector_strs");
+ addDirectiveHandler<
+ &DarwinAsmParser::parseSectionDirectiveObjCStringObject>(
+ ".objc_string_object");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveObjCSymbols>(
+ ".objc_symbols");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectivePICSymbolStub>(
+ ".picsymbol_stub");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticConst>(
+ ".static_const");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveStaticData>(
+ ".static_data");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveSymbolStub>(
+ ".symbol_stub");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTData>(".tdata");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveText>(".text");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveThreadInitFunc>(
+ ".thread_init_func");
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveTLV>(".tlv");
+
+ addDirectiveHandler<&DarwinAsmParser::parseSectionDirectiveIdent>(".ident");
+ addDirectiveHandler<&DarwinAsmParser::parseWatchOSVersionMin>(
+ ".watchos_version_min");
+ addDirectiveHandler<&DarwinAsmParser::parseTvOSVersionMin>(
+ ".tvos_version_min");
+ addDirectiveHandler<&DarwinAsmParser::parseIOSVersionMin>(
+ ".ios_version_min");
+ addDirectiveHandler<&DarwinAsmParser::parseMacOSXVersionMin>(
+ ".macosx_version_min");
+ addDirectiveHandler<&DarwinAsmParser::parseBuildVersion>(".build_version");
+
+ LastVersionDirective = SMLoc();
+ }
+
+ bool parseDirectiveAltEntry(StringRef, SMLoc);
+ bool parseDirectiveDesc(StringRef, SMLoc);
+ bool parseDirectiveIndirectSymbol(StringRef, SMLoc);
+ bool parseDirectiveDumpOrLoad(StringRef, SMLoc);
+ bool parseDirectiveLsym(StringRef, SMLoc);
+ bool parseDirectiveLinkerOption(StringRef, SMLoc);
+ bool parseDirectiveSection(StringRef, SMLoc);
+ bool parseDirectivePushSection(StringRef, SMLoc);
+ bool parseDirectivePopSection(StringRef, SMLoc);
+ bool parseDirectivePrevious(StringRef, SMLoc);
+ bool parseDirectiveSecureLogReset(StringRef, SMLoc);
+ bool parseDirectiveSecureLogUnique(StringRef, SMLoc);
+ bool parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc);
+ bool parseDirectiveTBSS(StringRef, SMLoc);
+ bool parseDirectiveZerofill(StringRef, SMLoc);
+ bool parseDirectiveDataRegion(StringRef, SMLoc);
+ bool parseDirectiveDataRegionEnd(StringRef, SMLoc);
+
+ // Named Section Directive
+ bool parseSectionDirectiveBss(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__bss");
+ }
+
+ bool parseSectionDirectiveConst(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__const");
+ }
+
+ bool parseSectionDirectiveStaticConst(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__static_const");
+ }
+
+ bool parseSectionDirectiveCString(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__cstring",
+ MachO::S_CSTRING_LITERALS);
+ }
+
+ bool parseSectionDirectiveLiteral4(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__literal4",
+ MachO::S_4BYTE_LITERALS, 4);
+ }
+
+ bool parseSectionDirectiveLiteral8(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__literal8",
+ MachO::S_8BYTE_LITERALS, 8);
+ }
+
+ bool parseSectionDirectiveLiteral16(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__literal16",
+ MachO::S_16BYTE_LITERALS, 16);
+ }
+
+ bool parseSectionDirectiveConstructor(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__constructor");
+ }
+
+ bool parseSectionDirectiveDestructor(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__destructor");
+ }
+
+ bool parseSectionDirectiveFVMLibInit0(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__fvmlib_init0");
+ }
+
+ bool parseSectionDirectiveFVMLibInit1(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__fvmlib_init1");
+ }
+
+ bool parseSectionDirectiveSymbolStub(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__symbol_stub",
+ MachO::S_SYMBOL_STUBS |
+ MachO::S_ATTR_PURE_INSTRUCTIONS,
+ // FIXME: Different on PPC and ARM.
+ 0, 16);
+ }
+
+ bool parseSectionDirectivePICSymbolStub(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT","__picsymbol_stub",
+ MachO::S_SYMBOL_STUBS |
+ MachO::S_ATTR_PURE_INSTRUCTIONS, 0, 26);
+ }
+
+ bool parseSectionDirectiveData(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__data");
+ }
+
+ bool parseSectionDirectiveStaticData(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__static_data");
+ }
+
+ bool parseSectionDirectiveNonLazySymbolPointers(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__nl_symbol_ptr",
+ MachO::S_NON_LAZY_SYMBOL_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveLazySymbolPointers(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__la_symbol_ptr",
+ MachO::S_LAZY_SYMBOL_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveThreadLocalVariablePointers(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__thread_ptr",
+ MachO::S_THREAD_LOCAL_VARIABLE_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveDyld(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__dyld");
+ }
+
+ bool parseSectionDirectiveModInitFunc(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__mod_init_func",
+ MachO::S_MOD_INIT_FUNC_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveModTermFunc(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__mod_term_func",
+ MachO::S_MOD_TERM_FUNC_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveConstData(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__const");
+ }
+
+ bool parseSectionDirectiveObjCClass(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__class",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCMetaClass(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__meta_class",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCCatClsMeth(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__cat_cls_meth",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCCatInstMeth(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__cat_inst_meth",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCProtocol(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__protocol",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCStringObject(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__string_object",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCClsMeth(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__cls_meth",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCInstMeth(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__inst_meth",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCClsRefs(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__cls_refs",
+ MachO::S_ATTR_NO_DEAD_STRIP |
+ MachO::S_LITERAL_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveObjCMessageRefs(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__message_refs",
+ MachO::S_ATTR_NO_DEAD_STRIP |
+ MachO::S_LITERAL_POINTERS, 4);
+ }
+
+ bool parseSectionDirectiveObjCSymbols(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__symbols",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCCategory(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__category",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCClassVars(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__class_vars",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCInstanceVars(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__instance_vars",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCModuleInfo(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__module_info",
+ MachO::S_ATTR_NO_DEAD_STRIP);
+ }
+
+ bool parseSectionDirectiveObjCClassNames(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__cstring",
+ MachO::S_CSTRING_LITERALS);
+ }
+
+ bool parseSectionDirectiveObjCMethVarTypes(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__cstring",
+ MachO::S_CSTRING_LITERALS);
+ }
+
+ bool parseSectionDirectiveObjCMethVarNames(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__cstring",
+ MachO::S_CSTRING_LITERALS);
+ }
+
+ bool parseSectionDirectiveObjCSelectorStrs(StringRef, SMLoc) {
+ return parseSectionSwitch("__OBJC", "__selector_strs",
+ MachO::S_CSTRING_LITERALS);
+ }
+
+ bool parseSectionDirectiveTData(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__thread_data",
+ MachO::S_THREAD_LOCAL_REGULAR);
+ }
+
+ bool parseSectionDirectiveText(StringRef, SMLoc) {
+ return parseSectionSwitch("__TEXT", "__text",
+ MachO::S_ATTR_PURE_INSTRUCTIONS);
+ }
+
+ bool parseSectionDirectiveTLV(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__thread_vars",
+ MachO::S_THREAD_LOCAL_VARIABLES);
+ }
+
+ bool parseSectionDirectiveIdent(StringRef, SMLoc) {
+ // Darwin silently ignores the .ident directive.
+ getParser().eatToEndOfStatement();
+ return false;
+ }
+
+ bool parseSectionDirectiveThreadInitFunc(StringRef, SMLoc) {
+ return parseSectionSwitch("__DATA", "__thread_init",
+ MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
+ }
+
+ bool parseWatchOSVersionMin(StringRef Directive, SMLoc Loc) {
+ return parseVersionMin(Directive, Loc, MCVM_WatchOSVersionMin);
+ }
+ bool parseTvOSVersionMin(StringRef Directive, SMLoc Loc) {
+ return parseVersionMin(Directive, Loc, MCVM_TvOSVersionMin);
+ }
+ bool parseIOSVersionMin(StringRef Directive, SMLoc Loc) {
+ return parseVersionMin(Directive, Loc, MCVM_IOSVersionMin);
+ }
+ bool parseMacOSXVersionMin(StringRef Directive, SMLoc Loc) {
+ return parseVersionMin(Directive, Loc, MCVM_OSXVersionMin);
+ }
+
+ bool parseBuildVersion(StringRef Directive, SMLoc Loc);
+ bool parseVersionMin(StringRef Directive, SMLoc Loc, MCVersionMinType Type);
+ bool parseMajorMinorVersionComponent(unsigned *Major, unsigned *Minor,
+ const char *VersionName);
+ bool parseOptionalTrailingVersionComponent(unsigned *Component,
+ const char *ComponentName);
+ bool parseVersion(unsigned *Major, unsigned *Minor, unsigned *Update);
+ bool parseSDKVersion(VersionTuple &SDKVersion);
+ void checkVersion(StringRef Directive, StringRef Arg, SMLoc Loc,
+ Triple::OSType ExpectedOS);
+};
+
+} // end anonymous namespace
+
+bool DarwinAsmParser::parseSectionSwitch(StringRef Segment, StringRef Section,
+ unsigned TAA, unsigned Align,
+ unsigned StubSize) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in section switching directive");
+ Lex();
+
+ // FIXME: Arch specific.
+ bool isText = TAA & MachO::S_ATTR_PURE_INSTRUCTIONS;
+ getStreamer().SwitchSection(getContext().getMachOSection(
+ Segment, Section, TAA, StubSize,
+ isText ? SectionKind::getText() : SectionKind::getData()));
+
+ // Set the implicit alignment, if any.
+ //
+ // FIXME: This isn't really what 'as' does; I think it just uses the implicit
+ // alignment on the section (e.g., if one manually inserts bytes into the
+ // section, then just issuing the section switch directive will not realign
+ // the section. However, this is arguably more reasonable behavior, and there
+ // is no good reason for someone to intentionally emit incorrectly sized
+ // values into the implicitly aligned sections.
+ if (Align)
+ getStreamer().EmitValueToAlignment(Align);
+
+ return false;
+}
+
+/// parseDirectiveAltEntry
+/// ::= .alt_entry identifier
+bool DarwinAsmParser::parseDirectiveAltEntry(StringRef, SMLoc) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Look up symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ if (Sym->isDefined())
+ return TokError(".alt_entry must preceed symbol definition");
+
+ if (!getStreamer().EmitSymbolAttribute(Sym, MCSA_AltEntry))
+ return TokError("unable to emit symbol attribute");
+
+ Lex();
+ return false;
+}
+
+/// parseDirectiveDesc
+/// ::= .desc identifier , expression
+bool DarwinAsmParser::parseDirectiveDesc(StringRef, SMLoc) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in '.desc' directive");
+ Lex();
+
+ int64_t DescValue;
+ if (getParser().parseAbsoluteExpression(DescValue))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.desc' directive");
+
+ Lex();
+
+ // Set the n_desc field of this Symbol to this DescValue
+ getStreamer().EmitSymbolDesc(Sym, DescValue);
+
+ return false;
+}
+
+/// parseDirectiveIndirectSymbol
+/// ::= .indirect_symbol identifier
+bool DarwinAsmParser::parseDirectiveIndirectSymbol(StringRef, SMLoc Loc) {
+ const MCSectionMachO *Current = static_cast<const MCSectionMachO *>(
+ getStreamer().getCurrentSectionOnly());
+ MachO::SectionType SectionType = Current->getType();
+ if (SectionType != MachO::S_NON_LAZY_SYMBOL_POINTERS &&
+ SectionType != MachO::S_LAZY_SYMBOL_POINTERS &&
+ SectionType != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS &&
+ SectionType != MachO::S_SYMBOL_STUBS)
+ return Error(Loc, "indirect symbol not in a symbol pointer or stub "
+ "section");
+
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in .indirect_symbol directive");
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ // Assembler local symbols don't make any sense here. Complain loudly.
+ if (Sym->isTemporary())
+ return TokError("non-local symbol required in directive");
+
+ if (!getStreamer().EmitSymbolAttribute(Sym, MCSA_IndirectSymbol))
+ return TokError("unable to emit indirect symbol attribute for: " + Name);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.indirect_symbol' directive");
+
+ Lex();
+
+ return false;
+}
+
+/// parseDirectiveDumpOrLoad
+/// ::= ( .dump | .load ) "filename"
+bool DarwinAsmParser::parseDirectiveDumpOrLoad(StringRef Directive,
+ SMLoc IDLoc) {
+ bool IsDump = Directive == ".dump";
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("expected string in '.dump' or '.load' directive");
+
+ Lex();
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.dump' or '.load' directive");
+
+ Lex();
+
+ // FIXME: If/when .dump and .load are implemented they will be done in the
+ // the assembly parser and not have any need for an MCStreamer API.
+ if (IsDump)
+ return Warning(IDLoc, "ignoring directive .dump for now");
+ else
+ return Warning(IDLoc, "ignoring directive .load for now");
+}
+
+/// ParseDirectiveLinkerOption
+/// ::= .linker_option "string" ( , "string" )*
+bool DarwinAsmParser::parseDirectiveLinkerOption(StringRef IDVal, SMLoc) {
+ SmallVector<std::string, 4> Args;
+ while (true) {
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("expected string in '" + Twine(IDVal) + "' directive");
+
+ std::string Data;
+ if (getParser().parseEscapedString(Data))
+ return true;
+
+ Args.push_back(Data);
+
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in '" + Twine(IDVal) + "' directive");
+ Lex();
+ }
+
+ getStreamer().EmitLinkerOptions(Args);
+ return false;
+}
+
+/// parseDirectiveLsym
+/// ::= .lsym identifier , expression
+bool DarwinAsmParser::parseDirectiveLsym(StringRef, SMLoc) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in '.lsym' directive");
+ Lex();
+
+ const MCExpr *Value;
+ if (getParser().parseExpression(Value))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.lsym' directive");
+
+ Lex();
+
+ // We don't currently support this directive.
+ //
+ // FIXME: Diagnostic location!
+ (void) Sym;
+ return TokError("directive '.lsym' is unsupported");
+}
+
+/// parseDirectiveSection:
+/// ::= .section identifier (',' identifier)*
+bool DarwinAsmParser::parseDirectiveSection(StringRef, SMLoc) {
+ SMLoc Loc = getLexer().getLoc();
+
+ StringRef SectionName;
+ if (getParser().parseIdentifier(SectionName))
+ return Error(Loc, "expected identifier after '.section' directive");
+
+ // Verify there is a following comma.
+ if (!getLexer().is(AsmToken::Comma))
+ return TokError("unexpected token in '.section' directive");
+
+ std::string SectionSpec = SectionName;
+ SectionSpec += ",";
+
+ // Add all the tokens until the end of the line, ParseSectionSpecifier will
+ // handle this.
+ StringRef EOL = getLexer().LexUntilEndOfStatement();
+ SectionSpec.append(EOL.begin(), EOL.end());
+
+ Lex();
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.section' directive");
+ Lex();
+
+ StringRef Segment, Section;
+ unsigned StubSize;
+ unsigned TAA;
+ bool TAAParsed;
+ std::string ErrorStr =
+ MCSectionMachO::ParseSectionSpecifier(SectionSpec, Segment, Section,
+ TAA, TAAParsed, StubSize);
+
+ if (!ErrorStr.empty())
+ return Error(Loc, ErrorStr);
+
+ // Issue a warning if the target is not powerpc and Section is a *coal* section.
+ Triple TT = getParser().getContext().getObjectFileInfo()->getTargetTriple();
+ Triple::ArchType ArchTy = TT.getArch();
+
+ if (ArchTy != Triple::ppc && ArchTy != Triple::ppc64) {
+ StringRef NonCoalSection = StringSwitch<StringRef>(Section)
+ .Case("__textcoal_nt", "__text")
+ .Case("__const_coal", "__const")
+ .Case("__datacoal_nt", "__data")
+ .Default(Section);
+
+ if (!Section.equals(NonCoalSection)) {
+ StringRef SectionVal(Loc.getPointer());
+ size_t B = SectionVal.find(',') + 1, E = SectionVal.find(',', B);
+ SMLoc BLoc = SMLoc::getFromPointer(SectionVal.data() + B);
+ SMLoc ELoc = SMLoc::getFromPointer(SectionVal.data() + E);
+ getParser().Warning(Loc, "section \"" + Section + "\" is deprecated",
+ SMRange(BLoc, ELoc));
+ getParser().Note(Loc, "change section name to \"" + NonCoalSection +
+ "\"", SMRange(BLoc, ELoc));
+ }
+ }
+
+ // FIXME: Arch specific.
+ bool isText = Segment == "__TEXT"; // FIXME: Hack.
+ getStreamer().SwitchSection(getContext().getMachOSection(
+ Segment, Section, TAA, StubSize,
+ isText ? SectionKind::getText() : SectionKind::getData()));
+ return false;
+}
+
+/// ParseDirectivePushSection:
+/// ::= .pushsection identifier (',' identifier)*
+bool DarwinAsmParser::parseDirectivePushSection(StringRef S, SMLoc Loc) {
+ getStreamer().PushSection();
+
+ if (parseDirectiveSection(S, Loc)) {
+ getStreamer().PopSection();
+ return true;
+ }
+
+ return false;
+}
+
+/// ParseDirectivePopSection:
+/// ::= .popsection
+bool DarwinAsmParser::parseDirectivePopSection(StringRef, SMLoc) {
+ if (!getStreamer().PopSection())
+ return TokError(".popsection without corresponding .pushsection");
+ return false;
+}
+
+/// ParseDirectivePrevious:
+/// ::= .previous
+bool DarwinAsmParser::parseDirectivePrevious(StringRef DirName, SMLoc) {
+ MCSectionSubPair PreviousSection = getStreamer().getPreviousSection();
+ if (!PreviousSection.first)
+ return TokError(".previous without corresponding .section");
+ getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second);
+ return false;
+}
+
+/// ParseDirectiveSecureLogUnique
+/// ::= .secure_log_unique ... message ...
+bool DarwinAsmParser::parseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) {
+ StringRef LogMessage = getParser().parseStringToEndOfStatement();
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.secure_log_unique' directive");
+
+ if (getContext().getSecureLogUsed())
+ return Error(IDLoc, ".secure_log_unique specified multiple times");
+
+ // Get the secure log path.
+ const char *SecureLogFile = getContext().getSecureLogFile();
+ if (!SecureLogFile)
+ return Error(IDLoc, ".secure_log_unique used but AS_SECURE_LOG_FILE "
+ "environment variable unset.");
+
+ // Open the secure log file if we haven't already.
+ raw_fd_ostream *OS = getContext().getSecureLog();
+ if (!OS) {
+ std::error_code EC;
+ auto NewOS = std::make_unique<raw_fd_ostream>(
+ StringRef(SecureLogFile), EC, sys::fs::OF_Append | sys::fs::OF_Text);
+ if (EC)
+ return Error(IDLoc, Twine("can't open secure log file: ") +
+ SecureLogFile + " (" + EC.message() + ")");
+ OS = NewOS.get();
+ getContext().setSecureLog(std::move(NewOS));
+ }
+
+ // Write the message.
+ unsigned CurBuf = getSourceManager().FindBufferContainingLoc(IDLoc);
+ *OS << getSourceManager().getBufferInfo(CurBuf).Buffer->getBufferIdentifier()
+ << ":" << getSourceManager().FindLineNumber(IDLoc, CurBuf) << ":"
+ << LogMessage + "\n";
+
+ getContext().setSecureLogUsed(true);
+
+ return false;
+}
+
+/// ParseDirectiveSecureLogReset
+/// ::= .secure_log_reset
+bool DarwinAsmParser::parseDirectiveSecureLogReset(StringRef, SMLoc IDLoc) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.secure_log_reset' directive");
+
+ Lex();
+
+ getContext().setSecureLogUsed(false);
+
+ return false;
+}
+
+/// parseDirectiveSubsectionsViaSymbols
+/// ::= .subsections_via_symbols
+bool DarwinAsmParser::parseDirectiveSubsectionsViaSymbols(StringRef, SMLoc) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.subsections_via_symbols' directive");
+
+ Lex();
+
+ getStreamer().EmitAssemblerFlag(MCAF_SubsectionsViaSymbols);
+
+ return false;
+}
+
+/// ParseDirectiveTBSS
+/// ::= .tbss identifier, size, align
+bool DarwinAsmParser::parseDirectiveTBSS(StringRef, SMLoc) {
+ SMLoc IDLoc = getLexer().getLoc();
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ int64_t Size;
+ SMLoc SizeLoc = getLexer().getLoc();
+ if (getParser().parseAbsoluteExpression(Size))
+ return true;
+
+ int64_t Pow2Alignment = 0;
+ SMLoc Pow2AlignmentLoc;
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+ Pow2AlignmentLoc = getLexer().getLoc();
+ if (getParser().parseAbsoluteExpression(Pow2Alignment))
+ return true;
+ }
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.tbss' directive");
+
+ Lex();
+
+ if (Size < 0)
+ return Error(SizeLoc, "invalid '.tbss' directive size, can't be less than"
+ "zero");
+
+ // FIXME: Diagnose overflow.
+ if (Pow2Alignment < 0)
+ return Error(Pow2AlignmentLoc, "invalid '.tbss' alignment, can't be less"
+ "than zero");
+
+ if (!Sym->isUndefined())
+ return Error(IDLoc, "invalid symbol redefinition");
+
+ getStreamer().EmitTBSSSymbol(getContext().getMachOSection(
+ "__DATA", "__thread_bss",
+ MachO::S_THREAD_LOCAL_ZEROFILL,
+ 0, SectionKind::getThreadBSS()),
+ Sym, Size, 1 << Pow2Alignment);
+
+ return false;
+}
+
+/// ParseDirectiveZerofill
+/// ::= .zerofill segname , sectname [, identifier , size_expression [
+/// , align_expression ]]
+bool DarwinAsmParser::parseDirectiveZerofill(StringRef, SMLoc) {
+ StringRef Segment;
+ if (getParser().parseIdentifier(Segment))
+ return TokError("expected segment name after '.zerofill' directive");
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ StringRef Section;
+ SMLoc SectionLoc = getLexer().getLoc();
+ if (getParser().parseIdentifier(Section))
+ return TokError("expected section name after comma in '.zerofill' "
+ "directive");
+
+ // If this is the end of the line all that was wanted was to create the
+ // the section but with no symbol.
+ if (getLexer().is(AsmToken::EndOfStatement)) {
+ // Create the zerofill section but no symbol
+ getStreamer().EmitZerofill(
+ getContext().getMachOSection(Segment, Section, MachO::S_ZEROFILL, 0,
+ SectionKind::getBSS()),
+ /*Symbol=*/nullptr, /*Size=*/0, /*ByteAlignment=*/0, SectionLoc);
+ return false;
+ }
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ SMLoc IDLoc = getLexer().getLoc();
+ StringRef IDStr;
+ if (getParser().parseIdentifier(IDStr))
+ return TokError("expected identifier in directive");
+
+ // handle the identifier as the key symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(IDStr);
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ int64_t Size;
+ SMLoc SizeLoc = getLexer().getLoc();
+ if (getParser().parseAbsoluteExpression(Size))
+ return true;
+
+ int64_t Pow2Alignment = 0;
+ SMLoc Pow2AlignmentLoc;
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+ Pow2AlignmentLoc = getLexer().getLoc();
+ if (getParser().parseAbsoluteExpression(Pow2Alignment))
+ return true;
+ }
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.zerofill' directive");
+
+ Lex();
+
+ if (Size < 0)
+ return Error(SizeLoc, "invalid '.zerofill' directive size, can't be less "
+ "than zero");
+
+ // NOTE: The alignment in the directive is a power of 2 value, the assembler
+ // may internally end up wanting an alignment in bytes.
+ // FIXME: Diagnose overflow.
+ if (Pow2Alignment < 0)
+ return Error(Pow2AlignmentLoc, "invalid '.zerofill' directive alignment, "
+ "can't be less than zero");
+
+ if (!Sym->isUndefined())
+ return Error(IDLoc, "invalid symbol redefinition");
+
+ // Create the zerofill Symbol with Size and Pow2Alignment
+ //
+ // FIXME: Arch specific.
+ getStreamer().EmitZerofill(getContext().getMachOSection(
+ Segment, Section, MachO::S_ZEROFILL,
+ 0, SectionKind::getBSS()),
+ Sym, Size, 1 << Pow2Alignment, SectionLoc);
+
+ return false;
+}
+
+/// ParseDirectiveDataRegion
+/// ::= .data_region [ ( jt8 | jt16 | jt32 ) ]
+bool DarwinAsmParser::parseDirectiveDataRegion(StringRef, SMLoc) {
+ if (getLexer().is(AsmToken::EndOfStatement)) {
+ Lex();
+ getStreamer().EmitDataRegion(MCDR_DataRegion);
+ return false;
+ }
+ StringRef RegionType;
+ SMLoc Loc = getParser().getTok().getLoc();
+ if (getParser().parseIdentifier(RegionType))
+ return TokError("expected region type after '.data_region' directive");
+ int Kind = StringSwitch<int>(RegionType)
+ .Case("jt8", MCDR_DataRegionJT8)
+ .Case("jt16", MCDR_DataRegionJT16)
+ .Case("jt32", MCDR_DataRegionJT32)
+ .Default(-1);
+ if (Kind == -1)
+ return Error(Loc, "unknown region type in '.data_region' directive");
+ Lex();
+
+ getStreamer().EmitDataRegion((MCDataRegionType)Kind);
+ return false;
+}
+
+/// ParseDirectiveDataRegionEnd
+/// ::= .end_data_region
+bool DarwinAsmParser::parseDirectiveDataRegionEnd(StringRef, SMLoc) {
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.end_data_region' directive");
+
+ Lex();
+ getStreamer().EmitDataRegion(MCDR_DataRegionEnd);
+ return false;
+}
+
+static bool isSDKVersionToken(const AsmToken &Tok) {
+ return Tok.is(AsmToken::Identifier) && Tok.getIdentifier() == "sdk_version";
+}
+
+/// parseMajorMinorVersionComponent ::= major, minor
+bool DarwinAsmParser::parseMajorMinorVersionComponent(unsigned *Major,
+ unsigned *Minor,
+ const char *VersionName) {
+ // Get the major version number.
+ if (getLexer().isNot(AsmToken::Integer))
+ return TokError(Twine("invalid ") + VersionName +
+ " major version number, integer expected");
+ int64_t MajorVal = getLexer().getTok().getIntVal();
+ if (MajorVal > 65535 || MajorVal <= 0)
+ return TokError(Twine("invalid ") + VersionName + " major version number");
+ *Major = (unsigned)MajorVal;
+ Lex();
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError(Twine(VersionName) +
+ " minor version number required, comma expected");
+ Lex();
+ // Get the minor version number.
+ if (getLexer().isNot(AsmToken::Integer))
+ return TokError(Twine("invalid ") + VersionName +
+ " minor version number, integer expected");
+ int64_t MinorVal = getLexer().getTok().getIntVal();
+ if (MinorVal > 255 || MinorVal < 0)
+ return TokError(Twine("invalid ") + VersionName + " minor version number");
+ *Minor = MinorVal;
+ Lex();
+ return false;
+}
+
+/// parseOptionalTrailingVersionComponent ::= , version_number
+bool DarwinAsmParser::parseOptionalTrailingVersionComponent(
+ unsigned *Component, const char *ComponentName) {
+ assert(getLexer().is(AsmToken::Comma) && "comma expected");
+ Lex();
+ if (getLexer().isNot(AsmToken::Integer))
+ return TokError(Twine("invalid ") + ComponentName +
+ " version number, integer expected");
+ int64_t Val = getLexer().getTok().getIntVal();
+ if (Val > 255 || Val < 0)
+ return TokError(Twine("invalid ") + ComponentName + " version number");
+ *Component = Val;
+ Lex();
+ return false;
+}
+
+/// parseVersion ::= parseMajorMinorVersionComponent
+/// parseOptionalTrailingVersionComponent
+bool DarwinAsmParser::parseVersion(unsigned *Major, unsigned *Minor,
+ unsigned *Update) {
+ if (parseMajorMinorVersionComponent(Major, Minor, "OS"))
+ return true;
+
+ // Get the update level, if specified
+ *Update = 0;
+ if (getLexer().is(AsmToken::EndOfStatement) ||
+ isSDKVersionToken(getLexer().getTok()))
+ return false;
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("invalid OS update specifier, comma expected");
+ if (parseOptionalTrailingVersionComponent(Update, "OS update"))
+ return true;
+ return false;
+}
+
+bool DarwinAsmParser::parseSDKVersion(VersionTuple &SDKVersion) {
+ assert(isSDKVersionToken(getLexer().getTok()) && "expected sdk_version");
+ Lex();
+ unsigned Major, Minor;
+ if (parseMajorMinorVersionComponent(&Major, &Minor, "SDK"))
+ return true;
+ SDKVersion = VersionTuple(Major, Minor);
+
+ // Get the subminor version, if specified.
+ if (getLexer().is(AsmToken::Comma)) {
+ unsigned Subminor;
+ if (parseOptionalTrailingVersionComponent(&Subminor, "SDK subminor"))
+ return true;
+ SDKVersion = VersionTuple(Major, Minor, Subminor);
+ }
+ return false;
+}
+
+void DarwinAsmParser::checkVersion(StringRef Directive, StringRef Arg,
+ SMLoc Loc, Triple::OSType ExpectedOS) {
+ const Triple &Target = getContext().getObjectFileInfo()->getTargetTriple();
+ if (Target.getOS() != ExpectedOS)
+ Warning(Loc, Twine(Directive) +
+ (Arg.empty() ? Twine() : Twine(' ') + Arg) +
+ " used while targeting " + Target.getOSName());
+
+ if (LastVersionDirective.isValid()) {
+ Warning(Loc, "overriding previous version directive");
+ Note(LastVersionDirective, "previous definition is here");
+ }
+ LastVersionDirective = Loc;
+}
+
+static Triple::OSType getOSTypeFromMCVM(MCVersionMinType Type) {
+ switch (Type) {
+ case MCVM_WatchOSVersionMin: return Triple::WatchOS;
+ case MCVM_TvOSVersionMin: return Triple::TvOS;
+ case MCVM_IOSVersionMin: return Triple::IOS;
+ case MCVM_OSXVersionMin: return Triple::MacOSX;
+ }
+ llvm_unreachable("Invalid mc version min type");
+}
+
+/// parseVersionMin
+/// ::= .ios_version_min parseVersion parseSDKVersion
+/// | .macosx_version_min parseVersion parseSDKVersion
+/// | .tvos_version_min parseVersion parseSDKVersion
+/// | .watchos_version_min parseVersion parseSDKVersion
+bool DarwinAsmParser::parseVersionMin(StringRef Directive, SMLoc Loc,
+ MCVersionMinType Type) {
+ unsigned Major;
+ unsigned Minor;
+ unsigned Update;
+ if (parseVersion(&Major, &Minor, &Update))
+ return true;
+
+ VersionTuple SDKVersion;
+ if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion))
+ return true;
+
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(Twine(" in '") + Directive + "' directive");
+
+ Triple::OSType ExpectedOS = getOSTypeFromMCVM(Type);
+ checkVersion(Directive, StringRef(), Loc, ExpectedOS);
+ getStreamer().EmitVersionMin(Type, Major, Minor, Update, SDKVersion);
+ return false;
+}
+
+static Triple::OSType getOSTypeFromPlatform(MachO::PlatformType Type) {
+ switch (Type) {
+ case MachO::PLATFORM_MACOS: return Triple::MacOSX;
+ case MachO::PLATFORM_IOS: return Triple::IOS;
+ case MachO::PLATFORM_TVOS: return Triple::TvOS;
+ case MachO::PLATFORM_WATCHOS: return Triple::WatchOS;
+ case MachO::PLATFORM_BRIDGEOS: /* silence warning */ break;
+ case MachO::PLATFORM_MACCATALYST: return Triple::IOS;
+ case MachO::PLATFORM_IOSSIMULATOR: /* silence warning */ break;
+ case MachO::PLATFORM_TVOSSIMULATOR: /* silence warning */ break;
+ case MachO::PLATFORM_WATCHOSSIMULATOR: /* silence warning */ break;
+ }
+ llvm_unreachable("Invalid mach-o platform type");
+}
+
+/// parseBuildVersion
+/// ::= .build_version (macos|ios|tvos|watchos), parseVersion parseSDKVersion
+bool DarwinAsmParser::parseBuildVersion(StringRef Directive, SMLoc Loc) {
+ StringRef PlatformName;
+ SMLoc PlatformLoc = getTok().getLoc();
+ if (getParser().parseIdentifier(PlatformName))
+ return TokError("platform name expected");
+
+ unsigned Platform = StringSwitch<unsigned>(PlatformName)
+ .Case("macos", MachO::PLATFORM_MACOS)
+ .Case("ios", MachO::PLATFORM_IOS)
+ .Case("tvos", MachO::PLATFORM_TVOS)
+ .Case("watchos", MachO::PLATFORM_WATCHOS)
+ .Case("macCatalyst", MachO::PLATFORM_MACCATALYST)
+ .Default(0);
+ if (Platform == 0)
+ return Error(PlatformLoc, "unknown platform name");
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("version number required, comma expected");
+ Lex();
+
+ unsigned Major;
+ unsigned Minor;
+ unsigned Update;
+ if (parseVersion(&Major, &Minor, &Update))
+ return true;
+
+ VersionTuple SDKVersion;
+ if (isSDKVersionToken(getLexer().getTok()) && parseSDKVersion(SDKVersion))
+ return true;
+
+ if (parseToken(AsmToken::EndOfStatement))
+ return addErrorSuffix(" in '.build_version' directive");
+
+ Triple::OSType ExpectedOS
+ = getOSTypeFromPlatform((MachO::PlatformType)Platform);
+ checkVersion(Directive, PlatformName, Loc, ExpectedOS);
+ getStreamer().EmitBuildVersion(Platform, Major, Minor, Update, SDKVersion);
+ return false;
+}
+
+
+namespace llvm {
+
+MCAsmParserExtension *createDarwinAsmParser() {
+ return new DarwinAsmParser;
+}
+
+} // end llvm namespace
diff --git a/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
new file mode 100644
index 000000000000..a55bdd5364cb
--- /dev/null
+++ b/llvm/lib/MC/MCParser/ELFAsmParser.cpp
@@ -0,0 +1,899 @@
+//===- ELFAsmParser.cpp - ELF Assembly Parser -----------------------------===//
+//
+// 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/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.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/SectionKind.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SMLoc.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+
+class ELFAsmParser : public MCAsmParserExtension {
+ template<bool (ELFAsmParser::*HandlerMethod)(StringRef, SMLoc)>
+ void addDirectiveHandler(StringRef Directive) {
+ MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
+ this, HandleDirective<ELFAsmParser, HandlerMethod>);
+
+ getParser().addDirectiveHandler(Directive, Handler);
+ }
+
+ bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags,
+ SectionKind Kind);
+
+public:
+ ELFAsmParser() { BracketExpressionsSupported = true; }
+
+ void Initialize(MCAsmParser &Parser) override {
+ // Call the base implementation.
+ this->MCAsmParserExtension::Initialize(Parser);
+
+ addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveData>(".data");
+ addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveText>(".text");
+ addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveBSS>(".bss");
+ addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveRoData>(".rodata");
+ addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTData>(".tdata");
+ addDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveTBSS>(".tbss");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseSectionDirectiveDataRel>(".data.rel");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseSectionDirectiveDataRelRo>(".data.rel.ro");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseDirectivePushSection>(".pushsection");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveVersion>(".version");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".weak");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveSymbolAttribute>(".local");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseDirectiveSymbolAttribute>(".protected");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseDirectiveSymbolAttribute>(".internal");
+ addDirectiveHandler<
+ &ELFAsmParser::ParseDirectiveSymbolAttribute>(".hidden");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveSubsection>(".subsection");
+ addDirectiveHandler<&ELFAsmParser::ParseDirectiveCGProfile>(".cg_profile");
+ }
+
+ // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is
+ // the best way for us to get access to it?
+ bool ParseSectionDirectiveData(StringRef, SMLoc) {
+ return ParseSectionSwitch(".data", ELF::SHT_PROGBITS,
+ ELF::SHF_WRITE | ELF::SHF_ALLOC,
+ SectionKind::getData());
+ }
+ bool ParseSectionDirectiveText(StringRef, SMLoc) {
+ return ParseSectionSwitch(".text", ELF::SHT_PROGBITS,
+ ELF::SHF_EXECINSTR |
+ ELF::SHF_ALLOC, SectionKind::getText());
+ }
+ bool ParseSectionDirectiveBSS(StringRef, SMLoc) {
+ return ParseSectionSwitch(".bss", ELF::SHT_NOBITS,
+ ELF::SHF_WRITE |
+ ELF::SHF_ALLOC, SectionKind::getBSS());
+ }
+ bool ParseSectionDirectiveRoData(StringRef, SMLoc) {
+ return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC,
+ SectionKind::getReadOnly());
+ }
+ bool ParseSectionDirectiveTData(StringRef, SMLoc) {
+ return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC |
+ ELF::SHF_TLS | ELF::SHF_WRITE,
+ SectionKind::getThreadData());
+ }
+ bool ParseSectionDirectiveTBSS(StringRef, SMLoc) {
+ return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS,
+ ELF::SHF_ALLOC |
+ ELF::SHF_TLS | ELF::SHF_WRITE,
+ SectionKind::getThreadBSS());
+ }
+ bool ParseSectionDirectiveDataRel(StringRef, SMLoc) {
+ return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_WRITE,
+ SectionKind::getData());
+ }
+ bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) {
+ return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC |
+ ELF::SHF_WRITE,
+ SectionKind::getReadOnlyWithRel());
+ }
+ bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) {
+ return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS,
+ ELF::SHF_ALLOC | ELF::SHF_WRITE,
+ SectionKind::getData());
+ }
+ bool ParseDirectivePushSection(StringRef, SMLoc);
+ bool ParseDirectivePopSection(StringRef, SMLoc);
+ bool ParseDirectiveSection(StringRef, SMLoc);
+ bool ParseDirectiveSize(StringRef, SMLoc);
+ bool ParseDirectivePrevious(StringRef, SMLoc);
+ bool ParseDirectiveType(StringRef, SMLoc);
+ bool ParseDirectiveIdent(StringRef, SMLoc);
+ bool ParseDirectiveSymver(StringRef, SMLoc);
+ bool ParseDirectiveVersion(StringRef, SMLoc);
+ bool ParseDirectiveWeakref(StringRef, SMLoc);
+ bool ParseDirectiveSymbolAttribute(StringRef, SMLoc);
+ bool ParseDirectiveSubsection(StringRef, SMLoc);
+ bool ParseDirectiveCGProfile(StringRef, SMLoc);
+
+private:
+ bool ParseSectionName(StringRef &SectionName);
+ bool ParseSectionArguments(bool IsPush, SMLoc loc);
+ unsigned parseSunStyleSectionFlags();
+ bool maybeParseSectionType(StringRef &TypeName);
+ bool parseMergeSize(int64_t &Size);
+ bool parseGroup(StringRef &GroupName);
+ bool parseMetadataSym(MCSymbolELF *&Associated);
+ bool maybeParseUniqueID(int64_t &UniqueID);
+};
+
+} // end anonymous namespace
+
+/// ParseDirectiveSymbolAttribute
+/// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ]
+bool ELFAsmParser::ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
+ MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
+ .Case(".weak", MCSA_Weak)
+ .Case(".local", MCSA_Local)
+ .Case(".hidden", MCSA_Hidden)
+ .Case(".internal", MCSA_Internal)
+ .Case(".protected", MCSA_Protected)
+ .Default(MCSA_Invalid);
+ assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ while (true) {
+ StringRef Name;
+
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ getStreamer().EmitSymbolAttribute(Sym, Attr);
+
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+ }
+ }
+
+ Lex();
+ return false;
+}
+
+bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type,
+ unsigned Flags, SectionKind Kind) {
+ const MCExpr *Subsection = nullptr;
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ if (getParser().parseExpression(Subsection))
+ return true;
+ }
+ Lex();
+
+ getStreamer().SwitchSection(getContext().getELFSection(Section, Type, Flags),
+ Subsection);
+
+ return false;
+}
+
+bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+ MCSymbolELF *Sym = cast<MCSymbolELF>(getContext().getOrCreateSymbol(Name));
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ const MCExpr *Expr;
+ if (getParser().parseExpression(Expr))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ getStreamer().emitELFSize(Sym, Expr);
+ return false;
+}
+
+bool ELFAsmParser::ParseSectionName(StringRef &SectionName) {
+ // A section name can contain -, so we cannot just use
+ // parseIdentifier.
+ SMLoc FirstLoc = getLexer().getLoc();
+ unsigned Size = 0;
+
+ if (getLexer().is(AsmToken::String)) {
+ SectionName = getTok().getIdentifier();
+ Lex();
+ return false;
+ }
+
+ while (!getParser().hasPendingError()) {
+ SMLoc PrevLoc = getLexer().getLoc();
+ if (getLexer().is(AsmToken::Comma) ||
+ getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ unsigned CurSize;
+ if (getLexer().is(AsmToken::String)) {
+ CurSize = getTok().getIdentifier().size() + 2;
+ Lex();
+ } else if (getLexer().is(AsmToken::Identifier)) {
+ CurSize = getTok().getIdentifier().size();
+ Lex();
+ } else {
+ CurSize = getTok().getString().size();
+ Lex();
+ }
+ Size += CurSize;
+ SectionName = StringRef(FirstLoc.getPointer(), Size);
+
+ // Make sure the following token is adjacent.
+ if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer())
+ break;
+ }
+ if (Size == 0)
+ return true;
+
+ return false;
+}
+
+static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) {
+ unsigned flags = 0;
+
+ // If a valid numerical value is set for the section flag, use it verbatim
+ if (!flagsStr.getAsInteger(0, flags))
+ return flags;
+
+ for (char i : flagsStr) {
+ switch (i) {
+ case 'a':
+ flags |= ELF::SHF_ALLOC;
+ break;
+ case 'e':
+ flags |= ELF::SHF_EXCLUDE;
+ break;
+ case 'x':
+ flags |= ELF::SHF_EXECINSTR;
+ break;
+ case 'w':
+ flags |= ELF::SHF_WRITE;
+ break;
+ case 'o':
+ flags |= ELF::SHF_LINK_ORDER;
+ break;
+ case 'M':
+ flags |= ELF::SHF_MERGE;
+ break;
+ case 'S':
+ flags |= ELF::SHF_STRINGS;
+ break;
+ case 'T':
+ flags |= ELF::SHF_TLS;
+ break;
+ case 'c':
+ flags |= ELF::XCORE_SHF_CP_SECTION;
+ break;
+ case 'd':
+ flags |= ELF::XCORE_SHF_DP_SECTION;
+ break;
+ case 'y':
+ flags |= ELF::SHF_ARM_PURECODE;
+ break;
+ case 's':
+ flags |= ELF::SHF_HEX_GPREL;
+ break;
+ case 'G':
+ flags |= ELF::SHF_GROUP;
+ break;
+ case '?':
+ *UseLastGroup = true;
+ break;
+ default:
+ return -1U;
+ }
+ }
+
+ return flags;
+}
+
+unsigned ELFAsmParser::parseSunStyleSectionFlags() {
+ unsigned flags = 0;
+ while (getLexer().is(AsmToken::Hash)) {
+ Lex(); // Eat the #.
+
+ if (!getLexer().is(AsmToken::Identifier))
+ return -1U;
+
+ StringRef flagId = getTok().getIdentifier();
+ if (flagId == "alloc")
+ flags |= ELF::SHF_ALLOC;
+ else if (flagId == "execinstr")
+ flags |= ELF::SHF_EXECINSTR;
+ else if (flagId == "write")
+ flags |= ELF::SHF_WRITE;
+ else if (flagId == "tls")
+ flags |= ELF::SHF_TLS;
+ else
+ return -1U;
+
+ Lex(); // Eat the flag.
+
+ if (!getLexer().is(AsmToken::Comma))
+ break;
+ Lex(); // Eat the comma.
+ }
+ return flags;
+}
+
+
+bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) {
+ getStreamer().PushSection();
+
+ if (ParseSectionArguments(/*IsPush=*/true, loc)) {
+ getStreamer().PopSection();
+ return true;
+ }
+
+ return false;
+}
+
+bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) {
+ if (!getStreamer().PopSection())
+ return TokError(".popsection without corresponding .pushsection");
+ return false;
+}
+
+bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc loc) {
+ return ParseSectionArguments(/*IsPush=*/false, loc);
+}
+
+bool ELFAsmParser::maybeParseSectionType(StringRef &TypeName) {
+ MCAsmLexer &L = getLexer();
+ if (L.isNot(AsmToken::Comma))
+ return false;
+ Lex();
+ if (L.isNot(AsmToken::At) && L.isNot(AsmToken::Percent) &&
+ L.isNot(AsmToken::String)) {
+ if (L.getAllowAtInIdentifier())
+ return TokError("expected '@<type>', '%<type>' or \"<type>\"");
+ else
+ return TokError("expected '%<type>' or \"<type>\"");
+ }
+ if (!L.is(AsmToken::String))
+ Lex();
+ if (L.is(AsmToken::Integer)) {
+ TypeName = getTok().getString();
+ Lex();
+ } else if (getParser().parseIdentifier(TypeName))
+ return TokError("expected identifier in directive");
+ return false;
+}
+
+bool ELFAsmParser::parseMergeSize(int64_t &Size) {
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("expected the entry size");
+ Lex();
+ if (getParser().parseAbsoluteExpression(Size))
+ return true;
+ if (Size <= 0)
+ return TokError("entry size must be positive");
+ return false;
+}
+
+bool ELFAsmParser::parseGroup(StringRef &GroupName) {
+ MCAsmLexer &L = getLexer();
+ if (L.isNot(AsmToken::Comma))
+ return TokError("expected group name");
+ Lex();
+ if (L.is(AsmToken::Integer)) {
+ GroupName = getTok().getString();
+ Lex();
+ } else if (getParser().parseIdentifier(GroupName)) {
+ return TokError("invalid group name");
+ }
+ if (L.is(AsmToken::Comma)) {
+ Lex();
+ StringRef Linkage;
+ if (getParser().parseIdentifier(Linkage))
+ return TokError("invalid linkage");
+ if (Linkage != "comdat")
+ return TokError("Linkage must be 'comdat'");
+ }
+ return false;
+}
+
+bool ELFAsmParser::parseMetadataSym(MCSymbolELF *&Associated) {
+ MCAsmLexer &L = getLexer();
+ if (L.isNot(AsmToken::Comma))
+ return TokError("expected metadata symbol");
+ Lex();
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("invalid metadata symbol");
+ Associated = dyn_cast_or_null<MCSymbolELF>(getContext().lookupSymbol(Name));
+ if (!Associated || !Associated->isInSection())
+ return TokError("symbol is not in a section: " + Name);
+ return false;
+}
+
+bool ELFAsmParser::maybeParseUniqueID(int64_t &UniqueID) {
+ MCAsmLexer &L = getLexer();
+ if (L.isNot(AsmToken::Comma))
+ return false;
+ Lex();
+ StringRef UniqueStr;
+ if (getParser().parseIdentifier(UniqueStr))
+ return TokError("expected identifier in directive");
+ if (UniqueStr != "unique")
+ return TokError("expected 'unique'");
+ if (L.isNot(AsmToken::Comma))
+ return TokError("expected commma");
+ Lex();
+ if (getParser().parseAbsoluteExpression(UniqueID))
+ return true;
+ if (UniqueID < 0)
+ return TokError("unique id must be positive");
+ if (!isUInt<32>(UniqueID) || UniqueID == ~0U)
+ return TokError("unique id is too large");
+ return false;
+}
+
+static bool hasPrefix(StringRef SectionName, StringRef Prefix) {
+ return SectionName.startswith(Prefix) || SectionName == Prefix.drop_back();
+}
+
+bool ELFAsmParser::ParseSectionArguments(bool IsPush, SMLoc loc) {
+ StringRef SectionName;
+
+ if (ParseSectionName(SectionName))
+ return TokError("expected identifier in directive");
+
+ StringRef TypeName;
+ int64_t Size = 0;
+ StringRef GroupName;
+ unsigned Flags = 0;
+ const MCExpr *Subsection = nullptr;
+ bool UseLastGroup = false;
+ MCSymbolELF *Associated = nullptr;
+ int64_t UniqueID = ~0;
+
+ // Set the defaults first.
+ if (hasPrefix(SectionName, ".rodata.") || SectionName == ".rodata1")
+ Flags |= ELF::SHF_ALLOC;
+ else if (SectionName == ".fini" || SectionName == ".init" ||
+ hasPrefix(SectionName, ".text."))
+ Flags |= ELF::SHF_ALLOC | ELF::SHF_EXECINSTR;
+ else if (hasPrefix(SectionName, ".data.") || SectionName == ".data1" ||
+ hasPrefix(SectionName, ".bss.") ||
+ hasPrefix(SectionName, ".init_array.") ||
+ hasPrefix(SectionName, ".fini_array.") ||
+ hasPrefix(SectionName, ".preinit_array."))
+ Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE;
+ else if (hasPrefix(SectionName, ".tdata.") ||
+ hasPrefix(SectionName, ".tbss."))
+ Flags |= ELF::SHF_ALLOC | ELF::SHF_WRITE | ELF::SHF_TLS;
+
+ if (getLexer().is(AsmToken::Comma)) {
+ Lex();
+
+ if (IsPush && getLexer().isNot(AsmToken::String)) {
+ if (getParser().parseExpression(Subsection))
+ return true;
+ if (getLexer().isNot(AsmToken::Comma))
+ goto EndStmt;
+ Lex();
+ }
+
+ unsigned extraFlags;
+
+ if (getLexer().isNot(AsmToken::String)) {
+ if (!getContext().getAsmInfo()->usesSunStyleELFSectionSwitchSyntax()
+ || getLexer().isNot(AsmToken::Hash))
+ return TokError("expected string in directive");
+ extraFlags = parseSunStyleSectionFlags();
+ } else {
+ StringRef FlagsStr = getTok().getStringContents();
+ Lex();
+ extraFlags = parseSectionFlags(FlagsStr, &UseLastGroup);
+ }
+
+ if (extraFlags == -1U)
+ return TokError("unknown flag");
+ Flags |= extraFlags;
+
+ bool Mergeable = Flags & ELF::SHF_MERGE;
+ bool Group = Flags & ELF::SHF_GROUP;
+ if (Group && UseLastGroup)
+ return TokError("Section cannot specifiy a group name while also acting "
+ "as a member of the last group");
+
+ if (maybeParseSectionType(TypeName))
+ return true;
+
+ MCAsmLexer &L = getLexer();
+ if (TypeName.empty()) {
+ if (Mergeable)
+ return TokError("Mergeable section must specify the type");
+ if (Group)
+ return TokError("Group section must specify the type");
+ if (L.isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+ }
+
+ if (Mergeable)
+ if (parseMergeSize(Size))
+ return true;
+ if (Group)
+ if (parseGroup(GroupName))
+ return true;
+ if (Flags & ELF::SHF_LINK_ORDER)
+ if (parseMetadataSym(Associated))
+ return true;
+ if (maybeParseUniqueID(UniqueID))
+ return true;
+ }
+
+EndStmt:
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+ Lex();
+
+ unsigned Type = ELF::SHT_PROGBITS;
+
+ if (TypeName.empty()) {
+ if (SectionName.startswith(".note"))
+ Type = ELF::SHT_NOTE;
+ else if (hasPrefix(SectionName, ".init_array."))
+ Type = ELF::SHT_INIT_ARRAY;
+ else if (hasPrefix(SectionName, ".bss."))
+ Type = ELF::SHT_NOBITS;
+ else if (hasPrefix(SectionName, ".tbss."))
+ Type = ELF::SHT_NOBITS;
+ else if (hasPrefix(SectionName, ".fini_array."))
+ Type = ELF::SHT_FINI_ARRAY;
+ else if (hasPrefix(SectionName, ".preinit_array."))
+ Type = ELF::SHT_PREINIT_ARRAY;
+ } else {
+ if (TypeName == "init_array")
+ Type = ELF::SHT_INIT_ARRAY;
+ else if (TypeName == "fini_array")
+ Type = ELF::SHT_FINI_ARRAY;
+ else if (TypeName == "preinit_array")
+ Type = ELF::SHT_PREINIT_ARRAY;
+ else if (TypeName == "nobits")
+ Type = ELF::SHT_NOBITS;
+ else if (TypeName == "progbits")
+ Type = ELF::SHT_PROGBITS;
+ else if (TypeName == "note")
+ Type = ELF::SHT_NOTE;
+ else if (TypeName == "unwind")
+ Type = ELF::SHT_X86_64_UNWIND;
+ else if (TypeName == "llvm_odrtab")
+ Type = ELF::SHT_LLVM_ODRTAB;
+ else if (TypeName == "llvm_linker_options")
+ Type = ELF::SHT_LLVM_LINKER_OPTIONS;
+ else if (TypeName == "llvm_call_graph_profile")
+ Type = ELF::SHT_LLVM_CALL_GRAPH_PROFILE;
+ else if (TypeName == "llvm_dependent_libraries")
+ Type = ELF::SHT_LLVM_DEPENDENT_LIBRARIES;
+ else if (TypeName == "llvm_sympart")
+ Type = ELF::SHT_LLVM_SYMPART;
+ else if (TypeName.getAsInteger(0, Type))
+ return TokError("unknown section type");
+ }
+
+ if (UseLastGroup) {
+ MCSectionSubPair CurrentSection = getStreamer().getCurrentSection();
+ if (const MCSectionELF *Section =
+ cast_or_null<MCSectionELF>(CurrentSection.first))
+ if (const MCSymbol *Group = Section->getGroup()) {
+ GroupName = Group->getName();
+ Flags |= ELF::SHF_GROUP;
+ }
+ }
+
+ MCSection *ELFSection =
+ getContext().getELFSection(SectionName, Type, Flags, Size, GroupName,
+ UniqueID, Associated);
+ getStreamer().SwitchSection(ELFSection, Subsection);
+
+ if (getContext().getGenDwarfForAssembly()) {
+ bool InsertResult = getContext().addGenDwarfSection(ELFSection);
+ if (InsertResult) {
+ if (getContext().getDwarfVersion() <= 2)
+ Warning(loc, "DWARF2 only supports one section per compilation unit");
+
+ if (!ELFSection->getBeginSymbol()) {
+ MCSymbol *SectionStartSymbol = getContext().createTempSymbol();
+ getStreamer().EmitLabel(SectionStartSymbol);
+ ELFSection->setBeginSymbol(SectionStartSymbol);
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) {
+ MCSectionSubPair PreviousSection = getStreamer().getPreviousSection();
+ if (PreviousSection.first == nullptr)
+ return TokError(".previous without corresponding .section");
+ getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second);
+
+ return false;
+}
+
+static MCSymbolAttr MCAttrForString(StringRef Type) {
+ return StringSwitch<MCSymbolAttr>(Type)
+ .Cases("STT_FUNC", "function", MCSA_ELF_TypeFunction)
+ .Cases("STT_OBJECT", "object", MCSA_ELF_TypeObject)
+ .Cases("STT_TLS", "tls_object", MCSA_ELF_TypeTLS)
+ .Cases("STT_COMMON", "common", MCSA_ELF_TypeCommon)
+ .Cases("STT_NOTYPE", "notype", MCSA_ELF_TypeNoType)
+ .Cases("STT_GNU_IFUNC", "gnu_indirect_function",
+ MCSA_ELF_TypeIndFunction)
+ .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject)
+ .Default(MCSA_Invalid);
+}
+
+/// ParseDirectiveELFType
+/// ::= .type identifier , STT_<TYPE_IN_UPPER_CASE>
+/// ::= .type identifier , #attribute
+/// ::= .type identifier , @attribute
+/// ::= .type identifier , %attribute
+/// ::= .type identifier , "attribute"
+bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ // Handle the identifier as the key symbol.
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ // NOTE the comma is optional in all cases. It is only documented as being
+ // optional in the first case, however, GAS will silently treat the comma as
+ // optional in all cases. Furthermore, although the documentation states that
+ // the first form only accepts STT_<TYPE_IN_UPPER_CASE>, in reality, GAS
+ // accepts both the upper case name as well as the lower case aliases.
+ if (getLexer().is(AsmToken::Comma))
+ Lex();
+
+ if (getLexer().isNot(AsmToken::Identifier) &&
+ getLexer().isNot(AsmToken::Hash) &&
+ getLexer().isNot(AsmToken::Percent) &&
+ getLexer().isNot(AsmToken::String)) {
+ if (!getLexer().getAllowAtInIdentifier())
+ return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', "
+ "'%<type>' or \"<type>\"");
+ else if (getLexer().isNot(AsmToken::At))
+ return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', '@<type>', "
+ "'%<type>' or \"<type>\"");
+ }
+
+ if (getLexer().isNot(AsmToken::String) &&
+ getLexer().isNot(AsmToken::Identifier))
+ Lex();
+
+ SMLoc TypeLoc = getLexer().getLoc();
+
+ StringRef Type;
+ if (getParser().parseIdentifier(Type))
+ return TokError("expected symbol type in directive");
+
+ MCSymbolAttr Attr = MCAttrForString(Type);
+ if (Attr == MCSA_Invalid)
+ return Error(TypeLoc, "unsupported attribute in '.type' directive");
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.type' directive");
+ Lex();
+
+ getStreamer().EmitSymbolAttribute(Sym, Attr);
+
+ return false;
+}
+
+/// ParseDirectiveIdent
+/// ::= .ident string
+bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) {
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("unexpected token in '.ident' directive");
+
+ StringRef Data = getTok().getIdentifier();
+
+ Lex();
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.ident' directive");
+ Lex();
+
+ getStreamer().EmitIdent(Data);
+ return false;
+}
+
+/// ParseDirectiveSymver
+/// ::= .symver foo, bar2@zed
+bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("expected a comma");
+
+ // ARM assembly uses @ for a comment...
+ // except when parsing the second parameter of the .symver directive.
+ // Force the next symbol to allow @ in the identifier, which is
+ // required for this directive and then reset it to its initial state.
+ const bool AllowAtInIdentifier = getLexer().getAllowAtInIdentifier();
+ getLexer().setAllowAtInIdentifier(true);
+ Lex();
+ getLexer().setAllowAtInIdentifier(AllowAtInIdentifier);
+
+ StringRef AliasName;
+ if (getParser().parseIdentifier(AliasName))
+ return TokError("expected identifier in directive");
+
+ if (AliasName.find('@') == StringRef::npos)
+ return TokError("expected a '@' in the name");
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+ getStreamer().emitELFSymverDirective(AliasName, Sym);
+ return false;
+}
+
+/// ParseDirectiveVersion
+/// ::= .version string
+bool ELFAsmParser::ParseDirectiveVersion(StringRef, SMLoc) {
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("unexpected token in '.version' directive");
+
+ StringRef Data = getTok().getIdentifier();
+
+ Lex();
+
+ MCSection *Note = getContext().getELFSection(".note", ELF::SHT_NOTE, 0);
+
+ getStreamer().PushSection();
+ getStreamer().SwitchSection(Note);
+ getStreamer().EmitIntValue(Data.size()+1, 4); // namesz.
+ getStreamer().EmitIntValue(0, 4); // descsz = 0 (no description).
+ getStreamer().EmitIntValue(1, 4); // type = NT_VERSION.
+ getStreamer().EmitBytes(Data); // name.
+ getStreamer().EmitIntValue(0, 1); // terminate the string.
+ getStreamer().EmitValueToAlignment(4); // ensure 4 byte alignment.
+ getStreamer().PopSection();
+ return false;
+}
+
+/// ParseDirectiveWeakref
+/// ::= .weakref foo, bar
+bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) {
+ // FIXME: Share code with the other alias building directives.
+
+ StringRef AliasName;
+ if (getParser().parseIdentifier(AliasName))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("expected a comma");
+
+ Lex();
+
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
+
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+
+ getStreamer().EmitWeakReference(Alias, Sym);
+ return false;
+}
+
+bool ELFAsmParser::ParseDirectiveSubsection(StringRef, SMLoc) {
+ const MCExpr *Subsection = nullptr;
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ if (getParser().parseExpression(Subsection))
+ return true;
+ }
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ Lex();
+
+ getStreamer().SubSection(Subsection);
+ return false;
+}
+
+/// ParseDirectiveCGProfile
+/// ::= .cg_profile identifier, identifier, <number>
+bool ELFAsmParser::ParseDirectiveCGProfile(StringRef, SMLoc) {
+ StringRef From;
+ SMLoc FromLoc = getLexer().getLoc();
+ if (getParser().parseIdentifier(From))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("expected a comma");
+ Lex();
+
+ StringRef To;
+ SMLoc ToLoc = getLexer().getLoc();
+ if (getParser().parseIdentifier(To))
+ return TokError("expected identifier in directive");
+
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("expected a comma");
+ Lex();
+
+ int64_t Count;
+ if (getParser().parseIntToken(
+ Count, "expected integer count in '.cg_profile' directive"))
+ return true;
+
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in directive");
+
+ MCSymbol *FromSym = getContext().getOrCreateSymbol(From);
+ MCSymbol *ToSym = getContext().getOrCreateSymbol(To);
+
+ getStreamer().emitCGProfileEntry(
+ MCSymbolRefExpr::create(FromSym, MCSymbolRefExpr::VK_None, getContext(),
+ FromLoc),
+ MCSymbolRefExpr::create(ToSym, MCSymbolRefExpr::VK_None, getContext(),
+ ToLoc),
+ Count);
+ return false;
+}
+
+namespace llvm {
+
+MCAsmParserExtension *createELFAsmParser() {
+ return new ELFAsmParser;
+}
+
+} // end namespace llvm
diff --git a/llvm/lib/MC/MCParser/MCAsmLexer.cpp b/llvm/lib/MC/MCParser/MCAsmLexer.cpp
new file mode 100644
index 000000000000..497055bc1760
--- /dev/null
+++ b/llvm/lib/MC/MCParser/MCAsmLexer.cpp
@@ -0,0 +1,129 @@
+//===- MCAsmLexer.cpp - Abstract Asm Lexer 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/MCParser/MCAsmLexer.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+MCAsmLexer::MCAsmLexer() {
+ CurTok.emplace_back(AsmToken::Space, StringRef());
+}
+
+MCAsmLexer::~MCAsmLexer() = default;
+
+SMLoc MCAsmLexer::getLoc() const {
+ return SMLoc::getFromPointer(TokStart);
+}
+
+SMLoc AsmToken::getLoc() const {
+ return SMLoc::getFromPointer(Str.data());
+}
+
+SMLoc AsmToken::getEndLoc() const {
+ return SMLoc::getFromPointer(Str.data() + Str.size());
+}
+
+SMRange AsmToken::getLocRange() const {
+ return SMRange(getLoc(), getEndLoc());
+}
+
+void AsmToken::dump(raw_ostream &OS) const {
+ switch (Kind) {
+ case AsmToken::Error:
+ OS << "error";
+ break;
+ case AsmToken::Identifier:
+ OS << "identifier: " << getString();
+ break;
+ case AsmToken::Integer:
+ OS << "int: " << getString();
+ break;
+ case AsmToken::Real:
+ OS << "real: " << getString();
+ break;
+ case AsmToken::String:
+ OS << "string: " << getString();
+ break;
+
+ case AsmToken::Amp: OS << "Amp"; break;
+ case AsmToken::AmpAmp: OS << "AmpAmp"; break;
+ case AsmToken::At: OS << "At"; break;
+ case AsmToken::BackSlash: OS << "BackSlash"; break;
+ case AsmToken::BigNum: OS << "BigNum"; break;
+ case AsmToken::Caret: OS << "Caret"; break;
+ case AsmToken::Colon: OS << "Colon"; break;
+ case AsmToken::Comma: OS << "Comma"; break;
+ case AsmToken::Comment: OS << "Comment"; break;
+ case AsmToken::Dollar: OS << "Dollar"; break;
+ case AsmToken::Dot: OS << "Dot"; break;
+ case AsmToken::EndOfStatement: OS << "EndOfStatement"; break;
+ case AsmToken::Eof: OS << "Eof"; break;
+ case AsmToken::Equal: OS << "Equal"; break;
+ case AsmToken::EqualEqual: OS << "EqualEqual"; break;
+ case AsmToken::Exclaim: OS << "Exclaim"; break;
+ case AsmToken::ExclaimEqual: OS << "ExclaimEqual"; break;
+ case AsmToken::Greater: OS << "Greater"; break;
+ case AsmToken::GreaterEqual: OS << "GreaterEqual"; break;
+ case AsmToken::GreaterGreater: OS << "GreaterGreater"; break;
+ case AsmToken::Hash: OS << "Hash"; break;
+ case AsmToken::HashDirective: OS << "HashDirective"; break;
+ case AsmToken::LBrac: OS << "LBrac"; break;
+ case AsmToken::LCurly: OS << "LCurly"; break;
+ case AsmToken::LParen: OS << "LParen"; break;
+ case AsmToken::Less: OS << "Less"; break;
+ case AsmToken::LessEqual: OS << "LessEqual"; break;
+ case AsmToken::LessGreater: OS << "LessGreater"; break;
+ case AsmToken::LessLess: OS << "LessLess"; break;
+ case AsmToken::Minus: OS << "Minus"; break;
+ case AsmToken::MinusGreater: OS << "MinusGreater"; break;
+ case AsmToken::Percent: OS << "Percent"; break;
+ case AsmToken::Pipe: OS << "Pipe"; break;
+ case AsmToken::PipePipe: OS << "PipePipe"; break;
+ case AsmToken::Plus: OS << "Plus"; break;
+ case AsmToken::RBrac: OS << "RBrac"; break;
+ case AsmToken::RCurly: OS << "RCurly"; break;
+ case AsmToken::RParen: OS << "RParen"; break;
+ case AsmToken::Slash: OS << "Slash"; break;
+ case AsmToken::Space: OS << "Space"; break;
+ case AsmToken::Star: OS << "Star"; break;
+ case AsmToken::Tilde: OS << "Tilde"; break;
+ case AsmToken::PercentCall16: OS << "PercentCall16"; break;
+ case AsmToken::PercentCall_Hi: OS << "PercentCall_Hi"; break;
+ case AsmToken::PercentCall_Lo: OS << "PercentCall_Lo"; break;
+ case AsmToken::PercentDtprel_Hi: OS << "PercentDtprel_Hi"; break;
+ case AsmToken::PercentDtprel_Lo: OS << "PercentDtprel_Lo"; break;
+ case AsmToken::PercentGot: OS << "PercentGot"; break;
+ case AsmToken::PercentGot_Disp: OS << "PercentGot_Disp"; break;
+ case AsmToken::PercentGot_Hi: OS << "PercentGot_Hi"; break;
+ case AsmToken::PercentGot_Lo: OS << "PercentGot_Lo"; break;
+ case AsmToken::PercentGot_Ofst: OS << "PercentGot_Ofst"; break;
+ case AsmToken::PercentGot_Page: OS << "PercentGot_Page"; break;
+ case AsmToken::PercentGottprel: OS << "PercentGottprel"; break;
+ case AsmToken::PercentGp_Rel: OS << "PercentGp_Rel"; break;
+ case AsmToken::PercentHi: OS << "PercentHi"; break;
+ case AsmToken::PercentHigher: OS << "PercentHigher"; break;
+ case AsmToken::PercentHighest: OS << "PercentHighest"; break;
+ case AsmToken::PercentLo: OS << "PercentLo"; break;
+ case AsmToken::PercentNeg: OS << "PercentNeg"; break;
+ case AsmToken::PercentPcrel_Hi: OS << "PercentPcrel_Hi"; break;
+ case AsmToken::PercentPcrel_Lo: OS << "PercentPcrel_Lo"; break;
+ case AsmToken::PercentTlsgd: OS << "PercentTlsgd"; break;
+ case AsmToken::PercentTlsldm: OS << "PercentTlsldm"; break;
+ case AsmToken::PercentTprel_Hi: OS << "PercentTprel_Hi"; break;
+ case AsmToken::PercentTprel_Lo: OS << "PercentTprel_Lo"; break;
+ }
+
+ // Print the token string.
+ OS << " (\"";
+ OS.write_escaped(getString());
+ OS << "\")";
+}
diff --git a/llvm/lib/MC/MCParser/MCAsmParser.cpp b/llvm/lib/MC/MCParser/MCAsmParser.cpp
new file mode 100644
index 000000000000..41a1ee555d6f
--- /dev/null
+++ b/llvm/lib/MC/MCParser/MCAsmParser.cpp
@@ -0,0 +1,136 @@
+//===-- MCAsmParser.cpp - Abstract Asm Parser 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/MCParser/MCAsmParser.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace llvm;
+
+MCAsmParser::MCAsmParser() {}
+
+MCAsmParser::~MCAsmParser() = default;
+
+void MCAsmParser::setTargetParser(MCTargetAsmParser &P) {
+ assert(!TargetParser && "Target parser is already initialized!");
+ TargetParser = &P;
+ TargetParser->Initialize(*this);
+}
+
+const AsmToken &MCAsmParser::getTok() const {
+ return getLexer().getTok();
+}
+
+bool MCAsmParser::parseTokenLoc(SMLoc &Loc) {
+ Loc = getTok().getLoc();
+ return false;
+}
+
+bool MCAsmParser::parseEOL(const Twine &Msg) {
+ if (getTok().getKind() != AsmToken::EndOfStatement)
+ return Error(getTok().getLoc(), Msg);
+ Lex();
+ return false;
+}
+
+bool MCAsmParser::parseToken(AsmToken::TokenKind T, const Twine &Msg) {
+ if (T == AsmToken::EndOfStatement)
+ return parseEOL(Msg);
+ if (getTok().getKind() != T)
+ return Error(getTok().getLoc(), Msg);
+ Lex();
+ return false;
+}
+
+bool MCAsmParser::parseIntToken(int64_t &V, const Twine &Msg) {
+ if (getTok().getKind() != AsmToken::Integer)
+ return TokError(Msg);
+ V = getTok().getIntVal();
+ Lex();
+ return false;
+}
+
+bool MCAsmParser::parseOptionalToken(AsmToken::TokenKind T) {
+ bool Present = (getTok().getKind() == T);
+ if (Present)
+ parseToken(T);
+ return Present;
+}
+
+bool MCAsmParser::check(bool P, const Twine &Msg) {
+ return check(P, getTok().getLoc(), Msg);
+}
+
+bool MCAsmParser::check(bool P, SMLoc Loc, const Twine &Msg) {
+ if (P)
+ return Error(Loc, Msg);
+ return false;
+}
+
+bool MCAsmParser::TokError(const Twine &Msg, SMRange Range) {
+ return Error(getLexer().getLoc(), Msg, Range);
+}
+
+bool MCAsmParser::Error(SMLoc L, const Twine &Msg, SMRange Range) {
+
+ MCPendingError PErr;
+ PErr.Loc = L;
+ Msg.toVector(PErr.Msg);
+ PErr.Range = Range;
+ PendingErrors.push_back(PErr);
+
+ // If we threw this parsing error after a lexing error, this should
+ // supercede the lexing error and so we remove it from the Lexer
+ // before it can propagate
+ if (getTok().is(AsmToken::Error))
+ getLexer().Lex();
+ return true;
+}
+
+bool MCAsmParser::addErrorSuffix(const Twine &Suffix) {
+ // Make sure lexing errors have propagated to the parser.
+ if (getTok().is(AsmToken::Error))
+ Lex();
+ for (auto &PErr : PendingErrors)
+ Suffix.toVector(PErr.Msg);
+ return true;
+}
+
+bool MCAsmParser::parseMany(function_ref<bool()> parseOne, bool hasComma) {
+ if (parseOptionalToken(AsmToken::EndOfStatement))
+ return false;
+ while (true) {
+ if (parseOne())
+ return true;
+ if (parseOptionalToken(AsmToken::EndOfStatement))
+ return false;
+ if (hasComma && parseToken(AsmToken::Comma))
+ return true;
+ }
+ return false;
+}
+
+bool MCAsmParser::parseExpression(const MCExpr *&Res) {
+ SMLoc L;
+ return parseExpression(Res, L);
+}
+
+void MCParsedAsmOperand::dump() const {
+ // Cannot completely remove virtual function even in release mode.
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ dbgs() << " " << *this;
+#endif
+}
diff --git a/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp b/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp
new file mode 100644
index 000000000000..18d18f0cf6ed
--- /dev/null
+++ b/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp
@@ -0,0 +1,19 @@
+//===- MCAsmParserExtension.cpp - Asm Parser Hooks ------------------------===//
+//
+// 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/MCParser/MCAsmParserExtension.h"
+
+using namespace llvm;
+
+MCAsmParserExtension::MCAsmParserExtension() = default;
+
+MCAsmParserExtension::~MCAsmParserExtension() = default;
+
+void MCAsmParserExtension::Initialize(MCAsmParser &Parser) {
+ this->Parser = &Parser;
+}
diff --git a/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
new file mode 100644
index 000000000000..940f26d4750b
--- /dev/null
+++ b/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp
@@ -0,0 +1,29 @@
+//===-- MCTargetAsmParser.cpp - Target Assembly Parser --------------------===//
+//
+// 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/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCContext.h"
+
+using namespace llvm;
+
+MCTargetAsmParser::MCTargetAsmParser(MCTargetOptions const &MCOptions,
+ const MCSubtargetInfo &STI,
+ const MCInstrInfo &MII)
+ : MCOptions(MCOptions), STI(&STI), MII(MII) {}
+
+MCTargetAsmParser::~MCTargetAsmParser() = default;
+
+MCSubtargetInfo &MCTargetAsmParser::copySTI() {
+ MCSubtargetInfo &STICopy = getContext().getSubtargetCopy(getSTI());
+ STI = &STICopy;
+ return STICopy;
+}
+
+const MCSubtargetInfo &MCTargetAsmParser::getSTI() const {
+ return *STI;
+}
diff --git a/llvm/lib/MC/MCParser/WasmAsmParser.cpp b/llvm/lib/MC/MCParser/WasmAsmParser.cpp
new file mode 100644
index 000000000000..0c242aed706d
--- /dev/null
+++ b/llvm/lib/MC/MCParser/WasmAsmParser.cpp
@@ -0,0 +1,256 @@
+//===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===//
+//
+// 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
+//
+// --
+//
+// Note, this is for wasm, the binary format (analogous to ELF), not wasm,
+// the instruction set (analogous to x86), for which parsing code lives in
+// WebAssemblyAsmParser.
+//
+// This file contains processing for generic directives implemented using
+// MCTargetStreamer, the ones that depend on WebAssemblyTargetStreamer are in
+// WebAssemblyAsmParser.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCParser/MCAsmLexer.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCAsmParserExtension.h"
+#include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/Support/MachineValueType.h"
+
+using namespace llvm;
+
+namespace {
+
+class WasmAsmParser : public MCAsmParserExtension {
+ MCAsmParser *Parser = nullptr;
+ MCAsmLexer *Lexer = nullptr;
+
+ template<bool (WasmAsmParser::*HandlerMethod)(StringRef, SMLoc)>
+ void addDirectiveHandler(StringRef Directive) {
+ MCAsmParser::ExtensionDirectiveHandler Handler = std::make_pair(
+ this, HandleDirective<WasmAsmParser, HandlerMethod>);
+
+ getParser().addDirectiveHandler(Directive, Handler);
+ }
+
+public:
+ WasmAsmParser() { BracketExpressionsSupported = true; }
+
+ void Initialize(MCAsmParser &P) override {
+ Parser = &P;
+ Lexer = &Parser->getLexer();
+ // Call the base implementation.
+ this->MCAsmParserExtension::Initialize(*Parser);
+
+ addDirectiveHandler<&WasmAsmParser::parseSectionDirectiveText>(".text");
+ addDirectiveHandler<&WasmAsmParser::parseSectionDirective>(".section");
+ addDirectiveHandler<&WasmAsmParser::parseDirectiveSize>(".size");
+ addDirectiveHandler<&WasmAsmParser::parseDirectiveType>(".type");
+ addDirectiveHandler<&WasmAsmParser::ParseDirectiveIdent>(".ident");
+ addDirectiveHandler<
+ &WasmAsmParser::ParseDirectiveSymbolAttribute>(".weak");
+ addDirectiveHandler<
+ &WasmAsmParser::ParseDirectiveSymbolAttribute>(".local");
+ addDirectiveHandler<
+ &WasmAsmParser::ParseDirectiveSymbolAttribute>(".internal");
+ addDirectiveHandler<
+ &WasmAsmParser::ParseDirectiveSymbolAttribute>(".hidden");
+ }
+
+ bool error(const StringRef &Msg, const AsmToken &Tok) {
+ return Parser->Error(Tok.getLoc(), Msg + Tok.getString());
+ }
+
+ bool isNext(AsmToken::TokenKind Kind) {
+ auto Ok = Lexer->is(Kind);
+ if (Ok)
+ Lex();
+ return Ok;
+ }
+
+ bool expect(AsmToken::TokenKind Kind, const char *KindName) {
+ if (!isNext(Kind))
+ return error(std::string("Expected ") + KindName + ", instead got: ",
+ Lexer->getTok());
+ return false;
+ }
+
+ bool parseSectionDirectiveText(StringRef, SMLoc) {
+ // FIXME: .text currently no-op.
+ return false;
+ }
+
+ bool parseSectionFlags(StringRef FlagStr, bool &Passive) {
+ SmallVector<StringRef, 2> Flags;
+ // If there are no flags, keep Flags empty
+ FlagStr.split(Flags, ",", -1, false);
+ for (auto &Flag : Flags) {
+ if (Flag == "passive")
+ Passive = true;
+ else
+ return error("Expected section flags, instead got: ", Lexer->getTok());
+ }
+ return false;
+ }
+
+ bool parseSectionDirective(StringRef, SMLoc) {
+ StringRef Name;
+ if (Parser->parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+
+ if (expect(AsmToken::Comma, ","))
+ return true;
+
+ if (Lexer->isNot(AsmToken::String))
+ return error("expected string in directive, instead got: ", Lexer->getTok());
+
+ auto Kind = StringSwitch<Optional<SectionKind>>(Name)
+ .StartsWith(".data", SectionKind::getData())
+ .StartsWith(".rodata", SectionKind::getReadOnly())
+ .StartsWith(".text", SectionKind::getText())
+ .StartsWith(".custom_section", SectionKind::getMetadata())
+ .StartsWith(".bss", SectionKind::getBSS())
+ // See use of .init_array in WasmObjectWriter and
+ // TargetLoweringObjectFileWasm
+ .StartsWith(".init_array", SectionKind::getData())
+ .StartsWith(".debug_", SectionKind::getMetadata())
+ .Default(Optional<SectionKind>());
+ if (!Kind.hasValue())
+ return Parser->Error(Lexer->getLoc(), "unknown section kind: " + Name);
+
+ MCSectionWasm *Section = getContext().getWasmSection(Name, Kind.getValue());
+
+ // Update section flags if present in this .section directive
+ bool Passive = false;
+ if (parseSectionFlags(getTok().getStringContents(), Passive))
+ return true;
+
+ if (Passive) {
+ if (!Section->isWasmData())
+ return Parser->Error(getTok().getLoc(),
+ "Only data sections can be passive");
+ Section->setPassive();
+ }
+
+ Lex();
+
+ if (expect(AsmToken::Comma, ",") || expect(AsmToken::At, "@") ||
+ expect(AsmToken::EndOfStatement, "eol"))
+ return true;
+
+ auto WS = getContext().getWasmSection(Name, Kind.getValue());
+ getStreamer().SwitchSection(WS);
+ return false;
+ }
+
+ // TODO: This function is almost the same as ELFAsmParser::ParseDirectiveSize
+ // so maybe could be shared somehow.
+ bool parseDirectiveSize(StringRef, SMLoc) {
+ StringRef Name;
+ if (Parser->parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+ auto Sym = getContext().getOrCreateSymbol(Name);
+ if (expect(AsmToken::Comma, ","))
+ return true;
+ const MCExpr *Expr;
+ if (Parser->parseExpression(Expr))
+ return true;
+ if (expect(AsmToken::EndOfStatement, "eol"))
+ return true;
+ // This is done automatically by the assembler for functions currently,
+ // so this is only currently needed for data sections:
+ getStreamer().emitELFSize(Sym, Expr);
+ return false;
+ }
+
+ bool parseDirectiveType(StringRef, SMLoc) {
+ // This could be the start of a function, check if followed by
+ // "label,@function"
+ if (!Lexer->is(AsmToken::Identifier))
+ return error("Expected label after .type directive, got: ",
+ Lexer->getTok());
+ auto WasmSym = cast<MCSymbolWasm>(
+ getStreamer().getContext().getOrCreateSymbol(
+ Lexer->getTok().getString()));
+ Lex();
+ if (!(isNext(AsmToken::Comma) && isNext(AsmToken::At) &&
+ Lexer->is(AsmToken::Identifier)))
+ return error("Expected label,@type declaration, got: ", Lexer->getTok());
+ auto TypeName = Lexer->getTok().getString();
+ if (TypeName == "function")
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ else if (TypeName == "global")
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
+ else if (TypeName == "object")
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_DATA);
+ else
+ return error("Unknown WASM symbol type: ", Lexer->getTok());
+ Lex();
+ return expect(AsmToken::EndOfStatement, "EOL");
+ }
+
+ // FIXME: Shared with ELF.
+ /// ParseDirectiveIdent
+ /// ::= .ident string
+ bool ParseDirectiveIdent(StringRef, SMLoc) {
+ if (getLexer().isNot(AsmToken::String))
+ return TokError("unexpected token in '.ident' directive");
+ StringRef Data = getTok().getIdentifier();
+ Lex();
+ if (getLexer().isNot(AsmToken::EndOfStatement))
+ return TokError("unexpected token in '.ident' directive");
+ Lex();
+ getStreamer().EmitIdent(Data);
+ return false;
+ }
+
+ // FIXME: Shared with ELF.
+ /// ParseDirectiveSymbolAttribute
+ /// ::= { ".local", ".weak", ... } [ identifier ( , identifier )* ]
+ bool ParseDirectiveSymbolAttribute(StringRef Directive, SMLoc) {
+ MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Directive)
+ .Case(".weak", MCSA_Weak)
+ .Case(".local", MCSA_Local)
+ .Case(".hidden", MCSA_Hidden)
+ .Case(".internal", MCSA_Internal)
+ .Case(".protected", MCSA_Protected)
+ .Default(MCSA_Invalid);
+ assert(Attr != MCSA_Invalid && "unexpected symbol attribute directive!");
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ while (true) {
+ StringRef Name;
+ if (getParser().parseIdentifier(Name))
+ return TokError("expected identifier in directive");
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Name);
+ getStreamer().EmitSymbolAttribute(Sym, Attr);
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+ if (getLexer().isNot(AsmToken::Comma))
+ return TokError("unexpected token in directive");
+ Lex();
+ }
+ }
+ Lex();
+ return false;
+ }
+};
+
+} // end anonymous namespace
+
+namespace llvm {
+
+MCAsmParserExtension *createWasmAsmParser() {
+ return new WasmAsmParser;
+}
+
+} // end namespace llvm
diff --git a/llvm/lib/MC/MCRegisterInfo.cpp b/llvm/lib/MC/MCRegisterInfo.cpp
new file mode 100644
index 000000000000..d491c0eb7e06
--- /dev/null
+++ b/llvm/lib/MC/MCRegisterInfo.cpp
@@ -0,0 +1,124 @@
+//===- MC/MCRegisterInfo.cpp - Target Register Description ----------------===//
+//
+// 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 implements MCRegisterInfo functions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+
+MCRegister
+MCRegisterInfo::getMatchingSuperReg(MCRegister Reg, unsigned SubIdx,
+ const MCRegisterClass *RC) const {
+ for (MCSuperRegIterator Supers(Reg, this); Supers.isValid(); ++Supers)
+ if (RC->contains(*Supers) && Reg == getSubReg(*Supers, SubIdx))
+ return *Supers;
+ return 0;
+}
+
+MCRegister MCRegisterInfo::getSubReg(MCRegister Reg, unsigned Idx) const {
+ assert(Idx && Idx < getNumSubRegIndices() &&
+ "This is not a subregister index");
+ // Get a pointer to the corresponding SubRegIndices list. This list has the
+ // name of each sub-register in the same order as MCSubRegIterator.
+ const uint16_t *SRI = SubRegIndices + get(Reg).SubRegIndices;
+ for (MCSubRegIterator Subs(Reg, this); Subs.isValid(); ++Subs, ++SRI)
+ if (*SRI == Idx)
+ return *Subs;
+ return 0;
+}
+
+unsigned MCRegisterInfo::getSubRegIndex(MCRegister Reg,
+ MCRegister SubReg) const {
+ assert(SubReg && SubReg < getNumRegs() && "This is not a register");
+ // Get a pointer to the corresponding SubRegIndices list. This list has the
+ // name of each sub-register in the same order as MCSubRegIterator.
+ const uint16_t *SRI = SubRegIndices + get(Reg).SubRegIndices;
+ for (MCSubRegIterator Subs(Reg, this); Subs.isValid(); ++Subs, ++SRI)
+ if (*Subs == SubReg)
+ return *SRI;
+ return 0;
+}
+
+unsigned MCRegisterInfo::getSubRegIdxSize(unsigned Idx) const {
+ assert(Idx && Idx < getNumSubRegIndices() &&
+ "This is not a subregister index");
+ return SubRegIdxRanges[Idx].Size;
+}
+
+unsigned MCRegisterInfo::getSubRegIdxOffset(unsigned Idx) const {
+ assert(Idx && Idx < getNumSubRegIndices() &&
+ "This is not a subregister index");
+ return SubRegIdxRanges[Idx].Offset;
+}
+
+int MCRegisterInfo::getDwarfRegNum(MCRegister RegNum, bool isEH) const {
+ const DwarfLLVMRegPair *M = isEH ? EHL2DwarfRegs : L2DwarfRegs;
+ unsigned Size = isEH ? EHL2DwarfRegsSize : L2DwarfRegsSize;
+
+ if (!M)
+ return -1;
+ DwarfLLVMRegPair Key = { RegNum, 0 };
+ const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key);
+ if (I == M+Size || I->FromReg != RegNum)
+ return -1;
+ return I->ToReg;
+}
+
+Optional<unsigned> MCRegisterInfo::getLLVMRegNum(unsigned RegNum,
+ bool isEH) const {
+ const DwarfLLVMRegPair *M = isEH ? EHDwarf2LRegs : Dwarf2LRegs;
+ unsigned Size = isEH ? EHDwarf2LRegsSize : Dwarf2LRegsSize;
+
+ if (!M)
+ return None;
+ DwarfLLVMRegPair Key = { RegNum, 0 };
+ const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key);
+ if (I != M + Size && I->FromReg == RegNum)
+ return I->ToReg;
+ return None;
+}
+
+int MCRegisterInfo::getDwarfRegNumFromDwarfEHRegNum(unsigned RegNum) const {
+ // On ELF platforms, DWARF EH register numbers are the same as DWARF
+ // other register numbers. On Darwin x86, they differ and so need to be
+ // mapped. The .cfi_* directives accept integer literals as well as
+ // register names and should generate exactly what the assembly code
+ // asked for, so there might be DWARF/EH register numbers that don't have
+ // a corresponding LLVM register number at all. So if we can't map the
+ // EH register number to an LLVM register number, assume it's just a
+ // valid DWARF register number as is.
+ if (Optional<unsigned> LRegNum = getLLVMRegNum(RegNum, true))
+ return getDwarfRegNum(*LRegNum, false);
+ return RegNum;
+}
+
+int MCRegisterInfo::getSEHRegNum(MCRegister RegNum) const {
+ const DenseMap<MCRegister, int>::const_iterator I = L2SEHRegs.find(RegNum);
+ if (I == L2SEHRegs.end()) return (int)RegNum;
+ return I->second;
+}
+
+int MCRegisterInfo::getCodeViewRegNum(MCRegister RegNum) const {
+ if (L2CVRegs.empty())
+ report_fatal_error("target does not implement codeview register mapping");
+ const DenseMap<MCRegister, int>::const_iterator I = L2CVRegs.find(RegNum);
+ if (I == L2CVRegs.end())
+ report_fatal_error("unknown codeview register " + (RegNum < getNumRegs()
+ ? getName(RegNum)
+ : Twine(RegNum)));
+ return I->second;
+}
diff --git a/llvm/lib/MC/MCSchedule.cpp b/llvm/lib/MC/MCSchedule.cpp
new file mode 100644
index 000000000000..1fc5ec5e975f
--- /dev/null
+++ b/llvm/lib/MC/MCSchedule.cpp
@@ -0,0 +1,167 @@
+//===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===//
+//
+// 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 defines the default scheduling model.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCSchedule.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstrDesc.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include <type_traits>
+
+using namespace llvm;
+
+static_assert(std::is_pod<MCSchedModel>::value,
+ "We shouldn't have a static constructor here");
+const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,
+ DefaultMicroOpBufferSize,
+ DefaultLoopMicroOpBufferSize,
+ DefaultLoadLatency,
+ DefaultHighLatency,
+ DefaultMispredictPenalty,
+ false,
+ true,
+ 0,
+ nullptr,
+ nullptr,
+ 0,
+ 0,
+ nullptr,
+ nullptr};
+
+int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
+ const MCSchedClassDesc &SCDesc) {
+ int Latency = 0;
+ for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;
+ DefIdx != DefEnd; ++DefIdx) {
+ // Lookup the definition's write latency in SubtargetInfo.
+ const MCWriteLatencyEntry *WLEntry =
+ STI.getWriteLatencyEntry(&SCDesc, DefIdx);
+ // Early exit if we found an invalid latency.
+ if (WLEntry->Cycles < 0)
+ return WLEntry->Cycles;
+ Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));
+ }
+ return Latency;
+}
+
+int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
+ unsigned SchedClass) const {
+ const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass);
+ if (!SCDesc.isValid())
+ return 0;
+ if (!SCDesc.isVariant())
+ return MCSchedModel::computeInstrLatency(STI, SCDesc);
+
+ llvm_unreachable("unsupported variant scheduling class");
+}
+
+int MCSchedModel::computeInstrLatency(const MCSubtargetInfo &STI,
+ const MCInstrInfo &MCII,
+ const MCInst &Inst) const {
+ unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
+ const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
+ if (!SCDesc->isValid())
+ return 0;
+
+ unsigned CPUID = getProcessorID();
+ while (SCDesc->isVariant()) {
+ SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID);
+ SCDesc = getSchedClassDesc(SchedClass);
+ }
+
+ if (SchedClass)
+ return MCSchedModel::computeInstrLatency(STI, *SCDesc);
+
+ llvm_unreachable("unsupported variant scheduling class");
+}
+
+double
+MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,
+ const MCSchedClassDesc &SCDesc) {
+ Optional<double> Throughput;
+ const MCSchedModel &SM = STI.getSchedModel();
+ const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc);
+ const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc);
+ for (; I != E; ++I) {
+ if (!I->Cycles)
+ continue;
+ unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits;
+ double Temp = NumUnits * 1.0 / I->Cycles;
+ Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp;
+ }
+ if (Throughput.hasValue())
+ return 1.0 / Throughput.getValue();
+
+ // If no throughput value was calculated, assume that we can execute at the
+ // maximum issue width scaled by number of micro-ops for the schedule class.
+ return ((double)SCDesc.NumMicroOps) / SM.IssueWidth;
+}
+
+double
+MCSchedModel::getReciprocalThroughput(const MCSubtargetInfo &STI,
+ const MCInstrInfo &MCII,
+ const MCInst &Inst) const {
+ unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
+ const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
+
+ // If there's no valid class, assume that the instruction executes/completes
+ // at the maximum issue width.
+ if (!SCDesc->isValid())
+ return 1.0 / IssueWidth;
+
+ unsigned CPUID = getProcessorID();
+ while (SCDesc->isVariant()) {
+ SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, CPUID);
+ SCDesc = getSchedClassDesc(SchedClass);
+ }
+
+ if (SchedClass)
+ return MCSchedModel::getReciprocalThroughput(STI, *SCDesc);
+
+ llvm_unreachable("unsupported variant scheduling class");
+}
+
+double
+MCSchedModel::getReciprocalThroughput(unsigned SchedClass,
+ const InstrItineraryData &IID) {
+ Optional<double> Throughput;
+ const InstrStage *I = IID.beginStage(SchedClass);
+ const InstrStage *E = IID.endStage(SchedClass);
+ for (; I != E; ++I) {
+ if (!I->getCycles())
+ continue;
+ double Temp = countPopulation(I->getUnits()) * 1.0 / I->getCycles();
+ Throughput = Throughput ? std::min(Throughput.getValue(), Temp) : Temp;
+ }
+ if (Throughput.hasValue())
+ return 1.0 / Throughput.getValue();
+
+ // If there are no execution resources specified for this class, then assume
+ // that it can execute at the maximum default issue width.
+ return 1.0 / DefaultIssueWidth;
+}
+
+unsigned
+MCSchedModel::getForwardingDelayCycles(ArrayRef<MCReadAdvanceEntry> Entries,
+ unsigned WriteResourceID) {
+ if (Entries.empty())
+ return 0;
+
+ int DelayCycles = 0;
+ for (const MCReadAdvanceEntry &E : Entries) {
+ if (E.WriteResourceID != WriteResourceID)
+ continue;
+ DelayCycles = std::min(DelayCycles, E.Cycles);
+ }
+
+ return std::abs(DelayCycles);
+}
diff --git a/llvm/lib/MC/MCSection.cpp b/llvm/lib/MC/MCSection.cpp
new file mode 100644
index 000000000000..2c892ab81608
--- /dev/null
+++ b/llvm/lib/MC/MCSection.cpp
@@ -0,0 +1,102 @@
+//===- lib/MC/MCSection.cpp - Machine Code Section Representation ---------===//
+//
+// 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/MCSection.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <utility>
+
+using namespace llvm;
+
+MCSection::MCSection(SectionVariant V, SectionKind K, MCSymbol *Begin)
+ : Begin(Begin), BundleGroupBeforeFirstInst(false), HasInstructions(false),
+ HasData(false), IsRegistered(false), DummyFragment(this), Variant(V),
+ Kind(K) {}
+
+MCSymbol *MCSection::getEndSymbol(MCContext &Ctx) {
+ if (!End)
+ End = Ctx.createTempSymbol("sec_end", true);
+ return End;
+}
+
+bool MCSection::hasEnded() const { return End && End->isInSection(); }
+
+MCSection::~MCSection() = default;
+
+void MCSection::setBundleLockState(BundleLockStateType NewState) {
+ if (NewState == NotBundleLocked) {
+ if (BundleLockNestingDepth == 0) {
+ report_fatal_error("Mismatched bundle_lock/unlock directives");
+ }
+ if (--BundleLockNestingDepth == 0) {
+ BundleLockState = NotBundleLocked;
+ }
+ return;
+ }
+
+ // If any of the directives is an align_to_end directive, the whole nested
+ // group is align_to_end. So don't downgrade from align_to_end to just locked.
+ if (BundleLockState != BundleLockedAlignToEnd) {
+ BundleLockState = NewState;
+ }
+ ++BundleLockNestingDepth;
+}
+
+MCSection::iterator
+MCSection::getSubsectionInsertionPoint(unsigned Subsection) {
+ if (Subsection == 0 && SubsectionFragmentMap.empty())
+ return end();
+
+ SmallVectorImpl<std::pair<unsigned, MCFragment *>>::iterator MI =
+ std::lower_bound(SubsectionFragmentMap.begin(),
+ SubsectionFragmentMap.end(),
+ std::make_pair(Subsection, (MCFragment *)nullptr));
+ bool ExactMatch = false;
+ if (MI != SubsectionFragmentMap.end()) {
+ ExactMatch = MI->first == Subsection;
+ if (ExactMatch)
+ ++MI;
+ }
+ iterator IP;
+ if (MI == SubsectionFragmentMap.end())
+ IP = end();
+ else
+ IP = MI->second->getIterator();
+ if (!ExactMatch && Subsection != 0) {
+ // The GNU as documentation claims that subsections have an alignment of 4,
+ // although this appears not to be the case.
+ MCFragment *F = new MCDataFragment();
+ SubsectionFragmentMap.insert(MI, std::make_pair(Subsection, F));
+ getFragmentList().insert(IP, F);
+ F->setParent(this);
+ }
+
+ return IP;
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCSection::dump() const {
+ raw_ostream &OS = errs();
+
+ OS << "<MCSection";
+ OS << " Fragments:[\n ";
+ for (auto it = begin(), ie = end(); it != ie; ++it) {
+ if (it != begin())
+ OS << ",\n ";
+ it->dump();
+ }
+ OS << "]>";
+}
+#endif
diff --git a/llvm/lib/MC/MCSectionCOFF.cpp b/llvm/lib/MC/MCSectionCOFF.cpp
new file mode 100644
index 000000000000..f0c06f70bd73
--- /dev/null
+++ b/llvm/lib/MC/MCSectionCOFF.cpp
@@ -0,0 +1,113 @@
+//===- lib/MC/MCSectionCOFF.cpp - COFF Code Section Representation --------===//
+//
+// 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/MCSectionCOFF.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace llvm;
+
+// ShouldOmitSectionDirective - Decides whether a '.section' directive
+// should be printed before the section name
+bool MCSectionCOFF::ShouldOmitSectionDirective(StringRef Name,
+ const MCAsmInfo &MAI) const {
+ if (COMDATSymbol)
+ return false;
+
+ // FIXME: Does .section .bss/.data/.text work everywhere??
+ if (Name == ".text" || Name == ".data" || Name == ".bss")
+ return true;
+
+ return false;
+}
+
+void MCSectionCOFF::setSelection(int Selection) const {
+ assert(Selection != 0 && "invalid COMDAT selection type");
+ this->Selection = Selection;
+ Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT;
+}
+
+void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+ raw_ostream &OS,
+ const MCExpr *Subsection) const {
+ // standard sections don't require the '.section'
+ if (ShouldOmitSectionDirective(SectionName, MAI)) {
+ OS << '\t' << getSectionName() << '\n';
+ return;
+ }
+
+ OS << "\t.section\t" << getSectionName() << ",\"";
+ if (getCharacteristics() & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
+ OS << 'd';
+ if (getCharacteristics() & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
+ OS << 'b';
+ if (getCharacteristics() & COFF::IMAGE_SCN_MEM_EXECUTE)
+ OS << 'x';
+ if (getCharacteristics() & COFF::IMAGE_SCN_MEM_WRITE)
+ OS << 'w';
+ else if (getCharacteristics() & COFF::IMAGE_SCN_MEM_READ)
+ OS << 'r';
+ else
+ OS << 'y';
+ if (getCharacteristics() & COFF::IMAGE_SCN_LNK_REMOVE)
+ OS << 'n';
+ if (getCharacteristics() & COFF::IMAGE_SCN_MEM_SHARED)
+ OS << 's';
+ if ((getCharacteristics() & COFF::IMAGE_SCN_MEM_DISCARDABLE) &&
+ !isImplicitlyDiscardable(SectionName))
+ OS << 'D';
+ OS << '"';
+
+ if (getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) {
+ if (COMDATSymbol)
+ OS << ",";
+ else
+ OS << "\n\t.linkonce\t";
+ switch (Selection) {
+ case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES:
+ OS << "one_only";
+ break;
+ case COFF::IMAGE_COMDAT_SELECT_ANY:
+ OS << "discard";
+ break;
+ case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE:
+ OS << "same_size";
+ break;
+ case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH:
+ OS << "same_contents";
+ break;
+ case COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE:
+ OS << "associative";
+ break;
+ case COFF::IMAGE_COMDAT_SELECT_LARGEST:
+ OS << "largest";
+ break;
+ case COFF::IMAGE_COMDAT_SELECT_NEWEST:
+ OS << "newest";
+ break;
+ default:
+ assert(false && "unsupported COFF selection type");
+ break;
+ }
+ if (COMDATSymbol) {
+ OS << ",";
+ COMDATSymbol->print(OS, &MAI);
+ }
+ }
+ OS << '\n';
+}
+
+bool MCSectionCOFF::UseCodeAlign() const {
+ return getKind().isText();
+}
+
+bool MCSectionCOFF::isVirtualSection() const {
+ return getCharacteristics() & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA;
+}
diff --git a/llvm/lib/MC/MCSectionELF.cpp b/llvm/lib/MC/MCSectionELF.cpp
new file mode 100644
index 000000000000..efe504b2024c
--- /dev/null
+++ b/llvm/lib/MC/MCSectionELF.cpp
@@ -0,0 +1,198 @@
+//===- lib/MC/MCSectionELF.cpp - ELF Code Section Representation ----------===//
+//
+// 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/MCSectionELF.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace llvm;
+
+// Decides whether a '.section' directive
+// should be printed before the section name.
+bool MCSectionELF::ShouldOmitSectionDirective(StringRef Name,
+ const MCAsmInfo &MAI) const {
+ if (isUnique())
+ return false;
+
+ return MAI.shouldOmitSectionDirective(Name);
+}
+
+static void printName(raw_ostream &OS, StringRef Name) {
+ if (Name.find_first_not_of("0123456789_."
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == Name.npos) {
+ OS << Name;
+ return;
+ }
+ OS << '"';
+ for (const char *B = Name.begin(), *E = Name.end(); B < E; ++B) {
+ if (*B == '"') // Unquoted "
+ OS << "\\\"";
+ else if (*B != '\\') // Neither " or backslash
+ OS << *B;
+ else if (B + 1 == E) // Trailing backslash
+ OS << "\\\\";
+ else {
+ OS << B[0] << B[1]; // Quoted character
+ ++B;
+ }
+ }
+ OS << '"';
+}
+
+void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+ raw_ostream &OS,
+ const MCExpr *Subsection) const {
+ if (ShouldOmitSectionDirective(SectionName, MAI)) {
+ OS << '\t' << getSectionName();
+ if (Subsection) {
+ OS << '\t';
+ Subsection->print(OS, &MAI);
+ }
+ OS << '\n';
+ return;
+ }
+
+ OS << "\t.section\t";
+ printName(OS, getSectionName());
+
+ // Handle the weird solaris syntax if desired.
+ if (MAI.usesSunStyleELFSectionSwitchSyntax() &&
+ !(Flags & ELF::SHF_MERGE)) {
+ if (Flags & ELF::SHF_ALLOC)
+ OS << ",#alloc";
+ if (Flags & ELF::SHF_EXECINSTR)
+ OS << ",#execinstr";
+ if (Flags & ELF::SHF_WRITE)
+ OS << ",#write";
+ if (Flags & ELF::SHF_EXCLUDE)
+ OS << ",#exclude";
+ if (Flags & ELF::SHF_TLS)
+ OS << ",#tls";
+ OS << '\n';
+ return;
+ }
+
+ OS << ",\"";
+ if (Flags & ELF::SHF_ALLOC)
+ OS << 'a';
+ if (Flags & ELF::SHF_EXCLUDE)
+ OS << 'e';
+ if (Flags & ELF::SHF_EXECINSTR)
+ OS << 'x';
+ if (Flags & ELF::SHF_GROUP)
+ OS << 'G';
+ if (Flags & ELF::SHF_WRITE)
+ OS << 'w';
+ if (Flags & ELF::SHF_MERGE)
+ OS << 'M';
+ if (Flags & ELF::SHF_STRINGS)
+ OS << 'S';
+ if (Flags & ELF::SHF_TLS)
+ OS << 'T';
+ if (Flags & ELF::SHF_LINK_ORDER)
+ OS << 'o';
+
+ // If there are target-specific flags, print them.
+ Triple::ArchType Arch = T.getArch();
+ if (Arch == Triple::xcore) {
+ if (Flags & ELF::XCORE_SHF_CP_SECTION)
+ OS << 'c';
+ if (Flags & ELF::XCORE_SHF_DP_SECTION)
+ OS << 'd';
+ } else if (T.isARM() || T.isThumb()) {
+ if (Flags & ELF::SHF_ARM_PURECODE)
+ OS << 'y';
+ } else if (Arch == Triple::hexagon) {
+ if (Flags & ELF::SHF_HEX_GPREL)
+ OS << 's';
+ }
+
+ OS << '"';
+
+ OS << ',';
+
+ // If comment string is '@', e.g. as on ARM - use '%' instead
+ if (MAI.getCommentString()[0] == '@')
+ OS << '%';
+ else
+ OS << '@';
+
+ if (Type == ELF::SHT_INIT_ARRAY)
+ OS << "init_array";
+ else if (Type == ELF::SHT_FINI_ARRAY)
+ OS << "fini_array";
+ else if (Type == ELF::SHT_PREINIT_ARRAY)
+ OS << "preinit_array";
+ else if (Type == ELF::SHT_NOBITS)
+ OS << "nobits";
+ else if (Type == ELF::SHT_NOTE)
+ OS << "note";
+ else if (Type == ELF::SHT_PROGBITS)
+ OS << "progbits";
+ else if (Type == ELF::SHT_X86_64_UNWIND)
+ OS << "unwind";
+ else if (Type == ELF::SHT_MIPS_DWARF)
+ // Print hex value of the flag while we do not have
+ // any standard symbolic representation of the flag.
+ OS << "0x7000001e";
+ else if (Type == ELF::SHT_LLVM_ODRTAB)
+ OS << "llvm_odrtab";
+ else if (Type == ELF::SHT_LLVM_LINKER_OPTIONS)
+ OS << "llvm_linker_options";
+ else if (Type == ELF::SHT_LLVM_CALL_GRAPH_PROFILE)
+ OS << "llvm_call_graph_profile";
+ else if (Type == ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
+ OS << "llvm_dependent_libraries";
+ else if (Type == ELF::SHT_LLVM_SYMPART)
+ OS << "llvm_sympart";
+ else
+ report_fatal_error("unsupported type 0x" + Twine::utohexstr(Type) +
+ " for section " + getSectionName());
+
+ if (EntrySize) {
+ assert(Flags & ELF::SHF_MERGE);
+ OS << "," << EntrySize;
+ }
+
+ if (Flags & ELF::SHF_GROUP) {
+ OS << ",";
+ printName(OS, Group->getName());
+ OS << ",comdat";
+ }
+
+ if (Flags & ELF::SHF_LINK_ORDER) {
+ assert(AssociatedSymbol);
+ OS << ",";
+ printName(OS, AssociatedSymbol->getName());
+ }
+
+ if (isUnique())
+ OS << ",unique," << UniqueID;
+
+ OS << '\n';
+
+ if (Subsection) {
+ OS << "\t.subsection\t";
+ Subsection->print(OS, &MAI);
+ OS << '\n';
+ }
+}
+
+bool MCSectionELF::UseCodeAlign() const {
+ return getFlags() & ELF::SHF_EXECINSTR;
+}
+
+bool MCSectionELF::isVirtualSection() const {
+ return getType() == ELF::SHT_NOBITS;
+}
diff --git a/llvm/lib/MC/MCSectionMachO.cpp b/llvm/lib/MC/MCSectionMachO.cpp
new file mode 100644
index 000000000000..0fd89dcbe5fa
--- /dev/null
+++ b/llvm/lib/MC/MCSectionMachO.cpp
@@ -0,0 +1,281 @@
+//===- lib/MC/MCSectionMachO.cpp - MachO Code Section Representation ------===//
+//
+// 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/MCSectionMachO.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cctype>
+using namespace llvm;
+
+/// SectionTypeDescriptors - These are strings that describe the various section
+/// types. This *must* be kept in order with and stay synchronized with the
+/// section type list.
+static constexpr struct {
+ StringLiteral AssemblerName, EnumName;
+} SectionTypeDescriptors[MachO::LAST_KNOWN_SECTION_TYPE + 1] = {
+ {StringLiteral("regular"), StringLiteral("S_REGULAR")}, // 0x00
+ {StringLiteral(""), StringLiteral("S_ZEROFILL")}, // 0x01
+ {StringLiteral("cstring_literals"),
+ StringLiteral("S_CSTRING_LITERALS")}, // 0x02
+ {StringLiteral("4byte_literals"),
+ StringLiteral("S_4BYTE_LITERALS")}, // 0x03
+ {StringLiteral("8byte_literals"),
+ StringLiteral("S_8BYTE_LITERALS")}, // 0x04
+ {StringLiteral("literal_pointers"),
+ StringLiteral("S_LITERAL_POINTERS")}, // 0x05
+ {StringLiteral("non_lazy_symbol_pointers"),
+ StringLiteral("S_NON_LAZY_SYMBOL_POINTERS")}, // 0x06
+ {StringLiteral("lazy_symbol_pointers"),
+ StringLiteral("S_LAZY_SYMBOL_POINTERS")}, // 0x07
+ {StringLiteral("symbol_stubs"), StringLiteral("S_SYMBOL_STUBS")}, // 0x08
+ {StringLiteral("mod_init_funcs"),
+ StringLiteral("S_MOD_INIT_FUNC_POINTERS")}, // 0x09
+ {StringLiteral("mod_term_funcs"),
+ StringLiteral("S_MOD_TERM_FUNC_POINTERS")}, // 0x0A
+ {StringLiteral("coalesced"), StringLiteral("S_COALESCED")}, // 0x0B
+ {StringLiteral("") /*FIXME??*/, StringLiteral("S_GB_ZEROFILL")}, // 0x0C
+ {StringLiteral("interposing"), StringLiteral("S_INTERPOSING")}, // 0x0D
+ {StringLiteral("16byte_literals"),
+ StringLiteral("S_16BYTE_LITERALS")}, // 0x0E
+ {StringLiteral("") /*FIXME??*/, StringLiteral("S_DTRACE_DOF")}, // 0x0F
+ {StringLiteral("") /*FIXME??*/,
+ StringLiteral("S_LAZY_DYLIB_SYMBOL_POINTERS")}, // 0x10
+ {StringLiteral("thread_local_regular"),
+ StringLiteral("S_THREAD_LOCAL_REGULAR")}, // 0x11
+ {StringLiteral("thread_local_zerofill"),
+ StringLiteral("S_THREAD_LOCAL_ZEROFILL")}, // 0x12
+ {StringLiteral("thread_local_variables"),
+ StringLiteral("S_THREAD_LOCAL_VARIABLES")}, // 0x13
+ {StringLiteral("thread_local_variable_pointers"),
+ StringLiteral("S_THREAD_LOCAL_VARIABLE_POINTERS")}, // 0x14
+ {StringLiteral("thread_local_init_function_pointers"),
+ StringLiteral("S_THREAD_LOCAL_INIT_FUNCTION_POINTERS")}, // 0x15
+};
+
+/// SectionAttrDescriptors - This is an array of descriptors for section
+/// attributes. Unlike the SectionTypeDescriptors, this is not directly indexed
+/// by attribute, instead it is searched.
+static constexpr struct {
+ unsigned AttrFlag;
+ StringLiteral AssemblerName, EnumName;
+} SectionAttrDescriptors[] = {
+#define ENTRY(ASMNAME, ENUM) \
+ { MachO::ENUM, StringLiteral(ASMNAME), StringLiteral(#ENUM) },
+ENTRY("pure_instructions", S_ATTR_PURE_INSTRUCTIONS)
+ENTRY("no_toc", S_ATTR_NO_TOC)
+ENTRY("strip_static_syms", S_ATTR_STRIP_STATIC_SYMS)
+ENTRY("no_dead_strip", S_ATTR_NO_DEAD_STRIP)
+ENTRY("live_support", S_ATTR_LIVE_SUPPORT)
+ENTRY("self_modifying_code", S_ATTR_SELF_MODIFYING_CODE)
+ENTRY("debug", S_ATTR_DEBUG)
+ENTRY("" /*FIXME*/, S_ATTR_SOME_INSTRUCTIONS)
+ENTRY("" /*FIXME*/, S_ATTR_EXT_RELOC)
+ENTRY("" /*FIXME*/, S_ATTR_LOC_RELOC)
+#undef ENTRY
+ { 0, StringLiteral("none"), StringLiteral("") }, // used if section has no attributes but has a stub size
+};
+
+MCSectionMachO::MCSectionMachO(StringRef Segment, StringRef Section,
+ unsigned TAA, unsigned reserved2, SectionKind K,
+ MCSymbol *Begin)
+ : MCSection(SV_MachO, K, Begin), TypeAndAttributes(TAA),
+ Reserved2(reserved2) {
+ assert(Segment.size() <= 16 && Section.size() <= 16 &&
+ "Segment or section string too long");
+ for (unsigned i = 0; i != 16; ++i) {
+ if (i < Segment.size())
+ SegmentName[i] = Segment[i];
+ else
+ SegmentName[i] = 0;
+
+ if (i < Section.size())
+ SectionName[i] = Section[i];
+ else
+ SectionName[i] = 0;
+ }
+}
+
+void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+ raw_ostream &OS,
+ const MCExpr *Subsection) const {
+ OS << "\t.section\t" << getSegmentName() << ',' << getSectionName();
+
+ // Get the section type and attributes.
+ unsigned TAA = getTypeAndAttributes();
+ if (TAA == 0) {
+ OS << '\n';
+ return;
+ }
+
+ MachO::SectionType SectionType = getType();
+ assert(SectionType <= MachO::LAST_KNOWN_SECTION_TYPE &&
+ "Invalid SectionType specified!");
+
+ if (!SectionTypeDescriptors[SectionType].AssemblerName.empty()) {
+ OS << ',';
+ OS << SectionTypeDescriptors[SectionType].AssemblerName;
+ } else {
+ // If we have no name for the attribute, stop here.
+ OS << '\n';
+ return;
+ }
+
+ // If we don't have any attributes, we're done.
+ unsigned SectionAttrs = TAA & MachO::SECTION_ATTRIBUTES;
+ if (SectionAttrs == 0) {
+ // If we have a S_SYMBOL_STUBS size specified, print it along with 'none' as
+ // the attribute specifier.
+ if (Reserved2 != 0)
+ OS << ",none," << Reserved2;
+ OS << '\n';
+ return;
+ }
+
+ // Check each attribute to see if we have it.
+ char Separator = ',';
+ for (unsigned i = 0;
+ SectionAttrs != 0 && SectionAttrDescriptors[i].AttrFlag;
+ ++i) {
+ // Check to see if we have this attribute.
+ if ((SectionAttrDescriptors[i].AttrFlag & SectionAttrs) == 0)
+ continue;
+
+ // Yep, clear it and print it.
+ SectionAttrs &= ~SectionAttrDescriptors[i].AttrFlag;
+
+ OS << Separator;
+ if (!SectionAttrDescriptors[i].AssemblerName.empty())
+ OS << SectionAttrDescriptors[i].AssemblerName;
+ else
+ OS << "<<" << SectionAttrDescriptors[i].EnumName << ">>";
+ Separator = '+';
+ }
+
+ assert(SectionAttrs == 0 && "Unknown section attributes!");
+
+ // If we have a S_SYMBOL_STUBS size specified, print it.
+ if (Reserved2 != 0)
+ OS << ',' << Reserved2;
+ OS << '\n';
+}
+
+bool MCSectionMachO::UseCodeAlign() const {
+ return hasAttribute(MachO::S_ATTR_PURE_INSTRUCTIONS);
+}
+
+bool MCSectionMachO::isVirtualSection() const {
+ return (getType() == MachO::S_ZEROFILL ||
+ getType() == MachO::S_GB_ZEROFILL ||
+ getType() == MachO::S_THREAD_LOCAL_ZEROFILL);
+}
+
+/// ParseSectionSpecifier - Parse the section specifier indicated by "Spec".
+/// This is a string that can appear after a .section directive in a mach-o
+/// flavored .s file. If successful, this fills in the specified Out
+/// parameters and returns an empty string. When an invalid section
+/// specifier is present, this returns a string indicating the problem.
+std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In.
+ StringRef &Segment, // Out.
+ StringRef &Section, // Out.
+ unsigned &TAA, // Out.
+ bool &TAAParsed, // Out.
+ unsigned &StubSize) { // Out.
+ TAAParsed = false;
+
+ SmallVector<StringRef, 5> SplitSpec;
+ Spec.split(SplitSpec, ',');
+ // Remove leading and trailing whitespace.
+ auto GetEmptyOrTrim = [&SplitSpec](size_t Idx) -> StringRef {
+ return SplitSpec.size() > Idx ? SplitSpec[Idx].trim() : StringRef();
+ };
+ Segment = GetEmptyOrTrim(0);
+ Section = GetEmptyOrTrim(1);
+ StringRef SectionType = GetEmptyOrTrim(2);
+ StringRef Attrs = GetEmptyOrTrim(3);
+ StringRef StubSizeStr = GetEmptyOrTrim(4);
+
+ // Verify that the segment is present and not too long.
+ if (Segment.empty() || Segment.size() > 16)
+ return "mach-o section specifier requires a segment whose length is "
+ "between 1 and 16 characters";
+
+ // Verify that the section is present and not too long.
+ if (Section.empty())
+ return "mach-o section specifier requires a segment and section "
+ "separated by a comma";
+
+ if (Section.size() > 16)
+ return "mach-o section specifier requires a section whose length is "
+ "between 1 and 16 characters";
+
+ // If there is no comma after the section, we're done.
+ TAA = 0;
+ StubSize = 0;
+ if (SectionType.empty())
+ return "";
+
+ // Figure out which section type it is.
+ auto TypeDescriptor = std::find_if(
+ std::begin(SectionTypeDescriptors), std::end(SectionTypeDescriptors),
+ [&](decltype(*SectionTypeDescriptors) &Descriptor) {
+ return SectionType == Descriptor.AssemblerName;
+ });
+
+ // If we didn't find the section type, reject it.
+ if (TypeDescriptor == std::end(SectionTypeDescriptors))
+ return "mach-o section specifier uses an unknown section type";
+
+ // Remember the TypeID.
+ TAA = TypeDescriptor - std::begin(SectionTypeDescriptors);
+ TAAParsed = true;
+
+ // If we have no comma after the section type, there are no attributes.
+ if (Attrs.empty()) {
+ // S_SYMBOL_STUBS always require a symbol stub size specifier.
+ if (TAA == MachO::S_SYMBOL_STUBS)
+ return "mach-o section specifier of type 'symbol_stubs' requires a size "
+ "specifier";
+ return "";
+ }
+
+ // The attribute list is a '+' separated list of attributes.
+ SmallVector<StringRef, 1> SectionAttrs;
+ Attrs.split(SectionAttrs, '+', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+
+ for (StringRef &SectionAttr : SectionAttrs) {
+ auto AttrDescriptorI = std::find_if(
+ std::begin(SectionAttrDescriptors), std::end(SectionAttrDescriptors),
+ [&](decltype(*SectionAttrDescriptors) &Descriptor) {
+ return SectionAttr.trim() == Descriptor.AssemblerName;
+ });
+ if (AttrDescriptorI == std::end(SectionAttrDescriptors))
+ return "mach-o section specifier has invalid attribute";
+
+ TAA |= AttrDescriptorI->AttrFlag;
+ }
+
+ // Okay, we've parsed the section attributes, see if we have a stub size spec.
+ if (StubSizeStr.empty()) {
+ // S_SYMBOL_STUBS always require a symbol stub size specifier.
+ if (TAA == MachO::S_SYMBOL_STUBS)
+ return "mach-o section specifier of type 'symbol_stubs' requires a size "
+ "specifier";
+ return "";
+ }
+
+ // If we have a stub size spec, we must have a sectiontype of S_SYMBOL_STUBS.
+ if ((TAA & MachO::SECTION_TYPE) != MachO::S_SYMBOL_STUBS)
+ return "mach-o section specifier cannot have a stub size specified because "
+ "it does not have type 'symbol_stubs'";
+
+ // Convert the stub size from a string to an integer.
+ if (StubSizeStr.getAsInteger(0, StubSize))
+ return "mach-o section specifier has a malformed stub size";
+
+ return "";
+}
diff --git a/llvm/lib/MC/MCSectionWasm.cpp b/llvm/lib/MC/MCSectionWasm.cpp
new file mode 100644
index 000000000000..8633c10a73fd
--- /dev/null
+++ b/llvm/lib/MC/MCSectionWasm.cpp
@@ -0,0 +1,94 @@
+//===- lib/MC/MCSectionWasm.cpp - Wasm Code Section Representation --------===//
+//
+// 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/MCSectionWasm.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+// Decides whether a '.section' directive
+// should be printed before the section name.
+bool MCSectionWasm::shouldOmitSectionDirective(StringRef Name,
+ const MCAsmInfo &MAI) const {
+ return MAI.shouldOmitSectionDirective(Name);
+}
+
+static void printName(raw_ostream &OS, StringRef Name) {
+ if (Name.find_first_not_of("0123456789_."
+ "abcdefghijklmnopqrstuvwxyz"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ") == Name.npos) {
+ OS << Name;
+ return;
+ }
+ OS << '"';
+ for (const char *B = Name.begin(), *E = Name.end(); B < E; ++B) {
+ if (*B == '"') // Unquoted "
+ OS << "\\\"";
+ else if (*B != '\\') // Neither " or backslash
+ OS << *B;
+ else if (B + 1 == E) // Trailing backslash
+ OS << "\\\\";
+ else {
+ OS << B[0] << B[1]; // Quoted character
+ ++B;
+ }
+ }
+ OS << '"';
+}
+
+void MCSectionWasm::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+ raw_ostream &OS,
+ const MCExpr *Subsection) const {
+
+ if (shouldOmitSectionDirective(SectionName, MAI)) {
+ OS << '\t' << getSectionName();
+ if (Subsection) {
+ OS << '\t';
+ Subsection->print(OS, &MAI);
+ }
+ OS << '\n';
+ return;
+ }
+
+ OS << "\t.section\t";
+ printName(OS, getSectionName());
+ OS << ",\"";
+
+ if (IsPassive)
+ OS << "passive";
+
+ OS << '"';
+
+ OS << ',';
+
+ // If comment string is '@', e.g. as on ARM - use '%' instead
+ if (MAI.getCommentString()[0] == '@')
+ OS << '%';
+ else
+ OS << '@';
+
+ // TODO: Print section type.
+
+ if (isUnique())
+ OS << ",unique," << UniqueID;
+
+ OS << '\n';
+
+ if (Subsection) {
+ OS << "\t.subsection\t";
+ Subsection->print(OS, &MAI);
+ OS << '\n';
+ }
+}
+
+bool MCSectionWasm::UseCodeAlign() const { return false; }
+
+bool MCSectionWasm::isVirtualSection() const { return false; }
diff --git a/llvm/lib/MC/MCSectionXCOFF.cpp b/llvm/lib/MC/MCSectionXCOFF.cpp
new file mode 100644
index 000000000000..d52959f15f92
--- /dev/null
+++ b/llvm/lib/MC/MCSectionXCOFF.cpp
@@ -0,0 +1,79 @@
+//===- lib/MC/MCSectionXCOFF.cpp - XCOFF Code Section Representation ------===//
+//
+// 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/MCSectionXCOFF.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+MCSectionXCOFF::~MCSectionXCOFF() = default;
+
+static StringRef getMappingClassString(XCOFF::StorageMappingClass SMC) {
+ switch (SMC) {
+ case XCOFF::XMC_DS:
+ return "DS";
+ case XCOFF::XMC_RW:
+ return "RW";
+ case XCOFF::XMC_PR:
+ return "PR";
+ default:
+ report_fatal_error("Unhandled storage-mapping class.");
+ }
+}
+
+void MCSectionXCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, const Triple &T,
+ raw_ostream &OS,
+ const MCExpr *Subsection) const {
+ if (getKind().isText()) {
+ if (getMappingClass() != XCOFF::XMC_PR)
+ report_fatal_error("Unhandled storage-mapping class for .text csect");
+
+ OS << "\t.csect " << getSectionName() << "["
+ << getMappingClassString(getMappingClass())
+ << "]" << '\n';
+ return;
+ }
+
+ if (getKind().isData()) {
+ switch (getMappingClass()) {
+ case XCOFF::XMC_RW:
+ case XCOFF::XMC_DS:
+ OS << "\t.csect " << getSectionName() << "["
+ << getMappingClassString(getMappingClass()) << "]" << '\n';
+ break;
+ case XCOFF::XMC_TC0:
+ OS << "\t.toc\n";
+ break;
+ default:
+ report_fatal_error(
+ "Unhandled storage-mapping class for .data csect.");
+ }
+ return;
+ }
+
+ if (getKind().isBSSLocal() || getKind().isCommon()) {
+ assert((getMappingClass() == XCOFF::XMC_RW ||
+ getMappingClass() == XCOFF::XMC_BS) &&
+ "Generated a storage-mapping class for a common/bss csect we don't "
+ "understand how to switch to.");
+ assert(getCSectType() == XCOFF::XTY_CM &&
+ "wrong csect type for .bss csect");
+ // Don't have to print a directive for switching to section for commons.
+ // '.comm' and '.lcomm' directives for the variable will create the needed
+ // csect.
+ return;
+ }
+
+ report_fatal_error("Printing for this SectionKind is unimplemented.");
+}
+
+bool MCSectionXCOFF::UseCodeAlign() const { return getKind().isText(); }
+
+bool MCSectionXCOFF::isVirtualSection() const { return XCOFF::XTY_CM == Type; }
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
new file mode 100644
index 000000000000..b8278cb11079
--- /dev/null
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -0,0 +1,1164 @@
+//===- lib/MC/MCStreamer.cpp - Streaming Machine Code 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCCodeView.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDwarf.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCRegister.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCWin64EH.h"
+#include "llvm/MC/MCWinEH.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <cstdlib>
+#include <utility>
+
+using namespace llvm;
+
+MCTargetStreamer::MCTargetStreamer(MCStreamer &S) : Streamer(S) {
+ S.setTargetStreamer(this);
+}
+
+// Pin the vtables to this file.
+MCTargetStreamer::~MCTargetStreamer() = default;
+
+void MCTargetStreamer::emitLabel(MCSymbol *Symbol) {}
+
+void MCTargetStreamer::finish() {}
+
+void MCTargetStreamer::changeSection(const MCSection *CurSection,
+ MCSection *Section,
+ const MCExpr *Subsection,
+ raw_ostream &OS) {
+ Section->PrintSwitchToSection(
+ *Streamer.getContext().getAsmInfo(),
+ Streamer.getContext().getObjectFileInfo()->getTargetTriple(), OS,
+ Subsection);
+}
+
+void MCTargetStreamer::emitDwarfFileDirective(StringRef Directive) {
+ Streamer.EmitRawText(Directive);
+}
+
+void MCTargetStreamer::emitValue(const MCExpr *Value) {
+ SmallString<128> Str;
+ raw_svector_ostream OS(Str);
+
+ Value->print(OS, Streamer.getContext().getAsmInfo());
+ Streamer.EmitRawText(OS.str());
+}
+
+void MCTargetStreamer::emitRawBytes(StringRef Data) {
+ const MCAsmInfo *MAI = Streamer.getContext().getAsmInfo();
+ const char *Directive = MAI->getData8bitsDirective();
+ for (const unsigned char C : Data.bytes()) {
+ SmallString<128> Str;
+ raw_svector_ostream OS(Str);
+
+ OS << Directive << (unsigned)C;
+ Streamer.EmitRawText(OS.str());
+ }
+}
+
+void MCTargetStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {}
+
+MCStreamer::MCStreamer(MCContext &Ctx)
+ : Context(Ctx), CurrentWinFrameInfo(nullptr),
+ UseAssemblerInfoForParsing(false) {
+ SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>());
+}
+
+MCStreamer::~MCStreamer() {}
+
+void MCStreamer::reset() {
+ DwarfFrameInfos.clear();
+ CurrentWinFrameInfo = nullptr;
+ WinFrameInfos.clear();
+ SymbolOrdering.clear();
+ SectionStack.clear();
+ SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>());
+}
+
+raw_ostream &MCStreamer::GetCommentOS() {
+ // By default, discard comments.
+ return nulls();
+}
+
+unsigned MCStreamer::getNumFrameInfos() { return DwarfFrameInfos.size(); }
+ArrayRef<MCDwarfFrameInfo> MCStreamer::getDwarfFrameInfos() const {
+ return DwarfFrameInfos;
+}
+
+void MCStreamer::emitRawComment(const Twine &T, bool TabPrefix) {}
+
+void MCStreamer::addExplicitComment(const Twine &T) {}
+void MCStreamer::emitExplicitComments() {}
+
+void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend *MAB) {
+ for (auto &FI : DwarfFrameInfos)
+ FI.CompactUnwindEncoding =
+ (MAB ? MAB->generateCompactUnwindEncoding(FI.Instructions) : 0);
+}
+
+/// EmitIntValue - Special case of EmitValue that avoids the client having to
+/// pass in a MCExpr for constant integers.
+void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size) {
+ assert(1 <= Size && Size <= 8 && "Invalid size");
+ assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) &&
+ "Invalid size");
+ char buf[8];
+ const bool isLittleEndian = Context.getAsmInfo()->isLittleEndian();
+ for (unsigned i = 0; i != Size; ++i) {
+ unsigned index = isLittleEndian ? i : (Size - i - 1);
+ buf[i] = uint8_t(Value >> (index * 8));
+ }
+ EmitBytes(StringRef(buf, Size));
+}
+
+/// EmitULEB128IntValue - Special case of EmitULEB128Value that avoids the
+/// client having to pass in a MCExpr for constant integers.
+void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned PadTo) {
+ SmallString<128> Tmp;
+ raw_svector_ostream OSE(Tmp);
+ encodeULEB128(Value, OSE, PadTo);
+ EmitBytes(OSE.str());
+}
+
+/// EmitSLEB128IntValue - Special case of EmitSLEB128Value that avoids the
+/// client having to pass in a MCExpr for constant integers.
+void MCStreamer::EmitSLEB128IntValue(int64_t Value) {
+ SmallString<128> Tmp;
+ raw_svector_ostream OSE(Tmp);
+ encodeSLEB128(Value, OSE);
+ EmitBytes(OSE.str());
+}
+
+void MCStreamer::EmitValue(const MCExpr *Value, unsigned Size, SMLoc Loc) {
+ EmitValueImpl(Value, Size, Loc);
+}
+
+void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size,
+ bool IsSectionRelative) {
+ assert((!IsSectionRelative || Size == 4) &&
+ "SectionRelative value requires 4-bytes");
+
+ if (!IsSectionRelative)
+ EmitValueImpl(MCSymbolRefExpr::create(Sym, getContext()), Size);
+ else
+ EmitCOFFSecRel32(Sym, /*Offset=*/0);
+}
+
+void MCStreamer::EmitDTPRel64Value(const MCExpr *Value) {
+ report_fatal_error("unsupported directive in streamer");
+}
+
+void MCStreamer::EmitDTPRel32Value(const MCExpr *Value) {
+ report_fatal_error("unsupported directive in streamer");
+}
+
+void MCStreamer::EmitTPRel64Value(const MCExpr *Value) {
+ report_fatal_error("unsupported directive in streamer");
+}
+
+void MCStreamer::EmitTPRel32Value(const MCExpr *Value) {
+ report_fatal_error("unsupported directive in streamer");
+}
+
+void MCStreamer::EmitGPRel64Value(const MCExpr *Value) {
+ report_fatal_error("unsupported directive in streamer");
+}
+
+void MCStreamer::EmitGPRel32Value(const MCExpr *Value) {
+ report_fatal_error("unsupported directive in streamer");
+}
+
+/// Emit NumBytes bytes worth of the value specified by FillValue.
+/// This implements directives such as '.space'.
+void MCStreamer::emitFill(uint64_t NumBytes, uint8_t FillValue) {
+ emitFill(*MCConstantExpr::create(NumBytes, getContext()), FillValue);
+}
+
+/// The implementation in this class just redirects to emitFill.
+void MCStreamer::EmitZeros(uint64_t NumBytes) {
+ emitFill(NumBytes, 0);
+}
+
+Expected<unsigned>
+MCStreamer::tryEmitDwarfFileDirective(unsigned FileNo, StringRef Directory,
+ StringRef Filename,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ unsigned CUID) {
+ return getContext().getDwarfFile(Directory, Filename, FileNo, Checksum,
+ Source, CUID);
+}
+
+void MCStreamer::emitDwarfFile0Directive(StringRef Directory,
+ StringRef Filename,
+ Optional<MD5::MD5Result> Checksum,
+ Optional<StringRef> Source,
+ unsigned CUID) {
+ getContext().setMCLineTableRootFile(CUID, Directory, Filename, Checksum,
+ Source);
+}
+
+void MCStreamer::EmitCFIBKeyFrame() {
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->IsBKeyFrame = true;
+}
+
+void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line,
+ unsigned Column, unsigned Flags,
+ unsigned Isa,
+ unsigned Discriminator,
+ StringRef FileName) {
+ getContext().setCurrentDwarfLoc(FileNo, Line, Column, Flags, Isa,
+ Discriminator);
+}
+
+MCSymbol *MCStreamer::getDwarfLineTableSymbol(unsigned CUID) {
+ MCDwarfLineTable &Table = getContext().getMCDwarfLineTable(CUID);
+ if (!Table.getLabel()) {
+ StringRef Prefix = Context.getAsmInfo()->getPrivateGlobalPrefix();
+ Table.setLabel(
+ Context.getOrCreateSymbol(Prefix + "line_table_start" + Twine(CUID)));
+ }
+ return Table.getLabel();
+}
+
+bool MCStreamer::hasUnfinishedDwarfFrameInfo() {
+ return !DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End;
+}
+
+MCDwarfFrameInfo *MCStreamer::getCurrentDwarfFrameInfo() {
+ if (!hasUnfinishedDwarfFrameInfo()) {
+ getContext().reportError(SMLoc(), "this directive must appear between "
+ ".cfi_startproc and .cfi_endproc "
+ "directives");
+ return nullptr;
+ }
+ return &DwarfFrameInfos.back();
+}
+
+bool MCStreamer::EmitCVFileDirective(unsigned FileNo, StringRef Filename,
+ ArrayRef<uint8_t> Checksum,
+ unsigned ChecksumKind) {
+ return getContext().getCVContext().addFile(*this, FileNo, Filename, Checksum,
+ ChecksumKind);
+}
+
+bool MCStreamer::EmitCVFuncIdDirective(unsigned FunctionId) {
+ return getContext().getCVContext().recordFunctionId(FunctionId);
+}
+
+bool MCStreamer::EmitCVInlineSiteIdDirective(unsigned FunctionId,
+ unsigned IAFunc, unsigned IAFile,
+ unsigned IALine, unsigned IACol,
+ SMLoc Loc) {
+ if (getContext().getCVContext().getCVFunctionInfo(IAFunc) == nullptr) {
+ getContext().reportError(Loc, "parent function id not introduced by "
+ ".cv_func_id or .cv_inline_site_id");
+ return true;
+ }
+
+ return getContext().getCVContext().recordInlinedCallSiteId(
+ FunctionId, IAFunc, IAFile, IALine, IACol);
+}
+
+void MCStreamer::EmitCVLocDirective(unsigned FunctionId, unsigned FileNo,
+ unsigned Line, unsigned Column,
+ bool PrologueEnd, bool IsStmt,
+ StringRef FileName, SMLoc Loc) {}
+
+bool MCStreamer::checkCVLocSection(unsigned FuncId, unsigned FileNo,
+ SMLoc Loc) {
+ CodeViewContext &CVC = getContext().getCVContext();
+ MCCVFunctionInfo *FI = CVC.getCVFunctionInfo(FuncId);
+ if (!FI) {
+ getContext().reportError(
+ Loc, "function id not introduced by .cv_func_id or .cv_inline_site_id");
+ return false;
+ }
+
+ // Track the section
+ if (FI->Section == nullptr)
+ FI->Section = getCurrentSectionOnly();
+ else if (FI->Section != getCurrentSectionOnly()) {
+ getContext().reportError(
+ Loc,
+ "all .cv_loc directives for a function must be in the same section");
+ return false;
+ }
+ return true;
+}
+
+void MCStreamer::EmitCVLinetableDirective(unsigned FunctionId,
+ const MCSymbol *Begin,
+ const MCSymbol *End) {}
+
+void MCStreamer::EmitCVInlineLinetableDirective(unsigned PrimaryFunctionId,
+ unsigned SourceFileId,
+ unsigned SourceLineNum,
+ const MCSymbol *FnStartSym,
+ const MCSymbol *FnEndSym) {}
+
+/// Only call this on endian-specific types like ulittle16_t and little32_t, or
+/// structs composed of them.
+template <typename T>
+static void copyBytesForDefRange(SmallString<20> &BytePrefix,
+ codeview::SymbolKind SymKind,
+ const T &DefRangeHeader) {
+ BytePrefix.resize(2 + sizeof(T));
+ codeview::ulittle16_t SymKindLE = codeview::ulittle16_t(SymKind);
+ memcpy(&BytePrefix[0], &SymKindLE, 2);
+ memcpy(&BytePrefix[2], &DefRangeHeader, sizeof(T));
+}
+
+void MCStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ StringRef FixedSizePortion) {}
+
+void MCStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeRegisterRelHeader DRHdr) {
+ SmallString<20> BytePrefix;
+ copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_REGISTER_REL, DRHdr);
+ EmitCVDefRangeDirective(Ranges, BytePrefix);
+}
+
+void MCStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeSubfieldRegisterHeader DRHdr) {
+ SmallString<20> BytePrefix;
+ copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_SUBFIELD_REGISTER,
+ DRHdr);
+ EmitCVDefRangeDirective(Ranges, BytePrefix);
+}
+
+void MCStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeRegisterHeader DRHdr) {
+ SmallString<20> BytePrefix;
+ copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_REGISTER, DRHdr);
+ EmitCVDefRangeDirective(Ranges, BytePrefix);
+}
+
+void MCStreamer::EmitCVDefRangeDirective(
+ ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges,
+ codeview::DefRangeFramePointerRelHeader DRHdr) {
+ SmallString<20> BytePrefix;
+ copyBytesForDefRange(BytePrefix, codeview::S_DEFRANGE_FRAMEPOINTER_REL,
+ DRHdr);
+ EmitCVDefRangeDirective(Ranges, BytePrefix);
+}
+
+void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol,
+ MCSymbol *EHSymbol) {
+}
+
+void MCStreamer::InitSections(bool NoExecStack) {
+ SwitchSection(getContext().getObjectFileInfo()->getTextSection());
+}
+
+void MCStreamer::AssignFragment(MCSymbol *Symbol, MCFragment *Fragment) {
+ assert(Fragment);
+ Symbol->setFragment(Fragment);
+
+ // As we emit symbols into a section, track the order so that they can
+ // be sorted upon later. Zero is reserved to mean 'unemitted'.
+ SymbolOrdering[Symbol] = 1 + SymbolOrdering.size();
+}
+
+void MCStreamer::EmitLabel(MCSymbol *Symbol, SMLoc Loc) {
+ Symbol->redefineIfPossible();
+
+ if (!Symbol->isUndefined() || Symbol->isVariable())
+ return getContext().reportError(Loc, "invalid symbol redefinition");
+
+ assert(!Symbol->isVariable() && "Cannot emit a variable symbol!");
+ assert(getCurrentSectionOnly() && "Cannot emit before setting section!");
+ assert(!Symbol->getFragment() && "Unexpected fragment on symbol data!");
+ assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
+
+ Symbol->setFragment(&getCurrentSectionOnly()->getDummyFragment());
+
+ MCTargetStreamer *TS = getTargetStreamer();
+ if (TS)
+ TS->emitLabel(Symbol);
+}
+
+void MCStreamer::EmitCFISections(bool EH, bool Debug) {
+ assert(EH || Debug);
+}
+
+void MCStreamer::EmitCFIStartProc(bool IsSimple, SMLoc Loc) {
+ if (hasUnfinishedDwarfFrameInfo())
+ return getContext().reportError(
+ Loc, "starting new .cfi frame before finishing the previous one");
+
+ MCDwarfFrameInfo Frame;
+ Frame.IsSimple = IsSimple;
+ EmitCFIStartProcImpl(Frame);
+
+ const MCAsmInfo* MAI = Context.getAsmInfo();
+ if (MAI) {
+ for (const MCCFIInstruction& Inst : MAI->getInitialFrameState()) {
+ if (Inst.getOperation() == MCCFIInstruction::OpDefCfa ||
+ Inst.getOperation() == MCCFIInstruction::OpDefCfaRegister) {
+ Frame.CurrentCfaRegister = Inst.getRegister();
+ }
+ }
+ }
+
+ DwarfFrameInfos.push_back(Frame);
+}
+
+void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) {
+}
+
+void MCStreamer::EmitCFIEndProc() {
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ EmitCFIEndProcImpl(*CurFrame);
+}
+
+void MCStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) {
+ // Put a dummy non-null value in Frame.End to mark that this frame has been
+ // closed.
+ Frame.End = (MCSymbol *)1;
+}
+
+MCSymbol *MCStreamer::EmitCFILabel() {
+ // Return a dummy non-null value so that label fields appear filled in when
+ // generating textual assembly.
+ return (MCSymbol *)1;
+}
+
+void MCStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createDefCfa(Label, Register, Offset);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+ CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register);
+}
+
+void MCStreamer::EmitCFIDefCfaOffset(int64_t Offset) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createDefCfaOffset(Label, Offset);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createAdjustCfaOffset(Label, Adjustment);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIDefCfaRegister(int64_t Register) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createDefCfaRegister(Label, Register);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+ CurFrame->CurrentCfaRegister = static_cast<unsigned>(Register);
+}
+
+void MCStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createOffset(Label, Register, Offset);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createRelOffset(Label, Register, Offset);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIPersonality(const MCSymbol *Sym,
+ unsigned Encoding) {
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Personality = Sym;
+ CurFrame->PersonalityEncoding = Encoding;
+}
+
+void MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) {
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Lsda = Sym;
+ CurFrame->LsdaEncoding = Encoding;
+}
+
+void MCStreamer::EmitCFIRememberState() {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction = MCCFIInstruction::createRememberState(Label);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIRestoreState() {
+ // FIXME: Error if there is no matching cfi_remember_state.
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction = MCCFIInstruction::createRestoreState(Label);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFISameValue(int64_t Register) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createSameValue(Label, Register);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIRestore(int64_t Register) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createRestore(Label, Register);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIEscape(StringRef Values) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction = MCCFIInstruction::createEscape(Label, Values);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIGnuArgsSize(int64_t Size) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createGnuArgsSize(Label, Size);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFISignalFrame() {
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->IsSignalFrame = true;
+}
+
+void MCStreamer::EmitCFIUndefined(int64_t Register) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createUndefined(Label, Register);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createRegister(Label, Register1, Register2);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIWindowSave() {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction =
+ MCCFIInstruction::createWindowSave(Label);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFINegateRAState() {
+ MCSymbol *Label = EmitCFILabel();
+ MCCFIInstruction Instruction = MCCFIInstruction::createNegateRAState(Label);
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->Instructions.push_back(Instruction);
+}
+
+void MCStreamer::EmitCFIReturnColumn(int64_t Register) {
+ MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+ if (!CurFrame)
+ return;
+ CurFrame->RAReg = Register;
+}
+
+WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) {
+ const MCAsmInfo *MAI = Context.getAsmInfo();
+ if (!MAI->usesWindowsCFI()) {
+ getContext().reportError(
+ Loc, ".seh_* directives are not supported on this target");
+ return nullptr;
+ }
+ if (!CurrentWinFrameInfo || CurrentWinFrameInfo->End) {
+ getContext().reportError(
+ Loc, ".seh_ directive must appear within an active frame");
+ return nullptr;
+ }
+ return CurrentWinFrameInfo;
+}
+
+void MCStreamer::EmitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
+ const MCAsmInfo *MAI = Context.getAsmInfo();
+ if (!MAI->usesWindowsCFI())
+ return getContext().reportError(
+ Loc, ".seh_* directives are not supported on this target");
+ if (CurrentWinFrameInfo && !CurrentWinFrameInfo->End)
+ getContext().reportError(
+ Loc, "Starting a function before ending the previous one!");
+
+ MCSymbol *StartProc = EmitCFILabel();
+
+ WinFrameInfos.emplace_back(
+ std::make_unique<WinEH::FrameInfo>(Symbol, StartProc));
+ CurrentWinFrameInfo = WinFrameInfos.back().get();
+ CurrentWinFrameInfo->TextSection = getCurrentSectionOnly();
+}
+
+void MCStreamer::EmitWinCFIEndProc(SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (CurFrame->ChainedParent)
+ getContext().reportError(Loc, "Not all chained regions terminated!");
+
+ MCSymbol *Label = EmitCFILabel();
+ CurFrame->End = Label;
+}
+
+void MCStreamer::EmitWinCFIFuncletOrFuncEnd(SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (CurFrame->ChainedParent)
+ getContext().reportError(Loc, "Not all chained regions terminated!");
+
+ MCSymbol *Label = EmitCFILabel();
+ CurFrame->FuncletOrFuncEnd = Label;
+}
+
+void MCStreamer::EmitWinCFIStartChained(SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+
+ MCSymbol *StartProc = EmitCFILabel();
+
+ WinFrameInfos.emplace_back(std::make_unique<WinEH::FrameInfo>(
+ CurFrame->Function, StartProc, CurFrame));
+ CurrentWinFrameInfo = WinFrameInfos.back().get();
+ CurrentWinFrameInfo->TextSection = getCurrentSectionOnly();
+}
+
+void MCStreamer::EmitWinCFIEndChained(SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (!CurFrame->ChainedParent)
+ return getContext().reportError(
+ Loc, "End of a chained region outside a chained region!");
+
+ MCSymbol *Label = EmitCFILabel();
+
+ CurFrame->End = Label;
+ CurrentWinFrameInfo = const_cast<WinEH::FrameInfo *>(CurFrame->ChainedParent);
+}
+
+void MCStreamer::EmitWinEHHandler(const MCSymbol *Sym, bool Unwind, bool Except,
+ SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (CurFrame->ChainedParent)
+ return getContext().reportError(
+ Loc, "Chained unwind areas can't have handlers!");
+ CurFrame->ExceptionHandler = Sym;
+ if (!Except && !Unwind)
+ getContext().reportError(Loc, "Don't know what kind of handler this is!");
+ if (Unwind)
+ CurFrame->HandlesUnwind = true;
+ if (Except)
+ CurFrame->HandlesExceptions = true;
+}
+
+void MCStreamer::EmitWinEHHandlerData(SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (CurFrame->ChainedParent)
+ getContext().reportError(Loc, "Chained unwind areas can't have handlers!");
+}
+
+void MCStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
+ const MCSymbolRefExpr *To, uint64_t Count) {
+}
+
+static MCSection *getWinCFISection(MCContext &Context, unsigned *NextWinCFIID,
+ MCSection *MainCFISec,
+ const MCSection *TextSec) {
+ // If this is the main .text section, use the main unwind info section.
+ if (TextSec == Context.getObjectFileInfo()->getTextSection())
+ return MainCFISec;
+
+ const auto *TextSecCOFF = cast<MCSectionCOFF>(TextSec);
+ auto *MainCFISecCOFF = cast<MCSectionCOFF>(MainCFISec);
+ unsigned UniqueID = TextSecCOFF->getOrAssignWinCFISectionID(NextWinCFIID);
+
+ // If this section is COMDAT, this unwind section should be COMDAT associative
+ // with its group.
+ const MCSymbol *KeySym = nullptr;
+ if (TextSecCOFF->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) {
+ KeySym = TextSecCOFF->getCOMDATSymbol();
+
+ // In a GNU environment, we can't use associative comdats. Instead, do what
+ // GCC does, which is to make plain comdat selectany section named like
+ // ".[px]data$_Z3foov".
+ if (!Context.getAsmInfo()->hasCOFFAssociativeComdats()) {
+ std::string SectionName =
+ (MainCFISecCOFF->getSectionName() + "$" +
+ TextSecCOFF->getSectionName().split('$').second)
+ .str();
+ return Context.getCOFFSection(
+ SectionName,
+ MainCFISecCOFF->getCharacteristics() | COFF::IMAGE_SCN_LNK_COMDAT,
+ MainCFISecCOFF->getKind(), "", COFF::IMAGE_COMDAT_SELECT_ANY);
+ }
+ }
+
+ return Context.getAssociativeCOFFSection(MainCFISecCOFF, KeySym, UniqueID);
+}
+
+MCSection *MCStreamer::getAssociatedPDataSection(const MCSection *TextSec) {
+ return getWinCFISection(getContext(), &NextWinCFIID,
+ getContext().getObjectFileInfo()->getPDataSection(),
+ TextSec);
+}
+
+MCSection *MCStreamer::getAssociatedXDataSection(const MCSection *TextSec) {
+ return getWinCFISection(getContext(), &NextWinCFIID,
+ getContext().getObjectFileInfo()->getXDataSection(),
+ TextSec);
+}
+
+void MCStreamer::EmitSyntaxDirective() {}
+
+static unsigned encodeSEHRegNum(MCContext &Ctx, MCRegister Reg) {
+ return Ctx.getRegisterInfo()->getSEHRegNum(Reg);
+}
+
+void MCStreamer::EmitWinCFIPushReg(MCRegister Register, SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+
+ MCSymbol *Label = EmitCFILabel();
+
+ WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol(
+ Label, encodeSEHRegNum(Context, Register));
+ CurFrame->Instructions.push_back(Inst);
+}
+
+void MCStreamer::EmitWinCFISetFrame(MCRegister Register, unsigned Offset,
+ SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (CurFrame->LastFrameInst >= 0)
+ return getContext().reportError(
+ Loc, "frame register and offset can be set at most once");
+ if (Offset & 0x0F)
+ return getContext().reportError(Loc, "offset is not a multiple of 16");
+ if (Offset > 240)
+ return getContext().reportError(
+ Loc, "frame offset must be less than or equal to 240");
+
+ MCSymbol *Label = EmitCFILabel();
+
+ WinEH::Instruction Inst = Win64EH::Instruction::SetFPReg(
+ Label, encodeSEHRegNum(getContext(), Register), Offset);
+ CurFrame->LastFrameInst = CurFrame->Instructions.size();
+ CurFrame->Instructions.push_back(Inst);
+}
+
+void MCStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (Size == 0)
+ return getContext().reportError(Loc,
+ "stack allocation size must be non-zero");
+ if (Size & 7)
+ return getContext().reportError(
+ Loc, "stack allocation size is not a multiple of 8");
+
+ MCSymbol *Label = EmitCFILabel();
+
+ WinEH::Instruction Inst = Win64EH::Instruction::Alloc(Label, Size);
+ CurFrame->Instructions.push_back(Inst);
+}
+
+void MCStreamer::EmitWinCFISaveReg(MCRegister Register, unsigned Offset,
+ SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+
+ if (Offset & 7)
+ return getContext().reportError(
+ Loc, "register save offset is not 8 byte aligned");
+
+ MCSymbol *Label = EmitCFILabel();
+
+ WinEH::Instruction Inst = Win64EH::Instruction::SaveNonVol(
+ Label, encodeSEHRegNum(Context, Register), Offset);
+ CurFrame->Instructions.push_back(Inst);
+}
+
+void MCStreamer::EmitWinCFISaveXMM(MCRegister Register, unsigned Offset,
+ SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (Offset & 0x0F)
+ return getContext().reportError(Loc, "offset is not a multiple of 16");
+
+ MCSymbol *Label = EmitCFILabel();
+
+ WinEH::Instruction Inst = Win64EH::Instruction::SaveXMM(
+ Label, encodeSEHRegNum(Context, Register), Offset);
+ CurFrame->Instructions.push_back(Inst);
+}
+
+void MCStreamer::EmitWinCFIPushFrame(bool Code, SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+ if (!CurFrame->Instructions.empty())
+ return getContext().reportError(
+ Loc, "If present, PushMachFrame must be the first UOP");
+
+ MCSymbol *Label = EmitCFILabel();
+
+ WinEH::Instruction Inst = Win64EH::Instruction::PushMachFrame(Label, Code);
+ CurFrame->Instructions.push_back(Inst);
+}
+
+void MCStreamer::EmitWinCFIEndProlog(SMLoc Loc) {
+ WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc);
+ if (!CurFrame)
+ return;
+
+ MCSymbol *Label = EmitCFILabel();
+
+ CurFrame->PrologEnd = Label;
+}
+
+void MCStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) {}
+
+void MCStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) {}
+
+void MCStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {}
+
+void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol, uint64_t Offset) {}
+
+void MCStreamer::EmitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) {}
+
+/// EmitRawText - If this file is backed by an assembly streamer, this dumps
+/// the specified string in the output .s file. This capability is
+/// indicated by the hasRawTextSupport() predicate.
+void MCStreamer::EmitRawTextImpl(StringRef String) {
+ // This is not llvm_unreachable for the sake of out of tree backend
+ // developers who may not have assembly streamers and should serve as a
+ // reminder to not accidentally call EmitRawText in the absence of such.
+ report_fatal_error("EmitRawText called on an MCStreamer that doesn't support "
+ "it (target backend is likely missing an AsmStreamer "
+ "implementation)");
+}
+
+void MCStreamer::EmitRawText(const Twine &T) {
+ SmallString<128> Str;
+ EmitRawTextImpl(T.toStringRef(Str));
+}
+
+void MCStreamer::EmitWindowsUnwindTables() {
+}
+
+void MCStreamer::Finish() {
+ if ((!DwarfFrameInfos.empty() && !DwarfFrameInfos.back().End) ||
+ (!WinFrameInfos.empty() && !WinFrameInfos.back()->End)) {
+ getContext().reportError(SMLoc(), "Unfinished frame!");
+ return;
+ }
+
+ MCTargetStreamer *TS = getTargetStreamer();
+ if (TS)
+ TS->finish();
+
+ FinishImpl();
+}
+
+void MCStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ visitUsedExpr(*Value);
+ Symbol->setVariableValue(Value);
+
+ MCTargetStreamer *TS = getTargetStreamer();
+ if (TS)
+ TS->emitAssignment(Symbol, Value);
+}
+
+void MCTargetStreamer::prettyPrintAsm(MCInstPrinter &InstPrinter,
+ raw_ostream &OS, const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ InstPrinter.printInst(&Inst, OS, "", STI);
+}
+
+void MCStreamer::visitUsedSymbol(const MCSymbol &Sym) {
+}
+
+void MCStreamer::visitUsedExpr(const MCExpr &Expr) {
+ switch (Expr.getKind()) {
+ case MCExpr::Target:
+ cast<MCTargetExpr>(Expr).visitUsedExpr(*this);
+ break;
+
+ case MCExpr::Constant:
+ break;
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr &BE = cast<MCBinaryExpr>(Expr);
+ visitUsedExpr(*BE.getLHS());
+ visitUsedExpr(*BE.getRHS());
+ break;
+ }
+
+ case MCExpr::SymbolRef:
+ visitUsedSymbol(cast<MCSymbolRefExpr>(Expr).getSymbol());
+ break;
+
+ case MCExpr::Unary:
+ visitUsedExpr(*cast<MCUnaryExpr>(Expr).getSubExpr());
+ break;
+ }
+}
+
+void MCStreamer::EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &) {
+ // Scan for values.
+ for (unsigned i = Inst.getNumOperands(); i--;)
+ if (Inst.getOperand(i).isExpr())
+ visitUsedExpr(*Inst.getOperand(i).getExpr());
+}
+
+void MCStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo,
+ unsigned Size) {
+ // Get the Hi-Lo expression.
+ const MCExpr *Diff =
+ MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Context),
+ MCSymbolRefExpr::create(Lo, Context), Context);
+
+ const MCAsmInfo *MAI = Context.getAsmInfo();
+ if (!MAI->doesSetDirectiveSuppressReloc()) {
+ EmitValue(Diff, Size);
+ return;
+ }
+
+ // Otherwise, emit with .set (aka assignment).
+ MCSymbol *SetLabel = Context.createTempSymbol("set", true);
+ EmitAssignment(SetLabel, Diff);
+ EmitSymbolValue(SetLabel, Size);
+}
+
+void MCStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
+ const MCSymbol *Lo) {
+ // Get the Hi-Lo expression.
+ const MCExpr *Diff =
+ MCBinaryExpr::createSub(MCSymbolRefExpr::create(Hi, Context),
+ MCSymbolRefExpr::create(Lo, Context), Context);
+
+ EmitULEB128Value(Diff);
+}
+
+void MCStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {}
+void MCStreamer::EmitThumbFunc(MCSymbol *Func) {}
+void MCStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {}
+void MCStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) {
+ llvm_unreachable("this directive only supported on COFF targets");
+}
+void MCStreamer::EndCOFFSymbolDef() {
+ llvm_unreachable("this directive only supported on COFF targets");
+}
+void MCStreamer::EmitFileDirective(StringRef Filename) {}
+void MCStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {
+ llvm_unreachable("this directive only supported on COFF targets");
+}
+void MCStreamer::EmitCOFFSymbolType(int Type) {
+ llvm_unreachable("this directive only supported on COFF targets");
+}
+void MCStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlign) {
+ llvm_unreachable("this directive only supported on XCOFF targets");
+}
+void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {}
+void MCStreamer::emitELFSymverDirective(StringRef AliasName,
+ const MCSymbol *Aliasee) {}
+void MCStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {}
+void MCStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {}
+void MCStreamer::ChangeSection(MCSection *, const MCExpr *) {}
+void MCStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) {}
+void MCStreamer::EmitBytes(StringRef Data) {}
+void MCStreamer::EmitBinaryData(StringRef Data) { EmitBytes(Data); }
+void MCStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, SMLoc Loc) {
+ visitUsedExpr(*Value);
+}
+void MCStreamer::EmitULEB128Value(const MCExpr *Value) {}
+void MCStreamer::EmitSLEB128Value(const MCExpr *Value) {}
+void MCStreamer::emitFill(const MCExpr &NumBytes, uint64_t Value, SMLoc Loc) {}
+void MCStreamer::emitFill(const MCExpr &NumValues, int64_t Size, int64_t Expr,
+ SMLoc Loc) {}
+void MCStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {}
+void MCStreamer::EmitCodeAlignment(unsigned ByteAlignment,
+ unsigned MaxBytesToEmit) {}
+void MCStreamer::emitValueToOffset(const MCExpr *Offset, unsigned char Value,
+ SMLoc Loc) {}
+void MCStreamer::EmitBundleAlignMode(unsigned AlignPow2) {}
+void MCStreamer::EmitBundleLock(bool AlignToEnd) {}
+void MCStreamer::FinishImpl() {}
+void MCStreamer::EmitBundleUnlock() {}
+
+void MCStreamer::SwitchSection(MCSection *Section, const MCExpr *Subsection) {
+ assert(Section && "Cannot switch to a null section!");
+ MCSectionSubPair curSection = SectionStack.back().first;
+ SectionStack.back().second = curSection;
+ if (MCSectionSubPair(Section, Subsection) != curSection) {
+ ChangeSection(Section, Subsection);
+ SectionStack.back().first = MCSectionSubPair(Section, Subsection);
+ assert(!Section->hasEnded() && "Section already ended");
+ MCSymbol *Sym = Section->getBeginSymbol();
+ if (Sym && !Sym->isInSection())
+ EmitLabel(Sym);
+ }
+}
+
+MCSymbol *MCStreamer::endSection(MCSection *Section) {
+ // TODO: keep track of the last subsection so that this symbol appears in the
+ // correct place.
+ MCSymbol *Sym = Section->getEndSymbol(Context);
+ if (Sym->isInSection())
+ return Sym;
+
+ SwitchSection(Section);
+ EmitLabel(Sym);
+ return Sym;
+}
+
+void MCStreamer::EmitVersionForTarget(const Triple &Target,
+ const VersionTuple &SDKVersion) {
+ if (!Target.isOSBinFormatMachO() || !Target.isOSDarwin())
+ return;
+ // Do we even know the version?
+ if (Target.getOSMajorVersion() == 0)
+ return;
+
+ unsigned Major;
+ unsigned Minor;
+ unsigned Update;
+ if (Target.isMacCatalystEnvironment()) {
+ // Mac Catalyst always uses the build version load command.
+ Target.getiOSVersion(Major, Minor, Update);
+ assert(Major && "A non-zero major version is expected");
+ EmitBuildVersion(MachO::PLATFORM_MACCATALYST, Major, Minor, Update,
+ SDKVersion);
+ return;
+ }
+
+ MCVersionMinType VersionType;
+ if (Target.isWatchOS()) {
+ VersionType = MCVM_WatchOSVersionMin;
+ Target.getWatchOSVersion(Major, Minor, Update);
+ } else if (Target.isTvOS()) {
+ VersionType = MCVM_TvOSVersionMin;
+ Target.getiOSVersion(Major, Minor, Update);
+ } else if (Target.isMacOSX()) {
+ VersionType = MCVM_OSXVersionMin;
+ if (!Target.getMacOSXVersion(Major, Minor, Update))
+ Major = 0;
+ } else {
+ VersionType = MCVM_IOSVersionMin;
+ Target.getiOSVersion(Major, Minor, Update);
+ }
+ if (Major != 0)
+ EmitVersionMin(VersionType, Major, Minor, Update, SDKVersion);
+}
diff --git a/llvm/lib/MC/MCSubtargetInfo.cpp b/llvm/lib/MC/MCSubtargetInfo.cpp
new file mode 100644
index 000000000000..c8678df02bfd
--- /dev/null
+++ b/llvm/lib/MC/MCSubtargetInfo.cpp
@@ -0,0 +1,342 @@
+//===- MCSubtargetInfo.cpp - Subtarget Information ------------------------===//
+//
+// 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/MCSubtargetInfo.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/MC/MCInstrItineraries.h"
+#include "llvm/MC/MCSchedule.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+using namespace llvm;
+
+/// Find KV in array using binary search.
+template <typename T>
+static const T *Find(StringRef S, ArrayRef<T> A) {
+ // Binary search the array
+ auto F = llvm::lower_bound(A, S);
+ // If not found then return NULL
+ if (F == A.end() || StringRef(F->Key) != S) return nullptr;
+ // Return the found array item
+ return F;
+}
+
+/// For each feature that is (transitively) implied by this feature, set it.
+static
+void SetImpliedBits(FeatureBitset &Bits, const FeatureBitset &Implies,
+ ArrayRef<SubtargetFeatureKV> FeatureTable) {
+ // OR the Implies bits in outside the loop. This allows the Implies for CPUs
+ // which might imply features not in FeatureTable to use this.
+ Bits |= Implies;
+ for (const SubtargetFeatureKV &FE : FeatureTable)
+ if (Implies.test(FE.Value))
+ SetImpliedBits(Bits, FE.Implies.getAsBitset(), FeatureTable);
+}
+
+/// For each feature that (transitively) implies this feature, clear it.
+static
+void ClearImpliedBits(FeatureBitset &Bits, unsigned Value,
+ ArrayRef<SubtargetFeatureKV> FeatureTable) {
+ for (const SubtargetFeatureKV &FE : FeatureTable) {
+ if (FE.Implies.getAsBitset().test(Value)) {
+ Bits.reset(FE.Value);
+ ClearImpliedBits(Bits, FE.Value, FeatureTable);
+ }
+ }
+}
+
+static void ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature,
+ ArrayRef<SubtargetFeatureKV> FeatureTable) {
+ assert(SubtargetFeatures::hasFlag(Feature) &&
+ "Feature flags should start with '+' or '-'");
+
+ // Find feature in table.
+ const SubtargetFeatureKV *FeatureEntry =
+ Find(SubtargetFeatures::StripFlag(Feature), FeatureTable);
+ // If there is a match
+ if (FeatureEntry) {
+ // Enable/disable feature in bits
+ if (SubtargetFeatures::isEnabled(Feature)) {
+ Bits.set(FeatureEntry->Value);
+
+ // For each feature that this implies, set it.
+ SetImpliedBits(Bits, FeatureEntry->Implies.getAsBitset(), FeatureTable);
+ } else {
+ Bits.reset(FeatureEntry->Value);
+
+ // For each feature that implies this, clear it.
+ ClearImpliedBits(Bits, FeatureEntry->Value, FeatureTable);
+ }
+ } else {
+ errs() << "'" << Feature << "' is not a recognized feature for this target"
+ << " (ignoring feature)\n";
+ }
+}
+
+/// Return the length of the longest entry in the table.
+template <typename T>
+static size_t getLongestEntryLength(ArrayRef<T> Table) {
+ size_t MaxLen = 0;
+ for (auto &I : Table)
+ MaxLen = std::max(MaxLen, std::strlen(I.Key));
+ return MaxLen;
+}
+
+/// Display help for feature and mcpu choices.
+static void Help(ArrayRef<SubtargetSubTypeKV> CPUTable,
+ ArrayRef<SubtargetFeatureKV> FeatTable) {
+ // the static variable ensures that the help information only gets
+ // printed once even though a target machine creates multiple subtargets
+ static bool PrintOnce = false;
+ if (PrintOnce) {
+ return;
+ }
+
+ // Determine the length of the longest CPU and Feature entries.
+ unsigned MaxCPULen = getLongestEntryLength(CPUTable);
+ unsigned MaxFeatLen = getLongestEntryLength(FeatTable);
+
+ // Print the CPU table.
+ errs() << "Available CPUs for this target:\n\n";
+ for (auto &CPU : CPUTable)
+ errs() << format(" %-*s - Select the %s processor.\n", MaxCPULen, CPU.Key,
+ CPU.Key);
+ errs() << '\n';
+
+ // Print the Feature table.
+ errs() << "Available features for this target:\n\n";
+ for (auto &Feature : FeatTable)
+ errs() << format(" %-*s - %s.\n", MaxFeatLen, Feature.Key, Feature.Desc);
+ errs() << '\n';
+
+ errs() << "Use +feature to enable a feature, or -feature to disable it.\n"
+ "For example, llc -mcpu=mycpu -mattr=+feature1,-feature2\n";
+
+ PrintOnce = true;
+}
+
+/// Display help for mcpu choices only
+static void cpuHelp(ArrayRef<SubtargetSubTypeKV> CPUTable) {
+ // the static variable ensures that the help information only gets
+ // printed once even though a target machine creates multiple subtargets
+ static bool PrintOnce = false;
+ if (PrintOnce) {
+ return;
+ }
+
+ // Print the CPU table.
+ errs() << "Available CPUs for this target:\n\n";
+ for (auto &CPU : CPUTable)
+ errs() << "\t" << CPU.Key << "\n";
+ errs() << '\n';
+
+ errs() << "Use -mcpu or -mtune to specify the target's processor.\n"
+ "For example, clang --target=aarch64-unknown-linux-gui "
+ "-mcpu=cortex-a35\n";
+
+ PrintOnce = true;
+}
+
+static FeatureBitset getFeatures(StringRef CPU, StringRef FS,
+ ArrayRef<SubtargetSubTypeKV> ProcDesc,
+ ArrayRef<SubtargetFeatureKV> ProcFeatures) {
+ SubtargetFeatures Features(FS);
+
+ if (ProcDesc.empty() || ProcFeatures.empty())
+ return FeatureBitset();
+
+ assert(std::is_sorted(std::begin(ProcDesc), std::end(ProcDesc)) &&
+ "CPU table is not sorted");
+ assert(std::is_sorted(std::begin(ProcFeatures), std::end(ProcFeatures)) &&
+ "CPU features table is not sorted");
+ // Resulting bits
+ FeatureBitset Bits;
+
+ // Check if help is needed
+ if (CPU == "help")
+ Help(ProcDesc, ProcFeatures);
+
+ // Find CPU entry if CPU name is specified.
+ else if (!CPU.empty()) {
+ const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc);
+
+ // If there is a match
+ if (CPUEntry) {
+ // Set the features implied by this CPU feature, if any.
+ SetImpliedBits(Bits, CPUEntry->Implies.getAsBitset(), ProcFeatures);
+ } else {
+ errs() << "'" << CPU << "' is not a recognized processor for this target"
+ << " (ignoring processor)\n";
+ }
+ }
+
+ // Iterate through each feature
+ for (const std::string &Feature : Features.getFeatures()) {
+ // Check for help
+ if (Feature == "+help")
+ Help(ProcDesc, ProcFeatures);
+ else if (Feature == "+cpuHelp")
+ cpuHelp(ProcDesc);
+ else
+ ApplyFeatureFlag(Bits, Feature, ProcFeatures);
+ }
+
+ return Bits;
+}
+
+void MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef FS) {
+ FeatureBits = getFeatures(CPU, FS, ProcDesc, ProcFeatures);
+ if (!CPU.empty())
+ CPUSchedModel = &getSchedModelForCPU(CPU);
+ else
+ CPUSchedModel = &MCSchedModel::GetDefaultSchedModel();
+}
+
+void MCSubtargetInfo::setDefaultFeatures(StringRef CPU, StringRef FS) {
+ FeatureBits = getFeatures(CPU, FS, ProcDesc, ProcFeatures);
+}
+
+MCSubtargetInfo::MCSubtargetInfo(
+ const Triple &TT, StringRef C, StringRef FS,
+ ArrayRef<SubtargetFeatureKV> PF, ArrayRef<SubtargetSubTypeKV> PD,
+ const MCWriteProcResEntry *WPR,
+ const MCWriteLatencyEntry *WL, const MCReadAdvanceEntry *RA,
+ const InstrStage *IS, const unsigned *OC, const unsigned *FP)
+ : TargetTriple(TT), CPU(C), ProcFeatures(PF), ProcDesc(PD),
+ WriteProcResTable(WPR), WriteLatencyTable(WL),
+ ReadAdvanceTable(RA), Stages(IS), OperandCycles(OC), ForwardingPaths(FP) {
+ InitMCProcessorInfo(CPU, FS);
+}
+
+FeatureBitset MCSubtargetInfo::ToggleFeature(uint64_t FB) {
+ FeatureBits.flip(FB);
+ return FeatureBits;
+}
+
+FeatureBitset MCSubtargetInfo::ToggleFeature(const FeatureBitset &FB) {
+ FeatureBits ^= FB;
+ return FeatureBits;
+}
+
+FeatureBitset MCSubtargetInfo::SetFeatureBitsTransitively(
+ const FeatureBitset &FB) {
+ SetImpliedBits(FeatureBits, FB, ProcFeatures);
+ return FeatureBits;
+}
+
+FeatureBitset MCSubtargetInfo::ClearFeatureBitsTransitively(
+ const FeatureBitset &FB) {
+ for (unsigned I = 0, E = FB.size(); I < E; I++) {
+ if (FB[I]) {
+ FeatureBits.reset(I);
+ ClearImpliedBits(FeatureBits, I, ProcFeatures);
+ }
+ }
+ return FeatureBits;
+}
+
+FeatureBitset MCSubtargetInfo::ToggleFeature(StringRef Feature) {
+ // Find feature in table.
+ const SubtargetFeatureKV *FeatureEntry =
+ Find(SubtargetFeatures::StripFlag(Feature), ProcFeatures);
+ // If there is a match
+ if (FeatureEntry) {
+ if (FeatureBits.test(FeatureEntry->Value)) {
+ FeatureBits.reset(FeatureEntry->Value);
+ // For each feature that implies this, clear it.
+ ClearImpliedBits(FeatureBits, FeatureEntry->Value, ProcFeatures);
+ } else {
+ FeatureBits.set(FeatureEntry->Value);
+
+ // For each feature that this implies, set it.
+ SetImpliedBits(FeatureBits, FeatureEntry->Implies.getAsBitset(),
+ ProcFeatures);
+ }
+ } else {
+ errs() << "'" << Feature << "' is not a recognized feature for this target"
+ << " (ignoring feature)\n";
+ }
+
+ return FeatureBits;
+}
+
+FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) {
+ ::ApplyFeatureFlag(FeatureBits, FS, ProcFeatures);
+ return FeatureBits;
+}
+
+bool MCSubtargetInfo::checkFeatures(StringRef FS) const {
+ SubtargetFeatures T(FS);
+ FeatureBitset Set, All;
+ for (std::string F : T.getFeatures()) {
+ ::ApplyFeatureFlag(Set, F, ProcFeatures);
+ if (F[0] == '-')
+ F[0] = '+';
+ ::ApplyFeatureFlag(All, F, ProcFeatures);
+ }
+ return (FeatureBits & All) == Set;
+}
+
+const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const {
+ assert(std::is_sorted(ProcDesc.begin(), ProcDesc.end()) &&
+ "Processor machine model table is not sorted");
+
+ // Find entry
+ const SubtargetSubTypeKV *CPUEntry = Find(CPU, ProcDesc);
+
+ if (!CPUEntry) {
+ if (CPU != "help") // Don't error if the user asked for help.
+ errs() << "'" << CPU
+ << "' is not a recognized processor for this target"
+ << " (ignoring processor)\n";
+ return MCSchedModel::GetDefaultSchedModel();
+ }
+ assert(CPUEntry->SchedModel && "Missing processor SchedModel value");
+ return *CPUEntry->SchedModel;
+}
+
+InstrItineraryData
+MCSubtargetInfo::getInstrItineraryForCPU(StringRef CPU) const {
+ const MCSchedModel &SchedModel = getSchedModelForCPU(CPU);
+ return InstrItineraryData(SchedModel, Stages, OperandCycles, ForwardingPaths);
+}
+
+void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const {
+ InstrItins = InstrItineraryData(getSchedModel(), Stages, OperandCycles,
+ ForwardingPaths);
+}
+
+Optional<unsigned> MCSubtargetInfo::getCacheSize(unsigned Level) const {
+ return Optional<unsigned>();
+}
+
+Optional<unsigned>
+MCSubtargetInfo::getCacheAssociativity(unsigned Level) const {
+ return Optional<unsigned>();
+}
+
+Optional<unsigned> MCSubtargetInfo::getCacheLineSize(unsigned Level) const {
+ return Optional<unsigned>();
+}
+
+unsigned MCSubtargetInfo::getPrefetchDistance() const {
+ return 0;
+}
+
+unsigned MCSubtargetInfo::getMaxPrefetchIterationsAhead() const {
+ return UINT_MAX;
+}
+
+unsigned MCSubtargetInfo::getMinPrefetchStride() const {
+ return 1;
+}
diff --git a/llvm/lib/MC/MCSymbol.cpp b/llvm/lib/MC/MCSymbol.cpp
new file mode 100644
index 000000000000..67cab9a92722
--- /dev/null
+++ b/llvm/lib/MC/MCSymbol.cpp
@@ -0,0 +1,88 @@
+//===- lib/MC/MCSymbol.cpp - MCSymbol implementation ----------------------===//
+//
+// 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/MCSymbol.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstddef>
+
+using namespace llvm;
+
+// Only the address of this fragment is ever actually used.
+static MCDummyFragment SentinelFragment(nullptr);
+
+// Sentinel value for the absolute pseudo fragment.
+MCFragment *MCSymbol::AbsolutePseudoFragment = &SentinelFragment;
+
+void *MCSymbol::operator new(size_t s, const StringMapEntry<bool> *Name,
+ MCContext &Ctx) {
+ // We may need more space for a Name to account for alignment. So allocate
+ // space for the storage type and not the name pointer.
+ size_t Size = s + (Name ? sizeof(NameEntryStorageTy) : 0);
+
+ // For safety, ensure that the alignment of a pointer is enough for an
+ // MCSymbol. This also ensures we don't need padding between the name and
+ // symbol.
+ static_assert((unsigned)alignof(MCSymbol) <= alignof(NameEntryStorageTy),
+ "Bad alignment of MCSymbol");
+ void *Storage = Ctx.allocate(Size, alignof(NameEntryStorageTy));
+ NameEntryStorageTy *Start = static_cast<NameEntryStorageTy*>(Storage);
+ NameEntryStorageTy *End = Start + (Name ? 1 : 0);
+ return End;
+}
+
+void MCSymbol::setVariableValue(const MCExpr *Value) {
+ assert(!IsUsed && "Cannot set a variable that has already been used.");
+ assert(Value && "Invalid variable value!");
+ assert((SymbolContents == SymContentsUnset ||
+ SymbolContents == SymContentsVariable) &&
+ "Cannot give common/offset symbol a variable value");
+ this->Value = Value;
+ SymbolContents = SymContentsVariable;
+ setUndefined();
+}
+
+void MCSymbol::print(raw_ostream &OS, const MCAsmInfo *MAI) const {
+ // The name for this MCSymbol is required to be a valid target name. However,
+ // some targets support quoting names with funny characters. If the name
+ // contains a funny character, then print it quoted.
+ StringRef Name = getName();
+ if (!MAI || MAI->isValidUnquotedName(Name)) {
+ OS << Name;
+ return;
+ }
+
+ if (MAI && !MAI->supportsNameQuoting())
+ report_fatal_error("Symbol name with unsupported characters");
+
+ OS << '"';
+ for (char C : Name) {
+ if (C == '\n')
+ OS << "\\n";
+ else if (C == '"')
+ OS << "\\\"";
+ else
+ OS << C;
+ }
+ OS << '"';
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCSymbol::dump() const {
+ dbgs() << *this;
+}
+#endif
diff --git a/llvm/lib/MC/MCSymbolELF.cpp b/llvm/lib/MC/MCSymbolELF.cpp
new file mode 100644
index 000000000000..a07c56c64f84
--- /dev/null
+++ b/llvm/lib/MC/MCSymbolELF.cpp
@@ -0,0 +1,201 @@
+//===- lib/MC/MCSymbolELF.cpp ---------------------------------------------===//
+//
+// 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/MCSymbolELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+
+namespace llvm {
+
+namespace {
+enum {
+ // Shift value for STT_* flags. 7 possible values. 3 bits.
+ ELF_STT_Shift = 0,
+
+ // Shift value for STB_* flags. 4 possible values, 2 bits.
+ ELF_STB_Shift = 3,
+
+ // Shift value for STV_* flags. 4 possible values, 2 bits.
+ ELF_STV_Shift = 5,
+
+ // Shift value for STO_* flags. 3 bits. All the values are between 0x20 and
+ // 0xe0, so we shift right by 5 before storing.
+ ELF_STO_Shift = 7,
+
+ // One bit.
+ ELF_IsSignature_Shift = 10,
+
+ // One bit.
+ ELF_WeakrefUsedInReloc_Shift = 11,
+
+ // One bit.
+ ELF_BindingSet_Shift = 12
+};
+}
+
+void MCSymbolELF::setBinding(unsigned Binding) const {
+ setIsBindingSet();
+ if (getType() == ELF::STT_SECTION && Binding != ELF::STB_LOCAL)
+ setType(ELF::STT_NOTYPE);
+ unsigned Val;
+ switch (Binding) {
+ default:
+ llvm_unreachable("Unsupported Binding");
+ case ELF::STB_LOCAL:
+ Val = 0;
+ break;
+ case ELF::STB_GLOBAL:
+ Val = 1;
+ break;
+ case ELF::STB_WEAK:
+ Val = 2;
+ break;
+ case ELF::STB_GNU_UNIQUE:
+ Val = 3;
+ break;
+ }
+ uint32_t OtherFlags = getFlags() & ~(0x3 << ELF_STB_Shift);
+ setFlags(OtherFlags | (Val << ELF_STB_Shift));
+}
+
+unsigned MCSymbolELF::getBinding() const {
+ if (isBindingSet()) {
+ uint32_t Val = (Flags >> ELF_STB_Shift) & 3;
+ switch (Val) {
+ default:
+ llvm_unreachable("Invalid value");
+ case 0:
+ return ELF::STB_LOCAL;
+ case 1:
+ return ELF::STB_GLOBAL;
+ case 2:
+ return ELF::STB_WEAK;
+ case 3:
+ return ELF::STB_GNU_UNIQUE;
+ }
+ }
+
+ if (isDefined())
+ return ELF::STB_LOCAL;
+ if (isUsedInReloc())
+ return ELF::STB_GLOBAL;
+ if (isWeakrefUsedInReloc())
+ return ELF::STB_WEAK;
+ if (isSignature())
+ return ELF::STB_LOCAL;
+ return ELF::STB_GLOBAL;
+}
+
+void MCSymbolELF::setType(unsigned Type) const {
+ unsigned Val;
+ if (Type == ELF::STT_SECTION && getBinding() != ELF::STB_LOCAL)
+ return;
+ switch (Type) {
+ default:
+ llvm_unreachable("Unsupported Binding");
+ case ELF::STT_NOTYPE:
+ Val = 0;
+ break;
+ case ELF::STT_OBJECT:
+ Val = 1;
+ break;
+ case ELF::STT_FUNC:
+ Val = 2;
+ break;
+ case ELF::STT_SECTION:
+ Val = 3;
+ break;
+ case ELF::STT_COMMON:
+ Val = 4;
+ break;
+ case ELF::STT_TLS:
+ Val = 5;
+ break;
+ case ELF::STT_GNU_IFUNC:
+ Val = 6;
+ break;
+ }
+ uint32_t OtherFlags = getFlags() & ~(0x7 << ELF_STT_Shift);
+ setFlags(OtherFlags | (Val << ELF_STT_Shift));
+}
+
+unsigned MCSymbolELF::getType() const {
+ uint32_t Val = (Flags >> ELF_STT_Shift) & 7;
+ switch (Val) {
+ default:
+ llvm_unreachable("Invalid value");
+ case 0:
+ return ELF::STT_NOTYPE;
+ case 1:
+ return ELF::STT_OBJECT;
+ case 2:
+ return ELF::STT_FUNC;
+ case 3:
+ return ELF::STT_SECTION;
+ case 4:
+ return ELF::STT_COMMON;
+ case 5:
+ return ELF::STT_TLS;
+ case 6:
+ return ELF::STT_GNU_IFUNC;
+ }
+}
+
+void MCSymbolELF::setVisibility(unsigned Visibility) {
+ assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL ||
+ Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED);
+
+ uint32_t OtherFlags = getFlags() & ~(0x3 << ELF_STV_Shift);
+ setFlags(OtherFlags | (Visibility << ELF_STV_Shift));
+}
+
+unsigned MCSymbolELF::getVisibility() const {
+ unsigned Visibility = (Flags >> ELF_STV_Shift) & 3;
+ return Visibility;
+}
+
+void MCSymbolELF::setOther(unsigned Other) {
+ assert((Other & 0x1f) == 0);
+ Other >>= 5;
+ assert(Other <= 0x7);
+ uint32_t OtherFlags = getFlags() & ~(0x7 << ELF_STO_Shift);
+ setFlags(OtherFlags | (Other << ELF_STO_Shift));
+}
+
+unsigned MCSymbolELF::getOther() const {
+ unsigned Other = (Flags >> ELF_STO_Shift) & 7;
+ return Other << 5;
+}
+
+void MCSymbolELF::setIsWeakrefUsedInReloc() const {
+ uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_WeakrefUsedInReloc_Shift);
+ setFlags(OtherFlags | (1 << ELF_WeakrefUsedInReloc_Shift));
+}
+
+bool MCSymbolELF::isWeakrefUsedInReloc() const {
+ return getFlags() & (0x1 << ELF_WeakrefUsedInReloc_Shift);
+}
+
+void MCSymbolELF::setIsSignature() const {
+ uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_IsSignature_Shift);
+ setFlags(OtherFlags | (1 << ELF_IsSignature_Shift));
+}
+
+bool MCSymbolELF::isSignature() const {
+ return getFlags() & (0x1 << ELF_IsSignature_Shift);
+}
+
+void MCSymbolELF::setIsBindingSet() const {
+ uint32_t OtherFlags = getFlags() & ~(0x1 << ELF_BindingSet_Shift);
+ setFlags(OtherFlags | (1 << ELF_BindingSet_Shift));
+}
+
+bool MCSymbolELF::isBindingSet() const {
+ return getFlags() & (0x1 << ELF_BindingSet_Shift);
+}
+}
diff --git a/llvm/lib/MC/MCTargetOptions.cpp b/llvm/lib/MC/MCTargetOptions.cpp
new file mode 100644
index 000000000000..96bb094134fe
--- /dev/null
+++ b/llvm/lib/MC/MCTargetOptions.cpp
@@ -0,0 +1,23 @@
+//===- lib/MC/MCTargetOptions.cpp - MC Target Options ---------------------===//
+//
+// 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/MCTargetOptions.h"
+#include "llvm/ADT/StringRef.h"
+
+using namespace llvm;
+
+MCTargetOptions::MCTargetOptions()
+ : MCRelaxAll(false), MCNoExecStack(false), MCFatalWarnings(false),
+ MCNoWarn(false), MCNoDeprecatedWarn(false), MCSaveTempLabels(false),
+ MCUseDwarfDirectory(false), MCIncrementalLinkerCompatible(false),
+ MCPIECopyRelocations(false), ShowMCEncoding(false), ShowMCInst(false),
+ AsmVerbose(false), PreserveAsmComments(true) {}
+
+StringRef MCTargetOptions::getABIName() const {
+ return ABIName;
+}
diff --git a/llvm/lib/MC/MCValue.cpp b/llvm/lib/MC/MCValue.cpp
new file mode 100644
index 000000000000..81da47b2eced
--- /dev/null
+++ b/llvm/lib/MC/MCValue.cpp
@@ -0,0 +1,61 @@
+//===- lib/MC/MCValue.cpp - MCValue implementation ------------------------===//
+//
+// 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/MCValue.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void MCValue::print(raw_ostream &OS) const {
+ if (isAbsolute()) {
+ OS << getConstant();
+ return;
+ }
+
+ // FIXME: prints as a number, which isn't ideal. But the meaning will be
+ // target-specific anyway.
+ if (getRefKind())
+ OS << ':' << getRefKind() << ':';
+
+ OS << *getSymA();
+
+ if (getSymB()) {
+ OS << " - ";
+ OS << *getSymB();
+ }
+
+ if (getConstant())
+ OS << " + " << getConstant();
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void MCValue::dump() const {
+ print(dbgs());
+}
+#endif
+
+MCSymbolRefExpr::VariantKind MCValue::getAccessVariant() const {
+ const MCSymbolRefExpr *B = getSymB();
+ if (B) {
+ if (B->getKind() != MCSymbolRefExpr::VK_None)
+ llvm_unreachable("unsupported");
+ }
+
+ const MCSymbolRefExpr *A = getSymA();
+ if (!A)
+ return MCSymbolRefExpr::VK_None;
+
+ MCSymbolRefExpr::VariantKind Kind = A->getKind();
+ if (Kind == MCSymbolRefExpr::VK_WEAKREF)
+ return MCSymbolRefExpr::VK_None;
+ return Kind;
+}
diff --git a/llvm/lib/MC/MCWasmObjectTargetWriter.cpp b/llvm/lib/MC/MCWasmObjectTargetWriter.cpp
new file mode 100644
index 000000000000..1ccb3a58d5c1
--- /dev/null
+++ b/llvm/lib/MC/MCWasmObjectTargetWriter.cpp
@@ -0,0 +1,18 @@
+//===-- MCWasmObjectTargetWriter.cpp - Wasm Target Writer Subclass --------===//
+//
+// 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/MCWasmObjectWriter.h"
+
+using namespace llvm;
+
+MCWasmObjectTargetWriter::MCWasmObjectTargetWriter(bool Is64Bit,
+ bool IsEmscripten)
+ : Is64Bit(Is64Bit), IsEmscripten(IsEmscripten) {}
+
+// Pin the vtable to this object file
+MCWasmObjectTargetWriter::~MCWasmObjectTargetWriter() = default;
diff --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp
new file mode 100644
index 000000000000..e7e96ecbb3a0
--- /dev/null
+++ b/llvm/lib/MC/MCWasmStreamer.cpp
@@ -0,0 +1,229 @@
+//===- lib/MC/MCWasmStreamer.cpp - Wasm 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 Wasm .o object files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCWasmStreamer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+MCWasmStreamer::~MCWasmStreamer() = default; // anchor.
+
+void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) {
+ 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 MCWasmStreamer::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.
+ llvm_unreachable("invalid assembler flag!");
+}
+
+void MCWasmStreamer::ChangeSection(MCSection *Section,
+ const MCExpr *Subsection) {
+ MCAssembler &Asm = getAssembler();
+ auto *SectionWasm = cast<MCSectionWasm>(Section);
+ const MCSymbol *Grp = SectionWasm->getGroup();
+ if (Grp)
+ Asm.registerSymbol(*Grp);
+
+ this->MCObjectStreamer::ChangeSection(Section, Subsection);
+ Asm.registerSymbol(*Section->getBeginSymbol());
+}
+
+void MCWasmStreamer::EmitWeakReference(MCSymbol *Alias,
+ const MCSymbol *Symbol) {
+ getAssembler().registerSymbol(*Symbol);
+ const MCExpr *Value = MCSymbolRefExpr::create(
+ Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext());
+ Alias->setVariableValue(Value);
+}
+
+bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
+ assert(Attribute != MCSA_IndirectSymbol && "indirect symbols not supported");
+
+ auto *Symbol = cast<MCSymbolWasm>(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);
+
+ switch (Attribute) {
+ 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_Protected:
+ return false;
+
+ case MCSA_Hidden:
+ Symbol->setHidden(true);
+ break;
+
+ case MCSA_Weak:
+ case MCSA_WeakReference:
+ Symbol->setWeak(true);
+ Symbol->setExternal(true);
+ break;
+
+ case MCSA_Global:
+ Symbol->setExternal(true);
+ break;
+
+ case MCSA_ELF_TypeFunction:
+ Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ break;
+
+ case MCSA_ELF_TypeObject:
+ case MCSA_Cold:
+ break;
+
+ case MCSA_NoDeadStrip:
+ Symbol->setNoStrip();
+ break;
+
+ default:
+ // unrecognized directive
+ llvm_unreachable("unexpected MCSymbolAttr");
+ return false;
+ }
+
+ return true;
+}
+
+void MCWasmStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size,
+ unsigned ByteAlignment) {
+ llvm_unreachable("Common symbols are not yet implemented for Wasm");
+}
+
+void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
+ cast<MCSymbolWasm>(Symbol)->setSize(Value);
+}
+
+void MCWasmStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
+ unsigned ByteAlignment) {
+ llvm_unreachable("Local common symbols are not yet implemented for Wasm");
+}
+
+void MCWasmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size,
+ SMLoc Loc) {
+ MCObjectStreamer::EmitValueImpl(Value, Size, Loc);
+}
+
+void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value,
+ unsigned ValueSize,
+ unsigned MaxBytesToEmit) {
+ MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, ValueSize,
+ MaxBytesToEmit);
+}
+
+void MCWasmStreamer::EmitIdent(StringRef IdentString) {
+ // TODO(sbc): Add the ident section once we support mergable strings
+ // sections in the object format
+}
+
+void MCWasmStreamer::EmitInstToFragment(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ this->MCObjectStreamer::EmitInstToFragment(Inst, STI);
+}
+
+void MCWasmStreamer::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);
+
+ // Append the encoded instruction to the current data fragment (or create a
+ // new such fragment if the current fragment is not a data fragment).
+ MCDataFragment *DF = getOrCreateDataFragment();
+
+ // Add the fixups and data.
+ for (unsigned I = 0, E = Fixups.size(); I != E; ++I) {
+ Fixups[I].setOffset(Fixups[I].getOffset() + DF->getContents().size());
+ DF->getFixups().push_back(Fixups[I]);
+ }
+ DF->setHasInstructions(STI);
+ DF->getContents().append(Code.begin(), Code.end());
+}
+
+void MCWasmStreamer::FinishImpl() {
+ EmitFrames(nullptr);
+
+ this->MCObjectStreamer::FinishImpl();
+}
+
+MCStreamer *llvm::createWasmStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> &&MAB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ bool RelaxAll) {
+ MCWasmStreamer *S =
+ new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE));
+ if (RelaxAll)
+ S->getAssembler().setRelaxAll(true);
+ return S;
+}
+
+void MCWasmStreamer::EmitThumbFunc(MCSymbol *Func) {
+ llvm_unreachable("Generic Wasm doesn't support this directive");
+}
+
+void MCWasmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
+ llvm_unreachable("Wasm doesn't support this directive");
+}
+
+void MCWasmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment,
+ SMLoc Loc) {
+ llvm_unreachable("Wasm doesn't support this directive");
+}
+
+void MCWasmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ llvm_unreachable("Wasm doesn't support this directive");
+}
diff --git a/llvm/lib/MC/MCWin64EH.cpp b/llvm/lib/MC/MCWin64EH.cpp
new file mode 100644
index 000000000000..4e9a29667097
--- /dev/null
+++ b/llvm/lib/MC/MCWin64EH.cpp
@@ -0,0 +1,680 @@
+//===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===//
+//
+// 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/MCWin64EH.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Win64EH.h"
+
+using namespace llvm;
+
+// NOTE: All relocations generated here are 4-byte image-relative.
+
+static uint8_t CountOfUnwindCodes(std::vector<WinEH::Instruction> &Insns) {
+ uint8_t Count = 0;
+ for (const auto &I : Insns) {
+ switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
+ default:
+ llvm_unreachable("Unsupported unwind code");
+ case Win64EH::UOP_PushNonVol:
+ case Win64EH::UOP_AllocSmall:
+ case Win64EH::UOP_SetFPReg:
+ case Win64EH::UOP_PushMachFrame:
+ Count += 1;
+ break;
+ case Win64EH::UOP_SaveNonVol:
+ case Win64EH::UOP_SaveXMM128:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveNonVolBig:
+ case Win64EH::UOP_SaveXMM128Big:
+ Count += 3;
+ break;
+ case Win64EH::UOP_AllocLarge:
+ Count += (I.Offset > 512 * 1024 - 8) ? 3 : 2;
+ break;
+ }
+ }
+ return Count;
+}
+
+static void EmitAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
+ const MCSymbol *RHS) {
+ MCContext &Context = Streamer.getContext();
+ const MCExpr *Diff =
+ MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
+ MCSymbolRefExpr::create(RHS, Context), Context);
+ Streamer.EmitValue(Diff, 1);
+}
+
+static void EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
+ WinEH::Instruction &inst) {
+ uint8_t b2;
+ uint16_t w;
+ b2 = (inst.Operation & 0x0F);
+ switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
+ default:
+ llvm_unreachable("Unsupported unwind code");
+ case Win64EH::UOP_PushNonVol:
+ EmitAbsDifference(streamer, inst.Label, begin);
+ b2 |= (inst.Register & 0x0F) << 4;
+ streamer.EmitIntValue(b2, 1);
+ break;
+ case Win64EH::UOP_AllocLarge:
+ EmitAbsDifference(streamer, inst.Label, begin);
+ if (inst.Offset > 512 * 1024 - 8) {
+ b2 |= 0x10;
+ streamer.EmitIntValue(b2, 1);
+ w = inst.Offset & 0xFFF8;
+ streamer.EmitIntValue(w, 2);
+ w = inst.Offset >> 16;
+ } else {
+ streamer.EmitIntValue(b2, 1);
+ w = inst.Offset >> 3;
+ }
+ streamer.EmitIntValue(w, 2);
+ break;
+ case Win64EH::UOP_AllocSmall:
+ b2 |= (((inst.Offset - 8) >> 3) & 0x0F) << 4;
+ EmitAbsDifference(streamer, inst.Label, begin);
+ streamer.EmitIntValue(b2, 1);
+ break;
+ case Win64EH::UOP_SetFPReg:
+ EmitAbsDifference(streamer, inst.Label, begin);
+ streamer.EmitIntValue(b2, 1);
+ break;
+ case Win64EH::UOP_SaveNonVol:
+ case Win64EH::UOP_SaveXMM128:
+ b2 |= (inst.Register & 0x0F) << 4;
+ EmitAbsDifference(streamer, inst.Label, begin);
+ streamer.EmitIntValue(b2, 1);
+ w = inst.Offset >> 3;
+ if (inst.Operation == Win64EH::UOP_SaveXMM128)
+ w >>= 1;
+ streamer.EmitIntValue(w, 2);
+ break;
+ case Win64EH::UOP_SaveNonVolBig:
+ case Win64EH::UOP_SaveXMM128Big:
+ b2 |= (inst.Register & 0x0F) << 4;
+ EmitAbsDifference(streamer, inst.Label, begin);
+ streamer.EmitIntValue(b2, 1);
+ if (inst.Operation == Win64EH::UOP_SaveXMM128Big)
+ w = inst.Offset & 0xFFF0;
+ else
+ w = inst.Offset & 0xFFF8;
+ streamer.EmitIntValue(w, 2);
+ w = inst.Offset >> 16;
+ streamer.EmitIntValue(w, 2);
+ break;
+ case Win64EH::UOP_PushMachFrame:
+ if (inst.Offset == 1)
+ b2 |= 0x10;
+ EmitAbsDifference(streamer, inst.Label, begin);
+ streamer.EmitIntValue(b2, 1);
+ break;
+ }
+}
+
+static void EmitSymbolRefWithOfs(MCStreamer &streamer,
+ const MCSymbol *Base,
+ const MCSymbol *Other) {
+ MCContext &Context = streamer.getContext();
+ const MCSymbolRefExpr *BaseRef = MCSymbolRefExpr::create(Base, Context);
+ const MCSymbolRefExpr *OtherRef = MCSymbolRefExpr::create(Other, Context);
+ const MCExpr *Ofs = MCBinaryExpr::createSub(OtherRef, BaseRef, Context);
+ const MCSymbolRefExpr *BaseRefRel = MCSymbolRefExpr::create(Base,
+ MCSymbolRefExpr::VK_COFF_IMGREL32,
+ Context);
+ streamer.EmitValue(MCBinaryExpr::createAdd(BaseRefRel, Ofs, Context), 4);
+}
+
+static void EmitRuntimeFunction(MCStreamer &streamer,
+ const WinEH::FrameInfo *info) {
+ MCContext &context = streamer.getContext();
+
+ streamer.EmitValueToAlignment(4);
+ EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
+ EmitSymbolRefWithOfs(streamer, info->Function, info->End);
+ streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol,
+ MCSymbolRefExpr::VK_COFF_IMGREL32,
+ context), 4);
+}
+
+static void EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
+ // If this UNWIND_INFO already has a symbol, it's already been emitted.
+ if (info->Symbol)
+ return;
+
+ MCContext &context = streamer.getContext();
+ MCSymbol *Label = context.createTempSymbol();
+
+ streamer.EmitValueToAlignment(4);
+ streamer.EmitLabel(Label);
+ info->Symbol = Label;
+
+ // Upper 3 bits are the version number (currently 1).
+ uint8_t flags = 0x01;
+ if (info->ChainedParent)
+ flags |= Win64EH::UNW_ChainInfo << 3;
+ else {
+ if (info->HandlesUnwind)
+ flags |= Win64EH::UNW_TerminateHandler << 3;
+ if (info->HandlesExceptions)
+ flags |= Win64EH::UNW_ExceptionHandler << 3;
+ }
+ streamer.EmitIntValue(flags, 1);
+
+ if (info->PrologEnd)
+ EmitAbsDifference(streamer, info->PrologEnd, info->Begin);
+ else
+ streamer.EmitIntValue(0, 1);
+
+ uint8_t numCodes = CountOfUnwindCodes(info->Instructions);
+ streamer.EmitIntValue(numCodes, 1);
+
+ uint8_t frame = 0;
+ if (info->LastFrameInst >= 0) {
+ WinEH::Instruction &frameInst = info->Instructions[info->LastFrameInst];
+ assert(frameInst.Operation == Win64EH::UOP_SetFPReg);
+ frame = (frameInst.Register & 0x0F) | (frameInst.Offset & 0xF0);
+ }
+ streamer.EmitIntValue(frame, 1);
+
+ // Emit unwind instructions (in reverse order).
+ uint8_t numInst = info->Instructions.size();
+ for (uint8_t c = 0; c < numInst; ++c) {
+ WinEH::Instruction inst = info->Instructions.back();
+ info->Instructions.pop_back();
+ EmitUnwindCode(streamer, info->Begin, inst);
+ }
+
+ // For alignment purposes, the instruction array will always have an even
+ // number of entries, with the final entry potentially unused (in which case
+ // the array will be one longer than indicated by the count of unwind codes
+ // field).
+ if (numCodes & 1) {
+ streamer.EmitIntValue(0, 2);
+ }
+
+ if (flags & (Win64EH::UNW_ChainInfo << 3))
+ EmitRuntimeFunction(streamer, info->ChainedParent);
+ else if (flags &
+ ((Win64EH::UNW_TerminateHandler|Win64EH::UNW_ExceptionHandler) << 3))
+ streamer.EmitValue(MCSymbolRefExpr::create(info->ExceptionHandler,
+ MCSymbolRefExpr::VK_COFF_IMGREL32,
+ context), 4);
+ else if (numCodes == 0) {
+ // The minimum size of an UNWIND_INFO struct is 8 bytes. If we're not
+ // a chained unwind info, if there is no handler, and if there are fewer
+ // than 2 slots used in the unwind code array, we have to pad to 8 bytes.
+ streamer.EmitIntValue(0, 4);
+ }
+}
+
+void llvm::Win64EH::UnwindEmitter::Emit(MCStreamer &Streamer) const {
+ // Emit the unwind info structs first.
+ for (const auto &CFI : Streamer.getWinFrameInfos()) {
+ MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
+ Streamer.SwitchSection(XData);
+ ::EmitUnwindInfo(Streamer, CFI.get());
+ }
+
+ // Now emit RUNTIME_FUNCTION entries.
+ for (const auto &CFI : Streamer.getWinFrameInfos()) {
+ MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
+ Streamer.SwitchSection(PData);
+ EmitRuntimeFunction(Streamer, CFI.get());
+ }
+}
+
+void llvm::Win64EH::UnwindEmitter::EmitUnwindInfo(
+ MCStreamer &Streamer, WinEH::FrameInfo *info) const {
+ // Switch sections (the static function above is meant to be called from
+ // here and from Emit().
+ MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
+ Streamer.SwitchSection(XData);
+
+ ::EmitUnwindInfo(Streamer, info);
+}
+
+static int64_t GetAbsDifference(MCStreamer &Streamer, const MCSymbol *LHS,
+ const MCSymbol *RHS) {
+ MCContext &Context = Streamer.getContext();
+ const MCExpr *Diff =
+ MCBinaryExpr::createSub(MCSymbolRefExpr::create(LHS, Context),
+ MCSymbolRefExpr::create(RHS, Context), Context);
+ MCObjectStreamer *OS = (MCObjectStreamer *)(&Streamer);
+ // It should normally be possible to calculate the length of a function
+ // at this point, but it might not be possible in the presence of certain
+ // unusual constructs, like an inline asm with an alignment directive.
+ int64_t value;
+ if (!Diff->evaluateAsAbsolute(value, OS->getAssembler()))
+ report_fatal_error("Failed to evaluate function length in SEH unwind info");
+ return value;
+}
+
+static uint32_t
+ARM64CountOfUnwindCodes(const std::vector<WinEH::Instruction> &Insns) {
+ uint32_t Count = 0;
+ for (const auto &I : Insns) {
+ switch (static_cast<Win64EH::UnwindOpcodes>(I.Operation)) {
+ default:
+ llvm_unreachable("Unsupported ARM64 unwind code");
+ case Win64EH::UOP_AllocSmall:
+ Count += 1;
+ break;
+ case Win64EH::UOP_AllocMedium:
+ Count += 2;
+ break;
+ case Win64EH::UOP_AllocLarge:
+ Count += 4;
+ break;
+ case Win64EH::UOP_SaveFPLRX:
+ Count += 1;
+ break;
+ case Win64EH::UOP_SaveFPLR:
+ Count += 1;
+ break;
+ case Win64EH::UOP_SaveReg:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveRegP:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveRegPX:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveRegX:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveFReg:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveFRegP:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveFRegX:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SaveFRegPX:
+ Count += 2;
+ break;
+ case Win64EH::UOP_SetFP:
+ Count += 1;
+ break;
+ case Win64EH::UOP_AddFP:
+ Count += 2;
+ break;
+ case Win64EH::UOP_Nop:
+ Count += 1;
+ break;
+ case Win64EH::UOP_End:
+ Count += 1;
+ break;
+ }
+ }
+ return Count;
+}
+
+// Unwind opcode encodings and restrictions are documented at
+// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
+static void ARM64EmitUnwindCode(MCStreamer &streamer, const MCSymbol *begin,
+ WinEH::Instruction &inst) {
+ uint8_t b, reg;
+ switch (static_cast<Win64EH::UnwindOpcodes>(inst.Operation)) {
+ default:
+ llvm_unreachable("Unsupported ARM64 unwind code");
+ case Win64EH::UOP_AllocSmall:
+ b = (inst.Offset >> 4) & 0x1F;
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_AllocMedium: {
+ uint16_t hw = (inst.Offset >> 4) & 0x7FF;
+ b = 0xC0;
+ b |= (hw >> 8);
+ streamer.EmitIntValue(b, 1);
+ b = hw & 0xFF;
+ streamer.EmitIntValue(b, 1);
+ break;
+ }
+ case Win64EH::UOP_AllocLarge: {
+ uint32_t w;
+ b = 0xE0;
+ streamer.EmitIntValue(b, 1);
+ w = inst.Offset >> 4;
+ b = (w & 0x00FF0000) >> 16;
+ streamer.EmitIntValue(b, 1);
+ b = (w & 0x0000FF00) >> 8;
+ streamer.EmitIntValue(b, 1);
+ b = w & 0x000000FF;
+ streamer.EmitIntValue(b, 1);
+ break;
+ }
+ case Win64EH::UOP_SetFP:
+ b = 0xE1;
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_AddFP:
+ b = 0xE2;
+ streamer.EmitIntValue(b, 1);
+ b = (inst.Offset >> 3);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_Nop:
+ b = 0xE3;
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveFPLRX:
+ b = 0x80;
+ b |= ((inst.Offset - 1) >> 3) & 0x3F;
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveFPLR:
+ b = 0x40;
+ b |= (inst.Offset >> 3) & 0x3F;
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveReg:
+ assert(inst.Register >= 19 && "Saved reg must be >= 19");
+ reg = inst.Register - 19;
+ b = 0xD0 | ((reg & 0xC) >> 2);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveRegX:
+ assert(inst.Register >= 19 && "Saved reg must be >= 19");
+ reg = inst.Register - 19;
+ b = 0xD4 | ((reg & 0x8) >> 3);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveRegP:
+ assert(inst.Register >= 19 && "Saved registers must be >= 19");
+ reg = inst.Register - 19;
+ b = 0xC8 | ((reg & 0xC) >> 2);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveRegPX:
+ assert(inst.Register >= 19 && "Saved registers must be >= 19");
+ reg = inst.Register - 19;
+ b = 0xCC | ((reg & 0xC) >> 2);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveFReg:
+ assert(inst.Register >= 8 && "Saved dreg must be >= 8");
+ reg = inst.Register - 8;
+ b = 0xDC | ((reg & 0x4) >> 2);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveFRegX:
+ assert(inst.Register >= 8 && "Saved dreg must be >= 8");
+ reg = inst.Register - 8;
+ b = 0xDE;
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x7) << 5) | ((inst.Offset >> 3) - 1);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveFRegP:
+ assert(inst.Register >= 8 && "Saved dregs must be >= 8");
+ reg = inst.Register - 8;
+ b = 0xD8 | ((reg & 0x4) >> 2);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x3) << 6) | (inst.Offset >> 3);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_SaveFRegPX:
+ assert(inst.Register >= 8 && "Saved dregs must be >= 8");
+ reg = inst.Register - 8;
+ b = 0xDA | ((reg & 0x4) >> 2);
+ streamer.EmitIntValue(b, 1);
+ b = ((reg & 0x3) << 6) | ((inst.Offset >> 3) - 1);
+ streamer.EmitIntValue(b, 1);
+ break;
+ case Win64EH::UOP_End:
+ b = 0xE4;
+ streamer.EmitIntValue(b, 1);
+ break;
+ }
+}
+
+// Returns the epilog symbol of an epilog with the exact same unwind code
+// sequence, if it exists. Otherwise, returns nulltpr.
+// EpilogInstrs - Unwind codes for the current epilog.
+// Epilogs - Epilogs that potentialy match the current epilog.
+static MCSymbol*
+FindMatchingEpilog(const std::vector<WinEH::Instruction>& EpilogInstrs,
+ const std::vector<MCSymbol *>& Epilogs,
+ const WinEH::FrameInfo *info) {
+ for (auto *EpilogStart : Epilogs) {
+ auto InstrsIter = info->EpilogMap.find(EpilogStart);
+ assert(InstrsIter != info->EpilogMap.end() &&
+ "Epilog not found in EpilogMap");
+ const auto &Instrs = InstrsIter->second;
+
+ if (Instrs.size() != EpilogInstrs.size())
+ continue;
+
+ bool Match = true;
+ for (unsigned i = 0; i < Instrs.size(); ++i)
+ if (Instrs[i].Operation != EpilogInstrs[i].Operation ||
+ Instrs[i].Offset != EpilogInstrs[i].Offset ||
+ Instrs[i].Register != EpilogInstrs[i].Register) {
+ Match = false;
+ break;
+ }
+
+ if (Match)
+ return EpilogStart;
+ }
+ return nullptr;
+}
+
+// Populate the .xdata section. The format of .xdata on ARM64 is documented at
+// https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling
+static void ARM64EmitUnwindInfo(MCStreamer &streamer, WinEH::FrameInfo *info) {
+ // If this UNWIND_INFO already has a symbol, it's already been emitted.
+ if (info->Symbol)
+ return;
+
+ MCContext &context = streamer.getContext();
+ MCSymbol *Label = context.createTempSymbol();
+
+ streamer.EmitValueToAlignment(4);
+ streamer.EmitLabel(Label);
+ info->Symbol = Label;
+
+ int64_t RawFuncLength;
+ if (!info->FuncletOrFuncEnd) {
+ // FIXME: This is very wrong; we emit SEH data which covers zero bytes
+ // of code. But otherwise test/MC/AArch64/seh.s crashes.
+ RawFuncLength = 0;
+ } else {
+ // FIXME: GetAbsDifference tries to compute the length of the function
+ // immediately, before the whole file is emitted, but in general
+ // that's impossible: the size in bytes of certain assembler directives
+ // like .align and .fill is not known until the whole file is parsed and
+ // relaxations are applied. Currently, GetAbsDifference fails with a fatal
+ // error in that case. (We mostly don't hit this because inline assembly
+ // specifying those directives is rare, and we don't normally try to
+ // align loops on AArch64.)
+ //
+ // There are two potential approaches to delaying the computation. One,
+ // we could emit something like ".word (endfunc-beginfunc)/4+0x10800000",
+ // as long as we have some conservative estimate we could use to prove
+ // that we don't need to split the unwind data. Emitting the constant
+ // is straightforward, but there's no existing code for estimating the
+ // size of the function.
+ //
+ // The other approach would be to use a dedicated, relaxable fragment,
+ // which could grow to accommodate splitting the unwind data if
+ // necessary. This is more straightforward, since it automatically works
+ // without any new infrastructure, and it's consistent with how we handle
+ // relaxation in other contexts. But it would require some refactoring
+ // to move parts of the pdata/xdata emission into the implementation of
+ // a fragment. We could probably continue to encode the unwind codes
+ // here, but we'd have to emit the pdata, the xdata header, and the
+ // epilogue scopes later, since they depend on whether the we need to
+ // split the unwind data.
+ RawFuncLength = GetAbsDifference(streamer, info->FuncletOrFuncEnd,
+ info->Begin);
+ }
+ if (RawFuncLength > 0xFFFFF)
+ report_fatal_error("SEH unwind data splitting not yet implemented");
+ uint32_t FuncLength = (uint32_t)RawFuncLength / 4;
+ uint32_t PrologCodeBytes = ARM64CountOfUnwindCodes(info->Instructions);
+ uint32_t TotalCodeBytes = PrologCodeBytes;
+
+ // Process epilogs.
+ MapVector<MCSymbol *, uint32_t> EpilogInfo;
+ // Epilogs processed so far.
+ std::vector<MCSymbol *> AddedEpilogs;
+
+ for (auto &I : info->EpilogMap) {
+ MCSymbol *EpilogStart = I.first;
+ auto &EpilogInstrs = I.second;
+ uint32_t CodeBytes = ARM64CountOfUnwindCodes(EpilogInstrs);
+
+ MCSymbol* MatchingEpilog =
+ FindMatchingEpilog(EpilogInstrs, AddedEpilogs, info);
+ if (MatchingEpilog) {
+ assert(EpilogInfo.find(MatchingEpilog) != EpilogInfo.end() &&
+ "Duplicate epilog not found");
+ EpilogInfo[EpilogStart] = EpilogInfo.lookup(MatchingEpilog);
+ // Clear the unwind codes in the EpilogMap, so that they don't get output
+ // in the logic below.
+ EpilogInstrs.clear();
+ } else {
+ EpilogInfo[EpilogStart] = TotalCodeBytes;
+ TotalCodeBytes += CodeBytes;
+ AddedEpilogs.push_back(EpilogStart);
+ }
+ }
+
+ // Code Words, Epilog count, E, X, Vers, Function Length
+ uint32_t row1 = 0x0;
+ uint32_t CodeWords = TotalCodeBytes / 4;
+ uint32_t CodeWordsMod = TotalCodeBytes % 4;
+ if (CodeWordsMod)
+ CodeWords++;
+ uint32_t EpilogCount = info->EpilogMap.size();
+ bool ExtensionWord = EpilogCount > 31 || TotalCodeBytes > 124;
+ if (!ExtensionWord) {
+ row1 |= (EpilogCount & 0x1F) << 22;
+ row1 |= (CodeWords & 0x1F) << 27;
+ }
+ // E is always 0 right now, TODO: packed epilog setup
+ if (info->HandlesExceptions) // X
+ row1 |= 1 << 20;
+ row1 |= FuncLength & 0x3FFFF;
+ streamer.EmitIntValue(row1, 4);
+
+ // Extended Code Words, Extended Epilog Count
+ if (ExtensionWord) {
+ // FIXME: We should be able to split unwind info into multiple sections.
+ // FIXME: We should share epilog codes across epilogs, where possible,
+ // which would make this issue show up less frequently.
+ if (CodeWords > 0xFF || EpilogCount > 0xFFFF)
+ report_fatal_error("SEH unwind data splitting not yet implemented");
+ uint32_t row2 = 0x0;
+ row2 |= (CodeWords & 0xFF) << 16;
+ row2 |= (EpilogCount & 0xFFFF);
+ streamer.EmitIntValue(row2, 4);
+ }
+
+ // Epilog Start Index, Epilog Start Offset
+ for (auto &I : EpilogInfo) {
+ MCSymbol *EpilogStart = I.first;
+ uint32_t EpilogIndex = I.second;
+ uint32_t EpilogOffset =
+ (uint32_t)GetAbsDifference(streamer, EpilogStart, info->Begin);
+ if (EpilogOffset)
+ EpilogOffset /= 4;
+ uint32_t row3 = EpilogOffset;
+ row3 |= (EpilogIndex & 0x3FF) << 22;
+ streamer.EmitIntValue(row3, 4);
+ }
+
+ // Emit prolog unwind instructions (in reverse order).
+ uint8_t numInst = info->Instructions.size();
+ for (uint8_t c = 0; c < numInst; ++c) {
+ WinEH::Instruction inst = info->Instructions.back();
+ info->Instructions.pop_back();
+ ARM64EmitUnwindCode(streamer, info->Begin, inst);
+ }
+
+ // Emit epilog unwind instructions
+ for (auto &I : info->EpilogMap) {
+ auto &EpilogInstrs = I.second;
+ for (uint32_t i = 0; i < EpilogInstrs.size(); i++) {
+ WinEH::Instruction inst = EpilogInstrs[i];
+ ARM64EmitUnwindCode(streamer, info->Begin, inst);
+ }
+ }
+
+ int32_t BytesMod = CodeWords * 4 - TotalCodeBytes;
+ assert(BytesMod >= 0);
+ for (int i = 0; i < BytesMod; i++)
+ streamer.EmitIntValue(0xE3, 1);
+
+ if (info->HandlesExceptions)
+ streamer.EmitValue(
+ MCSymbolRefExpr::create(info->ExceptionHandler,
+ MCSymbolRefExpr::VK_COFF_IMGREL32, context),
+ 4);
+}
+
+static void ARM64EmitRuntimeFunction(MCStreamer &streamer,
+ const WinEH::FrameInfo *info) {
+ MCContext &context = streamer.getContext();
+
+ streamer.EmitValueToAlignment(4);
+ EmitSymbolRefWithOfs(streamer, info->Function, info->Begin);
+ streamer.EmitValue(MCSymbolRefExpr::create(info->Symbol,
+ MCSymbolRefExpr::VK_COFF_IMGREL32,
+ context),
+ 4);
+}
+
+void llvm::Win64EH::ARM64UnwindEmitter::Emit(MCStreamer &Streamer) const {
+ // Emit the unwind info structs first.
+ for (const auto &CFI : Streamer.getWinFrameInfos()) {
+ MCSection *XData = Streamer.getAssociatedXDataSection(CFI->TextSection);
+ Streamer.SwitchSection(XData);
+ ARM64EmitUnwindInfo(Streamer, CFI.get());
+ }
+
+ // Now emit RUNTIME_FUNCTION entries.
+ for (const auto &CFI : Streamer.getWinFrameInfos()) {
+ MCSection *PData = Streamer.getAssociatedPDataSection(CFI->TextSection);
+ Streamer.SwitchSection(PData);
+ ARM64EmitRuntimeFunction(Streamer, CFI.get());
+ }
+}
+
+void llvm::Win64EH::ARM64UnwindEmitter::EmitUnwindInfo(
+ MCStreamer &Streamer, WinEH::FrameInfo *info) const {
+ // Switch sections (the static function above is meant to be called from
+ // here and from Emit().
+ MCSection *XData = Streamer.getAssociatedXDataSection(info->TextSection);
+ Streamer.SwitchSection(XData);
+ ARM64EmitUnwindInfo(Streamer, info);
+}
diff --git a/llvm/lib/MC/MCWinCOFFStreamer.cpp b/llvm/lib/MC/MCWinCOFFStreamer.cpp
new file mode 100644
index 000000000000..c5a21312140b
--- /dev/null
+++ b/llvm/lib/MC/MCWinCOFFStreamer.cpp
@@ -0,0 +1,337 @@
+//===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===//
+//
+// 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 contains an implementation of a Windows COFF object file streamer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCAsmBackend.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/MCObjectStreamer.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSymbolCOFF.h"
+#include "llvm/MC/MCWinCOFFStreamer.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "WinCOFFStreamer"
+
+MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> MAB,
+ std::unique_ptr<MCCodeEmitter> CE,
+ std::unique_ptr<MCObjectWriter> OW)
+ : MCObjectStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)),
+ CurSymbol(nullptr) {}
+
+void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ MCDataFragment *DF = getOrCreateDataFragment();
+
+ SmallVector<MCFixup, 4> Fixups;
+ SmallString<256> Code;
+ raw_svector_ostream VecOS(Code);
+ getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
+
+ // Add the fixups and data.
+ for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
+ Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
+ DF->getFixups().push_back(Fixups[i]);
+ }
+ DF->setHasInstructions(STI);
+ DF->getContents().append(Code.begin(), Code.end());
+}
+
+void MCWinCOFFStreamer::InitSections(bool NoExecStack) {
+ // FIXME: this is identical to the ELF one.
+ // This emulates the same behavior of GNU as. This makes it easier
+ // to compare the output as the major sections are in the same order.
+ SwitchSection(getContext().getObjectFileInfo()->getTextSection());
+ EmitCodeAlignment(4);
+
+ SwitchSection(getContext().getObjectFileInfo()->getDataSection());
+ EmitCodeAlignment(4);
+
+ SwitchSection(getContext().getObjectFileInfo()->getBSSSection());
+ EmitCodeAlignment(4);
+
+ SwitchSection(getContext().getObjectFileInfo()->getTextSection());
+}
+
+void MCWinCOFFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) {
+ auto *Symbol = cast<MCSymbolCOFF>(S);
+ MCObjectStreamer::EmitLabel(Symbol, Loc);
+}
+
+void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
+ // Let the target do whatever target specific stuff it needs to do.
+ getAssembler().getBackend().handleAssemblerFlag(Flag);
+
+ switch (Flag) {
+ // None of these require COFF specific handling.
+ case MCAF_SyntaxUnified:
+ case MCAF_Code16:
+ case MCAF_Code32:
+ case MCAF_Code64:
+ break;
+ case MCAF_SubsectionsViaSymbols:
+ llvm_unreachable("COFF doesn't support .subsections_via_symbols");
+ }
+}
+
+void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) {
+ llvm_unreachable("not implemented");
+}
+
+bool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *S,
+ MCSymbolAttr Attribute) {
+ auto *Symbol = cast<MCSymbolCOFF>(S);
+ getAssembler().registerSymbol(*Symbol);
+
+ switch (Attribute) {
+ default: return false;
+ case MCSA_WeakReference:
+ case MCSA_Weak:
+ Symbol->setIsWeakExternal();
+ Symbol->setExternal(true);
+ break;
+ case MCSA_Global:
+ Symbol->setExternal(true);
+ break;
+ case MCSA_AltEntry:
+ llvm_unreachable("COFF doesn't support the .alt_entry attribute");
+ }
+
+ return true;
+}
+
+void MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
+ llvm_unreachable("not implemented");
+}
+
+void MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *S) {
+ auto *Symbol = cast<MCSymbolCOFF>(S);
+ if (CurSymbol)
+ Error("starting a new symbol definition without completing the "
+ "previous one");
+ CurSymbol = Symbol;
+}
+
+void MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {
+ if (!CurSymbol) {
+ Error("storage class specified outside of symbol definition");
+ return;
+ }
+
+ if (StorageClass & ~COFF::SSC_Invalid) {
+ Error("storage class value '" + Twine(StorageClass) +
+ "' out of range");
+ return;
+ }
+
+ getAssembler().registerSymbol(*CurSymbol);
+ cast<MCSymbolCOFF>(CurSymbol)->setClass((uint16_t)StorageClass);
+}
+
+void MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) {
+ if (!CurSymbol) {
+ Error("symbol type specified outside of a symbol definition");
+ return;
+ }
+
+ if (Type & ~0xffff) {
+ Error("type value '" + Twine(Type) + "' out of range");
+ return;
+ }
+
+ getAssembler().registerSymbol(*CurSymbol);
+ cast<MCSymbolCOFF>(CurSymbol)->setType((uint16_t)Type);
+}
+
+void MCWinCOFFStreamer::EndCOFFSymbolDef() {
+ if (!CurSymbol)
+ Error("ending symbol definition without starting one");
+ CurSymbol = nullptr;
+}
+
+void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) {
+ // SafeSEH is a feature specific to 32-bit x86. It does not exist (and is
+ // unnecessary) on all platforms which use table-based exception dispatch.
+ if (getContext().getObjectFileInfo()->getTargetTriple().getArch() !=
+ Triple::x86)
+ return;
+
+ const MCSymbolCOFF *CSymbol = cast<MCSymbolCOFF>(Symbol);
+ if (CSymbol->isSafeSEH())
+ return;
+
+ MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection();
+ getAssembler().registerSection(*SXData);
+ if (SXData->getAlignment() < 4)
+ SXData->setAlignment(Align(4));
+
+ new MCSymbolIdFragment(Symbol, SXData);
+
+ getAssembler().registerSymbol(*Symbol);
+ CSymbol->setIsSafeSEH();
+
+ // The Microsoft linker requires that the symbol type of a handler be
+ // function. Go ahead and oblige it here.
+ CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
+ << COFF::SCT_COMPLEX_TYPE_SHIFT);
+}
+
+void MCWinCOFFStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) {
+ MCSection *Sec = getCurrentSectionOnly();
+ getAssembler().registerSection(*Sec);
+ if (Sec->getAlignment() < 4)
+ Sec->setAlignment(Align(4));
+
+ new MCSymbolIdFragment(Symbol, getCurrentSectionOnly());
+
+ getAssembler().registerSymbol(*Symbol);
+}
+
+void MCWinCOFFStreamer::EmitCOFFSectionIndex(const MCSymbol *Symbol) {
+ visitUsedSymbol(*Symbol);
+ MCDataFragment *DF = getOrCreateDataFragment();
+ const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
+ MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_2);
+ DF->getFixups().push_back(Fixup);
+ DF->getContents().resize(DF->getContents().size() + 2, 0);
+}
+
+void MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol,
+ uint64_t Offset) {
+ visitUsedSymbol(*Symbol);
+ MCDataFragment *DF = getOrCreateDataFragment();
+ // Create Symbol A for the relocation relative reference.
+ const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext());
+ // Add the constant offset, if given.
+ if (Offset)
+ MCE = MCBinaryExpr::createAdd(
+ MCE, MCConstantExpr::create(Offset, getContext()), getContext());
+ // Build the secrel32 relocation.
+ MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_SecRel_4);
+ // Record the relocation.
+ DF->getFixups().push_back(Fixup);
+ // Emit 4 bytes (zeros) to the object file.
+ DF->getContents().resize(DF->getContents().size() + 4, 0);
+}
+
+void MCWinCOFFStreamer::EmitCOFFImgRel32(const MCSymbol *Symbol,
+ int64_t Offset) {
+ visitUsedSymbol(*Symbol);
+ MCDataFragment *DF = getOrCreateDataFragment();
+ // Create Symbol A for the relocation relative reference.
+ const MCExpr *MCE = MCSymbolRefExpr::create(
+ Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, getContext());
+ // Add the constant offset, if given.
+ if (Offset)
+ MCE = MCBinaryExpr::createAdd(
+ MCE, MCConstantExpr::create(Offset, getContext()), getContext());
+ // Build the imgrel relocation.
+ MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_Data_4);
+ // Record the relocation.
+ DF->getFixups().push_back(Fixup);
+ // Emit 4 bytes (zeros) to the object file.
+ DF->getContents().resize(DF->getContents().size() + 4, 0);
+}
+
+void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size,
+ unsigned ByteAlignment) {
+ auto *Symbol = cast<MCSymbolCOFF>(S);
+
+ const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
+ if (T.isWindowsMSVCEnvironment()) {
+ if (ByteAlignment > 32)
+ report_fatal_error("alignment is limited to 32-bytes");
+
+ // Round size up to alignment so that we will honor the alignment request.
+ Size = std::max(Size, static_cast<uint64_t>(ByteAlignment));
+ }
+
+ getAssembler().registerSymbol(*Symbol);
+ Symbol->setExternal(true);
+ Symbol->setCommon(Size, ByteAlignment);
+
+ if (!T.isWindowsMSVCEnvironment() && ByteAlignment > 1) {
+ SmallString<128> Directive;
+ raw_svector_ostream OS(Directive);
+ const MCObjectFileInfo *MFI = getContext().getObjectFileInfo();
+
+ OS << " -aligncomm:\"" << Symbol->getName() << "\","
+ << Log2_32_Ceil(ByteAlignment);
+
+ PushSection();
+ SwitchSection(MFI->getDrectveSection());
+ EmitBytes(Directive);
+ PopSection();
+ }
+}
+
+void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
+ unsigned ByteAlignment) {
+ auto *Symbol = cast<MCSymbolCOFF>(S);
+
+ MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
+ PushSection();
+ SwitchSection(Section);
+ EmitValueToAlignment(ByteAlignment, 0, 1, 0);
+ EmitLabel(Symbol);
+ Symbol->setExternal(false);
+ EmitZeros(Size);
+ PopSection();
+}
+
+void MCWinCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment,
+ SMLoc Loc) {
+ llvm_unreachable("not implemented");
+}
+
+void MCWinCOFFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment) {
+ llvm_unreachable("not implemented");
+}
+
+// TODO: Implement this if you want to emit .comment section in COFF obj files.
+void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) {
+ llvm_unreachable("not implemented");
+}
+
+void MCWinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) {
+ llvm_unreachable("not implemented");
+}
+
+void MCWinCOFFStreamer::FinishImpl() {
+ MCObjectStreamer::FinishImpl();
+}
+
+void MCWinCOFFStreamer::Error(const Twine &Msg) const {
+ getContext().reportError(SMLoc(), Msg);
+}
diff --git a/llvm/lib/MC/MCWinEH.cpp b/llvm/lib/MC/MCWinEH.cpp
new file mode 100644
index 000000000000..e58a0b2cf654
--- /dev/null
+++ b/llvm/lib/MC/MCWinEH.cpp
@@ -0,0 +1,25 @@
+//===- lib/MC/MCWinEH.cpp - Windows EH implementation ---------------------===//
+//
+// 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/MCWinEH.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+
+namespace llvm {
+namespace WinEH {
+
+UnwindEmitter::~UnwindEmitter() {}
+
+}
+}
+
diff --git a/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp b/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp
new file mode 100644
index 000000000000..504e333cb2d4
--- /dev/null
+++ b/llvm/lib/MC/MCXCOFFObjectTargetWriter.cpp
@@ -0,0 +1,16 @@
+//===- MCXCOFFObjectTargetWriter.cpp - XCOFF Target Writer Subclass -------===//
+//
+// 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/MCXCOFFObjectWriter.h"
+
+using namespace llvm;
+
+MCXCOFFObjectTargetWriter::MCXCOFFObjectTargetWriter(bool Is64Bit)
+ : Is64Bit(Is64Bit) {}
+
+MCXCOFFObjectTargetWriter::~MCXCOFFObjectTargetWriter() = default;
diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp
new file mode 100644
index 000000000000..50937d6adc0c
--- /dev/null
+++ b/llvm/lib/MC/MCXCOFFStreamer.cpp
@@ -0,0 +1,101 @@
+//===- lib/MC/MCXCOFFStreamer.cpp - XCOFF 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 XCOFF .o object files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/XCOFF.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSymbolXCOFF.h"
+#include "llvm/MC/MCXCOFFStreamer.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+MCXCOFFStreamer::MCXCOFFStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> MAB,
+ std::unique_ptr<MCObjectWriter> OW,
+ std::unique_ptr<MCCodeEmitter> Emitter)
+ : MCObjectStreamer(Context, std::move(MAB), std::move(OW),
+ std::move(Emitter)) {}
+
+bool MCXCOFFStreamer::EmitSymbolAttribute(MCSymbol *Sym,
+ MCSymbolAttr Attribute) {
+ auto *Symbol = cast<MCSymbolXCOFF>(Sym);
+ getAssembler().registerSymbol(*Symbol);
+
+ switch (Attribute) {
+ case MCSA_Global:
+ Symbol->setStorageClass(XCOFF::C_EXT);
+ Symbol->setExternal(true);
+ break;
+ default:
+ report_fatal_error("Not implemented yet.");
+ }
+ return true;
+}
+
+void MCXCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ getAssembler().registerSymbol(*Symbol);
+ Symbol->setExternal(cast<MCSymbolXCOFF>(Symbol)->getStorageClass() !=
+ XCOFF::C_HIDEXT);
+ Symbol->setCommon(Size, ByteAlignment);
+
+ // Need to add this symbol to the current Fragment which will belong to the
+ // containing CSECT.
+ auto *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
+ assert(F && "Expected a valid section with a fragment set.");
+ Symbol->setFragment(F);
+
+ // Emit the alignment and storage for the variable to the section.
+ EmitValueToAlignment(ByteAlignment);
+ EmitZeros(Size);
+}
+
+void MCXCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment,
+ SMLoc Loc) {
+ report_fatal_error("Zero fill not implemented for XCOFF.");
+}
+
+void MCXCOFFStreamer::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);
+
+ // TODO: Handle Fixups later
+
+ MCDataFragment *DF = getOrCreateDataFragment(&STI);
+ DF->setHasInstructions(STI);
+ DF->getContents().append(Code.begin(), Code.end());
+}
+
+MCStreamer *llvm::createXCOFFStreamer(MCContext &Context,
+ std::unique_ptr<MCAsmBackend> &&MAB,
+ std::unique_ptr<MCObjectWriter> &&OW,
+ std::unique_ptr<MCCodeEmitter> &&CE,
+ bool RelaxAll) {
+ MCXCOFFStreamer *S = new MCXCOFFStreamer(Context, std::move(MAB),
+ std::move(OW), std::move(CE));
+ if (RelaxAll)
+ S->getAssembler().setRelaxAll(true);
+ return S;
+}
+
+void MCXCOFFStreamer::EmitXCOFFLocalCommonSymbol(MCSymbol *Symbol,
+ uint64_t Size,
+ unsigned ByteAlignment) {
+ EmitCommonSymbol(Symbol, Size, ByteAlignment);
+}
diff --git a/llvm/lib/MC/MachObjectWriter.cpp b/llvm/lib/MC/MachObjectWriter.cpp
new file mode 100644
index 000000000000..9f6af981aca1
--- /dev/null
+++ b/llvm/lib/MC/MachObjectWriter.cpp
@@ -0,0 +1,1052 @@
+//===- lib/MC/MachObjectWriter.cpp - Mach-O File Writer -------------------===//
+//
+// 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/ADT/DenseMap.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolMachO.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mc"
+
+void MachObjectWriter::reset() {
+ Relocations.clear();
+ IndirectSymBase.clear();
+ StringTable.clear();
+ LocalSymbolData.clear();
+ ExternalSymbolData.clear();
+ UndefinedSymbolData.clear();
+ MCObjectWriter::reset();
+}
+
+bool MachObjectWriter::doesSymbolRequireExternRelocation(const MCSymbol &S) {
+ // Undefined symbols are always extern.
+ if (S.isUndefined())
+ return true;
+
+ // References to weak definitions require external relocation entries; the
+ // definition may not always be the one in the same object file.
+ if (cast<MCSymbolMachO>(S).isWeakDefinition())
+ return true;
+
+ // Otherwise, we can use an internal relocation.
+ return false;
+}
+
+bool MachObjectWriter::
+MachSymbolData::operator<(const MachSymbolData &RHS) const {
+ return Symbol->getName() < RHS.Symbol->getName();
+}
+
+bool MachObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) {
+ const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo(
+ (MCFixupKind) Kind);
+
+ return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel;
+}
+
+uint64_t MachObjectWriter::getFragmentAddress(const MCFragment *Fragment,
+ const MCAsmLayout &Layout) const {
+ return getSectionAddress(Fragment->getParent()) +
+ Layout.getFragmentOffset(Fragment);
+}
+
+uint64_t MachObjectWriter::getSymbolAddress(const MCSymbol &S,
+ const MCAsmLayout &Layout) const {
+ // If this is a variable, then recursively evaluate now.
+ if (S.isVariable()) {
+ if (const MCConstantExpr *C =
+ dyn_cast<const MCConstantExpr>(S.getVariableValue()))
+ return C->getValue();
+
+ MCValue Target;
+ if (!S.getVariableValue()->evaluateAsRelocatable(Target, &Layout, nullptr))
+ report_fatal_error("unable to evaluate offset for variable '" +
+ S.getName() + "'");
+
+ // Verify that any used symbols are defined.
+ if (Target.getSymA() && Target.getSymA()->getSymbol().isUndefined())
+ report_fatal_error("unable to evaluate offset to undefined symbol '" +
+ Target.getSymA()->getSymbol().getName() + "'");
+ if (Target.getSymB() && Target.getSymB()->getSymbol().isUndefined())
+ report_fatal_error("unable to evaluate offset to undefined symbol '" +
+ Target.getSymB()->getSymbol().getName() + "'");
+
+ uint64_t Address = Target.getConstant();
+ if (Target.getSymA())
+ Address += getSymbolAddress(Target.getSymA()->getSymbol(), Layout);
+ if (Target.getSymB())
+ Address += getSymbolAddress(Target.getSymB()->getSymbol(), Layout);
+ return Address;
+ }
+
+ return getSectionAddress(S.getFragment()->getParent()) +
+ Layout.getSymbolOffset(S);
+}
+
+uint64_t MachObjectWriter::getPaddingSize(const MCSection *Sec,
+ const MCAsmLayout &Layout) const {
+ uint64_t EndAddr = getSectionAddress(Sec) + Layout.getSectionAddressSize(Sec);
+ unsigned Next = Sec->getLayoutOrder() + 1;
+ if (Next >= Layout.getSectionOrder().size())
+ return 0;
+
+ const MCSection &NextSec = *Layout.getSectionOrder()[Next];
+ if (NextSec.isVirtualSection())
+ return 0;
+ return offsetToAlignment(EndAddr, Align(NextSec.getAlignment()));
+}
+
+void MachObjectWriter::writeHeader(MachO::HeaderFileType Type,
+ unsigned NumLoadCommands,
+ unsigned LoadCommandsSize,
+ bool SubsectionsViaSymbols) {
+ uint32_t Flags = 0;
+
+ if (SubsectionsViaSymbols)
+ Flags |= MachO::MH_SUBSECTIONS_VIA_SYMBOLS;
+
+ // struct mach_header (28 bytes) or
+ // struct mach_header_64 (32 bytes)
+
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ W.write<uint32_t>(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC);
+
+ W.write<uint32_t>(TargetObjectWriter->getCPUType());
+ W.write<uint32_t>(TargetObjectWriter->getCPUSubtype());
+
+ W.write<uint32_t>(Type);
+ W.write<uint32_t>(NumLoadCommands);
+ W.write<uint32_t>(LoadCommandsSize);
+ W.write<uint32_t>(Flags);
+ if (is64Bit())
+ W.write<uint32_t>(0); // reserved
+
+ assert(W.OS.tell() - Start == (is64Bit() ? sizeof(MachO::mach_header_64)
+ : sizeof(MachO::mach_header)));
+}
+
+void MachObjectWriter::writeWithPadding(StringRef Str, uint64_t Size) {
+ assert(Size >= Str.size());
+ W.OS << Str;
+ W.OS.write_zeros(Size - Str.size());
+}
+
+/// writeSegmentLoadCommand - Write a segment load command.
+///
+/// \param NumSections The number of sections in this segment.
+/// \param SectionDataSize The total size of the sections.
+void MachObjectWriter::writeSegmentLoadCommand(
+ StringRef Name, unsigned NumSections, uint64_t VMAddr, uint64_t VMSize,
+ uint64_t SectionDataStartOffset, uint64_t SectionDataSize, uint32_t MaxProt,
+ uint32_t InitProt) {
+ // struct segment_command (56 bytes) or
+ // struct segment_command_64 (72 bytes)
+
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ unsigned SegmentLoadCommandSize =
+ is64Bit() ? sizeof(MachO::segment_command_64):
+ sizeof(MachO::segment_command);
+ W.write<uint32_t>(is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT);
+ W.write<uint32_t>(SegmentLoadCommandSize +
+ NumSections * (is64Bit() ? sizeof(MachO::section_64) :
+ sizeof(MachO::section)));
+
+ writeWithPadding(Name, 16);
+ if (is64Bit()) {
+ W.write<uint64_t>(VMAddr); // vmaddr
+ W.write<uint64_t>(VMSize); // vmsize
+ W.write<uint64_t>(SectionDataStartOffset); // file offset
+ W.write<uint64_t>(SectionDataSize); // file size
+ } else {
+ W.write<uint32_t>(VMAddr); // vmaddr
+ W.write<uint32_t>(VMSize); // vmsize
+ W.write<uint32_t>(SectionDataStartOffset); // file offset
+ W.write<uint32_t>(SectionDataSize); // file size
+ }
+ // maxprot
+ W.write<uint32_t>(MaxProt);
+ // initprot
+ W.write<uint32_t>(InitProt);
+ W.write<uint32_t>(NumSections);
+ W.write<uint32_t>(0); // flags
+
+ assert(W.OS.tell() - Start == SegmentLoadCommandSize);
+}
+
+void MachObjectWriter::writeSection(const MCAsmLayout &Layout,
+ const MCSection &Sec, uint64_t VMAddr,
+ uint64_t FileOffset, unsigned Flags,
+ uint64_t RelocationsStart,
+ unsigned NumRelocations) {
+ uint64_t SectionSize = Layout.getSectionAddressSize(&Sec);
+ const MCSectionMachO &Section = cast<MCSectionMachO>(Sec);
+
+ // The offset is unused for virtual sections.
+ if (Section.isVirtualSection()) {
+ assert(Layout.getSectionFileSize(&Sec) == 0 && "Invalid file size!");
+ FileOffset = 0;
+ }
+
+ // struct section (68 bytes) or
+ // struct section_64 (80 bytes)
+
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ writeWithPadding(Section.getSectionName(), 16);
+ writeWithPadding(Section.getSegmentName(), 16);
+ if (is64Bit()) {
+ W.write<uint64_t>(VMAddr); // address
+ W.write<uint64_t>(SectionSize); // size
+ } else {
+ W.write<uint32_t>(VMAddr); // address
+ W.write<uint32_t>(SectionSize); // size
+ }
+ W.write<uint32_t>(FileOffset);
+
+ assert(isPowerOf2_32(Section.getAlignment()) && "Invalid alignment!");
+ W.write<uint32_t>(Log2_32(Section.getAlignment()));
+ W.write<uint32_t>(NumRelocations ? RelocationsStart : 0);
+ W.write<uint32_t>(NumRelocations);
+ W.write<uint32_t>(Flags);
+ W.write<uint32_t>(IndirectSymBase.lookup(&Sec)); // reserved1
+ W.write<uint32_t>(Section.getStubSize()); // reserved2
+ if (is64Bit())
+ W.write<uint32_t>(0); // reserved3
+
+ assert(W.OS.tell() - Start ==
+ (is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section)));
+}
+
+void MachObjectWriter::writeSymtabLoadCommand(uint32_t SymbolOffset,
+ uint32_t NumSymbols,
+ uint32_t StringTableOffset,
+ uint32_t StringTableSize) {
+ // struct symtab_command (24 bytes)
+
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ W.write<uint32_t>(MachO::LC_SYMTAB);
+ W.write<uint32_t>(sizeof(MachO::symtab_command));
+ W.write<uint32_t>(SymbolOffset);
+ W.write<uint32_t>(NumSymbols);
+ W.write<uint32_t>(StringTableOffset);
+ W.write<uint32_t>(StringTableSize);
+
+ assert(W.OS.tell() - Start == sizeof(MachO::symtab_command));
+}
+
+void MachObjectWriter::writeDysymtabLoadCommand(uint32_t FirstLocalSymbol,
+ uint32_t NumLocalSymbols,
+ uint32_t FirstExternalSymbol,
+ uint32_t NumExternalSymbols,
+ uint32_t FirstUndefinedSymbol,
+ uint32_t NumUndefinedSymbols,
+ uint32_t IndirectSymbolOffset,
+ uint32_t NumIndirectSymbols) {
+ // struct dysymtab_command (80 bytes)
+
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ W.write<uint32_t>(MachO::LC_DYSYMTAB);
+ W.write<uint32_t>(sizeof(MachO::dysymtab_command));
+ W.write<uint32_t>(FirstLocalSymbol);
+ W.write<uint32_t>(NumLocalSymbols);
+ W.write<uint32_t>(FirstExternalSymbol);
+ W.write<uint32_t>(NumExternalSymbols);
+ W.write<uint32_t>(FirstUndefinedSymbol);
+ W.write<uint32_t>(NumUndefinedSymbols);
+ W.write<uint32_t>(0); // tocoff
+ W.write<uint32_t>(0); // ntoc
+ W.write<uint32_t>(0); // modtaboff
+ W.write<uint32_t>(0); // nmodtab
+ W.write<uint32_t>(0); // extrefsymoff
+ W.write<uint32_t>(0); // nextrefsyms
+ W.write<uint32_t>(IndirectSymbolOffset);
+ W.write<uint32_t>(NumIndirectSymbols);
+ W.write<uint32_t>(0); // extreloff
+ W.write<uint32_t>(0); // nextrel
+ W.write<uint32_t>(0); // locreloff
+ W.write<uint32_t>(0); // nlocrel
+
+ assert(W.OS.tell() - Start == sizeof(MachO::dysymtab_command));
+}
+
+MachObjectWriter::MachSymbolData *
+MachObjectWriter::findSymbolData(const MCSymbol &Sym) {
+ for (auto *SymbolData :
+ {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
+ for (MachSymbolData &Entry : *SymbolData)
+ if (Entry.Symbol == &Sym)
+ return &Entry;
+
+ return nullptr;
+}
+
+const MCSymbol &MachObjectWriter::findAliasedSymbol(const MCSymbol &Sym) const {
+ const MCSymbol *S = &Sym;
+ while (S->isVariable()) {
+ const MCExpr *Value = S->getVariableValue();
+ const auto *Ref = dyn_cast<MCSymbolRefExpr>(Value);
+ if (!Ref)
+ return *S;
+ S = &Ref->getSymbol();
+ }
+ return *S;
+}
+
+void MachObjectWriter::writeNlist(MachSymbolData &MSD,
+ const MCAsmLayout &Layout) {
+ const MCSymbol *Symbol = MSD.Symbol;
+ const MCSymbol &Data = *Symbol;
+ const MCSymbol *AliasedSymbol = &findAliasedSymbol(*Symbol);
+ uint8_t SectionIndex = MSD.SectionIndex;
+ uint8_t Type = 0;
+ uint64_t Address = 0;
+ bool IsAlias = Symbol != AliasedSymbol;
+
+ const MCSymbol &OrigSymbol = *Symbol;
+ MachSymbolData *AliaseeInfo;
+ if (IsAlias) {
+ AliaseeInfo = findSymbolData(*AliasedSymbol);
+ if (AliaseeInfo)
+ SectionIndex = AliaseeInfo->SectionIndex;
+ Symbol = AliasedSymbol;
+ // FIXME: Should this update Data as well?
+ }
+
+ // Set the N_TYPE bits. See <mach-o/nlist.h>.
+ //
+ // FIXME: Are the prebound or indirect fields possible here?
+ if (IsAlias && Symbol->isUndefined())
+ Type = MachO::N_INDR;
+ else if (Symbol->isUndefined())
+ Type = MachO::N_UNDF;
+ else if (Symbol->isAbsolute())
+ Type = MachO::N_ABS;
+ else
+ Type = MachO::N_SECT;
+
+ // FIXME: Set STAB bits.
+
+ if (Data.isPrivateExtern())
+ Type |= MachO::N_PEXT;
+
+ // Set external bit.
+ if (Data.isExternal() || (!IsAlias && Symbol->isUndefined()))
+ Type |= MachO::N_EXT;
+
+ // Compute the symbol address.
+ if (IsAlias && Symbol->isUndefined())
+ Address = AliaseeInfo->StringIndex;
+ else if (Symbol->isDefined())
+ Address = getSymbolAddress(OrigSymbol, Layout);
+ else if (Symbol->isCommon()) {
+ // Common symbols are encoded with the size in the address
+ // field, and their alignment in the flags.
+ Address = Symbol->getCommonSize();
+ }
+
+ // struct nlist (12 bytes)
+
+ W.write<uint32_t>(MSD.StringIndex);
+ W.OS << char(Type);
+ W.OS << char(SectionIndex);
+
+ // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc'
+ // value.
+ bool EncodeAsAltEntry =
+ IsAlias && cast<MCSymbolMachO>(OrigSymbol).isAltEntry();
+ W.write<uint16_t>(cast<MCSymbolMachO>(Symbol)->getEncodedFlags(EncodeAsAltEntry));
+ if (is64Bit())
+ W.write<uint64_t>(Address);
+ else
+ W.write<uint32_t>(Address);
+}
+
+void MachObjectWriter::writeLinkeditLoadCommand(uint32_t Type,
+ uint32_t DataOffset,
+ uint32_t DataSize) {
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ W.write<uint32_t>(Type);
+ W.write<uint32_t>(sizeof(MachO::linkedit_data_command));
+ W.write<uint32_t>(DataOffset);
+ W.write<uint32_t>(DataSize);
+
+ assert(W.OS.tell() - Start == sizeof(MachO::linkedit_data_command));
+}
+
+static unsigned ComputeLinkerOptionsLoadCommandSize(
+ const std::vector<std::string> &Options, bool is64Bit)
+{
+ unsigned Size = sizeof(MachO::linker_option_command);
+ for (const std::string &Option : Options)
+ Size += Option.size() + 1;
+ return alignTo(Size, is64Bit ? 8 : 4);
+}
+
+void MachObjectWriter::writeLinkerOptionsLoadCommand(
+ const std::vector<std::string> &Options)
+{
+ unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options, is64Bit());
+ uint64_t Start = W.OS.tell();
+ (void) Start;
+
+ W.write<uint32_t>(MachO::LC_LINKER_OPTION);
+ W.write<uint32_t>(Size);
+ W.write<uint32_t>(Options.size());
+ uint64_t BytesWritten = sizeof(MachO::linker_option_command);
+ for (const std::string &Option : Options) {
+ // Write each string, including the null byte.
+ W.OS << Option << '\0';
+ BytesWritten += Option.size() + 1;
+ }
+
+ // Pad to a multiple of the pointer size.
+ W.OS.write_zeros(
+ offsetToAlignment(BytesWritten, is64Bit() ? Align(8) : Align(4)));
+
+ assert(W.OS.tell() - Start == Size);
+}
+
+static bool isFixupTargetValid(const MCValue &Target) {
+ // Target is (LHS - RHS + cst).
+ // We don't support the form where LHS is null: -RHS + cst
+ if (!Target.getSymA() && Target.getSymB())
+ return false;
+ return true;
+}
+
+void MachObjectWriter::recordRelocation(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ if (!isFixupTargetValid(Target)) {
+ Asm.getContext().reportError(Fixup.getLoc(),
+ "unsupported relocation expression");
+ return;
+ }
+
+ TargetObjectWriter->recordRelocation(this, Asm, Layout, Fragment, Fixup,
+ Target, FixedValue);
+}
+
+void MachObjectWriter::bindIndirectSymbols(MCAssembler &Asm) {
+ // This is the point where 'as' creates actual symbols for indirect symbols
+ // (in the following two passes). It would be easier for us to do this sooner
+ // when we see the attribute, but that makes getting the order in the symbol
+ // table much more complicated than it is worth.
+ //
+ // FIXME: Revisit this when the dust settles.
+
+ // Report errors for use of .indirect_symbol not in a symbol pointer section
+ // or stub section.
+ for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it) {
+ const MCSectionMachO &Section = cast<MCSectionMachO>(*it->Section);
+
+ if (Section.getType() != MachO::S_NON_LAZY_SYMBOL_POINTERS &&
+ Section.getType() != MachO::S_LAZY_SYMBOL_POINTERS &&
+ Section.getType() != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS &&
+ Section.getType() != MachO::S_SYMBOL_STUBS) {
+ MCSymbol &Symbol = *it->Symbol;
+ report_fatal_error("indirect symbol '" + Symbol.getName() +
+ "' not in a symbol pointer or stub section");
+ }
+ }
+
+ // Bind non-lazy symbol pointers first.
+ unsigned IndirectIndex = 0;
+ for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) {
+ const MCSectionMachO &Section = cast<MCSectionMachO>(*it->Section);
+
+ if (Section.getType() != MachO::S_NON_LAZY_SYMBOL_POINTERS &&
+ Section.getType() != MachO::S_THREAD_LOCAL_VARIABLE_POINTERS)
+ continue;
+
+ // Initialize the section indirect symbol base, if necessary.
+ IndirectSymBase.insert(std::make_pair(it->Section, IndirectIndex));
+
+ Asm.registerSymbol(*it->Symbol);
+ }
+
+ // Then lazy symbol pointers and symbol stubs.
+ IndirectIndex = 0;
+ for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it, ++IndirectIndex) {
+ const MCSectionMachO &Section = cast<MCSectionMachO>(*it->Section);
+
+ if (Section.getType() != MachO::S_LAZY_SYMBOL_POINTERS &&
+ Section.getType() != MachO::S_SYMBOL_STUBS)
+ continue;
+
+ // Initialize the section indirect symbol base, if necessary.
+ IndirectSymBase.insert(std::make_pair(it->Section, IndirectIndex));
+
+ // Set the symbol type to undefined lazy, but only on construction.
+ //
+ // FIXME: Do not hardcode.
+ bool Created;
+ Asm.registerSymbol(*it->Symbol, &Created);
+ if (Created)
+ cast<MCSymbolMachO>(it->Symbol)->setReferenceTypeUndefinedLazy(true);
+ }
+}
+
+/// computeSymbolTable - Compute the symbol table data
+void MachObjectWriter::computeSymbolTable(
+ MCAssembler &Asm, std::vector<MachSymbolData> &LocalSymbolData,
+ std::vector<MachSymbolData> &ExternalSymbolData,
+ std::vector<MachSymbolData> &UndefinedSymbolData) {
+ // Build section lookup table.
+ DenseMap<const MCSection*, uint8_t> SectionIndexMap;
+ unsigned Index = 1;
+ for (MCAssembler::iterator it = Asm.begin(),
+ ie = Asm.end(); it != ie; ++it, ++Index)
+ SectionIndexMap[&*it] = Index;
+ assert(Index <= 256 && "Too many sections!");
+
+ // Build the string table.
+ for (const MCSymbol &Symbol : Asm.symbols()) {
+ if (!Asm.isSymbolLinkerVisible(Symbol))
+ continue;
+
+ StringTable.add(Symbol.getName());
+ }
+ StringTable.finalize();
+
+ // Build the symbol arrays but only for non-local symbols.
+ //
+ // The particular order that we collect and then sort the symbols is chosen to
+ // match 'as'. Even though it doesn't matter for correctness, this is
+ // important for letting us diff .o files.
+ for (const MCSymbol &Symbol : Asm.symbols()) {
+ // Ignore non-linker visible symbols.
+ if (!Asm.isSymbolLinkerVisible(Symbol))
+ continue;
+
+ if (!Symbol.isExternal() && !Symbol.isUndefined())
+ continue;
+
+ MachSymbolData MSD;
+ MSD.Symbol = &Symbol;
+ MSD.StringIndex = StringTable.getOffset(Symbol.getName());
+
+ if (Symbol.isUndefined()) {
+ MSD.SectionIndex = 0;
+ UndefinedSymbolData.push_back(MSD);
+ } else if (Symbol.isAbsolute()) {
+ MSD.SectionIndex = 0;
+ ExternalSymbolData.push_back(MSD);
+ } else {
+ MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
+ assert(MSD.SectionIndex && "Invalid section index!");
+ ExternalSymbolData.push_back(MSD);
+ }
+ }
+
+ // Now add the data for local symbols.
+ for (const MCSymbol &Symbol : Asm.symbols()) {
+ // Ignore non-linker visible symbols.
+ if (!Asm.isSymbolLinkerVisible(Symbol))
+ continue;
+
+ if (Symbol.isExternal() || Symbol.isUndefined())
+ continue;
+
+ MachSymbolData MSD;
+ MSD.Symbol = &Symbol;
+ MSD.StringIndex = StringTable.getOffset(Symbol.getName());
+
+ if (Symbol.isAbsolute()) {
+ MSD.SectionIndex = 0;
+ LocalSymbolData.push_back(MSD);
+ } else {
+ MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection());
+ assert(MSD.SectionIndex && "Invalid section index!");
+ LocalSymbolData.push_back(MSD);
+ }
+ }
+
+ // External and undefined symbols are required to be in lexicographic order.
+ llvm::sort(ExternalSymbolData);
+ llvm::sort(UndefinedSymbolData);
+
+ // Set the symbol indices.
+ Index = 0;
+ for (auto *SymbolData :
+ {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
+ for (MachSymbolData &Entry : *SymbolData)
+ Entry.Symbol->setIndex(Index++);
+
+ for (const MCSection &Section : Asm) {
+ for (RelAndSymbol &Rel : Relocations[&Section]) {
+ if (!Rel.Sym)
+ continue;
+
+ // Set the Index and the IsExtern bit.
+ unsigned Index = Rel.Sym->getIndex();
+ assert(isInt<24>(Index));
+ if (W.Endian == support::little)
+ Rel.MRE.r_word1 = (Rel.MRE.r_word1 & (~0U << 24)) | Index | (1 << 27);
+ else
+ Rel.MRE.r_word1 = (Rel.MRE.r_word1 & 0xff) | Index << 8 | (1 << 4);
+ }
+ }
+}
+
+void MachObjectWriter::computeSectionAddresses(const MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ uint64_t StartAddress = 0;
+ for (const MCSection *Sec : Layout.getSectionOrder()) {
+ StartAddress = alignTo(StartAddress, Sec->getAlignment());
+ SectionAddress[Sec] = StartAddress;
+ StartAddress += Layout.getSectionAddressSize(Sec);
+
+ // Explicitly pad the section to match the alignment requirements of the
+ // following one. This is for 'gas' compatibility, it shouldn't
+ /// strictly be necessary.
+ StartAddress += getPaddingSize(Sec, Layout);
+ }
+}
+
+void MachObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ computeSectionAddresses(Asm, Layout);
+
+ // Create symbol data for any indirect symbols.
+ bindIndirectSymbols(Asm);
+}
+
+bool MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &A, const MCSymbol &B,
+ bool InSet) const {
+ // FIXME: We don't handle things like
+ // foo = .
+ // creating atoms.
+ if (A.isVariable() || B.isVariable())
+ return false;
+ return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, A, B,
+ InSet);
+}
+
+bool MachObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB,
+ bool InSet, bool IsPCRel) const {
+ if (InSet)
+ return true;
+
+ // The effective address is
+ // addr(atom(A)) + offset(A)
+ // - addr(atom(B)) - offset(B)
+ // and the offsets are not relocatable, so the fixup is fully resolved when
+ // addr(atom(A)) - addr(atom(B)) == 0.
+ const MCSymbol &SA = findAliasedSymbol(SymA);
+ const MCSection &SecA = SA.getSection();
+ const MCSection &SecB = *FB.getParent();
+
+ if (IsPCRel) {
+ // The simple (Darwin, except on x86_64) way of dealing with this was to
+ // assume that any reference to a temporary symbol *must* be a temporary
+ // symbol in the same atom, unless the sections differ. Therefore, any PCrel
+ // relocation to a temporary symbol (in the same section) is fully
+ // resolved. This also works in conjunction with absolutized .set, which
+ // requires the compiler to use .set to absolutize the differences between
+ // symbols which the compiler knows to be assembly time constants, so we
+ // don't need to worry about considering symbol differences fully resolved.
+ //
+ // If the file isn't using sub-sections-via-symbols, we can make the
+ // same assumptions about any symbol that we normally make about
+ // assembler locals.
+
+ bool hasReliableSymbolDifference = isX86_64();
+ if (!hasReliableSymbolDifference) {
+ if (!SA.isInSection() || &SecA != &SecB ||
+ (!SA.isTemporary() && FB.getAtom() != SA.getFragment()->getAtom() &&
+ Asm.getSubsectionsViaSymbols()))
+ return false;
+ return true;
+ }
+ // For Darwin x86_64, there is one special case when the reference IsPCRel.
+ // If the fragment with the reference does not have a base symbol but meets
+ // the simple way of dealing with this, in that it is a temporary symbol in
+ // the same atom then it is assumed to be fully resolved. This is needed so
+ // a relocation entry is not created and so the static linker does not
+ // mess up the reference later.
+ else if(!FB.getAtom() &&
+ SA.isTemporary() && SA.isInSection() && &SecA == &SecB){
+ return true;
+ }
+ }
+
+ // If they are not in the same section, we can't compute the diff.
+ if (&SecA != &SecB)
+ return false;
+
+ const MCFragment *FA = SA.getFragment();
+
+ // Bail if the symbol has no fragment.
+ if (!FA)
+ return false;
+
+ // If the atoms are the same, they are guaranteed to have the same address.
+ if (FA->getAtom() == FB.getAtom())
+ return true;
+
+ // Otherwise, we can't prove this is fully resolved.
+ return false;
+}
+
+static MachO::LoadCommandType getLCFromMCVM(MCVersionMinType Type) {
+ switch (Type) {
+ case MCVM_OSXVersionMin: return MachO::LC_VERSION_MIN_MACOSX;
+ case MCVM_IOSVersionMin: return MachO::LC_VERSION_MIN_IPHONEOS;
+ case MCVM_TvOSVersionMin: return MachO::LC_VERSION_MIN_TVOS;
+ case MCVM_WatchOSVersionMin: return MachO::LC_VERSION_MIN_WATCHOS;
+ }
+ llvm_unreachable("Invalid mc version min type");
+}
+
+uint64_t MachObjectWriter::writeObject(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ uint64_t StartOffset = W.OS.tell();
+
+ // Compute symbol table information and bind symbol indices.
+ computeSymbolTable(Asm, LocalSymbolData, ExternalSymbolData,
+ UndefinedSymbolData);
+
+ unsigned NumSections = Asm.size();
+ const MCAssembler::VersionInfoType &VersionInfo =
+ Layout.getAssembler().getVersionInfo();
+
+ // The section data starts after the header, the segment load command (and
+ // section headers) and the symbol table.
+ unsigned NumLoadCommands = 1;
+ uint64_t LoadCommandsSize = is64Bit() ?
+ sizeof(MachO::segment_command_64) + NumSections * sizeof(MachO::section_64):
+ sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section);
+
+ // Add the deployment target version info load command size, if used.
+ if (VersionInfo.Major != 0) {
+ ++NumLoadCommands;
+ if (VersionInfo.EmitBuildVersion)
+ LoadCommandsSize += sizeof(MachO::build_version_command);
+ else
+ LoadCommandsSize += sizeof(MachO::version_min_command);
+ }
+
+ // Add the data-in-code load command size, if used.
+ unsigned NumDataRegions = Asm.getDataRegions().size();
+ if (NumDataRegions) {
+ ++NumLoadCommands;
+ LoadCommandsSize += sizeof(MachO::linkedit_data_command);
+ }
+
+ // Add the loh load command size, if used.
+ uint64_t LOHRawSize = Asm.getLOHContainer().getEmitSize(*this, Layout);
+ uint64_t LOHSize = alignTo(LOHRawSize, is64Bit() ? 8 : 4);
+ if (LOHSize) {
+ ++NumLoadCommands;
+ LoadCommandsSize += sizeof(MachO::linkedit_data_command);
+ }
+
+ // Add the symbol table load command sizes, if used.
+ unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() +
+ UndefinedSymbolData.size();
+ if (NumSymbols) {
+ NumLoadCommands += 2;
+ LoadCommandsSize += (sizeof(MachO::symtab_command) +
+ sizeof(MachO::dysymtab_command));
+ }
+
+ // Add the linker option load commands sizes.
+ for (const auto &Option : Asm.getLinkerOptions()) {
+ ++NumLoadCommands;
+ LoadCommandsSize += ComputeLinkerOptionsLoadCommandSize(Option, is64Bit());
+ }
+
+ // Compute the total size of the section data, as well as its file size and vm
+ // size.
+ uint64_t SectionDataStart = (is64Bit() ? sizeof(MachO::mach_header_64) :
+ sizeof(MachO::mach_header)) + LoadCommandsSize;
+ uint64_t SectionDataSize = 0;
+ uint64_t SectionDataFileSize = 0;
+ uint64_t VMSize = 0;
+ for (const MCSection &Sec : Asm) {
+ uint64_t Address = getSectionAddress(&Sec);
+ uint64_t Size = Layout.getSectionAddressSize(&Sec);
+ uint64_t FileSize = Layout.getSectionFileSize(&Sec);
+ FileSize += getPaddingSize(&Sec, Layout);
+
+ VMSize = std::max(VMSize, Address + Size);
+
+ if (Sec.isVirtualSection())
+ continue;
+
+ SectionDataSize = std::max(SectionDataSize, Address + Size);
+ SectionDataFileSize = std::max(SectionDataFileSize, Address + FileSize);
+ }
+
+ // The section data is padded to 4 bytes.
+ //
+ // FIXME: Is this machine dependent?
+ unsigned SectionDataPadding =
+ offsetToAlignment(SectionDataFileSize, Align(4));
+ SectionDataFileSize += SectionDataPadding;
+
+ // Write the prolog, starting with the header and load command...
+ writeHeader(MachO::MH_OBJECT, NumLoadCommands, LoadCommandsSize,
+ Asm.getSubsectionsViaSymbols());
+ uint32_t Prot =
+ MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
+ writeSegmentLoadCommand("", NumSections, 0, VMSize, SectionDataStart,
+ SectionDataSize, Prot, Prot);
+
+ // ... and then the section headers.
+ uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize;
+ for (const MCSection &Section : Asm) {
+ const auto &Sec = cast<MCSectionMachO>(Section);
+ std::vector<RelAndSymbol> &Relocs = Relocations[&Sec];
+ unsigned NumRelocs = Relocs.size();
+ uint64_t SectionStart = SectionDataStart + getSectionAddress(&Sec);
+ unsigned Flags = Sec.getTypeAndAttributes();
+ if (Sec.hasInstructions())
+ Flags |= MachO::S_ATTR_SOME_INSTRUCTIONS;
+ writeSection(Layout, Sec, getSectionAddress(&Sec), SectionStart, Flags,
+ RelocTableEnd, NumRelocs);
+ RelocTableEnd += NumRelocs * sizeof(MachO::any_relocation_info);
+ }
+
+ // Write out the deployment target information, if it's available.
+ if (VersionInfo.Major != 0) {
+ auto EncodeVersion = [](VersionTuple V) -> uint32_t {
+ assert(!V.empty() && "empty version");
+ unsigned Update = V.getSubminor() ? *V.getSubminor() : 0;
+ unsigned Minor = V.getMinor() ? *V.getMinor() : 0;
+ assert(Update < 256 && "unencodable update target version");
+ assert(Minor < 256 && "unencodable minor target version");
+ assert(V.getMajor() < 65536 && "unencodable major target version");
+ return Update | (Minor << 8) | (V.getMajor() << 16);
+ };
+ uint32_t EncodedVersion = EncodeVersion(
+ VersionTuple(VersionInfo.Major, VersionInfo.Minor, VersionInfo.Update));
+ uint32_t SDKVersion = !VersionInfo.SDKVersion.empty()
+ ? EncodeVersion(VersionInfo.SDKVersion)
+ : 0;
+ if (VersionInfo.EmitBuildVersion) {
+ // FIXME: Currently empty tools. Add clang version in the future.
+ W.write<uint32_t>(MachO::LC_BUILD_VERSION);
+ W.write<uint32_t>(sizeof(MachO::build_version_command));
+ W.write<uint32_t>(VersionInfo.TypeOrPlatform.Platform);
+ W.write<uint32_t>(EncodedVersion);
+ W.write<uint32_t>(SDKVersion);
+ W.write<uint32_t>(0); // Empty tools list.
+ } else {
+ MachO::LoadCommandType LCType
+ = getLCFromMCVM(VersionInfo.TypeOrPlatform.Type);
+ W.write<uint32_t>(LCType);
+ W.write<uint32_t>(sizeof(MachO::version_min_command));
+ W.write<uint32_t>(EncodedVersion);
+ W.write<uint32_t>(SDKVersion);
+ }
+ }
+
+ // Write the data-in-code load command, if used.
+ uint64_t DataInCodeTableEnd = RelocTableEnd + NumDataRegions * 8;
+ if (NumDataRegions) {
+ uint64_t DataRegionsOffset = RelocTableEnd;
+ uint64_t DataRegionsSize = NumDataRegions * 8;
+ writeLinkeditLoadCommand(MachO::LC_DATA_IN_CODE, DataRegionsOffset,
+ DataRegionsSize);
+ }
+
+ // Write the loh load command, if used.
+ uint64_t LOHTableEnd = DataInCodeTableEnd + LOHSize;
+ if (LOHSize)
+ writeLinkeditLoadCommand(MachO::LC_LINKER_OPTIMIZATION_HINT,
+ DataInCodeTableEnd, LOHSize);
+
+ // Write the symbol table load command, if used.
+ if (NumSymbols) {
+ unsigned FirstLocalSymbol = 0;
+ unsigned NumLocalSymbols = LocalSymbolData.size();
+ unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols;
+ unsigned NumExternalSymbols = ExternalSymbolData.size();
+ unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols;
+ unsigned NumUndefinedSymbols = UndefinedSymbolData.size();
+ unsigned NumIndirectSymbols = Asm.indirect_symbol_size();
+ unsigned NumSymTabSymbols =
+ NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols;
+ uint64_t IndirectSymbolSize = NumIndirectSymbols * 4;
+ uint64_t IndirectSymbolOffset = 0;
+
+ // If used, the indirect symbols are written after the section data.
+ if (NumIndirectSymbols)
+ IndirectSymbolOffset = LOHTableEnd;
+
+ // The symbol table is written after the indirect symbol data.
+ uint64_t SymbolTableOffset = LOHTableEnd + IndirectSymbolSize;
+
+ // The string table is written after symbol table.
+ uint64_t StringTableOffset =
+ SymbolTableOffset + NumSymTabSymbols * (is64Bit() ?
+ sizeof(MachO::nlist_64) :
+ sizeof(MachO::nlist));
+ writeSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols,
+ StringTableOffset, StringTable.getSize());
+
+ writeDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols,
+ FirstExternalSymbol, NumExternalSymbols,
+ FirstUndefinedSymbol, NumUndefinedSymbols,
+ IndirectSymbolOffset, NumIndirectSymbols);
+ }
+
+ // Write the linker options load commands.
+ for (const auto &Option : Asm.getLinkerOptions())
+ writeLinkerOptionsLoadCommand(Option);
+
+ // Write the actual section data.
+ for (const MCSection &Sec : Asm) {
+ Asm.writeSectionData(W.OS, &Sec, Layout);
+
+ uint64_t Pad = getPaddingSize(&Sec, Layout);
+ W.OS.write_zeros(Pad);
+ }
+
+ // Write the extra padding.
+ W.OS.write_zeros(SectionDataPadding);
+
+ // Write the relocation entries.
+ for (const MCSection &Sec : Asm) {
+ // Write the section relocation entries, in reverse order to match 'as'
+ // (approximately, the exact algorithm is more complicated than this).
+ std::vector<RelAndSymbol> &Relocs = Relocations[&Sec];
+ for (const RelAndSymbol &Rel : make_range(Relocs.rbegin(), Relocs.rend())) {
+ W.write<uint32_t>(Rel.MRE.r_word0);
+ W.write<uint32_t>(Rel.MRE.r_word1);
+ }
+ }
+
+ // Write out the data-in-code region payload, if there is one.
+ for (MCAssembler::const_data_region_iterator
+ it = Asm.data_region_begin(), ie = Asm.data_region_end();
+ it != ie; ++it) {
+ const DataRegionData *Data = &(*it);
+ uint64_t Start = getSymbolAddress(*Data->Start, Layout);
+ uint64_t End;
+ if (Data->End)
+ End = getSymbolAddress(*Data->End, Layout);
+ else
+ report_fatal_error("Data region not terminated");
+
+ LLVM_DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind
+ << " start: " << Start << "(" << Data->Start->getName()
+ << ")"
+ << " end: " << End << "(" << Data->End->getName() << ")"
+ << " size: " << End - Start << "\n");
+ W.write<uint32_t>(Start);
+ W.write<uint16_t>(End - Start);
+ W.write<uint16_t>(Data->Kind);
+ }
+
+ // Write out the loh commands, if there is one.
+ if (LOHSize) {
+#ifndef NDEBUG
+ unsigned Start = W.OS.tell();
+#endif
+ Asm.getLOHContainer().emit(*this, Layout);
+ // Pad to a multiple of the pointer size.
+ W.OS.write_zeros(
+ offsetToAlignment(LOHRawSize, is64Bit() ? Align(8) : Align(4)));
+ assert(W.OS.tell() - Start == LOHSize);
+ }
+
+ // Write the symbol table data, if used.
+ if (NumSymbols) {
+ // Write the indirect symbol entries.
+ for (MCAssembler::const_indirect_symbol_iterator
+ it = Asm.indirect_symbol_begin(),
+ ie = Asm.indirect_symbol_end(); it != ie; ++it) {
+ // Indirect symbols in the non-lazy symbol pointer section have some
+ // special handling.
+ const MCSectionMachO &Section =
+ static_cast<const MCSectionMachO &>(*it->Section);
+ if (Section.getType() == MachO::S_NON_LAZY_SYMBOL_POINTERS) {
+ // If this symbol is defined and internal, mark it as such.
+ if (it->Symbol->isDefined() && !it->Symbol->isExternal()) {
+ uint32_t Flags = MachO::INDIRECT_SYMBOL_LOCAL;
+ if (it->Symbol->isAbsolute())
+ Flags |= MachO::INDIRECT_SYMBOL_ABS;
+ W.write<uint32_t>(Flags);
+ continue;
+ }
+ }
+
+ W.write<uint32_t>(it->Symbol->getIndex());
+ }
+
+ // FIXME: Check that offsets match computed ones.
+
+ // Write the symbol table entries.
+ for (auto *SymbolData :
+ {&LocalSymbolData, &ExternalSymbolData, &UndefinedSymbolData})
+ for (MachSymbolData &Entry : *SymbolData)
+ writeNlist(Entry, Layout);
+
+ // Write the string table.
+ StringTable.write(W.OS);
+ }
+
+ return W.OS.tell() - StartOffset;
+}
+
+std::unique_ptr<MCObjectWriter>
+llvm::createMachObjectWriter(std::unique_ptr<MCMachObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS, bool IsLittleEndian) {
+ return std::make_unique<MachObjectWriter>(std::move(MOTW), OS,
+ IsLittleEndian);
+}
diff --git a/llvm/lib/MC/StringTableBuilder.cpp b/llvm/lib/MC/StringTableBuilder.cpp
new file mode 100644
index 000000000000..c9c88ec58432
--- /dev/null
+++ b/llvm/lib/MC/StringTableBuilder.cpp
@@ -0,0 +1,199 @@
+//===- StringTableBuilder.cpp - String table building utility -------------===//
+//
+// 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/StringTableBuilder.h"
+#include "llvm/ADT/CachedHashString.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+
+StringTableBuilder::~StringTableBuilder() = default;
+
+void StringTableBuilder::initSize() {
+ // Account for leading bytes in table so that offsets returned from add are
+ // correct.
+ switch (K) {
+ case RAW:
+ case DWARF:
+ Size = 0;
+ break;
+ case MachO:
+ case ELF:
+ // Start the table with a NUL byte.
+ Size = 1;
+ break;
+ case XCOFF:
+ case WinCOFF:
+ // Make room to write the table size later.
+ Size = 4;
+ break;
+ }
+}
+
+StringTableBuilder::StringTableBuilder(Kind K, unsigned Alignment)
+ : K(K), Alignment(Alignment) {
+ initSize();
+}
+
+void StringTableBuilder::write(raw_ostream &OS) const {
+ assert(isFinalized());
+ SmallString<0> Data;
+ Data.resize(getSize());
+ write((uint8_t *)Data.data());
+ OS << Data;
+}
+
+using StringPair = std::pair<CachedHashStringRef, size_t>;
+
+void StringTableBuilder::write(uint8_t *Buf) const {
+ assert(isFinalized());
+ for (const StringPair &P : StringIndexMap) {
+ StringRef Data = P.first.val();
+ if (!Data.empty())
+ memcpy(Buf + P.second, Data.data(), Data.size());
+ }
+ // The COFF formats store the size of the string table in the first 4 bytes.
+ // For Windows, the format is little-endian; for AIX, it is big-endian.
+ if (K == WinCOFF)
+ support::endian::write32le(Buf, Size);
+ else if (K == XCOFF)
+ support::endian::write32be(Buf, Size);
+}
+
+// Returns the character at Pos from end of a string.
+static int charTailAt(StringPair *P, size_t Pos) {
+ StringRef S = P->first.val();
+ if (Pos >= S.size())
+ return -1;
+ return (unsigned char)S[S.size() - Pos - 1];
+}
+
+// Three-way radix quicksort. This is much faster than std::sort with strcmp
+// because it does not compare characters that we already know the same.
+static void multikeySort(MutableArrayRef<StringPair *> Vec, int Pos) {
+tailcall:
+ if (Vec.size() <= 1)
+ return;
+
+ // Partition items so that items in [0, I) are greater than the pivot,
+ // [I, J) are the same as the pivot, and [J, Vec.size()) are less than
+ // the pivot.
+ int Pivot = charTailAt(Vec[0], Pos);
+ size_t I = 0;
+ size_t J = Vec.size();
+ for (size_t K = 1; K < J;) {
+ int C = charTailAt(Vec[K], Pos);
+ if (C > Pivot)
+ std::swap(Vec[I++], Vec[K++]);
+ else if (C < Pivot)
+ std::swap(Vec[--J], Vec[K]);
+ else
+ K++;
+ }
+
+ multikeySort(Vec.slice(0, I), Pos);
+ multikeySort(Vec.slice(J), Pos);
+
+ // multikeySort(Vec.slice(I, J - I), Pos + 1), but with
+ // tail call optimization.
+ if (Pivot != -1) {
+ Vec = Vec.slice(I, J - I);
+ ++Pos;
+ goto tailcall;
+ }
+}
+
+void StringTableBuilder::finalize() {
+ assert(K != DWARF);
+ finalizeStringTable(/*Optimize=*/true);
+}
+
+void StringTableBuilder::finalizeInOrder() {
+ finalizeStringTable(/*Optimize=*/false);
+}
+
+void StringTableBuilder::finalizeStringTable(bool Optimize) {
+ Finalized = true;
+
+ if (Optimize) {
+ std::vector<StringPair *> Strings;
+ Strings.reserve(StringIndexMap.size());
+ for (StringPair &P : StringIndexMap)
+ Strings.push_back(&P);
+
+ multikeySort(Strings, 0);
+ initSize();
+
+ StringRef Previous;
+ for (StringPair *P : Strings) {
+ StringRef S = P->first.val();
+ if (Previous.endswith(S)) {
+ size_t Pos = Size - S.size() - (K != RAW);
+ if (!(Pos & (Alignment - 1))) {
+ P->second = Pos;
+ continue;
+ }
+ }
+
+ Size = alignTo(Size, Alignment);
+ P->second = Size;
+
+ Size += S.size();
+ if (K != RAW)
+ ++Size;
+ Previous = S;
+ }
+ }
+
+ if (K == MachO)
+ Size = alignTo(Size, 4); // Pad to multiple of 4.
+
+ // The first byte in an ELF string table must be null, according to the ELF
+ // specification. In 'initSize()' we reserved the first byte to hold null for
+ // this purpose and here we actually add the string to allow 'getOffset()' to
+ // be called on an empty string.
+ if (K == ELF)
+ StringIndexMap[CachedHashStringRef("")] = 0;
+}
+
+void StringTableBuilder::clear() {
+ Finalized = false;
+ StringIndexMap.clear();
+}
+
+size_t StringTableBuilder::getOffset(CachedHashStringRef S) const {
+ assert(isFinalized());
+ auto I = StringIndexMap.find(S);
+ assert(I != StringIndexMap.end() && "String is not in table!");
+ return I->second;
+}
+
+size_t StringTableBuilder::add(CachedHashStringRef S) {
+ if (K == WinCOFF)
+ assert(S.size() > COFF::NameSize && "Short string in COFF string table!");
+
+ assert(!isFinalized());
+ auto P = StringIndexMap.insert(std::make_pair(S, 0));
+ if (P.second) {
+ size_t Start = alignTo(Size, Alignment);
+ P.first->second = Start;
+ Size = Start + S.size() + (K != RAW);
+ }
+ return P.first->second;
+}
diff --git a/llvm/lib/MC/SubtargetFeature.cpp b/llvm/lib/MC/SubtargetFeature.cpp
new file mode 100644
index 000000000000..c4dd77359b24
--- /dev/null
+++ b/llvm/lib/MC/SubtargetFeature.cpp
@@ -0,0 +1,82 @@
+//===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+/// \file Implements the SubtargetFeature interface.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+#include <iterator>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+
+/// Splits a string of comma separated items in to a vector of strings.
+void SubtargetFeatures::Split(std::vector<std::string> &V, StringRef S) {
+ SmallVector<StringRef, 3> Tmp;
+ S.split(Tmp, ',', -1, false /* KeepEmpty */);
+ V.assign(Tmp.begin(), Tmp.end());
+}
+
+void SubtargetFeatures::AddFeature(StringRef String, bool Enable) {
+ // Don't add empty features.
+ if (!String.empty())
+ // Convert to lowercase, prepend flag if we don't already have a flag.
+ Features.push_back(hasFlag(String) ? String.lower()
+ : (Enable ? "+" : "-") + String.lower());
+}
+
+SubtargetFeatures::SubtargetFeatures(StringRef Initial) {
+ // Break up string into separate features
+ Split(Features, Initial);
+}
+
+std::string SubtargetFeatures::getString() const {
+ return join(Features.begin(), Features.end(), ",");
+}
+
+void SubtargetFeatures::print(raw_ostream &OS) const {
+ for (auto &F : Features)
+ OS << F << " ";
+ OS << "\n";
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void SubtargetFeatures::dump() const {
+ print(dbgs());
+}
+#endif
+
+void SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) {
+ // FIXME: This is an inelegant way of specifying the features of a
+ // subtarget. It would be better if we could encode this information
+ // into the IR. See <rdar://5972456>.
+ if (Triple.getVendor() == Triple::Apple) {
+ if (Triple.getArch() == Triple::ppc) {
+ // powerpc-apple-*
+ AddFeature("altivec");
+ } else if (Triple.getArch() == Triple::ppc64) {
+ // powerpc64-apple-*
+ AddFeature("64bit");
+ AddFeature("altivec");
+ }
+ }
+}
diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp
new file mode 100644
index 000000000000..c1ff3cc2480c
--- /dev/null
+++ b/llvm/lib/MC/WasmObjectWriter.cpp
@@ -0,0 +1,1599 @@
+//===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===//
+//
+// 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 implements Wasm object file writer information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSectionWasm.h"
+#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCWasmObjectWriter.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/StringSaver.h"
+#include <vector>
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mc"
+
+namespace {
+
+// Went we ceate the indirect function table we start at 1, so that there is
+// and emtpy slot at 0 and therefore calling a null function pointer will trap.
+static const uint32_t InitialTableOffset = 1;
+
+// For patching purposes, we need to remember where each section starts, both
+// for patching up the section size field, and for patching up references to
+// locations within the section.
+struct SectionBookkeeping {
+ // Where the size of the section is written.
+ uint64_t SizeOffset;
+ // Where the section header ends (without custom section name).
+ uint64_t PayloadOffset;
+ // Where the contents of the section starts.
+ uint64_t ContentsOffset;
+ uint32_t Index;
+};
+
+// The signature of a wasm function or event, in a struct capable of being used
+// as a DenseMap key.
+// TODO: Consider using wasm::WasmSignature directly instead.
+struct WasmSignature {
+ // Support empty and tombstone instances, needed by DenseMap.
+ enum { Plain, Empty, Tombstone } State = Plain;
+
+ // The return types of the function.
+ SmallVector<wasm::ValType, 1> Returns;
+
+ // The parameter types of the function.
+ SmallVector<wasm::ValType, 4> Params;
+
+ bool operator==(const WasmSignature &Other) const {
+ return State == Other.State && Returns == Other.Returns &&
+ Params == Other.Params;
+ }
+};
+
+// Traits for using WasmSignature in a DenseMap.
+struct WasmSignatureDenseMapInfo {
+ static WasmSignature getEmptyKey() {
+ WasmSignature Sig;
+ Sig.State = WasmSignature::Empty;
+ return Sig;
+ }
+ static WasmSignature getTombstoneKey() {
+ WasmSignature Sig;
+ Sig.State = WasmSignature::Tombstone;
+ return Sig;
+ }
+ static unsigned getHashValue(const WasmSignature &Sig) {
+ uintptr_t Value = Sig.State;
+ for (wasm::ValType Ret : Sig.Returns)
+ Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Ret));
+ for (wasm::ValType Param : Sig.Params)
+ Value += DenseMapInfo<uint32_t>::getHashValue(uint32_t(Param));
+ return Value;
+ }
+ static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) {
+ return LHS == RHS;
+ }
+};
+
+// A wasm data segment. A wasm binary contains only a single data section
+// but that can contain many segments, each with their own virtual location
+// in memory. Each MCSection data created by llvm is modeled as its own
+// wasm data segment.
+struct WasmDataSegment {
+ MCSectionWasm *Section;
+ StringRef Name;
+ uint32_t InitFlags;
+ uint32_t Offset;
+ uint32_t Alignment;
+ uint32_t LinkerFlags;
+ SmallVector<char, 4> Data;
+};
+
+// A wasm function to be written into the function section.
+struct WasmFunction {
+ uint32_t SigIndex;
+ const MCSymbolWasm *Sym;
+};
+
+// A wasm global to be written into the global section.
+struct WasmGlobal {
+ wasm::WasmGlobalType Type;
+ uint64_t InitialValue;
+};
+
+// Information about a single item which is part of a COMDAT. For each data
+// segment or function which is in the COMDAT, there is a corresponding
+// WasmComdatEntry.
+struct WasmComdatEntry {
+ unsigned Kind;
+ uint32_t Index;
+};
+
+// Information about a single relocation.
+struct WasmRelocationEntry {
+ uint64_t Offset; // Where is the relocation.
+ const MCSymbolWasm *Symbol; // The symbol to relocate with.
+ int64_t Addend; // A value to add to the symbol.
+ unsigned Type; // The type of the relocation.
+ const MCSectionWasm *FixupSection; // The section the relocation is targeting.
+
+ WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
+ int64_t Addend, unsigned Type,
+ const MCSectionWasm *FixupSection)
+ : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
+ FixupSection(FixupSection) {}
+
+ bool hasAddend() const { return wasm::relocTypeHasAddend(Type); }
+
+ void print(raw_ostream &Out) const {
+ Out << wasm::relocTypetoString(Type) << " Off=" << Offset
+ << ", Sym=" << *Symbol << ", Addend=" << Addend
+ << ", FixupSection=" << FixupSection->getSectionName();
+ }
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+ LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
+#endif
+};
+
+static const uint32_t InvalidIndex = -1;
+
+struct WasmCustomSection {
+
+ StringRef Name;
+ MCSectionWasm *Section;
+
+ uint32_t OutputContentsOffset;
+ uint32_t OutputIndex;
+
+ WasmCustomSection(StringRef Name, MCSectionWasm *Section)
+ : Name(Name), Section(Section), OutputContentsOffset(0),
+ OutputIndex(InvalidIndex) {}
+};
+
+#if !defined(NDEBUG)
+raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) {
+ Rel.print(OS);
+ return OS;
+}
+#endif
+
+// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
+// to allow patching.
+static void writePatchableLEB(raw_pwrite_stream &Stream, uint32_t X,
+ uint64_t Offset) {
+ uint8_t Buffer[5];
+ unsigned SizeLen = encodeULEB128(X, Buffer, 5);
+ assert(SizeLen == 5);
+ Stream.pwrite((char *)Buffer, SizeLen, Offset);
+}
+
+// Write X as an signed LEB value at offset Offset in Stream, padded
+// to allow patching.
+static void writePatchableSLEB(raw_pwrite_stream &Stream, int32_t X,
+ uint64_t Offset) {
+ uint8_t Buffer[5];
+ unsigned SizeLen = encodeSLEB128(X, Buffer, 5);
+ assert(SizeLen == 5);
+ Stream.pwrite((char *)Buffer, SizeLen, Offset);
+}
+
+// Write X as a plain integer value at offset Offset in Stream.
+static void writeI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
+ uint8_t Buffer[4];
+ support::endian::write32le(Buffer, X);
+ Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
+}
+
+class WasmObjectWriter : public MCObjectWriter {
+ support::endian::Writer W;
+
+ /// The target specific Wasm writer instance.
+ std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
+
+ // Relocations for fixing up references in the code section.
+ std::vector<WasmRelocationEntry> CodeRelocations;
+ uint32_t CodeSectionIndex;
+
+ // Relocations for fixing up references in the data section.
+ std::vector<WasmRelocationEntry> DataRelocations;
+ uint32_t DataSectionIndex;
+
+ // Index values to use for fixing up call_indirect type indices.
+ // Maps function symbols to the index of the type of the function
+ DenseMap<const MCSymbolWasm *, uint32_t> TypeIndices;
+ // Maps function symbols to the table element index space. Used
+ // for TABLE_INDEX relocation types (i.e. address taken functions).
+ DenseMap<const MCSymbolWasm *, uint32_t> TableIndices;
+ // Maps function/global symbols to the function/global/event/section index
+ // space.
+ DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices;
+ DenseMap<const MCSymbolWasm *, uint32_t> GOTIndices;
+ // Maps data symbols to the Wasm segment and offset/size with the segment.
+ DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations;
+
+ // Stores output data (index, relocations, content offset) for custom
+ // section.
+ std::vector<WasmCustomSection> CustomSections;
+ std::unique_ptr<WasmCustomSection> ProducersSection;
+ std::unique_ptr<WasmCustomSection> TargetFeaturesSection;
+ // Relocations for fixing up references in the custom sections.
+ DenseMap<const MCSectionWasm *, std::vector<WasmRelocationEntry>>
+ CustomSectionsRelocations;
+
+ // Map from section to defining function symbol.
+ DenseMap<const MCSection *, const MCSymbol *> SectionFunctions;
+
+ DenseMap<WasmSignature, uint32_t, WasmSignatureDenseMapInfo> SignatureIndices;
+ SmallVector<WasmSignature, 4> Signatures;
+ SmallVector<WasmDataSegment, 4> DataSegments;
+ unsigned NumFunctionImports = 0;
+ unsigned NumGlobalImports = 0;
+ unsigned NumEventImports = 0;
+ uint32_t SectionCount = 0;
+
+ // TargetObjectWriter wrappers.
+ bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
+ bool isEmscripten() const { return TargetObjectWriter->isEmscripten(); }
+
+ void startSection(SectionBookkeeping &Section, unsigned SectionId);
+ void startCustomSection(SectionBookkeeping &Section, StringRef Name);
+ void endSection(SectionBookkeeping &Section);
+
+public:
+ WasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS)
+ : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {}
+
+private:
+ void reset() override {
+ CodeRelocations.clear();
+ DataRelocations.clear();
+ TypeIndices.clear();
+ WasmIndices.clear();
+ GOTIndices.clear();
+ TableIndices.clear();
+ DataLocations.clear();
+ CustomSections.clear();
+ ProducersSection.reset();
+ TargetFeaturesSection.reset();
+ CustomSectionsRelocations.clear();
+ SignatureIndices.clear();
+ Signatures.clear();
+ DataSegments.clear();
+ SectionFunctions.clear();
+ NumFunctionImports = 0;
+ NumGlobalImports = 0;
+ MCObjectWriter::reset();
+ }
+
+ void writeHeader(const MCAssembler &Asm);
+
+ void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, uint64_t &FixedValue) override;
+
+ void executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) override;
+
+ uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+
+ void writeString(const StringRef Str) {
+ encodeULEB128(Str.size(), W.OS);
+ W.OS << Str;
+ }
+
+ void writeValueType(wasm::ValType Ty) { W.OS << static_cast<char>(Ty); }
+
+ void writeTypeSection(ArrayRef<WasmSignature> Signatures);
+ void writeImportSection(ArrayRef<wasm::WasmImport> Imports, uint32_t DataSize,
+ uint32_t NumElements);
+ void writeFunctionSection(ArrayRef<WasmFunction> Functions);
+ void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
+ void writeElemSection(ArrayRef<uint32_t> TableElems);
+ void writeDataCountSection();
+ void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ ArrayRef<WasmFunction> Functions);
+ void writeDataSection();
+ void writeEventSection(ArrayRef<wasm::WasmEventType> Events);
+ void writeRelocSection(uint32_t SectionIndex, StringRef Name,
+ std::vector<WasmRelocationEntry> &Relocations);
+ void writeLinkingMetaDataSection(
+ ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
+ ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
+ const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats);
+ void writeCustomSection(WasmCustomSection &CustomSection,
+ const MCAssembler &Asm, const MCAsmLayout &Layout);
+ void writeCustomRelocSections();
+ void
+ updateCustomSectionRelocations(const SmallVector<WasmFunction, 4> &Functions,
+ const MCAsmLayout &Layout);
+
+ uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry);
+ void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations,
+ uint64_t ContentsOffset);
+
+ uint32_t getRelocationIndexValue(const WasmRelocationEntry &RelEntry);
+ uint32_t getFunctionType(const MCSymbolWasm &Symbol);
+ uint32_t getEventType(const MCSymbolWasm &Symbol);
+ void registerFunctionType(const MCSymbolWasm &Symbol);
+ void registerEventType(const MCSymbolWasm &Symbol);
+};
+
+} // end anonymous namespace
+
+// Write out a section header and a patchable section size field.
+void WasmObjectWriter::startSection(SectionBookkeeping &Section,
+ unsigned SectionId) {
+ LLVM_DEBUG(dbgs() << "startSection " << SectionId << "\n");
+ W.OS << char(SectionId);
+
+ Section.SizeOffset = W.OS.tell();
+
+ // The section size. We don't know the size yet, so reserve enough space
+ // for any 32-bit value; we'll patch it later.
+ encodeULEB128(0, W.OS, 5);
+
+ // The position where the section starts, for measuring its size.
+ Section.ContentsOffset = W.OS.tell();
+ Section.PayloadOffset = W.OS.tell();
+ Section.Index = SectionCount++;
+}
+
+void WasmObjectWriter::startCustomSection(SectionBookkeeping &Section,
+ StringRef Name) {
+ LLVM_DEBUG(dbgs() << "startCustomSection " << Name << "\n");
+ startSection(Section, wasm::WASM_SEC_CUSTOM);
+
+ // The position where the section header ends, for measuring its size.
+ Section.PayloadOffset = W.OS.tell();
+
+ // Custom sections in wasm also have a string identifier.
+ writeString(Name);
+
+ // The position where the custom section starts.
+ Section.ContentsOffset = W.OS.tell();
+}
+
+// Now that the section is complete and we know how big it is, patch up the
+// section size field at the start of the section.
+void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
+ uint64_t Size = W.OS.tell();
+ // /dev/null doesn't support seek/tell and can report offset of 0.
+ // Simply skip this patching in that case.
+ if (!Size)
+ return;
+
+ Size -= Section.PayloadOffset;
+ if (uint32_t(Size) != Size)
+ report_fatal_error("section size does not fit in a uint32_t");
+
+ LLVM_DEBUG(dbgs() << "endSection size=" << Size << "\n");
+
+ // Write the final section size to the payload_len field, which follows
+ // the section id byte.
+ writePatchableLEB(static_cast<raw_pwrite_stream &>(W.OS), Size,
+ Section.SizeOffset);
+}
+
+// Emit the Wasm header.
+void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
+ W.OS.write(wasm::WasmMagic, sizeof(wasm::WasmMagic));
+ W.write<uint32_t>(wasm::WasmVersion);
+}
+
+void WasmObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ // Build a map of sections to the function that defines them, for use
+ // in recordRelocation.
+ for (const MCSymbol &S : Asm.symbols()) {
+ const auto &WS = static_cast<const MCSymbolWasm &>(S);
+ if (WS.isDefined() && WS.isFunction() && !WS.isVariable()) {
+ const auto &Sec = static_cast<const MCSectionWasm &>(S.getSection());
+ auto Pair = SectionFunctions.insert(std::make_pair(&Sec, &S));
+ if (!Pair.second)
+ report_fatal_error("section already has a defining function: " +
+ Sec.getSectionName());
+ }
+ }
+}
+
+void WasmObjectWriter::recordRelocation(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ // The WebAssembly backend should never generate FKF_IsPCRel fixups
+ assert(!(Asm.getBackend().getFixupKindInfo(Fixup.getKind()).Flags &
+ MCFixupKindInfo::FKF_IsPCRel));
+
+ const auto &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
+ uint64_t C = Target.getConstant();
+ uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+ MCContext &Ctx = Asm.getContext();
+
+ // The .init_array isn't translated as data, so don't do relocations in it.
+ if (FixupSection.getSectionName().startswith(".init_array"))
+ return;
+
+ if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
+ // To get here the A - B expression must have failed evaluateAsRelocatable.
+ // This means either A or B must be undefined and in WebAssembly we can't
+ // support either of those cases.
+ const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
+ Ctx.reportError(
+ Fixup.getLoc(),
+ Twine("symbol '") + SymB.getName() +
+ "': unsupported subtraction expression used in relocation.");
+ return;
+ }
+
+ // We either rejected the fixup or folded B into C at this point.
+ const MCSymbolRefExpr *RefA = Target.getSymA();
+ const auto *SymA = cast<MCSymbolWasm>(&RefA->getSymbol());
+
+ if (SymA->isVariable()) {
+ const MCExpr *Expr = SymA->getVariableValue();
+ const auto *Inner = cast<MCSymbolRefExpr>(Expr);
+ if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF)
+ llvm_unreachable("weakref used in reloc not yet implemented");
+ }
+
+ // Put any constant offset in an addend. Offsets can be negative, and
+ // LLVM expects wrapping, in contrast to wasm's immediates which can't
+ // be negative and don't wrap.
+ FixedValue = 0;
+
+ unsigned Type = TargetObjectWriter->getRelocType(Target, Fixup);
+
+ // Absolute offset within a section or a function.
+ // Currently only supported for for metadata sections.
+ // See: test/MC/WebAssembly/blockaddress.ll
+ if (Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
+ Type == wasm::R_WASM_SECTION_OFFSET_I32) {
+ if (!FixupSection.getKind().isMetadata())
+ report_fatal_error("relocations for function or section offsets are "
+ "only supported in metadata sections");
+
+ const MCSymbol *SectionSymbol = nullptr;
+ const MCSection &SecA = SymA->getSection();
+ if (SecA.getKind().isText())
+ SectionSymbol = SectionFunctions.find(&SecA)->second;
+ else
+ SectionSymbol = SecA.getBeginSymbol();
+ if (!SectionSymbol)
+ report_fatal_error("section symbol is required for relocation");
+
+ C += Layout.getSymbolOffset(*SymA);
+ SymA = cast<MCSymbolWasm>(SectionSymbol);
+ }
+
+ // Relocation other than R_WASM_TYPE_INDEX_LEB are required to be
+ // against a named symbol.
+ if (Type != wasm::R_WASM_TYPE_INDEX_LEB) {
+ if (SymA->getName().empty())
+ report_fatal_error("relocations against un-named temporaries are not yet "
+ "supported by wasm");
+
+ SymA->setUsedInReloc();
+ }
+
+ if (RefA->getKind() == MCSymbolRefExpr::VK_GOT)
+ SymA->setUsedInGOT();
+
+ WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
+ LLVM_DEBUG(dbgs() << "WasmReloc: " << Rec << "\n");
+
+ if (FixupSection.isWasmData()) {
+ DataRelocations.push_back(Rec);
+ } else if (FixupSection.getKind().isText()) {
+ CodeRelocations.push_back(Rec);
+ } else if (FixupSection.getKind().isMetadata()) {
+ CustomSectionsRelocations[&FixupSection].push_back(Rec);
+ } else {
+ llvm_unreachable("unexpected section type");
+ }
+}
+
+static const MCSymbolWasm *resolveSymbol(const MCSymbolWasm &Symbol) {
+ const MCSymbolWasm* Ret = &Symbol;
+ while (Ret->isVariable()) {
+ const MCExpr *Expr = Ret->getVariableValue();
+ auto *Inner = cast<MCSymbolRefExpr>(Expr);
+ Ret = cast<MCSymbolWasm>(&Inner->getSymbol());
+ }
+ return Ret;
+}
+
+// Compute a value to write into the code at the location covered
+// by RelEntry. This value isn't used by the static linker; it just serves
+// to make the object format more readable and more likely to be directly
+// useable.
+uint32_t
+WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) {
+ if (RelEntry.Type == wasm::R_WASM_GLOBAL_INDEX_LEB && !RelEntry.Symbol->isGlobal()) {
+ assert(GOTIndices.count(RelEntry.Symbol) > 0 && "symbol not found in GOT index space");
+ return GOTIndices[RelEntry.Symbol];
+ }
+
+ switch (RelEntry.Type) {
+ case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_I32: {
+ // Provisional value is table address of the resolved symbol itself
+ const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
+ assert(Sym->isFunction());
+ return TableIndices[Sym];
+ }
+ case wasm::R_WASM_TYPE_INDEX_LEB:
+ // Provisional value is same as the index
+ return getRelocationIndexValue(RelEntry);
+ case wasm::R_WASM_FUNCTION_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_LEB:
+ case wasm::R_WASM_EVENT_INDEX_LEB:
+ // Provisional value is function/global/event Wasm index
+ assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
+ return WasmIndices[RelEntry.Symbol];
+ case wasm::R_WASM_FUNCTION_OFFSET_I32:
+ case wasm::R_WASM_SECTION_OFFSET_I32: {
+ const auto &Section =
+ static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection());
+ return Section.getSectionOffset() + RelEntry.Addend;
+ }
+ case wasm::R_WASM_MEMORY_ADDR_LEB:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB: {
+ // Provisional value is address of the global
+ const MCSymbolWasm *Sym = resolveSymbol(*RelEntry.Symbol);
+ // For undefined symbols, use zero
+ if (!Sym->isDefined())
+ return 0;
+ const wasm::WasmDataReference &Ref = DataLocations[Sym];
+ const WasmDataSegment &Segment = DataSegments[Ref.Segment];
+ // Ignore overflow. LLVM allows address arithmetic to silently wrap.
+ return Segment.Offset + Ref.Offset + RelEntry.Addend;
+ }
+ default:
+ llvm_unreachable("invalid relocation type");
+ }
+}
+
+static void addData(SmallVectorImpl<char> &DataBytes,
+ MCSectionWasm &DataSection) {
+ LLVM_DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n");
+
+ DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
+
+ for (const MCFragment &Frag : DataSection) {
+ if (Frag.hasInstructions())
+ report_fatal_error("only data supported in data sections");
+
+ if (auto *Align = dyn_cast<MCAlignFragment>(&Frag)) {
+ if (Align->getValueSize() != 1)
+ report_fatal_error("only byte values supported for alignment");
+ // If nops are requested, use zeros, as this is the data section.
+ uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
+ uint64_t Size =
+ std::min<uint64_t>(alignTo(DataBytes.size(), Align->getAlignment()),
+ DataBytes.size() + Align->getMaxBytesToEmit());
+ DataBytes.resize(Size, Value);
+ } else if (auto *Fill = dyn_cast<MCFillFragment>(&Frag)) {
+ int64_t NumValues;
+ if (!Fill->getNumValues().evaluateAsAbsolute(NumValues))
+ llvm_unreachable("The fill should be an assembler constant");
+ DataBytes.insert(DataBytes.end(), Fill->getValueSize() * NumValues,
+ Fill->getValue());
+ } else if (auto *LEB = dyn_cast<MCLEBFragment>(&Frag)) {
+ const SmallVectorImpl<char> &Contents = LEB->getContents();
+ DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
+ } else {
+ const auto &DataFrag = cast<MCDataFragment>(Frag);
+ const SmallVectorImpl<char> &Contents = DataFrag.getContents();
+ DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
+ }
+ }
+
+ LLVM_DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n");
+}
+
+uint32_t
+WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) {
+ if (RelEntry.Type == wasm::R_WASM_TYPE_INDEX_LEB) {
+ if (!TypeIndices.count(RelEntry.Symbol))
+ report_fatal_error("symbol not found in type index space: " +
+ RelEntry.Symbol->getName());
+ return TypeIndices[RelEntry.Symbol];
+ }
+
+ return RelEntry.Symbol->getIndex();
+}
+
+// Apply the portions of the relocation records that we can handle ourselves
+// directly.
+void WasmObjectWriter::applyRelocations(
+ ArrayRef<WasmRelocationEntry> Relocations, uint64_t ContentsOffset) {
+ auto &Stream = static_cast<raw_pwrite_stream &>(W.OS);
+ for (const WasmRelocationEntry &RelEntry : Relocations) {
+ uint64_t Offset = ContentsOffset +
+ RelEntry.FixupSection->getSectionOffset() +
+ RelEntry.Offset;
+
+ LLVM_DEBUG(dbgs() << "applyRelocation: " << RelEntry << "\n");
+ uint32_t Value = getProvisionalValue(RelEntry);
+
+ switch (RelEntry.Type) {
+ case wasm::R_WASM_FUNCTION_INDEX_LEB:
+ case wasm::R_WASM_TYPE_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_LEB:
+ case wasm::R_WASM_MEMORY_ADDR_LEB:
+ case wasm::R_WASM_EVENT_INDEX_LEB:
+ writePatchableLEB(Stream, Value, Offset);
+ break;
+ case wasm::R_WASM_TABLE_INDEX_I32:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_FUNCTION_OFFSET_I32:
+ case wasm::R_WASM_SECTION_OFFSET_I32:
+ writeI32(Stream, Value, Offset);
+ break;
+ case wasm::R_WASM_TABLE_INDEX_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
+ writePatchableSLEB(Stream, Value, Offset);
+ break;
+ default:
+ llvm_unreachable("invalid relocation type");
+ }
+ }
+}
+
+void WasmObjectWriter::writeTypeSection(ArrayRef<WasmSignature> Signatures) {
+ if (Signatures.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_TYPE);
+
+ encodeULEB128(Signatures.size(), W.OS);
+
+ for (const WasmSignature &Sig : Signatures) {
+ W.OS << char(wasm::WASM_TYPE_FUNC);
+ encodeULEB128(Sig.Params.size(), W.OS);
+ for (wasm::ValType Ty : Sig.Params)
+ writeValueType(Ty);
+ encodeULEB128(Sig.Returns.size(), W.OS);
+ for (wasm::ValType Ty : Sig.Returns)
+ writeValueType(Ty);
+ }
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeImportSection(ArrayRef<wasm::WasmImport> Imports,
+ uint32_t DataSize,
+ uint32_t NumElements) {
+ if (Imports.empty())
+ return;
+
+ uint32_t NumPages = (DataSize + wasm::WasmPageSize - 1) / wasm::WasmPageSize;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_IMPORT);
+
+ encodeULEB128(Imports.size(), W.OS);
+ for (const wasm::WasmImport &Import : Imports) {
+ writeString(Import.Module);
+ writeString(Import.Field);
+ W.OS << char(Import.Kind);
+
+ switch (Import.Kind) {
+ case wasm::WASM_EXTERNAL_FUNCTION:
+ encodeULEB128(Import.SigIndex, W.OS);
+ break;
+ case wasm::WASM_EXTERNAL_GLOBAL:
+ W.OS << char(Import.Global.Type);
+ W.OS << char(Import.Global.Mutable ? 1 : 0);
+ break;
+ case wasm::WASM_EXTERNAL_MEMORY:
+ encodeULEB128(0, W.OS); // flags
+ encodeULEB128(NumPages, W.OS); // initial
+ break;
+ case wasm::WASM_EXTERNAL_TABLE:
+ W.OS << char(Import.Table.ElemType);
+ encodeULEB128(0, W.OS); // flags
+ encodeULEB128(NumElements, W.OS); // initial
+ break;
+ case wasm::WASM_EXTERNAL_EVENT:
+ encodeULEB128(Import.Event.Attribute, W.OS);
+ encodeULEB128(Import.Event.SigIndex, W.OS);
+ break;
+ default:
+ llvm_unreachable("unsupported import kind");
+ }
+ }
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeFunctionSection(ArrayRef<WasmFunction> Functions) {
+ if (Functions.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_FUNCTION);
+
+ encodeULEB128(Functions.size(), W.OS);
+ for (const WasmFunction &Func : Functions)
+ encodeULEB128(Func.SigIndex, W.OS);
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeEventSection(ArrayRef<wasm::WasmEventType> Events) {
+ if (Events.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_EVENT);
+
+ encodeULEB128(Events.size(), W.OS);
+ for (const wasm::WasmEventType &Event : Events) {
+ encodeULEB128(Event.Attribute, W.OS);
+ encodeULEB128(Event.SigIndex, W.OS);
+ }
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
+ if (Exports.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_EXPORT);
+
+ encodeULEB128(Exports.size(), W.OS);
+ for (const wasm::WasmExport &Export : Exports) {
+ writeString(Export.Name);
+ W.OS << char(Export.Kind);
+ encodeULEB128(Export.Index, W.OS);
+ }
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
+ if (TableElems.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_ELEM);
+
+ encodeULEB128(1, W.OS); // number of "segments"
+ encodeULEB128(0, W.OS); // the table index
+
+ // init expr for starting offset
+ W.OS << char(wasm::WASM_OPCODE_I32_CONST);
+ encodeSLEB128(InitialTableOffset, W.OS);
+ W.OS << char(wasm::WASM_OPCODE_END);
+
+ encodeULEB128(TableElems.size(), W.OS);
+ for (uint32_t Elem : TableElems)
+ encodeULEB128(Elem, W.OS);
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeDataCountSection() {
+ if (DataSegments.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_DATACOUNT);
+ encodeULEB128(DataSegments.size(), W.OS);
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ ArrayRef<WasmFunction> Functions) {
+ if (Functions.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_CODE);
+ CodeSectionIndex = Section.Index;
+
+ encodeULEB128(Functions.size(), W.OS);
+
+ for (const WasmFunction &Func : Functions) {
+ auto &FuncSection = static_cast<MCSectionWasm &>(Func.Sym->getSection());
+
+ int64_t Size = 0;
+ if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
+ report_fatal_error(".size expression must be evaluatable");
+
+ encodeULEB128(Size, W.OS);
+ FuncSection.setSectionOffset(W.OS.tell() - Section.ContentsOffset);
+ Asm.writeSectionData(W.OS, &FuncSection, Layout);
+ }
+
+ // Apply fixups.
+ applyRelocations(CodeRelocations, Section.ContentsOffset);
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeDataSection() {
+ if (DataSegments.empty())
+ return;
+
+ SectionBookkeeping Section;
+ startSection(Section, wasm::WASM_SEC_DATA);
+ DataSectionIndex = Section.Index;
+
+ encodeULEB128(DataSegments.size(), W.OS); // count
+
+ for (const WasmDataSegment &Segment : DataSegments) {
+ encodeULEB128(Segment.InitFlags, W.OS); // flags
+ if (Segment.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
+ encodeULEB128(0, W.OS); // memory index
+ if ((Segment.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
+ W.OS << char(wasm::WASM_OPCODE_I32_CONST);
+ encodeSLEB128(Segment.Offset, W.OS); // offset
+ W.OS << char(wasm::WASM_OPCODE_END);
+ }
+ encodeULEB128(Segment.Data.size(), W.OS); // size
+ Segment.Section->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
+ W.OS << Segment.Data; // data
+ }
+
+ // Apply fixups.
+ applyRelocations(DataRelocations, Section.ContentsOffset);
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeRelocSection(
+ uint32_t SectionIndex, StringRef Name,
+ std::vector<WasmRelocationEntry> &Relocs) {
+ // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
+ // for descriptions of the reloc sections.
+
+ if (Relocs.empty())
+ return;
+
+ // First, ensure the relocations are sorted in offset order. In general they
+ // should already be sorted since `recordRelocation` is called in offset
+ // order, but for the code section we combine many MC sections into single
+ // wasm section, and this order is determined by the order of Asm.Symbols()
+ // not the sections order.
+ llvm::stable_sort(
+ Relocs, [](const WasmRelocationEntry &A, const WasmRelocationEntry &B) {
+ return (A.Offset + A.FixupSection->getSectionOffset()) <
+ (B.Offset + B.FixupSection->getSectionOffset());
+ });
+
+ SectionBookkeeping Section;
+ startCustomSection(Section, std::string("reloc.") + Name.str());
+
+ encodeULEB128(SectionIndex, W.OS);
+ encodeULEB128(Relocs.size(), W.OS);
+ for (const WasmRelocationEntry &RelEntry : Relocs) {
+ uint64_t Offset =
+ RelEntry.Offset + RelEntry.FixupSection->getSectionOffset();
+ uint32_t Index = getRelocationIndexValue(RelEntry);
+
+ W.OS << char(RelEntry.Type);
+ encodeULEB128(Offset, W.OS);
+ encodeULEB128(Index, W.OS);
+ if (RelEntry.hasAddend())
+ encodeSLEB128(RelEntry.Addend, W.OS);
+ }
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeCustomRelocSections() {
+ for (const auto &Sec : CustomSections) {
+ auto &Relocations = CustomSectionsRelocations[Sec.Section];
+ writeRelocSection(Sec.OutputIndex, Sec.Name, Relocations);
+ }
+}
+
+void WasmObjectWriter::writeLinkingMetaDataSection(
+ ArrayRef<wasm::WasmSymbolInfo> SymbolInfos,
+ ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs,
+ const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) {
+ SectionBookkeeping Section;
+ startCustomSection(Section, "linking");
+ encodeULEB128(wasm::WasmMetadataVersion, W.OS);
+
+ SectionBookkeeping SubSection;
+ if (SymbolInfos.size() != 0) {
+ startSection(SubSection, wasm::WASM_SYMBOL_TABLE);
+ encodeULEB128(SymbolInfos.size(), W.OS);
+ for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) {
+ encodeULEB128(Sym.Kind, W.OS);
+ encodeULEB128(Sym.Flags, W.OS);
+ switch (Sym.Kind) {
+ case wasm::WASM_SYMBOL_TYPE_FUNCTION:
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ case wasm::WASM_SYMBOL_TYPE_EVENT:
+ encodeULEB128(Sym.ElementIndex, W.OS);
+ if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 ||
+ (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
+ writeString(Sym.Name);
+ break;
+ case wasm::WASM_SYMBOL_TYPE_DATA:
+ writeString(Sym.Name);
+ if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) {
+ encodeULEB128(Sym.DataRef.Segment, W.OS);
+ encodeULEB128(Sym.DataRef.Offset, W.OS);
+ encodeULEB128(Sym.DataRef.Size, W.OS);
+ }
+ break;
+ case wasm::WASM_SYMBOL_TYPE_SECTION: {
+ const uint32_t SectionIndex =
+ CustomSections[Sym.ElementIndex].OutputIndex;
+ encodeULEB128(SectionIndex, W.OS);
+ break;
+ }
+ default:
+ llvm_unreachable("unexpected kind");
+ }
+ }
+ endSection(SubSection);
+ }
+
+ if (DataSegments.size()) {
+ startSection(SubSection, wasm::WASM_SEGMENT_INFO);
+ encodeULEB128(DataSegments.size(), W.OS);
+ for (const WasmDataSegment &Segment : DataSegments) {
+ writeString(Segment.Name);
+ encodeULEB128(Segment.Alignment, W.OS);
+ encodeULEB128(Segment.LinkerFlags, W.OS);
+ }
+ endSection(SubSection);
+ }
+
+ if (!InitFuncs.empty()) {
+ startSection(SubSection, wasm::WASM_INIT_FUNCS);
+ encodeULEB128(InitFuncs.size(), W.OS);
+ for (auto &StartFunc : InitFuncs) {
+ encodeULEB128(StartFunc.first, W.OS); // priority
+ encodeULEB128(StartFunc.second, W.OS); // function index
+ }
+ endSection(SubSection);
+ }
+
+ if (Comdats.size()) {
+ startSection(SubSection, wasm::WASM_COMDAT_INFO);
+ encodeULEB128(Comdats.size(), W.OS);
+ for (const auto &C : Comdats) {
+ writeString(C.first);
+ encodeULEB128(0, W.OS); // flags for future use
+ encodeULEB128(C.second.size(), W.OS);
+ for (const WasmComdatEntry &Entry : C.second) {
+ encodeULEB128(Entry.Kind, W.OS);
+ encodeULEB128(Entry.Index, W.OS);
+ }
+ }
+ endSection(SubSection);
+ }
+
+ endSection(Section);
+}
+
+void WasmObjectWriter::writeCustomSection(WasmCustomSection &CustomSection,
+ const MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ SectionBookkeeping Section;
+ auto *Sec = CustomSection.Section;
+ startCustomSection(Section, CustomSection.Name);
+
+ Sec->setSectionOffset(W.OS.tell() - Section.ContentsOffset);
+ Asm.writeSectionData(W.OS, Sec, Layout);
+
+ CustomSection.OutputContentsOffset = Section.ContentsOffset;
+ CustomSection.OutputIndex = Section.Index;
+
+ endSection(Section);
+
+ // Apply fixups.
+ auto &Relocations = CustomSectionsRelocations[CustomSection.Section];
+ applyRelocations(Relocations, CustomSection.OutputContentsOffset);
+}
+
+uint32_t WasmObjectWriter::getFunctionType(const MCSymbolWasm &Symbol) {
+ assert(Symbol.isFunction());
+ assert(TypeIndices.count(&Symbol));
+ return TypeIndices[&Symbol];
+}
+
+uint32_t WasmObjectWriter::getEventType(const MCSymbolWasm &Symbol) {
+ assert(Symbol.isEvent());
+ assert(TypeIndices.count(&Symbol));
+ return TypeIndices[&Symbol];
+}
+
+void WasmObjectWriter::registerFunctionType(const MCSymbolWasm &Symbol) {
+ assert(Symbol.isFunction());
+
+ WasmSignature S;
+ const MCSymbolWasm *ResolvedSym = resolveSymbol(Symbol);
+ if (auto *Sig = ResolvedSym->getSignature()) {
+ S.Returns = Sig->Returns;
+ S.Params = Sig->Params;
+ }
+
+ auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
+ if (Pair.second)
+ Signatures.push_back(S);
+ TypeIndices[&Symbol] = Pair.first->second;
+
+ LLVM_DEBUG(dbgs() << "registerFunctionType: " << Symbol
+ << " new:" << Pair.second << "\n");
+ LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
+}
+
+void WasmObjectWriter::registerEventType(const MCSymbolWasm &Symbol) {
+ assert(Symbol.isEvent());
+
+ // TODO Currently we don't generate imported exceptions, but if we do, we
+ // should have a way of infering types of imported exceptions.
+ WasmSignature S;
+ if (auto *Sig = Symbol.getSignature()) {
+ S.Returns = Sig->Returns;
+ S.Params = Sig->Params;
+ }
+
+ auto Pair = SignatureIndices.insert(std::make_pair(S, Signatures.size()));
+ if (Pair.second)
+ Signatures.push_back(S);
+ TypeIndices[&Symbol] = Pair.first->second;
+
+ LLVM_DEBUG(dbgs() << "registerEventType: " << Symbol << " new:" << Pair.second
+ << "\n");
+ LLVM_DEBUG(dbgs() << " -> type index: " << Pair.first->second << "\n");
+}
+
+static bool isInSymtab(const MCSymbolWasm &Sym) {
+ if (Sym.isUsedInReloc())
+ return true;
+
+ if (Sym.isComdat() && !Sym.isDefined())
+ return false;
+
+ if (Sym.isTemporary() && Sym.getName().empty())
+ return false;
+
+ if (Sym.isTemporary() && Sym.isData() && !Sym.getSize())
+ return false;
+
+ if (Sym.isSection())
+ return false;
+
+ return true;
+}
+
+uint64_t WasmObjectWriter::writeObject(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ uint64_t StartOffset = W.OS.tell();
+
+ LLVM_DEBUG(dbgs() << "WasmObjectWriter::writeObject\n");
+
+ // Collect information from the available symbols.
+ SmallVector<WasmFunction, 4> Functions;
+ SmallVector<uint32_t, 4> TableElems;
+ SmallVector<wasm::WasmImport, 4> Imports;
+ SmallVector<wasm::WasmExport, 4> Exports;
+ SmallVector<wasm::WasmEventType, 1> Events;
+ SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos;
+ SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs;
+ std::map<StringRef, std::vector<WasmComdatEntry>> Comdats;
+ uint32_t DataSize = 0;
+
+ // For now, always emit the memory import, since loads and stores are not
+ // valid without it. In the future, we could perhaps be more clever and omit
+ // it if there are no loads or stores.
+ wasm::WasmImport MemImport;
+ MemImport.Module = "env";
+ MemImport.Field = "__linear_memory";
+ MemImport.Kind = wasm::WASM_EXTERNAL_MEMORY;
+ Imports.push_back(MemImport);
+
+ // For now, always emit the table section, since indirect calls are not
+ // valid without it. In the future, we could perhaps be more clever and omit
+ // it if there are no indirect calls.
+ wasm::WasmImport TableImport;
+ TableImport.Module = "env";
+ TableImport.Field = "__indirect_function_table";
+ TableImport.Kind = wasm::WASM_EXTERNAL_TABLE;
+ TableImport.Table.ElemType = wasm::WASM_TYPE_FUNCREF;
+ Imports.push_back(TableImport);
+
+ // Populate SignatureIndices, and Imports and WasmIndices for undefined
+ // symbols. This must be done before populating WasmIndices for defined
+ // symbols.
+ for (const MCSymbol &S : Asm.symbols()) {
+ const auto &WS = static_cast<const MCSymbolWasm &>(S);
+
+ // Register types for all functions, including those with private linkage
+ // (because wasm always needs a type signature).
+ if (WS.isFunction())
+ registerFunctionType(WS);
+
+ if (WS.isEvent())
+ registerEventType(WS);
+
+ if (WS.isTemporary())
+ continue;
+
+ // If the symbol is not defined in this translation unit, import it.
+ if (!WS.isDefined() && !WS.isComdat()) {
+ if (WS.isFunction()) {
+ wasm::WasmImport Import;
+ Import.Module = WS.getImportModule();
+ Import.Field = WS.getImportName();
+ Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
+ Import.SigIndex = getFunctionType(WS);
+ Imports.push_back(Import);
+ assert(WasmIndices.count(&WS) == 0);
+ WasmIndices[&WS] = NumFunctionImports++;
+ } else if (WS.isGlobal()) {
+ if (WS.isWeak())
+ report_fatal_error("undefined global symbol cannot be weak");
+
+ wasm::WasmImport Import;
+ Import.Field = WS.getImportName();
+ Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
+ Import.Module = WS.getImportModule();
+ Import.Global = WS.getGlobalType();
+ Imports.push_back(Import);
+ assert(WasmIndices.count(&WS) == 0);
+ WasmIndices[&WS] = NumGlobalImports++;
+ } else if (WS.isEvent()) {
+ if (WS.isWeak())
+ report_fatal_error("undefined event symbol cannot be weak");
+
+ wasm::WasmImport Import;
+ Import.Module = WS.getImportModule();
+ Import.Field = WS.getImportName();
+ Import.Kind = wasm::WASM_EXTERNAL_EVENT;
+ Import.Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
+ Import.Event.SigIndex = getEventType(WS);
+ Imports.push_back(Import);
+ assert(WasmIndices.count(&WS) == 0);
+ WasmIndices[&WS] = NumEventImports++;
+ }
+ }
+ }
+
+ // Add imports for GOT globals
+ for (const MCSymbol &S : Asm.symbols()) {
+ const auto &WS = static_cast<const MCSymbolWasm &>(S);
+ if (WS.isUsedInGOT()) {
+ wasm::WasmImport Import;
+ if (WS.isFunction())
+ Import.Module = "GOT.func";
+ else
+ Import.Module = "GOT.mem";
+ Import.Field = WS.getName();
+ Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
+ Import.Global = {wasm::WASM_TYPE_I32, true};
+ Imports.push_back(Import);
+ assert(GOTIndices.count(&WS) == 0);
+ GOTIndices[&WS] = NumGlobalImports++;
+ }
+ }
+
+ // Populate DataSegments and CustomSections, which must be done before
+ // populating DataLocations.
+ for (MCSection &Sec : Asm) {
+ auto &Section = static_cast<MCSectionWasm &>(Sec);
+ StringRef SectionName = Section.getSectionName();
+
+ // .init_array sections are handled specially elsewhere.
+ if (SectionName.startswith(".init_array"))
+ continue;
+
+ // Code is handled separately
+ if (Section.getKind().isText())
+ continue;
+
+ if (Section.isWasmData()) {
+ uint32_t SegmentIndex = DataSegments.size();
+ DataSize = alignTo(DataSize, Section.getAlignment());
+ DataSegments.emplace_back();
+ WasmDataSegment &Segment = DataSegments.back();
+ Segment.Name = SectionName;
+ Segment.InitFlags =
+ Section.getPassive() ? (uint32_t)wasm::WASM_SEGMENT_IS_PASSIVE : 0;
+ Segment.Offset = DataSize;
+ Segment.Section = &Section;
+ addData(Segment.Data, Section);
+ Segment.Alignment = Log2_32(Section.getAlignment());
+ Segment.LinkerFlags = 0;
+ DataSize += Segment.Data.size();
+ Section.setSegmentIndex(SegmentIndex);
+
+ if (const MCSymbolWasm *C = Section.getGroup()) {
+ Comdats[C->getName()].emplace_back(
+ WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex});
+ }
+ } else {
+ // Create custom sections
+ assert(Sec.getKind().isMetadata());
+
+ StringRef Name = SectionName;
+
+ // For user-defined custom sections, strip the prefix
+ if (Name.startswith(".custom_section."))
+ Name = Name.substr(strlen(".custom_section."));
+
+ MCSymbol *Begin = Sec.getBeginSymbol();
+ if (Begin) {
+ WasmIndices[cast<MCSymbolWasm>(Begin)] = CustomSections.size();
+ if (SectionName != Begin->getName())
+ report_fatal_error("section name and begin symbol should match: " +
+ Twine(SectionName));
+ }
+
+ // Separate out the producers and target features sections
+ if (Name == "producers") {
+ ProducersSection = std::make_unique<WasmCustomSection>(Name, &Section);
+ continue;
+ }
+ if (Name == "target_features") {
+ TargetFeaturesSection =
+ std::make_unique<WasmCustomSection>(Name, &Section);
+ continue;
+ }
+
+ CustomSections.emplace_back(Name, &Section);
+ }
+ }
+
+ // Populate WasmIndices and DataLocations for defined symbols.
+ for (const MCSymbol &S : Asm.symbols()) {
+ // Ignore unnamed temporary symbols, which aren't ever exported, imported,
+ // or used in relocations.
+ if (S.isTemporary() && S.getName().empty())
+ continue;
+
+ const auto &WS = static_cast<const MCSymbolWasm &>(S);
+ LLVM_DEBUG(
+ dbgs() << "MCSymbol: " << toString(WS.getType()) << " '" << S << "'"
+ << " isDefined=" << S.isDefined() << " isExternal="
+ << S.isExternal() << " isTemporary=" << S.isTemporary()
+ << " isWeak=" << WS.isWeak() << " isHidden=" << WS.isHidden()
+ << " isVariable=" << WS.isVariable() << "\n");
+
+ if (WS.isVariable())
+ continue;
+ if (WS.isComdat() && !WS.isDefined())
+ continue;
+
+ if (WS.isFunction()) {
+ unsigned Index;
+ if (WS.isDefined()) {
+ if (WS.getOffset() != 0)
+ report_fatal_error(
+ "function sections must contain one function each");
+
+ if (WS.getSize() == nullptr)
+ report_fatal_error(
+ "function symbols must have a size set with .size");
+
+ // A definition. Write out the function body.
+ Index = NumFunctionImports + Functions.size();
+ WasmFunction Func;
+ Func.SigIndex = getFunctionType(WS);
+ Func.Sym = &WS;
+ WasmIndices[&WS] = Index;
+ Functions.push_back(Func);
+
+ auto &Section = static_cast<MCSectionWasm &>(WS.getSection());
+ if (const MCSymbolWasm *C = Section.getGroup()) {
+ Comdats[C->getName()].emplace_back(
+ WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index});
+ }
+ } else {
+ // An import; the index was assigned above.
+ Index = WasmIndices.find(&WS)->second;
+ }
+
+ LLVM_DEBUG(dbgs() << " -> function index: " << Index << "\n");
+
+ } else if (WS.isData()) {
+ if (!isInSymtab(WS))
+ continue;
+
+ if (!WS.isDefined()) {
+ LLVM_DEBUG(dbgs() << " -> segment index: -1"
+ << "\n");
+ continue;
+ }
+
+ if (!WS.getSize())
+ report_fatal_error("data symbols must have a size set with .size: " +
+ WS.getName());
+
+ int64_t Size = 0;
+ if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
+ report_fatal_error(".size expression must be evaluatable");
+
+ auto &DataSection = static_cast<MCSectionWasm &>(WS.getSection());
+ if (!DataSection.isWasmData())
+ report_fatal_error("data symbols must live in a data section: " +
+ WS.getName());
+
+ // For each data symbol, export it in the symtab as a reference to the
+ // corresponding Wasm data segment.
+ wasm::WasmDataReference Ref = wasm::WasmDataReference{
+ DataSection.getSegmentIndex(),
+ static_cast<uint32_t>(Layout.getSymbolOffset(WS)),
+ static_cast<uint32_t>(Size)};
+ DataLocations[&WS] = Ref;
+ LLVM_DEBUG(dbgs() << " -> segment index: " << Ref.Segment << "\n");
+
+ } else if (WS.isGlobal()) {
+ // A "true" Wasm global (currently just __stack_pointer)
+ if (WS.isDefined())
+ report_fatal_error("don't yet support defined globals");
+
+ // An import; the index was assigned above
+ LLVM_DEBUG(dbgs() << " -> global index: "
+ << WasmIndices.find(&WS)->second << "\n");
+
+ } else if (WS.isEvent()) {
+ // C++ exception symbol (__cpp_exception)
+ unsigned Index;
+ if (WS.isDefined()) {
+ Index = NumEventImports + Events.size();
+ wasm::WasmEventType Event;
+ Event.SigIndex = getEventType(WS);
+ Event.Attribute = wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION;
+ assert(WasmIndices.count(&WS) == 0);
+ WasmIndices[&WS] = Index;
+ Events.push_back(Event);
+ } else {
+ // An import; the index was assigned above.
+ assert(WasmIndices.count(&WS) > 0);
+ }
+ LLVM_DEBUG(dbgs() << " -> event index: " << WasmIndices.find(&WS)->second
+ << "\n");
+
+ } else {
+ assert(WS.isSection());
+ }
+ }
+
+ // Populate WasmIndices and DataLocations for aliased symbols. We need to
+ // process these in a separate pass because we need to have processed the
+ // target of the alias before the alias itself and the symbols are not
+ // necessarily ordered in this way.
+ for (const MCSymbol &S : Asm.symbols()) {
+ if (!S.isVariable())
+ continue;
+
+ assert(S.isDefined());
+
+ // Find the target symbol of this weak alias and export that index
+ const auto &WS = static_cast<const MCSymbolWasm &>(S);
+ const MCSymbolWasm *ResolvedSym = resolveSymbol(WS);
+ LLVM_DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym
+ << "'\n");
+
+ if (ResolvedSym->isFunction()) {
+ assert(WasmIndices.count(ResolvedSym) > 0);
+ uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second;
+ assert(WasmIndices.count(&WS) == 0);
+ WasmIndices[&WS] = WasmIndex;
+ LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n");
+ } else if (ResolvedSym->isData()) {
+ assert(DataLocations.count(ResolvedSym) > 0);
+ const wasm::WasmDataReference &Ref =
+ DataLocations.find(ResolvedSym)->second;
+ DataLocations[&WS] = Ref;
+ LLVM_DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n");
+ } else {
+ report_fatal_error("don't yet support global/event aliases");
+ }
+ }
+
+ // Finally, populate the symbol table itself, in its "natural" order.
+ for (const MCSymbol &S : Asm.symbols()) {
+ const auto &WS = static_cast<const MCSymbolWasm &>(S);
+ if (!isInSymtab(WS)) {
+ WS.setIndex(InvalidIndex);
+ continue;
+ }
+ LLVM_DEBUG(dbgs() << "adding to symtab: " << WS << "\n");
+
+ uint32_t Flags = 0;
+ if (WS.isWeak())
+ Flags |= wasm::WASM_SYMBOL_BINDING_WEAK;
+ if (WS.isHidden())
+ Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN;
+ if (!WS.isExternal() && WS.isDefined())
+ Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
+ if (WS.isUndefined())
+ Flags |= wasm::WASM_SYMBOL_UNDEFINED;
+ if (WS.isNoStrip()) {
+ Flags |= wasm::WASM_SYMBOL_NO_STRIP;
+ if (isEmscripten()) {
+ Flags |= wasm::WASM_SYMBOL_EXPORTED;
+ }
+ }
+ if (WS.getName() != WS.getImportName())
+ Flags |= wasm::WASM_SYMBOL_EXPLICIT_NAME;
+
+ wasm::WasmSymbolInfo Info;
+ Info.Name = WS.getName();
+ Info.Kind = WS.getType();
+ Info.Flags = Flags;
+ if (!WS.isData()) {
+ assert(WasmIndices.count(&WS) > 0);
+ Info.ElementIndex = WasmIndices.find(&WS)->second;
+ } else if (WS.isDefined()) {
+ assert(DataLocations.count(&WS) > 0);
+ Info.DataRef = DataLocations.find(&WS)->second;
+ }
+ WS.setIndex(SymbolInfos.size());
+ SymbolInfos.emplace_back(Info);
+ }
+
+ {
+ auto HandleReloc = [&](const WasmRelocationEntry &Rel) {
+ // Functions referenced by a relocation need to put in the table. This is
+ // purely to make the object file's provisional values readable, and is
+ // ignored by the linker, which re-calculates the relocations itself.
+ if (Rel.Type != wasm::R_WASM_TABLE_INDEX_I32 &&
+ Rel.Type != wasm::R_WASM_TABLE_INDEX_SLEB)
+ return;
+ assert(Rel.Symbol->isFunction());
+ const MCSymbolWasm &WS = *resolveSymbol(*Rel.Symbol);
+ uint32_t FunctionIndex = WasmIndices.find(&WS)->second;
+ uint32_t TableIndex = TableElems.size() + InitialTableOffset;
+ if (TableIndices.try_emplace(&WS, TableIndex).second) {
+ LLVM_DEBUG(dbgs() << " -> adding " << WS.getName()
+ << " to table: " << TableIndex << "\n");
+ TableElems.push_back(FunctionIndex);
+ registerFunctionType(WS);
+ }
+ };
+
+ for (const WasmRelocationEntry &RelEntry : CodeRelocations)
+ HandleReloc(RelEntry);
+ for (const WasmRelocationEntry &RelEntry : DataRelocations)
+ HandleReloc(RelEntry);
+ }
+
+ // Translate .init_array section contents into start functions.
+ for (const MCSection &S : Asm) {
+ const auto &WS = static_cast<const MCSectionWasm &>(S);
+ if (WS.getSectionName().startswith(".fini_array"))
+ report_fatal_error(".fini_array sections are unsupported");
+ if (!WS.getSectionName().startswith(".init_array"))
+ continue;
+ if (WS.getFragmentList().empty())
+ continue;
+
+ // init_array is expected to contain a single non-empty data fragment
+ if (WS.getFragmentList().size() != 3)
+ report_fatal_error("only one .init_array section fragment supported");
+
+ auto IT = WS.begin();
+ const MCFragment &EmptyFrag = *IT;
+ if (EmptyFrag.getKind() != MCFragment::FT_Data)
+ report_fatal_error(".init_array section should be aligned");
+
+ IT = std::next(IT);
+ const MCFragment &AlignFrag = *IT;
+ if (AlignFrag.getKind() != MCFragment::FT_Align)
+ report_fatal_error(".init_array section should be aligned");
+ if (cast<MCAlignFragment>(AlignFrag).getAlignment() != (is64Bit() ? 8 : 4))
+ report_fatal_error(".init_array section should be aligned for pointers");
+
+ const MCFragment &Frag = *std::next(IT);
+ if (Frag.hasInstructions() || Frag.getKind() != MCFragment::FT_Data)
+ report_fatal_error("only data supported in .init_array section");
+
+ uint16_t Priority = UINT16_MAX;
+ unsigned PrefixLength = strlen(".init_array");
+ if (WS.getSectionName().size() > PrefixLength) {
+ if (WS.getSectionName()[PrefixLength] != '.')
+ report_fatal_error(
+ ".init_array section priority should start with '.'");
+ if (WS.getSectionName()
+ .substr(PrefixLength + 1)
+ .getAsInteger(10, Priority))
+ report_fatal_error("invalid .init_array section priority");
+ }
+ const auto &DataFrag = cast<MCDataFragment>(Frag);
+ const SmallVectorImpl<char> &Contents = DataFrag.getContents();
+ for (const uint8_t *
+ P = (const uint8_t *)Contents.data(),
+ *End = (const uint8_t *)Contents.data() + Contents.size();
+ P != End; ++P) {
+ if (*P != 0)
+ report_fatal_error("non-symbolic data in .init_array section");
+ }
+ for (const MCFixup &Fixup : DataFrag.getFixups()) {
+ assert(Fixup.getKind() ==
+ MCFixup::getKindForSize(is64Bit() ? 8 : 4, false));
+ const MCExpr *Expr = Fixup.getValue();
+ auto *SymRef = dyn_cast<MCSymbolRefExpr>(Expr);
+ if (!SymRef)
+ report_fatal_error("fixups in .init_array should be symbol references");
+ const auto &TargetSym = cast<const MCSymbolWasm>(SymRef->getSymbol());
+ if (TargetSym.getIndex() == InvalidIndex)
+ report_fatal_error("symbols in .init_array should exist in symbtab");
+ if (!TargetSym.isFunction())
+ report_fatal_error("symbols in .init_array should be for functions");
+ InitFuncs.push_back(
+ std::make_pair(Priority, TargetSym.getIndex()));
+ }
+ }
+
+ // Write out the Wasm header.
+ writeHeader(Asm);
+
+ writeTypeSection(Signatures);
+ writeImportSection(Imports, DataSize, TableElems.size());
+ writeFunctionSection(Functions);
+ // Skip the "table" section; we import the table instead.
+ // Skip the "memory" section; we import the memory instead.
+ writeEventSection(Events);
+ writeExportSection(Exports);
+ writeElemSection(TableElems);
+ writeDataCountSection();
+ writeCodeSection(Asm, Layout, Functions);
+ writeDataSection();
+ for (auto &CustomSection : CustomSections)
+ writeCustomSection(CustomSection, Asm, Layout);
+ writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats);
+ writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations);
+ writeRelocSection(DataSectionIndex, "DATA", DataRelocations);
+ writeCustomRelocSections();
+ if (ProducersSection)
+ writeCustomSection(*ProducersSection, Asm, Layout);
+ if (TargetFeaturesSection)
+ writeCustomSection(*TargetFeaturesSection, Asm, Layout);
+
+ // TODO: Translate the .comment section to the output.
+ return W.OS.tell() - StartOffset;
+}
+
+std::unique_ptr<MCObjectWriter>
+llvm::createWasmObjectWriter(std::unique_ptr<MCWasmObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS) {
+ return std::make_unique<WasmObjectWriter>(std::move(MOTW), OS);
+}
diff --git a/llvm/lib/MC/WinCOFFObjectWriter.cpp b/llvm/lib/MC/WinCOFFObjectWriter.cpp
new file mode 100644
index 000000000000..749ed8badfaa
--- /dev/null
+++ b/llvm/lib/MC/WinCOFFObjectWriter.cpp
@@ -0,0 +1,1102 @@
+//===- llvm/MC/WinCOFFObjectWriter.cpp ------------------------------------===//
+//
+// 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 contains an implementation of a Win32 COFF object file writer.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionCOFF.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCSymbolCOFF.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <memory>
+#include <string>
+#include <vector>
+
+using namespace llvm;
+using llvm::support::endian::write32le;
+
+#define DEBUG_TYPE "WinCOFFObjectWriter"
+
+namespace {
+
+using name = SmallString<COFF::NameSize>;
+
+enum AuxiliaryType {
+ ATWeakExternal,
+ ATFile,
+ ATSectionDefinition
+};
+
+struct AuxSymbol {
+ AuxiliaryType AuxType;
+ COFF::Auxiliary Aux;
+};
+
+class COFFSection;
+
+class COFFSymbol {
+public:
+ COFF::symbol Data = {};
+
+ using AuxiliarySymbols = SmallVector<AuxSymbol, 1>;
+
+ name Name;
+ int Index;
+ AuxiliarySymbols Aux;
+ COFFSymbol *Other = nullptr;
+ COFFSection *Section = nullptr;
+ int Relocations = 0;
+ const MCSymbol *MC = nullptr;
+
+ COFFSymbol(StringRef Name) : Name(Name) {}
+
+ void set_name_offset(uint32_t Offset);
+
+ int64_t getIndex() const { return Index; }
+ void setIndex(int Value) {
+ Index = Value;
+ if (MC)
+ MC->setIndex(static_cast<uint32_t>(Value));
+ }
+};
+
+// This class contains staging data for a COFF relocation entry.
+struct COFFRelocation {
+ COFF::relocation Data;
+ COFFSymbol *Symb = nullptr;
+
+ COFFRelocation() = default;
+
+ static size_t size() { return COFF::RelocationSize; }
+};
+
+using relocations = std::vector<COFFRelocation>;
+
+class COFFSection {
+public:
+ COFF::section Header = {};
+
+ std::string Name;
+ int Number;
+ MCSectionCOFF const *MCSection = nullptr;
+ COFFSymbol *Symbol = nullptr;
+ relocations Relocations;
+
+ COFFSection(StringRef Name) : Name(Name) {}
+};
+
+class WinCOFFObjectWriter : public MCObjectWriter {
+public:
+ support::endian::Writer W;
+
+ using symbols = std::vector<std::unique_ptr<COFFSymbol>>;
+ using sections = std::vector<std::unique_ptr<COFFSection>>;
+
+ using symbol_map = DenseMap<MCSymbol const *, COFFSymbol *>;
+ using section_map = DenseMap<MCSection const *, COFFSection *>;
+
+ std::unique_ptr<MCWinCOFFObjectTargetWriter> TargetObjectWriter;
+
+ // Root level file contents.
+ COFF::header Header = {};
+ sections Sections;
+ symbols Symbols;
+ StringTableBuilder Strings{StringTableBuilder::WinCOFF};
+
+ // Maps used during object file creation.
+ section_map SectionMap;
+ symbol_map SymbolMap;
+
+ bool UseBigObj;
+
+ bool EmitAddrsigSection = false;
+ MCSectionCOFF *AddrsigSection;
+ std::vector<const MCSymbol *> AddrsigSyms;
+
+ WinCOFFObjectWriter(std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS);
+
+ void reset() override {
+ memset(&Header, 0, sizeof(Header));
+ Header.Machine = TargetObjectWriter->getMachine();
+ Sections.clear();
+ Symbols.clear();
+ Strings.clear();
+ SectionMap.clear();
+ SymbolMap.clear();
+ MCObjectWriter::reset();
+ }
+
+ COFFSymbol *createSymbol(StringRef Name);
+ COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol *Symbol);
+ COFFSection *createSection(StringRef Name);
+
+ void defineSection(MCSectionCOFF const &Sec);
+
+ COFFSymbol *getLinkedSymbol(const MCSymbol &Symbol);
+ void DefineSymbol(const MCSymbol &Symbol, MCAssembler &Assembler,
+ const MCAsmLayout &Layout);
+
+ void SetSymbolName(COFFSymbol &S);
+ void SetSectionName(COFFSection &S);
+
+ bool IsPhysicalSection(COFFSection *S);
+
+ // Entity writing methods.
+
+ void WriteFileHeader(const COFF::header &Header);
+ void WriteSymbol(const COFFSymbol &S);
+ void WriteAuxiliarySymbols(const COFFSymbol::AuxiliarySymbols &S);
+ void writeSectionHeaders();
+ void WriteRelocation(const COFF::relocation &R);
+ uint32_t writeSectionContents(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCSection &MCSec);
+ void writeSection(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const COFFSection &Sec, const MCSection &MCSec);
+
+ // MCObjectWriter interface implementation.
+
+ void executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) override;
+
+ bool isSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm,
+ const MCSymbol &SymA,
+ const MCFragment &FB, bool InSet,
+ bool IsPCRel) const override;
+
+ void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFragment *Fragment, const MCFixup &Fixup,
+ MCValue Target, uint64_t &FixedValue) override;
+
+ void createFileSymbols(MCAssembler &Asm);
+ void assignSectionNumbers();
+ void assignFileOffsets(MCAssembler &Asm, const MCAsmLayout &Layout);
+
+ void emitAddrsigSection() override { EmitAddrsigSection = true; }
+ void addAddrsigSymbol(const MCSymbol *Sym) override {
+ AddrsigSyms.push_back(Sym);
+ }
+
+ uint64_t writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) override;
+};
+
+} // end anonymous namespace
+
+//------------------------------------------------------------------------------
+// Symbol class implementation
+
+// In the case that the name does not fit within 8 bytes, the offset
+// into the string table is stored in the last 4 bytes instead, leaving
+// the first 4 bytes as 0.
+void COFFSymbol::set_name_offset(uint32_t Offset) {
+ write32le(Data.Name + 0, 0);
+ write32le(Data.Name + 4, Offset);
+}
+
+//------------------------------------------------------------------------------
+// WinCOFFObjectWriter class implementation
+
+WinCOFFObjectWriter::WinCOFFObjectWriter(
+ std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
+ : W(OS, support::little), TargetObjectWriter(std::move(MOTW)) {
+ Header.Machine = TargetObjectWriter->getMachine();
+}
+
+COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) {
+ Symbols.push_back(std::make_unique<COFFSymbol>(Name));
+ return Symbols.back().get();
+}
+
+COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol *Symbol) {
+ COFFSymbol *&Ret = SymbolMap[Symbol];
+ if (!Ret)
+ Ret = createSymbol(Symbol->getName());
+ return Ret;
+}
+
+COFFSection *WinCOFFObjectWriter::createSection(StringRef Name) {
+ Sections.emplace_back(std::make_unique<COFFSection>(Name));
+ return Sections.back().get();
+}
+
+static uint32_t getAlignment(const MCSectionCOFF &Sec) {
+ switch (Sec.getAlignment()) {
+ case 1:
+ return COFF::IMAGE_SCN_ALIGN_1BYTES;
+ case 2:
+ return COFF::IMAGE_SCN_ALIGN_2BYTES;
+ case 4:
+ return COFF::IMAGE_SCN_ALIGN_4BYTES;
+ case 8:
+ return COFF::IMAGE_SCN_ALIGN_8BYTES;
+ case 16:
+ return COFF::IMAGE_SCN_ALIGN_16BYTES;
+ case 32:
+ return COFF::IMAGE_SCN_ALIGN_32BYTES;
+ case 64:
+ return COFF::IMAGE_SCN_ALIGN_64BYTES;
+ case 128:
+ return COFF::IMAGE_SCN_ALIGN_128BYTES;
+ case 256:
+ return COFF::IMAGE_SCN_ALIGN_256BYTES;
+ case 512:
+ return COFF::IMAGE_SCN_ALIGN_512BYTES;
+ case 1024:
+ return COFF::IMAGE_SCN_ALIGN_1024BYTES;
+ case 2048:
+ return COFF::IMAGE_SCN_ALIGN_2048BYTES;
+ case 4096:
+ return COFF::IMAGE_SCN_ALIGN_4096BYTES;
+ case 8192:
+ return COFF::IMAGE_SCN_ALIGN_8192BYTES;
+ }
+ llvm_unreachable("unsupported section alignment");
+}
+
+/// This function takes a section data object from the assembler
+/// and creates the associated COFF section staging object.
+void WinCOFFObjectWriter::defineSection(const MCSectionCOFF &MCSec) {
+ COFFSection *Section = createSection(MCSec.getSectionName());
+ COFFSymbol *Symbol = createSymbol(MCSec.getSectionName());
+ Section->Symbol = Symbol;
+ Symbol->Section = Section;
+ Symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
+
+ // Create a COMDAT symbol if needed.
+ if (MCSec.getSelection() != COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
+ if (const MCSymbol *S = MCSec.getCOMDATSymbol()) {
+ COFFSymbol *COMDATSymbol = GetOrCreateCOFFSymbol(S);
+ if (COMDATSymbol->Section)
+ report_fatal_error("two sections have the same comdat");
+ COMDATSymbol->Section = Section;
+ }
+ }
+
+ // In this case the auxiliary symbol is a Section Definition.
+ Symbol->Aux.resize(1);
+ Symbol->Aux[0] = {};
+ Symbol->Aux[0].AuxType = ATSectionDefinition;
+ Symbol->Aux[0].Aux.SectionDefinition.Selection = MCSec.getSelection();
+
+ // Set section alignment.
+ Section->Header.Characteristics = MCSec.getCharacteristics();
+ Section->Header.Characteristics |= getAlignment(MCSec);
+
+ // Bind internal COFF section to MC section.
+ Section->MCSection = &MCSec;
+ SectionMap[&MCSec] = Section;
+}
+
+static uint64_t getSymbolValue(const MCSymbol &Symbol,
+ const MCAsmLayout &Layout) {
+ if (Symbol.isCommon() && Symbol.isExternal())
+ return Symbol.getCommonSize();
+
+ uint64_t Res;
+ if (!Layout.getSymbolOffset(Symbol, Res))
+ return 0;
+
+ return Res;
+}
+
+COFFSymbol *WinCOFFObjectWriter::getLinkedSymbol(const MCSymbol &Symbol) {
+ if (!Symbol.isVariable())
+ return nullptr;
+
+ const MCSymbolRefExpr *SymRef =
+ dyn_cast<MCSymbolRefExpr>(Symbol.getVariableValue());
+ if (!SymRef)
+ return nullptr;
+
+ const MCSymbol &Aliasee = SymRef->getSymbol();
+ if (!Aliasee.isUndefined())
+ return nullptr;
+ return GetOrCreateCOFFSymbol(&Aliasee);
+}
+
+/// This function takes a symbol data object from the assembler
+/// and creates the associated COFF symbol staging object.
+void WinCOFFObjectWriter::DefineSymbol(const MCSymbol &MCSym,
+ MCAssembler &Assembler,
+ const MCAsmLayout &Layout) {
+ COFFSymbol *Sym = GetOrCreateCOFFSymbol(&MCSym);
+ const MCSymbol *Base = Layout.getBaseSymbol(MCSym);
+ COFFSection *Sec = nullptr;
+ if (Base && Base->getFragment()) {
+ Sec = SectionMap[Base->getFragment()->getParent()];
+ if (Sym->Section && Sym->Section != Sec)
+ report_fatal_error("conflicting sections for symbol");
+ }
+
+ COFFSymbol *Local = nullptr;
+ if (cast<MCSymbolCOFF>(MCSym).isWeakExternal()) {
+ Sym->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL;
+
+ COFFSymbol *WeakDefault = getLinkedSymbol(MCSym);
+ if (!WeakDefault) {
+ std::string WeakName = (".weak." + MCSym.getName() + ".default").str();
+ WeakDefault = createSymbol(WeakName);
+ if (!Sec)
+ WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
+ else
+ WeakDefault->Section = Sec;
+ Local = WeakDefault;
+ }
+
+ Sym->Other = WeakDefault;
+
+ // Setup the Weak External auxiliary symbol.
+ Sym->Aux.resize(1);
+ memset(&Sym->Aux[0], 0, sizeof(Sym->Aux[0]));
+ Sym->Aux[0].AuxType = ATWeakExternal;
+ Sym->Aux[0].Aux.WeakExternal.TagIndex = 0;
+ Sym->Aux[0].Aux.WeakExternal.Characteristics =
+ COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS;
+ } else {
+ if (!Base)
+ Sym->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE;
+ else
+ Sym->Section = Sec;
+ Local = Sym;
+ }
+
+ if (Local) {
+ Local->Data.Value = getSymbolValue(MCSym, Layout);
+
+ const MCSymbolCOFF &SymbolCOFF = cast<MCSymbolCOFF>(MCSym);
+ Local->Data.Type = SymbolCOFF.getType();
+ Local->Data.StorageClass = SymbolCOFF.getClass();
+
+ // If no storage class was specified in the streamer, define it here.
+ if (Local->Data.StorageClass == COFF::IMAGE_SYM_CLASS_NULL) {
+ bool IsExternal = MCSym.isExternal() ||
+ (!MCSym.getFragment() && !MCSym.isVariable());
+
+ Local->Data.StorageClass = IsExternal ? COFF::IMAGE_SYM_CLASS_EXTERNAL
+ : COFF::IMAGE_SYM_CLASS_STATIC;
+ }
+ }
+
+ Sym->MC = &MCSym;
+}
+
+// Maximum offsets for different string table entry encodings.
+enum : unsigned { Max7DecimalOffset = 9999999U };
+enum : uint64_t { MaxBase64Offset = 0xFFFFFFFFFULL }; // 64^6, including 0
+
+// Encode a string table entry offset in base 64, padded to 6 chars, and
+// prefixed with a double slash: '//AAAAAA', '//AAAAAB', ...
+// Buffer must be at least 8 bytes large. No terminating null appended.
+static void encodeBase64StringEntry(char *Buffer, uint64_t Value) {
+ assert(Value > Max7DecimalOffset && Value <= MaxBase64Offset &&
+ "Illegal section name encoding for value");
+
+ static const char Alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+ Buffer[0] = '/';
+ Buffer[1] = '/';
+
+ char *Ptr = Buffer + 7;
+ for (unsigned i = 0; i < 6; ++i) {
+ unsigned Rem = Value % 64;
+ Value /= 64;
+ *(Ptr--) = Alphabet[Rem];
+ }
+}
+
+void WinCOFFObjectWriter::SetSectionName(COFFSection &S) {
+ if (S.Name.size() <= COFF::NameSize) {
+ std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size());
+ return;
+ }
+
+ uint64_t StringTableEntry = Strings.getOffset(S.Name);
+ if (StringTableEntry <= Max7DecimalOffset) {
+ SmallVector<char, COFF::NameSize> Buffer;
+ Twine('/').concat(Twine(StringTableEntry)).toVector(Buffer);
+ assert(Buffer.size() <= COFF::NameSize && Buffer.size() >= 2);
+ std::memcpy(S.Header.Name, Buffer.data(), Buffer.size());
+ return;
+ }
+ if (StringTableEntry <= MaxBase64Offset) {
+ // Starting with 10,000,000, offsets are encoded as base64.
+ encodeBase64StringEntry(S.Header.Name, StringTableEntry);
+ return;
+ }
+ report_fatal_error("COFF string table is greater than 64 GB.");
+}
+
+void WinCOFFObjectWriter::SetSymbolName(COFFSymbol &S) {
+ if (S.Name.size() > COFF::NameSize)
+ S.set_name_offset(Strings.getOffset(S.Name));
+ else
+ std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size());
+}
+
+bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) {
+ return (S->Header.Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) ==
+ 0;
+}
+
+//------------------------------------------------------------------------------
+// entity writing methods
+
+void WinCOFFObjectWriter::WriteFileHeader(const COFF::header &Header) {
+ if (UseBigObj) {
+ W.write<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
+ W.write<uint16_t>(0xFFFF);
+ W.write<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion);
+ W.write<uint16_t>(Header.Machine);
+ W.write<uint32_t>(Header.TimeDateStamp);
+ W.OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
+ W.write<uint32_t>(0);
+ W.write<uint32_t>(0);
+ W.write<uint32_t>(0);
+ W.write<uint32_t>(0);
+ W.write<uint32_t>(Header.NumberOfSections);
+ W.write<uint32_t>(Header.PointerToSymbolTable);
+ W.write<uint32_t>(Header.NumberOfSymbols);
+ } else {
+ W.write<uint16_t>(Header.Machine);
+ W.write<uint16_t>(static_cast<int16_t>(Header.NumberOfSections));
+ W.write<uint32_t>(Header.TimeDateStamp);
+ W.write<uint32_t>(Header.PointerToSymbolTable);
+ W.write<uint32_t>(Header.NumberOfSymbols);
+ W.write<uint16_t>(Header.SizeOfOptionalHeader);
+ W.write<uint16_t>(Header.Characteristics);
+ }
+}
+
+void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol &S) {
+ W.OS.write(S.Data.Name, COFF::NameSize);
+ W.write<uint32_t>(S.Data.Value);
+ if (UseBigObj)
+ W.write<uint32_t>(S.Data.SectionNumber);
+ else
+ W.write<uint16_t>(static_cast<int16_t>(S.Data.SectionNumber));
+ W.write<uint16_t>(S.Data.Type);
+ W.OS << char(S.Data.StorageClass);
+ W.OS << char(S.Data.NumberOfAuxSymbols);
+ WriteAuxiliarySymbols(S.Aux);
+}
+
+void WinCOFFObjectWriter::WriteAuxiliarySymbols(
+ const COFFSymbol::AuxiliarySymbols &S) {
+ for (const AuxSymbol &i : S) {
+ switch (i.AuxType) {
+ case ATWeakExternal:
+ W.write<uint32_t>(i.Aux.WeakExternal.TagIndex);
+ W.write<uint32_t>(i.Aux.WeakExternal.Characteristics);
+ W.OS.write_zeros(sizeof(i.Aux.WeakExternal.unused));
+ if (UseBigObj)
+ W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size);
+ break;
+ case ATFile:
+ W.OS.write(reinterpret_cast<const char *>(&i.Aux),
+ UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size);
+ break;
+ case ATSectionDefinition:
+ W.write<uint32_t>(i.Aux.SectionDefinition.Length);
+ W.write<uint16_t>(i.Aux.SectionDefinition.NumberOfRelocations);
+ W.write<uint16_t>(i.Aux.SectionDefinition.NumberOfLinenumbers);
+ W.write<uint32_t>(i.Aux.SectionDefinition.CheckSum);
+ W.write<uint16_t>(static_cast<int16_t>(i.Aux.SectionDefinition.Number));
+ W.OS << char(i.Aux.SectionDefinition.Selection);
+ W.OS.write_zeros(sizeof(i.Aux.SectionDefinition.unused));
+ W.write<uint16_t>(static_cast<int16_t>(i.Aux.SectionDefinition.Number >> 16));
+ if (UseBigObj)
+ W.OS.write_zeros(COFF::Symbol32Size - COFF::Symbol16Size);
+ break;
+ }
+ }
+}
+
+// Write the section header.
+void WinCOFFObjectWriter::writeSectionHeaders() {
+ // Section numbers must be monotonically increasing in the section
+ // header, but our Sections array is not sorted by section number,
+ // so make a copy of Sections and sort it.
+ std::vector<COFFSection *> Arr;
+ for (auto &Section : Sections)
+ Arr.push_back(Section.get());
+ llvm::sort(Arr, [](const COFFSection *A, const COFFSection *B) {
+ return A->Number < B->Number;
+ });
+
+ for (auto &Section : Arr) {
+ if (Section->Number == -1)
+ continue;
+
+ COFF::section &S = Section->Header;
+ if (Section->Relocations.size() >= 0xffff)
+ S.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL;
+ W.OS.write(S.Name, COFF::NameSize);
+ W.write<uint32_t>(S.VirtualSize);
+ W.write<uint32_t>(S.VirtualAddress);
+ W.write<uint32_t>(S.SizeOfRawData);
+ W.write<uint32_t>(S.PointerToRawData);
+ W.write<uint32_t>(S.PointerToRelocations);
+ W.write<uint32_t>(S.PointerToLineNumbers);
+ W.write<uint16_t>(S.NumberOfRelocations);
+ W.write<uint16_t>(S.NumberOfLineNumbers);
+ W.write<uint32_t>(S.Characteristics);
+ }
+}
+
+void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) {
+ W.write<uint32_t>(R.VirtualAddress);
+ W.write<uint32_t>(R.SymbolTableIndex);
+ W.write<uint16_t>(R.Type);
+}
+
+// Write MCSec's contents. What this function does is essentially
+// "Asm.writeSectionData(&MCSec, Layout)", but it's a bit complicated
+// because it needs to compute a CRC.
+uint32_t WinCOFFObjectWriter::writeSectionContents(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCSection &MCSec) {
+ // Save the contents of the section to a temporary buffer, we need this
+ // to CRC the data before we dump it into the object file.
+ SmallVector<char, 128> Buf;
+ raw_svector_ostream VecOS(Buf);
+ Asm.writeSectionData(VecOS, &MCSec, Layout);
+
+ // Write the section contents to the object file.
+ W.OS << Buf;
+
+ // Calculate our CRC with an initial value of '0', this is not how
+ // JamCRC is specified but it aligns with the expected output.
+ JamCRC JC(/*Init=*/0);
+ JC.update(makeArrayRef(reinterpret_cast<uint8_t*>(Buf.data()), Buf.size()));
+ return JC.getCRC();
+}
+
+void WinCOFFObjectWriter::writeSection(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const COFFSection &Sec,
+ const MCSection &MCSec) {
+ if (Sec.Number == -1)
+ return;
+
+ // Write the section contents.
+ if (Sec.Header.PointerToRawData != 0) {
+ assert(W.OS.tell() == Sec.Header.PointerToRawData &&
+ "Section::PointerToRawData is insane!");
+
+ uint32_t CRC = writeSectionContents(Asm, Layout, MCSec);
+
+ // Update the section definition auxiliary symbol to record the CRC.
+ COFFSection *Sec = SectionMap[&MCSec];
+ COFFSymbol::AuxiliarySymbols &AuxSyms = Sec->Symbol->Aux;
+ assert(AuxSyms.size() == 1 && AuxSyms[0].AuxType == ATSectionDefinition);
+ AuxSymbol &SecDef = AuxSyms[0];
+ SecDef.Aux.SectionDefinition.CheckSum = CRC;
+ }
+
+ // Write relocations for this section.
+ if (Sec.Relocations.empty()) {
+ assert(Sec.Header.PointerToRelocations == 0 &&
+ "Section::PointerToRelocations is insane!");
+ return;
+ }
+
+ assert(W.OS.tell() == Sec.Header.PointerToRelocations &&
+ "Section::PointerToRelocations is insane!");
+
+ if (Sec.Relocations.size() >= 0xffff) {
+ // In case of overflow, write actual relocation count as first
+ // relocation. Including the synthetic reloc itself (+ 1).
+ COFF::relocation R;
+ R.VirtualAddress = Sec.Relocations.size() + 1;
+ R.SymbolTableIndex = 0;
+ R.Type = 0;
+ WriteRelocation(R);
+ }
+
+ for (const auto &Relocation : Sec.Relocations)
+ WriteRelocation(Relocation.Data);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// MCObjectWriter interface implementations
+
+void WinCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ if (EmitAddrsigSection) {
+ AddrsigSection = Asm.getContext().getCOFFSection(
+ ".llvm_addrsig", COFF::IMAGE_SCN_LNK_REMOVE,
+ SectionKind::getMetadata());
+ Asm.registerSection(*AddrsigSection);
+ }
+
+ // "Define" each section & symbol. This creates section & symbol
+ // entries in the staging area.
+ for (const auto &Section : Asm)
+ defineSection(static_cast<const MCSectionCOFF &>(Section));
+
+ for (const MCSymbol &Symbol : Asm.symbols())
+ if (!Symbol.isTemporary())
+ DefineSymbol(Symbol, Asm, Layout);
+}
+
+bool WinCOFFObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(
+ const MCAssembler &Asm, const MCSymbol &SymA, const MCFragment &FB,
+ bool InSet, bool IsPCRel) const {
+ // Don't drop relocations between functions, even if they are in the same text
+ // section. Multiple Visual C++ linker features depend on having the
+ // relocations present. The /INCREMENTAL flag will cause these relocations to
+ // point to thunks, and the /GUARD:CF flag assumes that it can use relocations
+ // to approximate the set of all address taken functions. LLD's implementation
+ // of /GUARD:CF also relies on the existance of these relocations.
+ uint16_t Type = cast<MCSymbolCOFF>(SymA).getType();
+ if ((Type >> COFF::SCT_COMPLEX_TYPE_SHIFT) == COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ return false;
+ return MCObjectWriter::isSymbolRefDifferenceFullyResolvedImpl(Asm, SymA, FB,
+ InSet, IsPCRel);
+}
+
+void WinCOFFObjectWriter::recordRelocation(MCAssembler &Asm,
+ const MCAsmLayout &Layout,
+ const MCFragment *Fragment,
+ const MCFixup &Fixup, MCValue Target,
+ uint64_t &FixedValue) {
+ assert(Target.getSymA() && "Relocation must reference a symbol!");
+
+ const MCSymbol &A = Target.getSymA()->getSymbol();
+ if (!A.isRegistered()) {
+ Asm.getContext().reportError(Fixup.getLoc(),
+ Twine("symbol '") + A.getName() +
+ "' can not be undefined");
+ return;
+ }
+ if (A.isTemporary() && A.isUndefined()) {
+ Asm.getContext().reportError(Fixup.getLoc(),
+ Twine("assembler label '") + A.getName() +
+ "' can not be undefined");
+ return;
+ }
+
+ MCSection *MCSec = Fragment->getParent();
+
+ // Mark this symbol as requiring an entry in the symbol table.
+ assert(SectionMap.find(MCSec) != SectionMap.end() &&
+ "Section must already have been defined in executePostLayoutBinding!");
+
+ COFFSection *Sec = SectionMap[MCSec];
+ const MCSymbolRefExpr *SymB = Target.getSymB();
+
+ if (SymB) {
+ const MCSymbol *B = &SymB->getSymbol();
+ if (!B->getFragment()) {
+ Asm.getContext().reportError(
+ Fixup.getLoc(),
+ Twine("symbol '") + B->getName() +
+ "' can not be undefined in a subtraction expression");
+ return;
+ }
+
+ // Offset of the symbol in the section
+ int64_t OffsetOfB = Layout.getSymbolOffset(*B);
+
+ // Offset of the relocation in the section
+ int64_t OffsetOfRelocation =
+ Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+
+ FixedValue = (OffsetOfRelocation - OffsetOfB) + Target.getConstant();
+ } else {
+ FixedValue = Target.getConstant();
+ }
+
+ COFFRelocation Reloc;
+
+ Reloc.Data.SymbolTableIndex = 0;
+ Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment);
+
+ // Turn relocations for temporary symbols into section relocations.
+ if (A.isTemporary()) {
+ MCSection *TargetSection = &A.getSection();
+ assert(
+ SectionMap.find(TargetSection) != SectionMap.end() &&
+ "Section must already have been defined in executePostLayoutBinding!");
+ Reloc.Symb = SectionMap[TargetSection]->Symbol;
+ FixedValue += Layout.getSymbolOffset(A);
+ } else {
+ assert(
+ SymbolMap.find(&A) != SymbolMap.end() &&
+ "Symbol must already have been defined in executePostLayoutBinding!");
+ Reloc.Symb = SymbolMap[&A];
+ }
+
+ ++Reloc.Symb->Relocations;
+
+ Reloc.Data.VirtualAddress += Fixup.getOffset();
+ Reloc.Data.Type = TargetObjectWriter->getRelocType(
+ Asm.getContext(), Target, Fixup, SymB, Asm.getBackend());
+
+ // FIXME: Can anyone explain what this does other than adjust for the size
+ // of the offset?
+ if ((Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64 &&
+ Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32) ||
+ (Header.Machine == COFF::IMAGE_FILE_MACHINE_I386 &&
+ Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32))
+ FixedValue += 4;
+
+ if (Header.Machine == COFF::IMAGE_FILE_MACHINE_ARMNT) {
+ switch (Reloc.Data.Type) {
+ case COFF::IMAGE_REL_ARM_ABSOLUTE:
+ case COFF::IMAGE_REL_ARM_ADDR32:
+ case COFF::IMAGE_REL_ARM_ADDR32NB:
+ case COFF::IMAGE_REL_ARM_TOKEN:
+ case COFF::IMAGE_REL_ARM_SECTION:
+ case COFF::IMAGE_REL_ARM_SECREL:
+ break;
+ case COFF::IMAGE_REL_ARM_BRANCH11:
+ case COFF::IMAGE_REL_ARM_BLX11:
+ // IMAGE_REL_ARM_BRANCH11 and IMAGE_REL_ARM_BLX11 are only used for
+ // pre-ARMv7, which implicitly rules it out of ARMNT (it would be valid
+ // for Windows CE).
+ case COFF::IMAGE_REL_ARM_BRANCH24:
+ case COFF::IMAGE_REL_ARM_BLX24:
+ case COFF::IMAGE_REL_ARM_MOV32A:
+ // IMAGE_REL_ARM_BRANCH24, IMAGE_REL_ARM_BLX24, IMAGE_REL_ARM_MOV32A are
+ // only used for ARM mode code, which is documented as being unsupported
+ // by Windows on ARM. Empirical proof indicates that masm is able to
+ // generate the relocations however the rest of the MSVC toolchain is
+ // unable to handle it.
+ llvm_unreachable("unsupported relocation");
+ break;
+ case COFF::IMAGE_REL_ARM_MOV32T:
+ break;
+ case COFF::IMAGE_REL_ARM_BRANCH20T:
+ case COFF::IMAGE_REL_ARM_BRANCH24T:
+ case COFF::IMAGE_REL_ARM_BLX23T:
+ // IMAGE_REL_BRANCH20T, IMAGE_REL_ARM_BRANCH24T, IMAGE_REL_ARM_BLX23T all
+ // perform a 4 byte adjustment to the relocation. Relative branches are
+ // offset by 4 on ARM, however, because there is no RELA relocations, all
+ // branches are offset by 4.
+ FixedValue = FixedValue + 4;
+ break;
+ }
+ }
+
+ // The fixed value never makes sense for section indices, ignore it.
+ if (Fixup.getKind() == FK_SecRel_2)
+ FixedValue = 0;
+
+ if (TargetObjectWriter->recordRelocation(Fixup))
+ Sec->Relocations.push_back(Reloc);
+}
+
+static std::time_t getTime() {
+ std::time_t Now = time(nullptr);
+ if (Now < 0 || !isUInt<32>(Now))
+ return UINT32_MAX;
+ return Now;
+}
+
+// Create .file symbols.
+void WinCOFFObjectWriter::createFileSymbols(MCAssembler &Asm) {
+ for (const std::string &Name : Asm.getFileNames()) {
+ // round up to calculate the number of auxiliary symbols required
+ unsigned SymbolSize = UseBigObj ? COFF::Symbol32Size : COFF::Symbol16Size;
+ unsigned Count = (Name.size() + SymbolSize - 1) / SymbolSize;
+
+ COFFSymbol *File = createSymbol(".file");
+ File->Data.SectionNumber = COFF::IMAGE_SYM_DEBUG;
+ File->Data.StorageClass = COFF::IMAGE_SYM_CLASS_FILE;
+ File->Aux.resize(Count);
+
+ unsigned Offset = 0;
+ unsigned Length = Name.size();
+ for (auto &Aux : File->Aux) {
+ Aux.AuxType = ATFile;
+
+ if (Length > SymbolSize) {
+ memcpy(&Aux.Aux, Name.c_str() + Offset, SymbolSize);
+ Length = Length - SymbolSize;
+ } else {
+ memcpy(&Aux.Aux, Name.c_str() + Offset, Length);
+ memset((char *)&Aux.Aux + Length, 0, SymbolSize - Length);
+ break;
+ }
+
+ Offset += SymbolSize;
+ }
+ }
+}
+
+static bool isAssociative(const COFFSection &Section) {
+ return Section.Symbol->Aux[0].Aux.SectionDefinition.Selection ==
+ COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE;
+}
+
+void WinCOFFObjectWriter::assignSectionNumbers() {
+ size_t I = 1;
+ auto Assign = [&](COFFSection &Section) {
+ Section.Number = I;
+ Section.Symbol->Data.SectionNumber = I;
+ Section.Symbol->Aux[0].Aux.SectionDefinition.Number = I;
+ ++I;
+ };
+
+ // Although it is not explicitly requested by the Microsoft COFF spec,
+ // we should avoid emitting forward associative section references,
+ // because MSVC link.exe as of 2017 cannot handle that.
+ for (const std::unique_ptr<COFFSection> &Section : Sections)
+ if (!isAssociative(*Section))
+ Assign(*Section);
+ for (const std::unique_ptr<COFFSection> &Section : Sections)
+ if (isAssociative(*Section))
+ Assign(*Section);
+}
+
+// Assign file offsets to COFF object file structures.
+void WinCOFFObjectWriter::assignFileOffsets(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ unsigned Offset = W.OS.tell();
+
+ Offset += UseBigObj ? COFF::Header32Size : COFF::Header16Size;
+ Offset += COFF::SectionSize * Header.NumberOfSections;
+
+ for (const auto &Section : Asm) {
+ COFFSection *Sec = SectionMap[&Section];
+
+ if (Sec->Number == -1)
+ continue;
+
+ Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(&Section);
+
+ if (IsPhysicalSection(Sec)) {
+ Sec->Header.PointerToRawData = Offset;
+ Offset += Sec->Header.SizeOfRawData;
+ }
+
+ if (!Sec->Relocations.empty()) {
+ bool RelocationsOverflow = Sec->Relocations.size() >= 0xffff;
+
+ if (RelocationsOverflow) {
+ // Signal overflow by setting NumberOfRelocations to max value. Actual
+ // size is found in reloc #0. Microsoft tools understand this.
+ Sec->Header.NumberOfRelocations = 0xffff;
+ } else {
+ Sec->Header.NumberOfRelocations = Sec->Relocations.size();
+ }
+ Sec->Header.PointerToRelocations = Offset;
+
+ if (RelocationsOverflow) {
+ // Reloc #0 will contain actual count, so make room for it.
+ Offset += COFF::RelocationSize;
+ }
+
+ Offset += COFF::RelocationSize * Sec->Relocations.size();
+
+ for (auto &Relocation : Sec->Relocations) {
+ assert(Relocation.Symb->getIndex() != -1);
+ Relocation.Data.SymbolTableIndex = Relocation.Symb->getIndex();
+ }
+ }
+
+ assert(Sec->Symbol->Aux.size() == 1 &&
+ "Section's symbol must have one aux!");
+ AuxSymbol &Aux = Sec->Symbol->Aux[0];
+ assert(Aux.AuxType == ATSectionDefinition &&
+ "Section's symbol's aux symbol must be a Section Definition!");
+ Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData;
+ Aux.Aux.SectionDefinition.NumberOfRelocations =
+ Sec->Header.NumberOfRelocations;
+ Aux.Aux.SectionDefinition.NumberOfLinenumbers =
+ Sec->Header.NumberOfLineNumbers;
+ }
+
+ Header.PointerToSymbolTable = Offset;
+}
+
+uint64_t WinCOFFObjectWriter::writeObject(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ uint64_t StartOffset = W.OS.tell();
+
+ if (Sections.size() > INT32_MAX)
+ report_fatal_error(
+ "PE COFF object files can't have more than 2147483647 sections");
+
+ UseBigObj = Sections.size() > COFF::MaxNumberOfSections16;
+ Header.NumberOfSections = Sections.size();
+ Header.NumberOfSymbols = 0;
+
+ assignSectionNumbers();
+ createFileSymbols(Asm);
+
+ for (auto &Symbol : Symbols) {
+ // Update section number & offset for symbols that have them.
+ if (Symbol->Section)
+ Symbol->Data.SectionNumber = Symbol->Section->Number;
+ Symbol->setIndex(Header.NumberOfSymbols++);
+ // Update auxiliary symbol info.
+ Symbol->Data.NumberOfAuxSymbols = Symbol->Aux.size();
+ Header.NumberOfSymbols += Symbol->Data.NumberOfAuxSymbols;
+ }
+
+ // Build string table.
+ for (const auto &S : Sections)
+ if (S->Name.size() > COFF::NameSize)
+ Strings.add(S->Name);
+ for (const auto &S : Symbols)
+ if (S->Name.size() > COFF::NameSize)
+ Strings.add(S->Name);
+ Strings.finalize();
+
+ // Set names.
+ for (const auto &S : Sections)
+ SetSectionName(*S);
+ for (auto &S : Symbols)
+ SetSymbolName(*S);
+
+ // Fixup weak external references.
+ for (auto &Symbol : Symbols) {
+ if (Symbol->Other) {
+ assert(Symbol->getIndex() != -1);
+ assert(Symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!");
+ assert(Symbol->Aux[0].AuxType == ATWeakExternal &&
+ "Symbol's aux symbol must be a Weak External!");
+ Symbol->Aux[0].Aux.WeakExternal.TagIndex = Symbol->Other->getIndex();
+ }
+ }
+
+ // Fixup associative COMDAT sections.
+ for (auto &Section : Sections) {
+ if (Section->Symbol->Aux[0].Aux.SectionDefinition.Selection !=
+ COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE)
+ continue;
+
+ const MCSectionCOFF &MCSec = *Section->MCSection;
+ const MCSymbol *AssocMCSym = MCSec.getCOMDATSymbol();
+ assert(AssocMCSym);
+
+ // It's an error to try to associate with an undefined symbol or a symbol
+ // without a section.
+ if (!AssocMCSym->isInSection()) {
+ Asm.getContext().reportError(
+ SMLoc(), Twine("cannot make section ") + MCSec.getSectionName() +
+ Twine(" associative with sectionless symbol ") +
+ AssocMCSym->getName());
+ continue;
+ }
+
+ const auto *AssocMCSec = cast<MCSectionCOFF>(&AssocMCSym->getSection());
+ assert(SectionMap.count(AssocMCSec));
+ COFFSection *AssocSec = SectionMap[AssocMCSec];
+
+ // Skip this section if the associated section is unused.
+ if (AssocSec->Number == -1)
+ continue;
+
+ Section->Symbol->Aux[0].Aux.SectionDefinition.Number = AssocSec->Number;
+ }
+
+ // Create the contents of the .llvm_addrsig section.
+ if (EmitAddrsigSection) {
+ auto Frag = new MCDataFragment(AddrsigSection);
+ Frag->setLayoutOrder(0);
+ raw_svector_ostream OS(Frag->getContents());
+ for (const MCSymbol *S : AddrsigSyms) {
+ if (!S->isTemporary()) {
+ encodeULEB128(S->getIndex(), OS);
+ continue;
+ }
+
+ MCSection *TargetSection = &S->getSection();
+ assert(SectionMap.find(TargetSection) != SectionMap.end() &&
+ "Section must already have been defined in "
+ "executePostLayoutBinding!");
+ encodeULEB128(SectionMap[TargetSection]->Symbol->getIndex(), OS);
+ }
+ }
+
+ assignFileOffsets(Asm, Layout);
+
+ // MS LINK expects to be able to use this timestamp to implement their
+ // /INCREMENTAL feature.
+ if (Asm.isIncrementalLinkerCompatible()) {
+ Header.TimeDateStamp = getTime();
+ } else {
+ // Have deterministic output if /INCREMENTAL isn't needed. Also matches GNU.
+ Header.TimeDateStamp = 0;
+ }
+
+ // Write it all to disk...
+ WriteFileHeader(Header);
+ writeSectionHeaders();
+
+ // Write section contents.
+ sections::iterator I = Sections.begin();
+ sections::iterator IE = Sections.end();
+ MCAssembler::iterator J = Asm.begin();
+ MCAssembler::iterator JE = Asm.end();
+ for (; I != IE && J != JE; ++I, ++J)
+ writeSection(Asm, Layout, **I, *J);
+
+ assert(W.OS.tell() == Header.PointerToSymbolTable &&
+ "Header::PointerToSymbolTable is insane!");
+
+ // Write a symbol table.
+ for (auto &Symbol : Symbols)
+ if (Symbol->getIndex() != -1)
+ WriteSymbol(*Symbol);
+
+ // Write a string table, which completes the entire COFF file.
+ Strings.write(W.OS);
+
+ return W.OS.tell() - StartOffset;
+}
+
+MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_)
+ : Machine(Machine_) {}
+
+// Pin the vtable to this file.
+void MCWinCOFFObjectTargetWriter::anchor() {}
+
+//------------------------------------------------------------------------------
+// WinCOFFObjectWriter factory function
+
+std::unique_ptr<MCObjectWriter> llvm::createWinCOFFObjectWriter(
+ std::unique_ptr<MCWinCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS) {
+ return std::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS);
+}
diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp
new file mode 100644
index 000000000000..353c21068735
--- /dev/null
+++ b/llvm/lib/MC/XCOFFObjectWriter.cpp
@@ -0,0 +1,603 @@
+//===-- lib/MC/XCOFFObjectWriter.cpp - XCOFF file writer ------------------===//
+//
+// 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 implements XCOFF object file writer information.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/BinaryFormat/XCOFF.h"
+#include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCSectionXCOFF.h"
+#include "llvm/MC/MCSymbolXCOFF.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/MC/MCXCOFFObjectWriter.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+
+#include <deque>
+
+using namespace llvm;
+
+// An XCOFF object file has a limited set of predefined sections. The most
+// important ones for us (right now) are:
+// .text --> contains program code and read-only data.
+// .data --> contains initialized data, function descriptors, and the TOC.
+// .bss --> contains uninitialized data.
+// Each of these sections is composed of 'Control Sections'. A Control Section
+// is more commonly referred to as a csect. A csect is an indivisible unit of
+// code or data, and acts as a container for symbols. A csect is mapped
+// into a section based on its storage-mapping class, with the exception of
+// XMC_RW which gets mapped to either .data or .bss based on whether it's
+// explicitly initialized or not.
+//
+// We don't represent the sections in the MC layer as there is nothing
+// interesting about them at at that level: they carry information that is
+// only relevant to the ObjectWriter, so we materialize them in this class.
+namespace {
+
+constexpr unsigned DefaultSectionAlign = 4;
+
+// Packs the csect's alignment and type into a byte.
+uint8_t getEncodedType(const MCSectionXCOFF *);
+
+// Wrapper around an MCSymbolXCOFF.
+struct Symbol {
+ const MCSymbolXCOFF *const MCSym;
+ uint32_t SymbolTableIndex;
+
+ XCOFF::StorageClass getStorageClass() const {
+ return MCSym->getStorageClass();
+ }
+ StringRef getName() const { return MCSym->getName(); }
+ Symbol(const MCSymbolXCOFF *MCSym) : MCSym(MCSym), SymbolTableIndex(-1) {}
+};
+
+// Wrapper for an MCSectionXCOFF.
+struct ControlSection {
+ const MCSectionXCOFF *const MCCsect;
+ uint32_t SymbolTableIndex;
+ uint32_t Address;
+ uint32_t Size;
+
+ SmallVector<Symbol, 1> Syms;
+ StringRef getName() const { return MCCsect->getSectionName(); }
+ ControlSection(const MCSectionXCOFF *MCSec)
+ : MCCsect(MCSec), SymbolTableIndex(-1), Address(-1), Size(0) {}
+};
+
+// Represents the data related to a section excluding the csects that make up
+// the raw data of the section. The csects are stored separately as not all
+// sections contain csects, and some sections contain csects which are better
+// stored separately, e.g. the .data section containing read-write, descriptor,
+// TOCBase and TOC-entry csects.
+struct Section {
+ char Name[XCOFF::NameSize];
+ // The physical/virtual address of the section. For an object file
+ // these values are equivalent.
+ uint32_t Address;
+ uint32_t Size;
+ uint32_t FileOffsetToData;
+ uint32_t FileOffsetToRelocations;
+ uint32_t RelocationCount;
+ int32_t Flags;
+
+ int16_t Index;
+
+ // Virtual sections do not need storage allocated in the object file.
+ const bool IsVirtual;
+
+ void reset() {
+ Address = 0;
+ Size = 0;
+ FileOffsetToData = 0;
+ FileOffsetToRelocations = 0;
+ RelocationCount = 0;
+ Index = -1;
+ }
+
+ Section(const char *N, XCOFF::SectionTypeFlags Flags, bool IsVirtual)
+ : Address(0), Size(0), FileOffsetToData(0), FileOffsetToRelocations(0),
+ RelocationCount(0), Flags(Flags), Index(-1), IsVirtual(IsVirtual) {
+ strncpy(Name, N, XCOFF::NameSize);
+ }
+};
+
+class XCOFFObjectWriter : public MCObjectWriter {
+ // Type to be used for a container representing a set of csects with
+ // (approximately) the same storage mapping class. For example all the csects
+ // with a storage mapping class of `xmc_pr` will get placed into the same
+ // container.
+ using CsectGroup = std::deque<ControlSection>;
+
+ support::endian::Writer W;
+ std::unique_ptr<MCXCOFFObjectTargetWriter> TargetObjectWriter;
+ StringTableBuilder Strings;
+
+ // The non-empty sections, in the order they will appear in the section header
+ // table.
+ std::vector<Section *> Sections;
+
+ // The Predefined sections.
+ Section Text;
+ Section BSS;
+
+ // CsectGroups. These store the csects which make up different parts of
+ // the sections. Should have one for each set of csects that get mapped into
+ // the same section and get handled in a 'similar' way.
+ CsectGroup ProgramCodeCsects;
+ CsectGroup BSSCsects;
+
+ uint32_t SymbolTableEntryCount = 0;
+ uint32_t SymbolTableOffset = 0;
+
+ virtual void reset() override;
+
+ void executePostLayoutBinding(MCAssembler &, const MCAsmLayout &) override;
+
+ void recordRelocation(MCAssembler &, const MCAsmLayout &, const MCFragment *,
+ const MCFixup &, MCValue, uint64_t &) override;
+
+ uint64_t writeObject(MCAssembler &, const MCAsmLayout &) override;
+
+ static bool nameShouldBeInStringTable(const StringRef &);
+ void writeSymbolName(const StringRef &);
+ void writeSymbolTableEntryForCsectMemberLabel(const Symbol &,
+ const ControlSection &, int16_t,
+ uint64_t);
+ void writeSymbolTableEntryForControlSection(const ControlSection &, int16_t,
+ XCOFF::StorageClass);
+ void writeFileHeader();
+ void writeSectionHeaderTable();
+ void writeSections(const MCAssembler &Asm, const MCAsmLayout &Layout);
+ void writeSymbolTable(const MCAsmLayout &Layout);
+
+ // Called after all the csects and symbols have been processed by
+ // `executePostLayoutBinding`, this function handles building up the majority
+ // of the structures in the object file representation. Namely:
+ // *) Calculates physical/virtual addresses, raw-pointer offsets, and section
+ // sizes.
+ // *) Assigns symbol table indices.
+ // *) Builds up the section header table by adding any non-empty sections to
+ // `Sections`.
+ void assignAddressesAndIndices(const MCAsmLayout &);
+
+ bool
+ needsAuxiliaryHeader() const { /* TODO aux header support not implemented. */
+ return false;
+ }
+
+ // Returns the size of the auxiliary header to be written to the object file.
+ size_t auxiliaryHeaderSize() const {
+ assert(!needsAuxiliaryHeader() &&
+ "Auxiliary header support not implemented.");
+ return 0;
+ }
+
+public:
+ XCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS);
+};
+
+XCOFFObjectWriter::XCOFFObjectWriter(
+ std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW, raw_pwrite_stream &OS)
+ : W(OS, support::big), TargetObjectWriter(std::move(MOTW)),
+ Strings(StringTableBuilder::XCOFF),
+ Text(".text", XCOFF::STYP_TEXT, /* IsVirtual */ false),
+ BSS(".bss", XCOFF::STYP_BSS, /* IsVirtual */ true) {}
+
+void XCOFFObjectWriter::reset() {
+ // Reset any sections we have written to, and empty the section header table.
+ for (auto *Sec : Sections)
+ Sec->reset();
+ Sections.clear();
+
+ // Clear any csects we have stored.
+ ProgramCodeCsects.clear();
+ BSSCsects.clear();
+
+ // Reset the symbol table and string table.
+ SymbolTableEntryCount = 0;
+ SymbolTableOffset = 0;
+ Strings.clear();
+
+ MCObjectWriter::reset();
+}
+
+void XCOFFObjectWriter::executePostLayoutBinding(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ if (TargetObjectWriter->is64Bit())
+ report_fatal_error("64-bit XCOFF object files are not supported yet.");
+
+ // Maps the MC Section representation to its corresponding ControlSection
+ // wrapper. Needed for finding the ControlSection to insert an MCSymbol into
+ // from its containing MCSectionXCOFF.
+ DenseMap<const MCSectionXCOFF *, ControlSection *> WrapperMap;
+
+ for (const auto &S : Asm) {
+ const auto *MCSec = cast<const MCSectionXCOFF>(&S);
+ assert(WrapperMap.find(MCSec) == WrapperMap.end() &&
+ "Cannot add a csect twice.");
+
+ // If the name does not fit in the storage provided in the symbol table
+ // entry, add it to the string table.
+ if (nameShouldBeInStringTable(MCSec->getSectionName()))
+ Strings.add(MCSec->getSectionName());
+
+ switch (MCSec->getMappingClass()) {
+ case XCOFF::XMC_PR:
+ assert(XCOFF::XTY_SD == MCSec->getCSectType() &&
+ "Only an initialized csect can contain program code.");
+ ProgramCodeCsects.emplace_back(MCSec);
+ WrapperMap[MCSec] = &ProgramCodeCsects.back();
+ break;
+ case XCOFF::XMC_RW:
+ if (XCOFF::XTY_CM == MCSec->getCSectType()) {
+ BSSCsects.emplace_back(MCSec);
+ WrapperMap[MCSec] = &BSSCsects.back();
+ break;
+ }
+ report_fatal_error("Unhandled mapping of read-write csect to section.");
+ case XCOFF::XMC_TC0:
+ // TODO FIXME Handle emiting the TOC base.
+ break;
+ case XCOFF::XMC_BS:
+ assert(XCOFF::XTY_CM == MCSec->getCSectType() &&
+ "Mapping invalid csect. CSECT with bss storage class must be "
+ "common type.");
+ BSSCsects.emplace_back(MCSec);
+ WrapperMap[MCSec] = &BSSCsects.back();
+ break;
+ default:
+ report_fatal_error("Unhandled mapping of csect to section.");
+ }
+ }
+
+ for (const MCSymbol &S : Asm.symbols()) {
+ // Nothing to do for temporary symbols.
+ if (S.isTemporary())
+ continue;
+ const MCSymbolXCOFF *XSym = cast<MCSymbolXCOFF>(&S);
+
+ // Map the symbol into its containing csect.
+ const MCSectionXCOFF *ContainingCsect = XSym->getContainingCsect();
+ assert(WrapperMap.find(ContainingCsect) != WrapperMap.end() &&
+ "Expected containing csect to exist in map");
+
+ // Lookup the containing csect and add the symbol to it.
+ WrapperMap[ContainingCsect]->Syms.emplace_back(XSym);
+
+ // If the name does not fit in the storage provided in the symbol table
+ // entry, add it to the string table.
+ if (nameShouldBeInStringTable(XSym->getName()))
+ Strings.add(XSym->getName());
+ }
+
+ Strings.finalize();
+ assignAddressesAndIndices(Layout);
+}
+
+void XCOFFObjectWriter::recordRelocation(MCAssembler &, const MCAsmLayout &,
+ const MCFragment *, const MCFixup &,
+ MCValue, uint64_t &) {
+ report_fatal_error("XCOFF relocations not supported.");
+}
+
+void XCOFFObjectWriter::writeSections(const MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ // Write the program code control sections one at a time.
+ uint32_t CurrentAddressLocation = Text.Address;
+ for (const auto &Csect : ProgramCodeCsects) {
+ if (uint32_t PaddingSize = Csect.Address - CurrentAddressLocation)
+ W.OS.write_zeros(PaddingSize);
+ Asm.writeSectionData(W.OS, Csect.MCCsect, Layout);
+ CurrentAddressLocation = Csect.Address + Csect.Size;
+ }
+
+ if (Text.Index != -1) {
+ // The size of the tail padding in a section is the end virtual address of
+ // the current section minus the the end virtual address of the last csect
+ // in that section.
+ if (uint32_t PaddingSize =
+ Text.Address + Text.Size - CurrentAddressLocation)
+ W.OS.write_zeros(PaddingSize);
+ }
+}
+
+uint64_t XCOFFObjectWriter::writeObject(MCAssembler &Asm,
+ const MCAsmLayout &Layout) {
+ // We always emit a timestamp of 0 for reproducibility, so ensure incremental
+ // linking is not enabled, in case, like with Windows COFF, such a timestamp
+ // is incompatible with incremental linking of XCOFF.
+ if (Asm.isIncrementalLinkerCompatible())
+ report_fatal_error("Incremental linking not supported for XCOFF.");
+
+ if (TargetObjectWriter->is64Bit())
+ report_fatal_error("64-bit XCOFF object files are not supported yet.");
+
+ uint64_t StartOffset = W.OS.tell();
+
+ writeFileHeader();
+ writeSectionHeaderTable();
+ writeSections(Asm, Layout);
+ // TODO writeRelocations();
+
+ writeSymbolTable(Layout);
+ // Write the string table.
+ Strings.write(W.OS);
+
+ return W.OS.tell() - StartOffset;
+}
+
+bool XCOFFObjectWriter::nameShouldBeInStringTable(const StringRef &SymbolName) {
+ return SymbolName.size() > XCOFF::NameSize;
+}
+
+void XCOFFObjectWriter::writeSymbolName(const StringRef &SymbolName) {
+ if (nameShouldBeInStringTable(SymbolName)) {
+ W.write<int32_t>(0);
+ W.write<uint32_t>(Strings.getOffset(SymbolName));
+ } else {
+ char Name[XCOFF::NameSize];
+ std::strncpy(Name, SymbolName.data(), XCOFF::NameSize);
+ ArrayRef<char> NameRef(Name, XCOFF::NameSize);
+ W.write(NameRef);
+ }
+}
+
+void XCOFFObjectWriter::writeSymbolTableEntryForCsectMemberLabel(
+ const Symbol &SymbolRef, const ControlSection &CSectionRef,
+ int16_t SectionIndex, uint64_t SymbolOffset) {
+ // Name or Zeros and string table offset
+ writeSymbolName(SymbolRef.getName());
+ assert(SymbolOffset <= UINT32_MAX - CSectionRef.Address &&
+ "Symbol address overflows.");
+ W.write<uint32_t>(CSectionRef.Address + SymbolOffset);
+ W.write<int16_t>(SectionIndex);
+ // Basic/Derived type. See the description of the n_type field for symbol
+ // table entries for a detailed description. Since we don't yet support
+ // visibility, and all other bits are either optionally set or reserved, this
+ // is always zero.
+ // TODO FIXME How to assert a symbol's visibilty is default?
+ // TODO Set the function indicator (bit 10, 0x0020) for functions
+ // when debugging is enabled.
+ W.write<uint16_t>(0);
+ W.write<uint8_t>(SymbolRef.getStorageClass());
+ // Always 1 aux entry for now.
+ W.write<uint8_t>(1);
+
+ // Now output the auxiliary entry.
+ W.write<uint32_t>(CSectionRef.SymbolTableIndex);
+ // Parameter typecheck hash. Not supported.
+ W.write<uint32_t>(0);
+ // Typecheck section number. Not supported.
+ W.write<uint16_t>(0);
+ // Symbol type: Label
+ W.write<uint8_t>(XCOFF::XTY_LD);
+ // Storage mapping class.
+ W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
+ // Reserved (x_stab).
+ W.write<uint32_t>(0);
+ // Reserved (x_snstab).
+ W.write<uint16_t>(0);
+}
+
+void XCOFFObjectWriter::writeSymbolTableEntryForControlSection(
+ const ControlSection &CSectionRef, int16_t SectionIndex,
+ XCOFF::StorageClass StorageClass) {
+ // n_name, n_zeros, n_offset
+ writeSymbolName(CSectionRef.getName());
+ // n_value
+ W.write<uint32_t>(CSectionRef.Address);
+ // n_scnum
+ W.write<int16_t>(SectionIndex);
+ // Basic/Derived type. See the description of the n_type field for symbol
+ // table entries for a detailed description. Since we don't yet support
+ // visibility, and all other bits are either optionally set or reserved, this
+ // is always zero.
+ // TODO FIXME How to assert a symbol's visibilty is default?
+ // TODO Set the function indicator (bit 10, 0x0020) for functions
+ // when debugging is enabled.
+ W.write<uint16_t>(0);
+ // n_sclass
+ W.write<uint8_t>(StorageClass);
+ // Always 1 aux entry for now.
+ W.write<uint8_t>(1);
+
+ // Now output the auxiliary entry.
+ W.write<uint32_t>(CSectionRef.Size);
+ // Parameter typecheck hash. Not supported.
+ W.write<uint32_t>(0);
+ // Typecheck section number. Not supported.
+ W.write<uint16_t>(0);
+ // Symbol type.
+ W.write<uint8_t>(getEncodedType(CSectionRef.MCCsect));
+ // Storage mapping class.
+ W.write<uint8_t>(CSectionRef.MCCsect->getMappingClass());
+ // Reserved (x_stab).
+ W.write<uint32_t>(0);
+ // Reserved (x_snstab).
+ W.write<uint16_t>(0);
+}
+
+void XCOFFObjectWriter::writeFileHeader() {
+ // Magic.
+ W.write<uint16_t>(0x01df);
+ // Number of sections.
+ W.write<uint16_t>(Sections.size());
+ // Timestamp field. For reproducible output we write a 0, which represents no
+ // timestamp.
+ W.write<int32_t>(0);
+ // Byte Offset to the start of the symbol table.
+ W.write<uint32_t>(SymbolTableOffset);
+ // Number of entries in the symbol table.
+ W.write<int32_t>(SymbolTableEntryCount);
+ // Size of the optional header.
+ W.write<uint16_t>(0);
+ // Flags.
+ W.write<uint16_t>(0);
+}
+
+void XCOFFObjectWriter::writeSectionHeaderTable() {
+ for (const auto *Sec : Sections) {
+ // Write Name.
+ ArrayRef<char> NameRef(Sec->Name, XCOFF::NameSize);
+ W.write(NameRef);
+
+ // Write the Physical Address and Virtual Address. In an object file these
+ // are the same.
+ W.write<uint32_t>(Sec->Address);
+ W.write<uint32_t>(Sec->Address);
+
+ W.write<uint32_t>(Sec->Size);
+ W.write<uint32_t>(Sec->FileOffsetToData);
+
+ // Relocation pointer and Lineno pointer. Not supported yet.
+ W.write<uint32_t>(0);
+ W.write<uint32_t>(0);
+
+ // Relocation and line-number counts. Not supported yet.
+ W.write<uint16_t>(0);
+ W.write<uint16_t>(0);
+
+ W.write<int32_t>(Sec->Flags);
+ }
+}
+
+void XCOFFObjectWriter::writeSymbolTable(const MCAsmLayout &Layout) {
+ // Print out symbol table for the program code.
+ for (const auto &Csect : ProgramCodeCsects) {
+ // Write out the control section first and then each symbol in it.
+ writeSymbolTableEntryForControlSection(Csect, Text.Index,
+ Csect.MCCsect->getStorageClass());
+ for (const auto &Sym : Csect.Syms)
+ writeSymbolTableEntryForCsectMemberLabel(
+ Sym, Csect, Text.Index, Layout.getSymbolOffset(*Sym.MCSym));
+ }
+
+ // The BSS Section is special in that the csects must contain a single symbol,
+ // and the contained symbol cannot be represented in the symbol table as a
+ // label definition.
+ for (auto &Csect : BSSCsects) {
+ assert(Csect.Syms.size() == 1 &&
+ "Uninitialized csect cannot contain more then 1 symbol.");
+ Symbol &Sym = Csect.Syms.back();
+ writeSymbolTableEntryForControlSection(Csect, BSS.Index,
+ Sym.getStorageClass());
+ }
+}
+
+void XCOFFObjectWriter::assignAddressesAndIndices(const MCAsmLayout &Layout) {
+ // The address corrresponds to the address of sections and symbols in the
+ // object file. We place the shared address 0 immediately after the
+ // section header table.
+ uint32_t Address = 0;
+ // Section indices are 1-based in XCOFF.
+ int16_t SectionIndex = 1;
+ // The first symbol table entry is for the file name. We are not emitting it
+ // yet, so start at index 0.
+ uint32_t SymbolTableIndex = 0;
+
+ // Text section comes first.
+ if (!ProgramCodeCsects.empty()) {
+ Sections.push_back(&Text);
+ Text.Index = SectionIndex++;
+ for (auto &Csect : ProgramCodeCsects) {
+ const MCSectionXCOFF *MCSec = Csect.MCCsect;
+ Csect.Address = alignTo(Address, MCSec->getAlignment());
+ Csect.Size = Layout.getSectionAddressSize(MCSec);
+ Address = Csect.Address + Csect.Size;
+ Csect.SymbolTableIndex = SymbolTableIndex;
+ // 1 main and 1 auxiliary symbol table entry for the csect.
+ SymbolTableIndex += 2;
+ for (auto &Sym : Csect.Syms) {
+ Sym.SymbolTableIndex = SymbolTableIndex;
+ // 1 main and 1 auxiliary symbol table entry for each contained symbol
+ SymbolTableIndex += 2;
+ }
+ }
+ Address = alignTo(Address, DefaultSectionAlign);
+
+ // The first csect of a section can be aligned by adjusting the virtual
+ // address of its containing section instead of writing zeroes into the
+ // object file.
+ Text.Address = ProgramCodeCsects.front().Address;
+
+ Text.Size = Address - Text.Address;
+ }
+
+ // Data section Second. TODO
+
+ // BSS Section third.
+ if (!BSSCsects.empty()) {
+ Sections.push_back(&BSS);
+ BSS.Index = SectionIndex++;
+ for (auto &Csect : BSSCsects) {
+ const MCSectionXCOFF *MCSec = Csect.MCCsect;
+ Csect.Address = alignTo(Address, MCSec->getAlignment());
+ Csect.Size = Layout.getSectionAddressSize(MCSec);
+ Address = Csect.Address + Csect.Size;
+ Csect.SymbolTableIndex = SymbolTableIndex;
+ // 1 main and 1 auxiliary symbol table entry for the csect.
+ SymbolTableIndex += 2;
+
+ assert(Csect.Syms.size() == 1 &&
+ "csect in the BSS can only contain a single symbol.");
+ Csect.Syms[0].SymbolTableIndex = Csect.SymbolTableIndex;
+ }
+ // Pad out Address to the default alignment. This is to match how the system
+ // assembler handles the .bss section. Its size is always a multiple of 4.
+ Address = alignTo(Address, DefaultSectionAlign);
+
+ BSS.Address = BSSCsects.front().Address;
+ BSS.Size = Address - BSS.Address;
+ }
+
+ SymbolTableEntryCount = SymbolTableIndex;
+
+ // Calculate the RawPointer value for each section.
+ uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() +
+ Sections.size() * sizeof(XCOFF::SectionHeader32);
+ for (auto *Sec : Sections) {
+ if (!Sec->IsVirtual) {
+ Sec->FileOffsetToData = RawPointer;
+ RawPointer += Sec->Size;
+ }
+ }
+
+ // TODO Add in Relocation storage to the RawPointer Calculation.
+ // TODO What to align the SymbolTable to?
+ // TODO Error check that the number of symbol table entries fits in 32-bits
+ // signed ...
+ if (SymbolTableEntryCount)
+ SymbolTableOffset = RawPointer;
+}
+
+// Takes the log base 2 of the alignment and shifts the result into the 5 most
+// significant bits of a byte, then or's in the csect type into the least
+// significant 3 bits.
+uint8_t getEncodedType(const MCSectionXCOFF *Sec) {
+ unsigned Align = Sec->getAlignment();
+ assert(isPowerOf2_32(Align) && "Alignment must be a power of 2.");
+ unsigned Log2Align = Log2_32(Align);
+ // Result is a number in the range [0, 31] which fits in the 5 least
+ // significant bits. Shift this value into the 5 most significant bits, and
+ // bitwise-or in the csect type.
+ uint8_t EncodedAlign = Log2Align << 3;
+ return EncodedAlign | Sec->getCSectType();
+}
+
+} // end anonymous namespace
+
+std::unique_ptr<MCObjectWriter>
+llvm::createXCOFFObjectWriter(std::unique_ptr<MCXCOFFObjectTargetWriter> MOTW,
+ raw_pwrite_stream &OS) {
+ return std::make_unique<XCOFFObjectWriter>(std::move(MOTW), OS);
+}