diff options
Diffstat (limited to 'llvm/lib/MC')
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); +}  | 
