diff options
Diffstat (limited to 'contrib/llvm/lib/MC')
71 files changed, 32573 insertions, 0 deletions
diff --git a/contrib/llvm/lib/MC/ConstantPools.cpp b/contrib/llvm/lib/MC/ConstantPools.cpp new file mode 100644 index 000000000000..18277a225640 --- /dev/null +++ b/contrib/llvm/lib/MC/ConstantPools.cpp @@ -0,0 +1,116 @@ +//===- ConstantPools.cpp - ConstantPool class -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/contrib/llvm/lib/MC/ELFObjectWriter.cpp b/contrib/llvm/lib/MC/ELFObjectWriter.cpp new file mode 100644 index 000000000000..89f3b30cddd6 --- /dev/null +++ b/contrib/llvm/lib/MC/ELFObjectWriter.cpp @@ -0,0 +1,1539 @@ +//===- lib/MC/ELFObjectWriter.cpp - ELF File Writer -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/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(), 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()); + W.OS << char(0); // e_ident[EI_ABIVERSION] + + 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.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; +} + +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 (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(); + 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() ? 8 : 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()) { + 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_shndxr", ELF::SHT_SYMTAB_SHNDX, 0, 4, ""); + SymtabShndxSectionIndex = addToSectionTable(SymtabShndxSection); + SymtabShndxSection->setAlignment(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() ? 8 : 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); + 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(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()); + + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; + + // FIXME: produce a better error message. + if (Symbol.isUndefined() && Rest.startswith("@@") && + !Rest.startswith("@@@")) + report_fatal_error("A @@ version cannot be undefined"); + + if (Renames.count(&Symbol) && Renames[&Symbol] != Alias) + report_fatal_error(llvm::Twine("Multiple symbol versions defined for ") + + Symbol.getName()); + + 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; + } + + // 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()) { + // Let A, B and C being the components of Target and R be the location of + // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). + // If it is pcrel, we want to compute (A - B + C - R). + + // In general, ELF has no relocations for -B. It can only represent (A + C) + // or (A + C - R). If B = R + K and the relocation is not pcrel, we can + // replace B to implement it: (A - R - K + C) + if (IsPCRel) { + Ctx.reportError( + Fixup.getLoc(), + "No relocation available to represent this relative expression"); + return; + } + + 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; + } + + uint64_t SymBOffset = Layout.getSymbolOffset(SymB); + uint64_t K = SymBOffset - FixupOffset; + IsPCRel = true; + C -= K; + } + + // 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; + } + } + } + + unsigned Type = TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel); + uint64_t OriginalC = C; + bool RelocateWithSymbol = shouldRelocateWithSymbol(Asm, RefA, SymA, C, Type); + if (!RelocateWithSymbol && SymA && !SymA->isUndefined()) + C += Layout.getSymbolOffset(*SymA); + + uint64_t Addend = 0; + if (hasRelocationAddend()) { + Addend = C; + C = 0; + } + + FixedValue = C; + + const MCSectionELF *SecA = (SymA && SymA->isInSection()) + ? cast<MCSectionELF>(&SymA->getSection()) + : nullptr; + if (!checkRelocation(Ctx, Fixup.getLoc(), &FixupSection, SecA)) + return; + + if (!RelocateWithSymbol) { + const auto *SectionSymbol = + SecA ? cast<MCSymbolELF>(SecA->getBeginSymbol()) : nullptr; + if (SectionSymbol) + SectionSymbol->setUsedInReloc(); + ELFRelocationEntry Rec(FixupOffset, SectionSymbol, Type, Addend, SymA, + OriginalC); + Relocations[&FixupSection].push_back(Rec); + return; + } + + const auto *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, + OriginalC); + 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 llvm::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 llvm::make_unique<ELFDwoObjectWriter>(std::move(MOTW), OS, DwoOS, + IsLittleEndian); +} diff --git a/contrib/llvm/lib/MC/MCAsmBackend.cpp b/contrib/llvm/lib/MC/MCAsmBackend.cpp new file mode 100644 index 000000000000..92d3a8a2645f --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmBackend.cpp @@ -0,0 +1,130 @@ +//===- MCAsmBackend.cpp - Target MC Assembly Backend ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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 <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); + 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_Data_1", 0, 8, 0}, + {"FK_Data_2", 0, 16, 0}, + {"FK_Data_4", 0, 32, 0}, + {"FK_Data_8", 0, 64, 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_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}}; + + 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/contrib/llvm/lib/MC/MCAsmInfo.cpp b/contrib/llvm/lib/MC/MCAsmInfo.cpp new file mode 100644 index 000000000000..30f22d2d68f4 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfo.cpp @@ -0,0 +1,123 @@ +//===- MCAsmInfo.cpp - Asm Info -------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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; + +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/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp b/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp new file mode 100644 index 000000000000..15886eb619b9 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp @@ -0,0 +1,69 @@ +//===- MCAsmInfoCOFF.cpp - COFF asm properties ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp b/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp new file mode 100644 index 000000000000..c74840982fb7 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp @@ -0,0 +1,98 @@ +//===- MCAsmInfoDarwin.cpp - Darwin asm properties ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/contrib/llvm/lib/MC/MCAsmInfoELF.cpp b/contrib/llvm/lib/MC/MCAsmInfoELF.cpp new file mode 100644 index 000000000000..b0dc43c6c868 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoELF.cpp @@ -0,0 +1,35 @@ +//===- MCAsmInfoELF.cpp - ELF asm properties ------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/contrib/llvm/lib/MC/MCAsmInfoWasm.cpp b/contrib/llvm/lib/MC/MCAsmInfoWasm.cpp new file mode 100644 index 000000000000..d448664baa14 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoWasm.cpp @@ -0,0 +1,25 @@ +//===-- MCAsmInfoWasm.cpp - Wasm asm properties -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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; + WeakRefDirective = "\t.weak\t"; + PrivateGlobalPrefix = ".L"; + PrivateLabelPrefix = ".L"; +} diff --git a/contrib/llvm/lib/MC/MCAsmMacro.cpp b/contrib/llvm/lib/MC/MCAsmMacro.cpp new file mode 100644 index 000000000000..7e89c03c6c6b --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmMacro.cpp @@ -0,0 +1,42 @@ +//===- MCAsmMacro.h - Assembly Macros ---------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmMacro.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +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"; +} diff --git a/contrib/llvm/lib/MC/MCAsmStreamer.cpp b/contrib/llvm/lib/MC/MCAsmStreamer.cpp new file mode 100644 index 000000000000..e017103070bf --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmStreamer.cpp @@ -0,0 +1,1950 @@ +//===- lib/MC/MCAsmStreamer.cpp - Text Assembly Output ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/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/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(llvm::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. + /// If PrintSchedInfo is true, then the comment sched:[x:y] will be added to + /// the output if supported by the target. + void AddEncodingComment(const MCInst &Inst, const MCSubtargetInfo &, + bool PrintSchedInfo); + + /// 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 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 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, + MD5::MD5Result *Checksum = 0, + Optional<StringRef> Source = None, + unsigned CUID = 0) override; + void emitDwarfFile0Directive(StringRef Directory, StringRef Filename, + 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 EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion) 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(unsigned Register, SMLoc Loc) override; + void EmitWinCFISetFrame(unsigned Register, unsigned Offset, + SMLoc Loc) override; + void EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) override; + void EmitWinCFISaveReg(unsigned Register, unsigned Offset, + SMLoc Loc) override; + void EmitWinCFISaveXMM(unsigned 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, + bool PrintSchedInfo) 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_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_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; + } + + 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(); +} + +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::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) { + // 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, + 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, + 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, 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, + 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::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion) { + 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); + } + OS << ", "; + PrintQuotedString(FixedSizePortion, OS); + EmitEOL(); + this->MCStreamer::EmitCVDefRangeDirective(Ranges, FixedSizePortion); +} + +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(); + int LLVMRegister = MRI->getLLVMRegNumFromEH(Register); + if (LLVMRegister != -1) { + 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(); + MCSection *TextSec = &CurFrame->Function->getSection(); + MCSection *XData = getAssociatedXDataSection(TextSec); + SwitchSectionNoChange(XData); + + OS << "\t.seh_handlerdata"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { + MCStreamer::EmitWinCFIPushReg(Register, Loc); + + OS << "\t.seh_pushreg " << Register; + EmitEOL(); +} + +void MCAsmStreamer::EmitWinCFISetFrame(unsigned Register, unsigned Offset, + SMLoc Loc) { + MCStreamer::EmitWinCFISetFrame(Register, Offset, Loc); + + OS << "\t.seh_setframe " << Register << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitWinCFIAllocStack(unsigned Size, SMLoc Loc) { + MCStreamer::EmitWinCFIAllocStack(Size, Loc); + + OS << "\t.seh_stackalloc " << Size; + EmitEOL(); +} + +void MCAsmStreamer::EmitWinCFISaveReg(unsigned Register, unsigned Offset, + SMLoc Loc) { + MCStreamer::EmitWinCFISaveReg(Register, Offset, Loc); + + OS << "\t.seh_savereg " << Register << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitWinCFISaveXMM(unsigned Register, unsigned Offset, + SMLoc Loc) { + MCStreamer::EmitWinCFISaveXMM(Register, Offset, Loc); + + OS << "\t.seh_savexmm " << Register << ", " << 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, + bool PrintSchedInfo) { + 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 << "]"; + // If we are not going to add fixup or schedule comments after this point + // then we have to end the current comment line with "\n". + if (Fixups.size() || !PrintSchedInfo) + 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, + bool PrintSchedInfo) { + assert(getCurrentSectionOnly() && + "Cannot emit contents before setting section!"); + + // Show the encoding in a comment if we have a code emitter. + AddEncodingComment(Inst, STI, PrintSchedInfo); + + // Show the MCInst if enabled. + if (ShowInst) { + if (PrintSchedInfo) + GetCommentOS() << "\n"; + Inst.dump_pretty(GetCommentOS(), InstPrinter.get(), "\n "); + GetCommentOS() << "\n"; + } + + if(getTargetStreamer()) + getTargetStreamer()->prettyPrintAsm(*InstPrinter, OS, Inst, STI); + else + InstPrinter->printInst(&Inst, OS, "", STI); + + if (PrintSchedInfo) { + std::string SI = STI.getSchedInfoStr(Inst); + if (!SI.empty()) + GetCommentOS() << SI; + } + + 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. + 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/contrib/llvm/lib/MC/MCAssembler.cpp b/contrib/llvm/lib/MC/MCAssembler.cpp new file mode 100644 index 000000000000..cde6a93a1647 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAssembler.cpp @@ -0,0 +1,1125 @@ +//===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/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, AF.getAlignment()); + // 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)) + 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 + 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; + if (getBackend().requiresDiffExpressionRelocations()) + Abs = DF.getAddrDelta().evaluateAsAbsolute(AddrDelta, Layout); + else { + Abs = DF.getAddrDelta().evaluateKnownAbsolute(AddrDelta, Layout); + assert(Abs && "We created a line delta with an invalid expression"); + } + int64_t LineDelta; + LineDelta = DF.getLineDelta(); + SmallVectorImpl<char> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + DF.getFixups().clear(); + + if (Abs) { + 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; + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + 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/contrib/llvm/lib/MC/MCCodeEmitter.cpp b/contrib/llvm/lib/MC/MCCodeEmitter.cpp new file mode 100644 index 000000000000..ca69478ed10d --- /dev/null +++ b/contrib/llvm/lib/MC/MCCodeEmitter.cpp @@ -0,0 +1,16 @@ +//===- MCCodeEmitter.cpp - Instruction Encoding ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCCodeEmitter.h" + +using namespace llvm; + +MCCodeEmitter::MCCodeEmitter() = default; + +MCCodeEmitter::~MCCodeEmitter() = default; diff --git a/contrib/llvm/lib/MC/MCCodePadder.cpp b/contrib/llvm/lib/MC/MCCodePadder.cpp new file mode 100644 index 000000000000..57547814e595 --- /dev/null +++ b/contrib/llvm/lib/MC/MCCodePadder.cpp @@ -0,0 +1,371 @@ +//===- MCCodePadder.cpp - Target MC Code Padder ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCCodeView.cpp b/contrib/llvm/lib/MC/MCCodeView.cpp new file mode 100644 index 000000000000..978ac789c31e --- /dev/null +++ b/contrib/llvm/lib/MC/MCCodeView.cpp @@ -0,0 +1,697 @@ +//===- MCCodeView.h - Machine Code CodeView support -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/contrib/llvm/lib/MC/MCContext.cpp b/contrib/llvm/lib/MC/MCContext.cpp new file mode 100644 index 000000000000..fab517075c5a --- /dev/null +++ b/contrib/llvm/lib/MC/MCContext.cpp @@ -0,0 +1,634 @@ +//===- lib/MC/MCContext.cpp - Machine Code Context ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/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/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/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, + bool DoAutoReset) + : SrcMgr(mgr), InlineSrcMgr(nullptr), MAI(mai), MRI(mri), MOFI(mofi), + Symbols(Allocator), UsedNames(Allocator), + CurrentDwarfLoc(0, 0, 0, DWARF2_FLAG_IS_STMT, 0, 0), + AutoReset(DoAutoReset) { + 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(); + + MCSubtargetAllocator.DestroyAll(); + 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(); + + 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); + } + } + 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)); +} + +//===----------------------------------------------------------------------===// +// 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::getCOFFSection(StringRef Section) { + COFFSectionKey T{Section, "", 0, GenericSectionID}; + auto Iter = COFFUniquingMap.find(T); + if (Iter == COFFUniquingMap.end()) + return nullptr; + return Iter->second; +} + +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; +} + +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 +//===----------------------------------------------------------------------===// + +/// 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, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID) { + MCDwarfLineTable &Table = MCDwarfLineTablesCUMap[CUID]; + return Table.tryGetFile(Directory, FileName, Checksum, Source, 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 && LineTable.hasRootFile(); + 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::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/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp new file mode 100644 index 000000000000..ad0a39991c53 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp @@ -0,0 +1,342 @@ +//===-- lib/MC/Disassembler.cpp - Disassembler Public C Interface ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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; + + const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(TT); + if (!MRI) + return nullptr; + + // Get the assembler info needed to setup the MCContext. + const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(*MRI, TT); + if (!MAI) + return nullptr; + + const MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + if (!MII) + return nullptr; + + const MCSubtargetInfo *STI = + TheTarget->createMCSubtargetInfo(TT, CPU, Features); + if (!STI) + return nullptr; + + // Set up the MCContext for creating symbols and MCExpr's. + MCContext *Ctx = new MCContext(MAI, MRI, nullptr); + if (!Ctx) + return nullptr; + + // Set up disassembler. + 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, std::move(RelInfo))); + DisAsm->setSymbolizer(std::move(Symbolizer)); + + // Set up the instruction printer. + int AsmPrinterVariant = MAI->getAssemblerDialect(); + MCInstPrinter *IP = TheTarget->createMCInstPrinter( + Triple(TT), AsmPrinterVariant, *MAI, *MII, *MRI); + if (!IP) + return nullptr; + + LLVMDisasmContext *DC = + new LLVMDisasmContext(TT, DisInfo, TagType, GetOpInfo, SymbolLookUp, + TheTarget, MAI, MRI, STI, MII, Ctx, DisAsm, 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/contrib/llvm/lib/MC/MCDisassembler/Disassembler.h b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.h new file mode 100644 index 000000000000..f638fdc781d7 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.h @@ -0,0 +1,127 @@ +//===------------- Disassembler.h - LLVM Disassembler -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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, const MCAsmInfo *mAI, + const MCRegisterInfo *mRI, const MCSubtargetInfo *mSI, + const MCInstrInfo *mII, llvm::MCContext *ctx, + const MCDisassembler *disAsm, MCInstPrinter *iP) + : TripleName(std::move(tripleName)), DisInfo(disInfo), TagType(tagType), + GetOpInfo(getOpInfo), SymbolLookUp(symbolLookUp), TheTarget(theTarget), + Options(0), CommentStream(CommentsToEmit) { + MAI.reset(mAI); + MRI.reset(mRI); + MSI.reset(mSI); + MII.reset(mII); + Ctx.reset(ctx); + DisAsm.reset(disAsm); + IP.reset(iP); + } + 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/contrib/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp new file mode 100644 index 000000000000..2f1275d00b86 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/MCDisassembler.cpp @@ -0,0 +1,38 @@ +//===- MCDisassembler.cpp - Disassembler interface ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCDisassembler/MCDisassembler.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; + +MCDisassembler::~MCDisassembler() = default; + +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/contrib/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp b/contrib/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp new file mode 100644 index 000000000000..1969c5dc66ab --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/MCExternalSymbolizer.cpp @@ -0,0 +1,200 @@ +//===-- MCExternalSymbolizer.cpp - External symbolizer --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp b/contrib/llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp new file mode 100644 index 000000000000..8f932a3f0d48 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/MCRelocationInfo.cpp @@ -0,0 +1,31 @@ +//===-- MCRelocationInfo.cpp ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp b/contrib/llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp new file mode 100644 index 000000000000..78e611e3ddda --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/MCSymbolizer.cpp @@ -0,0 +1,14 @@ +//===-- llvm/MC/MCSymbolizer.cpp - MCSymbolizer class ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCDisassembler/MCSymbolizer.h" + +using namespace llvm; + +MCSymbolizer::~MCSymbolizer() = default; diff --git a/contrib/llvm/lib/MC/MCDwarf.cpp b/contrib/llvm/lib/MC/MCDwarf.cpp new file mode 100644 index 000000000000..38b02694d81d --- /dev/null +++ b/contrib/llvm/lib/MC/MCDwarf.cpp @@ -0,0 +1,1884 @@ +//===- lib/MC/MCDwarf.cpp - MCDwarf implementation ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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 (Header.MCDwarfFiles.empty()) + 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) { + 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, + StringRef CtxCompilationDir) 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() ? CtxCompilationDir : 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. 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. + MCOS->EmitULEB128IntValue(MCDwarfFiles.size()); + 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, context.getCompilationDir()); + 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, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned FileNumber) { + return Header.tryGetFile(Directory, FileName, Checksum, Source, FileNumber); +} + +Expected<unsigned> +MCDwarfLineTableHeader::tryGetFile(StringRef &Directory, + StringRef &FileName, + MD5::MD5Result *Checksum, + Optional<StringRef> &Source, + 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); + HasSource = (Source != None); + } + 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 = 0; + for (unsigned End = MCDwarfDirs.size(); DirIndex < End; DirIndex++) { + if (Directory == MCDwarfDirs[DirIndex]) + break; + } + 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); + 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; + std::vector<uint8_t> FillData; + FillData.insert(FillData.begin(), AddrSize, 0); + OS.write(reinterpret_cast<char *>(FillData.data()), 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 = + MCOS->getContext().getMCDwarfFiles(); + MCOS->EmitBytes(MCDwarfFiles[1].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) {} + + 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(); + for (auto I = FrameArray.begin(), E = FrameArray.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) { + // Scale the address delta by the minimum instruction length. + AddrDelta = ScaleAddrDelta(Context, AddrDelta); + + support::endianness E = + Context.getAsmInfo()->isLittleEndian() ? support::little : support::big; + if (AddrDelta == 0) { + } else if (isUIntN(6, AddrDelta)) { + uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; + OS << Opcode; + } else if (isUInt<8>(AddrDelta)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc1); + OS << uint8_t(AddrDelta); + } else if (isUInt<16>(AddrDelta)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc2); + support::endian::write<uint16_t>(OS, AddrDelta, E); + } else { + assert(isUInt<32>(AddrDelta)); + OS << uint8_t(dwarf::DW_CFA_advance_loc4); + support::endian::write<uint32_t>(OS, AddrDelta, E); + } +} diff --git a/contrib/llvm/lib/MC/MCELFObjectTargetWriter.cpp b/contrib/llvm/lib/MC/MCELFObjectTargetWriter.cpp new file mode 100644 index 000000000000..ff53dd7299c1 --- /dev/null +++ b/contrib/llvm/lib/MC/MCELFObjectTargetWriter.cpp @@ -0,0 +1,31 @@ +//===-- MCELFObjectTargetWriter.cpp - ELF Target Writer Subclass ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCELFObjectWriter.h" + +using namespace llvm; + +MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, uint8_t OSABI_, + uint16_t EMachine_, + bool HasRelocationAddend_) + : OSABI(OSABI_), 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/contrib/llvm/lib/MC/MCELFStreamer.cpp b/contrib/llvm/lib/MC/MCELFStreamer.cpp new file mode 100644 index 000000000000..95b48e6abc74 --- /dev/null +++ b/contrib/llvm/lib/MC/MCELFStreamer.cpp @@ -0,0 +1,706 @@ +//===- lib/MC/MCELFStreamer.cpp - ELF Object Output -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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(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_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"); + } + + 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(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_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/contrib/llvm/lib/MC/MCExpr.cpp b/contrib/llvm/lib/MC/MCExpr.cpp new file mode 100644 index 000000000000..0e4174a7a4c9 --- /dev/null +++ b/contrib/llvm/lib/MC/MCExpr.cpp @@ -0,0 +1,906 @@ +//===- MCExpr.cpp - Assembly Level Expression Implementation --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCExpr.h" +#include "llvm/ADT/Statistic.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: + OS << cast<MCConstantExpr>(*this).getValue(); + 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) { + return new (Ctx) MCConstantExpr(Value); +} + +/* *** */ + +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_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_WebAssembly_FUNCTION: return "FUNCTION"; + case VK_WebAssembly_GLOBAL: return "GLOBAL"; + case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX"; + case VK_WebAssembly_EVENT: return "EVENT"; + 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"; + } + 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("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("function", VK_WebAssembly_FUNCTION) + .Case("global", VK_WebAssembly_GLOBAL) + .Case("typeindex", VK_WebAssembly_TYPEINDEX) + .Case("event", VK_WebAssembly_EVENT) + .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) + .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); +} + +bool MCExpr::evaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout) const { + return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, nullptr); +} + +bool MCExpr::evaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout, + const SectionAddrMap &Addrs) const { + return evaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs); +} + +bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { + return evaluateAsAbsolute(Res, &Asm, nullptr, nullptr); +} + +bool MCExpr::evaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm) const { + return evaluateAsAbsolute(Res, Asm, nullptr, nullptr); +} + +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) const { + // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us + // absolutize differences across sections and that is what the MachO writer + // uses Addrs for. + return evaluateAsAbsolute(Res, Asm, Layout, Addrs, Addrs); +} + +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; +} + +/// 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 && + (InSet || !Asm->getBackend().requiresDiffExpressionRelocations())) { + // 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/contrib/llvm/lib/MC/MCFragment.cpp b/contrib/llvm/lib/MC/MCFragment.cpp new file mode 100644 index 000000000000..d22b117972bf --- /dev/null +++ b/contrib/llvm/lib/MC/MCFragment.cpp @@ -0,0 +1,468 @@ +//===- lib/MC/MCFragment.cpp - Assembler Fragment Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCInst.cpp b/contrib/llvm/lib/MC/MCInst.cpp new file mode 100644 index 000000000000..64f111fc7114 --- /dev/null +++ b/contrib/llvm/lib/MC/MCInst.cpp @@ -0,0 +1,99 @@ +//===- lib/MC/MCInst.cpp - MCInst implementation --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCInstPrinter.cpp b/contrib/llvm/lib/MC/MCInstPrinter.cpp new file mode 100644 index 000000000000..9296fcedb72b --- /dev/null +++ b/contrib/llvm/lib/MC/MCInstPrinter.cpp @@ -0,0 +1,122 @@ +//===- MCInstPrinter.cpp - Convert an MCInst to target assembly syntax ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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"; + for (char i: bytes) { + OS << hex_rep[(i & 0xF0) >> 4]; + OS << hex_rep[i & 0xF]; + OS << ' '; + } +} + +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 ""; +} +StringRef MCInstPrinter::markup(StringRef a, StringRef b) const { + if (getUseMarkup()) + return a; + else + return b; +} + +// 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) + return format("-0x%" PRIx64, -Value); + else + return format("0x%" PRIx64, Value); + case HexStyle::Asm: + if (Value < 0) { + if (needsLeadingZero((uint64_t)(-Value))) + return format("-0%" PRIx64 "h", -Value); + else + return format("-%" PRIx64 "h", -Value); + } else { + if (needsLeadingZero((uint64_t)(Value))) + return format("0%" PRIx64 "h", Value); + else + 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/contrib/llvm/lib/MC/MCInstrAnalysis.cpp b/contrib/llvm/lib/MC/MCInstrAnalysis.cpp new file mode 100644 index 000000000000..8223f3a5c66f --- /dev/null +++ b/contrib/llvm/lib/MC/MCInstrAnalysis.cpp @@ -0,0 +1,36 @@ +//===- MCInstrAnalysis.cpp - InstrDesc target hooks -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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; +} diff --git a/contrib/llvm/lib/MC/MCInstrDesc.cpp b/contrib/llvm/lib/MC/MCInstrDesc.cpp new file mode 100644 index 000000000000..53cba864a85d --- /dev/null +++ b/contrib/llvm/lib/MC/MCInstrDesc.cpp @@ -0,0 +1,66 @@ +//===------ llvm/MC/MCInstrDesc.cpp- Instruction Descriptors --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/contrib/llvm/lib/MC/MCLabel.cpp b/contrib/llvm/lib/MC/MCLabel.cpp new file mode 100644 index 000000000000..c376c83274ef --- /dev/null +++ b/contrib/llvm/lib/MC/MCLabel.cpp @@ -0,0 +1,26 @@ +//===- lib/MC/MCLabel.cpp - MCLabel implementation ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp b/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp new file mode 100644 index 000000000000..2f8581470ea6 --- /dev/null +++ b/contrib/llvm/lib/MC/MCLinkerOptimizationHint.cpp @@ -0,0 +1,60 @@ +//===- llvm/MC/MCLinkerOptimizationHint.cpp ----- LOH handling ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp new file mode 100644 index 000000000000..b30317e74672 --- /dev/null +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -0,0 +1,516 @@ +//===- MCMachOStreamer.cpp - MachO Streamer -------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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: + 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; + } + + 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/contrib/llvm/lib/MC/MCMachObjectTargetWriter.cpp b/contrib/llvm/lib/MC/MCMachObjectTargetWriter.cpp new file mode 100644 index 000000000000..8809a3c320f8 --- /dev/null +++ b/contrib/llvm/lib/MC/MCMachObjectTargetWriter.cpp @@ -0,0 +1,19 @@ +//===- MCMachObjectTargetWriter.cpp - Mach-O Target Writer Subclass -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCNullStreamer.cpp b/contrib/llvm/lib/MC/MCNullStreamer.cpp new file mode 100644 index 000000000000..4e97e7550bcb --- /dev/null +++ b/contrib/llvm/lib/MC/MCNullStreamer.cpp @@ -0,0 +1,50 @@ +//===- lib/MC/MCNullStreamer.cpp - Dummy Streamer Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCObjectFileInfo.cpp b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp new file mode 100644 index 000000000000..9e35355d06e0 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp @@ -0,0 +1,847 @@ +//===-- MCObjectFileInfo.cpp - Object File Information --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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" + +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) + 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) + 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) + 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()); + + 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); +} + +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::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::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::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/contrib/llvm/lib/MC/MCObjectStreamer.cpp b/contrib/llvm/lib/MC/MCObjectStreamer.cpp new file mode 100644 index 000000000000..6ec705bdddb7 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectStreamer.cpp @@ -0,0 +1,732 @@ +//===- lib/MC/MCObjectStreamer.cpp - Object File MCStreamer Interface -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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(llvm::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, bool) { + 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(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/contrib/llvm/lib/MC/MCObjectWriter.cpp b/contrib/llvm/lib/MC/MCObjectWriter.cpp new file mode 100644 index 000000000000..98ac48a23f91 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectWriter.cpp @@ -0,0 +1,53 @@ +//===- lib/MC/MCObjectWriter.cpp - MCObjectWriter implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp b/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp new file mode 100644 index 000000000000..2b0d20f9b8e2 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp @@ -0,0 +1,753 @@ +//===- AsmLexer.cpp - Lexer for Assembly Files ----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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++; +} + +/// LexFloatLiteral: [0-9]*[.][0-9]*([eE][+-]?[0-9]*)? +/// +/// 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; + + // Check for exponent; we intentionally accept a slighlty wider set of + // literals here and rely on the upstream client to reject invalid ones (e.g., + // "1e+"). + 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 (*CurPtr == 'e' || *CurPtr == 'E' || + !IsIdentifierChar(*CurPtr, AllowAtInIdentifier)) + 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; + 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 preceeding 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/contrib/llvm/lib/MC/MCParser/AsmParser.cpp b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp new file mode 100644 index 000000000000..a0506715be37 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp @@ -0,0 +1,5936 @@ +//===- AsmParser.cpp - Parser for Assembly Files --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/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 = 0; + SMLoc Loc; + unsigned Buf = 0; + }; + CppHashInfoTy CppHashInfo; + + /// 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_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; + + // ".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(); +}; + +} // 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; + } + + PlatformParser->Initialize(*this); + initializeDirectiveKindMap(); + + 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) + getContext().setGenDwarfFileNumber(getStreamer().EmitDwarfFileDirective( + 0, StringRef(), getContext().getMainFileName())); + 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().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_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. + CppHashInfo.Loc = L; + CppHashInfo.Filename = Filename; + CppHashInfo.LineNumber = LineNumber; + CppHashInfo.Buf = CurBuffer; + 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'. Notably, it doesn't support hex escapes. + ++i; + if (i == e) + return TokError("unexpected backslash at end of string"); + + // 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. + // Also reset any implicit ".file 0" for the assembler source. + if (Ctx.getGenDwarfForAssembly()) { + Ctx.getMCDwarfLineTable(0).resetRootFile(); + Ctx.setGenDwarfForAssembly(false); + } + + MD5::MD5Result *CKMem = nullptr; + if (HasMD5) { + CKMem = (MD5::MD5Result *)Ctx.allocate(sizeof(MD5::MD5Result), 1); + for (unsigned i = 0; i != 8; ++i) { + CKMem->Bytes[i] = uint8_t(MD5Hi >> ((7 - i) * 8)); + CKMem->Bytes[i + 8] = uint8_t(MD5Lo >> ((7 - i) * 8)); + } + } + 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())); + FileNumber = FileNumOrErr.get(); + } + // 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; +} + +/// 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}); + } + + std::string FixedSizePortion; + if (parseToken(AsmToken::Comma, "unexpected token in directive") || + parseEscapedString(FixedSizePortion)) + return true; + + getStreamer().EmitCVDefRangeDirective(Ranges, FixedSizePortion); + return false; +} + +/// 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()); + else + TheCondState.CondMet = (!Sym || Sym->isUndefined()); + 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[".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/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp new file mode 100644 index 000000000000..388304a72395 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -0,0 +1,866 @@ +//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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"); + + // 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::ParseSEHDirectivePushReg>( + ".seh_pushreg"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSetFrame>( + ".seh_setframe"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveAllocStack>( + ".seh_stackalloc"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveReg>( + ".seh_savereg"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveSaveXMM>( + ".seh_savexmm"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectivePushFrame>( + ".seh_pushframe"); + addDirectiveHandler<&COFFAsmParser::ParseSEHDirectiveEndProlog>( + ".seh_endprologue"); + addDirectiveHandler<&COFFAsmParser::ParseDirectiveSymbolAttribute>(".weak"); + } + + 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 ParseSEHDirectivePushReg(StringRef, SMLoc); + bool ParseSEHDirectiveSetFrame(StringRef, SMLoc); + bool ParseSEHDirectiveAllocStack(StringRef, SMLoc); + bool ParseSEHDirectiveSaveReg(StringRef, SMLoc); + bool ParseSEHDirectiveSaveXMM(StringRef, SMLoc); + bool ParseSEHDirectivePushFrame(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::ParseSEHDirectivePushReg(StringRef, SMLoc Loc) { + unsigned Reg = 0; + if (ParseSEHRegisterNumber(Reg)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWinCFIPushReg(Reg, Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc Loc) { + unsigned Reg = 0; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify a stack pointer offset"); + + Lex(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWinCFISetFrame(Reg, Off, Loc); + 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::ParseSEHDirectiveSaveReg(StringRef, SMLoc Loc) { + unsigned Reg = 0; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify an offset on the stack"); + + Lex(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + // FIXME: Err on %xmm* registers + getStreamer().EmitWinCFISaveReg(Reg, Off, Loc); + return false; +} + +// FIXME: This method is inherently x86-specific. It should really be in the +// x86 backend. +bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc Loc) { + unsigned Reg = 0; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify an offset on the stack"); + + Lex(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + // FIXME: Err on non-%xmm* registers + getStreamer().EmitWinCFISaveXMM(Reg, Off, Loc); + return false; +} + +bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc Loc) { + bool Code = false; + StringRef CodeID; + if (getLexer().is(AsmToken::At)) { + SMLoc startLoc = getLexer().getLoc(); + Lex(); + if (!getParser().parseIdentifier(CodeID)) { + if (CodeID != "code") + return Error(startLoc, "expected @code"); + Code = true; + } + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWinCFIPushFrame(Code, 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; +} + +bool COFFAsmParser::ParseSEHRegisterNumber(unsigned &RegNo) { + SMLoc startLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Percent)) { + const MCRegisterInfo *MRI = getContext().getRegisterInfo(); + SMLoc endLoc; + unsigned LLVMRegNo; + if (getParser().getTargetParser().ParseRegister(LLVMRegNo,startLoc,endLoc)) + return true; + +#if 0 + // FIXME: TargetAsmInfo::getCalleeSavedRegs() commits a serious layering + // violation so this validation code is disabled. + + // Check that this is a non-volatile register. + const unsigned *NVRegs = TAI.getCalleeSavedRegs(); + unsigned i; + for (i = 0; NVRegs[i] != 0; ++i) + if (NVRegs[i] == LLVMRegNo) + break; + if (NVRegs[i] == 0) + return Error(startLoc, "expected non-volatile register"); +#endif + + int SEHRegNo = MRI->getSEHRegNum(LLVMRegNo); + if (SEHRegNo < 0) + return Error(startLoc,"register can't be represented in SEH unwind info"); + RegNo = SEHRegNo; + } + else { + int64_t n; + if (getParser().parseAbsoluteExpression(n)) + return true; + if (n > 15) + return Error(startLoc, "register number is too high"); + RegNo = n; + } + + return false; +} + +namespace llvm { + +MCAsmParserExtension *createCOFFAsmParser() { + return new COFFAsmParser; +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp new file mode 100644 index 000000000000..cd99112292a9 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp @@ -0,0 +1,1207 @@ +//===- DarwinAsmParser.cpp - Darwin (Mach-O) Assembly Parser --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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 = llvm::make_unique<raw_fd_ostream>( + StringRef(SecureLogFile), EC, sys::fs::F_Append | sys::fs::F_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_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) + .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/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp new file mode 100644 index 000000000000..d568f7a71eeb --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -0,0 +1,896 @@ +//===- ELFAsmParser.cpp - ELF Assembly Parser -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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.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/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp new file mode 100644 index 000000000000..10960fc69633 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp @@ -0,0 +1,130 @@ +//===- MCAsmLexer.cpp - Abstract Asm Lexer Interface ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp new file mode 100644 index 000000000000..efedcdc5a314 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -0,0 +1,137 @@ +//===-- MCAsmParser.cpp - Abstract Asm Parser Interface -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp new file mode 100644 index 000000000000..031f473dc5fe --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp @@ -0,0 +1,20 @@ +//===- MCAsmParserExtension.cpp - Asm Parser Hooks ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp new file mode 100644 index 000000000000..a0c06c9d5018 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp @@ -0,0 +1,30 @@ +//===-- MCTargetAsmParser.cpp - Target Assembly Parser --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCParser/WasmAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/WasmAsmParser.cpp new file mode 100644 index 000000000000..93bb0cb3c72e --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/WasmAsmParser.cpp @@ -0,0 +1,145 @@ +//===- WasmAsmParser.cpp - Wasm Assembly Parser -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// -- +// +// 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/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; + MCAsmLexer *Lexer; + + 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() : Parser(nullptr), Lexer(nullptr) { + 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"); + } + + 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 parseSectionDirective(StringRef, SMLoc) { + // FIXME: .section currently no-op. + while (Lexer->isNot(AsmToken::EndOfStatement)) Parser->Lex(); + 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 (Lexer->isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + const MCExpr *Expr; + if (Parser->parseExpression(Expr)) + return true; + if (Lexer->isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + Lex(); + // MCWasmStreamer implements this. + 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 + return Error("Unknown WASM symbol type: ", Lexer->getTok()); + Lex(); + return Expect(AsmToken::EndOfStatement, "EOL"); + } +}; + +} // end anonymous namespace + +namespace llvm { + +MCAsmParserExtension *createWasmAsmParser() { + return new WasmAsmParser; +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/MC/MCRegisterInfo.cpp b/contrib/llvm/lib/MC/MCRegisterInfo.cpp new file mode 100644 index 000000000000..5abae5379867 --- /dev/null +++ b/contrib/llvm/lib/MC/MCRegisterInfo.cpp @@ -0,0 +1,135 @@ +//===- MC/MCRegisterInfo.cpp - Target Register Description ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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; + +unsigned MCRegisterInfo::getMatchingSuperReg(unsigned 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; +} + +unsigned MCRegisterInfo::getSubReg(unsigned 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(unsigned Reg, unsigned 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(unsigned 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; +} + +int MCRegisterInfo::getLLVMRegNum(unsigned RegNum, bool isEH) const { + const DwarfLLVMRegPair *M = isEH ? EHDwarf2LRegs : Dwarf2LRegs; + unsigned Size = isEH ? EHDwarf2LRegsSize : Dwarf2LRegsSize; + + if (!M) + return -1; + DwarfLLVMRegPair Key = { RegNum, 0 }; + const DwarfLLVMRegPair *I = std::lower_bound(M, M+Size, Key); + assert(I != M+Size && I->FromReg == RegNum && "Invalid RegNum"); + return I->ToReg; +} + +int MCRegisterInfo::getLLVMRegNumFromEH(unsigned RegNum) const { + const DwarfLLVMRegPair *M = EHDwarf2LRegs; + unsigned Size = EHDwarf2LRegsSize; + + 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; +} + +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. + int LRegNum = getLLVMRegNumFromEH(RegNum); + if (LRegNum != -1) + return getDwarfRegNum(LRegNum, false); + return RegNum; +} + +int MCRegisterInfo::getSEHRegNum(unsigned RegNum) const { + const DenseMap<unsigned, int>::const_iterator I = L2SEHRegs.find(RegNum); + if (I == L2SEHRegs.end()) return (int)RegNum; + return I->second; +} + +int MCRegisterInfo::getCodeViewRegNum(unsigned RegNum) const { + if (L2CVRegs.empty()) + report_fatal_error("target does not implement codeview register mapping"); + const DenseMap<unsigned, 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/contrib/llvm/lib/MC/MCSchedule.cpp b/contrib/llvm/lib/MC/MCSchedule.cpp new file mode 100644 index 000000000000..929bd7f6046c --- /dev/null +++ b/contrib/llvm/lib/MC/MCSchedule.cpp @@ -0,0 +1,152 @@ +//===- MCSchedule.cpp - Scheduling ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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; +} diff --git a/contrib/llvm/lib/MC/MCSection.cpp b/contrib/llvm/lib/MC/MCSection.cpp new file mode 100644 index 000000000000..d4f11d10136a --- /dev/null +++ b/contrib/llvm/lib/MC/MCSection.cpp @@ -0,0 +1,103 @@ +//===- lib/MC/MCSection.cpp - Machine Code Section Representation ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCSectionCOFF.cpp b/contrib/llvm/lib/MC/MCSectionCOFF.cpp new file mode 100644 index 000000000000..c861963eec8a --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionCOFF.cpp @@ -0,0 +1,116 @@ +//===- lib/MC/MCSectionCOFF.cpp - COFF Code Section Representation --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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; + +MCSectionCOFF::~MCSectionCOFF() = default; // anchor. + +// 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/contrib/llvm/lib/MC/MCSectionELF.cpp b/contrib/llvm/lib/MC/MCSectionELF.cpp new file mode 100644 index 000000000000..7ee1694ebbf7 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionELF.cpp @@ -0,0 +1,197 @@ +//===- lib/MC/MCSectionELF.cpp - ELF Code Section Representation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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; + +MCSectionELF::~MCSectionELF() = default; // anchor. + +// 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 + 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/contrib/llvm/lib/MC/MCSectionMachO.cpp b/contrib/llvm/lib/MC/MCSectionMachO.cpp new file mode 100644 index 000000000000..f40237231a2f --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionMachO.cpp @@ -0,0 +1,282 @@ +//===- lib/MC/MCSectionMachO.cpp - MachO Code Section Representation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCSectionWasm.cpp b/contrib/llvm/lib/MC/MCSectionWasm.cpp new file mode 100644 index 000000000000..626027a24f97 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionWasm.cpp @@ -0,0 +1,96 @@ +//===- lib/MC/MCSectionWasm.cpp - Wasm Code Section Representation --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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; + +MCSectionWasm::~MCSectionWasm() {} // anchor. + +// 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 << ",\""; + + // TODO: Print section flags. + + 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/contrib/llvm/lib/MC/MCStreamer.cpp b/contrib/llvm/lib/MC/MCStreamer.cpp new file mode 100644 index 000000000000..6a8471bc61b4 --- /dev/null +++ b/contrib/llvm/lib/MC/MCStreamer.cpp @@ -0,0 +1,1094 @@ +//===- lib/MC/MCStreamer.cpp - Streaming Machine Code Output --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/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/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(); +} + +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) { + SmallString<128> Tmp; + raw_svector_ostream OSE(Tmp); + encodeULEB128(Value, OSE); + 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, + MD5::MD5Result *Checksum, + Optional<StringRef> Source, + unsigned CUID) { + return getContext().getDwarfFile(Directory, Filename, FileNo, Checksum, + Source, CUID); +} + +void MCStreamer::emitDwarfFile0Directive(StringRef Directory, + StringRef Filename, + 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) {} + +void MCStreamer::EmitCVDefRangeDirective( + ArrayRef<std::pair<const MCSymbol *, const MCSymbol *>> Ranges, + StringRef FixedSizePortion) {} + +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( + llvm::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(llvm::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() {} + +void MCStreamer::EmitWinCFIPushReg(unsigned Register, SMLoc Loc) { + WinEH::FrameInfo *CurFrame = EnsureValidWinFrameInfo(Loc); + if (!CurFrame) + return; + + MCSymbol *Label = EmitCFILabel(); + + WinEH::Instruction Inst = Win64EH::Instruction::PushNonVol(Label, Register); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWinCFISetFrame(unsigned 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, 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(unsigned 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, Register, Offset); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWinCFISaveXMM(unsigned 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, 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 &STI, + bool) { + // 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::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; + 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/contrib/llvm/lib/MC/MCSubtargetInfo.cpp b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp new file mode 100644 index 000000000000..f6167826fae2 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp @@ -0,0 +1,120 @@ +//===- MCSubtargetInfo.cpp - Subtarget Information ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstring> + +using namespace llvm; + +static FeatureBitset getFeatures(StringRef CPU, StringRef FS, + ArrayRef<SubtargetFeatureKV> ProcDesc, + ArrayRef<SubtargetFeatureKV> ProcFeatures) { + SubtargetFeatures Features(FS); + return Features.getFeatureBits(CPU, ProcDesc, ProcFeatures); +} + +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<SubtargetFeatureKV> PD, + const SubtargetInfoKV *ProcSched, 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), + ProcSchedModels(ProcSched), 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::ToggleFeature(StringRef FS) { + SubtargetFeatures::ToggleFeature(FeatureBits, FS, ProcFeatures); + return FeatureBits; +} + +FeatureBitset MCSubtargetInfo::ApplyFeatureFlag(StringRef FS) { + SubtargetFeatures::ApplyFeatureFlag(FeatureBits, FS, ProcFeatures); + return FeatureBits; +} + +bool MCSubtargetInfo::checkFeatures(StringRef FS) const { + SubtargetFeatures T(FS); + FeatureBitset Set, All; + for (std::string F : T.getFeatures()) { + SubtargetFeatures::ApplyFeatureFlag(Set, F, ProcFeatures); + if (F[0] == '-') + F[0] = '+'; + SubtargetFeatures::ApplyFeatureFlag(All, F, ProcFeatures); + } + return (FeatureBits & All) == Set; +} + +const MCSchedModel &MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const { + assert(ProcSchedModels && "Processor machine model not available!"); + + ArrayRef<SubtargetInfoKV> SchedModels(ProcSchedModels, ProcDesc.size()); + + assert(std::is_sorted(SchedModels.begin(), SchedModels.end(), + [](const SubtargetInfoKV &LHS, const SubtargetInfoKV &RHS) { + return strcmp(LHS.Key, RHS.Key) < 0; + }) && + "Processor machine model table is not sorted"); + + // Find entry + auto Found = + std::lower_bound(SchedModels.begin(), SchedModels.end(), CPU); + if (Found == SchedModels.end() || StringRef(Found->Key) != CPU) { + 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(Found->Value && "Missing processor SchedModel value"); + return *(const MCSchedModel *)Found->Value; +} + +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); +} diff --git a/contrib/llvm/lib/MC/MCSymbol.cpp b/contrib/llvm/lib/MC/MCSymbol.cpp new file mode 100644 index 000000000000..5502c658f565 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSymbol.cpp @@ -0,0 +1,89 @@ +//===- lib/MC/MCSymbol.cpp - MCSymbol implementation ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCSymbolELF.cpp b/contrib/llvm/lib/MC/MCSymbolELF.cpp new file mode 100644 index 000000000000..12c724f6b1ee --- /dev/null +++ b/contrib/llvm/lib/MC/MCSymbolELF.cpp @@ -0,0 +1,204 @@ +//===- lib/MC/MCSymbolELF.cpp ---------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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 = (getFlags() & (0x3 << ELF_STB_Shift)) >> ELF_STB_Shift; + 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 = (getFlags() & (0x7 << ELF_STT_Shift)) >> ELF_STT_Shift; + 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 = (getFlags() & (0x3 << ELF_STV_Shift)) >> ELF_STV_Shift; + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + 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 = (getFlags() & (0x7 << ELF_STO_Shift)) >> ELF_STO_Shift; + 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/contrib/llvm/lib/MC/MCTargetOptions.cpp b/contrib/llvm/lib/MC/MCTargetOptions.cpp new file mode 100644 index 000000000000..b85e53db5d61 --- /dev/null +++ b/contrib/llvm/lib/MC/MCTargetOptions.cpp @@ -0,0 +1,25 @@ +//===- lib/MC/MCTargetOptions.cpp - MC Target Options ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCTargetOptions.h" +#include "llvm/ADT/StringRef.h" + +using namespace llvm; + +MCTargetOptions::MCTargetOptions() + : SanitizeAddress(false), 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/contrib/llvm/lib/MC/MCValue.cpp b/contrib/llvm/lib/MC/MCValue.cpp new file mode 100644 index 000000000000..7e03913aa680 --- /dev/null +++ b/contrib/llvm/lib/MC/MCValue.cpp @@ -0,0 +1,62 @@ +//===- lib/MC/MCValue.cpp - MCValue implementation ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp b/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp new file mode 100644 index 000000000000..59082a160caf --- /dev/null +++ b/contrib/llvm/lib/MC/MCWasmObjectTargetWriter.cpp @@ -0,0 +1,18 @@ +//===-- MCWasmObjectTargetWriter.cpp - Wasm Target Writer Subclass --------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCWasmObjectWriter.h" + +using namespace llvm; + +MCWasmObjectTargetWriter::MCWasmObjectTargetWriter(bool Is64Bit_) + : Is64Bit(Is64Bit_) {} + +// Pin the vtable to this object file +MCWasmObjectTargetWriter::~MCWasmObjectTargetWriter() = default; diff --git a/contrib/llvm/lib/MC/MCWasmStreamer.cpp b/contrib/llvm/lib/MC/MCWasmStreamer.cpp new file mode 100644 index 000000000000..d2a152058b90 --- /dev/null +++ b/contrib/llvm/lib/MC/MCWasmStreamer.cpp @@ -0,0 +1,225 @@ +//===- lib/MC/MCWasmStreamer.cpp - Wasm Object Output ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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() {} + +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: + 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/contrib/llvm/lib/MC/MCWin64EH.cpp b/contrib/llvm/lib/MC/MCWin64EH.cpp new file mode 100644 index 000000000000..8bc1f08c8875 --- /dev/null +++ b/contrib/llvm/lib/MC/MCWin64EH.cpp @@ -0,0 +1,644 @@ +//===- lib/MC/MCWin64EH.cpp - MCWin64EH implementation --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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); + int64_t value; + Diff->evaluateAsAbsolute(value, OS->getAssembler()); + 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; + + uint32_t FuncLength = 0x0; + if (info->FuncletOrFuncEnd) + FuncLength = (uint32_t)GetAbsDifference(streamer, info->FuncletOrFuncEnd, + info->Begin); + FuncLength /= 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[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/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp new file mode 100644 index 000000000000..7b1dc7abf708 --- /dev/null +++ b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -0,0 +1,326 @@ +//===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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) { + llvm_unreachable("not implemented"); +} + +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(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(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.isKnownWindowsMSVCEnvironment()) { + 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.isKnownWindowsMSVCEnvironment() && 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/contrib/llvm/lib/MC/MCWinEH.cpp b/contrib/llvm/lib/MC/MCWinEH.cpp new file mode 100644 index 000000000000..a5d0f5a2cb75 --- /dev/null +++ b/contrib/llvm/lib/MC/MCWinEH.cpp @@ -0,0 +1,26 @@ +//===- lib/MC/MCWinEH.cpp - Windows EH implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/contrib/llvm/lib/MC/MachObjectWriter.cpp b/contrib/llvm/lib/MC/MachObjectWriter.cpp new file mode 100644 index 000000000000..2fa65658ccfa --- /dev/null +++ b/contrib/llvm/lib/MC/MachObjectWriter.cpp @@ -0,0 +1,1034 @@ +//===- lib/MC/MachObjectWriter.cpp - Mach-O File Writer -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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/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/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, 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() ? 8 : 4)); + + assert(W.OS.tell() - Start == Size); +} + +void MachObjectWriter::recordRelocation(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + 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, 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() ? 8 : 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 llvm::make_unique<MachObjectWriter>(std::move(MOTW), OS, + IsLittleEndian); +} diff --git a/contrib/llvm/lib/MC/StringTableBuilder.cpp b/contrib/llvm/lib/MC/StringTableBuilder.cpp new file mode 100644 index 000000000000..de40a7728d3f --- /dev/null +++ b/contrib/llvm/lib/MC/StringTableBuilder.cpp @@ -0,0 +1,189 @@ +//===- StringTableBuilder.cpp - String table building utility -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#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 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()); + } + if (K != WinCOFF) + return; + support::endian::write32le(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. +} + +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/contrib/llvm/lib/MC/SubtargetFeature.cpp b/contrib/llvm/lib/MC/SubtargetFeature.cpp new file mode 100644 index 000000000000..b69af24b531e --- /dev/null +++ b/contrib/llvm/lib/MC/SubtargetFeature.cpp @@ -0,0 +1,280 @@ +//===- SubtargetFeature.cpp - CPU characteristics Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +/// \file Implements the SubtargetFeature interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/ADT/ArrayRef.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/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <cstring> +#include <iterator> +#include <string> +#include <vector> + +using namespace llvm; + +/// Determine if a feature has a flag; '+' or '-' +static inline bool hasFlag(StringRef Feature) { + assert(!Feature.empty() && "Empty string"); + // Get first character + char Ch = Feature[0]; + // Check if first character is '+' or '-' flag + return Ch == '+' || Ch =='-'; +} + +/// Return string stripped of flag. +static inline std::string StripFlag(StringRef Feature) { + return hasFlag(Feature) ? Feature.substr(1) : Feature; +} + +/// Return true if enable flag; '+'. +static inline bool isEnabled(StringRef Feature) { + assert(!Feature.empty() && "Empty string"); + // Get first character + char Ch = Feature[0]; + // Check if first character is '+' for enabled + return Ch == '+'; +} + +/// Splits a string of comma separated items in to a vector of strings. +static void 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()); +} + +/// Find KV in array using binary search. +static const SubtargetFeatureKV *Find(StringRef S, + ArrayRef<SubtargetFeatureKV> A) { + // Binary search the array + auto F = std::lower_bound(A.begin(), A.end(), S); + // If not found then return NULL + if (F == A.end() || StringRef(F->Key) != S) return nullptr; + // Return the found array item + return F; +} + +/// Return the length of the longest entry in the table. +static size_t getLongestEntryLength(ArrayRef<SubtargetFeatureKV> Table) { + size_t MaxLen = 0; + for (auto &I : Table) + MaxLen = std::max(MaxLen, std::strlen(I.Key)); + return MaxLen; +} + +/// Display help for feature choices. +static void Help(ArrayRef<SubtargetFeatureKV> CPUTable, + ArrayRef<SubtargetFeatureKV> FeatTable) { + // 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 - %s.\n", MaxCPULen, CPU.Key, CPU.Desc); + 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"; +} + +SubtargetFeatures::SubtargetFeatures(StringRef Initial) { + // Break up string into separate features + Split(Features, Initial); +} + +std::string SubtargetFeatures::getString() const { + return join(Features.begin(), Features.end(), ","); +} + +/// For each feature that is (transitively) implied by this feature, set it. +static +void SetImpliedBits(FeatureBitset &Bits, const SubtargetFeatureKV &FeatureEntry, + ArrayRef<SubtargetFeatureKV> FeatureTable) { + for (const SubtargetFeatureKV &FE : FeatureTable) { + if (FeatureEntry.Value == FE.Value) continue; + + if ((FeatureEntry.Implies & FE.Value).any()) { + Bits |= FE.Value; + SetImpliedBits(Bits, FE, FeatureTable); + } + } +} + +/// For each feature that (transitively) implies this feature, clear it. +static +void ClearImpliedBits(FeatureBitset &Bits, + const SubtargetFeatureKV &FeatureEntry, + ArrayRef<SubtargetFeatureKV> FeatureTable) { + for (const SubtargetFeatureKV &FE : FeatureTable) { + if (FeatureEntry.Value == FE.Value) continue; + + if ((FE.Implies & FeatureEntry.Value).any()) { + Bits &= ~FE.Value; + ClearImpliedBits(Bits, FE, FeatureTable); + } + } +} + +void +SubtargetFeatures::ToggleFeature(FeatureBitset &Bits, StringRef Feature, + ArrayRef<SubtargetFeatureKV> FeatureTable) { + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable); + // If there is a match + if (FeatureEntry) { + if ((Bits & FeatureEntry->Value) == FeatureEntry->Value) { + Bits &= ~FeatureEntry->Value; + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, *FeatureEntry, FeatureTable); + } else { + Bits |= FeatureEntry->Value; + + // For each feature that this implies, set it. + SetImpliedBits(Bits, *FeatureEntry, FeatureTable); + } + } else { + errs() << "'" << Feature << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } +} + +void SubtargetFeatures::ApplyFeatureFlag(FeatureBitset &Bits, StringRef Feature, + ArrayRef<SubtargetFeatureKV> FeatureTable) { + assert(hasFlag(Feature)); + + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable); + // If there is a match + if (FeatureEntry) { + // Enable/disable feature in bits + if (isEnabled(Feature)) { + Bits |= FeatureEntry->Value; + + // For each feature that this implies, set it. + SetImpliedBits(Bits, *FeatureEntry, FeatureTable); + } else { + Bits &= ~FeatureEntry->Value; + + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, *FeatureEntry, FeatureTable); + } + } else { + errs() << "'" << Feature << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } +} + +FeatureBitset +SubtargetFeatures::getFeatureBits(StringRef CPU, + ArrayRef<SubtargetFeatureKV> CPUTable, + ArrayRef<SubtargetFeatureKV> FeatureTable) { + if (CPUTable.empty() || FeatureTable.empty()) + return FeatureBitset(); + + assert(std::is_sorted(std::begin(CPUTable), std::end(CPUTable)) && + "CPU table is not sorted"); + assert(std::is_sorted(std::begin(FeatureTable), std::end(FeatureTable)) && + "CPU features table is not sorted"); + // Resulting bits + FeatureBitset Bits; + + // Check if help is needed + if (CPU == "help") + Help(CPUTable, FeatureTable); + + // Find CPU entry if CPU name is specified. + else if (!CPU.empty()) { + const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable); + + // If there is a match + if (CPUEntry) { + // Set base feature bits + Bits = CPUEntry->Value; + + // Set the feature implied by this CPU feature, if any. + for (auto &FE : FeatureTable) { + if ((CPUEntry->Value & FE.Value).any()) + SetImpliedBits(Bits, FE, FeatureTable); + } + } else { + errs() << "'" << CPU << "' is not a recognized processor for this target" + << " (ignoring processor)\n"; + } + } + + // Iterate through each feature + for (const std::string &Feature : Features) { + // Check for help + if (Feature == "+help") + Help(CPUTable, FeatureTable); + + ApplyFeatureFlag(Bits, Feature, FeatureTable); + } + + return Bits; +} + +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/contrib/llvm/lib/MC/WasmObjectWriter.cpp b/contrib/llvm/lib/MC/WasmObjectWriter.cpp new file mode 100644 index 000000000000..333748db9190 --- /dev/null +++ b/contrib/llvm/lib/MC/WasmObjectWriter.cpp @@ -0,0 +1,1590 @@ +//===- lib/MC/WasmObjectWriter.cpp - Wasm File Writer ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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 kInitialTableOffset = 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; + + // The return types of the function. + SmallVector<wasm::ValType, 1> Returns; + + // The parameter types of the function. + SmallVector<wasm::ValType, 4> Params; + + WasmSignature() : State(Plain) {} + + 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 Offset; + uint32_t Alignment; + uint32_t Flags; + 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 { + switch (Type) { + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + return true; + default: + return false; + } + } + + 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 INVALID_INDEX = -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(INVALID_INDEX) {} +}; + +#if !defined(NDEBUG) +raw_ostream &operator<<(raw_ostream &OS, const WasmRelocationEntry &Rel) { + Rel.print(OS); + return OS; +} +#endif + +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; + // 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; + // 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<WasmGlobal, 4> Globals; + 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(); } + unsigned getRelocType(const MCValue &Target, const MCFixup &Fixup) const { + return TargetObjectWriter->getRelocType(Target, Fixup); + } + + 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)) {} + + ~WasmObjectWriter() override; + +private: + void reset() override { + CodeRelocations.clear(); + DataRelocations.clear(); + TypeIndices.clear(); + WasmIndices.clear(); + TableIndices.clear(); + DataLocations.clear(); + CustomSectionsRelocations.clear(); + SignatureIndices.clear(); + Signatures.clear(); + Globals.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 writeGlobalSection(); + void writeExportSection(ArrayRef<wasm::WasmExport> Exports); + void writeElemSection(ArrayRef<uint32_t> TableElems); + 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 writeCustomSections(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 + +WasmObjectWriter::~WasmObjectWriter() {} + +// 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(UINT32_MAX, W.OS); + + // 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() - 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. + uint8_t Buffer[16]; + unsigned SizeLen = encodeULEB128(Size, Buffer, 5); + assert(SizeLen == 5); + static_cast<raw_pwrite_stream &>(W.OS).pwrite((char *)Buffer, SizeLen, + 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) { + MCAsmBackend &Backend = Asm.getBackend(); + bool IsPCRel = Backend.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()) { + assert(RefB->getKind() == MCSymbolRefExpr::VK_None && + "Should not have constructed this"); + + // Let A, B and C being the components of Target and R be the location of + // the fixup. If the fixup is not pcrel, we want to compute (A - B + C). + // If it is pcrel, we want to compute (A - B + C - R). + + // In general, Wasm has no relocations for -B. It can only represent (A + C) + // or (A + C - R). If B = R + K and the relocation is not pcrel, we can + // replace B to implement it: (A - R - K + C) + if (IsPCRel) { + Ctx.reportError( + Fixup.getLoc(), + "No relocation available to represent this relative expression"); + return; + } + + const auto &SymB = cast<MCSymbolWasm>(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; + } + + uint64_t SymBOffset = Layout.getSymbolOffset(SymB); + uint64_t K = SymBOffset - FixupOffset; + IsPCRel = true; + C -= K; + } + + // We either rejected the fixup or folded B into C at this point. + const MCSymbolRefExpr *RefA = Target.getSymA(); + const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr; + + if (SymA && 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 = getRelocType(Target, Fixup); + assert(!IsPCRel); + assert(SymA); + + // 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_WEBASSEMBLY_FUNCTION_OFFSET_I32 || + Type == wasm::R_WEBASSEMBLY_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_WEBASSEMBLY_TYPE_INDEX_LEB are required to be + // against a named symbol. + if (Type != wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) { + if (SymA->getName().empty()) + report_fatal_error("relocations against un-named temporaries are not yet " + "supported by wasm"); + + SymA->setUsedInReloc(); + } + + 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"); + } +} + +// 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); +} + +static const MCSymbolWasm *ResolveSymbol(const MCSymbolWasm &Symbol) { + if (Symbol.isVariable()) { + const MCExpr *Expr = Symbol.getVariableValue(); + auto *Inner = cast<MCSymbolRefExpr>(Expr); + return cast<MCSymbolWasm>(&Inner->getSymbol()); + } + return &Symbol; +} + +// 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) { + switch (RelEntry.Type) { + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_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_WEBASSEMBLY_TYPE_INDEX_LEB: + // Provisional value is same as the index + return getRelocationIndexValue(RelEntry); + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + // Provisional value is function/global/event Wasm index + if (!WasmIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found in wasm index space: " + + RelEntry.Symbol->getName()); + return WasmIndices[RelEntry.Symbol]; + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: { + const auto &Section = + static_cast<const MCSectionWasm &>(RelEntry.Symbol->getSection()); + return Section.getSectionOffset() + RelEntry.Addend; + } + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_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_WEBASSEMBLY_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_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + WritePatchableLEB(Stream, Value, Offset); + break; + case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + WriteI32(Stream, Value, Offset); + break; + case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_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::writeGlobalSection() { + if (Globals.empty()) + return; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_GLOBAL); + + encodeULEB128(Globals.size(), W.OS); + for (const WasmGlobal &Global : Globals) { + writeValueType(static_cast<wasm::ValType>(Global.Type.Type)); + W.OS << char(Global.Type.Mutable); + + W.OS << char(wasm::WASM_OPCODE_I32_CONST); + encodeSLEB128(Global.InitialValue, W.OS); + W.OS << char(wasm::WASM_OPCODE_END); + } + + 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(kInitialTableOffset, 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::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(0, W.OS); // memory index + 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. + std::stable_sort( + Relocs.begin(), Relocs.end(), + [](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.Flags, 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::writeCustomSections(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + for (auto &CustomSection : CustomSections) { + 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"); + MCContext &Ctx = Asm.getContext(); + + // 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. + MCSymbolWasm *MemorySym = + cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__linear_memory")); + wasm::WasmImport MemImport; + MemImport.Module = MemorySym->getImportModule(); + MemImport.Field = MemorySym->getImportName(); + 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. + MCSymbolWasm *TableSym = + cast<MCSymbolWasm>(Ctx.getOrCreateSymbol("__indirect_function_table")); + wasm::WasmImport TableImport; + TableImport.Module = TableSym->getImportModule(); + TableImport.Field = TableSym->getImportName(); + 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); + WasmIndices[&WS] = NumFunctionImports++; + } else if (WS.isGlobal()) { + if (WS.isWeak()) + report_fatal_error("undefined global symbol cannot be weak"); + + wasm::WasmImport Import; + Import.Module = WS.getImportModule(); + Import.Field = WS.getImportName(); + Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; + Import.Global = WS.getGlobalType(); + Imports.push_back(Import); + 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); + WasmIndices[&WS] = NumEventImports++; + } + } + } + + // 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.Offset = DataSize; + Segment.Section = &Section; + addData(Segment.Data, Section); + Segment.Alignment = Log2_32(Section.getAlignment()); + Segment.Flags = 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)); + } + 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() == 0) + 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 (WS.isTemporary() && !WS.getSize()) + 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()); + assert(DataSection.isWasmData()); + + // 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; + WasmIndices[&WS] = Index; + Events.push_back(Event); + } else { + // An import; the index was assigned above. + Index = WasmIndices.find(&WS)->second; + } + 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 (WS.isFunction()) { + assert(WasmIndices.count(ResolvedSym) > 0); + uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; + WasmIndices[&WS] = WasmIndex; + LLVM_DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); + } else if (WS.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(INVALID_INDEX); + 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.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_WEBASSEMBLY_TABLE_INDEX_I32 && + Rel.Type != wasm::R_WEBASSEMBLY_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() + kInitialTableOffset; + 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 *Sym = dyn_cast<MCSymbolRefExpr>(Expr); + if (!Sym) + report_fatal_error("fixups in .init_array should be symbol references"); + if (Sym->getKind() != MCSymbolRefExpr::VK_WebAssembly_FUNCTION) + report_fatal_error("symbols in .init_array should be for functions"); + if (Sym->getSymbol().getIndex() == INVALID_INDEX) + report_fatal_error("symbols in .init_array should exist in symbtab"); + InitFuncs.push_back( + std::make_pair(Priority, Sym->getSymbol().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. + writeGlobalSection(); + writeEventSection(Events); + writeExportSection(Exports); + writeElemSection(TableElems); + writeCodeSection(Asm, Layout, Functions); + writeDataSection(); + writeCustomSections(Asm, Layout); + writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); + writeRelocSection(CodeSectionIndex, "CODE", CodeRelocations); + writeRelocSection(DataSectionIndex, "DATA", DataRelocations); + writeCustomRelocSections(); + + // 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 llvm::make_unique<WasmObjectWriter>(std::move(MOTW), OS); +} diff --git a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp new file mode 100644 index 000000000000..b774852eabe6 --- /dev/null +++ b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -0,0 +1,1103 @@ +//===- llvm/MC/WinCOFFObjectWriter.cpp ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// 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/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/JamCRC.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(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(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_LIBRARY; + } 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(Buf); + 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 llvm::make_unique<WinCOFFObjectWriter>(std::move(MOTW), OS); +} |