diff options
Diffstat (limited to 'contrib/llvm/lib/MC')
62 files changed, 24531 insertions, 0 deletions
diff --git a/contrib/llvm/lib/MC/ELFObjectWriter.cpp b/contrib/llvm/lib/MC/ELFObjectWriter.cpp new file mode 100644 index 000000000000..9899bb2eac22 --- /dev/null +++ b/contrib/llvm/lib/MC/ELFObjectWriter.cpp @@ -0,0 +1,1618 @@ +//===- 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/MC/MCELFObjectWriter.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELF.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include <vector> +using namespace llvm; + +#undef DEBUG_TYPE +#define DEBUG_TYPE "reloc-info" + +namespace { +class ELFObjectWriter : public MCObjectWriter { + protected: + + static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind); + static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant); + static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout); + static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, + bool Used, bool Renamed); + static bool isLocal(const MCSymbolData &Data, bool isSignature, + bool isUsedInReloc); + static bool IsELFMetaDataSection(const MCSectionData &SD); + static uint64_t DataSectionSize(const MCSectionData &SD); + static uint64_t GetSectionFileSize(const MCAsmLayout &Layout, + const MCSectionData &SD); + static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout, + const MCSectionData &SD); + + void WriteDataSectionData(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCSectionELF &Section); + + /*static bool isFixupKindX86RIPRel(unsigned Kind) { + return Kind == X86::reloc_riprel_4byte || + Kind == X86::reloc_riprel_4byte_movq_load; + }*/ + + /// ELFSymbolData - Helper struct for containing some precomputed + /// information on symbols. + struct ELFSymbolData { + MCSymbolData *SymbolData; + uint64_t StringIndex; + uint32_t SectionIndex; + + // Support lexicographic sorting. + bool operator<(const ELFSymbolData &RHS) const { + return SymbolData->getSymbol().getName() < + RHS.SymbolData->getSymbol().getName(); + } + }; + + /// The target specific ELF writer instance. + llvm::OwningPtr<MCELFObjectTargetWriter> TargetObjectWriter; + + SmallPtrSet<const MCSymbol *, 16> UsedInReloc; + SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc; + DenseMap<const MCSymbol *, const MCSymbol *> Renames; + + llvm::DenseMap<const MCSectionData*, + std::vector<ELFRelocationEntry> > Relocations; + DenseMap<const MCSection*, uint64_t> SectionStringTableIndex; + + /// @} + /// @name Symbol Table Data + /// @{ + + SmallString<256> StringTable; + std::vector<uint64_t> FileSymbolData; + std::vector<ELFSymbolData> LocalSymbolData; + std::vector<ELFSymbolData> ExternalSymbolData; + std::vector<ELFSymbolData> UndefinedSymbolData; + + /// @} + + bool NeedsGOT; + + bool NeedsSymtabShndx; + + // 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; + + unsigned ShstrtabIndex; + + + const MCSymbol *SymbolToReloc(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const; + + // TargetObjectWriter wrappers. + const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + return TargetObjectWriter->ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); + } + const MCSymbol *undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + return TargetObjectWriter->undefinedExplicitRelSym(Target, Fixup, + IsPCRel); + } + + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool hasRelocationAddend() const { + return TargetObjectWriter->hasRelocationAddend(); + } + unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) const { + return TargetObjectWriter->GetRelocType(Target, Fixup, IsPCRel, + IsRelocWithSymbol, Addend); + } + + public: + ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, bool IsLittleEndian) + : MCObjectWriter(_OS, IsLittleEndian), + TargetObjectWriter(MOTW), + NeedsGOT(false), NeedsSymtabShndx(false) { + } + + virtual ~ELFObjectWriter(); + + void WriteWord(uint64_t W) { + if (is64Bit()) + Write64(W); + else + Write32(W); + } + + void StringLE16(char *buf, uint16_t Value) { + buf[0] = char(Value >> 0); + buf[1] = char(Value >> 8); + } + + void StringLE32(char *buf, uint32_t Value) { + StringLE16(buf, uint16_t(Value >> 0)); + StringLE16(buf + 2, uint16_t(Value >> 16)); + } + + void StringLE64(char *buf, uint64_t Value) { + StringLE32(buf, uint32_t(Value >> 0)); + StringLE32(buf + 4, uint32_t(Value >> 32)); + } + + void StringBE16(char *buf ,uint16_t Value) { + buf[0] = char(Value >> 8); + buf[1] = char(Value >> 0); + } + + void StringBE32(char *buf, uint32_t Value) { + StringBE16(buf, uint16_t(Value >> 16)); + StringBE16(buf + 2, uint16_t(Value >> 0)); + } + + void StringBE64(char *buf, uint64_t Value) { + StringBE32(buf, uint32_t(Value >> 32)); + StringBE32(buf + 4, uint32_t(Value >> 0)); + } + + void String8(MCDataFragment &F, uint8_t Value) { + char buf[1]; + buf[0] = Value; + F.getContents().append(&buf[0], &buf[1]); + } + + void String16(MCDataFragment &F, uint16_t Value) { + char buf[2]; + if (isLittleEndian()) + StringLE16(buf, Value); + else + StringBE16(buf, Value); + F.getContents().append(&buf[0], &buf[2]); + } + + void String32(MCDataFragment &F, uint32_t Value) { + char buf[4]; + if (isLittleEndian()) + StringLE32(buf, Value); + else + StringBE32(buf, Value); + F.getContents().append(&buf[0], &buf[4]); + } + + void String64(MCDataFragment &F, uint64_t Value) { + char buf[8]; + if (isLittleEndian()) + StringLE64(buf, Value); + else + StringBE64(buf, Value); + F.getContents().append(&buf[0], &buf[8]); + } + + void WriteHeader(const MCAssembler &Asm, + uint64_t SectionDataSize, + unsigned NumberOfSections); + + void WriteSymbolEntry(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + uint64_t name, uint8_t info, + uint64_t value, uint64_t size, + uint8_t other, uint32_t shndx, + bool Reserved); + + void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + ELFSymbolData &MSD, + const MCAsmLayout &Layout); + + typedef DenseMap<const MCSectionELF*, uint32_t> SectionIndexMapTy; + void WriteSymbolTable(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + const MCAssembler &Asm, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap); + + virtual void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue); + + uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S); + + // Map from a group section to the signature symbol + typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy; + // Map from a signature symbol to the group section + typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy; + // Map from a section to the section with the relocations + typedef DenseMap<const MCSectionELF*, const MCSectionELF*> RelMapTy; + // Map from a section to its offset + typedef DenseMap<const MCSectionELF*, uint64_t> SectionOffsetMapTy; + + /// ComputeSymbolTable - 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. + /// \param NumRegularSections - Number of non-relocation sections. + void ComputeSymbolTable(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + RevGroupMapTy RevGroupMap, + unsigned NumRegularSections); + + void ComputeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap, + const RelMapTy &RelMap); + + void CreateRelocationSections(MCAssembler &Asm, MCAsmLayout &Layout, + RelMapTy &RelMap); + + void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout, + const RelMapTy &RelMap); + + void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, + SectionIndexMapTy &SectionIndexMap, + const RelMapTy &RelMap); + + // Create the sections that show up in the symbol table. Currently + // those are the .note.GNU-stack section and the group sections. + void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap, + SectionIndexMapTy &SectionIndexMap, + const RelMapTy &RelMap); + + virtual void ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout); + + void WriteSectionHeader(MCAssembler &Asm, const GroupMapTy &GroupMap, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap, + const SectionOffsetMapTy &SectionOffsetMap); + + void ComputeSectionOrder(MCAssembler &Asm, + std::vector<const MCSectionELF*> &Sections); + + 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 WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD); + + virtual bool + IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const; + + virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); + void WriteSection(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, + uint64_t Offset, uint64_t Size, uint64_t Alignment, + const MCSectionELF &Section); + }; +} + +bool ELFObjectWriter::isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { + const MCFixupKindInfo &FKI = + Asm.getBackend().getFixupKindInfo((MCFixupKind) Kind); + + return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; +} + +bool ELFObjectWriter::RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant) { + switch (Variant) { + default: + return false; + case MCSymbolRefExpr::VK_GOT: + case MCSymbolRefExpr::VK_PLT: + case MCSymbolRefExpr::VK_GOTPCREL: + case MCSymbolRefExpr::VK_GOTOFF: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_INDNTPOFF: + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_TLSLD: + return true; + } +} + +ELFObjectWriter::~ELFObjectWriter() +{} + +// Emit the ELF header. +void ELFObjectWriter::WriteHeader(const MCAssembler &Asm, + uint64_t SectionDataSize, + unsigned NumberOfSections) { + // ELF Header + // ---------- + // + // Note + // ---- + // emitWord method behaves differently for ELF32 and ELF64, writing + // 4 bytes in the former and 8 in the latter. + + Write8(0x7f); // e_ident[EI_MAG0] + Write8('E'); // e_ident[EI_MAG1] + Write8('L'); // e_ident[EI_MAG2] + Write8('F'); // e_ident[EI_MAG3] + + Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] + + // e_ident[EI_DATA] + Write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + + Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] + // e_ident[EI_OSABI] + Write8(TargetObjectWriter->getOSABI()); + Write8(0); // e_ident[EI_ABIVERSION] + + WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); + + Write16(ELF::ET_REL); // e_type + + Write16(TargetObjectWriter->getEMachine()); // e_machine = target + + Write32(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(SectionDataSize + (is64Bit() ? sizeof(ELF::Elf64_Ehdr) : + sizeof(ELF::Elf32_Ehdr))); // e_shoff = sec hdr table off in bytes + + // e_flags = whatever the target wants + Write32(Asm.getELFHeaderEFlags()); + + // e_ehsize = ELF header size + Write16(is64Bit() ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); + + Write16(0); // e_phentsize = prog header entry size + Write16(0); // e_phnum = # prog header entries = 0 + + // e_shentsize = Section header entry size + Write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); + + // e_shnum = # of section header ents + if (NumberOfSections >= ELF::SHN_LORESERVE) + Write16(ELF::SHN_UNDEF); + else + Write16(NumberOfSections); + + // e_shstrndx = Section # of '.shstrtab' + if (ShstrtabIndex >= ELF::SHN_LORESERVE) + Write16(ELF::SHN_XINDEX); + else + Write16(ShstrtabIndex); +} + +void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + uint64_t name, + uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint32_t shndx, + bool Reserved) { + if (ShndxF) { + if (shndx >= ELF::SHN_LORESERVE && !Reserved) + String32(*ShndxF, shndx); + else + String32(*ShndxF, 0); + } + + uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ? + uint16_t(ELF::SHN_XINDEX) : shndx; + + if (is64Bit()) { + String32(*SymtabF, name); // st_name + String8(*SymtabF, info); // st_info + String8(*SymtabF, other); // st_other + String16(*SymtabF, Index); // st_shndx + String64(*SymtabF, value); // st_value + String64(*SymtabF, size); // st_size + } else { + String32(*SymtabF, name); // st_name + String32(*SymtabF, value); // st_value + String32(*SymtabF, size); // st_size + String8(*SymtabF, info); // st_info + String8(*SymtabF, other); // st_other + String16(*SymtabF, Index); // st_shndx + } +} + +uint64_t ELFObjectWriter::SymbolValue(MCSymbolData &Data, + const MCAsmLayout &Layout) { + if (Data.isCommon() && Data.isExternal()) + return Data.getCommonAlignment(); + + const MCSymbol &Symbol = Data.getSymbol(); + + if (Symbol.isAbsolute() && Symbol.isVariable()) { + if (const MCExpr *Value = Symbol.getVariableValue()) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, Layout)) + return (uint64_t)IntValue; + } + } + + if (!Symbol.isInSection()) + return 0; + + + if (Data.getFragment()) { + if (Data.getFlags() & ELF_Other_ThumbFunc) + return Layout.getSymbolOffset(&Data)+1; + else + return Layout.getSymbolOffset(&Data); + } + + return 0; +} + +void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. + + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Alias = it->getSymbol(); + const MCSymbol &Symbol = Alias.AliasedSymbol(); + MCSymbolData &SD = Asm.getSymbolData(Symbol); + + // Not an alias. + if (&Symbol == &Alias) + continue; + + StringRef AliasName = Alias.getName(); + size_t Pos = AliasName.find('@'); + if (Pos == StringRef::npos) + continue; + + // Aliases defined with .symvar copy the binding from the symbol they alias. + // This is the first place we are able to copy this information. + it->setExternal(SD.isExternal()); + MCELF::SetBinding(*it, MCELF::GetBinding(SD)); + + StringRef Rest = AliasName.substr(Pos); + 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"); + + Renames.insert(std::make_pair(&Symbol, &Alias)); + } +} + +void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + ELFSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &OrigData = *MSD.SymbolData; + MCSymbolData &Data = + Layout.getAssembler().getSymbolData(OrigData.getSymbol().AliasedSymbol()); + + bool IsReserved = Data.isCommon() || Data.getSymbol().isAbsolute() || + Data.getSymbol().isVariable(); + + // Binding and Type share the same byte as upper and lower nibbles + uint8_t Binding = MCELF::GetBinding(OrigData); + uint8_t Type = MCELF::GetType(Data); + uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift); + + // Other and Visibility share the same byte with Visibility using the lower + // 2 bits + uint8_t Visibility = MCELF::GetVisibility(OrigData); + uint8_t Other = MCELF::getOther(OrigData) << + (ELF_Other_Shift - ELF_STV_Shift); + Other |= Visibility; + + uint64_t Value = SymbolValue(Data, Layout); + uint64_t Size = 0; + + assert(!(Data.isCommon() && !Data.isExternal())); + + const MCExpr *ESize = Data.getSize(); + if (ESize) { + int64_t Res; + if (!ESize->EvaluateAsAbsolute(Res, Layout)) + report_fatal_error("Size expression must be absolute."); + Size = Res; + } + + // Write out the symbol table entry + WriteSymbolEntry(SymtabF, ShndxF, MSD.StringIndex, Info, Value, + Size, Other, MSD.SectionIndex, IsReserved); +} + +void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + const MCAssembler &Asm, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap) { + // The string table must be emitted first because we need the index + // into the string table for all the symbol names. + assert(StringTable.size() && "Missing string table"); + + // FIXME: Make sure the start of the symbol table is aligned. + + // The first entry is the undefined symbol entry. + WriteSymbolEntry(SymtabF, ShndxF, 0, 0, 0, 0, 0, 0, false); + + for (unsigned i = 0, e = FileSymbolData.size(); i != e; ++i) { + WriteSymbolEntry(SymtabF, ShndxF, FileSymbolData[i], + ELF::STT_FILE | ELF::STB_LOCAL, 0, 0, + ELF::STV_DEFAULT, ELF::SHN_ABS, true); + } + + // Write the symbol table entries. + LastLocalSymbolIndex = FileSymbolData.size() + LocalSymbolData.size() + 1; + + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = LocalSymbolData[i]; + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + } + + // Write out a symbol table entry for each regular section. + for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; + ++i) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(i->getSection()); + if (Section.getType() == ELF::SHT_RELA || + Section.getType() == ELF::SHT_REL || + Section.getType() == ELF::SHT_STRTAB || + Section.getType() == ELF::SHT_SYMTAB || + Section.getType() == ELF::SHT_SYMTAB_SHNDX) + continue; + WriteSymbolEntry(SymtabF, ShndxF, 0, ELF::STT_SECTION, 0, 0, + ELF::STV_DEFAULT, SectionIndexMap.lookup(&Section), + false); + LastLocalSymbolIndex++; + } + + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = ExternalSymbolData[i]; + MCSymbolData &Data = *MSD.SymbolData; + assert(((Data.getFlags() & ELF_STB_Global) || + (Data.getFlags() & ELF_STB_Weak)) && + "External symbol requires STB_GLOBAL or STB_WEAK flag"); + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + if (MCELF::GetBinding(Data) == ELF::STB_LOCAL) + LastLocalSymbolIndex++; + } + + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = UndefinedSymbolData[i]; + MCSymbolData &Data = *MSD.SymbolData; + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + if (MCELF::GetBinding(Data) == ELF::STB_LOCAL) + LastLocalSymbolIndex++; + } +} + +const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + const MCSymbol *Renamed = Renames.lookup(&Symbol); + const MCSymbolData &SD = Asm.getSymbolData(Symbol); + + if (ASymbol.isUndefined()) { + if (Renamed) + return Renamed; + return undefinedExplicitRelSym(Target, Fixup, IsPCRel); + } + + if (SD.isExternal()) { + if (Renamed) + return Renamed; + return &Symbol; + } + + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(ASymbol.getSection()); + const SectionKind secKind = Section.getKind(); + + if (secKind.isBSS()) + return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); + + if (secKind.isThreadLocal()) { + if (Renamed) + return Renamed; + return &Symbol; + } + + MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); + const MCSectionELF &Sec2 = + static_cast<const MCSectionELF&>(F.getParent()->getSection()); + + if (&Sec2 != &Section && + (Kind == MCSymbolRefExpr::VK_PLT || + Kind == MCSymbolRefExpr::VK_GOTPCREL || + Kind == MCSymbolRefExpr::VK_GOTOFF)) { + if (Renamed) + return Renamed; + return &Symbol; + } + + if (Section.getFlags() & ELF::SHF_MERGE) { + if (Target.getConstant() == 0) + return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); + if (Renamed) + return Renamed; + return &Symbol; + } + + return ExplicitRelSym(Asm, Target, F, Fixup, IsPCRel); + +} + + +void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { + int64_t Addend = 0; + int Index = 0; + int64_t Value = Target.getConstant(); + const MCSymbol *RelocSymbol = NULL; + + bool IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + if (!Target.isAbsolute()) { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + RelocSymbol = SymbolToReloc(Asm, Target, *Fragment, Fixup, IsPCRel); + + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + const MCSymbol &SymbolB = RefB->getSymbol(); + MCSymbolData &SDB = Asm.getSymbolData(SymbolB); + IsPCRel = true; + + // Offset of the symbol in the section + int64_t a = Layout.getSymbolOffset(&SDB); + + // Offset of the relocation in the section + int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + Value += b - a; + } + + if (!RelocSymbol) { + MCSymbolData &SD = Asm.getSymbolData(ASymbol); + MCFragment *F = SD.getFragment(); + + if (F) { + Index = F->getParent()->getOrdinal() + 1; + // Offset of the symbol in the section + Value += Layout.getSymbolOffset(&SD); + } else { + Index = 0; + } + } else { + if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref) + WeakrefUsedInReloc.insert(RelocSymbol); + else + UsedInReloc.insert(RelocSymbol); + Index = -1; + } + Addend = Value; + if (hasRelocationAddend()) + Value = 0; + } + + FixedValue = Value; + unsigned Type = GetRelocType(Target, Fixup, IsPCRel, + (RelocSymbol != 0), Addend); + MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + if (RelocNeedsGOT(Modifier)) + NeedsGOT = true; + + uint64_t RelocOffset = Layout.getFragmentOffset(Fragment) + + Fixup.getOffset(); + + if (!hasRelocationAddend()) + Addend = 0; + + if (is64Bit()) + assert(isInt<64>(Addend)); + else + assert(isInt<32>(Addend)); + + ELFRelocationEntry ERE(RelocOffset, Index, Type, RelocSymbol, Addend, Fixup); + Relocations[Fragment->getParent()].push_back(ERE); +} + + +uint64_t +ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S) { + MCSymbolData &SD = Asm.getSymbolData(*S); + return SD.getIndex(); +} + +bool ELFObjectWriter::isInSymtab(const MCAssembler &Asm, + const MCSymbolData &Data, + bool Used, bool Renamed) { + if (Data.getFlags() & ELF_Other_Weakref) + return false; + + if (Used) + return true; + + if (Renamed) + return false; + + const MCSymbol &Symbol = Data.getSymbol(); + + if (Symbol.getName() == "_GLOBAL_OFFSET_TABLE_") + return true; + + const MCSymbol &A = Symbol.AliasedSymbol(); + if (Symbol.isVariable() && !A.isVariable() && A.isUndefined()) + return false; + + bool IsGlobal = MCELF::GetBinding(Data) == ELF::STB_GLOBAL; + if (!Symbol.isVariable() && Symbol.isUndefined() && !IsGlobal) + return false; + + if (!Asm.isSymbolLinkerVisible(Symbol) && !Symbol.isUndefined()) + return false; + + if (Symbol.isTemporary()) + return false; + + return true; +} + +bool ELFObjectWriter::isLocal(const MCSymbolData &Data, bool isSignature, + bool isUsedInReloc) { + if (Data.isExternal()) + return false; + + const MCSymbol &Symbol = Data.getSymbol(); + const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); + + if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) { + if (isSignature && !isUsedInReloc) + return true; + + return false; + } + + return true; +} + +void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap, + const RelMapTy &RelMap) { + unsigned Index = 1; + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() != ELF::SHT_GROUP) + continue; + SectionIndexMap[&Section] = Index++; + } + + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() == ELF::SHT_GROUP || + Section.getType() == ELF::SHT_REL || + Section.getType() == ELF::SHT_RELA) + continue; + SectionIndexMap[&Section] = Index++; + const MCSectionELF *RelSection = RelMap.lookup(&Section); + if (RelSection) + SectionIndexMap[RelSection] = Index++; + } +} + +void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + RevGroupMapTy RevGroupMap, + unsigned NumRegularSections) { + // FIXME: Is this the correct place to do this? + // FIXME: Why is an undefined reference to _GLOBAL_OFFSET_TABLE_ needed? + if (NeedsGOT) { + StringRef Name = "_GLOBAL_OFFSET_TABLE_"; + MCSymbol *Sym = Asm.getContext().GetOrCreateSymbol(Name); + MCSymbolData &Data = Asm.getOrCreateSymbolData(*Sym); + Data.setExternal(true); + MCELF::SetBinding(Data, ELF::STB_GLOBAL); + } + + // Index 0 is always the empty string. + StringMap<uint64_t> StringIndexMap; + StringTable += '\x00'; + + // FIXME: We could optimize suffixes in strtab in the same way we + // optimize them in shstrtab. + + for (MCAssembler::const_file_name_iterator it = Asm.file_names_begin(), + ie = Asm.file_names_end(); + it != ie; + ++it) { + StringRef Name = *it; + uint64_t &Entry = StringIndexMap[Name]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Name; + StringTable += '\x00'; + } + FileSymbolData.push_back(Entry); + } + + // Add the data for the symbols. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + bool Used = UsedInReloc.count(&Symbol); + bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); + bool isSignature = RevGroupMap.count(&Symbol); + + if (!isInSymtab(Asm, *it, + Used || WeakrefUsed || isSignature, + Renames.count(&Symbol))) + continue; + + ELFSymbolData MSD; + MSD.SymbolData = it; + const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); + + // Undefined symbols are global, but this is the first place we + // are able to set it. + bool Local = isLocal(*it, isSignature, Used); + if (!Local && MCELF::GetBinding(*it) == ELF::STB_LOCAL) { + MCSymbolData &SD = Asm.getSymbolData(RefSymbol); + MCELF::SetBinding(*it, ELF::STB_GLOBAL); + MCELF::SetBinding(SD, ELF::STB_GLOBAL); + } + + if (RefSymbol.isUndefined() && !Used && WeakrefUsed) + MCELF::SetBinding(*it, ELF::STB_WEAK); + + if (it->isCommon()) { + assert(!Local); + MSD.SectionIndex = ELF::SHN_COMMON; + } else if (Symbol.isAbsolute() || RefSymbol.isVariable()) { + MSD.SectionIndex = ELF::SHN_ABS; + } else if (RefSymbol.isUndefined()) { + if (isSignature && !Used) + MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap[&Symbol]); + else + MSD.SectionIndex = ELF::SHN_UNDEF; + } else { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(RefSymbol.getSection()); + MSD.SectionIndex = SectionIndexMap.lookup(&Section); + if (MSD.SectionIndex >= ELF::SHN_LORESERVE) + NeedsSymtabShndx = true; + assert(MSD.SectionIndex && "Invalid section index!"); + } + + // The @@@ in symbol version is replaced with @ in undefined symbols and + // @@ in defined ones. + StringRef Name = Symbol.getName(); + SmallString<32> Buf; + + size_t Pos = Name.find("@@@"); + if (Pos != StringRef::npos) { + Buf += Name.substr(0, Pos); + unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; + Buf += Name.substr(Pos + Skip); + Name = Buf; + } + + uint64_t &Entry = StringIndexMap[Name]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Name; + StringTable += '\x00'; + } + MSD.StringIndex = Entry; + if (MSD.SectionIndex == ELF::SHN_UNDEF) + UndefinedSymbolData.push_back(MSD); + else if (Local) + LocalSymbolData.push_back(MSD); + else + ExternalSymbolData.push_back(MSD); + } + + // Symbols are required to be in lexicographic order. + array_pod_sort(LocalSymbolData.begin(), LocalSymbolData.end()); + array_pod_sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); + array_pod_sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + + // Set the symbol indices. Local symbols must come before all other + // symbols with non-local bindings. + unsigned Index = FileSymbolData.size() + 1; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + LocalSymbolData[i].SymbolData->setIndex(Index++); + + Index += NumRegularSections; + + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + ExternalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + UndefinedSymbolData[i].SymbolData->setIndex(Index++); + + if (Index >= ELF::SHN_LORESERVE) + NeedsSymtabShndx = true; +} + +void ELFObjectWriter::CreateRelocationSections(MCAssembler &Asm, + MCAsmLayout &Layout, + RelMapTy &RelMap) { + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + if (Relocations[&SD].empty()) + continue; + + MCContext &Ctx = Asm.getContext(); + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(SD.getSection()); + + const StringRef SectionName = Section.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; + StringRef Group = ""; + if (Section.getFlags() & ELF::SHF_GROUP) { + Flags = ELF::SHF_GROUP; + Group = Section.getGroup()->getName(); + } + + const MCSectionELF *RelaSection = + Ctx.getELFSection(RelaSectionName, hasRelocationAddend() ? + ELF::SHT_RELA : ELF::SHT_REL, Flags, + SectionKind::getReadOnly(), + EntrySize, Group); + RelMap[&Section] = RelaSection; + Asm.getOrCreateSectionData(*RelaSection); + } +} + +void ELFObjectWriter::WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout, + const RelMapTy &RelMap) { + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(SD.getSection()); + + const MCSectionELF *RelaSection = RelMap.lookup(&Section); + if (!RelaSection) + continue; + MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); + RelaSD.setAlignment(is64Bit() ? 8 : 4); + + MCDataFragment *F = new MCDataFragment(&RelaSD); + WriteRelocationsFragment(Asm, F, &*it); + } +} + +void ELFObjectWriter::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) { + Write32(Name); // sh_name: index into string table + Write32(Type); // sh_type + WriteWord(Flags); // sh_flags + WriteWord(Address); // sh_addr + WriteWord(Offset); // sh_offset + WriteWord(Size); // sh_size + Write32(Link); // sh_link + Write32(Info); // sh_info + WriteWord(Alignment); // sh_addralign + WriteWord(EntrySize); // sh_entsize +} + +void ELFObjectWriter::WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD) { + std::vector<ELFRelocationEntry> &Relocs = Relocations[SD]; + + // Sort the relocation entries. Most targets just sort by r_offset, but some + // (e.g., MIPS) have additional constraints. + TargetObjectWriter->sortRelocs(Asm, Relocs); + + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { + ELFRelocationEntry entry = Relocs[e - i - 1]; + + if (!entry.Index) + ; + else if (entry.Index < 0) + entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol); + else + entry.Index += FileSymbolData.size() + LocalSymbolData.size(); + if (is64Bit()) { + String64(*F, entry.r_offset); + if (TargetObjectWriter->isN64()) { + String32(*F, entry.Index); + + String8(*F, TargetObjectWriter->getRSsym(entry.Type)); + String8(*F, TargetObjectWriter->getRType3(entry.Type)); + String8(*F, TargetObjectWriter->getRType2(entry.Type)); + String8(*F, TargetObjectWriter->getRType(entry.Type)); + } + else { + struct ELF::Elf64_Rela ERE64; + ERE64.setSymbolAndType(entry.Index, entry.Type); + String64(*F, ERE64.r_info); + } + if (hasRelocationAddend()) + String64(*F, entry.r_addend); + } else { + String32(*F, entry.r_offset); + + struct ELF::Elf32_Rela ERE32; + ERE32.setSymbolAndType(entry.Index, entry.Type); + String32(*F, ERE32.r_info); + + if (hasRelocationAddend()) + String32(*F, entry.r_addend); + } + } +} + +static int compareBySuffix(const MCSectionELF *const *a, + const MCSectionELF *const *b) { + const StringRef &NameA = (*a)->getSectionName(); + const StringRef &NameB = (*b)->getSectionName(); + const unsigned sizeA = NameA.size(); + const unsigned sizeB = NameB.size(); + const unsigned len = std::min(sizeA, sizeB); + for (unsigned int i = 0; i < len; ++i) { + char ca = NameA[sizeA - i - 1]; + char cb = NameB[sizeB - i - 1]; + if (ca != cb) + return cb - ca; + } + + return sizeB - sizeA; +} + +void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, + MCAsmLayout &Layout, + SectionIndexMapTy &SectionIndexMap, + const RelMapTy &RelMap) { + MCContext &Ctx = Asm.getContext(); + MCDataFragment *F; + + unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + + // We construct .shstrtab, .symtab and .strtab in this order to match gnu as. + const MCSectionELF *ShstrtabSection = + Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly()); + MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); + ShstrtabSD.setAlignment(1); + + const MCSectionELF *SymtabSection = + Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + EntrySize, ""); + MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); + SymtabSD.setAlignment(is64Bit() ? 8 : 4); + + MCSectionData *SymtabShndxSD = NULL; + + if (NeedsSymtabShndx) { + const MCSectionELF *SymtabShndxSection = + Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, + SectionKind::getReadOnly(), 4, ""); + SymtabShndxSD = &Asm.getOrCreateSectionData(*SymtabShndxSection); + SymtabShndxSD->setAlignment(4); + } + + const MCSectionELF *StrtabSection; + StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly()); + MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); + StrtabSD.setAlignment(1); + + ComputeIndexMap(Asm, SectionIndexMap, RelMap); + + ShstrtabIndex = SectionIndexMap.lookup(ShstrtabSection); + SymbolTableIndex = SectionIndexMap.lookup(SymtabSection); + StringTableIndex = SectionIndexMap.lookup(StrtabSection); + + // Symbol table + F = new MCDataFragment(&SymtabSD); + MCDataFragment *ShndxF = NULL; + if (NeedsSymtabShndx) { + ShndxF = new MCDataFragment(SymtabShndxSD); + } + WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap); + + F = new MCDataFragment(&StrtabSD); + F->getContents().append(StringTable.begin(), StringTable.end()); + + F = new MCDataFragment(&ShstrtabSD); + + std::vector<const MCSectionELF*> Sections; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + Sections.push_back(&Section); + } + array_pod_sort(Sections.begin(), Sections.end(), compareBySuffix); + + // Section header string table. + // + // The first entry of a string table holds a null character so skip + // section 0. + uint64_t Index = 1; + F->getContents().push_back('\x00'); + + for (unsigned int I = 0, E = Sections.size(); I != E; ++I) { + const MCSectionELF &Section = *Sections[I]; + + StringRef Name = Section.getSectionName(); + if (I != 0) { + StringRef PreviousName = Sections[I - 1]->getSectionName(); + if (PreviousName.endswith(Name)) { + SectionStringTableIndex[&Section] = Index - Name.size() - 1; + continue; + } + } + // Remember the index into the string table so we can write it + // into the sh_name field of the section header table. + SectionStringTableIndex[&Section] = Index; + + Index += Name.size() + 1; + F->getContents().append(Name.begin(), Name.end()); + F->getContents().push_back('\x00'); + } +} + +void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, + MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap, + SectionIndexMapTy &SectionIndexMap, + const RelMapTy &RelMap) { + // Create the .note.GNU-stack section if needed. + MCContext &Ctx = Asm.getContext(); + if (Asm.getNoExecStack()) { + const MCSectionELF *GnuStackSection = + Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly()); + Asm.getOrCreateSectionData(*GnuStackSection); + } + + // Build the groups + for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); + it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + if (!(Section.getFlags() & ELF::SHF_GROUP)) + continue; + + const MCSymbol *SignatureSymbol = Section.getGroup(); + Asm.getOrCreateSymbolData(*SignatureSymbol); + const MCSectionELF *&Group = RevGroupMap[SignatureSymbol]; + if (!Group) { + Group = Ctx.CreateELFGroupSection(); + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + Data.setAlignment(4); + MCDataFragment *F = new MCDataFragment(&Data); + String32(*F, ELF::GRP_COMDAT); + } + GroupMap[Group] = SignatureSymbol; + } + + ComputeIndexMap(Asm, SectionIndexMap, RelMap); + + // Add sections to the groups + for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); + it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + if (!(Section.getFlags() & ELF::SHF_GROUP)) + continue; + const MCSectionELF *Group = RevGroupMap[Section.getGroup()]; + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + // FIXME: we could use the previous fragment + MCDataFragment *F = new MCDataFragment(&Data); + unsigned Index = SectionIndexMap.lookup(&Section); + String32(*F, Index); + } +} + +void ELFObjectWriter::WriteSection(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, + uint64_t Offset, uint64_t Size, + uint64_t Alignment, + const MCSectionELF &Section) { + uint64_t sh_link = 0; + uint64_t sh_info = 0; + + switch(Section.getType()) { + case ELF::SHT_DYNAMIC: + sh_link = SectionStringTableIndex[&Section]; + sh_info = 0; + break; + + case ELF::SHT_REL: + case ELF::SHT_RELA: { + const MCSectionELF *SymtabSection; + const MCSectionELF *InfoSection; + SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, + 0, + SectionKind::getReadOnly()); + sh_link = SectionIndexMap.lookup(SymtabSection); + assert(sh_link && ".symtab not found"); + + // Remove ".rel" and ".rela" prefixes. + unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; + StringRef SectionName = Section.getSectionName().substr(SecNameLen); + StringRef GroupName = + Section.getGroup() ? Section.getGroup()->getName() : ""; + + InfoSection = Asm.getContext().getELFSection(SectionName, ELF::SHT_PROGBITS, + 0, SectionKind::getReadOnly(), + 0, GroupName); + sh_info = SectionIndexMap.lookup(InfoSection); + break; + } + + case ELF::SHT_SYMTAB: + case ELF::SHT_DYNSYM: + sh_link = StringTableIndex; + sh_info = LastLocalSymbolIndex; + break; + + case ELF::SHT_SYMTAB_SHNDX: + sh_link = SymbolTableIndex; + break; + + case ELF::SHT_PROGBITS: + case ELF::SHT_STRTAB: + case ELF::SHT_NOBITS: + case ELF::SHT_NOTE: + case ELF::SHT_NULL: + case ELF::SHT_ARM_ATTRIBUTES: + case ELF::SHT_INIT_ARRAY: + case ELF::SHT_FINI_ARRAY: + case ELF::SHT_PREINIT_ARRAY: + case ELF::SHT_X86_64_UNWIND: + case ELF::SHT_MIPS_REGINFO: + case ELF::SHT_MIPS_OPTIONS: + // Nothing to do. + break; + + case ELF::SHT_GROUP: + sh_link = SymbolTableIndex; + sh_info = GroupSymbolIndex; + break; + + default: + assert(0 && "FIXME: sh_type value not supported!"); + break; + } + + if (TargetObjectWriter->getEMachine() == ELF::EM_ARM && + Section.getType() == ELF::SHT_ARM_EXIDX) { + StringRef SecName(Section.getSectionName()); + if (SecName == ".ARM.exidx") { + sh_link = SectionIndexMap.lookup( + Asm.getContext().getELFSection(".text", + ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, + SectionKind::getText())); + } else if (SecName.startswith(".ARM.exidx")) { + StringRef GroupName = + Section.getGroup() ? Section.getGroup()->getName() : ""; + sh_link = SectionIndexMap.lookup(Asm.getContext().getELFSection( + SecName.substr(sizeof(".ARM.exidx") - 1), ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, SectionKind::getText(), 0, + GroupName)); + } + } + + WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), + Section.getFlags(), 0, Offset, Size, sh_link, sh_info, + Alignment, Section.getEntrySize()); +} + +bool ELFObjectWriter::IsELFMetaDataSection(const MCSectionData &SD) { + return SD.getOrdinal() == ~UINT32_C(0) && + !SD.getSection().isVirtualSection(); +} + +uint64_t ELFObjectWriter::DataSectionSize(const MCSectionData &SD) { + uint64_t Ret = 0; + for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; + ++i) { + const MCFragment &F = *i; + assert(F.getKind() == MCFragment::FT_Data); + Ret += cast<MCDataFragment>(F).getContents().size(); + } + return Ret; +} + +uint64_t ELFObjectWriter::GetSectionFileSize(const MCAsmLayout &Layout, + const MCSectionData &SD) { + if (IsELFMetaDataSection(SD)) + return DataSectionSize(SD); + return Layout.getSectionFileSize(&SD); +} + +uint64_t ELFObjectWriter::GetSectionAddressSize(const MCAsmLayout &Layout, + const MCSectionData &SD) { + if (IsELFMetaDataSection(SD)) + return DataSectionSize(SD); + return Layout.getSectionAddressSize(&SD); +} + +void ELFObjectWriter::WriteDataSectionData(MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCSectionELF &Section) { + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + + uint64_t Padding = OffsetToAlignment(OS.tell(), SD.getAlignment()); + WriteZeros(Padding); + + if (IsELFMetaDataSection(SD)) { + for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; + ++i) { + const MCFragment &F = *i; + assert(F.getKind() == MCFragment::FT_Data); + WriteBytes(cast<MCDataFragment>(F).getContents()); + } + } else { + Asm.writeSectionData(&SD, Layout); + } +} + +void ELFObjectWriter::WriteSectionHeader(MCAssembler &Asm, + const GroupMapTy &GroupMap, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap, + const SectionOffsetMapTy &SectionOffsetMap) { + const unsigned NumSections = Asm.size() + 1; + + std::vector<const MCSectionELF*> Sections; + Sections.resize(NumSections - 1); + + for (SectionIndexMapTy::const_iterator i= + SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) { + const std::pair<const MCSectionELF*, uint32_t> &p = *i; + Sections[p.second - 1] = p.first; + } + + // Null section first. + uint64_t FirstSectionSize = + NumSections >= ELF::SHN_LORESERVE ? NumSections : 0; + uint32_t FirstSectionLink = + ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0; + WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0); + + for (unsigned i = 0; i < NumSections - 1; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + uint32_t GroupSymbolIndex; + if (Section.getType() != ELF::SHT_GROUP) + GroupSymbolIndex = 0; + else + GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, + GroupMap.lookup(&Section)); + + uint64_t Size = GetSectionAddressSize(Layout, SD); + + WriteSection(Asm, SectionIndexMap, GroupSymbolIndex, + SectionOffsetMap.lookup(&Section), Size, + SD.getAlignment(), Section); + } +} + +void ELFObjectWriter::ComputeSectionOrder(MCAssembler &Asm, + std::vector<const MCSectionELF*> &Sections) { + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() == ELF::SHT_GROUP) + Sections.push_back(&Section); + } + + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() != ELF::SHT_GROUP && + Section.getType() != ELF::SHT_REL && + Section.getType() != ELF::SHT_RELA) + Sections.push_back(&Section); + } + + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() == ELF::SHT_REL || + Section.getType() == ELF::SHT_RELA) + Sections.push_back(&Section); + } +} + +void ELFObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + GroupMapTy GroupMap; + RevGroupMapTy RevGroupMap; + SectionIndexMapTy SectionIndexMap; + + unsigned NumUserSections = Asm.size(); + + DenseMap<const MCSectionELF*, const MCSectionELF*> RelMap; + CreateRelocationSections(Asm, const_cast<MCAsmLayout&>(Layout), RelMap); + + const unsigned NumUserAndRelocSections = Asm.size(); + CreateIndexedSections(Asm, const_cast<MCAsmLayout&>(Layout), GroupMap, + RevGroupMap, SectionIndexMap, RelMap); + const unsigned AllSections = Asm.size(); + const unsigned NumIndexedSections = AllSections - NumUserAndRelocSections; + + unsigned NumRegularSections = NumUserSections + NumIndexedSections; + + // Compute symbol table information. + ComputeSymbolTable(Asm, SectionIndexMap, RevGroupMap, NumRegularSections); + + + WriteRelocations(Asm, const_cast<MCAsmLayout&>(Layout), RelMap); + + CreateMetadataSections(const_cast<MCAssembler&>(Asm), + const_cast<MCAsmLayout&>(Layout), + SectionIndexMap, + RelMap); + + uint64_t NaturalAlignment = is64Bit() ? 8 : 4; + uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) : + sizeof(ELF::Elf32_Ehdr); + uint64_t FileOff = HeaderSize; + + std::vector<const MCSectionELF*> Sections; + ComputeSectionOrder(Asm, Sections); + unsigned NumSections = Sections.size(); + SectionOffsetMapTy SectionOffsetMap; + for (unsigned i = 0; i < NumRegularSections + 1; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + + FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); + + // Remember the offset into the file for this section. + SectionOffsetMap[&Section] = FileOff; + + // Get the size of the section in the output file (including padding). + FileOff += GetSectionFileSize(Layout, SD); + } + + FileOff = RoundUpToAlignment(FileOff, NaturalAlignment); + + const unsigned SectionHeaderOffset = FileOff - HeaderSize; + + uint64_t SectionHeaderEntrySize = is64Bit() ? + sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr); + FileOff += (NumSections + 1) * SectionHeaderEntrySize; + + for (unsigned i = NumRegularSections + 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + + FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); + + // Remember the offset into the file for this section. + SectionOffsetMap[&Section] = FileOff; + + // Get the size of the section in the output file (including padding). + FileOff += GetSectionFileSize(Layout, SD); + } + + // Write out the ELF header ... + WriteHeader(Asm, SectionHeaderOffset, NumSections + 1); + + // ... then the regular sections ... + // + because of .shstrtab + for (unsigned i = 0; i < NumRegularSections + 1; ++i) + WriteDataSectionData(Asm, Layout, *Sections[i]); + + uint64_t Padding = OffsetToAlignment(OS.tell(), NaturalAlignment); + WriteZeros(Padding); + + // ... then the section header table ... + WriteSectionHeader(Asm, GroupMap, Layout, SectionIndexMap, + SectionOffsetMap); + + // ... and then the remaining sections ... + for (unsigned i = NumRegularSections + 1; i < NumSections; ++i) + WriteDataSectionData(Asm, Layout, *Sections[i]); +} + +bool +ELFObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + if (DataA.getFlags() & ELF_STB_Weak) + return false; + return MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl( + Asm, DataA, FB,InSet, IsPCRel); +} + +MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &OS, + bool IsLittleEndian) { + return new ELFObjectWriter(MOTW, OS, IsLittleEndian); +} diff --git a/contrib/llvm/lib/MC/MCAsmBackend.cpp b/contrib/llvm/lib/MC/MCAsmBackend.cpp new file mode 100644 index 000000000000..c4c98cc900ac --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmBackend.cpp @@ -0,0 +1,43 @@ +//===-- 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/STLExtras.h" +#include "llvm/MC/MCFixupKindInfo.h" +using namespace llvm; + +MCAsmBackend::MCAsmBackend() + : HasReliableSymbolDifference(false), HasDataInCodeSupport(false) {} + +MCAsmBackend::~MCAsmBackend() {} + +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_SecRel_1", 0, 8, 0 }, + { "FK_SecRel_2", 0, 16, 0 }, + { "FK_SecRel_4", 0, 32, 0 }, + { "FK_SecRel_8", 0, 64, 0 } + }; + + assert((size_t)Kind <= array_lengthof(Builtins) && "Unknown fixup kind"); + return Builtins[Kind]; +} diff --git a/contrib/llvm/lib/MC/MCAsmInfo.cpp b/contrib/llvm/lib/MC/MCAsmInfo.cpp new file mode 100644 index 000000000000..28f1c951641c --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfo.cpp @@ -0,0 +1,140 @@ +//===-- 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/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/Dwarf.h" +#include <cctype> +#include <cstring> +using namespace llvm; + +MCAsmInfo::MCAsmInfo() { + PointerSize = 4; + CalleeSaveStackSlotSize = 4; + + IsLittleEndian = true; + StackGrowsUp = false; + HasSubsectionsViaSymbols = false; + HasMachoZeroFillDirective = false; + HasMachoTBSSDirective = false; + HasStaticCtorDtorReferenceInStaticMode = false; + LinkerRequiresNonEmptyDwarfLines = false; + MaxInstLength = 4; + MinInstAlignment = 1; + DollarIsPC = false; + SeparatorString = ";"; + CommentColumn = 40; + CommentString = "#"; + LabelSuffix = ":"; + DebugLabelSuffix = ":"; + GlobalPrefix = ""; + PrivateGlobalPrefix = "."; + LinkerPrivateGlobalPrefix = ""; + InlineAsmStart = "APP"; + InlineAsmEnd = "NO_APP"; + Code16Directive = ".code16"; + Code32Directive = ".code32"; + Code64Directive = ".code64"; + AssemblerDialect = 0; + AllowAtInName = false; + UseDataRegionDirectives = false; + 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"; + SunStyleELFSectionSwitchSyntax = false; + UsesELFSectionDirectiveForBSS = false; + AlignDirective = "\t.align\t"; + AlignmentIsInBytes = true; + TextAlignFillValue = 0; + GPRel64Directive = 0; + GPRel32Directive = 0; + GlobalDirective = "\t.globl\t"; + HasSetDirective = true; + HasAggressiveSymbolFolding = true; + COMMDirectiveAlignmentIsInBytes = true; + LCOMMDirectiveAlignmentType = LCOMM::NoAlignment; + HasDotTypeDotSizeDirective = true; + HasSingleParameterDotFile = true; + HasIdentDirective = false; + HasNoDeadStrip = false; + WeakRefDirective = 0; + WeakDefDirective = 0; + LinkOnceDirective = 0; + HiddenVisibilityAttr = MCSA_Hidden; + HiddenDeclarationVisibilityAttr = MCSA_Hidden; + ProtectedVisibilityAttr = MCSA_Protected; + HasLEB128 = false; + SupportsDebugInformation = false; + ExceptionsType = ExceptionHandling::None; + DwarfUsesRelocationsAcrossSections = true; + DwarfRegNumForCFI = false; + HasMicrosoftFastStdCallMangling = false; + NeedsDwarfSectionOffsetDirective = false; +} + +MCAsmInfo::~MCAsmInfo() { +} + + +unsigned MCAsmInfo::getULEB128Size(uint64_t Value) { + unsigned Size = 0; + do { + Value >>= 7; + Size += sizeof(int8_t); + } while (Value); + return Size; +} + +unsigned MCAsmInfo::getSLEB128Size(int64_t Value) { + unsigned Size = 0; + int Sign = Value >> (8 * sizeof(Value) - 1); + bool IsMore; + + do { + unsigned Byte = Value & 0x7f; + Value >>= 7; + IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0; + Size += sizeof(int8_t); + } while (IsMore); + return Size; +} + +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); +} diff --git a/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp b/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp new file mode 100644 index 000000000000..9d9f98e72b96 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoCOFF.cpp @@ -0,0 +1,52 @@ +//===-- MCAsmInfoCOFF.cpp - COFF 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 COFF-based targets +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoCOFF.h" +using namespace llvm; + +void MCAsmInfoCOFF::anchor() { } + +MCAsmInfoCOFF::MCAsmInfoCOFF() { + GlobalPrefix = "_"; + // MingW 4.5 and later support .comm with log2 alignment, but .lcomm uses byte + // alignment. + COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::ByteAlignment; + HasDotTypeDotSizeDirective = false; + HasSingleParameterDotFile = false; + PrivateGlobalPrefix = "L"; // Prefix for private global symbols + WeakRefDirective = "\t.weak\t"; + LinkOnceDirective = "\t.linkonce discard\n"; + + // Doesn't support visibility: + HiddenVisibilityAttr = HiddenDeclarationVisibilityAttr = MCSA_Invalid; + ProtectedVisibilityAttr = MCSA_Invalid; + + // Set up DWARF directives + HasLEB128 = true; // Target asm supports leb128 directives (little-endian) + SupportsDebugInformation = true; + HasMicrosoftFastStdCallMangling = true; + NeedsDwarfSectionOffsetDirective = true; +} + +void MCAsmInfoMicrosoft::anchor() { } + +MCAsmInfoMicrosoft::MCAsmInfoMicrosoft() { +} + +void MCAsmInfoGNUCOFF::anchor() { } + +MCAsmInfoGNUCOFF::MCAsmInfoGNUCOFF() { + +} diff --git a/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp b/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp new file mode 100644 index 000000000000..704c8161f880 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp @@ -0,0 +1,62 @@ +//===-- MCAsmInfoDarwin.cpp - Darwin 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 Darwin-based targets +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoDarwin.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCStreamer.h" +using namespace llvm; + +void MCAsmInfoDarwin::anchor() { } + +MCAsmInfoDarwin::MCAsmInfoDarwin() { + // Common settings for all Darwin targets. + // Syntax: + GlobalPrefix = "_"; + PrivateGlobalPrefix = "L"; + LinkerPrivateGlobalPrefix = "l"; + HasSingleParameterDotFile = false; + HasSubsectionsViaSymbols = true; + + AlignmentIsInBytes = false; + COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; + InlineAsmStart = " InlineAsm Start"; + InlineAsmEnd = " InlineAsm End"; + + // Directives: + WeakDefDirective = "\t.weak_definition "; + WeakRefDirective = "\t.weak_reference "; + ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. + HasMachoZeroFillDirective = true; // Uses .zerofill + HasMachoTBSSDirective = true; // Uses .tbss + HasStaticCtorDtorReferenceInStaticMode = true; + + // FIXME: Darwin 10 and newer don't need this. + LinkerRequiresNonEmptyDwarfLines = true; + + // 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; + + DwarfUsesRelocationsAcrossSections = false; +} diff --git a/contrib/llvm/lib/MC/MCAsmInfoELF.cpp b/contrib/llvm/lib/MC/MCAsmInfoELF.cpp new file mode 100644 index 000000000000..8cf4e4fea233 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmInfoELF.cpp @@ -0,0 +1,23 @@ +//===-- MCAsmInfoELF.cpp - ELF 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 ELF-based targets +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoELF.h" +using namespace llvm; + +void MCAsmInfoELF::anchor() { } + +MCAsmInfoELF::MCAsmInfoELF() { + HasIdentDirective = true; + WeakRefDirective = "\t.weak\t"; +} diff --git a/contrib/llvm/lib/MC/MCAsmStreamer.cpp b/contrib/llvm/lib/MC/MCAsmStreamer.cpp new file mode 100644 index 000000000000..ca49f8f5908e --- /dev/null +++ b/contrib/llvm/lib/MC/MCAsmStreamer.cpp @@ -0,0 +1,1380 @@ +//===- lib/MC/MCAsmStreamer.cpp - Text Assembly 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/OwningPtr.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/MCCodeEmitter.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/MCRegisterInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Path.h" +#include <cctype> +using namespace llvm; + +namespace { + +class MCAsmStreamer : public MCStreamer { +protected: + formatted_raw_ostream &OS; + const MCAsmInfo *MAI; +private: + OwningPtr<MCInstPrinter> InstPrinter; + OwningPtr<MCCodeEmitter> Emitter; + OwningPtr<MCAsmBackend> AsmBackend; + + SmallString<128> CommentToEmit; + raw_svector_ostream CommentStream; + + unsigned IsVerboseAsm : 1; + unsigned ShowInst : 1; + unsigned UseLoc : 1; + unsigned UseCFI : 1; + unsigned UseDwarfDirectory : 1; + + enum EHSymbolFlags { EHGlobal = 1, + EHWeakDefinition = 1 << 1, + EHPrivateExtern = 1 << 2 }; + DenseMap<const MCSymbol*, unsigned> FlagMap; + + bool needsSet(const MCExpr *Value); + + void EmitRegisterName(int64_t Register); + virtual void EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame); + virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame); + +public: + MCAsmStreamer(MCContext &Context, MCTargetStreamer *TargetStreamer, + formatted_raw_ostream &os, bool isVerboseAsm, bool useLoc, + bool useCFI, bool useDwarfDirectory, MCInstPrinter *printer, + MCCodeEmitter *emitter, MCAsmBackend *asmbackend, bool showInst) + : MCStreamer(Context, TargetStreamer), OS(os), MAI(Context.getAsmInfo()), + InstPrinter(printer), Emitter(emitter), AsmBackend(asmbackend), + CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), + ShowInst(showInst), UseLoc(useLoc), UseCFI(useCFI), + UseDwarfDirectory(useDwarfDirectory) { + if (InstPrinter && IsVerboseAsm) + InstPrinter->setCommentStream(CommentStream); + } + ~MCAsmStreamer() {} + + inline void EmitEOL() { + // If we don't have any comments, just emit a \n. + if (!IsVerboseAsm) { + OS << '\n'; + return; + } + EmitCommentsAndEOL(); + } + void EmitCommentsAndEOL(); + + /// isVerboseAsm - Return true if this streamer supports verbose assembly at + /// all. + virtual bool isVerboseAsm() const { return IsVerboseAsm; } + + /// hasRawTextSupport - We support EmitRawText. + virtual bool hasRawTextSupport() const { return true; } + + /// AddComment - Add a comment that can be emitted to the generated .s + /// file if applicable as a QoI issue to make the output of the compiler + /// more readable. This only affects the MCAsmStreamer, and only when + /// verbose assembly output is enabled. + virtual void AddComment(const Twine &T); + + /// AddEncodingComment - Add a comment showing the encoding of an instruction. + virtual void AddEncodingComment(const MCInst &Inst); + + /// GetCommentOS - 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. + virtual raw_ostream &GetCommentOS() { + if (!IsVerboseAsm) + return nulls(); // Discard comments unless in verbose asm mode. + return CommentStream; + } + + /// AddBlankLine - Emit a blank line to a .s file to pretty it up. + virtual void AddBlankLine() { + EmitEOL(); + } + + /// @name MCStreamer Interface + /// @{ + + virtual void ChangeSection(const MCSection *Section, + const MCExpr *Subsection); + + virtual void InitSections() { + InitToTextSection(); + } + + virtual void InitToTextSection() { + SwitchSection(getContext().getObjectFileInfo()->getTextSection()); + } + + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitDebugLabel(MCSymbol *Symbol); + + virtual void EmitEHSymAttributes(const MCSymbol *Symbol, + MCSymbol *EHSymbol); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitLinkerOptions(ArrayRef<std::string> Options); + virtual void EmitDataRegion(MCDataRegionType Kind); + virtual void EmitThumbFunc(MCSymbol *Func); + + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label, + unsigned PointerSize); + virtual void EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label); + + virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); + + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol); + virtual void EmitCOFFSymbolStorageClass(int StorageClass); + virtual void EmitCOFFSymbolType(int Type); + virtual void EndCOFFSymbolDef(); + virtual void EmitCOFFSecRel32(MCSymbol const *Symbol); + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + + /// EmitLocalCommonSymbol - 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. + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + uint64_t Size = 0, unsigned ByteAlignment = 0); + + virtual void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0); + + virtual void EmitBytes(StringRef Data); + + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size); + virtual void EmitIntValue(uint64_t Value, unsigned Size); + + virtual void EmitULEB128Value(const MCExpr *Value); + + virtual void EmitSLEB128Value(const MCExpr *Value); + + virtual void EmitGPRel64Value(const MCExpr *Value); + + virtual void EmitGPRel32Value(const MCExpr *Value); + + + virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue); + + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); + + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + + virtual bool EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + + virtual void EmitFileDirective(StringRef Filename); + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, unsigned CUID = 0); + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator, + StringRef FileName); + + virtual void EmitIdent(StringRef IdentString); + virtual void EmitCFISections(bool EH, bool Debug); + virtual void EmitCFIDefCfa(int64_t Register, int64_t Offset); + virtual void EmitCFIDefCfaOffset(int64_t Offset); + virtual void EmitCFIDefCfaRegister(int64_t Register); + virtual void EmitCFIOffset(int64_t Register, int64_t Offset); + virtual void EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding); + virtual void EmitCFILsda(const MCSymbol *Sym, unsigned Encoding); + virtual void EmitCFIRememberState(); + virtual void EmitCFIRestoreState(); + virtual void EmitCFISameValue(int64_t Register); + virtual void EmitCFIRelOffset(int64_t Register, int64_t Offset); + virtual void EmitCFIAdjustCfaOffset(int64_t Adjustment); + virtual void EmitCFISignalFrame(); + virtual void EmitCFIUndefined(int64_t Register); + virtual void EmitCFIRegister(int64_t Register1, int64_t Register2); + virtual void EmitCFIWindowSave(); + + virtual void EmitWin64EHStartProc(const MCSymbol *Symbol); + virtual void EmitWin64EHEndProc(); + virtual void EmitWin64EHStartChained(); + virtual void EmitWin64EHEndChained(); + virtual void EmitWin64EHHandler(const MCSymbol *Sym, bool Unwind, + bool Except); + virtual void EmitWin64EHHandlerData(); + virtual void EmitWin64EHPushReg(unsigned Register); + virtual void EmitWin64EHSetFrame(unsigned Register, unsigned Offset); + virtual void EmitWin64EHAllocStack(unsigned Size); + virtual void EmitWin64EHSaveReg(unsigned Register, unsigned Offset); + virtual void EmitWin64EHSaveXMM(unsigned Register, unsigned Offset); + virtual void EmitWin64EHPushFrame(bool Code); + virtual void EmitWin64EHEndProlog(); + + virtual void EmitInstruction(const MCInst &Inst); + + virtual void EmitBundleAlignMode(unsigned AlignPow2); + virtual void EmitBundleLock(bool AlignToEnd); + virtual void EmitBundleUnlock(); + + /// 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. + virtual void EmitRawTextImpl(StringRef String); + + virtual void FinishImpl(); +}; + +} // end anonymous namespace. + +/// AddComment - Add a comment that can be emitted to the generated .s +/// file if applicable as a QoI issue to make the output of the compiler +/// more readable. This only affects the MCAsmStreamer, and only when +/// verbose assembly output is enabled. +void MCAsmStreamer::AddComment(const Twine &T) { + if (!IsVerboseAsm) return; + + // Make sure that CommentStream is flushed. + CommentStream.flush(); + + T.toVector(CommentToEmit); + // Each comment goes on its own line. + CommentToEmit.push_back('\n'); + + // Tell the comment stream that the vector changed underneath it. + CommentStream.resync(); +} + +void MCAsmStreamer::EmitCommentsAndEOL() { + if (CommentToEmit.empty() && CommentStream.GetNumBytesInBuffer() == 0) { + OS << '\n'; + return; + } + + CommentStream.flush(); + StringRef Comments = CommentToEmit.str(); + + 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(); + // Tell the comment stream that the vector changed underneath it. + CommentStream.resync(); +} + +static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { + assert(Bytes && "Invalid size!"); + return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); +} + +void MCAsmStreamer::ChangeSection(const MCSection *Section, + const MCExpr *Subsection) { + assert(Section && "Cannot switch to a null section!"); + Section->PrintSwitchToSection(*MAI, OS, Subsection); +} + +void MCAsmStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, + MCSymbol *EHSymbol) { + if (UseCFI) + return; + + unsigned Flags = FlagMap.lookup(Symbol); + + if (Flags & EHGlobal) + EmitSymbolAttribute(EHSymbol, MCSA_Global); + if (Flags & EHWeakDefinition) + EmitSymbolAttribute(EHSymbol, MCSA_WeakDefinition); + if (Flags & EHPrivateExtern) + EmitSymbolAttribute(EHSymbol, MCSA_PrivateExtern); +} + +void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + MCStreamer::EmitLabel(Symbol); + + OS << *Symbol << MAI->getLabelSuffix(); + EmitEOL(); +} + +void MCAsmStreamer::EmitDebugLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + MCStreamer::EmitDebugLabel(Symbol); + + OS << *Symbol << MAI->getDebugLabelSuffix(); + 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 << '"'; + } + OS << "\n"; +} + +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(); +} + +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; + EmitEOL(); +} + +void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + OS << *Symbol << " = " << *Value; + EmitEOL(); + + // FIXME: Lift context changes into super class. + Symbol->setVariableValue(Value); +} + +void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + OS << ".weakref " << *Alias << ", " << *Symbol; + EmitEOL(); +} + +void MCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label, + unsigned PointerSize) { + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); +} + +void MCAsmStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label) { + EmitIntValue(dwarf::DW_CFA_advance_loc4, 1); + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + AddrDelta = ForceExpAbs(AddrDelta); + EmitValue(AddrDelta, 4); +} + + +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 << ',' + << ((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 << "no_type"; break; + case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break; + } + EmitEOL(); + return true; + case MCSA_Global: // .globl/.global + OS << MAI->getGlobalDirective(); + FlagMap[Symbol] |= EHGlobal; + 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: OS << "\t.no_dead_strip\t"; break; + case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break; + case MCSA_PrivateExtern: + OS << "\t.private_extern\t"; + FlagMap[Symbol] |= EHPrivateExtern; + break; + case MCSA_Protected: OS << "\t.protected\t"; break; + case MCSA_Reference: OS << "\t.reference\t"; break; + case MCSA_Weak: OS << "\t.weak\t"; break; + case MCSA_WeakDefinition: + OS << "\t.weak_definition\t"; + FlagMap[Symbol] |= EHWeakDefinition; + break; + // .weak_reference + case MCSA_WeakReference: OS << MAI->getWeakRefDirective(); break; + case MCSA_WeakDefAutoPrivate: OS << "\t.weak_def_can_be_hidden\t"; break; + } + + OS << *Symbol; + EmitEOL(); + + return true; +} + +void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + OS << ".desc" << ' ' << *Symbol << ',' << DescValue; + EmitEOL(); +} + +void MCAsmStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { + OS << "\t.def\t " << *Symbol << ';'; + 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::EmitCOFFSecRel32(MCSymbol const *Symbol) { + OS << "\t.secrel32\t" << *Symbol << '\n'; + EmitEOL(); +} + +void MCAsmStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + assert(MAI->hasDotTypeDotSizeDirective()); + OS << "\t.size\t" << *Symbol << ", " << *Value << '\n'; +} + +void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + // Common symbols do not belong to any actual section. + AssignSection(Symbol, NULL); + + OS << "\t.comm\t" << *Symbol << ',' << Size; + if (ByteAlignment != 0) { + if (MAI->getCOMMDirectiveAlignmentIsInBytes()) + OS << ',' << ByteAlignment; + else + OS << ',' << Log2_32(ByteAlignment); + } + EmitEOL(); +} + +/// EmitLocalCommonSymbol - Emit a local common (.lcomm) symbol. +/// +/// @param Symbol - The common symbol to emit. +/// @param Size - The size of the common symbol. +void MCAsmStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlign) { + // Common symbols do not belong to any actual section. + AssignSection(Symbol, NULL); + + OS << "\t.lcomm\t" << *Symbol << ',' << 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(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + if (Symbol) + AssignSection(Symbol, Section); + + // Note: a .zerofill directive does not switch sections. + OS << ".zerofill "; + + // This is a mach-o specific directive. + const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); + OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); + + if (Symbol != NULL) { + OS << ',' << *Symbol << ',' << 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(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + AssignSection(Symbol, Section); + + assert(Symbol != NULL && "Symbol shouldn't be NULL!"); + // Instead of using the Section we'll just use the shortcut. + // This is a mach-o specific directive and section. + OS << ".tbss " << *Symbol << ", " << 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(getCurrentSection().first && + "Cannot emit contents before setting section!"); + if (Data.empty()) return; + + if (Data.size() == 1) { + OS << MAI->getData8bitsDirective(); + OS << (unsigned)(unsigned char)Data[0]; + 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::EmitIntValue(uint64_t Value, unsigned Size) { + EmitValue(MCConstantExpr::Create(Value, getContext()), Size); +} + +void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size) { + assert(getCurrentSection().first && + "Cannot emit contents before setting section!"); + const char *Directive = 0; + 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(); + // If the target doesn't support 64-bit data, emit as two 32-bit halves. + if (Directive) break; + int64_t IntValue; + if (!Value->EvaluateAsAbsolute(IntValue)) + report_fatal_error("Don't know how to emit this value."); + if (MAI->isLittleEndian()) { + EmitIntValue((uint32_t)(IntValue >> 0 ), 4); + EmitIntValue((uint32_t)(IntValue >> 32), 4); + } else { + EmitIntValue((uint32_t)(IntValue >> 32), 4); + EmitIntValue((uint32_t)(IntValue >> 0 ), 4); + } + return; + } + + assert(Directive && "Invalid size for machine code value!"); + OS << Directive << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue)) { + EmitULEB128IntValue(IntValue); + return; + } + assert(MAI->hasLEB128() && "Cannot print a .uleb"); + OS << ".uleb128 " << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue)) { + EmitSLEB128IntValue(IntValue); + return; + } + assert(MAI->hasLEB128() && "Cannot print a .sleb"); + OS << ".sleb128 " << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitGPRel64Value(const MCExpr *Value) { + assert(MAI->getGPRel64Directive() != 0); + OS << MAI->getGPRel64Directive() << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { + assert(MAI->getGPRel32Directive() != 0); + OS << MAI->getGPRel32Directive() << *Value; + EmitEOL(); +} + + +/// EmitFill - Emit NumBytes bytes worth of the value specified by +/// FillValue. This implements directives such as '.space'. +void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) { + if (NumBytes == 0) return; + + if (const char *ZeroDirective = MAI->getZeroDirective()) { + OS << ZeroDirective << NumBytes; + if (FillValue != 0) + OS << ',' << (int)FillValue; + EmitEOL(); + return; + } + + // Emit a byte at a time. + MCStreamer::EmitFill(NumBytes, FillValue); +} + +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 << MAI->getAlignDirective(); break; + // FIXME: use MAI for this! + case 2: OS << ".p2alignw "; break; + case 4: OS << ".p2alignl "; break; + case 8: llvm_unreachable("Unsupported alignment size!"); + } + + if (MAI->getAlignmentIsInBytes()) + OS << ByteAlignment; + else + 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); +} + +bool MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + // FIXME: Verify that Offset is associated with the current section. + OS << ".org " << *Offset << ", " << (unsigned) Value; + EmitEOL(); + return false; +} + + +void MCAsmStreamer::EmitFileDirective(StringRef Filename) { + assert(MAI->hasSingleParameterDotFile()); + OS << "\t.file\t"; + PrintQuotedString(Filename, OS); + EmitEOL(); +} + +bool MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, unsigned CUID) { + if (!UseDwarfDirectory && !Directory.empty()) { + if (sys::path::is_absolute(Filename)) + return EmitDwarfFileDirective(FileNo, "", Filename, CUID); + + SmallString<128> FullPathName = Directory; + sys::path::append(FullPathName, Filename); + return EmitDwarfFileDirective(FileNo, "", FullPathName, CUID); + } + + if (UseLoc) { + OS << "\t.file\t" << FileNo << ' '; + if (!Directory.empty()) { + PrintQuotedString(Directory, OS); + OS << ' '; + } + PrintQuotedString(Filename, OS); + EmitEOL(); + // All .file will belong to a single CUID. + CUID = 0; + } + return this->MCStreamer::EmitDwarfFileDirective(FileNo, Directory, Filename, + CUID); +} + +void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, + unsigned Discriminator, + StringRef FileName) { + this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, + Isa, Discriminator, FileName); + if (!UseLoc) + return; + + OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; + 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(); +} + +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); + + if (!UseCFI) + return; + + 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) { + if (!UseCFI) { + RecordProcStart(Frame); + return; + } + + OS << "\t.cfi_startproc"; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { + if (!UseCFI) { + RecordProcEnd(Frame); + return; + } + + // Put a dummy non-null value in Frame.End to mark that this frame has been + // closed. + Frame.End = (MCSymbol *) 1; + + OS << "\t.cfi_endproc"; + EmitEOL(); +} + +void MCAsmStreamer::EmitRegisterName(int64_t Register) { + if (InstPrinter && !MAI->useDwarfRegNumForCFI()) { + const MCRegisterInfo *MRI = getContext().getRegisterInfo(); + unsigned LLVMRegister = MRI->getLLVMRegNum(Register, true); + InstPrinter->printRegName(OS, LLVMRegister); + } else { + OS << Register; + } +} + +void MCAsmStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { + MCStreamer::EmitCFIDefCfa(Register, Offset); + + if (!UseCFI) + return; + + OS << "\t.cfi_def_cfa "; + EmitRegisterName(Register); + OS << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) { + MCStreamer::EmitCFIDefCfaOffset(Offset); + + if (!UseCFI) + return; + + OS << "\t.cfi_def_cfa_offset " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) { + MCStreamer::EmitCFIDefCfaRegister(Register); + + if (!UseCFI) + return; + + OS << "\t.cfi_def_cfa_register "; + EmitRegisterName(Register); + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { + this->MCStreamer::EmitCFIOffset(Register, Offset); + + if (!UseCFI) + return; + + OS << "\t.cfi_offset "; + EmitRegisterName(Register); + OS << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding) { + MCStreamer::EmitCFIPersonality(Sym, Encoding); + + if (!UseCFI) + return; + + OS << "\t.cfi_personality " << Encoding << ", " << *Sym; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { + MCStreamer::EmitCFILsda(Sym, Encoding); + + if (!UseCFI) + return; + + OS << "\t.cfi_lsda " << Encoding << ", " << *Sym; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIRememberState() { + MCStreamer::EmitCFIRememberState(); + + if (!UseCFI) + return; + + OS << "\t.cfi_remember_state"; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIRestoreState() { + MCStreamer::EmitCFIRestoreState(); + + if (!UseCFI) + return; + + OS << "\t.cfi_restore_state"; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFISameValue(int64_t Register) { + MCStreamer::EmitCFISameValue(Register); + + if (!UseCFI) + return; + + OS << "\t.cfi_same_value "; + EmitRegisterName(Register); + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) { + MCStreamer::EmitCFIRelOffset(Register, Offset); + + if (!UseCFI) + return; + + OS << "\t.cfi_rel_offset "; + EmitRegisterName(Register); + OS << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) { + MCStreamer::EmitCFIAdjustCfaOffset(Adjustment); + + if (!UseCFI) + return; + + OS << "\t.cfi_adjust_cfa_offset " << Adjustment; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFISignalFrame() { + MCStreamer::EmitCFISignalFrame(); + + if (!UseCFI) + return; + + OS << "\t.cfi_signal_frame"; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIUndefined(int64_t Register) { + MCStreamer::EmitCFIUndefined(Register); + + if (!UseCFI) + return; + + OS << "\t.cfi_undefined " << Register; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) { + MCStreamer::EmitCFIRegister(Register1, Register2); + + if (!UseCFI) + return; + + OS << "\t.cfi_register " << Register1 << ", " << Register2; + EmitEOL(); +} + +void MCAsmStreamer::EmitCFIWindowSave() { + MCStreamer::EmitCFIWindowSave(); + + if (!UseCFI) + return; + + OS << "\t.cfi_window_save"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHStartProc(const MCSymbol *Symbol) { + MCStreamer::EmitWin64EHStartProc(Symbol); + + OS << ".seh_proc " << *Symbol; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHEndProc() { + MCStreamer::EmitWin64EHEndProc(); + + OS << "\t.seh_endproc"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHStartChained() { + MCStreamer::EmitWin64EHStartChained(); + + OS << "\t.seh_startchained"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHEndChained() { + MCStreamer::EmitWin64EHEndChained(); + + OS << "\t.seh_endchained"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHHandler(const MCSymbol *Sym, bool Unwind, + bool Except) { + MCStreamer::EmitWin64EHHandler(Sym, Unwind, Except); + + OS << "\t.seh_handler " << *Sym; + if (Unwind) + OS << ", @unwind"; + if (Except) + OS << ", @except"; + EmitEOL(); +} + +static const MCSection *getWin64EHTableSection(StringRef suffix, + MCContext &context) { + // FIXME: This doesn't belong in MCObjectFileInfo. However, + /// this duplicate code in MCWin64EH.cpp. + if (suffix == "") + return context.getObjectFileInfo()->getXDataSection(); + return context.getCOFFSection((".xdata"+suffix).str(), + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); +} + +void MCAsmStreamer::EmitWin64EHHandlerData() { + MCStreamer::EmitWin64EHHandlerData(); + + // 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. + MCWin64EHUnwindInfo *CurFrame = getCurrentW64UnwindInfo(); + StringRef suffix=MCWin64EHUnwindEmitter::GetSectionSuffix(CurFrame->Function); + const MCSection *xdataSect = getWin64EHTableSection(suffix, getContext()); + if (xdataSect) + SwitchSectionNoChange(xdataSect); + + OS << "\t.seh_handlerdata"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHPushReg(unsigned Register) { + MCStreamer::EmitWin64EHPushReg(Register); + + OS << "\t.seh_pushreg " << Register; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHSetFrame(unsigned Register, unsigned Offset) { + MCStreamer::EmitWin64EHSetFrame(Register, Offset); + + OS << "\t.seh_setframe " << Register << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHAllocStack(unsigned Size) { + MCStreamer::EmitWin64EHAllocStack(Size); + + OS << "\t.seh_stackalloc " << Size; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHSaveReg(unsigned Register, unsigned Offset) { + MCStreamer::EmitWin64EHSaveReg(Register, Offset); + + OS << "\t.seh_savereg " << Register << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHSaveXMM(unsigned Register, unsigned Offset) { + MCStreamer::EmitWin64EHSaveXMM(Register, Offset); + + OS << "\t.seh_savexmm " << Register << ", " << Offset; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHPushFrame(bool Code) { + MCStreamer::EmitWin64EHPushFrame(Code); + + OS << "\t.seh_pushframe"; + if (Code) + OS << " @code"; + EmitEOL(); +} + +void MCAsmStreamer::EmitWin64EHEndProlog(void) { + MCStreamer::EmitWin64EHEndProlog(); + + OS << "\t.seh_endprologue"; + EmitEOL(); +} + +void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { + raw_ostream &OS = GetCommentOS(); + SmallString<256> Code; + SmallVector<MCFixup, 4> Fixups; + raw_svector_ostream VecOS(Code); + Emitter->EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // 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 = AsmBackend->getFixupKindInfo(F.getKind()); + for (unsigned j = 0; j != Info.TargetSize; ++j) { + unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; + assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); + FixupMap[Index] = 1 + i; + } + } + + // FIXME: Note the fixup comments for Thumb2 are completely bogus since the + // high order halfword of a 32-bit Thumb2 instruction is emitted first. + OS << "encoding: ["; + for (unsigned i = 0, e = Code.size(); i != e; ++i) { + if (i) + OS << ','; + + // See if all bits are the same map entry. + uint8_t MapEntry = FixupMap[i * 8 + 0]; + for (unsigned j = 1; j != 8; ++j) { + if (FixupMap[i * 8 + j] == MapEntry) + continue; + + MapEntry = uint8_t(~0U); + break; + } + + if (MapEntry != uint8_t(~0U)) { + if (MapEntry == 0) { + OS << format("0x%02x", uint8_t(Code[i])); + } else { + if (Code[i]) { + // FIXME: Some of the 8 bits require fix up. + OS << format("0x%02x", uint8_t(Code[i])) << '\'' + << char('A' + MapEntry - 1) << '\''; + } else + OS << char('A' + MapEntry - 1); + } + } else { + // Otherwise, write out in binary. + OS << "0b"; + for (unsigned j = 8; j--;) { + unsigned Bit = (Code[i] >> j) & 1; + + unsigned FixupBit; + if (MAI->isLittleEndian()) + FixupBit = i * 8 + j; + else + FixupBit = i * 8 + (7-j); + + if (uint8_t MapEntry = FixupMap[FixupBit]) { + assert(Bit == 0 && "Encoder wrote into fixed up bit!"); + OS << char('A' + MapEntry - 1); + } else + OS << Bit; + } + } + } + OS << "]\n"; + + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + MCFixup &F = Fixups[i]; + const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); + OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() + << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; + } +} + +void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { + assert(getCurrentSection().first && + "Cannot emit contents before setting section!"); + + // Show the encoding in a comment if we have a code emitter. + if (Emitter) + AddEncodingComment(Inst); + + // Show the MCInst if enabled. + if (ShowInst) { + Inst.dump_pretty(GetCommentOS(), MAI, InstPrinter.get(), "\n "); + GetCommentOS() << "\n"; + } + + // If we have an AsmPrinter, use that to print, otherwise print the MCInst. + if (InstPrinter) + InstPrinter->printInst(&Inst, OS, ""); + else + Inst.print(OS, MAI); + 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(); +} + +/// 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() { + // FIXME: This header is duplicated with MCObjectStreamer + // Dump out the dwarf file & directory tables and line tables. + const MCSymbol *LineSectionSymbol = NULL; + if (getContext().hasDwarfFiles() && !UseLoc) + LineSectionSymbol = MCDwarfFileTable::Emit(this); + + // If we are generating dwarf for assembly source files dump out the sections. + if (getContext().getGenDwarfForAssembly()) + MCGenDwarfInfo::Emit(this, LineSectionSymbol); + + if (!UseCFI) + EmitFrames(AsmBackend.get(), false); +} + +MCStreamer *llvm::createAsmStreamer(MCContext &Context, + MCTargetStreamer *TargetStreamer, + formatted_raw_ostream &OS, + bool isVerboseAsm, bool useLoc, bool useCFI, + bool useDwarfDirectory, MCInstPrinter *IP, + MCCodeEmitter *CE, MCAsmBackend *MAB, + bool ShowInst) { + return new MCAsmStreamer(Context, TargetStreamer, OS, isVerboseAsm, useLoc, + useCFI, useDwarfDirectory, IP, CE, MAB, ShowInst); +} diff --git a/contrib/llvm/lib/MC/MCAssembler.cpp b/contrib/llvm/lib/MC/MCAssembler.cpp new file mode 100644 index 000000000000..68111f187d38 --- /dev/null +++ b/contrib/llvm/lib/MC/MCAssembler.cpp @@ -0,0 +1,1187 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "assembler" +#include "llvm/MC/MCAssembler.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +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"); +} +} + +// 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. + +/* *** */ + +MCAsmLayout::MCAsmLayout(MCAssembler &Asm) + : Assembler(Asm), LastValidFragment() + { + // Compute the section layout order. Virtual sections must go last. + for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) + if (!it->getSection().isVirtualSection()) + SectionOrder.push_back(&*it); + for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) + if (it->getSection().isVirtualSection()) + SectionOrder.push_back(&*it); +} + +bool MCAsmLayout::isFragmentValid(const MCFragment *F) const { + const MCSectionData &SD = *F->getParent(); + const MCFragment *LastValid = LastValidFragment.lookup(&SD); + if (!LastValid) + return false; + assert(LastValid->getParent() == F->getParent()); + 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). + const MCSectionData &SD = *F->getParent(); + LastValidFragment[&SD] = F->getPrevNode(); +} + +void MCAsmLayout::ensureValid(const MCFragment *F) const { + MCSectionData &SD = *F->getParent(); + + MCFragment *Cur = LastValidFragment[&SD]; + if (!Cur) + Cur = &*SD.begin(); + else + Cur = Cur->getNextNode(); + + // Advance the layout position until the fragment is valid. + while (!isFragmentValid(F)) { + assert(Cur && "Layout bookkeeping error"); + const_cast<MCAsmLayout*>(this)->layoutFragment(Cur); + Cur = Cur->getNextNode(); + } +} + +uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const { + ensureValid(F); + assert(F->Offset != ~UINT64_C(0) && "Address not set!"); + return F->Offset; +} + +uint64_t MCAsmLayout::getSymbolOffset(const MCSymbolData *SD) const { + const MCSymbol &S = SD->getSymbol(); + + // If this is a variable, then recursively evaluate now. + if (S.isVariable()) { + MCValue Target; + if (!S.getVariableValue()->EvaluateAsRelocatable(Target, *this)) + 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 Offset = Target.getConstant(); + if (Target.getSymA()) + Offset += getSymbolOffset(&Assembler.getSymbolData( + Target.getSymA()->getSymbol())); + if (Target.getSymB()) + Offset -= getSymbolOffset(&Assembler.getSymbolData( + Target.getSymB()->getSymbol())); + return Offset; + } + + assert(SD->getFragment() && "Invalid getOffset() on undefined symbol!"); + return getFragmentOffset(SD->getFragment()) + SD->getOffset(); +} + +uint64_t MCAsmLayout::getSectionAddressSize(const MCSectionData *SD) const { + // The size is the last fragment's end offset. + const MCFragment &F = SD->getFragmentList().back(); + return getFragmentOffset(&F) + getAssembler().computeFragmentSize(*this, F); +} + +uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const { + // Virtual sections have no file size. + if (SD->getSection().isVirtualSection()) + return 0; + + // Otherwise, the file size is the same as the address space size. + return getSectionAddressSize(SD); +} + +uint64_t MCAsmLayout::computeBundlePadding(const MCFragment *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 (EndOfFragment > BundleSize) + return BundleSize - OffsetInBundle; + else + return 0; +} + +/* *** */ + +MCFragment::MCFragment() : Kind(FragmentType(~0)) { +} + +MCFragment::~MCFragment() { +} + +MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent) + : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)) +{ + if (Parent) + Parent->getFragmentList().push_back(this); +} + +/* *** */ + +MCEncodedFragment::~MCEncodedFragment() { +} + +/* *** */ + +MCEncodedFragmentWithFixups::~MCEncodedFragmentWithFixups() { +} + +/* *** */ + +MCSectionData::MCSectionData() : Section(0) {} + +MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) + : Section(&_Section), + Ordinal(~UINT32_C(0)), + Alignment(1), + BundleLockState(NotBundleLocked), BundleGroupBeforeFirstInst(false), + HasInstructions(false) +{ + if (A) + A->getSectionList().push_back(this); +} + +MCSectionData::iterator +MCSectionData::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 *)0)); + 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; + 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; +} + +/* *** */ + +MCSymbolData::MCSymbolData() : Symbol(0) {} + +MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, + uint64_t _Offset, MCAssembler *A) + : Symbol(&_Symbol), Fragment(_Fragment), Offset(_Offset), + IsExternal(false), IsPrivateExtern(false), + CommonSize(0), SymbolSize(0), CommonAlign(0), + Flags(0), Index(0) +{ + if (A) + A->getSymbolList().push_back(this); +} + +/* *** */ + +MCAssembler::MCAssembler(MCContext &Context_, MCAsmBackend &Backend_, + MCCodeEmitter &Emitter_, MCObjectWriter &Writer_, + raw_ostream &OS_) + : Context(Context_), Backend(Backend_), Emitter(Emitter_), Writer(Writer_), + OS(OS_), BundleAlignSize(0), RelaxAll(false), NoExecStack(false), + SubsectionsViaSymbols(false), ELFHeaderEFlags(0) { +} + +MCAssembler::~MCAssembler() { +} + +void MCAssembler::reset() { + Sections.clear(); + Symbols.clear(); + SectionMap.clear(); + SymbolMap.clear(); + IndirectSymbols.clear(); + DataRegions.clear(); + ThumbFuncs.clear(); + RelaxAll = false; + NoExecStack = false; + SubsectionsViaSymbols = false; + ELFHeaderEFlags = 0; + + // reset objects owned by us + getBackend().reset(); + getEmitter().reset(); + getWriter().reset(); +} + +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; + + // Otherwise, check if the section requires symbols even for temporary labels. + return getBackend().doesSectionRequireSymbols(Symbol.getSection()); +} + +const MCSymbolData *MCAssembler::getAtom(const MCSymbolData *SD) const { + // Linker visible symbols define atoms. + if (isSymbolLinkerVisible(SD->getSymbol())) + return SD; + + // Absolute and undefined symbols have no defining atom. + if (!SD->getFragment()) + return 0; + + // Non-linker visible symbols in sections which can't be atomized have no + // defining atom. + if (!getBackend().isSectionAtomizable( + SD->getFragment()->getParent()->getSection())) + return 0; + + // Otherwise, return the atom for the containing fragment. + return SD->getFragment()->getAtom(); +} + +bool MCAssembler::evaluateFixup(const MCAsmLayout &Layout, + const MCFixup &Fixup, const MCFragment *DF, + MCValue &Target, uint64_t &Value) const { + ++stats::evaluateFixup; + + if (!Fixup.getValue()->EvaluateAsRelocatable(Target, Layout)) + getContext().FatalError(Fixup.getLoc(), "expected relocatable expression"); + + bool IsPCRel = Backend.getFixupKindInfo( + Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; + + bool IsResolved; + 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.AliasedSymbol().isUndefined()) { + IsResolved = false; + } else { + const MCSymbolData &DataA = getSymbolData(SA); + IsResolved = + getWriter().IsSymbolRefDifferenceFullyResolvedImpl(*this, DataA, + *DF, false, true); + } + } + } else { + IsResolved = Target.isAbsolute(); + } + + Value = Target.getConstant(); + + if (const MCSymbolRefExpr *A = Target.getSymA()) { + const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value += Layout.getSymbolOffset(&getSymbolData(Sym)); + } + if (const MCSymbolRefExpr *B = Target.getSymB()) { + const MCSymbol &Sym = B->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value -= Layout.getSymbolOffset(&getSymbolData(Sym)); + } + + + bool ShouldAlignPC = Backend.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 adjust the fixup value if necessary, including whether + // we need a relocation. + Backend.processFixupValue(*this, Layout, Fixup, DF, Target, Value, + IsResolved); + + return IsResolved; +} + +uint64_t MCAssembler::computeFragmentSize(const MCAsmLayout &Layout, + const MCFragment &F) const { + switch (F.getKind()) { + case MCFragment::FT_Data: + case MCFragment::FT_Relaxable: + case MCFragment::FT_CompactEncodedInst: + return cast<MCEncodedFragment>(F).getContents().size(); + case MCFragment::FT_Fill: + return cast<MCFillFragment>(F).getSize(); + + case MCFragment::FT_LEB: + return cast<MCLEBFragment>(F).getContents().size(); + + 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); + int64_t TargetLocation; + if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, Layout)) + report_fatal_error("expected assembly-time absolute expression"); + + // FIXME: We need a way to communicate this error. + uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); + int64_t Size = TargetLocation - FragmentOffset; + if (Size < 0 || Size >= 0x40000000) + report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + + "' (at offset '" + Twine(FragmentOffset) + "')"); + return Size; + } + + case MCFragment::FT_Dwarf: + return cast<MCDwarfLineAddrFragment>(F).getContents().size(); + case MCFragment::FT_DwarfFrame: + return cast<MCDwarfCallFrameFragment>(F).getContents().size(); + } + + 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. + // + if (Assembler.isBundlingEnabled() && F->hasInstructions()) { + assert(isa<MCEncodedFragment>(F) && + "Only MCEncodedFragment implementations have instructions"); + uint64_t FSize = Assembler.computeFragmentSize(*this, *F); + + if (FSize > Assembler.getBundleAlignSize()) + report_fatal_error("Fragment can't be larger than a bundle size"); + + uint64_t RequiredBundlePadding = computeBundlePadding(F, F->Offset, FSize); + if (RequiredBundlePadding > UINT8_MAX) + report_fatal_error("Padding cannot exceed 255 bytes"); + F->setBundlePadding(static_cast<uint8_t>(RequiredBundlePadding)); + F->Offset += RequiredBundlePadding; + } +} + +/// \brief Write the contents of a fragment to the given object writer. Expects +/// a MCEncodedFragment. +static void writeFragmentContents(const MCFragment &F, MCObjectWriter *OW) { + const MCEncodedFragment &EF = cast<MCEncodedFragment>(F); + OW->WriteBytes(EF.getContents()); +} + +/// \brief Write the fragment \p F to the output file. +static void writeFragment(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment &F) { + MCObjectWriter *OW = &Asm.getWriter(); + + // FIXME: Embed in fragments instead? + uint64_t FragmentSize = Asm.computeFragmentSize(Layout, F); + + // Should NOP padding be written out before this fragment? + unsigned BundlePadding = F.getBundlePadding(); + if (BundlePadding > 0) { + assert(Asm.isBundlingEnabled() && + "Writing bundle padding with disabled bundling"); + assert(F.hasInstructions() && + "Writing bundle padding for a fragment without instructions"); + + unsigned TotalLength = BundlePadding + static_cast<unsigned>(FragmentSize); + if (F.alignToBundleEnd() && TotalLength > Asm.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 - Asm.getBundleAlignSize(); + if (!Asm.getBackend().writeNopData(DistanceToBoundary, OW)) + report_fatal_error("unable to write NOP sequence of " + + Twine(DistanceToBoundary) + " bytes"); + BundlePadding -= DistanceToBoundary; + } + if (!Asm.getBackend().writeNopData(BundlePadding, OW)) + report_fatal_error("unable to write NOP sequence of " + + Twine(BundlePadding) + " bytes"); + } + + // This variable (and its dummy usage) is to participate in the assert at + // the end of the function. + uint64_t Start = OW->getStream().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(Count, OW)) + 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: OW->Write8 (uint8_t (AF.getValue())); break; + case 2: OW->Write16(uint16_t(AF.getValue())); break; + case 4: OW->Write32(uint32_t(AF.getValue())); break; + case 8: OW->Write64(uint64_t(AF.getValue())); break; + } + } + break; + } + + case MCFragment::FT_Data: + ++stats::EmittedDataFragments; + writeFragmentContents(F, OW); + break; + + case MCFragment::FT_Relaxable: + ++stats::EmittedRelaxableFragments; + writeFragmentContents(F, OW); + break; + + case MCFragment::FT_CompactEncodedInst: + ++stats::EmittedCompactEncodedInstFragments; + writeFragmentContents(F, OW); + break; + + case MCFragment::FT_Fill: { + ++stats::EmittedFillFragments; + const MCFillFragment &FF = cast<MCFillFragment>(F); + + assert(FF.getValueSize() && "Invalid virtual align in concrete fragment!"); + + for (uint64_t i = 0, e = FF.getSize() / FF.getValueSize(); i != e; ++i) { + switch (FF.getValueSize()) { + default: llvm_unreachable("Invalid size!"); + case 1: OW->Write8 (uint8_t (FF.getValue())); break; + case 2: OW->Write16(uint16_t(FF.getValue())); break; + case 4: OW->Write32(uint32_t(FF.getValue())); break; + case 8: OW->Write64(uint64_t(FF.getValue())); break; + } + } + break; + } + + case MCFragment::FT_LEB: { + const MCLEBFragment &LF = cast<MCLEBFragment>(F); + OW->WriteBytes(LF.getContents().str()); + break; + } + + case MCFragment::FT_Org: { + ++stats::EmittedOrgFragments; + const MCOrgFragment &OF = cast<MCOrgFragment>(F); + + for (uint64_t i = 0, e = FragmentSize; i != e; ++i) + OW->Write8(uint8_t(OF.getValue())); + + break; + } + + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); + OW->WriteBytes(OF.getContents().str()); + break; + } + case MCFragment::FT_DwarfFrame: { + const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F); + OW->WriteBytes(CF.getContents().str()); + break; + } + } + + assert(OW->getStream().tell() - Start == FragmentSize && + "The stream should advance by fragment size"); +} + +void MCAssembler::writeSectionData(const MCSectionData *SD, + const MCAsmLayout &Layout) const { + // Ignore virtual sections. + if (SD->getSection().isVirtualSection()) { + assert(Layout.getSectionFileSize(SD) == 0 && "Invalid size for section!"); + + // Check that contents are only things legal inside a virtual section. + for (MCSectionData::const_iterator it = SD->begin(), + ie = SD->end(); it != ie; ++it) { + switch (it->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>(*it); + assert(DF.fixup_begin() == DF.fixup_end() && + "Cannot have fixups in virtual section!"); + for (unsigned i = 0, e = DF.getContents().size(); i != e; ++i) + assert(DF.getContents()[i] == 0 && + "Invalid data value for 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>(it)->getValueSize() == 0 || + cast<MCAlignFragment>(it)->getValue() == 0) && + "Invalid align in virtual section!"); + break; + case MCFragment::FT_Fill: + assert((cast<MCFillFragment>(it)->getValueSize() == 0 || + cast<MCFillFragment>(it)->getValue() == 0) && + "Invalid fill in virtual section!"); + break; + } + } + + return; + } + + uint64_t Start = getWriter().getStream().tell(); + (void)Start; + + for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); + it != ie; ++it) + writeFragment(*this, Layout, *it); + + assert(getWriter().getStream().tell() - Start == + Layout.getSectionAddressSize(SD)); +} + + +uint64_t MCAssembler::handleFixup(const MCAsmLayout &Layout, + MCFragment &F, + const MCFixup &Fixup) { + // Evaluate the fixup. + MCValue Target; + uint64_t FixedValue; + if (!evaluateFixup(Layout, Fixup, &F, Target, FixedValue)) { + // 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. + getWriter().RecordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); + } + return FixedValue; + } + +void MCAssembler::Finish() { + DEBUG_WITH_TYPE("mc-dump", { + llvm::errs() << "assembler backend - pre-layout\n--\n"; + dump(); }); + + // Create the layout object. + MCAsmLayout Layout(*this); + + // Create dummy fragments and assign section ordinals. + unsigned SectionIndex = 0; + for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { + // Create dummy fragments to eliminate any empty sections, this simplifies + // layout. + if (it->getFragmentList().empty()) + new MCDataFragment(it); + + it->setOrdinal(SectionIndex++); + } + + // Assign layout order indices to sections and fragments. + for (unsigned i = 0, e = Layout.getSectionOrder().size(); i != e; ++i) { + MCSectionData *SD = Layout.getSectionOrder()[i]; + SD->setLayoutOrder(i); + + unsigned FragmentIndex = 0; + for (MCSectionData::iterator iFrag = SD->begin(), iFragEnd = SD->end(); + iFrag != iFragEnd; ++iFrag) + iFrag->setLayoutOrder(FragmentIndex++); + } + + // Layout until everything fits. + while (layoutOnce(Layout)) + continue; + + DEBUG_WITH_TYPE("mc-dump", { + llvm::errs() << "assembler backend - post-relaxation\n--\n"; + dump(); }); + + // Finalize the layout, including fragment lowering. + finishLayout(Layout); + + DEBUG_WITH_TYPE("mc-dump", { + llvm::errs() << "assembler backend - final-layout\n--\n"; + dump(); }); + + uint64_t StartOffset = OS.tell(); + + // 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 (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { + for (MCSectionData::iterator it2 = it->begin(), + ie2 = it->end(); it2 != ie2; ++it2) { + MCEncodedFragmentWithFixups *F = + dyn_cast<MCEncodedFragmentWithFixups>(it2); + if (F) { + for (MCEncodedFragmentWithFixups::fixup_iterator it3 = F->fixup_begin(), + ie3 = F->fixup_end(); it3 != ie3; ++it3) { + MCFixup &Fixup = *it3; + uint64_t FixedValue = handleFixup(Layout, *F, Fixup); + getBackend().applyFixup(Fixup, F->getContents().data(), + F->getContents().size(), FixedValue); + } + } + } + } + + // Write the object file. + getWriter().WriteObject(*this, Layout); + + stats::ObjectBytes += OS.tell() - StartOffset; +} + +bool MCAssembler::fixupNeedsRelaxation(const MCFixup &Fixup, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const { + // If we cannot resolve the fixup value, it requires relaxation. + MCValue Target; + uint64_t Value; + if (!evaluateFixup(Layout, Fixup, DF, Target, Value)) + return true; + + return getBackend().fixupNeedsRelaxation(Fixup, Value, DF, Layout); +} + +bool MCAssembler::fragmentNeedsRelaxation(const MCRelaxableFragment *F, + const MCAsmLayout &Layout) const { + // 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())) + return false; + + for (MCRelaxableFragment::const_fixup_iterator it = F->fixup_begin(), + ie = F->fixup_end(); it != ie; ++it) + if (fixupNeedsRelaxation(*it, F, Layout)) + return true; + + return false; +} + +bool MCAssembler::relaxInstruction(MCAsmLayout &Layout, + MCRelaxableFragment &F) { + 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(), 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); + VecOS.flush(); + + // Update the fragment. + F.setInst(Relaxed); + F.getContents() = Code; + F.getFixups() = Fixups; + + return true; +} + +bool MCAssembler::relaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { + int64_t Value = 0; + uint64_t OldSize = LF.getContents().size(); + bool IsAbs = LF.getValue().EvaluateAsAbsolute(Value, Layout); + (void)IsAbs; + assert(IsAbs); + SmallString<8> &Data = LF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + if (LF.isSigned()) + encodeSLEB128(Value, OSE); + else + encodeULEB128(Value, OSE); + OSE.flush(); + return OldSize != LF.getContents().size(); +} + +bool MCAssembler::relaxDwarfLineAddr(MCAsmLayout &Layout, + MCDwarfLineAddrFragment &DF) { + MCContext &Context = Layout.getAssembler().getContext(); + int64_t AddrDelta = 0; + uint64_t OldSize = DF.getContents().size(); + bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + int64_t LineDelta; + LineDelta = DF.getLineDelta(); + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + MCDwarfLineAddr::Encode(Context, LineDelta, AddrDelta, OSE); + OSE.flush(); + return OldSize != Data.size(); +} + +bool MCAssembler::relaxDwarfCallFrameFragment(MCAsmLayout &Layout, + MCDwarfCallFrameFragment &DF) { + MCContext &Context = Layout.getAssembler().getContext(); + int64_t AddrDelta = 0; + uint64_t OldSize = DF.getContents().size(); + bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + MCDwarfFrameEmitter::EncodeAdvanceLoc(Context, AddrDelta, OSE); + OSE.flush(); + return OldSize != Data.size(); +} + +bool MCAssembler::layoutSectionOnce(MCAsmLayout &Layout, MCSectionData &SD) { + // 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 = NULL; + + // Attempt to relax all the fragments in the section. + for (MCSectionData::iterator I = SD.begin(), IE = SD.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; + } + 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) { + MCSectionData &SD = *it; + while (layoutSectionOnce(Layout, SD)) + WasRelaxed = true; + } + + return WasRelaxed; +} + +void MCAssembler::finishLayout(MCAsmLayout &Layout) { + // The layout is done. Mark every fragment as valid. + for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { + Layout.getFragmentOffset(&*Layout.getSectionOrder()[i]->rbegin()); + } +} + +// 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; +} + +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCFragment::dump() { + raw_ostream &OS = llvm::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; + } + + OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder + << " Offset:" << Offset + << " HasInstructions:" << hasInstructions() + << " BundlePadding:" << static_cast<unsigned>(getBundlePadding()) << ">"; + + 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:" << FF->getValue() << " ValueSize:" << FF->getValueSize() + << " Size:" << FF->getSize(); + 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:" << 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; + } + } + OS << ">"; +} + +void MCSectionData::dump() { + raw_ostream &OS = llvm::errs(); + + OS << "<MCSectionData"; + OS << " Alignment:" << getAlignment() + << " Fragments:[\n "; + for (iterator it = begin(), ie = end(); it != ie; ++it) { + if (it != begin()) OS << ",\n "; + it->dump(); + } + OS << "]>"; +} + +void MCSymbolData::dump() { + raw_ostream &OS = llvm::errs(); + + OS << "<MCSymbolData Symbol:" << getSymbol() + << " Fragment:" << getFragment() << " Offset:" << getOffset() + << " Flags:" << getFlags() << " Index:" << getIndex(); + if (isCommon()) + OS << " (common, size:" << getCommonSize() + << " align: " << getCommonAlignment() << ")"; + if (isExternal()) + OS << " (external)"; + if (isPrivateExtern()) + OS << " (private extern)"; + OS << ">"; +} + +void MCAssembler::dump() { + raw_ostream &OS = llvm::errs(); + + OS << "<MCAssembler\n"; + OS << " Sections:[\n "; + for (iterator it = begin(), ie = end(); it != ie; ++it) { + if (it != begin()) OS << ",\n "; + it->dump(); + } + OS << "],\n"; + OS << " Symbols:["; + + for (symbol_iterator it = symbol_begin(), ie = symbol_end(); it != ie; ++it) { + if (it != symbol_begin()) OS << ",\n "; + it->dump(); + } + OS << "]>\n"; +} +#endif + +// anchors for MC*Fragment vtables +void MCEncodedFragment::anchor() { } +void MCEncodedFragmentWithFixups::anchor() { } +void MCDataFragment::anchor() { } +void MCCompactEncodedInstFragment::anchor() { } +void MCRelaxableFragment::anchor() { } +void MCAlignFragment::anchor() { } +void MCFillFragment::anchor() { } +void MCOrgFragment::anchor() { } +void MCLEBFragment::anchor() { } +void MCDwarfLineAddrFragment::anchor() { } +void MCDwarfCallFrameFragment::anchor() { } diff --git a/contrib/llvm/lib/MC/MCAtom.cpp b/contrib/llvm/lib/MC/MCAtom.cpp new file mode 100644 index 000000000000..bc353cdcf65d --- /dev/null +++ b/contrib/llvm/lib/MC/MCAtom.cpp @@ -0,0 +1,114 @@ +//===- lib/MC/MCAtom.cpp - MCAtom 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/MCAtom.h" +#include "llvm/MC/MCModule.h" +#include "llvm/Support/ErrorHandling.h" +#include <iterator> + +using namespace llvm; + +// Pin the vtable to this file. +void MCAtom::anchor() {} + +void MCAtom::remap(uint64_t NewBegin, uint64_t NewEnd) { + Parent->remap(this, NewBegin, NewEnd); +} + +void MCAtom::remapForTruncate(uint64_t TruncPt) { + assert((TruncPt >= Begin && TruncPt < End) && + "Truncation point not contained in atom!"); + remap(Begin, TruncPt); +} + +void MCAtom::remapForSplit(uint64_t SplitPt, + uint64_t &LBegin, uint64_t &LEnd, + uint64_t &RBegin, uint64_t &REnd) { + assert((SplitPt > Begin && SplitPt <= End) && + "Splitting at point not contained in atom!"); + + // Compute the new begin/end points. + LBegin = Begin; + LEnd = SplitPt - 1; + RBegin = SplitPt; + REnd = End; + + // Remap this atom to become the lower of the two new ones. + remap(LBegin, LEnd); +} + +// MCDataAtom + +void MCDataAtom::addData(const MCData &D) { + Data.push_back(D); + if (Data.size() > End + 1 - Begin) + remap(Begin, End + 1); +} + +void MCDataAtom::truncate(uint64_t TruncPt) { + remapForTruncate(TruncPt); + + Data.resize(TruncPt - Begin + 1); +} + +MCDataAtom *MCDataAtom::split(uint64_t SplitPt) { + uint64_t LBegin, LEnd, RBegin, REnd; + remapForSplit(SplitPt, LBegin, LEnd, RBegin, REnd); + + MCDataAtom *RightAtom = Parent->createDataAtom(RBegin, REnd); + RightAtom->setName(getName()); + + std::vector<MCData>::iterator I = Data.begin() + (RBegin - LBegin); + assert(I != Data.end() && "Split point not found in range!"); + + std::copy(I, Data.end(), std::back_inserter(RightAtom->Data)); + Data.erase(I, Data.end()); + return RightAtom; +} + +// MCTextAtom + +void MCTextAtom::addInst(const MCInst &I, uint64_t Size) { + if (NextInstAddress + Size - 1 > End) + remap(Begin, NextInstAddress + Size - 1); + Insts.push_back(MCDecodedInst(I, NextInstAddress, Size)); + NextInstAddress += Size; +} + +void MCTextAtom::truncate(uint64_t TruncPt) { + remapForTruncate(TruncPt); + + InstListTy::iterator I = Insts.begin(); + while (I != Insts.end() && I->Address <= TruncPt) ++I; + + assert(I != Insts.end() && "Truncation point not found in disassembly!"); + assert(I->Address == TruncPt + 1 && + "Truncation point does not fall on instruction boundary"); + + Insts.erase(I, Insts.end()); +} + +MCTextAtom *MCTextAtom::split(uint64_t SplitPt) { + uint64_t LBegin, LEnd, RBegin, REnd; + remapForSplit(SplitPt, LBegin, LEnd, RBegin, REnd); + + MCTextAtom *RightAtom = Parent->createTextAtom(RBegin, REnd); + RightAtom->setName(getName()); + + InstListTy::iterator I = Insts.begin(); + while (I != Insts.end() && I->Address < SplitPt) ++I; + assert(I != Insts.end() && "Split point not found in disassembly!"); + assert(I->Address == SplitPt && + "Split point does not fall on instruction boundary!"); + + std::copy(I, Insts.end(), std::back_inserter(RightAtom->Insts)); + Insts.erase(I, Insts.end()); + Parent->splitBasicBlocksForAtom(this, RightAtom); + return RightAtom; +} diff --git a/contrib/llvm/lib/MC/MCCodeEmitter.cpp b/contrib/llvm/lib/MC/MCCodeEmitter.cpp new file mode 100644 index 000000000000..c122763b2fe5 --- /dev/null +++ b/contrib/llvm/lib/MC/MCCodeEmitter.cpp @@ -0,0 +1,18 @@ +//===-- 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() { +} + +MCCodeEmitter::~MCCodeEmitter() { +} diff --git a/contrib/llvm/lib/MC/MCCodeGenInfo.cpp b/contrib/llvm/lib/MC/MCCodeGenInfo.cpp new file mode 100644 index 000000000000..d9dcfd0614bc --- /dev/null +++ b/contrib/llvm/lib/MC/MCCodeGenInfo.cpp @@ -0,0 +1,23 @@ +//===-- MCCodeGenInfo.cpp - Target CodeGen Info -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file tracks information about the target which can affect codegen, +// asm parsing, and asm printing. For example, relocation model. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCCodeGenInfo.h" +using namespace llvm; + +void MCCodeGenInfo::InitMCCodeGenInfo(Reloc::Model RM, CodeModel::Model CM, + CodeGenOpt::Level OL) { + RelocationModel = RM; + CMModel = CM; + OptLevel = OL; +} diff --git a/contrib/llvm/lib/MC/MCContext.cpp b/contrib/llvm/lib/MC/MCContext.cpp new file mode 100644 index 000000000000..3b45d1670d2c --- /dev/null +++ b/contrib/llvm/lib/MC/MCContext.cpp @@ -0,0 +1,426 @@ +//===- 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/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCLabel.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/SourceMgr.h" + +#include <map> + +using namespace llvm; + +typedef std::pair<std::string, std::string> SectionGroupPair; + +typedef StringMap<const MCSectionMachO*> MachOUniqueMapTy; +typedef std::map<SectionGroupPair, const MCSectionELF *> ELFUniqueMapTy; +typedef std::map<SectionGroupPair, const MCSectionCOFF *> COFFUniqueMapTy; + +MCContext::MCContext(const MCAsmInfo *mai, const MCRegisterInfo *mri, + const MCObjectFileInfo *mofi, const SourceMgr *mgr, + bool DoAutoReset) : + SrcMgr(mgr), MAI(mai), MRI(mri), MOFI(mofi), + Allocator(), Symbols(Allocator), UsedNames(Allocator), + NextUniqueID(0), + CurrentDwarfLoc(0,0,0,DWARF2_FLAG_IS_STMT,0,0), + DwarfLocSeen(false), GenDwarfForAssembly(false), GenDwarfFileNumber(0), + AllowTemporaryLabels(true), DwarfCompileUnitID(0), AutoReset(DoAutoReset) { + + error_code EC = llvm::sys::fs::current_path(CompilationDir); + assert(!EC && "Could not determine the current directory"); + (void)EC; + + MachOUniquingMap = 0; + ELFUniquingMap = 0; + COFFUniquingMap = 0; + + SecureLogFile = getenv("AS_SECURE_LOG_FILE"); + SecureLog = 0; + SecureLogUsed = false; + + if (SrcMgr && SrcMgr->getNumBuffers() > 0) + MainFileName = SrcMgr->getMemoryBuffer(0)->getBufferIdentifier(); + else + MainFileName = ""; +} + +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. + + // If the stream for the .secure_log_unique directive was created free it. + delete (raw_ostream*)SecureLog; +} + +//===----------------------------------------------------------------------===// +// Module Lifetime Management +//===----------------------------------------------------------------------===// + +void MCContext::reset() { + UsedNames.clear(); + Symbols.clear(); + Allocator.Reset(); + Instances.clear(); + MCDwarfFilesCUMap.clear(); + MCDwarfDirsCUMap.clear(); + MCGenDwarfLabelEntries.clear(); + DwarfDebugFlags = StringRef(); + MCLineSections.clear(); + MCLineSectionOrder.clear(); + DwarfCompileUnitID = 0; + MCLineTableSymbols.clear(); + CurrentDwarfLoc = MCDwarfLoc(0,0,0,DWARF2_FLAG_IS_STMT,0,0); + + // If we have the MachO uniquing map, free it. + delete (MachOUniqueMapTy*)MachOUniquingMap; + delete (ELFUniqueMapTy*)ELFUniquingMap; + delete (COFFUniqueMapTy*)COFFUniquingMap; + MachOUniquingMap = 0; + ELFUniquingMap = 0; + COFFUniquingMap = 0; + + NextUniqueID = 0; + AllowTemporaryLabels = true; + DwarfLocSeen = false; + GenDwarfForAssembly = false; + GenDwarfFileNumber = 0; +} + +//===----------------------------------------------------------------------===// +// Symbol Manipulation +//===----------------------------------------------------------------------===// + +MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name) { + assert(!Name.empty() && "Normal symbols cannot be unnamed!"); + + // Do the lookup and get the entire StringMapEntry. We want access to the + // key if we are creating the entry. + StringMapEntry<MCSymbol*> &Entry = Symbols.GetOrCreateValue(Name); + MCSymbol *Sym = Entry.getValue(); + + if (Sym) + return Sym; + + Sym = CreateSymbol(Name); + Entry.setValue(Sym); + return Sym; +} + +MCSymbol *MCContext::CreateSymbol(StringRef Name) { + // Determine whether this is an assembler temporary or normal label, if used. + bool isTemporary = false; + if (AllowTemporaryLabels) + isTemporary = Name.startswith(MAI->getPrivateGlobalPrefix()); + + StringMapEntry<bool> *NameEntry = &UsedNames.GetOrCreateValue(Name); + if (NameEntry->getValue()) { + assert(isTemporary && "Cannot rename non temporary symbols"); + SmallString<128> NewName = Name; + do { + NewName.resize(Name.size()); + raw_svector_ostream(NewName) << NextUniqueID++; + NameEntry = &UsedNames.GetOrCreateValue(NewName); + } while (NameEntry->getValue()); + } + NameEntry->setValue(true); + + // Ok, the entry doesn't already exist. Have the MCSymbol object itself refer + // to the copy of the string that is embedded in the UsedNames entry. + MCSymbol *Result = new (*this) MCSymbol(NameEntry->getKey(), isTemporary); + + return Result; +} + +MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { + SmallString<128> NameSV; + Name.toVector(NameSV); + return GetOrCreateSymbol(NameSV.str()); +} + +MCSymbol *MCContext::CreateTempSymbol() { + SmallString<128> NameSV; + raw_svector_ostream(NameSV) + << MAI->getPrivateGlobalPrefix() << "tmp" << NextUniqueID++; + return CreateSymbol(NameSV); +} + +unsigned MCContext::NextInstance(int64_t LocalLabelVal) { + MCLabel *&Label = Instances[LocalLabelVal]; + if (!Label) + Label = new (*this) MCLabel(0); + return Label->incInstance(); +} + +unsigned MCContext::GetInstance(int64_t LocalLabelVal) { + MCLabel *&Label = Instances[LocalLabelVal]; + if (!Label) + Label = new (*this) MCLabel(0); + return Label->getInstance(); +} + +MCSymbol *MCContext::CreateDirectionalLocalSymbol(int64_t LocalLabelVal) { + return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + + Twine(LocalLabelVal) + + "\2" + + Twine(NextInstance(LocalLabelVal))); +} +MCSymbol *MCContext::GetDirectionalLocalSymbol(int64_t LocalLabelVal, + int bORf) { + return GetOrCreateSymbol(Twine(MAI->getPrivateGlobalPrefix()) + + Twine(LocalLabelVal) + + "\2" + + Twine(GetInstance(LocalLabelVal) + bORf)); +} + +MCSymbol *MCContext::LookupSymbol(StringRef Name) const { + return Symbols.lookup(Name); +} + +MCSymbol *MCContext::LookupSymbol(const Twine &Name) const { + SmallString<128> NameSV; + Name.toVector(NameSV); + return LookupSymbol(NameSV.str()); +} + +//===----------------------------------------------------------------------===// +// Section Management +//===----------------------------------------------------------------------===// + +const MCSectionMachO *MCContext:: +getMachOSection(StringRef Segment, StringRef Section, + unsigned TypeAndAttributes, + unsigned Reserved2, SectionKind Kind) { + + // 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. + + // Create the map if it doesn't already exist. + if (MachOUniquingMap == 0) + MachOUniquingMap = new MachOUniqueMapTy(); + MachOUniqueMapTy &Map = *(MachOUniqueMapTy*)MachOUniquingMap; + + // 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. + const MCSectionMachO *&Entry = Map[Name.str()]; + if (Entry) return Entry; + + // Otherwise, return a new section. + return Entry = new (*this) MCSectionMachO(Segment, Section, TypeAndAttributes, + Reserved2, Kind); +} + +const MCSectionELF *MCContext:: +getELFSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind) { + return getELFSection(Section, Type, Flags, Kind, 0, ""); +} + +const MCSectionELF *MCContext:: +getELFSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind, unsigned EntrySize, StringRef Group) { + if (ELFUniquingMap == 0) + ELFUniquingMap = new ELFUniqueMapTy(); + ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; + + // Do the lookup, if we have a hit, return it. + std::pair<ELFUniqueMapTy::iterator, bool> Entry = Map.insert( + std::make_pair(SectionGroupPair(Section, Group), (MCSectionELF *)0)); + if (!Entry.second) return Entry.first->second; + + // Possibly refine the entry size first. + if (!EntrySize) { + EntrySize = MCSectionELF::DetermineEntrySize(Kind); + } + + MCSymbol *GroupSym = NULL; + if (!Group.empty()) + GroupSym = GetOrCreateSymbol(Group); + + MCSectionELF *Result = new (*this) MCSectionELF( + Entry.first->first.first, Type, Flags, Kind, EntrySize, GroupSym); + Entry.first->second = Result; + return Result; +} + +const MCSectionELF *MCContext::CreateELFGroupSection() { + MCSectionELF *Result = + new (*this) MCSectionELF(".group", ELF::SHT_GROUP, 0, + SectionKind::getReadOnly(), 4, NULL); + return Result; +} + +const MCSectionCOFF * +MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, + SectionKind Kind, StringRef COMDATSymName, + int Selection, const MCSectionCOFF *Assoc) { + if (COFFUniquingMap == 0) + COFFUniquingMap = new COFFUniqueMapTy(); + COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; + + // Do the lookup, if we have a hit, return it. + + SectionGroupPair P(Section, COMDATSymName); + std::pair<COFFUniqueMapTy::iterator, bool> Entry = + Map.insert(std::make_pair(P, (MCSectionCOFF *)0)); + COFFUniqueMapTy::iterator Iter = Entry.first; + if (!Entry.second) + return Iter->second; + + const MCSymbol *COMDATSymbol = NULL; + if (!COMDATSymName.empty()) + COMDATSymbol = GetOrCreateSymbol(COMDATSymName); + + MCSectionCOFF *Result = + new (*this) MCSectionCOFF(Iter->first.first, Characteristics, + COMDATSymbol, Selection, Assoc, Kind); + + Iter->second = Result; + return Result; +} + +const MCSectionCOFF * +MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, + SectionKind Kind) { + return getCOFFSection(Section, Characteristics, Kind, "", 0); +} + +const MCSectionCOFF *MCContext::getCOFFSection(StringRef Section) { + if (COFFUniquingMap == 0) + COFFUniquingMap = new COFFUniqueMapTy(); + COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; + + SectionGroupPair P(Section, ""); + COFFUniqueMapTy::iterator Iter = Map.find(P); + if (Iter == Map.end()) + return 0; + return Iter->second; +} + +//===----------------------------------------------------------------------===// +// Dwarf Management +//===----------------------------------------------------------------------===// + +/// GetDwarfFile - takes a file name an 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. +unsigned MCContext::GetDwarfFile(StringRef Directory, StringRef FileName, + unsigned FileNumber, unsigned CUID) { + // TODO: a FileNumber of zero says to use the next available file number. + // Note: in GenericAsmParser::ParseDirectiveFile() FileNumber was checked + // to not be less than one. This needs to be change to be not less than zero. + + SmallVectorImpl<MCDwarfFile *>& MCDwarfFiles = MCDwarfFilesCUMap[CUID]; + SmallVectorImpl<StringRef>& MCDwarfDirs = MCDwarfDirsCUMap[CUID]; + // Make space for this FileNumber in the MCDwarfFiles vector if needed. + if (FileNumber >= MCDwarfFiles.size()) { + MCDwarfFiles.resize(FileNumber + 1); + } else { + MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; + if (ExistingFile) + // It is an error to use see the same number more than once. + return 0; + } + + // Get the new MCDwarfFile slot for this FileNumber. + MCDwarfFile *&File = MCDwarfFiles[FileNumber]; + + 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 a 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()) { + char *Buf = static_cast<char *>(Allocate(Directory.size())); + memcpy(Buf, Directory.data(), Directory.size()); + MCDwarfDirs.push_back(StringRef(Buf, Directory.size())); + } + // 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++; + } + + // Now make the MCDwarfFile entry and place it in the slot in the MCDwarfFiles + // vector. + char *Buf = static_cast<char *>(Allocate(FileName.size())); + memcpy(Buf, FileName.data(), FileName.size()); + File = new (*this) MCDwarfFile(StringRef(Buf, FileName.size()), DirIndex); + + // return the allocated FileNumber. + return 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) { + SmallVectorImpl<MCDwarfFile *>& MCDwarfFiles = MCDwarfFilesCUMap[CUID]; + if(FileNumber == 0 || FileNumber >= MCDwarfFiles.size()) + return false; + + return MCDwarfFiles[FileNumber] != 0; +} + +void MCContext::FatalError(SMLoc Loc, const Twine &Msg) { + // If we have a source manager and a location, use it. Otherwise just + // use the generic report_fatal_error(). + if (!SrcMgr || Loc == SMLoc()) + report_fatal_error(Msg); + + // Use the source manager to print the message. + SrcMgr->PrintMessage(Loc, SourceMgr::DK_Error, 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.cpp b/contrib/llvm/lib/MC/MCDisassembler.cpp new file mode 100644 index 000000000000..bfd51ab1af97 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler.cpp @@ -0,0 +1,56 @@ +//===-- lib/MC/MCDisassembler.cpp - Disassembler interface ------*- 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/MCDisassembler.h" +#include "llvm/MC/MCExternalSymbolizer.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCDisassembler::~MCDisassembler() { +} + +void +MCDisassembler::setupForSymbolicDisassembly( + LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp, + void *DisInfo, + MCContext *Ctx, + OwningPtr<MCRelocationInfo> &RelInfo) { + this->GetOpInfo = GetOpInfo; + this->SymbolLookUp = SymbolLookUp; + this->DisInfo = DisInfo; + this->Ctx = Ctx; + assert(Ctx != 0 && "No MCContext given for symbolic disassembly"); + if (!Symbolizer) + Symbolizer.reset(new MCExternalSymbolizer(*Ctx, RelInfo, GetOpInfo, + SymbolLookUp, DisInfo)); +} + +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(OwningPtr<MCSymbolizer> &Symzer) { + Symbolizer.reset(Symzer.take()); +} diff --git a/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp new file mode 100644 index 000000000000..a0066c8885c5 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.cpp @@ -0,0 +1,362 @@ +//===-- 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/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCRelocationInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbolizer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/TargetRegistry.h" + +namespace llvm { +class Target; +} // namespace llvm +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 LLVMCreateDisasmCPU(const char *Triple, const char *CPU, + void *DisInfo, int TagType, + LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp){ + // Get the target. + std::string Error; + const Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); + if (!TheTarget) + return 0; + + const MCRegisterInfo *MRI = TheTarget->createMCRegInfo(Triple); + if (!MRI) + return 0; + + // Get the assembler info needed to setup the MCContext. + const MCAsmInfo *MAI = TheTarget->createMCAsmInfo(*MRI, Triple); + if (!MAI) + return 0; + + const MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + if (!MII) + return 0; + + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + + const MCSubtargetInfo *STI = TheTarget->createMCSubtargetInfo(Triple, CPU, + FeaturesStr); + if (!STI) + return 0; + + // Set up the MCContext for creating symbols and MCExpr's. + MCContext *Ctx = new MCContext(MAI, MRI, 0); + if (!Ctx) + return 0; + + // Set up disassembler. + MCDisassembler *DisAsm = TheTarget->createMCDisassembler(*STI); + if (!DisAsm) + return 0; + + OwningPtr<MCRelocationInfo> RelInfo( + TheTarget->createMCRelocationInfo(Triple, *Ctx)); + if (!RelInfo) + return 0; + + OwningPtr<MCSymbolizer> Symbolizer( + TheTarget->createMCSymbolizer(Triple, GetOpInfo, SymbolLookUp, DisInfo, + Ctx, RelInfo.take())); + DisAsm->setSymbolizer(Symbolizer); + DisAsm->setupForSymbolicDisassembly(GetOpInfo, SymbolLookUp, DisInfo, + Ctx, RelInfo); + // Set up the instruction printer. + int AsmPrinterVariant = MAI->getAssemblerDialect(); + MCInstPrinter *IP = TheTarget->createMCInstPrinter(AsmPrinterVariant, + *MAI, *MII, *MRI, *STI); + if (!IP) + return 0; + + LLVMDisasmContext *DC = new LLVMDisasmContext(Triple, DisInfo, TagType, + GetOpInfo, SymbolLookUp, + TheTarget, MAI, MRI, + STI, MII, Ctx, DisAsm, IP); + if (!DC) + return 0; + + DC->setCPU(CPU); + return DC; +} + +LLVMDisasmContextRef LLVMCreateDisasm(const char *Triple, void *DisInfo, + int TagType, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp) { + return LLVMCreateDisasmCPU(Triple, "", DisInfo, TagType, GetOpInfo, + SymbolLookUp); +} + +// +// LLVMDisasmDispose() disposes of the disassembler specified by the context. +// +void LLVMDisasmDispose(LLVMDisasmContextRef DCR){ + LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + delete DC; +} + +namespace { +// +// The memory object created by LLVMDisasmInstruction(). +// +class DisasmMemoryObject : public MemoryObject { + uint8_t *Bytes; + uint64_t Size; + uint64_t BasePC; +public: + DisasmMemoryObject(uint8_t *bytes, uint64_t size, uint64_t basePC) : + Bytes(bytes), Size(size), BasePC(basePC) {} + + uint64_t getBase() const { return BasePC; } + uint64_t getExtent() const { return Size; } + + int readByte(uint64_t Addr, uint8_t *Byte) const { + if (Addr - BasePC >= Size) + return -1; + *Byte = Bytes[Addr - BasePC]; + return 0; + } +}; +} // end anonymous namespace + +/// \brief 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. + DC->CommentStream.flush(); + StringRef Comments = DC->CommentsToEmit.str(); + // Get the default information for printing a comment. + const MCAsmInfo *MAI = DC->getAsmInfo(); + const char *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(); + DC->CommentStream.resync(); +} + +/// \brief Gets latency information for \p Inst form the itinerary +/// scheduling model, based on \p DC information. +/// \return The maximum expected latency over all the operands or -1 +/// if no information are 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; +} + +/// \brief 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 are 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 || !SCModel->hasInstrSchedModel()) + // Try to fall back to the itinerary model if we do not have a + // scheduling model. + 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. + 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); + Latency = std::max(Latency, WLEntry->Cycles); + } + + return Latency; +} + + +/// \brief 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 latency. + 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 = (LLVMDisasmContext *)DCR; + // Wrap the pointer to the Bytes, BytesSize and PC in a MemoryObject. + DisasmMemoryObject MemoryObject(Bytes, BytesSize, PC); + + 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, MemoryObject, 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: { + Annotations.flush(); + StringRef AnnotationsStr = Annotations.str(); + + SmallVector<char, 64> InsnStr; + raw_svector_ostream OS(InsnStr); + formatted_raw_ostream FormattedOS(OS); + IP->printInst(&Inst, FormattedOS, AnnotationsStr); + + 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 = (LLVMDisasmContext *)DCR; + MCInstPrinter *IP = DC->getIP(); + IP->setUseMarkup(1); + DC->addOptions(LLVMDisassembler_Option_UseMarkup); + Options &= ~LLVMDisassembler_Option_UseMarkup; + } + if (Options & LLVMDisassembler_Option_PrintImmHex){ + LLVMDisasmContext *DC = (LLVMDisasmContext *)DCR; + MCInstPrinter *IP = DC->getIP(); + IP->setPrintImmHex(1); + DC->addOptions(LLVMDisassembler_Option_PrintImmHex); + Options &= ~LLVMDisassembler_Option_PrintImmHex; + } + if (Options & LLVMDisassembler_Option_AsmPrinterVariant){ + LLVMDisasmContext *DC = (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(); + const MCSubtargetInfo *STI = DC->getSubtargetInfo(); + int AsmPrinterVariant = MAI->getAssemblerDialect(); + AsmPrinterVariant = AsmPrinterVariant == 0 ? 1 : 0; + MCInstPrinter *IP = DC->getTarget()->createMCInstPrinter( + AsmPrinterVariant, *MAI, *MII, *MRI, *STI); + if (IP) { + DC->setIP(IP); + DC->addOptions(LLVMDisassembler_Option_AsmPrinterVariant); + Options &= ~LLVMDisassembler_Option_AsmPrinterVariant; + } + } + if (Options & LLVMDisassembler_Option_SetInstrComments) { + LLVMDisasmContext *DC = (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 = (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..4855af27dd2c --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/Disassembler.h @@ -0,0 +1,130 @@ +//===------------- 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_MC_DISASSEMBLER_H +#define LLVM_MC_DISASSEMBLER_H + +#include "llvm-c/Disassembler.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +#include <string> + +namespace llvm { +class MCContext; +class MCAsmInfo; +class MCDisassembler; +class MCInstPrinter; +class MCInstrInfo; +class MCRegisterInfo; +class MCSubtargetInfo; +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 llvm::OwningPtr<const llvm::Target> causes a malloc error + // when this LLVMDisasmContext is deleted. + const Target *TheTarget; + // The assembly information for the target architecture. + llvm::OwningPtr<const llvm::MCAsmInfo> MAI; + // The register information for the target architecture. + llvm::OwningPtr<const llvm::MCRegisterInfo> MRI; + // The subtarget information for the target architecture. + llvm::OwningPtr<const llvm::MCSubtargetInfo> MSI; + // The instruction information for the target architecture. + llvm::OwningPtr<const llvm::MCInstrInfo> MII; + // The assembly context for creating symbols and MCExprs. + llvm::OwningPtr<const llvm::MCContext> Ctx; + // The disassembler for the target architecture. + llvm::OwningPtr<const llvm::MCDisassembler> DisAsm; + // The instruction printer for the target architecture. + llvm::OwningPtr<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(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/MCDwarf.cpp b/contrib/llvm/lib/MC/MCDwarf.cpp new file mode 100644 index 000000000000..1e5c2e34c488 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDwarf.cpp @@ -0,0 +1,1517 @@ +//===- 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/Hashing.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Twine.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/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +// Given a special op, return the address skip amount (in units of +// DWARF2_LINE_MIN_INSN_LENGTH. +#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) + +// The maximum address skip amount that can be encoded with a special op. +#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) + +// First special line opcode - leave room for the standard opcodes. +// Note: If you want to change this, you'll have to update the +// "standard_opcode_lengths" table that is emitted in DwarfFileTable::Emit(). +#define DWARF2_LINE_OPCODE_BASE 13 + +// Minimum line offset in a special line info. opcode. This value +// was chosen to give a reasonable range of values. +#define DWARF2_LINE_BASE -5 + +// Range of line offsets in a special line info. opcode. +#define DWARF2_LINE_RANGE 14 + +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 MCLineEntry::Make(MCStreamer *MCOS, const 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 MCLineEntry. + 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. + MCLineEntry LineEntry(LineSym, DwarfLoc); + + // clear DwarfLocSeen saying the current .loc info is now used. + MCOS->getContext().ClearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections.lookup(Section); + if (!LineSection) { + // Create a new MCLineSection. This will be deleted after the dwarf line + // table is created using it by iterating through the MCLineSections + // DenseMap. + LineSection = new MCLineSection; + // Save a pointer to the new LineSection into the MCLineSections DenseMap. + MCOS->getContext().addMCLineSection(Section, LineSection); + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry, + MCOS->getContext().getDwarfCompileUnitID()); +} + +// +// 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 emits the Dwarf line table for the specified section from the entries +// in the LineSection. +// +static inline void EmitDwarfLineTable(MCStreamer *MCOS, + const MCSection *Section, + const MCLineSection *LineSection, + unsigned CUID) { + // This LineSection does not contain any LineEntry for the given Compile Unit. + if (!LineSection->containEntriesForID(CUID)) + return; + + unsigned FileNum = 1; + unsigned LastLine = 1; + unsigned Column = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; + unsigned Isa = 0; + MCSymbol *LastLabel = NULL; + + // Loop through each MCLineEntry and encode the dwarf line number table. + for (MCLineSection::const_iterator + it = LineSection->getMCLineEntries(CUID).begin(), + ie = LineSection->getMCLineEntries(CUID).end(); it != ie; ++it) { + + if (FileNum != it->getFileNum()) { + FileNum = it->getFileNum(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1); + MCOS->EmitULEB128IntValue(FileNum); + } + if (Column != it->getColumn()) { + Column = it->getColumn(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1); + MCOS->EmitULEB128IntValue(Column); + } + if (Isa != it->getIsa()) { + Isa = it->getIsa(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); + MCOS->EmitULEB128IntValue(Isa); + } + if ((it->getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { + Flags = it->getFlags(); + MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); + } + if (it->getFlags() & DWARF2_FLAG_BASIC_BLOCK) + MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); + if (it->getFlags() & DWARF2_FLAG_PROLOGUE_END) + MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); + if (it->getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) + MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); + + int64_t LineDelta = static_cast<int64_t>(it->getLine()) - LastLine; + MCSymbol *Label = it->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->getPointerSize()); + + LastLine = it->getLine(); + LastLabel = Label; + } + + // Emit a DW_LNE_end_sequence for the end of the section. + // Using the pointer Section create a temporary label at the end of the + // section and use that and the LastLabel 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. + + // Switch to the section to be able to create a symbol at its end. + // TODO: keep track of the last subsection so that this symbol appears in the + // correct place. + MCOS->SwitchSection(Section); + + MCContext &context = MCOS->getContext(); + // Create a symbol at the end of the section. + MCSymbol *SectionEnd = context.CreateTempSymbol(); + // Set the value of the symbol, as we are at the end of the section. + MCOS->EmitLabel(SectionEnd); + + // Switch back the dwarf line section. + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection()); + + const MCAsmInfo *asmInfo = MCOS->getContext().getAsmInfo(); + MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd, + asmInfo->getPointerSize()); +} + +// +// This emits the Dwarf file and the line tables. +// +const MCSymbol *MCDwarfFileTable::Emit(MCStreamer *MCOS) { + MCContext &context = MCOS->getContext(); + // Switch to the section where the table will be emitted into. + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfLineSection()); + + const DenseMap<unsigned, MCSymbol *> &MCLineTableSymbols = + MCOS->getContext().getMCLineTableSymbols(); + // CUID and MCLineTableSymbols are set in DwarfDebug, when DwarfDebug does + // not exist, CUID will be 0 and MCLineTableSymbols will be empty. + // Handle Compile Unit 0, the line table start symbol is the section symbol. + const MCSymbol *LineStartSym = EmitCU(MCOS, 0); + // Handle the rest of the Compile Units. + for (unsigned Is = 1, Ie = MCLineTableSymbols.size(); Is < Ie; Is++) + EmitCU(MCOS, Is); + + // Now delete the MCLineSections that were created in MCLineEntry::Make() + // and used to emit the line table. + const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + for (DenseMap<const MCSection *, MCLineSection *>::const_iterator it = + MCLineSections.begin(), ie = MCLineSections.end(); it != ie; + ++it) + delete it->second; + + return LineStartSym; +} + +const MCSymbol *MCDwarfFileTable::EmitCU(MCStreamer *MCOS, unsigned CUID) { + MCContext &context = MCOS->getContext(); + + // Create a symbol at the beginning of the line table. + MCSymbol *LineStartSym = MCOS->getContext().getMCLineTableSymbol(CUID); + 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). + MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym,4), + 4); + + // Next 2 bytes is the Version, which is Dwarf 2. + MCOS->EmitIntValue(2, 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. Which is the start of the + // section to the end of the prologue. Not including the 4 bytes for the + // total length, the 2 bytes for the version, and these 4 bytes for the + // length of the prologue. + MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, + (4 + 2 + 4)), 4); + + // Parameters of the state machine, are next. + MCOS->EmitIntValue(context.getAsmInfo()->getMinInstAlignment(), 1); + MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1); + MCOS->EmitIntValue(DWARF2_LINE_BASE, 1); + MCOS->EmitIntValue(DWARF2_LINE_RANGE, 1); + MCOS->EmitIntValue(DWARF2_LINE_OPCODE_BASE, 1); + + // Standard opcode lengths + MCOS->EmitIntValue(0, 1); // length of DW_LNS_copy + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_line + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_file + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_column + MCOS->EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + MCOS->EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + MCOS->EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const SmallVectorImpl<StringRef> &MCDwarfDirs = + context.getMCDwarfDirs(CUID); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + MCOS->EmitBytes(MCDwarfDirs[i]); // the DirectoryName + MCOS->EmitBytes(StringRef("\0", 1)); // the null term. of the string + } + MCOS->EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + const SmallVectorImpl<MCDwarfFile *> &MCDwarfFiles = + MCOS->getContext().getMCDwarfFiles(CUID); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + MCOS->EmitBytes(MCDwarfFiles[i]->getName()); // FileName + MCOS->EmitBytes(StringRef("\0", 1)); // the null term. of the string + // the Directory num + MCOS->EmitULEB128IntValue(MCDwarfFiles[i]->getDirIndex()); + MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0) + MCOS->EmitIntValue(0, 1); // filesize (always 0) + } + MCOS->EmitIntValue(0, 1); // Terminate the file list + + // 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); + + // Put out the line tables. + const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + const std::vector<const MCSection *> &MCLineSectionOrder = + MCOS->getContext().getMCLineSectionOrder(); + for (std::vector<const MCSection*>::const_iterator it = + MCLineSectionOrder.begin(), ie = MCLineSectionOrder.end(); it != ie; + ++it) { + const MCSection *Sec = *it; + const MCLineSection *Line = MCLineSections.lookup(Sec); + EmitDwarfLineTable(MCOS, Sec, Line, CUID); + } + + if (MCOS->getContext().getAsmInfo()->getLinkerRequiresNonEmptyDwarfLines() + && MCLineSectionOrder.begin() == MCLineSectionOrder.end()) { + // The darwin9 linker has a bug (see PR8715). For for 32-bit architectures + // it requires: + // total_length >= prologue_length + 10 + // We are 4 bytes short, since we have total_length = 51 and + // prologue_length = 45 + + // The regular end_sequence should be sufficient. + MCDwarfLineAddr::Emit(MCOS, INT64_MAX, 0); + } + + // 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); + + return LineStartSym; +} + +/// Utility function to emit the encoding to a streamer. +void MCDwarfLineAddr::Emit(MCStreamer *MCOS, int64_t LineDelta, + uint64_t AddrDelta) { + MCContext &Context = MCOS->getContext(); + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(Context, LineDelta, AddrDelta, OS); + MCOS->EmitBytes(OS.str()); +} + +/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. +void MCDwarfLineAddr::Encode(MCContext &Context, int64_t LineDelta, + uint64_t AddrDelta, raw_ostream &OS) { + uint64_t Temp, Opcode; + bool NeedCopy = false; + + // 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 == MAX_SPECIAL_ADDR_DELTA) + OS << char(dwarf::DW_LNS_const_add_pc); + else { + 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 - DWARF2_LINE_BASE; + + // If the line increment is out of range of a special opcode, we must encode + // it with DW_LNS_advance_line. + if (Temp >= DWARF2_LINE_RANGE) { + OS << char(dwarf::DW_LNS_advance_line); + encodeSLEB128(LineDelta, OS); + + LineDelta = 0; + Temp = 0 - DWARF2_LINE_BASE; + 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 += DWARF2_LINE_OPCODE_BASE; + + // Avoid overflow when addr_delta is large. + if (AddrDelta < 256 + MAX_SPECIAL_ADDR_DELTA) { + // Try using a special opcode. + Opcode = Temp + AddrDelta * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(Opcode); + return; + } + + // Try using DW_LNS_const_add_pc followed by special op. + Opcode = Temp + (AddrDelta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; + 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 + OS << char(Temp); +} + +void MCDwarfFile::print(raw_ostream &OS) const { + OS << '"' << getName() << '"'; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCDwarfFile::dump() const { + print(dbgs()); +} +#endif + +// 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, dwarf::DW_FORM_data4); + 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); + 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. Which contains a header and a table of pairs of +// PointerSize'ed values for the address and size of section(s) with line table +// entries (just the default .text in our case) and a terminating pair of zeros. +static void EmitGenDwarfAranges(MCStreamer *MCOS, + const MCSymbol *InfoSectionSymbol) { + MCContext &context = MCOS->getContext(); + + // Create a symbol at the end of the section that we are creating the dwarf + // debugging info to use later in here as part of the expression to calculate + // the size of the section for the table. + MCOS->SwitchSection(context.getGenDwarfSection()); + MCSymbol *SectionEndSym = context.CreateTempSymbol(); + MCOS->EmitLabel(SectionEndSym); + context.setGenDwarfSectionEndSym(SectionEndSym); + + 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->getPointerSize(); + 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 the one default .text section we have in the table. + Length += 2 * AddrSize; + // 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); + 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(s) + // address and size, in our case just the one default .text section. + const MCExpr *Addr = MCSymbolRefExpr::Create( + context.getGenDwarfSectionStartSym(), MCSymbolRefExpr::VK_None, context); + const MCExpr *Size = MakeStartMinusEndExpr(*MCOS, + *context.getGenDwarfSectionStartSym(), *SectionEndSym, 0); + MCOS->EmitAbsValue(Addr, AddrSize); + MCOS->EmitAbsValue(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) { + 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); + MCOS->EmitAbsValue(Length, 4); + + // The 2 byte DWARF version, which is 2. + MCOS->EmitIntValue(2, 2); + + // 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) { + MCOS->EmitSymbolValue(AbbrevSectionSymbol, 4); + } else { + MCOS->EmitIntValue(0, 4); + } + + const MCAsmInfo *asmInfo = context.getAsmInfo(); + int AddrSize = asmInfo->getPointerSize(); + // The 1 byte size of an address. + 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); + } else { + MCOS->EmitIntValue(0, 4); + } + + // AT_low_pc, the first address of the default .text section. + const MCExpr *Start = MCSymbolRefExpr::Create( + context.getGenDwarfSectionStartSym(), MCSymbolRefExpr::VK_None, context); + MCOS->EmitAbsValue(Start, AddrSize); + + // AT_high_pc, the last address of the default .text section. + const MCExpr *End = MCSymbolRefExpr::Create( + context.getGenDwarfSectionEndSym(), MCSymbolRefExpr::VK_None, context); + MCOS->EmitAbsValue(End, AddrSize); + + // AT_name, the name of the source file. Reconstruct from the first directory + // and file table entries. + const SmallVectorImpl<StringRef> &MCDwarfDirs = + context.getMCDwarfDirs(); + if (MCDwarfDirs.size() > 0) { + MCOS->EmitBytes(MCDwarfDirs[0]); + MCOS->EmitBytes("/"); + } + const SmallVectorImpl<MCDwarfFile *> &MCDwarfFiles = + MCOS->getContext().getMCDwarfFiles(); + MCOS->EmitBytes(MCDwarfFiles[1]->getName()); + MCOS->EmitIntValue(0, 1); // NULL byte to terminate the string. + + // AT_comp_dir, the working directory the assembly was done in. + 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 ")); + MCOS->EmitBytes(StringRef(PACKAGE_VERSION)); + MCOS->EmitBytes(StringRef(")")); + } + 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<const MCGenDwarfLabelEntry *> &Entries = + MCOS->getContext().getMCGenDwarfLabelEntries(); + for (std::vector<const MCGenDwarfLabelEntry *>::const_iterator it = + Entries.begin(), ie = Entries.end(); it != ie; + ++it) { + const MCGenDwarfLabelEntry *Entry = *it; + + // 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->EmitAbsValue(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); + } + // Deallocate the MCGenDwarfLabelEntry classes that saved away the info + // for the dwarf labels. + for (std::vector<const MCGenDwarfLabelEntry *>::const_iterator it = + Entries.begin(), ie = Entries.end(); it != ie; + ++it) { + const MCGenDwarfLabelEntry *Entry = *it; + delete Entry; + } + + // 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 Dwarf +// sections. +// +void MCGenDwarfInfo::Emit(MCStreamer *MCOS, const MCSymbol *LineSectionSymbol) { + // Create the dwarf sections in this order (.debug_line already created). + MCContext &context = MCOS->getContext(); + const MCAsmInfo *AsmInfo = context.getAsmInfo(); + bool CreateDwarfSectionSymbols = + AsmInfo->doesDwarfUseRelocationsAcrossSections(); + if (!CreateDwarfSectionSymbols) + LineSectionSymbol = NULL; + MCSymbol *AbbrevSectionSymbol = NULL; + MCSymbol *InfoSectionSymbol = NULL; + 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); + } + MCOS->SwitchSection(context.getObjectFileInfo()->getDwarfARangesSection()); + + // If there are no line table entries then do not emit any section contents. + if (context.getMCLineSections().empty()) + return; + + // Output the data for .debug_aranges section. + EmitGenDwarfAranges(MCOS, InfoSectionSymbol); + + // Output the data for .debug_abbrev section. + EmitGenDwarfAbbrev(MCOS); + + // Output the data for .debug_info section. + EmitGenDwarfInfo(MCOS, AbbrevSectionSymbol, LineSectionSymbol); +} + +// +// 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 or symbols not in + // the default text. + if (Symbol->isTemporary()) + return; + MCContext &context = MCOS->getContext(); + if (context.getGenDwarfSection() != MCOS->getCurrentSection().first) + 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. + int 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. + MCGenDwarfLabelEntry *Entry = + new MCGenDwarfLabelEntry(Name, FileNumber, LineNumber, Label); + MCOS->getContext().addMCGenDwarfLabelEntry(Entry); +} + +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()->getPointerSize(); + 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 EmitSymbol(MCStreamer &streamer, const MCSymbol &symbol, + unsigned symbolEncoding, const char *comment = 0) { + MCContext &context = streamer.getContext(); + const MCAsmInfo *asmInfo = context.getAsmInfo(); + const MCExpr *v = asmInfo->getExprForFDESymbol(&symbol, + symbolEncoding, + streamer); + unsigned size = getSizeForEncoding(streamer, symbolEncoding); + if (streamer.isVerboseAsm() && comment) streamer.AddComment(comment); + streamer.EmitAbsValue(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; + int CIENum; + bool UsingCFI; + bool IsEH; + const MCSymbol *SectionStart; + public: + FrameEmitterImpl(bool usingCFI, bool isEH) + : CFAOffset(0), CIENum(0), UsingCFI(usingCFI), IsEH(isEH), + SectionStart(0) {} + + void setSectionStart(const MCSymbol *Label) { SectionStart = Label; } + + /// EmitCompactUnwind - Emit the unwind information in a compact way. + void EmitCompactUnwind(MCStreamer &streamer, + const MCDwarfFrameInfo &frame); + + const MCSymbol &EmitCIE(MCStreamer &streamer, + const MCSymbol *personality, + unsigned personalityEncoding, + const MCSymbol *lsda, + bool IsSignalFrame, + unsigned lsdaEncoding); + MCSymbol *EmitFDE(MCStreamer &streamer, + const MCSymbol &cieStart, + const MCDwarfFrameInfo &frame); + void EmitCFIInstructions(MCStreamer &streamer, + ArrayRef<MCCFIInstruction> Instrs, + MCSymbol *BaseLabel); + void EmitCFIInstruction(MCStreamer &Streamer, + const MCCFIInstruction &Instr); + }; + +} // end anonymous namespace + +static void EmitEncodingByte(MCStreamer &Streamer, unsigned Encoding, + StringRef Prefix) { + if (Streamer.isVerboseAsm()) { + const char *EncStr; + switch (Encoding) { + default: EncStr = "<unknown encoding>"; break; + case dwarf::DW_EH_PE_absptr: EncStr = "absptr"; break; + case dwarf::DW_EH_PE_omit: EncStr = "omit"; break; + case dwarf::DW_EH_PE_pcrel: EncStr = "pcrel"; break; + case dwarf::DW_EH_PE_udata4: EncStr = "udata4"; break; + case dwarf::DW_EH_PE_udata8: EncStr = "udata8"; break; + case dwarf::DW_EH_PE_sdata4: EncStr = "sdata4"; break; + case dwarf::DW_EH_PE_sdata8: EncStr = "sdata8"; break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata4: + EncStr = "pcrel udata4"; + break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4: + EncStr = "pcrel sdata4"; + break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8: + EncStr = "pcrel udata8"; + break; + case dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8: + EncStr = "screl sdata8"; + break; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata4: + EncStr = "indirect pcrel udata4"; + break; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata4: + EncStr = "indirect pcrel sdata4"; + break; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_udata8: + EncStr = "indirect pcrel udata8"; + break; + case dwarf::DW_EH_PE_indirect |dwarf::DW_EH_PE_pcrel|dwarf::DW_EH_PE_sdata8: + EncStr = "indirect pcrel sdata8"; + break; + } + + Streamer.AddComment(Twine(Prefix) + " = " + EncStr); + } + + Streamer.EmitIntValue(Encoding, 1); +} + +void FrameEmitterImpl::EmitCFIInstruction(MCStreamer &Streamer, + const MCCFIInstruction &Instr) { + int dataAlignmentFactor = getDataAlignmentFactor(Streamer); + bool VerboseAsm = Streamer.isVerboseAsm(); + + switch (Instr.getOperation()) { + case MCCFIInstruction::OpRegister: { + unsigned Reg1 = Instr.getRegister(); + unsigned Reg2 = Instr.getRegister2(); + if (VerboseAsm) { + Streamer.AddComment("DW_CFA_register"); + Streamer.AddComment(Twine("Reg1 ") + Twine(Reg1)); + Streamer.AddComment(Twine("Reg2 ") + Twine(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::OpUndefined: { + unsigned Reg = Instr.getRegister(); + if (VerboseAsm) { + Streamer.AddComment("DW_CFA_undefined"); + Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + } + Streamer.EmitIntValue(dwarf::DW_CFA_undefined, 1); + Streamer.EmitULEB128IntValue(Reg); + return; + } + case MCCFIInstruction::OpAdjustCfaOffset: + case MCCFIInstruction::OpDefCfaOffset: { + const bool IsRelative = + Instr.getOperation() == MCCFIInstruction::OpAdjustCfaOffset; + + if (VerboseAsm) + Streamer.AddComment("DW_CFA_def_cfa_offset"); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); + + if (IsRelative) + CFAOffset += Instr.getOffset(); + else + CFAOffset = -Instr.getOffset(); + + if (VerboseAsm) + Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); + Streamer.EmitULEB128IntValue(CFAOffset); + + return; + } + case MCCFIInstruction::OpDefCfa: { + if (VerboseAsm) + Streamer.AddComment("DW_CFA_def_cfa"); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); + + if (VerboseAsm) + Streamer.AddComment(Twine("Reg ") + Twine(Instr.getRegister())); + Streamer.EmitULEB128IntValue(Instr.getRegister()); + + CFAOffset = -Instr.getOffset(); + + if (VerboseAsm) + Streamer.AddComment(Twine("Offset " + Twine(CFAOffset))); + Streamer.EmitULEB128IntValue(CFAOffset); + + return; + } + + case MCCFIInstruction::OpDefCfaRegister: { + if (VerboseAsm) + Streamer.AddComment("DW_CFA_def_cfa_register"); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); + + if (VerboseAsm) + Streamer.AddComment(Twine("Reg ") + Twine(Instr.getRegister())); + Streamer.EmitULEB128IntValue(Instr.getRegister()); + + return; + } + + case MCCFIInstruction::OpOffset: + case MCCFIInstruction::OpRelOffset: { + const bool IsRelative = + Instr.getOperation() == MCCFIInstruction::OpRelOffset; + + unsigned Reg = Instr.getRegister(); + int Offset = Instr.getOffset(); + if (IsRelative) + Offset -= CFAOffset; + Offset = Offset / dataAlignmentFactor; + + if (Offset < 0) { + if (VerboseAsm) Streamer.AddComment("DW_CFA_offset_extended_sf"); + Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + Streamer.EmitULEB128IntValue(Reg); + if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); + Streamer.EmitSLEB128IntValue(Offset); + } else if (Reg < 64) { + if (VerboseAsm) Streamer.AddComment(Twine("DW_CFA_offset + Reg(") + + Twine(Reg) + ")"); + Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); + Streamer.EmitULEB128IntValue(Offset); + } else { + if (VerboseAsm) Streamer.AddComment("DW_CFA_offset_extended"); + Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + Streamer.EmitULEB128IntValue(Reg); + if (VerboseAsm) Streamer.AddComment(Twine("Offset ") + Twine(Offset)); + Streamer.EmitULEB128IntValue(Offset); + } + return; + } + case MCCFIInstruction::OpRememberState: + if (VerboseAsm) Streamer.AddComment("DW_CFA_remember_state"); + Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); + return; + case MCCFIInstruction::OpRestoreState: + if (VerboseAsm) Streamer.AddComment("DW_CFA_restore_state"); + Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); + return; + case MCCFIInstruction::OpSameValue: { + unsigned Reg = Instr.getRegister(); + if (VerboseAsm) Streamer.AddComment("DW_CFA_same_value"); + Streamer.EmitIntValue(dwarf::DW_CFA_same_value, 1); + if (VerboseAsm) Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + Streamer.EmitULEB128IntValue(Reg); + return; + } + case MCCFIInstruction::OpRestore: { + unsigned Reg = Instr.getRegister(); + if (VerboseAsm) { + Streamer.AddComment("DW_CFA_restore"); + Streamer.AddComment(Twine("Reg ") + Twine(Reg)); + } + Streamer.EmitIntValue(dwarf::DW_CFA_restore | Reg, 1); + return; + } + case MCCFIInstruction::OpEscape: + if (VerboseAsm) Streamer.AddComment("Escape bytes"); + Streamer.EmitBytes(Instr.getValues()); + return; + } + llvm_unreachable("Unhandled case in switch"); +} + +/// EmitFrameMoves - Emit frame instructions to describe the layout of the +/// frame. +void FrameEmitterImpl::EmitCFIInstructions(MCStreamer &streamer, + ArrayRef<MCCFIInstruction> Instrs, + MCSymbol *BaseLabel) { + for (unsigned i = 0, N = Instrs.size(); i < N; ++i) { + const MCCFIInstruction &Instr = Instrs[i]; + 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) { + if (streamer.isVerboseAsm()) streamer.AddComment("DW_CFA_advance_loc4"); + streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym); + BaseLabel = ThisSym; + } + } + + EmitCFIInstruction(streamer, Instr); + } +} + +/// EmitCompactUnwind - Emit the unwind information in a compact way. +void FrameEmitterImpl::EmitCompactUnwind(MCStreamer &Streamer, + const MCDwarfFrameInfo &Frame) { + MCContext &Context = Streamer.getContext(); + const MCObjectFileInfo *MOFI = Context.getObjectFileInfo(); + bool VerboseAsm = Streamer.isVerboseAsm(); + + // 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(UsingCFI); + unsigned Size = getSizeForEncoding(Streamer, FDEEncoding); + if (VerboseAsm) Streamer.AddComment("Range Start"); + Streamer.EmitSymbolValue(Frame.Function, Size); + + // Range Length + const MCExpr *Range = MakeStartMinusEndExpr(Streamer, *Frame.Begin, + *Frame.End, 0); + if (VerboseAsm) Streamer.AddComment("Range Length"); + Streamer.EmitAbsValue(Range, 4); + + // Compact Encoding + Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_udata4); + if (VerboseAsm) Streamer.AddComment("Compact Unwind Encoding: 0x" + + Twine::utohexstr(Encoding)); + Streamer.EmitIntValue(Encoding, Size); + + // Personality Function + Size = getSizeForEncoding(Streamer, dwarf::DW_EH_PE_absptr); + if (VerboseAsm) Streamer.AddComment("Personality Function"); + if (!DwarfEHFrameOnly && Frame.Personality) + Streamer.EmitSymbolValue(Frame.Personality, Size); + else + Streamer.EmitIntValue(0, Size); // No personality fn + + // LSDA + Size = getSizeForEncoding(Streamer, Frame.LsdaEncoding); + if (VerboseAsm) Streamer.AddComment("LSDA"); + if (!DwarfEHFrameOnly && Frame.Lsda) + Streamer.EmitSymbolValue(Frame.Lsda, Size); + else + Streamer.EmitIntValue(0, Size); // No LSDA +} + +const MCSymbol &FrameEmitterImpl::EmitCIE(MCStreamer &streamer, + const MCSymbol *personality, + unsigned personalityEncoding, + const MCSymbol *lsda, + bool IsSignalFrame, + unsigned lsdaEncoding) { + MCContext &context = streamer.getContext(); + const MCRegisterInfo *MRI = context.getRegisterInfo(); + const MCObjectFileInfo *MOFI = context.getObjectFileInfo(); + bool verboseAsm = streamer.isVerboseAsm(); + + MCSymbol *sectionStart; + if (MOFI->isFunctionEHFrameSymbolPrivate() || !IsEH) + sectionStart = context.CreateTempSymbol(); + else + sectionStart = context.GetOrCreateSymbol(Twine("EH_frame") + Twine(CIENum)); + + streamer.EmitLabel(sectionStart); + CIENum++; + + MCSymbol *sectionEnd = context.CreateTempSymbol(); + + // Length + const MCExpr *Length = MakeStartMinusEndExpr(streamer, *sectionStart, + *sectionEnd, 4); + if (verboseAsm) streamer.AddComment("CIE Length"); + streamer.EmitAbsValue(Length, 4); + + // CIE ID + unsigned CIE_ID = IsEH ? 0 : -1; + if (verboseAsm) streamer.AddComment("CIE ID Tag"); + streamer.EmitIntValue(CIE_ID, 4); + + // Version + if (verboseAsm) streamer.AddComment("DW_CIE_VERSION"); + streamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1); + + // Augmentation String + SmallString<8> Augmentation; + if (IsEH) { + if (verboseAsm) streamer.AddComment("CIE Augmentation"); + Augmentation += "z"; + if (personality) + Augmentation += "P"; + if (lsda) + Augmentation += "L"; + Augmentation += "R"; + if (IsSignalFrame) + Augmentation += "S"; + streamer.EmitBytes(Augmentation.str()); + } + streamer.EmitIntValue(0, 1); + + // Code Alignment Factor + if (verboseAsm) streamer.AddComment("CIE Code Alignment Factor"); + streamer.EmitULEB128IntValue(context.getAsmInfo()->getMinInstAlignment()); + + // Data Alignment Factor + if (verboseAsm) streamer.AddComment("CIE Data Alignment Factor"); + streamer.EmitSLEB128IntValue(getDataAlignmentFactor(streamer)); + + // Return Address Register + if (verboseAsm) streamer.AddComment("CIE Return Address Column"); + streamer.EmitULEB128IntValue(MRI->getDwarfRegNum(MRI->getRARegister(), true)); + + // Augmentation Data Length (optional) + + unsigned augmentationLength = 0; + if (IsEH) { + if (personality) { + // Personality Encoding + augmentationLength += 1; + // Personality + augmentationLength += getSizeForEncoding(streamer, personalityEncoding); + } + if (lsda) + augmentationLength += 1; + // Encoding of the FDE pointers + augmentationLength += 1; + + if (verboseAsm) streamer.AddComment("Augmentation Size"); + streamer.EmitULEB128IntValue(augmentationLength); + + // Augmentation Data (optional) + if (personality) { + // Personality Encoding + EmitEncodingByte(streamer, personalityEncoding, + "Personality Encoding"); + // Personality + if (verboseAsm) streamer.AddComment("Personality"); + EmitPersonality(streamer, *personality, personalityEncoding); + } + + if (lsda) + EmitEncodingByte(streamer, lsdaEncoding, "LSDA Encoding"); + + // Encoding of the FDE pointers + EmitEncodingByte(streamer, MOFI->getFDEEncoding(UsingCFI), + "FDE Encoding"); + } + + // Initial Instructions + + const MCAsmInfo *MAI = context.getAsmInfo(); + const std::vector<MCCFIInstruction> &Instructions = + MAI->getInitialFrameState(); + EmitCFIInstructions(streamer, Instructions, NULL); + + // Padding + streamer.EmitValueToAlignment(IsEH ? 4 : MAI->getPointerSize()); + + streamer.EmitLabel(sectionEnd); + return *sectionStart; +} + +MCSymbol *FrameEmitterImpl::EmitFDE(MCStreamer &streamer, + const MCSymbol &cieStart, + const MCDwarfFrameInfo &frame) { + MCContext &context = streamer.getContext(); + MCSymbol *fdeStart = context.CreateTempSymbol(); + MCSymbol *fdeEnd = context.CreateTempSymbol(); + const MCObjectFileInfo *MOFI = context.getObjectFileInfo(); + bool verboseAsm = streamer.isVerboseAsm(); + + if (IsEH && frame.Function && !MOFI->isFunctionEHFrameSymbolPrivate()) { + MCSymbol *EHSym = + context.GetOrCreateSymbol(frame.Function->getName() + Twine(".eh")); + streamer.EmitEHSymAttributes(frame.Function, EHSym); + streamer.EmitLabel(EHSym); + } + + // Length + const MCExpr *Length = MakeStartMinusEndExpr(streamer, *fdeStart, *fdeEnd, 0); + if (verboseAsm) streamer.AddComment("FDE Length"); + streamer.EmitAbsValue(Length, 4); + + streamer.EmitLabel(fdeStart); + + // CIE Pointer + const MCAsmInfo *asmInfo = context.getAsmInfo(); + if (IsEH) { + const MCExpr *offset = MakeStartMinusEndExpr(streamer, cieStart, *fdeStart, + 0); + if (verboseAsm) streamer.AddComment("FDE CIE Offset"); + streamer.EmitAbsValue(offset, 4); + } else if (!asmInfo->doesDwarfUseRelocationsAcrossSections()) { + const MCExpr *offset = MakeStartMinusEndExpr(streamer, *SectionStart, + cieStart, 0); + streamer.EmitAbsValue(offset, 4); + } else { + streamer.EmitSymbolValue(&cieStart, 4); + } + + // PC Begin + unsigned PCEncoding = IsEH ? MOFI->getFDEEncoding(UsingCFI) + : (unsigned)dwarf::DW_EH_PE_absptr; + unsigned PCSize = getSizeForEncoding(streamer, PCEncoding); + EmitSymbol(streamer, *frame.Begin, PCEncoding, "FDE initial location"); + + // PC Range + const MCExpr *Range = MakeStartMinusEndExpr(streamer, *frame.Begin, + *frame.End, 0); + if (verboseAsm) streamer.AddComment("FDE address range"); + streamer.EmitAbsValue(Range, PCSize); + + if (IsEH) { + // Augmentation Data Length + unsigned augmentationLength = 0; + + if (frame.Lsda) + augmentationLength += getSizeForEncoding(streamer, frame.LsdaEncoding); + + if (verboseAsm) streamer.AddComment("Augmentation size"); + streamer.EmitULEB128IntValue(augmentationLength); + + // Augmentation Data + if (frame.Lsda) + EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding, + "Language Specific Data Area"); + } + + // Call Frame Instructions + EmitCFIInstructions(streamer, frame.Instructions, frame.Begin); + + // Padding + streamer.EmitValueToAlignment(PCSize); + + return fdeEnd; +} + +namespace { + struct CIEKey { + static const CIEKey getEmptyKey() { return CIEKey(0, 0, -1, false); } + static const CIEKey getTombstoneKey() { return CIEKey(0, -1, 0, false); } + + CIEKey(const MCSymbol* Personality_, unsigned PersonalityEncoding_, + unsigned LsdaEncoding_, bool IsSignalFrame_) : + Personality(Personality_), PersonalityEncoding(PersonalityEncoding_), + LsdaEncoding(LsdaEncoding_), IsSignalFrame(IsSignalFrame_) { + } + const MCSymbol* Personality; + unsigned PersonalityEncoding; + unsigned LsdaEncoding; + bool IsSignalFrame; + }; +} + +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)); + } + 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; + } + }; +} + +void MCDwarfFrameEmitter::Emit(MCStreamer &Streamer, MCAsmBackend *MAB, + bool UsingCFI, bool IsEH) { + Streamer.generateCompactUnwindEncodings(MAB); + + MCContext &Context = Streamer.getContext(); + const MCObjectFileInfo *MOFI = Context.getObjectFileInfo(); + FrameEmitterImpl Emitter(UsingCFI, IsEH); + ArrayRef<MCDwarfFrameInfo> FrameArray = Streamer.getFrameInfos(); + + // Emit the compact unwind info if available. + if (IsEH && MOFI->getCompactUnwindSection()) { + bool SectionEmitted = false; + for (unsigned i = 0, n = FrameArray.size(); i < n; ++i) { + const MCDwarfFrameInfo &Frame = FrameArray[i]; + if (Frame.CompactUnwindEncoding == 0) continue; + if (!SectionEmitted) { + Streamer.SwitchSection(MOFI->getCompactUnwindSection()); + Streamer.EmitValueToAlignment(Context.getAsmInfo()->getPointerSize()); + SectionEmitted = true; + } + Emitter.EmitCompactUnwind(Streamer, Frame); + } + } + + const MCSection &Section = + IsEH ? *const_cast<MCObjectFileInfo*>(MOFI)->getEHFrameSection() : + *MOFI->getDwarfFrameSection(); + Streamer.SwitchSection(&Section); + MCSymbol *SectionStart = Context.CreateTempSymbol(); + Streamer.EmitLabel(SectionStart); + Emitter.setSectionStart(SectionStart); + + MCSymbol *FDEEnd = NULL; + DenseMap<CIEKey, const MCSymbol*> CIEStarts; + + const MCSymbol *DummyDebugKey = NULL; + for (unsigned i = 0, n = FrameArray.size(); i < n; ++i) { + const MCDwarfFrameInfo &Frame = FrameArray[i]; + CIEKey Key(Frame.Personality, Frame.PersonalityEncoding, + Frame.LsdaEncoding, Frame.IsSignalFrame); + const MCSymbol *&CIEStart = IsEH ? CIEStarts[Key] : DummyDebugKey; + if (!CIEStart) + CIEStart = &Emitter.EmitCIE(Streamer, Frame.Personality, + Frame.PersonalityEncoding, Frame.Lsda, + Frame.IsSignalFrame, + Frame.LsdaEncoding); + + FDEEnd = Emitter.EmitFDE(Streamer, *CIEStart, Frame); + + if (i != n - 1) + Streamer.EmitLabel(FDEEnd); + } + + Streamer.EmitValueToAlignment(Context.getAsmInfo()->getPointerSize()); + if (FDEEnd) + Streamer.EmitLabel(FDEEnd); +} + +void MCDwarfFrameEmitter::EmitAdvanceLoc(MCStreamer &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); + + 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)) { + // FIXME: check what is the correct behavior on a big endian machine. + OS << uint8_t(dwarf::DW_CFA_advance_loc2); + OS << uint8_t( AddrDelta & 0xff); + OS << uint8_t((AddrDelta >> 8) & 0xff); + } else { + // FIXME: check what is the correct behavior on a big endian machine. + assert(isUInt<32>(AddrDelta)); + OS << uint8_t(dwarf::DW_CFA_advance_loc4); + OS << uint8_t( AddrDelta & 0xff); + OS << uint8_t((AddrDelta >> 8) & 0xff); + OS << uint8_t((AddrDelta >> 16) & 0xff); + OS << uint8_t((AddrDelta >> 24) & 0xff); + + } +} diff --git a/contrib/llvm/lib/MC/MCELF.cpp b/contrib/llvm/lib/MC/MCELF.cpp new file mode 100644 index 000000000000..ebb189e5439e --- /dev/null +++ b/contrib/llvm/lib/MC/MCELF.cpp @@ -0,0 +1,85 @@ +//===- lib/MC/MCELF.cpp - MC ELF ------------------------------------------===// +// +// 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/MC/MCELF.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/Support/ELF.h" + +namespace llvm { + +void MCELF::SetBinding(MCSymbolData &SD, unsigned Binding) { + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); + SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); +} + +unsigned MCELF::GetBinding(const MCSymbolData &SD) { + uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + return Binding; +} + +void MCELF::SetType(MCSymbolData &SD, unsigned Type) { + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_COMMON || Type == ELF::STT_TLS || + Type == ELF::STT_GNU_IFUNC); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STT_Shift); + SD.setFlags(OtherFlags | (Type << ELF_STT_Shift)); +} + +unsigned MCELF::GetType(const MCSymbolData &SD) { + uint32_t Type = (SD.getFlags() & (0xf << ELF_STT_Shift)) >> ELF_STT_Shift; + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_COMMON || Type == ELF::STT_TLS || Type == ELF::STT_GNU_IFUNC); + return Type; +} + +// Visibility is stored in the first two bits of st_other +// st_other values are stored in the second byte of get/setFlags +void MCELF::SetVisibility(MCSymbolData &SD, unsigned Visibility) { + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + + uint32_t OtherFlags = SD.getFlags() & ~(0x3 << ELF_STV_Shift); + SD.setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); +} + +unsigned MCELF::GetVisibility(MCSymbolData &SD) { + unsigned Visibility = + (SD.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; +} + +// Other is stored in the last six bits of st_other +// st_other values are stored in the second byte of get/setFlags +void MCELF::setOther(MCSymbolData &SD, unsigned Other) { + uint32_t OtherFlags = SD.getFlags() & ~(0x3f << ELF_Other_Shift); + SD.setFlags(OtherFlags | (Other << ELF_Other_Shift)); +} + +unsigned MCELF::getOther(MCSymbolData &SD) { + unsigned Other = + (SD.getFlags() & (0x3f << ELF_Other_Shift)) >> ELF_Other_Shift; + return Other; +} + +} diff --git a/contrib/llvm/lib/MC/MCELFObjectTargetWriter.cpp b/contrib/llvm/lib/MC/MCELFObjectTargetWriter.cpp new file mode 100644 index 000000000000..0c39e4a17efd --- /dev/null +++ b/contrib/llvm/lib/MC/MCELFObjectTargetWriter.cpp @@ -0,0 +1,61 @@ +//===-- 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/ADT/STLExtras.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" + +using namespace llvm; + +MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, + uint8_t OSABI_, + uint16_t EMachine_, + bool HasRelocationAddend_, + bool IsN64_) + : OSABI(OSABI_), EMachine(EMachine_), + HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_), + IsN64(IsN64_){ +} + +const MCSymbol *MCELFObjectTargetWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + const MCFixup &Fixup, + bool IsPCRel) const { + return NULL; +} + +const MCSymbol *MCELFObjectTargetWriter::undefinedExplicitRelSym(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + return &Symbol.AliasedSymbol(); +} + +// ELF doesn't require relocations to be in any order. We sort by the r_offset, +// just to match gnu as for easier comparison. The use type and index is an +// arbitrary way of making the sort deterministic. +static int cmpRel(const ELFRelocationEntry *AP, const ELFRelocationEntry *BP) { + const ELFRelocationEntry &A = *AP; + const ELFRelocationEntry &B = *BP; + if (A.r_offset != B.r_offset) + return B.r_offset - A.r_offset; + if (B.Type != A.Type) + return A.Type - B.Type; + if (B.Index != A.Index) + return B.Index - A.Index; + llvm_unreachable("ELFRelocs might be unstable!"); +} + +void +MCELFObjectTargetWriter::sortRelocs(const MCAssembler &Asm, + std::vector<ELFRelocationEntry> &Relocs) { + array_pod_sort(Relocs.begin(), Relocs.end(), cmpRel); +} diff --git a/contrib/llvm/lib/MC/MCELFStreamer.cpp b/contrib/llvm/lib/MC/MCELFStreamer.cpp new file mode 100644 index 000000000000..e806cb9f1c94 --- /dev/null +++ b/contrib/llvm/lib/MC/MCELFStreamer.cpp @@ -0,0 +1,625 @@ +//===- 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/SmallPtrSet.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELF.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + + +inline void MCELFStreamer::SetSection(StringRef Section, unsigned Type, + unsigned Flags, SectionKind Kind) { + SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); +} + +inline void MCELFStreamer::SetSectionData() { + SetSection(".data", + ELF::SHT_PROGBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); +} + +inline void MCELFStreamer::SetSectionText() { + SetSection(".text", + ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | ELF::SHF_ALLOC, + SectionKind::getText()); + EmitCodeAlignment(4, 0); +} + +inline void MCELFStreamer::SetSectionBss() { + SetSection(".bss", + ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getBSS()); + EmitCodeAlignment(4, 0); +} + +MCELFStreamer::~MCELFStreamer() { +} + +void MCELFStreamer::InitToTextSection() { + SetSectionText(); +} + +void MCELFStreamer::InitSections() { + // 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. + SetSectionText(); + SetSectionData(); + SetSectionBss(); + SetSectionText(); +} + +void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + MCObjectStreamer::EmitLabel(Symbol); + + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(Symbol->getSection()); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); + if (Section.getFlags() & ELF::SHF_TLS) + MCELF::SetType(SD, ELF::STT_TLS); +} + +void MCELFStreamer::EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); +} + +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!"); +} + +void MCELFStreamer::ChangeSection(const MCSection *Section, + const MCExpr *Subsection) { + MCSectionData *CurSection = getCurrentSectionData(); + if (CurSection && CurSection->isBundleLocked()) + report_fatal_error("Unterminated .bundle_lock when changing a section"); + const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::ChangeSection(Section, Subsection); +} + +void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + getAssembler().getOrCreateSymbolData(*Symbol); + MCSymbolData &AliasSD = getAssembler().getOrCreateSymbolData(*Alias); + AliasSD.setFlags(AliasSD.getFlags() | ELF_Other_Weakref); + const MCExpr *Value = MCSymbolRefExpr::Create(Symbol, 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) { + unsigned TypeOrdering[] = {ELF::STT_NOTYPE, ELF::STT_OBJECT, ELF::STT_FUNC, + ELF::STT_GNU_IFUNC, ELF::STT_TLS}; + for (unsigned i = 0; i != array_lengthof(TypeOrdering); ++i) { + if (T1 == TypeOrdering[i]) + return T2; + if (T2 == TypeOrdering[i]) + return T1; + } + + return T2; +} + +bool MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + MCSymbolAttr Attribute) { + // 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.SectionData = getCurrentSectionData(); + getAssembler().getIndirectSymbols().push_back(ISD); + return true; + } + + // Adding a symbol attribute always introduces the symbol, note that an + // important side effect of calling getOrCreateSymbolData here is to register + // the symbol with the assembler. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*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: + case MCSA_ELF_TypeGnuUniqueObject: + // Ignore for now. + break; + + case MCSA_Global: + MCELF::SetBinding(SD, ELF::STB_GLOBAL); + SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); + break; + + case MCSA_WeakReference: + case MCSA_Weak: + MCELF::SetBinding(SD, ELF::STB_WEAK); + SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); + break; + + case MCSA_Local: + MCELF::SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); + break; + + case MCSA_ELF_TypeFunction: + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_FUNC)); + break; + + case MCSA_ELF_TypeIndFunction: + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_GNU_IFUNC)); + break; + + case MCSA_ELF_TypeObject: + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_OBJECT)); + break; + + case MCSA_ELF_TypeTLS: + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_TLS)); + break; + + case MCSA_ELF_TypeCommon: + // TODO: Emit these as a common symbol. + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_OBJECT)); + break; + + case MCSA_ELF_TypeNoType: + MCELF::SetType(SD, CombineSymbolTypes(MCELF::GetType(SD), + ELF::STT_NOTYPE)); + break; + + case MCSA_Protected: + MCELF::SetVisibility(SD, ELF::STV_PROTECTED); + break; + + case MCSA_Hidden: + MCELF::SetVisibility(SD, ELF::STV_HIDDEN); + break; + + case MCSA_Internal: + MCELF::SetVisibility(SD, ELF::STV_INTERNAL); + break; + } + + return true; +} + +void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + if (!BindingExplicitlySet.count(Symbol)) { + MCELF::SetBinding(SD, ELF::STB_GLOBAL); + SD.setExternal(true); + } + + MCELF::SetType(SD, ELF::STT_OBJECT); + + if (MCELF::GetBinding(SD) == ELF_STB_Local) { + const MCSection *Section = getAssembler().getContext().getELFSection(".bss", + ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, + SectionKind::getBSS()); + + AssignSection(Symbol, Section); + + struct LocalCommon L = {&SD, Size, ByteAlignment}; + LocalCommons.push_back(L); + } else { + SD.setCommon(Size, ByteAlignment); + } + + SD.setSize(MCConstantExpr::Create(Size, getContext())); +} + +void MCELFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setSize(Value); +} + +void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + // FIXME: Should this be caught and done earlier? + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + MCELF::SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); + EmitCommonSymbol(Symbol, Size, ByteAlignment); +} + +void MCELFStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size) { + if (getCurrentSectionData()->isBundleLocked()) + report_fatal_error("Emitting values inside a locked bundle is forbidden"); + fixSymbolsInTLSFixups(Value); + MCObjectStreamer::EmitValueImpl(Value, Size); +} + +void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) { + if (getCurrentSectionData()->isBundleLocked()) + report_fatal_error("Emitting values inside a locked bundle is forbidden"); + MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, + ValueSize, MaxBytesToEmit); +} + +// Add a symbol for the file name of this module. They start after the +// null symbol and don't count as normal symbol, i.e. a non-STT_FILE symbol +// with the same name may appear. +void MCELFStreamer::EmitFileDirective(StringRef Filename) { + getAssembler().addFileName(Filename); +} + +void MCELFStreamer::EmitIdent(StringRef IdentString) { + const MCSection *Comment = getAssembler().getContext().getELFSection( + ".comment", ELF::SHT_PROGBITS, ELF::SHF_MERGE | ELF::SHF_STRINGS, + SectionKind::getReadOnly(), 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_DTPOFF: + case MCSymbolRefExpr::VK_ARM_TLSGD: + case MCSymbolRefExpr::VK_ARM_TPOFF: + case MCSymbolRefExpr::VK_ARM_GOTTPOFF: + case MCSymbolRefExpr::VK_Mips_TLSGD: + case MCSymbolRefExpr::VK_Mips_GOTTPREL: + case MCSymbolRefExpr::VK_Mips_TPREL_HI: + case MCSymbolRefExpr::VK_Mips_TPREL_LO: + case MCSymbolRefExpr::VK_PPC_DTPMOD: + case MCSymbolRefExpr::VK_PPC_TPREL: + case MCSymbolRefExpr::VK_PPC_TPREL_LO: + case MCSymbolRefExpr::VK_PPC_TPREL_HI: + case MCSymbolRefExpr::VK_PPC_TPREL_HA: + 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: + case MCSymbolRefExpr::VK_PPC_DTPREL_LO: + case MCSymbolRefExpr::VK_PPC_DTPREL_HI: + case MCSymbolRefExpr::VK_PPC_DTPREL_HA: + 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; + } + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(symRef.getSymbol()); + MCELF::SetType(SD, ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr()); + break; + } +} + +void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { + this->MCObjectStreamer::EmitInstToFragment(Inst); + MCRelaxableFragment &F = *cast<MCRelaxableFragment>(getCurrentFragment()); + + for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i) + fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); +} + +void MCELFStreamer::EmitInstToData(const MCInst &Inst) { + MCAssembler &Assembler = getAssembler(); + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + Assembler.getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + 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). + // + // 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()) { + MCSectionData *SD = getCurrentSectionData(); + if (SD->isBundleLocked() && !SD->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()); + else if (!SD->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()); + return; + } else { + DF = new MCDataFragment(); + insert(DF); + if (SD->getBundleLockState() == MCSectionData::BundleLockedAlignToEnd) { + // If this is a new fragment created for a bundle-locked group, and the + // group was marked as "align_to_end", set a flag in the fragment. + DF->setAlignToBundleEnd(true); + } + } + + // We're now emitting an instruction in a bundle group, so this flag has + // to be turned off. + SD->setBundleGroupBeforeFirstInst(false); + } else { + 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(true); + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCELFStreamer::EmitBundleAlignMode(unsigned AlignPow2) { + assert(AlignPow2 <= 30 && "Invalid bundle alignment"); + MCAssembler &Assembler = getAssembler(); + if (Assembler.getBundleAlignSize() == 0 && AlignPow2 > 0) + Assembler.setBundleAlignSize(1 << AlignPow2); + else + report_fatal_error(".bundle_align_mode should be only set once per file"); +} + +void MCELFStreamer::EmitBundleLock(bool AlignToEnd) { + MCSectionData *SD = getCurrentSectionData(); + + // Sanity checks + // + if (!getAssembler().isBundlingEnabled()) + report_fatal_error(".bundle_lock forbidden when bundling is disabled"); + else if (SD->isBundleLocked()) + report_fatal_error("Nesting of .bundle_lock is forbidden"); + + SD->setBundleLockState(AlignToEnd ? MCSectionData::BundleLockedAlignToEnd : + MCSectionData::BundleLocked); + SD->setBundleGroupBeforeFirstInst(true); +} + +void MCELFStreamer::EmitBundleUnlock() { + MCSectionData *SD = getCurrentSectionData(); + + // Sanity checks + if (!getAssembler().isBundlingEnabled()) + report_fatal_error(".bundle_unlock forbidden when bundling is disabled"); + else if (!SD->isBundleLocked()) + report_fatal_error(".bundle_unlock without matching lock"); + else if (SD->isBundleGroupBeforeFirstInst()) + report_fatal_error("Empty bundle-locked group is forbidden"); + + SD->setBundleLockState(MCSectionData::NotBundleLocked); +} + +void MCELFStreamer::Flush() { + for (std::vector<LocalCommon>::const_iterator i = LocalCommons.begin(), + e = LocalCommons.end(); + i != e; ++i) { + MCSymbolData *SD = i->SD; + uint64_t Size = i->Size; + unsigned ByteAlignment = i->ByteAlignment; + const MCSymbol &Symbol = SD->getSymbol(); + const MCSection &Section = Symbol.getSection(); + + MCSectionData &SectData = getAssembler().getOrCreateSectionData(Section); + new MCAlignFragment(ByteAlignment, 0, 1, ByteAlignment, &SectData); + + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD->setFragment(F); + + // Update the maximum alignment of the section if necessary. + if (ByteAlignment > SectData.getAlignment()) + SectData.setAlignment(ByteAlignment); + } + + LocalCommons.clear(); +} + +void MCELFStreamer::FinishImpl() { + EmitFrames(NULL, true); + + Flush(); + + this->MCObjectStreamer::FinishImpl(); +} + +MCStreamer *llvm::createELFStreamer(MCContext &Context, + MCTargetStreamer *Streamer, + MCAsmBackend &MAB, raw_ostream &OS, + MCCodeEmitter *CE, bool RelaxAll, + bool NoExecStack) { + MCELFStreamer *S = new MCELFStreamer(Context, Streamer, MAB, OS, CE); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); + return S; +} + +void MCELFStreamer::EmitThumbFunc(MCSymbol *Func) { + llvm_unreachable("Generic ELF doesn't support this directive"); +} + +MCSymbolData &MCELFStreamer::getOrCreateSymbolData(MCSymbol *Symbol) { + return getAssembler().getOrCreateSymbolData(*Symbol); +} + +void MCELFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::BeginCOFFSymbolDef(const MCSymbol *Symbol) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitCOFFSymbolType(int Type) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EndCOFFSymbolDef() { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("ELF doesn't support this directive"); +} + +void MCELFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("ELF doesn't support this directive"); +} diff --git a/contrib/llvm/lib/MC/MCExpr.cpp b/contrib/llvm/lib/MC/MCExpr.cpp new file mode 100644 index 000000000000..c777e648bdc6 --- /dev/null +++ b/contrib/llvm/lib/MC/MCExpr.cpp @@ -0,0 +1,782 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "mcexpr" +#include "llvm/MC/MCExpr.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringSwitch.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/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { +namespace stats { +STATISTIC(MCExprEvaluate, "Number of MCExpr evaluations"); +} +} + +void MCExpr::print(raw_ostream &OS) const { + switch (getKind()) { + case MCExpr::Target: + return cast<MCTargetExpr>(this)->PrintImpl(OS); + 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 = Sym.getName()[0] == '$'; + if (UseParens) + OS << '(' << Sym << ')'; + else + OS << Sym; + + if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_NONE || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_PLT || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TLSGD || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOT || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TPOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTTPOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET1 || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TARGET2 || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_PREL31) + OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + else if (SRE.getKind() != MCSymbolRefExpr::VK_None) + OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + + 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; + } + OS << *UE.getSubExpr(); + 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())) { + OS << *BE.getLHS(); + } else { + OS << '(' << *BE.getLHS() << ')'; + } + + 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::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::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::Shr: 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())) { + OS << *BE.getRHS(); + } else { + OS << '(' << *BE.getRHS() << ')'; + } + return; + } + } + + llvm_unreachable("Invalid expression kind!"); +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCExpr::dump() const { + print(dbgs()); + dbgs() << '\n'; +} +#endif + +/* *** */ + +const MCBinaryExpr *MCBinaryExpr::Create(Opcode Opc, const MCExpr *LHS, + const MCExpr *RHS, MCContext &Ctx) { + return new (Ctx) MCBinaryExpr(Opc, LHS, RHS); +} + +const MCUnaryExpr *MCUnaryExpr::Create(Opcode Opc, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) MCUnaryExpr(Opc, Expr); +} + +const MCConstantExpr *MCConstantExpr::Create(int64_t Value, MCContext &Ctx) { + return new (Ctx) MCConstantExpr(Value); +} + +/* *** */ + +const MCSymbolRefExpr *MCSymbolRefExpr::Create(const MCSymbol *Sym, + VariantKind Kind, + MCContext &Ctx) { + return new (Ctx) MCSymbolRefExpr(Sym, Kind); +} + +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_GOT: return "GOT"; + case VK_GOTOFF: return "GOTOFF"; + 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_DTPOFF: return "DTPOFF"; + case VK_TLVP: return "TLVP"; + case VK_SECREL: return "SECREL32"; + case VK_ARM_NONE: return "(NONE)"; + case VK_ARM_PLT: return "(PLT)"; + case VK_ARM_GOT: return "(GOT)"; + case VK_ARM_GOTOFF: return "(GOTOFF)"; + case VK_ARM_TPOFF: return "(tpoff)"; + case VK_ARM_GOTTPOFF: return "(gottpoff)"; + case VK_ARM_TLSGD: return "(tlsgd)"; + case VK_ARM_TARGET1: return "(target1)"; + case VK_ARM_TARGET2: return "(target2)"; + case VK_ARM_PREL31: return "(prel31)"; + case VK_PPC_LO: return "l"; + case VK_PPC_HI: return "h"; + case VK_PPC_HA: return "ha"; + 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: return "tprel"; + 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_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: return "dtprel"; + 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_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_Mips_GPREL: return "GPREL"; + case VK_Mips_GOT_CALL: return "GOT_CALL"; + case VK_Mips_GOT16: return "GOT16"; + case VK_Mips_GOT: return "GOT"; + case VK_Mips_ABS_HI: return "ABS_HI"; + case VK_Mips_ABS_LO: return "ABS_LO"; + case VK_Mips_TLSGD: return "TLSGD"; + case VK_Mips_TLSLDM: return "TLSLDM"; + case VK_Mips_DTPREL_HI: return "DTPREL_HI"; + case VK_Mips_DTPREL_LO: return "DTPREL_LO"; + case VK_Mips_GOTTPREL: return "GOTTPREL"; + case VK_Mips_TPREL_HI: return "TPREL_HI"; + case VK_Mips_TPREL_LO: return "TPREL_LO"; + case VK_Mips_GPOFF_HI: return "GPOFF_HI"; + case VK_Mips_GPOFF_LO: return "GPOFF_LO"; + case VK_Mips_GOT_DISP: return "GOT_DISP"; + case VK_Mips_GOT_PAGE: return "GOT_PAGE"; + case VK_Mips_GOT_OFST: return "GOT_OFST"; + case VK_Mips_HIGHER: return "HIGHER"; + case VK_Mips_HIGHEST: return "HIGHEST"; + case VK_Mips_GOT_HI16: return "GOT_HI16"; + case VK_Mips_GOT_LO16: return "GOT_LO16"; + case VK_Mips_CALL_HI16: return "CALL_HI16"; + case VK_Mips_CALL_LO16: return "CALL_LO16"; + case VK_COFF_IMGREL32: return "IMGREL32"; + } + llvm_unreachable("Invalid variant kind"); +} + +MCSymbolRefExpr::VariantKind +MCSymbolRefExpr::getVariantKindForName(StringRef Name) { + return StringSwitch<VariantKind>(Name) + .Case("GOT", VK_GOT) + .Case("got", VK_GOT) + .Case("GOTOFF", VK_GOTOFF) + .Case("gotoff", VK_GOTOFF) + .Case("GOTPCREL", VK_GOTPCREL) + .Case("gotpcrel", VK_GOTPCREL) + .Case("GOTTPOFF", VK_GOTTPOFF) + .Case("gottpoff", VK_GOTTPOFF) + .Case("INDNTPOFF", VK_INDNTPOFF) + .Case("indntpoff", VK_INDNTPOFF) + .Case("NTPOFF", VK_NTPOFF) + .Case("ntpoff", VK_NTPOFF) + .Case("GOTNTPOFF", VK_GOTNTPOFF) + .Case("gotntpoff", VK_GOTNTPOFF) + .Case("PLT", VK_PLT) + .Case("plt", VK_PLT) + .Case("TLSGD", VK_TLSGD) + .Case("tlsgd", VK_TLSGD) + .Case("TLSLD", VK_TLSLD) + .Case("tlsld", VK_TLSLD) + .Case("TLSLDM", VK_TLSLDM) + .Case("tlsldm", VK_TLSLDM) + .Case("TPOFF", VK_TPOFF) + .Case("tpoff", VK_TPOFF) + .Case("DTPOFF", VK_DTPOFF) + .Case("dtpoff", VK_DTPOFF) + .Case("TLVP", VK_TLVP) + .Case("tlvp", VK_TLVP) + .Case("IMGREL", VK_COFF_IMGREL32) + .Case("imgrel", VK_COFF_IMGREL32) + .Case("SECREL32", VK_SECREL) + .Case("secrel32", VK_SECREL) + .Case("L", VK_PPC_LO) + .Case("l", VK_PPC_LO) + .Case("H", VK_PPC_HI) + .Case("h", VK_PPC_HI) + .Case("HA", VK_PPC_HA) + .Case("ha", VK_PPC_HA) + .Case("HIGHER", VK_PPC_HIGHER) + .Case("higher", VK_PPC_HIGHER) + .Case("HIGHERA", VK_PPC_HIGHERA) + .Case("highera", VK_PPC_HIGHERA) + .Case("HIGHEST", VK_PPC_HIGHEST) + .Case("highest", VK_PPC_HIGHEST) + .Case("HIGHESTA", VK_PPC_HIGHESTA) + .Case("highesta", VK_PPC_HIGHESTA) + .Case("GOT@L", VK_PPC_GOT_LO) + .Case("got@l", VK_PPC_GOT_LO) + .Case("GOT@H", VK_PPC_GOT_HI) + .Case("got@h", VK_PPC_GOT_HI) + .Case("GOT@HA", VK_PPC_GOT_HA) + .Case("got@ha", VK_PPC_GOT_HA) + .Case("TOCBASE", VK_PPC_TOCBASE) + .Case("tocbase", VK_PPC_TOCBASE) + .Case("TOC", VK_PPC_TOC) + .Case("toc", VK_PPC_TOC) + .Case("TOC@L", VK_PPC_TOC_LO) + .Case("toc@l", VK_PPC_TOC_LO) + .Case("TOC@H", VK_PPC_TOC_HI) + .Case("toc@h", VK_PPC_TOC_HI) + .Case("TOC@HA", VK_PPC_TOC_HA) + .Case("toc@ha", VK_PPC_TOC_HA) + .Case("TLS", VK_PPC_TLS) + .Case("tls", VK_PPC_TLS) + .Case("DTPMOD", VK_PPC_DTPMOD) + .Case("dtpmod", VK_PPC_DTPMOD) + .Case("TPREL", VK_PPC_TPREL) + .Case("tprel", VK_PPC_TPREL) + .Case("TPREL@L", VK_PPC_TPREL_LO) + .Case("tprel@l", VK_PPC_TPREL_LO) + .Case("TPREL@H", VK_PPC_TPREL_HI) + .Case("tprel@h", VK_PPC_TPREL_HI) + .Case("TPREL@HA", VK_PPC_TPREL_HA) + .Case("tprel@ha", VK_PPC_TPREL_HA) + .Case("TPREL@HIGHER", VK_PPC_TPREL_HIGHER) + .Case("tprel@higher", VK_PPC_TPREL_HIGHER) + .Case("TPREL@HIGHERA", VK_PPC_TPREL_HIGHERA) + .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) + .Case("TPREL@HIGHEST", VK_PPC_TPREL_HIGHEST) + .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) + .Case("TPREL@HIGHESTA", VK_PPC_TPREL_HIGHESTA) + .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) + .Case("DTPREL", VK_PPC_DTPREL) + .Case("dtprel", VK_PPC_DTPREL) + .Case("DTPREL@L", VK_PPC_DTPREL_LO) + .Case("dtprel@l", VK_PPC_DTPREL_LO) + .Case("DTPREL@H", VK_PPC_DTPREL_HI) + .Case("dtprel@h", VK_PPC_DTPREL_HI) + .Case("DTPREL@HA", VK_PPC_DTPREL_HA) + .Case("dtprel@ha", VK_PPC_DTPREL_HA) + .Case("DTPREL@HIGHER", VK_PPC_DTPREL_HIGHER) + .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) + .Case("DTPREL@HIGHERA", VK_PPC_DTPREL_HIGHERA) + .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) + .Case("DTPREL@HIGHEST", VK_PPC_DTPREL_HIGHEST) + .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) + .Case("DTPREL@HIGHESTA", VK_PPC_DTPREL_HIGHESTA) + .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) + .Case("GOT@TPREL", VK_PPC_GOT_TPREL) + .Case("got@tprel", VK_PPC_GOT_TPREL) + .Case("GOT@TPREL@L", VK_PPC_GOT_TPREL_LO) + .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) + .Case("GOT@TPREL@H", VK_PPC_GOT_TPREL_HI) + .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) + .Case("GOT@TPREL@HA", VK_PPC_GOT_TPREL_HA) + .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) + .Case("GOT@DTPREL", VK_PPC_GOT_DTPREL) + .Case("got@dtprel", VK_PPC_GOT_DTPREL) + .Case("GOT@DTPREL@L", VK_PPC_GOT_DTPREL_LO) + .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) + .Case("GOT@DTPREL@H", VK_PPC_GOT_DTPREL_HI) + .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) + .Case("GOT@DTPREL@HA", VK_PPC_GOT_DTPREL_HA) + .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) + .Case("GOT@TLSGD", VK_PPC_GOT_TLSGD) + .Case("got@tlsgd", VK_PPC_GOT_TLSGD) + .Case("GOT@TLSGD@L", VK_PPC_GOT_TLSGD_LO) + .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) + .Case("GOT@TLSGD@H", VK_PPC_GOT_TLSGD_HI) + .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) + .Case("GOT@TLSGD@HA", VK_PPC_GOT_TLSGD_HA) + .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) + .Case("GOT@TLSLD", VK_PPC_GOT_TLSLD) + .Case("got@tlsld", VK_PPC_GOT_TLSLD) + .Case("GOT@TLSLD@L", VK_PPC_GOT_TLSLD_LO) + .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) + .Case("GOT@TLSLD@H", VK_PPC_GOT_TLSLD_HI) + .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) + .Case("GOT@TLSLD@HA", VK_PPC_GOT_TLSLD_HA) + .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) + .Default(VK_Invalid); +} + +/* *** */ + +void MCTargetExpr::anchor() {} + +/* *** */ + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { + return EvaluateAsAbsolute(Res, 0, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout) const { + return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, 0); +} + +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, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs) const { + MCValue Value; + + // Fast path constants. + if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(this)) { + Res = CE->getValue(); + return true; + } + + // 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. + bool IsRelocatable = + EvaluateAsRelocatableImpl(Value, Asm, Layout, Addrs, /*InSet*/ Addrs); + + // Record the current value. + Res = Value.getConstant(); + + return IsRelocatable && Value.isAbsolute(); +} + +/// \brief 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; + + MCSymbolData &AD = Asm->getSymbolData(SA); + MCSymbolData &BD = Asm->getSymbolData(SB); + + if (AD.getFragment() == BD.getFragment()) { + Addend += (AD.getOffset() - BD.getOffset()); + + // Pointers to Thumb symbols need to have their low-bit set to allow + // for interworking. + if (Asm->isThumbFunc(&SA)) + Addend |= 1; + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = 0; + return; + } + + if (!Layout) + return; + + const MCSectionData &SecA = *AD.getFragment()->getParent(); + const MCSectionData &SecB = *BD.getFragment()->getParent(); + + if ((&SecA != &SecB) && !Addrs) + return; + + // Eagerly evaluate. + Addend += (Layout->getSymbolOffset(&Asm->getSymbolData(A->getSymbol())) - + Layout->getSymbolOffset(&Asm->getSymbolData(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; + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = 0; +} + +/// \brief 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. + if (Asm) { + // 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; + + // If we have a negated symbol, then we must have also have a non-negated + // symbol in order to encode the expression. + if (B && !A) + return false; + + Res = MCValue::get(A, B, Result_Cst); + return true; +} + +bool MCExpr::EvaluateAsRelocatable(MCValue &Res, + const MCAsmLayout &Layout) const { + return EvaluateAsRelocatableImpl(Res, &Layout.getAssembler(), &Layout, + 0, false); +} + +bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet) const { + ++stats::MCExprEvaluate; + + switch (getKind()) { + case Target: + return cast<MCTargetExpr>(this)->EvaluateAsRelocatableImpl(Res, Layout); + + 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) { + bool Ret = Sym.getVariableValue()->EvaluateAsRelocatableImpl(Res, Asm, + Layout, + Addrs, + true); + // If we failed to simplify this to a constant, let the target + // handle it. + if (Ret && !Res.getSymA() && !Res.getSymB()) + return true; + } + + Res = MCValue::get(SRE, 0, 0); + return true; + } + + case Unary: { + const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this); + MCValue Value; + + if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Asm, Layout, + 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; + Res = MCValue::get(Value.getSymB(), Value.getSymA(), + -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, + Addrs, InSet) || + !ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Asm, Layout, + Addrs, InSet)) + 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. + return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, + RHSValue.getSymB(), RHSValue.getSymA(), + -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 and right shifts + // differently from Apple as. + int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant(); + int64_t Result = 0; + switch (ABE->getOpcode()) { + case MCBinaryExpr::Add: Result = LHS + RHS; break; + case MCBinaryExpr::And: Result = LHS & RHS; break; + case MCBinaryExpr::Div: 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::LT: Result = LHS < RHS; break; + case MCBinaryExpr::LTE: Result = LHS <= RHS; break; + case MCBinaryExpr::Mod: 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 = LHS << RHS; break; + case MCBinaryExpr::Shr: Result = LHS >> RHS; break; + case MCBinaryExpr::Sub: Result = LHS - RHS; break; + case MCBinaryExpr::Xor: Result = LHS ^ RHS; break; + } + + Res = MCValue::get(Result); + return true; + } + } + + llvm_unreachable("Invalid assembly expression kind!"); +} + +const MCSection *MCExpr::FindAssociatedSection() const { + switch (getKind()) { + case Target: + // We never look through target specific expressions. + return cast<MCTargetExpr>(this)->FindAssociatedSection(); + + case Constant: + return MCSymbol::AbsolutePseudoSection; + + case SymbolRef: { + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(this); + const MCSymbol &Sym = SRE->getSymbol(); + + if (Sym.isDefined()) + return &Sym.getSection(); + + return 0; + } + + case Unary: + return cast<MCUnaryExpr>(this)->getSubExpr()->FindAssociatedSection(); + + case Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(this); + const MCSection *LHS_S = BE->getLHS()->FindAssociatedSection(); + const MCSection *RHS_S = BE->getRHS()->FindAssociatedSection(); + + // If either section is absolute, return the other. + if (LHS_S == MCSymbol::AbsolutePseudoSection) + return RHS_S; + if (RHS_S == MCSymbol::AbsolutePseudoSection) + return LHS_S; + + // Otherwise, return the first non-null section. + return LHS_S ? LHS_S : RHS_S; + } + } + + llvm_unreachable("Invalid assembly expression kind!"); +} diff --git a/contrib/llvm/lib/MC/MCExternalSymbolizer.cpp b/contrib/llvm/lib/MC/MCExternalSymbolizer.cpp new file mode 100644 index 000000000000..ca368b27e195 --- /dev/null +++ b/contrib/llvm/lib/MC/MCExternalSymbolizer.cpp @@ -0,0 +1,181 @@ +//===-- lib/MC/MCExternalSymbolizer.cpp - External symbolizer ---*- 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/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; + +// 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)); + if (!SymbolLookUp) + 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; + } + // 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 = NULL; + 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 = NULL; + 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 = NULL; + 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 != 0) + Expr = MCBinaryExpr::CreateAdd(LHS, Off, Ctx); + else + Expr = LHS; + } else if (Add) { + if (Off != 0) + Expr = MCBinaryExpr::CreateAdd(Add, Off, Ctx); + else + Expr = Add; + } else { + if (Off != 0) + 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: \"" << ReferenceName << "\""; + 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(StringRef TT, LLVMOpInfoCallback GetOpInfo, + LLVMSymbolLookupCallback SymbolLookUp, + void *DisInfo, + MCContext *Ctx, + MCRelocationInfo *RelInfo) { + assert(Ctx != 0 && "No MCContext given for symbolic disassembly"); + + OwningPtr<MCRelocationInfo> RelInfoOwingPtr(RelInfo); + return new MCExternalSymbolizer(*Ctx, RelInfoOwingPtr, GetOpInfo, + SymbolLookUp, DisInfo); +} +} diff --git a/contrib/llvm/lib/MC/MCFunction.cpp b/contrib/llvm/lib/MC/MCFunction.cpp new file mode 100644 index 000000000000..767e1e0f470f --- /dev/null +++ b/contrib/llvm/lib/MC/MCFunction.cpp @@ -0,0 +1,81 @@ +//===-- lib/MC/MCFunction.cpp -----------------------------------*- 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/MCFunction.h" +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCModule.h" +#include <algorithm> + +using namespace llvm; + +// MCFunction + +MCFunction::MCFunction(StringRef Name, MCModule *Parent) + : Name(Name), ParentModule(Parent) +{} + +MCFunction::~MCFunction() { + for (iterator I = begin(), E = end(); I != E; ++I) + delete *I; +} + +MCBasicBlock &MCFunction::createBlock(const MCTextAtom &TA) { + MCBasicBlock *MCBB = new MCBasicBlock(TA, this); + Blocks.push_back(MCBB); + return *MCBB; +} + +MCBasicBlock *MCFunction::find(uint64_t StartAddr) { + for (const_iterator I = begin(), E = end(); I != E; ++I) + if ((*I)->getInsts()->getBeginAddr() == StartAddr) + return *I; + return 0; +} + +const MCBasicBlock *MCFunction::find(uint64_t StartAddr) const { + return const_cast<MCFunction *>(this)->find(StartAddr); +} + +// MCBasicBlock + +MCBasicBlock::MCBasicBlock(const MCTextAtom &Insts, MCFunction *Parent) + : Insts(&Insts), Parent(Parent) { + getParent()->getParent()->trackBBForAtom(&Insts, this); +} + +void MCBasicBlock::addSuccessor(const MCBasicBlock *MCBB) { + if (!isSuccessor(MCBB)) + Successors.push_back(MCBB); +} + +bool MCBasicBlock::isSuccessor(const MCBasicBlock *MCBB) const { + return std::find(Successors.begin(), Successors.end(), + MCBB) != Successors.end(); +} + +void MCBasicBlock::addPredecessor(const MCBasicBlock *MCBB) { + if (!isPredecessor(MCBB)) + Predecessors.push_back(MCBB); +} + +bool MCBasicBlock::isPredecessor(const MCBasicBlock *MCBB) const { + return std::find(Predecessors.begin(), Predecessors.end(), + MCBB) != Predecessors.end(); +} + +void MCBasicBlock::splitBasicBlock(MCBasicBlock *SplitBB) { + assert(Insts->getEndAddr() + 1 == SplitBB->Insts->getBeginAddr() && + "Splitting unrelated basic blocks!"); + SplitBB->addPredecessor(this); + assert(SplitBB->Successors.empty() && + "Split basic block shouldn't already have successors!"); + SplitBB->Successors = Successors; + Successors.clear(); + addSuccessor(SplitBB); +} diff --git a/contrib/llvm/lib/MC/MCInst.cpp b/contrib/llvm/lib/MC/MCInst.cpp new file mode 100644 index 000000000000..124cc149beb6 --- /dev/null +++ b/contrib/llvm/lib/MC/MCInst.cpp @@ -0,0 +1,72 @@ +//===- 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/MC/MCExpr.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void MCOperand::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + OS << "<MCOperand "; + if (!isValid()) + OS << "INVALID"; + else if (isReg()) + OS << "Reg:" << getReg(); + else if (isImm()) + OS << "Imm:" << getImm(); + else if (isExpr()) { + OS << "Expr:(" << *getExpr() << ")"; + } else if (isInst()) { + OS << "Inst:(" << *getInst() << ")"; + } else + OS << "UNDEFINED"; + OS << ">"; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCOperand::dump() const { + print(dbgs(), 0); + dbgs() << "\n"; +} +#endif + +void MCInst::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + OS << "<MCInst " << getOpcode(); + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + OS << " "; + getOperand(i).print(OS, MAI); + } + OS << ">"; +} + +void MCInst::dump_pretty(raw_ostream &OS, const MCAsmInfo *MAI, + const MCInstPrinter *Printer, + StringRef Separator) const { + OS << "<MCInst #" << getOpcode(); + + // Show the instruction opcode name if we have access to a printer. + if (Printer) + OS << ' ' << Printer->getOpcodeName(getOpcode()); + + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + OS << Separator; + getOperand(i).print(OS, MAI); + } + OS << ">"; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCInst::dump() const { + print(dbgs(), 0); + 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..ba71245d0184 --- /dev/null +++ b/contrib/llvm/lib/MC/MCInstPrinter.cpp @@ -0,0 +1,110 @@ +//===-- 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/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" +using namespace llvm; + +MCInstPrinter::~MCInstPrinter() { +} + +/// 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_object1<int64_t> MCInstPrinter::formatDec(const int64_t Value) const { + return format("%" PRId64, Value); +} + +format_object1<int64_t> MCInstPrinter::formatHex(const 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_object1<uint64_t> MCInstPrinter::formatHex(const 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..2d8336d77ac7 --- /dev/null +++ b/contrib/llvm/lib/MC/MCInstrAnalysis.cpp @@ -0,0 +1,22 @@ +//===-- MCInstrAnalysis.cpp - InstrDesc target hooks ------------*- 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/MCInstrAnalysis.h" +using namespace llvm; + +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/MCLabel.cpp b/contrib/llvm/lib/MC/MCLabel.cpp new file mode 100644 index 000000000000..1d3022a93e86 --- /dev/null +++ b/contrib/llvm/lib/MC/MCLabel.cpp @@ -0,0 +1,23 @@ +//===- 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/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) +void MCLabel::dump() const { + print(dbgs()); +} +#endif diff --git a/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp new file mode 100644 index 000000000000..2924dcd87630 --- /dev/null +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -0,0 +1,440 @@ +//===-- 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/MC/MCStreamer.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCMachOSymbolFlags.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Dwarf.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +class MCMachOStreamer : public MCObjectStreamer { +private: + virtual void EmitInstToData(const MCInst &Inst); + + void EmitDataRegion(DataRegionData::KindTy Kind); + void EmitDataRegionEnd(); +public: + MCMachOStreamer(MCContext &Context, MCAsmBackend &MAB, raw_ostream &OS, + MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, 0, MAB, OS, Emitter) {} + + /// @name MCStreamer Interface + /// @{ + + virtual void InitSections(); + virtual void InitToTextSection(); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitDebugLabel(MCSymbol *Symbol); + virtual void EmitEHSymAttributes(const MCSymbol *Symbol, + MCSymbol *EHSymbol); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitLinkerOptions(ArrayRef<std::string> Options); + virtual void EmitDataRegion(MCDataRegionType Kind); + virtual void EmitThumbFunc(MCSymbol *Func); + virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { + llvm_unreachable("macho doesn't support this directive"); + } + virtual void EmitCOFFSymbolStorageClass(int StorageClass) { + llvm_unreachable("macho doesn't support this directive"); + } + virtual void EmitCOFFSymbolType(int Type) { + llvm_unreachable("macho doesn't support this directive"); + } + virtual void EndCOFFSymbolDef() { + llvm_unreachable("macho doesn't support this directive"); + } + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + llvm_unreachable("macho doesn't support this directive"); + } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + uint64_t Size = 0, unsigned ByteAlignment = 0); + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0); + + virtual void EmitFileDirective(StringRef Filename) { + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + // report_fatal_error("unsupported directive: '.file'"); + } + + virtual void EmitIdent(StringRef IdentString) { + llvm_unreachable("macho doesn't support this directive"); + } + + virtual void FinishImpl(); +}; + +} // end anonymous namespace. + +void MCMachOStreamer::InitSections() { + InitToTextSection(); +} + +void MCMachOStreamer::InitToTextSection() { + SwitchSection(getContext().getMachOSection( + "__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, 0, + SectionKind::getText())); +} + +void MCMachOStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, + MCSymbol *EHSymbol) { + MCSymbolData &SD = + getAssembler().getOrCreateSymbolData(*Symbol); + if (SD.isExternal()) + EmitSymbolAttribute(EHSymbol, MCSA_Global); + if (SD.getFlags() & SF_WeakDefinition) + EmitSymbolAttribute(EHSymbol, MCSA_WeakDefinition); + if (SD.isPrivateExtern()) + EmitSymbolAttribute(EHSymbol, MCSA_PrivateExtern); +} + +void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + // isSymbolLinkerVisible uses the section. + AssignSection(Symbol, getCurrentSection().first); + // 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); + + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); + // 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. + SD.setFlags(SD.getFlags() & ~SF_ReferenceTypeMask); +} + +void MCMachOStreamer::EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); +} +void MCMachOStreamer::EmitDataRegion(DataRegionData::KindTy Kind) { + if (!getAssembler().getBackend().hasDataInCodeSupport()) + return; + // 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, NULL }; + std::vector<DataRegionData> &Regions = getAssembler().getDataRegions(); + Regions.push_back(Data); +} + +void MCMachOStreamer::EmitDataRegionEnd() { + if (!getAssembler().getBackend().hasDataInCodeSupport()) + return; + std::vector<DataRegionData> &Regions = getAssembler().getDataRegions(); + assert(Regions.size() && "Mismatched .end_data_region!"); + DataRegionData &Data = Regions.back(); + assert(Data.End == NULL && "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::EmitThumbFunc(MCSymbol *Symbol) { + // Remember that the function is a thumb function. Fixup and relocation + // values will need adjusted. + getAssembler().setIsThumbFunc(Symbol); + + // Mark the thumb bit on the symbol. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setFlags(SD.getFlags() | SF_ThumbFunc); +} + +bool MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + MCSymbolAttr Attribute) { + // 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.SectionData = getCurrentSectionData(); + getAssembler().getIndirectSymbols().push_back(ISD); + return true; + } + + // Adding a symbol attribute always introduces the symbol, note that an + // important side effect of calling getOrCreateSymbolData here is to register + // the symbol with the assembler. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*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: + SD.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. + SD.setFlags(SD.getFlags() & ~SF_ReferenceTypeUndefinedLazy); + break; + + case MCSA_LazyReference: + // FIXME: This requires -dynamic. + SD.setFlags(SD.getFlags() | SF_NoDeadStrip); + if (Symbol->isUndefined()) + SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy); + break; + + // Since .reference sets the no dead strip bit, it is equivalent to + // .no_dead_strip in practice. + case MCSA_Reference: + case MCSA_NoDeadStrip: + SD.setFlags(SD.getFlags() | SF_NoDeadStrip); + break; + + case MCSA_SymbolResolver: + SD.setFlags(SD.getFlags() | SF_SymbolResolver); + break; + + case MCSA_PrivateExtern: + SD.setExternal(true); + SD.setPrivateExtern(true); + break; + + case MCSA_WeakReference: + // FIXME: This requires -dynamic. + if (Symbol->isUndefined()) + SD.setFlags(SD.getFlags() | SF_WeakReference); + 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. + SD.setFlags(SD.getFlags() | SF_WeakDefinition); + break; + + case MCSA_WeakDefAutoPrivate: + SD.setFlags(SD.getFlags() | SF_WeakDefinition | SF_WeakReference); + break; + } + + return true; +} + +void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + // Encode the 'desc' value into the lowest implementation defined bits. + assert(DescValue == (DescValue & SF_DescFlagsMask) && + "Invalid .desc value!"); + getAssembler().getOrCreateSymbolData(*Symbol).setFlags( + DescValue & SF_DescFlagsMask); +} + +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!"); + + AssignSection(Symbol, NULL); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setExternal(true); + SD.setCommon(Size, ByteAlignment); +} + +void MCMachOStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + // '.lcomm' is equivalent to '.zerofill'. + return EmitZerofill(getContext().getMachOSection("__DATA", "__bss", + MCSectionMachO::S_ZEROFILL, + 0, SectionKind::getBSS()), + Symbol, Size, ByteAlignment); +} + +void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + MCSectionData &SectData = getAssembler().getOrCreateSectionData(*Section); + + // The symbol may not be present, which only creates the section. + if (!Symbol) + return; + + // On darwin all virtual sections have zerofill type. + assert(Section->isVirtualSection() && "Section does not have zerofill type!"); + + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // Emit an align fragment if necessary. + if (ByteAlignment != 1) + new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, &SectData); + + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD.setFragment(F); + + AssignSection(Symbol, Section); + + // Update the maximum alignment on the zero fill section if necessary. + if (ByteAlignment > SectData.getAlignment()) + SectData.setAlignment(ByteAlignment); +} + +// 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(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + EmitZerofill(Section, Symbol, Size, ByteAlignment); + return; +} + +void MCMachOStreamer::EmitInstToData(const MCInst &Inst) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // 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->getContents().append(Code.begin(), Code.end()); +} + +void MCMachOStreamer::FinishImpl() { + EmitFrames(&getAssembler().getBackend(), true); + + // 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*, MCSymbolData*> DefiningSymbolMap; + for (MCAssembler::symbol_iterator it = getAssembler().symbol_begin(), + ie = getAssembler().symbol_end(); it != ie; ++it) { + if (getAssembler().isSymbolLinkerVisible(it->getSymbol()) && + it->getFragment()) { + // An atom defining symbol should never be internal to a fragment. + assert(it->getOffset() == 0 && "Invalid offset in atom defining symbol!"); + DefiningSymbolMap[it->getFragment()] = it; + } + } + + // Set the fragment atom associations by tracking the last seen atom defining + // symbol. + for (MCAssembler::iterator it = getAssembler().begin(), + ie = getAssembler().end(); it != ie; ++it) { + MCSymbolData *CurrentAtom = 0; + for (MCSectionData::iterator it2 = it->begin(), + ie2 = it->end(); it2 != ie2; ++it2) { + if (MCSymbolData *SD = DefiningSymbolMap.lookup(it2)) + CurrentAtom = SD; + it2->setAtom(CurrentAtom); + } + } + + this->MCObjectStreamer::FinishImpl(); +} + +MCStreamer *llvm::createMachOStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll) { + MCMachOStreamer *S = new MCMachOStreamer(Context, MAB, OS, CE); + 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..146cebf01a3a --- /dev/null +++ b/contrib/llvm/lib/MC/MCMachObjectTargetWriter.cpp @@ -0,0 +1,22 @@ +//===-- 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_, + bool UseAggressiveSymbolFolding_) + : Is64Bit(Is64Bit_), CPUType(CPUType_), CPUSubtype(CPUSubtype_), + UseAggressiveSymbolFolding(UseAggressiveSymbolFolding_) { +} + +MCMachObjectTargetWriter::~MCMachObjectTargetWriter() { +} diff --git a/contrib/llvm/lib/MC/MCModule.cpp b/contrib/llvm/lib/MC/MCModule.cpp new file mode 100644 index 000000000000..7e9e18a5a917 --- /dev/null +++ b/contrib/llvm/lib/MC/MCModule.cpp @@ -0,0 +1,142 @@ +//===- lib/MC/MCModule.cpp - MCModule 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/MCModule.h" +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCFunction.h" +#include <algorithm> + +using namespace llvm; + +static bool AtomComp(const MCAtom *L, uint64_t Addr) { + return L->getEndAddr() < Addr; +} + +static bool AtomCompInv(uint64_t Addr, const MCAtom *R) { + return Addr < R->getEndAddr(); +} + +void MCModule::map(MCAtom *NewAtom) { + uint64_t Begin = NewAtom->Begin; + + assert(Begin <= NewAtom->End && "Creating MCAtom with endpoints reversed?"); + + // Check for atoms already covering this range. + AtomListTy::iterator I = std::lower_bound(atom_begin(), atom_end(), + Begin, AtomComp); + assert((I == atom_end() || (*I)->getBeginAddr() > NewAtom->End) + && "Offset range already occupied!"); + + // Insert the new atom to the list. + Atoms.insert(I, NewAtom); +} + +MCTextAtom *MCModule::createTextAtom(uint64_t Begin, uint64_t End) { + MCTextAtom *NewAtom = new MCTextAtom(this, Begin, End); + map(NewAtom); + return NewAtom; +} + +MCDataAtom *MCModule::createDataAtom(uint64_t Begin, uint64_t End) { + MCDataAtom *NewAtom = new MCDataAtom(this, Begin, End); + map(NewAtom); + return NewAtom; +} + +// remap - Update the interval mapping for an atom. +void MCModule::remap(MCAtom *Atom, uint64_t NewBegin, uint64_t NewEnd) { + // Find and erase the old mapping. + AtomListTy::iterator I = std::lower_bound(atom_begin(), atom_end(), + Atom->Begin, AtomComp); + assert(I != atom_end() && "Atom offset not found in module!"); + assert(*I == Atom && "Previous atom mapping was invalid!"); + Atoms.erase(I); + + // FIXME: special case NewBegin == Atom->Begin + + // Insert the new mapping. + AtomListTy::iterator NewI = std::lower_bound(atom_begin(), atom_end(), + NewBegin, AtomComp); + assert((NewI == atom_end() || (*NewI)->getBeginAddr() > Atom->End) + && "Offset range already occupied!"); + Atoms.insert(NewI, Atom); + + // Update the atom internal bounds. + Atom->Begin = NewBegin; + Atom->End = NewEnd; +} + +const MCAtom *MCModule::findAtomContaining(uint64_t Addr) const { + AtomListTy::const_iterator I = std::lower_bound(atom_begin(), atom_end(), + Addr, AtomComp); + if (I != atom_end() && (*I)->getBeginAddr() <= Addr) + return *I; + return 0; +} + +MCAtom *MCModule::findAtomContaining(uint64_t Addr) { + return const_cast<MCAtom*>( + const_cast<const MCModule *>(this)->findAtomContaining(Addr)); +} + +const MCAtom *MCModule::findFirstAtomAfter(uint64_t Addr) const { + AtomListTy::const_iterator I = std::upper_bound(atom_begin(), atom_end(), + Addr, AtomCompInv); + if (I != atom_end()) + return *I; + return 0; +} + +MCAtom *MCModule::findFirstAtomAfter(uint64_t Addr) { + return const_cast<MCAtom*>( + const_cast<const MCModule *>(this)->findFirstAtomAfter(Addr)); +} + +MCFunction *MCModule::createFunction(StringRef Name) { + Functions.push_back(new MCFunction(Name, this)); + return Functions.back(); +} + +static bool CompBBToAtom(MCBasicBlock *BB, const MCTextAtom *Atom) { + return BB->getInsts() < Atom; +} + +void MCModule::splitBasicBlocksForAtom(const MCTextAtom *TA, + const MCTextAtom *NewTA) { + BBsByAtomTy::iterator + I = std::lower_bound(BBsByAtom.begin(), BBsByAtom.end(), + TA, CompBBToAtom); + for (; I != BBsByAtom.end() && (*I)->getInsts() == TA; ++I) { + MCBasicBlock *BB = *I; + MCBasicBlock *NewBB = &BB->getParent()->createBlock(*NewTA); + BB->splitBasicBlock(NewBB); + } +} + +void MCModule::trackBBForAtom(const MCTextAtom *Atom, MCBasicBlock *BB) { + assert(Atom == BB->getInsts() && "Text atom doesn't back the basic block!"); + BBsByAtomTy::iterator I = std::lower_bound(BBsByAtom.begin(), + BBsByAtom.end(), + Atom, CompBBToAtom); + for (; I != BBsByAtom.end() && (*I)->getInsts() == Atom; ++I) + if (*I == BB) + return; + BBsByAtom.insert(I, BB); +} + +MCModule::~MCModule() { + for (AtomListTy::iterator AI = atom_begin(), + AE = atom_end(); + AI != AE; ++AI) + delete *AI; + for (FunctionListTy::iterator FI = func_begin(), + FE = func_end(); + FI != FE; ++FI) + delete *FI; +} diff --git a/contrib/llvm/lib/MC/MCModuleYAML.cpp b/contrib/llvm/lib/MC/MCModuleYAML.cpp new file mode 100644 index 000000000000..e2de57849b92 --- /dev/null +++ b/contrib/llvm/lib/MC/MCModuleYAML.cpp @@ -0,0 +1,461 @@ +//===- MCModuleYAML.cpp - MCModule YAMLIO implementation ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines classes for handling the YAML representation of MCModule. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCModuleYAML.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCFunction.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Object/YAML.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/YAMLTraits.h" +#include <vector> + +namespace llvm { + +namespace { + +// This class is used to map opcode and register names to enum values. +// +// There are at least 3 obvious ways to do this: +// 1- Generate an MII/MRI method using a tablegen StringMatcher +// 2- Write an MII/MRI method using std::lower_bound and the assumption that +// the enums are sorted (starting at a fixed value). +// 3- Do the matching manually as is done here. +// +// Why 3? +// 1- A StringMatcher function for thousands of entries would incur +// a non-negligible binary size overhead. +// 2- The lower_bound comparators would be somewhat involved and aren't +// obviously reusable (see LessRecordRegister in llvm/TableGen/Record.h) +// 3- This isn't actually something useful outside tests (but the same argument +// can be made against having {MII,MRI}::getName). +// +// If this becomes useful outside this specific situation, feel free to do +// the Right Thing (tm) and move the functionality to MII/MRI. +// +class InstrRegInfoHolder { + typedef StringMap<unsigned, BumpPtrAllocator> EnumValByNameTy; + EnumValByNameTy InstEnumValueByName; + EnumValByNameTy RegEnumValueByName; + +public: + const MCInstrInfo &MII; + const MCRegisterInfo &MRI; + InstrRegInfoHolder(const MCInstrInfo &MII, const MCRegisterInfo &MRI) + : InstEnumValueByName(NextPowerOf2(MII.getNumOpcodes())), + RegEnumValueByName(NextPowerOf2(MRI.getNumRegs())), MII(MII), MRI(MRI) { + for (int i = 0, e = MII.getNumOpcodes(); i != e; ++i) + InstEnumValueByName[MII.getName(i)] = i; + for (int i = 0, e = MRI.getNumRegs(); i != e; ++i) + RegEnumValueByName[MRI.getName(i)] = i; + } + + bool matchRegister(StringRef Name, unsigned &Reg) { + EnumValByNameTy::const_iterator It = RegEnumValueByName.find(Name); + if (It == RegEnumValueByName.end()) + return false; + Reg = It->getValue(); + return true; + } + bool matchOpcode(StringRef Name, unsigned &Opc) { + EnumValByNameTy::const_iterator It = InstEnumValueByName.find(Name); + if (It == InstEnumValueByName.end()) + return false; + Opc = It->getValue(); + return true; + } +}; + +} // end unnamed namespace + +namespace MCModuleYAML { + +LLVM_YAML_STRONG_TYPEDEF(unsigned, OpcodeEnum) + +struct Operand { + MCOperand MCOp; +}; + +struct Inst { + OpcodeEnum Opcode; + std::vector<Operand> Operands; + uint64_t Size; +}; + +struct Atom { + MCAtom::AtomKind Type; + yaml::Hex64 StartAddress; + uint64_t Size; + + std::vector<Inst> Insts; + object::yaml::BinaryRef Data; +}; + +struct BasicBlock { + yaml::Hex64 Address; + std::vector<yaml::Hex64> Preds; + std::vector<yaml::Hex64> Succs; +}; + +struct Function { + StringRef Name; + std::vector<BasicBlock> BasicBlocks; +}; + +struct Module { + std::vector<Atom> Atoms; + std::vector<Function> Functions; +}; + +} // end namespace MCModuleYAML +} // end namespace llvm + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::Hex64) +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::MCModuleYAML::Operand) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Inst) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Atom) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::BasicBlock) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MCModuleYAML::Function) + +namespace llvm { + +namespace yaml { + +template <> struct ScalarEnumerationTraits<MCAtom::AtomKind> { + static void enumeration(IO &IO, MCAtom::AtomKind &Kind); +}; + +template <> struct MappingTraits<MCModuleYAML::Atom> { + static void mapping(IO &IO, MCModuleYAML::Atom &A); +}; + +template <> struct MappingTraits<MCModuleYAML::Inst> { + static void mapping(IO &IO, MCModuleYAML::Inst &I); +}; + +template <> struct MappingTraits<MCModuleYAML::BasicBlock> { + static void mapping(IO &IO, MCModuleYAML::BasicBlock &BB); +}; + +template <> struct MappingTraits<MCModuleYAML::Function> { + static void mapping(IO &IO, MCModuleYAML::Function &Fn); +}; + +template <> struct MappingTraits<MCModuleYAML::Module> { + static void mapping(IO &IO, MCModuleYAML::Module &M); +}; + +template <> struct ScalarTraits<MCModuleYAML::Operand> { + static void output(const MCModuleYAML::Operand &, void *, + llvm::raw_ostream &); + static StringRef input(StringRef, void *, MCModuleYAML::Operand &); +}; + +template <> struct ScalarTraits<MCModuleYAML::OpcodeEnum> { + static void output(const MCModuleYAML::OpcodeEnum &, void *, + llvm::raw_ostream &); + static StringRef input(StringRef, void *, MCModuleYAML::OpcodeEnum &); +}; + +void ScalarEnumerationTraits<MCAtom::AtomKind>::enumeration( + IO &IO, MCAtom::AtomKind &Value) { + IO.enumCase(Value, "Text", MCAtom::TextAtom); + IO.enumCase(Value, "Data", MCAtom::DataAtom); +} + +void MappingTraits<MCModuleYAML::Atom>::mapping(IO &IO, MCModuleYAML::Atom &A) { + IO.mapRequired("StartAddress", A.StartAddress); + IO.mapRequired("Size", A.Size); + IO.mapRequired("Type", A.Type); + if (A.Type == MCAtom::TextAtom) + IO.mapRequired("Content", A.Insts); + else if (A.Type == MCAtom::DataAtom) + IO.mapRequired("Content", A.Data); +} + +void MappingTraits<MCModuleYAML::Inst>::mapping(IO &IO, MCModuleYAML::Inst &I) { + IO.mapRequired("Inst", I.Opcode); + IO.mapRequired("Size", I.Size); + IO.mapRequired("Ops", I.Operands); +} + +void +MappingTraits<MCModuleYAML::BasicBlock>::mapping(IO &IO, + MCModuleYAML::BasicBlock &BB) { + IO.mapRequired("Address", BB.Address); + IO.mapRequired("Preds", BB.Preds); + IO.mapRequired("Succs", BB.Succs); +} + +void MappingTraits<MCModuleYAML::Function>::mapping(IO &IO, + MCModuleYAML::Function &F) { + IO.mapRequired("Name", F.Name); + IO.mapRequired("BasicBlocks", F.BasicBlocks); +} + +void MappingTraits<MCModuleYAML::Module>::mapping(IO &IO, + MCModuleYAML::Module &M) { + IO.mapRequired("Atoms", M.Atoms); + IO.mapOptional("Functions", M.Functions); +} + +void +ScalarTraits<MCModuleYAML::Operand>::output(const MCModuleYAML::Operand &Val, + void *Ctx, raw_ostream &Out) { + InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; + + // FIXME: Doesn't support FPImm and expr/inst, but do these make sense? + if (Val.MCOp.isImm()) + Out << "I" << Val.MCOp.getImm(); + else if (Val.MCOp.isReg()) + Out << "R" << IRI->MRI.getName(Val.MCOp.getReg()); + else + llvm_unreachable("Trying to output invalid MCOperand!"); +} + +StringRef +ScalarTraits<MCModuleYAML::Operand>::input(StringRef Scalar, void *Ctx, + MCModuleYAML::Operand &Val) { + InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; + char Type = 0; + if (Scalar.size() >= 1) + Type = Scalar.front(); + if (Type != 'R' && Type != 'I') + return "Operand must start with 'R' (register) or 'I' (immediate)."; + if (Type == 'R') { + unsigned Reg; + if (!IRI->matchRegister(Scalar.substr(1), Reg)) + return "Invalid register name."; + Val.MCOp = MCOperand::CreateReg(Reg); + } else if (Type == 'I') { + int64_t RIVal; + if (Scalar.substr(1).getAsInteger(10, RIVal)) + return "Invalid immediate value."; + Val.MCOp = MCOperand::CreateImm(RIVal); + } else { + Val.MCOp = MCOperand(); + } + return StringRef(); +} + +void ScalarTraits<MCModuleYAML::OpcodeEnum>::output( + const MCModuleYAML::OpcodeEnum &Val, void *Ctx, raw_ostream &Out) { + InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; + Out << IRI->MII.getName(Val); +} + +StringRef +ScalarTraits<MCModuleYAML::OpcodeEnum>::input(StringRef Scalar, void *Ctx, + MCModuleYAML::OpcodeEnum &Val) { + InstrRegInfoHolder *IRI = (InstrRegInfoHolder *)Ctx; + unsigned Opc; + if (!IRI->matchOpcode(Scalar, Opc)) + return "Invalid instruction opcode."; + Val = Opc; + return ""; +} + +} // end namespace yaml + +namespace { + +class MCModule2YAML { + const MCModule &MCM; + MCModuleYAML::Module YAMLModule; + void dumpAtom(const MCAtom *MCA); + void dumpFunction(const MCFunction *MCF); + void dumpBasicBlock(const MCBasicBlock *MCBB); + +public: + MCModule2YAML(const MCModule &MCM); + MCModuleYAML::Module &getYAMLModule(); +}; + +class YAML2MCModule { + MCModule &MCM; + +public: + YAML2MCModule(MCModule &MCM); + StringRef parse(const MCModuleYAML::Module &YAMLModule); +}; + +} // end unnamed namespace + +MCModule2YAML::MCModule2YAML(const MCModule &MCM) : MCM(MCM), YAMLModule() { + for (MCModule::const_atom_iterator AI = MCM.atom_begin(), AE = MCM.atom_end(); + AI != AE; ++AI) + dumpAtom(*AI); + for (MCModule::const_func_iterator FI = MCM.func_begin(), FE = MCM.func_end(); + FI != FE; ++FI) + dumpFunction(*FI); +} + +void MCModule2YAML::dumpAtom(const MCAtom *MCA) { + YAMLModule.Atoms.resize(YAMLModule.Atoms.size() + 1); + MCModuleYAML::Atom &A = YAMLModule.Atoms.back(); + A.Type = MCA->getKind(); + A.StartAddress = MCA->getBeginAddr(); + A.Size = MCA->getEndAddr() - MCA->getBeginAddr() + 1; + if (const MCTextAtom *TA = dyn_cast<MCTextAtom>(MCA)) { + const size_t InstCount = TA->size(); + A.Insts.resize(InstCount); + for (size_t i = 0; i != InstCount; ++i) { + const MCDecodedInst &MCDI = TA->at(i); + A.Insts[i].Opcode = MCDI.Inst.getOpcode(); + A.Insts[i].Size = MCDI.Size; + const unsigned OpCount = MCDI.Inst.getNumOperands(); + A.Insts[i].Operands.resize(OpCount); + for (unsigned oi = 0; oi != OpCount; ++oi) + A.Insts[i].Operands[oi].MCOp = MCDI.Inst.getOperand(oi); + } + } else if (const MCDataAtom *DA = dyn_cast<MCDataAtom>(MCA)) { + A.Data = DA->getData(); + } else { + llvm_unreachable("Unknown atom type."); + } +} + +void MCModule2YAML::dumpFunction(const MCFunction *MCF) { + YAMLModule.Functions.resize(YAMLModule.Functions.size() + 1); + MCModuleYAML::Function &F = YAMLModule.Functions.back(); + F.Name = MCF->getName(); + for (MCFunction::const_iterator BBI = MCF->begin(), BBE = MCF->end(); + BBI != BBE; ++BBI) { + const MCBasicBlock *MCBB = *BBI; + F.BasicBlocks.resize(F.BasicBlocks.size() + 1); + MCModuleYAML::BasicBlock &BB = F.BasicBlocks.back(); + BB.Address = MCBB->getInsts()->getBeginAddr(); + for (MCBasicBlock::pred_const_iterator PI = MCBB->pred_begin(), + PE = MCBB->pred_end(); + PI != PE; ++PI) + BB.Preds.push_back((*PI)->getInsts()->getBeginAddr()); + for (MCBasicBlock::succ_const_iterator SI = MCBB->succ_begin(), + SE = MCBB->succ_end(); + SI != SE; ++SI) + BB.Succs.push_back((*SI)->getInsts()->getBeginAddr()); + } +} + +MCModuleYAML::Module &MCModule2YAML::getYAMLModule() { return YAMLModule; } + +YAML2MCModule::YAML2MCModule(MCModule &MCM) : MCM(MCM) {} + +StringRef YAML2MCModule::parse(const MCModuleYAML::Module &YAMLModule) { + typedef std::vector<MCModuleYAML::Atom>::const_iterator AtomIt; + typedef std::vector<MCModuleYAML::Inst>::const_iterator InstIt; + typedef std::vector<MCModuleYAML::Operand>::const_iterator OpIt; + + typedef DenseMap<uint64_t, MCTextAtom *> AddrToTextAtomTy; + AddrToTextAtomTy TAByAddr; + + for (AtomIt AI = YAMLModule.Atoms.begin(), AE = YAMLModule.Atoms.end(); + AI != AE; ++AI) { + uint64_t StartAddress = AI->StartAddress; + if (AI->Size == 0) + return "Atoms can't be empty!"; + uint64_t EndAddress = StartAddress + AI->Size - 1; + switch (AI->Type) { + case MCAtom::TextAtom: { + MCTextAtom *TA = MCM.createTextAtom(StartAddress, EndAddress); + TAByAddr[StartAddress] = TA; + for (InstIt II = AI->Insts.begin(), IE = AI->Insts.end(); II != IE; + ++II) { + MCInst MI; + MI.setOpcode(II->Opcode); + for (OpIt OI = II->Operands.begin(), OE = II->Operands.end(); OI != OE; + ++OI) + MI.addOperand(OI->MCOp); + TA->addInst(MI, II->Size); + } + break; + } + case MCAtom::DataAtom: { + MCDataAtom *DA = MCM.createDataAtom(StartAddress, EndAddress); + SmallVector<char, 64> Data; + raw_svector_ostream OS(Data); + AI->Data.writeAsBinary(OS); + OS.flush(); + for (size_t i = 0, e = Data.size(); i != e; ++i) + DA->addData((uint8_t)Data[i]); + break; + } + } + } + + typedef std::vector<MCModuleYAML::Function>::const_iterator FuncIt; + typedef std::vector<MCModuleYAML::BasicBlock>::const_iterator BBIt; + typedef std::vector<yaml::Hex64>::const_iterator AddrIt; + for (FuncIt FI = YAMLModule.Functions.begin(), + FE = YAMLModule.Functions.end(); + FI != FE; ++FI) { + MCFunction *MCFN = MCM.createFunction(FI->Name); + for (BBIt BBI = FI->BasicBlocks.begin(), BBE = FI->BasicBlocks.end(); + BBI != BBE; ++BBI) { + AddrToTextAtomTy::const_iterator It = TAByAddr.find(BBI->Address); + if (It == TAByAddr.end()) + return "Basic block start address doesn't match any text atom!"; + MCFN->createBlock(*It->second); + } + for (BBIt BBI = FI->BasicBlocks.begin(), BBE = FI->BasicBlocks.end(); + BBI != BBE; ++BBI) { + MCBasicBlock *MCBB = MCFN->find(BBI->Address); + if (!MCBB) + return "Couldn't find matching basic block in function."; + for (AddrIt PI = BBI->Preds.begin(), PE = BBI->Preds.end(); PI != PE; + ++PI) { + MCBasicBlock *Pred = MCFN->find(*PI); + if (!Pred) + return "Couldn't find predecessor basic block."; + MCBB->addPredecessor(Pred); + } + for (AddrIt SI = BBI->Succs.begin(), SE = BBI->Succs.end(); SI != SE; + ++SI) { + MCBasicBlock *Succ = MCFN->find(*SI); + if (!Succ) + return "Couldn't find predecessor basic block."; + MCBB->addSuccessor(Succ); + } + } + } + return ""; +} + +StringRef mcmodule2yaml(raw_ostream &OS, const MCModule &MCM, + const MCInstrInfo &MII, const MCRegisterInfo &MRI) { + MCModule2YAML Dumper(MCM); + InstrRegInfoHolder IRI(MII, MRI); + yaml::Output YOut(OS, (void *)&IRI); + YOut << Dumper.getYAMLModule(); + return ""; +} + +StringRef yaml2mcmodule(OwningPtr<MCModule> &MCM, StringRef YamlContent, + const MCInstrInfo &MII, const MCRegisterInfo &MRI) { + MCM.reset(new MCModule); + YAML2MCModule Parser(*MCM); + MCModuleYAML::Module YAMLModule; + InstrRegInfoHolder IRI(MII, MRI); + yaml::Input YIn(YamlContent, (void *)&IRI); + YIn >> YAMLModule; + if (error_code ec = YIn.error()) + return ec.message(); + StringRef err = Parser.parse(YAMLModule); + if (!err.empty()) + return err; + return ""; +} + +} // end namespace llvm diff --git a/contrib/llvm/lib/MC/MCNullStreamer.cpp b/contrib/llvm/lib/MC/MCNullStreamer.cpp new file mode 100644 index 000000000000..9b9c4aa2a0cd --- /dev/null +++ b/contrib/llvm/lib/MC/MCNullStreamer.cpp @@ -0,0 +1,118 @@ +//===- 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/MC/MCStreamer.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" + +using namespace llvm; + +namespace { + + class MCNullStreamer : public MCStreamer { + public: + MCNullStreamer(MCContext &Context) : MCStreamer(Context, 0) {} + + /// @name MCStreamer Interface + /// @{ + + virtual void InitToTextSection() { + } + + virtual void InitSections() { + } + + virtual void ChangeSection(const MCSection *Section, + const MCExpr *Subsection) { + } + + virtual void EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + assert(getCurrentSection().first &&"Cannot emit before setting section!"); + AssignSection(Symbol, getCurrentSection().first); + } + virtual void EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); + } + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} + virtual void EmitThumbFunc(MCSymbol *Func) {} + + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol){} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label, + unsigned PointerSize) {} + + virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){ + return true; + } + + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} + + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) {} + virtual void EmitCOFFSymbolStorageClass(int StorageClass) {} + virtual void EmitCOFFSymbolType(int Type) {} + virtual void EndCOFFSymbolDef() {} + virtual void EmitCOFFSecRel32(MCSymbol const *Symbol) {} + + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) {} + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + uint64_t Size = 0, unsigned ByteAlignment = 0) {} + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) {} + virtual void EmitBytes(StringRef Data) {} + + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size) {} + virtual void EmitULEB128Value(const MCExpr *Value) {} + virtual void EmitSLEB128Value(const MCExpr *Value) {} + virtual void EmitGPRel32Value(const MCExpr *Value) {} + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0) {} + + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0) {} + + virtual bool EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0) { return false; } + + virtual void EmitFileDirective(StringRef Filename) {} + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, unsigned CUID = 0) { + return false; + } + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator, + StringRef FileName) {} + virtual void EmitInstruction(const MCInst &Inst) {} + + virtual void EmitBundleAlignMode(unsigned AlignPow2) {} + virtual void EmitBundleLock(bool AlignToEnd) {} + virtual void EmitBundleUnlock() {} + + virtual void FinishImpl() {} + + virtual void EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { + RecordProcEnd(Frame); + } + }; + +} + +MCStreamer *llvm::createNullStreamer(MCContext &Context) { + return new MCNullStreamer(Context); +} diff --git a/contrib/llvm/lib/MC/MCObjectDisassembler.cpp b/contrib/llvm/lib/MC/MCObjectDisassembler.cpp new file mode 100644 index 000000000000..16a110f09bf8 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectDisassembler.cpp @@ -0,0 +1,584 @@ +//===- lib/MC/MCObjectDisassembler.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/MCObjectDisassembler.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAtom.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCFunction.h" +#include "llvm/MC/MCInstrAnalysis.h" +#include "llvm/MC/MCModule.h" +#include "llvm/MC/MCObjectSymbolizer.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/MachO.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/StringRefMemoryObject.h" +#include "llvm/Support/raw_ostream.h" +#include <map> + +using namespace llvm; +using namespace object; + +MCObjectDisassembler::MCObjectDisassembler(const ObjectFile &Obj, + const MCDisassembler &Dis, + const MCInstrAnalysis &MIA) + : Obj(Obj), Dis(Dis), MIA(MIA), MOS(0) {} + +uint64_t MCObjectDisassembler::getEntrypoint() { + error_code ec; + for (symbol_iterator SI = Obj.begin_symbols(), SE = Obj.end_symbols(); + SI != SE; SI.increment(ec)) { + if (ec) + break; + StringRef Name; + SI->getName(Name); + if (Name == "main" || Name == "_main") { + uint64_t Entrypoint; + SI->getAddress(Entrypoint); + return getEffectiveLoadAddr(Entrypoint); + } + } + return 0; +} + +ArrayRef<uint64_t> MCObjectDisassembler::getStaticInitFunctions() { + return ArrayRef<uint64_t>(); +} + +ArrayRef<uint64_t> MCObjectDisassembler::getStaticExitFunctions() { + return ArrayRef<uint64_t>(); +} + +MemoryObject *MCObjectDisassembler::getRegionFor(uint64_t Addr) { + // FIXME: Keep track of object sections. + return FallbackRegion.get(); +} + +uint64_t MCObjectDisassembler::getEffectiveLoadAddr(uint64_t Addr) { + return Addr; +} + +uint64_t MCObjectDisassembler::getOriginalLoadAddr(uint64_t Addr) { + return Addr; +} + +MCModule *MCObjectDisassembler::buildEmptyModule() { + MCModule *Module = new MCModule; + Module->Entrypoint = getEntrypoint(); + return Module; +} + +MCModule *MCObjectDisassembler::buildModule(bool withCFG) { + MCModule *Module = buildEmptyModule(); + + buildSectionAtoms(Module); + if (withCFG) + buildCFG(Module); + return Module; +} + +void MCObjectDisassembler::buildSectionAtoms(MCModule *Module) { + error_code ec; + for (section_iterator SI = Obj.begin_sections(), + SE = Obj.end_sections(); + SI != SE; + SI.increment(ec)) { + if (ec) break; + + bool isText; SI->isText(isText); + bool isData; SI->isData(isData); + if (!isData && !isText) + continue; + + uint64_t StartAddr; SI->getAddress(StartAddr); + uint64_t SecSize; SI->getSize(SecSize); + if (StartAddr == UnknownAddressOrSize || SecSize == UnknownAddressOrSize) + continue; + StartAddr = getEffectiveLoadAddr(StartAddr); + + StringRef Contents; SI->getContents(Contents); + StringRefMemoryObject memoryObject(Contents, StartAddr); + + // We don't care about things like non-file-backed sections yet. + if (Contents.size() != SecSize || !SecSize) + continue; + uint64_t EndAddr = StartAddr + SecSize - 1; + + StringRef SecName; SI->getName(SecName); + + if (isText) { + MCTextAtom *Text = 0; + MCDataAtom *InvalidData = 0; + + uint64_t InstSize; + for (uint64_t Index = 0; Index < SecSize; Index += InstSize) { + const uint64_t CurAddr = StartAddr + Index; + MCInst Inst; + if (Dis.getInstruction(Inst, InstSize, memoryObject, CurAddr, nulls(), + nulls())) { + if (!Text) { + Text = Module->createTextAtom(CurAddr, CurAddr); + Text->setName(SecName); + } + Text->addInst(Inst, InstSize); + InvalidData = 0; + } else { + assert(InstSize && "getInstruction() consumed no bytes"); + if (!InvalidData) { + Text = 0; + InvalidData = Module->createDataAtom(CurAddr, CurAddr+InstSize - 1); + } + for (uint64_t I = 0; I < InstSize; ++I) + InvalidData->addData(Contents[Index+I]); + } + } + } else { + MCDataAtom *Data = Module->createDataAtom(StartAddr, EndAddr); + Data->setName(SecName); + for (uint64_t Index = 0; Index < SecSize; ++Index) + Data->addData(Contents[Index]); + } + } +} + +namespace { + struct BBInfo; + typedef SmallPtrSet<BBInfo*, 2> BBInfoSetTy; + + struct BBInfo { + MCTextAtom *Atom; + MCBasicBlock *BB; + BBInfoSetTy Succs; + BBInfoSetTy Preds; + MCObjectDisassembler::AddressSetTy SuccAddrs; + + BBInfo() : Atom(0), BB(0) {} + + void addSucc(BBInfo &Succ) { + Succs.insert(&Succ); + Succ.Preds.insert(this); + } + }; +} + +static void RemoveDupsFromAddressVector(MCObjectDisassembler::AddressSetTy &V) { + std::sort(V.begin(), V.end()); + V.erase(std::unique(V.begin(), V.end()), V.end()); +} + +void MCObjectDisassembler::buildCFG(MCModule *Module) { + typedef std::map<uint64_t, BBInfo> BBInfoByAddrTy; + BBInfoByAddrTy BBInfos; + AddressSetTy Splits; + AddressSetTy Calls; + + error_code ec; + for (symbol_iterator SI = Obj.begin_symbols(), SE = Obj.end_symbols(); + SI != SE; SI.increment(ec)) { + if (ec) + break; + SymbolRef::Type SymType; + SI->getType(SymType); + if (SymType == SymbolRef::ST_Function) { + uint64_t SymAddr; + SI->getAddress(SymAddr); + SymAddr = getEffectiveLoadAddr(SymAddr); + Calls.push_back(SymAddr); + Splits.push_back(SymAddr); + } + } + + assert(Module->func_begin() == Module->func_end() + && "Module already has a CFG!"); + + // First, determine the basic block boundaries and call targets. + for (MCModule::atom_iterator AI = Module->atom_begin(), + AE = Module->atom_end(); + AI != AE; ++AI) { + MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI); + if (!TA) continue; + Calls.push_back(TA->getBeginAddr()); + BBInfos[TA->getBeginAddr()].Atom = TA; + for (MCTextAtom::const_iterator II = TA->begin(), IE = TA->end(); + II != IE; ++II) { + if (MIA.isTerminator(II->Inst)) + Splits.push_back(II->Address + II->Size); + uint64_t Target; + if (MIA.evaluateBranch(II->Inst, II->Address, II->Size, Target)) { + if (MIA.isCall(II->Inst)) + Calls.push_back(Target); + Splits.push_back(Target); + } + } + } + + RemoveDupsFromAddressVector(Splits); + RemoveDupsFromAddressVector(Calls); + + // Split text atoms into basic block atoms. + for (AddressSetTy::const_iterator SI = Splits.begin(), SE = Splits.end(); + SI != SE; ++SI) { + MCAtom *A = Module->findAtomContaining(*SI); + if (!A) continue; + MCTextAtom *TA = cast<MCTextAtom>(A); + if (TA->getBeginAddr() == *SI) + continue; + MCTextAtom *NewAtom = TA->split(*SI); + BBInfos[NewAtom->getBeginAddr()].Atom = NewAtom; + StringRef BBName = TA->getName(); + BBName = BBName.substr(0, BBName.find_last_of(':')); + NewAtom->setName((BBName + ":" + utohexstr(*SI)).str()); + } + + // Compute succs/preds. + for (MCModule::atom_iterator AI = Module->atom_begin(), + AE = Module->atom_end(); + AI != AE; ++AI) { + MCTextAtom *TA = dyn_cast<MCTextAtom>(*AI); + if (!TA) continue; + BBInfo &CurBB = BBInfos[TA->getBeginAddr()]; + const MCDecodedInst &LI = TA->back(); + if (MIA.isBranch(LI.Inst)) { + uint64_t Target; + if (MIA.evaluateBranch(LI.Inst, LI.Address, LI.Size, Target)) + CurBB.addSucc(BBInfos[Target]); + if (MIA.isConditionalBranch(LI.Inst)) + CurBB.addSucc(BBInfos[LI.Address + LI.Size]); + } else if (!MIA.isTerminator(LI.Inst)) + CurBB.addSucc(BBInfos[LI.Address + LI.Size]); + } + + + // Create functions and basic blocks. + for (AddressSetTy::const_iterator CI = Calls.begin(), CE = Calls.end(); + CI != CE; ++CI) { + BBInfo &BBI = BBInfos[*CI]; + if (!BBI.Atom) continue; + + MCFunction &MCFN = *Module->createFunction(BBI.Atom->getName()); + + // Create MCBBs. + SmallSetVector<BBInfo*, 16> Worklist; + Worklist.insert(&BBI); + for (size_t wi = 0; wi < Worklist.size(); ++wi) { + BBInfo *BBI = Worklist[wi]; + if (!BBI->Atom) + continue; + BBI->BB = &MCFN.createBlock(*BBI->Atom); + // Add all predecessors and successors to the worklist. + for (BBInfoSetTy::iterator SI = BBI->Succs.begin(), SE = BBI->Succs.end(); + SI != SE; ++SI) + Worklist.insert(*SI); + for (BBInfoSetTy::iterator PI = BBI->Preds.begin(), PE = BBI->Preds.end(); + PI != PE; ++PI) + Worklist.insert(*PI); + } + + // Set preds/succs. + for (size_t wi = 0; wi < Worklist.size(); ++wi) { + BBInfo *BBI = Worklist[wi]; + MCBasicBlock *MCBB = BBI->BB; + if (!MCBB) + continue; + for (BBInfoSetTy::iterator SI = BBI->Succs.begin(), SE = BBI->Succs.end(); + SI != SE; ++SI) + if ((*SI)->BB) + MCBB->addSuccessor((*SI)->BB); + for (BBInfoSetTy::iterator PI = BBI->Preds.begin(), PE = BBI->Preds.end(); + PI != PE; ++PI) + if ((*PI)->BB) + MCBB->addPredecessor((*PI)->BB); + } + } +} + +// Basic idea of the disassembly + discovery: +// +// start with the wanted address, insert it in the worklist +// while worklist not empty, take next address in the worklist: +// - check if atom exists there +// - if middle of atom: +// - split basic blocks referencing the atom +// - look for an already encountered BBInfo (using a map<atom, bbinfo>) +// - if there is, split it (new one, fallthrough, move succs, etc..) +// - if start of atom: nothing else to do +// - if no atom: create new atom and new bbinfo +// - look at the last instruction in the atom, add succs to worklist +// for all elements in the worklist: +// - create basic block, update preds/succs, etc.. +// +MCBasicBlock *MCObjectDisassembler::getBBAt(MCModule *Module, MCFunction *MCFN, + uint64_t BBBeginAddr, + AddressSetTy &CallTargets, + AddressSetTy &TailCallTargets) { + typedef std::map<uint64_t, BBInfo> BBInfoByAddrTy; + typedef SmallSetVector<uint64_t, 16> AddrWorklistTy; + BBInfoByAddrTy BBInfos; + AddrWorklistTy Worklist; + + Worklist.insert(BBBeginAddr); + for (size_t wi = 0; wi < Worklist.size(); ++wi) { + const uint64_t BeginAddr = Worklist[wi]; + BBInfo *BBI = &BBInfos[BeginAddr]; + + MCTextAtom *&TA = BBI->Atom; + assert(!TA && "Discovered basic block already has an associated atom!"); + + // Look for an atom at BeginAddr. + if (MCAtom *A = Module->findAtomContaining(BeginAddr)) { + // FIXME: We don't care about mixed atoms, see above. + TA = cast<MCTextAtom>(A); + + // The found atom doesn't begin at BeginAddr, we have to split it. + if (TA->getBeginAddr() != BeginAddr) { + // FIXME: Handle overlapping atoms: middle-starting instructions, etc.. + MCTextAtom *NewTA = TA->split(BeginAddr); + + // Look for an already encountered basic block that needs splitting + BBInfoByAddrTy::iterator It = BBInfos.find(TA->getBeginAddr()); + if (It != BBInfos.end() && It->second.Atom) { + BBI->SuccAddrs = It->second.SuccAddrs; + It->second.SuccAddrs.clear(); + It->second.SuccAddrs.push_back(BeginAddr); + } + TA = NewTA; + } + BBI->Atom = TA; + } else { + // If we didn't find an atom, then we have to disassemble to create one! + + MemoryObject *Region = getRegionFor(BeginAddr); + if (!Region) + llvm_unreachable(("Couldn't find suitable region for disassembly at " + + utostr(BeginAddr)).c_str()); + + uint64_t InstSize; + uint64_t EndAddr = Region->getBase() + Region->getExtent(); + + // We want to stop before the next atom and have a fallthrough to it. + if (MCTextAtom *NextAtom = + cast_or_null<MCTextAtom>(Module->findFirstAtomAfter(BeginAddr))) + EndAddr = std::min(EndAddr, NextAtom->getBeginAddr()); + + for (uint64_t Addr = BeginAddr; Addr < EndAddr; Addr += InstSize) { + MCInst Inst; + if (Dis.getInstruction(Inst, InstSize, *Region, Addr, nulls(), + nulls())) { + if (!TA) + TA = Module->createTextAtom(Addr, Addr); + TA->addInst(Inst, InstSize); + } else { + // We don't care about splitting mixed atoms either. + llvm_unreachable("Couldn't disassemble instruction in atom."); + } + + uint64_t BranchTarget; + if (MIA.evaluateBranch(Inst, Addr, InstSize, BranchTarget)) { + if (MIA.isCall(Inst)) + CallTargets.push_back(BranchTarget); + } + + if (MIA.isTerminator(Inst)) + break; + } + BBI->Atom = TA; + } + + assert(TA && "Couldn't disassemble atom, none was created!"); + assert(TA->begin() != TA->end() && "Empty atom!"); + + MemoryObject *Region = getRegionFor(TA->getBeginAddr()); + assert(Region && "Couldn't find region for already disassembled code!"); + uint64_t EndRegion = Region->getBase() + Region->getExtent(); + + // Now we have a basic block atom, add successors. + // Add the fallthrough block. + if ((MIA.isConditionalBranch(TA->back().Inst) || + !MIA.isTerminator(TA->back().Inst)) && + (TA->getEndAddr() + 1 < EndRegion)) { + BBI->SuccAddrs.push_back(TA->getEndAddr() + 1); + Worklist.insert(TA->getEndAddr() + 1); + } + + // If the terminator is a branch, add the target block. + if (MIA.isBranch(TA->back().Inst)) { + uint64_t BranchTarget; + if (MIA.evaluateBranch(TA->back().Inst, TA->back().Address, + TA->back().Size, BranchTarget)) { + StringRef ExtFnName; + if (MOS) + ExtFnName = + MOS->findExternalFunctionAt(getOriginalLoadAddr(BranchTarget)); + if (!ExtFnName.empty()) { + TailCallTargets.push_back(BranchTarget); + CallTargets.push_back(BranchTarget); + } else { + BBI->SuccAddrs.push_back(BranchTarget); + Worklist.insert(BranchTarget); + } + } + } + } + + for (size_t wi = 0, we = Worklist.size(); wi != we; ++wi) { + const uint64_t BeginAddr = Worklist[wi]; + BBInfo *BBI = &BBInfos[BeginAddr]; + + assert(BBI->Atom && "Found a basic block without an associated atom!"); + + // Look for a basic block at BeginAddr. + BBI->BB = MCFN->find(BeginAddr); + if (BBI->BB) { + // FIXME: check that the succs/preds are the same + continue; + } + // If there was none, we have to create one from the atom. + BBI->BB = &MCFN->createBlock(*BBI->Atom); + } + + for (size_t wi = 0, we = Worklist.size(); wi != we; ++wi) { + const uint64_t BeginAddr = Worklist[wi]; + BBInfo *BBI = &BBInfos[BeginAddr]; + MCBasicBlock *BB = BBI->BB; + + RemoveDupsFromAddressVector(BBI->SuccAddrs); + for (AddressSetTy::const_iterator SI = BBI->SuccAddrs.begin(), + SE = BBI->SuccAddrs.end(); + SE != SE; ++SI) { + MCBasicBlock *Succ = BBInfos[*SI].BB; + BB->addSuccessor(Succ); + Succ->addPredecessor(BB); + } + } + + assert(BBInfos[Worklist[0]].BB && + "No basic block created at requested address?"); + + return BBInfos[Worklist[0]].BB; +} + +MCFunction * +MCObjectDisassembler::createFunction(MCModule *Module, uint64_t BeginAddr, + AddressSetTy &CallTargets, + AddressSetTy &TailCallTargets) { + // First, check if this is an external function. + StringRef ExtFnName; + if (MOS) + ExtFnName = MOS->findExternalFunctionAt(getOriginalLoadAddr(BeginAddr)); + if (!ExtFnName.empty()) + return Module->createFunction(ExtFnName); + + // If it's not, look for an existing function. + for (MCModule::func_iterator FI = Module->func_begin(), + FE = Module->func_end(); + FI != FE; ++FI) { + if ((*FI)->empty()) + continue; + // FIXME: MCModule should provide a findFunctionByAddr() + if ((*FI)->getEntryBlock()->getInsts()->getBeginAddr() == BeginAddr) + return *FI; + } + + // Finally, just create a new one. + MCFunction *MCFN = Module->createFunction(""); + getBBAt(Module, MCFN, BeginAddr, CallTargets, TailCallTargets); + return MCFN; +} + +// MachO MCObjectDisassembler implementation. + +MCMachOObjectDisassembler::MCMachOObjectDisassembler( + const MachOObjectFile &MOOF, const MCDisassembler &Dis, + const MCInstrAnalysis &MIA, uint64_t VMAddrSlide, + uint64_t HeaderLoadAddress) + : MCObjectDisassembler(MOOF, Dis, MIA), MOOF(MOOF), + VMAddrSlide(VMAddrSlide), HeaderLoadAddress(HeaderLoadAddress) { + + error_code ec; + for (section_iterator SI = MOOF.begin_sections(), SE = MOOF.end_sections(); + SI != SE; SI.increment(ec)) { + if (ec) + break; + StringRef Name; + SI->getName(Name); + // FIXME: We should use the S_ section type instead of the name. + if (Name == "__mod_init_func") { + DEBUG(dbgs() << "Found __mod_init_func section!\n"); + SI->getContents(ModInitContents); + } else if (Name == "__mod_exit_func") { + DEBUG(dbgs() << "Found __mod_exit_func section!\n"); + SI->getContents(ModExitContents); + } + } +} + +// FIXME: Only do the translations for addresses actually inside the object. +uint64_t MCMachOObjectDisassembler::getEffectiveLoadAddr(uint64_t Addr) { + return Addr + VMAddrSlide; +} + +uint64_t +MCMachOObjectDisassembler::getOriginalLoadAddr(uint64_t EffectiveAddr) { + return EffectiveAddr - VMAddrSlide; +} + +uint64_t MCMachOObjectDisassembler::getEntrypoint() { + uint64_t EntryFileOffset = 0; + + // Look for LC_MAIN. + { + uint32_t LoadCommandCount = MOOF.getHeader().ncmds; + MachOObjectFile::LoadCommandInfo Load = MOOF.getFirstLoadCommandInfo(); + for (unsigned I = 0;; ++I) { + if (Load.C.cmd == MachO::LC_MAIN) { + EntryFileOffset = + ((const MachO::entry_point_command *)Load.Ptr)->entryoff; + break; + } + + if (I == LoadCommandCount - 1) + break; + else + Load = MOOF.getNextLoadCommandInfo(Load); + } + } + + // If we didn't find anything, default to the common implementation. + // FIXME: Maybe we could also look at LC_UNIXTHREAD and friends? + if (EntryFileOffset) + return MCObjectDisassembler::getEntrypoint(); + + return EntryFileOffset + HeaderLoadAddress; +} + +ArrayRef<uint64_t> MCMachOObjectDisassembler::getStaticInitFunctions() { + // FIXME: We only handle 64bit mach-o + assert(MOOF.is64Bit()); + + size_t EntrySize = 8; + size_t EntryCount = ModInitContents.size() / EntrySize; + return ArrayRef<uint64_t>( + reinterpret_cast<const uint64_t *>(ModInitContents.data()), EntryCount); +} + +ArrayRef<uint64_t> MCMachOObjectDisassembler::getStaticExitFunctions() { + // FIXME: We only handle 64bit mach-o + assert(MOOF.is64Bit()); + + size_t EntrySize = 8; + size_t EntryCount = ModExitContents.size() / EntrySize; + return ArrayRef<uint64_t>( + reinterpret_cast<const uint64_t *>(ModExitContents.data()), EntryCount); +} diff --git a/contrib/llvm/lib/MC/MCObjectFileInfo.cpp b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp new file mode 100644 index 000000000000..8ef4a0a6d7b1 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectFileInfo.cpp @@ -0,0 +1,742 @@ +//===-- MObjectFileInfo.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/Triple.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" +using namespace llvm; + +void MCObjectFileInfo::InitMachOMCObjectFileInfo(Triple T) { + // MachO + IsFunctionEHFrameSymbolPrivate = false; + SupportsWeakOmittedEHFrame = false; + + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel + | dwarf::DW_EH_PE_sdata4; + LSDAEncoding = FDEEncoding = FDECFIEncoding = dwarf::DW_EH_PE_pcrel; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + + // .comm doesn't support alignment before Leopard. + if (T.isMacOSX() && T.isMacOSXVersionLT(10, 5)) + CommDirectiveSupportsAlignment = false; + + TextSection // .text + = Ctx->getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + SectionKind::getText()); + DataSection // .data + = Ctx->getMachOSection("__DATA", "__data", 0, + SectionKind::getDataRel()); + + // BSSSection might not be expected initialized on msvc. + BSSSection = 0; + + TLSDataSection // .tdata + = Ctx->getMachOSection("__DATA", "__thread_data", + MCSectionMachO::S_THREAD_LOCAL_REGULAR, + SectionKind::getDataRel()); + TLSBSSSection // .tbss + = Ctx->getMachOSection("__DATA", "__thread_bss", + MCSectionMachO::S_THREAD_LOCAL_ZEROFILL, + SectionKind::getThreadBSS()); + + // TODO: Verify datarel below. + TLSTLVSection // .tlv + = Ctx->getMachOSection("__DATA", "__thread_vars", + MCSectionMachO::S_THREAD_LOCAL_VARIABLES, + SectionKind::getDataRel()); + + TLSThreadInitSection + = Ctx->getMachOSection("__DATA", "__thread_init", + MCSectionMachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS, + SectionKind::getDataRel()); + + CStringSection // .cstring + = Ctx->getMachOSection("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS, + SectionKind::getMergeable1ByteCString()); + UStringSection + = Ctx->getMachOSection("__TEXT","__ustring", 0, + SectionKind::getMergeable2ByteCString()); + FourByteConstantSection // .literal4 + = Ctx->getMachOSection("__TEXT", "__literal4", + MCSectionMachO::S_4BYTE_LITERALS, + SectionKind::getMergeableConst4()); + EightByteConstantSection // .literal8 + = Ctx->getMachOSection("__TEXT", "__literal8", + MCSectionMachO::S_8BYTE_LITERALS, + SectionKind::getMergeableConst8()); + + // ld_classic doesn't support .literal16 in 32-bit mode, and ld64 falls back + // to using it in -static mode. + SixteenByteConstantSection = 0; + if (RelocM != Reloc::Static && + T.getArch() != Triple::x86_64 && T.getArch() != Triple::ppc64 && + T.getArch() != Triple::ppc64le) + SixteenByteConstantSection = // .literal16 + Ctx->getMachOSection("__TEXT", "__literal16", + MCSectionMachO::S_16BYTE_LITERALS, + SectionKind::getMergeableConst16()); + + ReadOnlySection // .const + = Ctx->getMachOSection("__TEXT", "__const", 0, + SectionKind::getReadOnly()); + + TextCoalSection + = Ctx->getMachOSection("__TEXT", "__textcoal_nt", + MCSectionMachO::S_COALESCED | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + SectionKind::getText()); + ConstTextCoalSection + = Ctx->getMachOSection("__TEXT", "__const_coal", + MCSectionMachO::S_COALESCED, + SectionKind::getReadOnly()); + ConstDataSection // .const_data + = Ctx->getMachOSection("__DATA", "__const", 0, + SectionKind::getReadOnlyWithRel()); + DataCoalSection + = Ctx->getMachOSection("__DATA","__datacoal_nt", + MCSectionMachO::S_COALESCED, + SectionKind::getDataRel()); + DataCommonSection + = Ctx->getMachOSection("__DATA","__common", + MCSectionMachO::S_ZEROFILL, + SectionKind::getBSS()); + DataBSSSection + = Ctx->getMachOSection("__DATA","__bss", MCSectionMachO::S_ZEROFILL, + SectionKind::getBSS()); + + + LazySymbolPointerSection + = Ctx->getMachOSection("__DATA", "__la_symbol_ptr", + MCSectionMachO::S_LAZY_SYMBOL_POINTERS, + SectionKind::getMetadata()); + NonLazySymbolPointerSection + = Ctx->getMachOSection("__DATA", "__nl_symbol_ptr", + MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, + SectionKind::getMetadata()); + + if (RelocM == Reloc::Static) { + StaticCtorSection + = Ctx->getMachOSection("__TEXT", "__constructor", 0, + SectionKind::getDataRel()); + StaticDtorSection + = Ctx->getMachOSection("__TEXT", "__destructor", 0, + SectionKind::getDataRel()); + } else { + StaticCtorSection + = Ctx->getMachOSection("__DATA", "__mod_init_func", + MCSectionMachO::S_MOD_INIT_FUNC_POINTERS, + SectionKind::getDataRel()); + StaticDtorSection + = Ctx->getMachOSection("__DATA", "__mod_term_func", + MCSectionMachO::S_MOD_TERM_FUNC_POINTERS, + SectionKind::getDataRel()); + } + + // Exception Handling. + LSDASection = Ctx->getMachOSection("__TEXT", "__gcc_except_tab", 0, + SectionKind::getReadOnlyWithRel()); + + if (T.isMacOSX() && !T.isMacOSXVersionLT(10, 6)) { + CompactUnwindSection = + Ctx->getMachOSection("__LD", "__compact_unwind", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getReadOnly()); + + if (T.getArch() == Triple::x86_64 || T.getArch() == Triple::x86) + CompactUnwindDwarfEHFrameOnly = 0x04000000; + } + + // Debug Information. + DwarfAccelNamesSection = + Ctx->getMachOSection("__DWARF", "__apple_names", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfAccelObjCSection = + Ctx->getMachOSection("__DWARF", "__apple_objc", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + // 16 character section limit... + DwarfAccelNamespaceSection = + Ctx->getMachOSection("__DWARF", "__apple_namespac", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfAccelTypesSection = + Ctx->getMachOSection("__DWARF", "__apple_types", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + + DwarfAbbrevSection = + Ctx->getMachOSection("__DWARF", "__debug_abbrev", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfInfoSection = + Ctx->getMachOSection("__DWARF", "__debug_info", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfLineSection = + Ctx->getMachOSection("__DWARF", "__debug_line", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfFrameSection = + Ctx->getMachOSection("__DWARF", "__debug_frame", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfPubNamesSection = + Ctx->getMachOSection("__DWARF", "__debug_pubnames", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfPubTypesSection = + Ctx->getMachOSection("__DWARF", "__debug_pubtypes", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfGnuPubNamesSection = + Ctx->getMachOSection("__DWARF", "__debug_gnu_pubn", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfGnuPubTypesSection = + Ctx->getMachOSection("__DWARF", "__debug_gnu_pubt", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfStrSection = + Ctx->getMachOSection("__DWARF", "__debug_str", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfLocSection = + Ctx->getMachOSection("__DWARF", "__debug_loc", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfARangesSection = + Ctx->getMachOSection("__DWARF", "__debug_aranges", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfRangesSection = + Ctx->getMachOSection("__DWARF", "__debug_ranges", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfMacroInfoSection = + Ctx->getMachOSection("__DWARF", "__debug_macinfo", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + DwarfDebugInlineSection = + Ctx->getMachOSection("__DWARF", "__debug_inlined", + MCSectionMachO::S_ATTR_DEBUG, + SectionKind::getMetadata()); + StackMapSection = + Ctx->getMachOSection("__LLVM_STACKMAPS", "__llvm_stackmaps", 0, + SectionKind::getMetadata()); + + TLSExtraDataSection = TLSTLVSection; +} + +void MCObjectFileInfo::InitELFMCObjectFileInfo(Triple T) { + if (T.getArch() == Triple::mips || + T.getArch() == Triple::mipsel) + FDECFIEncoding = dwarf::DW_EH_PE_sdata4; + else if (T.getArch() == Triple::mips64 || + T.getArch() == Triple::mips64el) + FDECFIEncoding = dwarf::DW_EH_PE_sdata8; + else + FDECFIEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + + if (T.getArch() == Triple::x86) { + PersonalityEncoding = (RelocM == Reloc::PIC_) + ? dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_absptr; + LSDAEncoding = (RelocM == Reloc::PIC_) + ? dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_absptr; + FDEEncoding = (RelocM == Reloc::PIC_) + ? dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_absptr; + TTypeEncoding = (RelocM == Reloc::PIC_) + ? dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4 + : dwarf::DW_EH_PE_absptr; + } else if (T.getArch() == Triple::x86_64) { + if (RelocM == Reloc::PIC_) { + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + ((CMModel == CodeModel::Small || CMModel == CodeModel::Medium) + ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); + LSDAEncoding = dwarf::DW_EH_PE_pcrel | + (CMModel == CodeModel::Small + ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + ((CMModel == CodeModel::Small || CMModel == CodeModel::Medium) + ? dwarf::DW_EH_PE_sdata4 : dwarf::DW_EH_PE_sdata8); + } else { + PersonalityEncoding = + (CMModel == CodeModel::Small || CMModel == CodeModel::Medium) + ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; + LSDAEncoding = (CMModel == CodeModel::Small) + ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; + FDEEncoding = dwarf::DW_EH_PE_udata4; + TTypeEncoding = (CMModel == CodeModel::Small) + ? dwarf::DW_EH_PE_udata4 : dwarf::DW_EH_PE_absptr; + } + } else if (T.getArch() == Triple::aarch64) { + // The small model guarantees static code/data size < 4GB, but not where it + // will be in memory. Most of these could end up >2GB away so even a signed + // pc-relative 32-bit address is insufficient, theoretically. + if (RelocM == Reloc::PIC_) { + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata8; + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata8; + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata8; + } else { + PersonalityEncoding = dwarf::DW_EH_PE_absptr; + LSDAEncoding = dwarf::DW_EH_PE_absptr; + FDEEncoding = dwarf::DW_EH_PE_udata4; + TTypeEncoding = dwarf::DW_EH_PE_absptr; + } + } else if (T.getArch() == Triple::ppc64 || T.getArch() == Triple::ppc64le) { + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_udata8; + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_udata8; + } else if (T.getArch() == Triple::systemz) { + // All currently-defined code models guarantee that 4-byte PC-relative + // values will be in range. + if (RelocM == Reloc::PIC_) { + PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4; + TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel | + dwarf::DW_EH_PE_sdata4; + } else { + PersonalityEncoding = dwarf::DW_EH_PE_absptr; + LSDAEncoding = dwarf::DW_EH_PE_absptr; + FDEEncoding = dwarf::DW_EH_PE_absptr; + TTypeEncoding = dwarf::DW_EH_PE_absptr; + } + } + + // Solaris requires different flags for .eh_frame to seemingly every other + // platform. + EHSectionType = ELF::SHT_PROGBITS; + EHSectionFlags = ELF::SHF_ALLOC; + if (T.getOS() == Triple::Solaris) { + if (T.getArch() == Triple::x86_64) + EHSectionType = ELF::SHT_X86_64_UNWIND; + else + EHSectionFlags |= ELF::SHF_WRITE; + } + + + // ELF + BSSSection = + Ctx->getELFSection(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | ELF::SHF_ALLOC, + SectionKind::getBSS()); + + TextSection = + Ctx->getELFSection(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, + SectionKind::getText()); + + DataSection = + Ctx->getELFSection(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, + SectionKind::getDataRel()); + + ReadOnlySection = + Ctx->getELFSection(".rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, + SectionKind::getReadOnly()); + + TLSDataSection = + Ctx->getELFSection(".tdata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | ELF::SHF_TLS | + ELF::SHF_WRITE, + SectionKind::getThreadData()); + + TLSBSSSection = + Ctx->getELFSection(".tbss", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | ELF::SHF_TLS | + ELF::SHF_WRITE, + SectionKind::getThreadBSS()); + + DataRelSection = + Ctx->getELFSection(".data.rel", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, + SectionKind::getDataRel()); + + DataRelLocalSection = + Ctx->getELFSection(".data.rel.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, + SectionKind::getDataRelLocal()); + + DataRelROSection = + Ctx->getELFSection(".data.rel.ro", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, + SectionKind::getReadOnlyWithRel()); + + DataRelROLocalSection = + Ctx->getELFSection(".data.rel.ro.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, + SectionKind::getReadOnlyWithRelLocal()); + + MergeableConst4Section = + Ctx->getELFSection(".rodata.cst4", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_MERGE, + SectionKind::getMergeableConst4()); + + MergeableConst8Section = + Ctx->getELFSection(".rodata.cst8", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_MERGE, + SectionKind::getMergeableConst8()); + + MergeableConst16Section = + Ctx->getELFSection(".rodata.cst16", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_MERGE, + SectionKind::getMergeableConst16()); + + StaticCtorSection = + Ctx->getELFSection(".ctors", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, + SectionKind::getDataRel()); + + StaticDtorSection = + Ctx->getELFSection(".dtors", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC |ELF::SHF_WRITE, + SectionKind::getDataRel()); + + // 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, + SectionKind::getReadOnly()); + + // Debug Info Sections. + DwarfAbbrevSection = + Ctx->getELFSection(".debug_abbrev", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfInfoSection = + Ctx->getELFSection(".debug_info", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfLineSection = + Ctx->getELFSection(".debug_line", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfFrameSection = + Ctx->getELFSection(".debug_frame", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfPubNamesSection = + Ctx->getELFSection(".debug_pubnames", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfPubTypesSection = + Ctx->getELFSection(".debug_pubtypes", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfGnuPubNamesSection = + Ctx->getELFSection(".debug_gnu_pubnames", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfGnuPubTypesSection = + Ctx->getELFSection(".debug_gnu_pubtypes", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfStrSection = + Ctx->getELFSection(".debug_str", ELF::SHT_PROGBITS, + ELF::SHF_MERGE | ELF::SHF_STRINGS, + SectionKind::getMergeable1ByteCString()); + DwarfLocSection = + Ctx->getELFSection(".debug_loc", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfARangesSection = + Ctx->getELFSection(".debug_aranges", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfRangesSection = + Ctx->getELFSection(".debug_ranges", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfMacroInfoSection = + Ctx->getELFSection(".debug_macinfo", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + + // DWARF5 Experimental Debug Info + + // Accelerator Tables + DwarfAccelNamesSection = + Ctx->getELFSection(".apple_names", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfAccelObjCSection = + Ctx->getELFSection(".apple_objc", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfAccelNamespaceSection = + Ctx->getELFSection(".apple_namespaces", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfAccelTypesSection = + Ctx->getELFSection(".apple_types", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + + // Fission Sections + DwarfInfoDWOSection = + Ctx->getELFSection(".debug_info.dwo", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfAbbrevDWOSection = + Ctx->getELFSection(".debug_abbrev.dwo", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfStrDWOSection = + Ctx->getELFSection(".debug_str.dwo", ELF::SHT_PROGBITS, + ELF::SHF_MERGE | ELF::SHF_STRINGS, + SectionKind::getMergeable1ByteCString()); + DwarfLineDWOSection = + Ctx->getELFSection(".debug_line.dwo", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfLocDWOSection = + Ctx->getELFSection(".debug_loc.dwo", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfStrOffDWOSection = + Ctx->getELFSection(".debug_str_offsets.dwo", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); + DwarfAddrSection = + Ctx->getELFSection(".debug_addr", ELF::SHT_PROGBITS, 0, + SectionKind::getMetadata()); +} + + +void MCObjectFileInfo::InitCOFFMCObjectFileInfo(Triple T) { + // 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", + 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::getDataRel()); + ReadOnlySection = + Ctx->getCOFFSection(".rdata", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getReadOnly()); + if (T.getOS() == Triple::Win32) { + StaticCtorSection = + Ctx->getCOFFSection(".CRT$XCU", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getReadOnly()); + } else { + StaticCtorSection = + Ctx->getCOFFSection(".ctors", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + } + + + if (T.getOS() == Triple::Win32) { + StaticDtorSection = + Ctx->getCOFFSection(".CRT$XTX", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getReadOnly()); + } else { + StaticDtorSection = + Ctx->getCOFFSection(".dtors", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + } + + // FIXME: We're emitting LSDA info into a readonly section on COFF, 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->getCOFFSection(".gcc_except_table", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getReadOnly()); + + // Debug info. + DwarfAbbrevSection = + Ctx->getCOFFSection(".debug_abbrev", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfInfoSection = + Ctx->getCOFFSection(".debug_info", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfLineSection = + Ctx->getCOFFSection(".debug_line", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfFrameSection = + Ctx->getCOFFSection(".debug_frame", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfPubNamesSection = + Ctx->getCOFFSection(".debug_pubnames", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfPubTypesSection = + Ctx->getCOFFSection(".debug_pubtypes", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfGnuPubNamesSection = + Ctx->getCOFFSection(".debug_gnu_pubnames", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfGnuPubTypesSection = + Ctx->getCOFFSection(".debug_gnu_pubtypes", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfStrSection = + Ctx->getCOFFSection(".debug_str", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfLocSection = + Ctx->getCOFFSection(".debug_loc", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfARangesSection = + Ctx->getCOFFSection(".debug_aranges", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfRangesSection = + Ctx->getCOFFSection(".debug_ranges", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + DwarfMacroInfoSection = + Ctx->getCOFFSection(".debug_macinfo", + COFF::IMAGE_SCN_MEM_DISCARDABLE | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getMetadata()); + + DrectveSection = + Ctx->getCOFFSection(".drectve", + COFF::IMAGE_SCN_LNK_INFO, + SectionKind::getMetadata()); + + PDataSection = + Ctx->getCOFFSection(".pdata", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getDataRel()); + + XDataSection = + Ctx->getCOFFSection(".xdata", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getDataRel()); + TLSDataSection = + Ctx->getCOFFSection(".tls$", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); +} + +void MCObjectFileInfo::InitMCObjectFileInfo(StringRef TT, Reloc::Model relocm, + CodeModel::Model cm, + MCContext &ctx) { + RelocM = relocm; + CMModel = cm; + Ctx = &ctx; + + // Common. + CommDirectiveSupportsAlignment = true; + SupportsWeakOmittedEHFrame = true; + IsFunctionEHFrameSymbolPrivate = true; + + PersonalityEncoding = LSDAEncoding = FDEEncoding = FDECFIEncoding = + TTypeEncoding = dwarf::DW_EH_PE_absptr; + + CompactUnwindDwarfEHFrameOnly = 0; + + EHFrameSection = 0; // Created on demand. + CompactUnwindSection = 0; // Used only by selected targets. + DwarfAccelNamesSection = 0; // Used only by selected targets. + DwarfAccelObjCSection = 0; // Used only by selected targets. + DwarfAccelNamespaceSection = 0; // Used only by selected targets. + DwarfAccelTypesSection = 0; // Used only by selected targets. + + Triple T(TT); + Triple::ArchType Arch = T.getArch(); + // FIXME: Checking for Arch here to filter out bogus triples such as + // cellspu-apple-darwin. Perhaps we should fix in Triple? + if ((Arch == Triple::x86 || Arch == Triple::x86_64 || + Arch == Triple::arm || Arch == Triple::thumb || + Arch == Triple::ppc || Arch == Triple::ppc64 || + Arch == Triple::UnknownArch) && + (T.isOSDarwin() || T.getEnvironment() == Triple::MachO)) { + Env = IsMachO; + InitMachOMCObjectFileInfo(T); + } else if ((Arch == Triple::x86 || Arch == Triple::x86_64) && + (T.getEnvironment() != Triple::ELF) && + (T.getOS() == Triple::MinGW32 || T.getOS() == Triple::Cygwin || + T.getOS() == Triple::Win32)) { + Env = IsCOFF; + InitCOFFMCObjectFileInfo(T); + } else { + Env = IsELF; + InitELFMCObjectFileInfo(T); + } +} + +void MCObjectFileInfo::InitEHFrameSection() { + if (Env == IsMachO) + EHFrameSection = + Ctx->getMachOSection("__TEXT", "__eh_frame", + MCSectionMachO::S_COALESCED | + MCSectionMachO::S_ATTR_NO_TOC | + MCSectionMachO::S_ATTR_STRIP_STATIC_SYMS | + MCSectionMachO::S_ATTR_LIVE_SUPPORT, + SectionKind::getReadOnly()); + else if (Env == IsELF) + EHFrameSection = + Ctx->getELFSection(".eh_frame", EHSectionType, + EHSectionFlags, + SectionKind::getDataRel()); + else + EHFrameSection = + Ctx->getCOFFSection(".eh_frame", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); +} diff --git a/contrib/llvm/lib/MC/MCObjectStreamer.cpp b/contrib/llvm/lib/MC/MCObjectStreamer.cpp new file mode 100644 index 000000000000..bc14c2ae2bc6 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectStreamer.cpp @@ -0,0 +1,393 @@ +//===- 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/MCAsmInfo.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCSection.h" +#include "llvm/Support/ErrorHandling.h" +using namespace llvm; + +MCObjectStreamer::MCObjectStreamer(MCContext &Context, + MCTargetStreamer *TargetStreamer, + MCAsmBackend &TAB, raw_ostream &OS, + MCCodeEmitter *Emitter_) + : MCStreamer(Context, TargetStreamer), + Assembler(new MCAssembler(Context, TAB, *Emitter_, + *TAB.createObjectWriter(OS), OS)), + CurSectionData(0) {} + +MCObjectStreamer::MCObjectStreamer(MCContext &Context, + MCTargetStreamer *TargetStreamer, + MCAsmBackend &TAB, raw_ostream &OS, + MCCodeEmitter *Emitter_, + MCAssembler *_Assembler) + : MCStreamer(Context, TargetStreamer), Assembler(_Assembler), + CurSectionData(0) {} + +MCObjectStreamer::~MCObjectStreamer() { + delete &Assembler->getBackend(); + delete &Assembler->getEmitter(); + delete &Assembler->getWriter(); + delete Assembler; +} + +void MCObjectStreamer::reset() { + if (Assembler) + Assembler->reset(); + CurSectionData = 0; + CurInsertionPoint = MCSectionData::iterator(); + MCStreamer::reset(); +} + +MCFragment *MCObjectStreamer::getCurrentFragment() const { + assert(getCurrentSectionData() && "No current section!"); + + if (CurInsertionPoint != getCurrentSectionData()->getFragmentList().begin()) + return prior(CurInsertionPoint); + + return 0; +} + +MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { + MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); + // When bundling is enabled, we don't want to add data to a fragment that + // already has instructions (see MCELFStreamer::EmitInstToData for details) + if (!F || (Assembler->isBundlingEnabled() && F->hasInstructions())) { + F = new MCDataFragment(); + insert(F); + } + return F; +} + +const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Target: + cast<MCTargetExpr>(Value)->AddValueSymbols(Assembler); + break; + + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + Assembler->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); + break; + } + + return Value; +} + +void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size) { + MCDataFragment *DF = getOrCreateDataFragment(); + + MCLineEntry::Make(this, getCurrentSection().first); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue, getAssembler())) { + EmitIntValue(AbsValue, Size); + return; + } + DF->getFixups().push_back( + MCFixup::Create(DF->getContents().size(), Value, + MCFixup::getKindForSize(Size, false))); + DF->getContents().resize(DF->getContents().size() + Size, 0); +} + +void MCObjectStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { + RecordProcStart(Frame); +} + +void MCObjectStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { + RecordProcEnd(Frame); +} + +void MCObjectStreamer::EmitLabel(MCSymbol *Symbol) { + MCStreamer::EmitLabel(Symbol); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); +} + +void MCObjectStreamer::EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); +} + +void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, getAssembler())) { + EmitULEB128IntValue(IntValue); + return; + } + Value = ForceExpAbs(Value); + insert(new MCLEBFragment(*Value, false)); +} + +void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, getAssembler())) { + EmitSLEB128IntValue(IntValue); + return; + } + Value = ForceExpAbs(Value); + 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(const MCSection *Section, + const MCExpr *Subsection) { + assert(Section && "Cannot switch to a null section!"); + + CurSectionData = &getAssembler().getOrCreateSectionData(*Section); + + int64_t IntSubsection = 0; + if (Subsection && + !Subsection->EvaluateAsAbsolute(IntSubsection, getAssembler())) + report_fatal_error("Cannot evaluate subsection number"); + if (IntSubsection < 0 || IntSubsection > 8192) + report_fatal_error("Subsection number out of range"); + CurInsertionPoint = + CurSectionData->getSubsectionInsertionPoint(unsigned(IntSubsection)); +} + +void MCObjectStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + getAssembler().getOrCreateSymbolData(*Symbol); + Symbol->setVariableValue(AddValueSymbols(Value)); +} + +void MCObjectStreamer::EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = Inst.getNumOperands(); i--; ) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + + MCSectionData *SD = getCurrentSectionData(); + SD->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. + MCLineEntry::Make(this, getCurrentSection().first); + + // If this instruction doesn't need relaxation, just emit it as data. + MCAssembler &Assembler = getAssembler(); + if (!Assembler.getBackend().mayNeedRelaxation(Inst)) { + EmitInstToData(Inst); + 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() && SD->isBundleLocked())) { + MCInst Relaxed; + getAssembler().getBackend().relaxInstruction(Inst, Relaxed); + while (getAssembler().getBackend().mayNeedRelaxation(Relaxed)) + getAssembler().getBackend().relaxInstruction(Relaxed, Relaxed); + EmitInstToData(Relaxed); + return; + } + + // Otherwise emit to a separate fragment. + EmitInstToFragment(Inst); +} + +void MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { + // Always create a new, separate fragment here, because its size can change + // during relaxation. + MCRelaxableFragment *IF = new MCRelaxableFragment(Inst); + insert(IF); + + SmallString<128> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, IF->getFixups()); + VecOS.flush(); + 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. + MCLineEntry::Make(this, getCurrentSection().first); + + this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, + Isa, Discriminator, FileName); +} + +void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label, + unsigned PointerSize) { + if (!LastLabel) { + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); + return; + } + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + MCDwarfLineAddr::Emit(this, LineDelta, Res); + return; + } + AddrDelta = ForceExpAbs(AddrDelta); + insert(new MCDwarfLineAddrFragment(LineDelta, *AddrDelta)); +} + +void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label) { + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res); + return; + } + AddrDelta = ForceExpAbs(AddrDelta); + insert(new MCDwarfCallFrameFragment(*AddrDelta)); +} + +void MCObjectStreamer::EmitBytes(StringRef Data) { + MCLineEntry::Make(this, getCurrentSection().first); + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); +} + +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. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCObjectStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + EmitValueToAlignment(ByteAlignment, 0, 1, MaxBytesToEmit); + cast<MCAlignFragment>(getCurrentFragment())->setEmitNops(true); +} + +bool MCObjectStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + int64_t Res; + if (Offset->EvaluateAsAbsolute(Res, getAssembler())) { + insert(new MCOrgFragment(*Offset, Value)); + return false; + } + + MCSymbol *CurrentPos = getContext().CreateTempSymbol(); + EmitLabel(CurrentPos); + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Ref = + MCSymbolRefExpr::Create(CurrentPos, Variant, getContext()); + const MCExpr *Delta = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Offset, Ref, getContext()); + + if (!Delta->EvaluateAsAbsolute(Res, getAssembler())) + return true; + EmitFill(Res, Value); + return false; +} + +// Associate GPRel32 fixup with data and resize data area +void MCObjectStreamer::EmitGPRel32Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + + DF->getFixups().push_back(MCFixup::Create(DF->getContents().size(), + Value, FK_GPRel_4)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +// Associate GPRel32 fixup with data and resize data area +void MCObjectStreamer::EmitGPRel64Value(const MCExpr *Value) { + MCDataFragment *DF = getOrCreateDataFragment(); + + DF->getFixups().push_back(MCFixup::Create(DF->getContents().size(), + Value, FK_GPRel_4)); + DF->getContents().resize(DF->getContents().size() + 8, 0); +} + +void MCObjectStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue) { + // FIXME: A MCFillFragment would be more memory efficient but MCExpr has + // problems evaluating expressions across multiple fragments. + getOrCreateDataFragment()->getContents().append(NumBytes, FillValue); +} + +void MCObjectStreamer::EmitZeros(uint64_t NumBytes) { + unsigned ItemSize = getCurrentSection().first->isVirtualSection() ? 0 : 1; + insert(new MCFillFragment(0, ItemSize, NumBytes)); +} + +void MCObjectStreamer::FinishImpl() { + // Dump out the dwarf file & directory tables and line tables. + const MCSymbol *LineSectionSymbol = NULL; + if (getContext().hasDwarfFiles()) + LineSectionSymbol = MCDwarfFileTable::Emit(this); + + // If we are generating dwarf for assembly source files dump out the sections. + if (getContext().getGenDwarfForAssembly()) + MCGenDwarfInfo::Emit(this, LineSectionSymbol); + + getAssembler().Finish(); +} diff --git a/contrib/llvm/lib/MC/MCObjectSymbolizer.cpp b/contrib/llvm/lib/MC/MCObjectSymbolizer.cpp new file mode 100644 index 000000000000..b9131d1ed609 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectSymbolizer.cpp @@ -0,0 +1,310 @@ +//===-- lib/MC/MCObjectSymbolizer.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/MCObjectSymbolizer.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCRelocationInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; +using namespace object; + +//===- MCMachObjectSymbolizer ---------------------------------------------===// + +namespace { +class MCMachObjectSymbolizer : public MCObjectSymbolizer { + const MachOObjectFile *MOOF; + // __TEXT;__stubs support. + uint64_t StubsStart; + uint64_t StubsCount; + uint64_t StubSize; + uint64_t StubsIndSymIndex; + +public: + MCMachObjectSymbolizer(MCContext &Ctx, OwningPtr<MCRelocationInfo> &RelInfo, + const MachOObjectFile *MOOF); + + StringRef findExternalFunctionAt(uint64_t Addr) LLVM_OVERRIDE; + + void tryAddingPcLoadReferenceComment(raw_ostream &cStream, + int64_t Value, + uint64_t Address) LLVM_OVERRIDE; +}; +} // End unnamed namespace + + +MCMachObjectSymbolizer:: +MCMachObjectSymbolizer(MCContext &Ctx, OwningPtr<MCRelocationInfo> &RelInfo, + const MachOObjectFile *MOOF) + : MCObjectSymbolizer(Ctx, RelInfo, MOOF), MOOF(MOOF), + StubsStart(0), StubsCount(0), StubSize(0), StubsIndSymIndex(0) { + + error_code ec; + for (section_iterator SI = MOOF->begin_sections(), SE = MOOF->end_sections(); + SI != SE; SI.increment(ec)) { + if (ec) break; + StringRef Name; SI->getName(Name); + if (Name == "__stubs") { + SectionRef StubsSec = *SI; + if (MOOF->is64Bit()) { + MachO::section_64 S = MOOF->getSection64(StubsSec.getRawDataRefImpl()); + StubsIndSymIndex = S.reserved1; + StubSize = S.reserved2; + } else { + MachO::section S = MOOF->getSection(StubsSec.getRawDataRefImpl()); + StubsIndSymIndex = S.reserved1; + StubSize = S.reserved2; + } + assert(StubSize && "Mach-O stub entry size can't be zero!"); + StubsSec.getAddress(StubsStart); + StubsSec.getSize(StubsCount); + StubsCount /= StubSize; + } + } +} + +StringRef MCMachObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) { + // FIXME: also, this can all be done at the very beginning, by iterating over + // all stubs and creating the calls to outside functions. Is it worth it + // though? + if (!StubSize) + return StringRef(); + uint64_t StubIdx = (Addr - StubsStart) / StubSize; + if (StubIdx >= StubsCount) + return StringRef(); + + uint32_t SymtabIdx = + MOOF->getIndirectSymbolTableEntry(MOOF->getDysymtabLoadCommand(), StubIdx); + + StringRef SymName; + symbol_iterator SI = MOOF->begin_symbols(); + error_code ec; + for (uint32_t i = 0; i != SymtabIdx; ++i) { + SI.increment(ec); + } + SI->getName(SymName); + assert(SI != MOOF->end_symbols() && "Stub wasn't found in the symbol table!"); + assert(SymName.front() == '_' && "Mach-O symbol doesn't start with '_'!"); + return SymName.substr(1); +} + +void MCMachObjectSymbolizer:: +tryAddingPcLoadReferenceComment(raw_ostream &cStream, int64_t Value, + uint64_t Address) { + if (const RelocationRef *R = findRelocationAt(Address)) { + const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R); + if (!RelExpr || RelExpr->EvaluateAsAbsolute(Value) == false) + return; + } + uint64_t Addr = Value; + if (const SectionRef *S = findSectionContaining(Addr)) { + StringRef Name; S->getName(Name); + uint64_t SAddr; S->getAddress(SAddr); + if (Name == "__cstring") { + StringRef Contents; + S->getContents(Contents); + Contents = Contents.substr(Addr - SAddr); + cStream << " ## literal pool for: " + << Contents.substr(0, Contents.find_first_of(0)); + } + } +} + +//===- MCObjectSymbolizer -------------------------------------------------===// + +MCObjectSymbolizer::MCObjectSymbolizer(MCContext &Ctx, + OwningPtr<MCRelocationInfo> &RelInfo, + const ObjectFile *Obj) + : MCSymbolizer(Ctx, RelInfo), Obj(Obj), SortedSections(), AddrToReloc() { +} + +bool MCObjectSymbolizer:: +tryAddingSymbolicOperand(MCInst &MI, raw_ostream &cStream, + int64_t Value, uint64_t Address, bool IsBranch, + uint64_t Offset, uint64_t InstSize) { + if (IsBranch) { + StringRef ExtFnName = findExternalFunctionAt((uint64_t)Value); + if (!ExtFnName.empty()) { + MCSymbol *Sym = Ctx.GetOrCreateSymbol(ExtFnName); + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + MI.addOperand(MCOperand::CreateExpr(Expr)); + return true; + } + } + + if (const RelocationRef *R = findRelocationAt(Address + Offset)) { + if (const MCExpr *RelExpr = RelInfo->createExprForRelocation(*R)) { + MI.addOperand(MCOperand::CreateExpr(RelExpr)); + return true; + } + // Only try to create a symbol+offset expression if there is no relocation. + return false; + } + + // Interpret Value as a branch target. + if (IsBranch == false) + return false; + uint64_t UValue = Value; + // FIXME: map instead of looping each time? + error_code ec; + for (symbol_iterator SI = Obj->begin_symbols(), SE = Obj->end_symbols(); + SI != SE; SI.increment(ec)) { + if (ec) break; + uint64_t SymAddr; SI->getAddress(SymAddr); + uint64_t SymSize; SI->getSize(SymSize); + StringRef SymName; SI->getName(SymName); + SymbolRef::Type SymType; SI->getType(SymType); + if (SymAddr == UnknownAddressOrSize || SymSize == UnknownAddressOrSize + || SymName.empty() || SymType != SymbolRef::ST_Function) + continue; + + if ( SymAddr == UValue || + (SymAddr <= UValue && SymAddr + SymSize > UValue)) { + MCSymbol *Sym = Ctx.GetOrCreateSymbol(SymName); + const MCExpr *Expr = MCSymbolRefExpr::Create(Sym, Ctx); + if (SymAddr != UValue) { + const MCExpr *Off = MCConstantExpr::Create(UValue - SymAddr, Ctx); + Expr = MCBinaryExpr::CreateAdd(Expr, Off, Ctx); + } + MI.addOperand(MCOperand::CreateExpr(Expr)); + return true; + } + } + return false; +} + +void MCObjectSymbolizer:: +tryAddingPcLoadReferenceComment(raw_ostream &cStream, + int64_t Value, uint64_t Address) { +} + +StringRef MCObjectSymbolizer::findExternalFunctionAt(uint64_t Addr) { + return StringRef(); +} + +MCObjectSymbolizer * +MCObjectSymbolizer::createObjectSymbolizer(MCContext &Ctx, + OwningPtr<MCRelocationInfo> &RelInfo, + const ObjectFile *Obj) { + if (const MachOObjectFile *MOOF = dyn_cast<MachOObjectFile>(Obj)) + return new MCMachObjectSymbolizer(Ctx, RelInfo, MOOF); + return new MCObjectSymbolizer(Ctx, RelInfo, Obj); +} + +// SortedSections implementation. + +static bool SectionStartsBefore(const SectionRef &S, uint64_t Addr) { + uint64_t SAddr; S.getAddress(SAddr); + return SAddr < Addr; +} + +const SectionRef *MCObjectSymbolizer::findSectionContaining(uint64_t Addr) { + if (SortedSections.empty()) + buildSectionList(); + + SortedSectionList::iterator + EndIt = SortedSections.end(), + It = std::lower_bound(SortedSections.begin(), EndIt, + Addr, SectionStartsBefore); + if (It == EndIt) + return 0; + uint64_t SAddr; It->getAddress(SAddr); + uint64_t SSize; It->getSize(SSize); + if (Addr >= SAddr + SSize) + return 0; + return &*It; +} + +const RelocationRef *MCObjectSymbolizer::findRelocationAt(uint64_t Addr) { + if (AddrToReloc.empty()) + buildRelocationByAddrMap(); + + AddrToRelocMap::const_iterator RI = AddrToReloc.find(Addr); + if (RI == AddrToReloc.end()) + return 0; + return &RI->second; +} + +void MCObjectSymbolizer::buildSectionList() { + error_code ec; + for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections(); + SI != SE; SI.increment(ec)) { + if (ec) break; + + bool RequiredForExec; SI->isRequiredForExecution(RequiredForExec); + if (RequiredForExec == false) + continue; + uint64_t SAddr; SI->getAddress(SAddr); + uint64_t SSize; SI->getSize(SSize); + SortedSectionList::iterator It = std::lower_bound(SortedSections.begin(), + SortedSections.end(), + SAddr, + SectionStartsBefore); + if (It != SortedSections.end()) { + uint64_t FoundSAddr; It->getAddress(FoundSAddr); + if (FoundSAddr < SAddr + SSize) + llvm_unreachable("Inserting overlapping sections"); + } + SortedSections.insert(It, *SI); + } +} + +void MCObjectSymbolizer::buildRelocationByAddrMap() { + error_code ec; + for (section_iterator SI = Obj->begin_sections(), SE = Obj->end_sections(); + SI != SE; SI.increment(ec)) { + if (ec) break; + + section_iterator RelSecI = SI->getRelocatedSection(); + if (RelSecI == Obj->end_sections()) + continue; + + uint64_t StartAddr; RelSecI->getAddress(StartAddr); + uint64_t Size; RelSecI->getSize(Size); + bool RequiredForExec; RelSecI->isRequiredForExecution(RequiredForExec); + if (RequiredForExec == false || Size == 0) + continue; + for (relocation_iterator RI = SI->begin_relocations(), + RE = SI->end_relocations(); + RI != RE; + RI.increment(ec)) { + if (ec) break; + // FIXME: libObject is inconsistent regarding error handling. The + // overwhelming majority of methods always return object_error::success, + // and assert for simple errors.. Here, ELFObjectFile::getRelocationOffset + // asserts when the file type isn't ET_REL. + // This workaround handles x86-64 elf, the only one that has a relocinfo. + uint64_t Offset; + if (Obj->isELF()) { + const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj); + if (ELFObj == 0) + break; + if (ELFObj->getELFFile()->getHeader()->e_type == ELF::ET_REL) { + RI->getOffset(Offset); + Offset += StartAddr; + } else { + RI->getAddress(Offset); + } + } else { + RI->getOffset(Offset); + Offset += StartAddr; + } + // At a specific address, only keep the first relocation. + if (AddrToReloc.find(Offset) == AddrToReloc.end()) + AddrToReloc[Offset] = *RI; + } + } +} diff --git a/contrib/llvm/lib/MC/MCObjectWriter.cpp b/contrib/llvm/lib/MC/MCObjectWriter.cpp new file mode 100644 index 000000000000..94d7cd6fd4f3 --- /dev/null +++ b/contrib/llvm/lib/MC/MCObjectWriter.cpp @@ -0,0 +1,56 @@ +//===- 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/MCAssembler.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbol.h" + +using namespace llvm; + +MCObjectWriter::~MCObjectWriter() { +} + +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.AliasedSymbol().isUndefined() || SB.AliasedSymbol().isUndefined()) + return false; + + const MCSymbolData &DataA = Asm.getSymbolData(SA); + const MCSymbolData &DataB = Asm.getSymbolData(SB); + if(!DataA.getFragment() || !DataB.getFragment()) + return false; + + return IsSymbolRefDifferenceFullyResolvedImpl(Asm, DataA, + *DataB.getFragment(), + InSet, + false); +} + +bool +MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + const MCSection &SecA = DataA.getSymbol().AliasedSymbol().getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + // 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..b49dd0104793 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp @@ -0,0 +1,568 @@ +//===- 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/MC/MCAsmInfo.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SMLoc.h" +#include <cctype> +#include <cerrno> +#include <cstdio> +#include <cstdlib> +using namespace llvm; + +AsmLexer::AsmLexer(const MCAsmInfo &_MAI) : MAI(_MAI) { + CurBuf = NULL; + CurPtr = NULL; + isAtStartOfLine = true; +} + +AsmLexer::~AsmLexer() { +} + +void AsmLexer::setBuffer(const MemoryBuffer *buf, const char *ptr) { + CurBuf = buf; + + if (ptr) + CurPtr = ptr; + else + CurPtr = CurBuf->getBufferStart(); + + TokStart = 0; +} + +/// 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, 0)); +} + +int AsmLexer::getNextChar() { + char CurChar = *CurPtr++; + switch (CurChar) { + default: + return (unsigned char)CurChar; + case 0: + // A nul character in the stream is either the end of the current buffer or + // a random nul in the file. Disambiguate that here. + if (CurPtr-1 != CurBuf->getBufferEnd()) + return 0; // Just whitespace. + + // Otherwise, return end of file. + --CurPtr; // Another call to lex will return EOF again. + return EOF; + } +} + +/// 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 (isxdigit(*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) { + return isalnum(c) || c == '_' || c == '$' || c == '.' || c == '@' || 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)) + return LexFloatLiteral(); + } + + while (IsIdentifierChar(*CurPtr)) + ++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 '*': break; // C style comment. + case '/': return ++CurPtr, LexLineComment(); + default: return AsmToken(AsmToken::Slash, StringRef(CurPtr-1, 1)); + } + + // C Style comment. + ++CurPtr; // skip the star. + while (1) { + int CurChar = getNextChar(); + switch (CurChar) { + case EOF: + return ReturnError(TokStart, "unterminated comment"); + case '*': + // End of the comment? + if (CurPtr[0] != '/') break; + + ++CurPtr; // End the */. + return LexToken(); + } + } +} + +/// LexLineComment: Comment: #[^\n]* +/// : //[^\n]* +AsmToken AsmLexer::LexLineComment() { + // FIXME: This is broken if we happen to a comment at the end of a file, which + // was .included, and which doesn't end with a newline. + int CurChar = getNextChar(); + while (CurChar != '\n' && CurChar != '\r' && CurChar != EOF) + CurChar = getNextChar(); + + if (CurChar == EOF) + return AsmToken(AsmToken::Eof, StringRef(CurPtr, 0)); + return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); +} + +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 doLookAhead(const char *&CurPtr, unsigned DefaultRadix) { + const char *FirstHex = 0; + const char *LookAhead = CurPtr; + while (1) { + if (isdigit(*LookAhead)) { + ++LookAhead; + } else if (isxdigit(*LookAhead)) { + if (!FirstHex) + FirstHex = LookAhead; + ++LookAhead; + } else { + break; + } + } + bool isHex = *LookAhead == 'h' || *LookAhead == 'H'; + CurPtr = isHex || !FirstHex ? LookAhead : FirstHex; + if (isHex) + return 16; + return DefaultRadix; +} + +/// 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() { + // Decimal integer: [1-9][0-9]* + if (CurPtr[-1] != '0' || CurPtr[0] == '.') { + unsigned Radix = doLookAhead(CurPtr, 10); + bool isHex = Radix == 16; + // Check for floating point literals. + if (!isHex && (*CurPtr == '.' || *CurPtr == 'e')) { + ++CurPtr; + return LexFloatLiteral(); + } + + StringRef Result(TokStart, CurPtr - TokStart); + + long long Value; + if (Result.getAsInteger(Radix, Value)) { + // Allow positive values that are too large to fit into a signed 64-bit + // integer, but that do fit in an unsigned one, we just convert them over. + unsigned long long UValue; + if (Result.getAsInteger(Radix, UValue)) + return ReturnError(TokStart, !isHex ? "invalid decimal number" : + "invalid hexdecimal number"); + Value = (long long)UValue; + } + + // Consume the [bB][hH]. + if (Radix == 2 || Radix == 16) + ++CurPtr; + + // The darwin/x86 (and x86-64) assembler accepts and ignores type + // suffices on integer literals. + SkipIgnoredIntegerSuffix(CurPtr); + + return AsmToken(AsmToken::Integer, Result, Value); + } + + if (*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); + + long long Value; + 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 AsmToken(AsmToken::Integer, Result, Value); + } + + if (*CurPtr == 'x') { + ++CurPtr; + const char *NumStart = CurPtr; + while (isxdigit(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"); + + unsigned long long Result; + if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) + return ReturnError(TokStart, "invalid hexadecimal number"); + + // Consume the optional [hH]. + if (*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 AsmToken(AsmToken::Integer, StringRef(TokStart, CurPtr - TokStart), + (int64_t)Result); + } + + // Either octal or hexadecimal. + long long Value; + unsigned Radix = doLookAhead(CurPtr, 8); + 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 AsmToken(AsmToken::Integer, 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 != 0 || CurPtr != CurBuf->getBufferEnd())) { + ++CurPtr; + } + return StringRef(TokStart, CurPtr-TokStart); +} + +StringRef AsmLexer::LexUntilEndOfLine() { + TokStart = CurPtr; + + while (*CurPtr != '\n' && + *CurPtr != '\r' && + (*CurPtr != 0 || CurPtr != CurBuf->getBufferEnd())) { + ++CurPtr; + } + return StringRef(TokStart, CurPtr-TokStart); +} + +bool AsmLexer::isAtStartOfComment(char Char) { + // FIXME: This won't work for multi-character comment indicators like "//". + return Char == *MAI.getCommentString(); +} + +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 (isAtStartOfComment(CurChar)) { + // If this comment starts with a '#', then return the Hash token and let + // the assembler parser see if it can be parsed as a cpp line filename + // comment. We do this only if we are at the start of a line. + if (CurChar == '#' && isAtStartOfLine) + return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + isAtStartOfLine = true; + return LexLineComment(); + } + if (isAtStatementSeparator(TokStart)) { + CurPtr += strlen(MAI.getSeparatorString()) - 1; + 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 && !isAtStartOfLine) { + isAtStartOfLine = true; + return AsmToken(AsmToken::EndOfStatement, StringRef(TokStart, 1)); + } + + isAtStartOfLine = 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: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); + case 0: + case ' ': + case '\t': + if (SkipSpace) { + // Ignore whitespace. + return LexToken(); + } else { + int len = 1; + while (*CurPtr==' ' || *CurPtr=='\t') { + CurPtr++; + len++; + } + return AsmToken(AsmToken::Space, StringRef(TokStart, len)); + } + case '\n': // FALL THROUGH. + case '\r': + isAtStartOfLine = 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::Minus, 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 == '=') + return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); + case '|': + if (*CurPtr == '|') + return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); + case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); + case '&': + if (*CurPtr == '&') + return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); + case '!': + if (*CurPtr == '=') + return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); + return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); + case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); + case '/': 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 '<': return ++CurPtr, AsmToken(AsmToken::LessLess, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, + StringRef(TokStart, 2)); + case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, + StringRef(TokStart, 2)); + default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); + } + case '>': + switch (*CurPtr) { + case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, + StringRef(TokStart, 2)); + case '=': return ++CurPtr, 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..a91bd93105b6 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp @@ -0,0 +1,4315 @@ +//===- 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/SmallString.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCParser/AsmCond.h" +#include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +#include <cctype> +#include <set> +#include <string> +#include <vector> +using namespace llvm; + +static cl::opt<bool> +FatalAssemblerWarnings("fatal-assembler-warnings", + cl::desc("Consider warnings as error")); + +MCAsmParserSemaCallback::~MCAsmParserSemaCallback() {} + +namespace { + +/// \brief Helper types for tracking macro definitions. +typedef std::vector<AsmToken> MCAsmMacroArgument; +typedef std::vector<MCAsmMacroArgument> MCAsmMacroArguments; +typedef std::pair<StringRef, MCAsmMacroArgument> MCAsmMacroParameter; +typedef std::vector<MCAsmMacroParameter> MCAsmMacroParameters; + +struct MCAsmMacro { + StringRef Name; + StringRef Body; + MCAsmMacroParameters Parameters; + +public: + MCAsmMacro(StringRef N, StringRef B, const MCAsmMacroParameters &P) : + Name(N), Body(B), Parameters(P) {} + + MCAsmMacro(const MCAsmMacro& Other) + : Name(Other.Name), Body(Other.Body), Parameters(Other.Parameters) {} +}; + +/// \brief Helper class for storing information about an active macro +/// instantiation. +struct MacroInstantiation { + /// The macro being instantiated. + const MCAsmMacro *TheMacro; + + /// The macro instantiation with substitutions. + MemoryBuffer *Instantiation; + + /// 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; + +public: + MacroInstantiation(const MCAsmMacro *M, SMLoc IL, int EB, SMLoc EL, + MemoryBuffer *I); +}; + +struct ParseStatementInfo { + /// \brief The parsed operands from the last parsed statement. + SmallVector<MCParsedAsmOperand*, 8> ParsedOperands; + + /// \brief The opcode from the last parsed instruction. + unsigned Opcode; + + /// \brief Was there an error parsing the inline assembly? + bool ParseError; + + SmallVectorImpl<AsmRewrite> *AsmRewrites; + + ParseStatementInfo() : Opcode(~0U), ParseError(false), AsmRewrites(0) {} + ParseStatementInfo(SmallVectorImpl<AsmRewrite> *rewrites) + : Opcode(~0), ParseError(false), AsmRewrites(rewrites) {} + + ~ParseStatementInfo() { + // Free any parsed operands. + for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i) + delete ParsedOperands[i]; + ParsedOperands.clear(); + } +}; + +/// \brief The concrete assembly parser instance. +class AsmParser : public MCAsmParser { + AsmParser(const AsmParser &) LLVM_DELETED_FUNCTION; + void operator=(const AsmParser &) LLVM_DELETED_FUNCTION; +private: + AsmLexer Lexer; + MCContext &Ctx; + MCStreamer &Out; + const MCAsmInfo &MAI; + SourceMgr &SrcMgr; + SourceMgr::DiagHandlerTy SavedDiagHandler; + void *SavedDiagContext; + MCAsmParserExtension *PlatformParser; + + /// This is the current buffer index we're lexing from as managed by the + /// SourceMgr object. + int CurBuffer; + + AsmCond TheCondState; + std::vector<AsmCond> TheCondStack; + + /// \brief maps directive names to handler methods in parser + /// extensions. Extensions register themselves in this map by calling + /// addDirectiveHandler. + StringMap<ExtensionDirectiveHandler> ExtensionDirectiveMap; + + /// \brief Map of currently defined macros. + StringMap<MCAsmMacro*> MacroMap; + + /// \brief Stack of active macro instantiations. + std::vector<MacroInstantiation*> ActiveMacros; + + /// \brief List of bodies of anonymous macros. + std::deque<MCAsmMacro> MacroLikeBodies; + + /// Boolean tracking whether macro substitution is enabled. + unsigned MacrosEnabledFlag : 1; + + /// Flag tracking whether any errors have been encountered. + unsigned HadError : 1; + + /// The values from the last parsed cpp hash file line comment if any. + StringRef CppHashFilename; + int64_t CppHashLineNumber; + SMLoc CppHashLoc; + int CppHashBuf; + /// When generating dwarf for assembly source files we need to calculate the + /// logical line number based on the last parsed cpp hash file line comment + /// and current line. Since this is slow and messes up the SourceMgr's + /// cache we save the last info we queried with SrcMgr.FindLineNumber(). + SMLoc LastQueryIDLoc; + int LastQueryBuffer; + unsigned LastQueryLine; + + /// AssemblerDialect. ~OU means unset value and use value provided by MAI. + unsigned AssemblerDialect; + + /// \brief is Darwin compatibility enabled? + bool IsDarwin; + + /// \brief Are we parsing ms-style inline assembly? + bool ParsingInlineAsm; + +public: + AsmParser(SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, + const MCAsmInfo &MAI); + virtual ~AsmParser(); + + virtual bool Run(bool NoInitialTextSection, bool NoFinalize = false); + + virtual void addDirectiveHandler(StringRef Directive, + ExtensionDirectiveHandler Handler) { + ExtensionDirectiveMap[Directive] = Handler; + } + +public: + /// @name MCAsmParser Interface + /// { + + virtual SourceMgr &getSourceManager() { return SrcMgr; } + virtual MCAsmLexer &getLexer() { return Lexer; } + virtual MCContext &getContext() { return Ctx; } + virtual MCStreamer &getStreamer() { return Out; } + virtual unsigned getAssemblerDialect() { + if (AssemblerDialect == ~0U) + return MAI.getAssemblerDialect(); + else + return AssemblerDialect; + } + virtual void setAssemblerDialect(unsigned i) { + AssemblerDialect = i; + } + + virtual bool Warning(SMLoc L, const Twine &Msg, + ArrayRef<SMRange> Ranges = None); + virtual bool Error(SMLoc L, const Twine &Msg, + ArrayRef<SMRange> Ranges = None); + + virtual const AsmToken &Lex(); + + void setParsingInlineAsm(bool V) { ParsingInlineAsm = V; } + bool isParsingInlineAsm() { 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); + + bool parseExpression(const MCExpr *&Res); + virtual bool parseExpression(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool parsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool parseAbsoluteExpression(int64_t &Res); + + /// \brief Parse an identifier or string (as a quoted identifier) + /// and set \p Res to the identifier contents. + virtual bool parseIdentifier(StringRef &Res); + virtual void eatToEndOfStatement(); + + virtual void checkForValidSection(); + /// } + +private: + + bool parseStatement(ParseStatementInfo &Info); + void eatToEndOfLine(); + bool parseCppHashLineFilenameComment(const SMLoc &L); + + void checkForBadMacro(SMLoc DirectiveLoc, StringRef Name, StringRef Body, + MCAsmMacroParameters Parameters); + bool expandMacro(raw_svector_ostream &OS, StringRef Body, + const MCAsmMacroParameters &Parameters, + const MCAsmMacroArguments &A, + const SMLoc &L); + + /// \brief Are macros enabled in the parser? + bool areMacrosEnabled() {return MacrosEnabledFlag;} + + /// \brief Control a flag in the parser that enables or disables macros. + void setMacrosEnabled(bool Flag) {MacrosEnabledFlag = Flag;} + + /// \brief Lookup a previously defined macro. + /// \param Name Macro name. + /// \returns Pointer to macro. NULL if no such macro was defined. + const MCAsmMacro* lookupMacro(StringRef Name); + + /// \brief Define a new macro with the given name and information. + void defineMacro(StringRef Name, const MCAsmMacro& Macro); + + /// \brief Undefine a macro. If no such macro was defined, it's a no-op. + void undefineMacro(StringRef Name); + + /// \brief Are we inside a macro instantiation? + bool isInsideMacroInstantiation() {return !ActiveMacros.empty();} + + /// \brief Handle entry to macro instantiation. + /// + /// \param M The macro. + /// \param NameLoc Instantiation location. + bool handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc); + + /// \brief Handle exit from macro instantiation. + void handleMacroExit(); + + /// \brief Extract AsmTokens for a macro argument. If the argument delimiter + /// is initially unknown, set it to AsmToken::Eof. It will be set to the + /// correct delimiter by the method. + bool parseMacroArgument(MCAsmMacroArgument &MA, + AsmToken::TokenKind &ArgumentDelimiter); + + /// \brief 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, + ArrayRef<SMRange> Ranges = None) const { + SrcMgr.PrintMessage(Loc, Kind, Msg, Ranges); + } + static void DiagHandler(const SMDiagnostic &Diag, void *Context); + + /// \brief Enter the specified file. This returns true on failure. + bool enterIncludeFile(const std::string &Filename); + + /// \brief Process the specified file for the .incbin directive. + /// This returns true on failure. + bool processIncbinFile(const std::string &Filename); + + /// \brief 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 -1, should be the known buffer id that contains the + /// location. + void jumpToLoc(SMLoc Loc, int InBuffer=-1); + + /// \brief 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. + virtual StringRef parseStringToEndOfStatement(); + + /// \brief 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); + + 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); + + // 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_VALUE, DK_2BYTE, DK_LONG, DK_INT, DK_4BYTE, DK_QUAD, DK_8BYTE, 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_IFB, DK_IFNB, DK_IFC, DK_IFNC, 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_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_SIGNAL_FRAME, DK_CFI_UNDEFINED, + DK_CFI_REGISTER, DK_CFI_WINDOW_SAVE, + DK_MACROS_ON, DK_MACROS_OFF, DK_MACRO, DK_ENDM, DK_ENDMACRO, DK_PURGEM, + DK_SLEB128, DK_ULEB128 + }; + + /// \brief Maps directive name --> DirectiveKind enum, for + /// directives parsed by this class. + StringMap<DirectiveKind> DirectiveKindMap; + + // ".ascii", ".asciz", ".string" + bool parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); + bool parseDirectiveValue(unsigned Size); // ".byte", ".long", ... + bool parseDirectiveRealValue(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(); + + // .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 parseDirectiveCFISignalFrame(); + bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc); + + // macro directives + bool parseDirectivePurgeMacro(SMLoc DirectiveLoc); + bool parseDirectiveEndMacro(StringRef Directive); + bool parseDirectiveMacro(SMLoc DirectiveLoc); + bool parseDirectiveMacrosOnOff(StringRef Directive); + + // ".bundle_align_mode" + bool parseDirectiveBundleAlignMode(); + // ".bundle_lock" + bool parseDirectiveBundleLock(); + // ".bundle_unlock" + bool parseDirectiveBundleUnlock(); + + // ".space", ".skip" + bool parseDirectiveSpace(StringRef IDVal); + + // .sleb128 (Signed=true) and .uleb128 (Signed=false) + bool parseDirectiveLEB128(bool Signed); + + /// \brief 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" + + bool parseDirectiveIf(SMLoc DirectiveLoc); // ".if" + // ".ifb" or ".ifnb", depending on ExpectBlank. + bool parseDirectiveIfb(SMLoc DirectiveLoc, bool ExpectBlank); + // ".ifc" or ".ifnc", depending on ExpectEqual. + bool parseDirectiveIfc(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 + virtual bool parseEscapedString(std::string &Data); + + 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); // ".rept" + 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); + + void initializeDirectiveKindMap(); +}; +} + +namespace llvm { + +extern MCAsmParserExtension *createDarwinAsmParser(); +extern MCAsmParserExtension *createELFAsmParser(); +extern MCAsmParserExtension *createCOFFAsmParser(); + +} + +enum { DEFAULT_ADDRSPACE = 0 }; + +AsmParser::AsmParser(SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, + const MCAsmInfo &_MAI) + : Lexer(_MAI), Ctx(_Ctx), Out(_Out), MAI(_MAI), SrcMgr(_SM), + PlatformParser(0), CurBuffer(0), MacrosEnabledFlag(true), + CppHashLineNumber(0), AssemblerDialect(~0U), IsDarwin(false), + ParsingInlineAsm(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)); + + // Initialize the platform / file format parser. + // + // FIXME: This is a hack, we need to (majorly) cleanup how these objects are + // created. + if (_MAI.hasMicrosoftFastStdCallMangling()) { + PlatformParser = createCOFFAsmParser(); + PlatformParser->Initialize(*this); + } else if (_MAI.hasSubsectionsViaSymbols()) { + PlatformParser = createDarwinAsmParser(); + PlatformParser->Initialize(*this); + IsDarwin = true; + } else { + PlatformParser = createELFAsmParser(); + PlatformParser->Initialize(*this); + } + + initializeDirectiveKindMap(); +} + +AsmParser::~AsmParser() { + assert(ActiveMacros.empty() && "Unexpected active macro instantiation!"); + + // Destroy any macros. + for (StringMap<MCAsmMacro *>::iterator it = MacroMap.begin(), + ie = MacroMap.end(); + it != ie; ++it) + delete it->getValue(); + + delete PlatformParser; +} + +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"); +} + +bool AsmParser::Warning(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { + if (FatalAssemblerWarnings) + return Error(L, Msg, Ranges); + printMessage(L, SourceMgr::DK_Warning, Msg, Ranges); + printMacroInstantiations(); + return false; +} + +bool AsmParser::Error(SMLoc L, const Twine &Msg, ArrayRef<SMRange> Ranges) { + HadError = true; + printMessage(L, SourceMgr::DK_Error, Msg, Ranges); + printMacroInstantiations(); + return true; +} + +bool AsmParser::enterIncludeFile(const std::string &Filename) { + std::string IncludedFile; + int NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); + if (NewBuf == -1) + return true; + + CurBuffer = NewBuf; + + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + + 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) { + std::string IncludedFile; + int NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc(), IncludedFile); + if (NewBuf == -1) + return true; + + // Pick up the bytes from the file and emit them. + getStreamer().EmitBytes(SrcMgr.getMemoryBuffer(NewBuf)->getBuffer()); + return false; +} + +void AsmParser::jumpToLoc(SMLoc Loc, int InBuffer) { + if (InBuffer != -1) { + CurBuffer = InBuffer; + } else { + CurBuffer = SrcMgr.FindBufferContainingLoc(Loc); + } + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), Loc.getPointer()); +} + +const AsmToken &AsmParser::Lex() { + const AsmToken *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); + tok = &Lexer.Lex(); + } + } + + if (tok->is(AsmToken::Error)) + Error(Lexer.getErrLoc(), Lexer.getErr()); + + return *tok; +} + +bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { + // Create the initial section, if requested. + if (!NoInitialTextSection) + Out.InitSections(); + + // Prime the lexer. + Lex(); + + HadError = false; + AsmCond StartingCondState = TheCondState; + + // If we are generating dwarf for assembly source files save the initial text + // section and generate a .file directive. + if (getContext().getGenDwarfForAssembly()) { + getContext().setGenDwarfSection(getStreamer().getCurrentSection().first); + MCSymbol *SectionStartSym = getContext().CreateTempSymbol(); + getStreamer().EmitLabel(SectionStartSym); + getContext().setGenDwarfSectionStartSym(SectionStartSym); + getStreamer().EmitDwarfFileDirective(getContext().nextGenDwarfFileNumber(), + StringRef(), + getContext().getMainFileName()); + } + + // While we have input, parse each statement. + while (Lexer.isNot(AsmToken::Eof)) { + ParseStatementInfo Info; + if (!parseStatement(Info)) + continue; + + // We had an error, validate that one was emitted and recover by skipping to + // the next line. + assert(HadError && "Parse statement returned an error, but none emitted!"); + eatToEndOfStatement(); + } + + if (TheCondState.TheCond != StartingCondState.TheCond || + TheCondState.Ignore != StartingCondState.Ignore) + return TokError("unmatched .ifs or .elses"); + + // Check to see there are no empty DwarfFile slots. + const SmallVectorImpl<MCDwarfFile *> &MCDwarfFiles = + getContext().getMCDwarfFiles(); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + if (!MCDwarfFiles[i]) + TokError("unassigned file number: " + Twine(i) + " for .file directives"); + } + + // 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 && MAI.hasSubsectionsViaSymbols()) { + const MCContext::SymbolTable &Symbols = getContext().getSymbols(); + for (MCContext::SymbolTable::const_iterator i = Symbols.begin(), + e = Symbols.end(); + i != e; ++i) { + MCSymbol *Sym = i->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. + printMessage( + getLexer().getLoc(), SourceMgr::DK_Error, + "assembler local symbol '" + Sym->getName() + "' not defined"); + } + } + + // Finalize the output stream if there are no errors and if the client wants + // us to. + if (!HadError && !NoFinalize) + Out.Finish(); + + return HadError; +} + +void AsmParser::checkForValidSection() { + if (!ParsingInlineAsm && !getStreamer().getCurrentSection().first) { + TokError("expected section directive before assembly directive"); + Out.InitToTextSection(); + } +} + +/// \brief Throw away the rest of the line for testing purposes. +void AsmParser::eatToEndOfStatement() { + while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) + Lex(); + + // Eat EOL. + if (Lexer.is(AsmToken::EndOfStatement)) + Lex(); +} + +StringRef AsmParser::parseStringToEndOfStatement() { + const char *Start = getTok().getLoc().getPointer(); + + while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) + 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)) + Lex(); + + const char *End = getTok().getLoc().getPointer(); + return StringRef(Start, End - Start); +} + +/// \brief 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; +} + +/// \brief 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; + if (Lexer.isNot(AsmToken::RBrac)) + return TokError("expected ']' in brackets expression"); + EndLoc = Lexer.getTok().getEndLoc(); + Lex(); + return false; +} + +/// \brief 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()); + return false; + case AsmToken::Dollar: + case AsmToken::At: + case AsmToken::String: + case AsmToken::Identifier: { + StringRef Identifier; + if (parseIdentifier(Identifier)) { + if (FirstTokenKind == AsmToken::Dollar) { + if (Lexer.getMAI().getDollarIsPC()) { + // 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; + } else + return Error(FirstTokenLoc, "invalid token in expression"); + return true; + } + } + + EndLoc = SMLoc::getFromPointer(Identifier.end()); + + // This is a symbol reference. + StringRef SymbolName = Identifier; + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + std::pair<StringRef, StringRef> Split = Identifier.split('@'); + + // Lookup the symbol variant if used. + if (Split.first.size() != Identifier.size()) { + Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); + if (Variant != MCSymbolRefExpr::VK_Invalid) { + SymbolName = Split.first; + } else if (MAI.doesAllowAtInName()) { + Variant = MCSymbolRefExpr::VK_None; + } else { + Variant = MCSymbolRefExpr::VK_None; + return TokError("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() && isa<MCConstantExpr>(Sym->getVariableValue())) { + if (Variant) + return Error(EndLoc, "unexpected modifier on variable reference"); + + Res = Sym->getVariableValue(); + return false; + } + + // Otherwise create a symbol ref. + Res = MCSymbolRefExpr::Create(Sym, Variant, getContext()); + return false; + } + 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) { + Variant = MCSymbolRefExpr::VK_None; + return TokError("invalid variant '" + Split.second + "'"); + } + IDVal = Split.first; + } + if (IDVal == "f" || IDVal == "b") { + MCSymbol *Sym = + Ctx.GetDirectionalLocalSymbol(IntVal, IDVal == "f" ? 1 : 0); + Res = MCSymbolRefExpr::Create(Sym, Variant, getContext()); + if (IDVal == "b" && Sym->isUndefined()) + return Error(Loc, "invalid reference to undefined symbol"); + 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()); + return false; + case AsmToken::Plus: + Lex(); // Eat the operator. + if (parsePrimaryExpr(Res, EndLoc)) + return true; + Res = MCUnaryExpr::CreatePlus(Res, getContext()); + return false; + case AsmToken::Tilde: + Lex(); // Eat the operator. + if (parsePrimaryExpr(Res, EndLoc)) + return true; + Res = MCUnaryExpr::CreateNot(Res, getContext()); + return false; + } +} + +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 0; + + 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 0; + 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 0; + + if (!LHS) + LHS = BE->getLHS(); + if (!RHS) + RHS = BE->getRHS(); + + return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext()); + } + } + + llvm_unreachable("Invalid expression kind!"); +} + +/// \brief 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 = 0; + if (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. + int64_t Value; + if (Res->EvaluateAsAbsolute(Value)) + Res = MCConstantExpr::Create(Value, getContext()); + + return false; +} + +bool AsmParser::parseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { + Res = 0; + return parseParenExpr(Res, EndLoc) || parseBinOpRHS(1, Res, EndLoc); +} + +bool AsmParser::parseAbsoluteExpression(int64_t &Res) { + const MCExpr *Expr; + + SMLoc StartLoc = Lexer.getLoc(); + if (parseExpression(Expr)) + return true; + + if (!Expr->EvaluateAsAbsolute(Res)) + return Error(StartLoc, "expected absolute expression"); + + return false; +} + +static unsigned getBinOpPrecedence(AsmToken::TokenKind K, + MCBinaryExpr::Opcode &Kind) { + 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 = MCBinaryExpr::Shr; + 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; + } +} + +/// \brief 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) { + while (1) { + 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 (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()); + } +} + +/// ParseStatement: +/// ::= EndOfStatement +/// ::= Label* Directive ...Operands... EndOfStatement +/// ::= Label* Identifier OperandList* EndOfStatement +bool AsmParser::parseStatement(ParseStatementInfo &Info) { + if (Lexer.is(AsmToken::EndOfStatement)) { + Out.AddBlankLine(); + Lex(); + return false; + } + + // Statements always start with an identifier or are a full line comment. + AsmToken ID = getTok(); + SMLoc IDLoc = ID.getLoc(); + StringRef IDVal; + int64_t LocalLabelVal = -1; + // A full line comment is a '#' as the first token. + if (Lexer.is(AsmToken::Hash)) + 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) + return TokError("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) + return TokError("unexpected token at start of statement"); + } + } + } else if (Lexer.is(AsmToken::Dot)) { + // Treat '.' as a valid identifier in this context. + Lex(); + IDVal = "."; + } else if (parseIdentifier(IDVal)) { + if (!TheCondState.Ignore) + return TokError("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: + return parseDirectiveIf(IDLoc); + case DK_IFB: + return parseDirectiveIfb(IDLoc, true); + case DK_IFNB: + return parseDirectiveIfb(IDLoc, false); + case DK_IFC: + return parseDirectiveIfc(IDLoc, true); + case DK_IFNC: + return parseDirectiveIfc(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: { + checkForValidSection(); + + // 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) + Sym = getContext().GetOrCreateSymbol(IDVal); + else + Sym = Ctx.CreateDirectionalLocalSymbol(LocalLabelVal); + if (!Sym->isUndefined() || Sym->isVariable()) + return Error(IDLoc, "invalid symbol redefinition"); + + // Emit the label. + if (!ParsingInlineAsm) + Out.EmitLabel(Sym); + + // 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 (getContext().getGenDwarfForAssembly()) + MCGenDwarfLabelEntry::Make(Sym, &getStreamer(), getSourceManager(), + IDLoc); + + getTargetParser().onLabelParsed(Sym); + + // Consume any end of statement token, if present, to avoid spurious + // AddBlankLine calls(). + if (Lexer.is(AsmToken::EndOfStatement)) { + Lex(); + if (Lexer.is(AsmToken::Eof)) + return false; + } + + return false; + } + + case AsmToken::Equal: + // 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 = lookupMacro(IDVal)) { + return handleMacroEntry(M, IDLoc); + } + + // Otherwise, we have a normal instruction or directive. + + // Directives start with "." + if (IDVal[0] == '.' && 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. + + // First query the target-specific parser. It will return 'true' if it + // isn't interested in this directive. + if (!getTargetParser().ParseDirective(ID)) + return false; + + // Next, check the extention 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: + return parseDirectiveValue(1); + case DK_SHORT: + case DK_VALUE: + case DK_2BYTE: + return parseDirectiveValue(2); + case DK_LONG: + case DK_INT: + case DK_4BYTE: + return parseDirectiveValue(4); + case DK_QUAD: + case DK_8BYTE: + return parseDirectiveValue(8); + case DK_SINGLE: + case DK_FLOAT: + return parseDirectiveRealValue(APFloat::IEEEsingle); + case DK_DOUBLE: + return parseDirectiveRealValue(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 supported yet"); + case DK_REPT: + return parseDirectiveRept(IDLoc); + 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_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_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_ENDM: + case DK_ENDMACRO: + return parseDirectiveEndMacro(IDVal); + case DK_PURGEM: + return parseDirectivePurgeMacro(IDLoc); + } + + 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); + + checkForValidSection(); + + // Canonicalize the opcode to lower case. + std::string OpcodeStr = IDVal.lower(); + ParseInstructionInfo IInfo(Info.AsmRewrites); + bool HadError = getTargetParser().ParseInstruction(IInfo, OpcodeStr, IDLoc, + Info.ParsedOperands); + Info.ParseError = HadError; + + // 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()); + } + + // If we are generating dwarf for assembly source files and the current + // section is the initial text section then generate a .loc directive for + // the instruction. + if (!HadError && getContext().getGenDwarfForAssembly() && + getContext().getGenDwarfSection() == + getStreamer().getCurrentSection().first) { + + unsigned Line = SrcMgr.FindLineNumber(IDLoc, CurBuffer); + + // 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. + const SmallVectorImpl<MCDwarfFile *> &MCDwarfFiles = + getContext().getMCDwarfFiles(); + if (CppHashFilename.size() != 0) { + if (MCDwarfFiles[getContext().getGenDwarfFileNumber()]->getName() != + CppHashFilename) + getStreamer().EmitDwarfFileDirective( + getContext().nextGenDwarfFileNumber(), StringRef(), + CppHashFilename); + + // Since SrcMgr.FindLineNumber() is slow and messes up the SourceMgr's + // cache with the different Loc from the call above we save the last + // info we queried here with SrcMgr.FindLineNumber(). + unsigned CppHashLocLineNo; + if (LastQueryIDLoc == CppHashLoc && LastQueryBuffer == CppHashBuf) + CppHashLocLineNo = LastQueryLine; + else { + CppHashLocLineNo = SrcMgr.FindLineNumber(CppHashLoc, CppHashBuf); + LastQueryLine = CppHashLocLineNo; + LastQueryIDLoc = CppHashLoc; + LastQueryBuffer = CppHashBuf; + } + Line = CppHashLineNumber - 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 (!HadError) { + unsigned ErrorInfo; + HadError = getTargetParser().MatchAndEmitInstruction( + IDLoc, Info.Opcode, Info.ParsedOperands, Out, ErrorInfo, + ParsingInlineAsm); + } + + // Don't skip the rest of the line, the instruction parser is responsible for + // that. + return false; +} + +/// eatToEndOfLine uses the Lexer to eat the characters to the end of the line +/// since they may not be able to be tokenized to get to the end of line token. +void AsmParser::eatToEndOfLine() { + if (!Lexer.is(AsmToken::EndOfStatement)) + Lexer.LexUntilEndOfLine(); + // Eat EOL. + Lex(); +} + +/// parseCppHashLineFilenameComment as this: +/// ::= # number "filename" +/// or just as a full line comment if it doesn't have a number and a string. +bool AsmParser::parseCppHashLineFilenameComment(const SMLoc &L) { + Lex(); // Eat the hash token. + + if (getLexer().isNot(AsmToken::Integer)) { + // Consume the line since in cases it is not a well-formed line directive, + // as if were simply a full line comment. + eatToEndOfLine(); + return false; + } + + int64_t LineNumber = getTok().getIntVal(); + Lex(); + + if (getLexer().isNot(AsmToken::String)) { + eatToEndOfLine(); + return false; + } + + StringRef Filename = getTok().getString(); + // Get rid of the enclosing quotes. + Filename = Filename.substr(1, Filename.size() - 2); + + // Save the SMLoc, Filename and LineNumber for later use by diagnostics. + CppHashLoc = L; + CppHashFilename = Filename; + CppHashLineNumber = LineNumber; + CppHashBuf = CurBuffer; + + // Ignore any trailing characters, they're just comment. + eatToEndOfLine(); + return false; +} + +/// \brief 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(); + const SMLoc &DiagLoc = Diag.getLoc(); + int DiagBuf = DiagSrcMgr.FindBufferContainingLoc(DiagLoc); + int CppHashBuf = Parser->SrcMgr.FindBufferContainingLoc(Parser->CppHashLoc); + + // Like SourceMgr::printMessage() we need to print the include stack if any + // before printing the message. + int DiagCurBuffer = DiagSrcMgr.FindBufferContainingLoc(DiagLoc); + if (!Parser->SavedDiagHandler && DiagCurBuffer > 0) { + 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->CppHashLineNumber || &DiagSrcMgr != &Parser->SrcMgr || + DiagBuf != CppHashBuf) { + if (Parser->SavedDiagHandler) + Parser->SavedDiagHandler(Diag, Parser->SavedDiagContext); + else + Diag.print(0, OS); + return; + } + + // Use the CppHashFilename and calculate a line number based on the + // CppHashLoc and CppHashLineNumber relative to this Diag's SMLoc for + // the diagnostic. + const std::string &Filename = Parser->CppHashFilename; + + int DiagLocLineNo = DiagSrcMgr.FindLineNumber(DiagLoc, DiagBuf); + int CppHashLocLineNo = + Parser->SrcMgr.FindLineNumber(Parser->CppHashLoc, CppHashBuf); + int LineNo = + Parser->CppHashLineNumber - 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(0, 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, + const MCAsmMacroParameters &Parameters, + const MCAsmMacroArguments &A, const SMLoc &L) { + unsigned NParameters = Parameters.size(); + if (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 (!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 (!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 (MCAsmMacroArgument::const_iterator it = A[Index].begin(), + ie = A[Index].end(); + it != ie; ++it) + OS << it->getString(); + 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].first == Argument) + break; + + if (Index == NParameters) { + if (Body[Pos + 1] == '(' && Body[Pos + 2] == ')') + Pos += 3; + else { + OS << '\\' << Argument; + Pos = I; + } + } else { + for (MCAsmMacroArgument::const_iterator it = A[Index].begin(), + ie = A[Index].end(); + it != ie; ++it) + if (it->getKind() == AsmToken::String) + OS << it->getStringContents(); + else + OS << it->getString(); + + Pos += 1 + Argument.size(); + } + } + // Update the scan point. + Body = Body.substr(Pos); + } + + return false; +} + +MacroInstantiation::MacroInstantiation(const MCAsmMacro *M, SMLoc IL, int EB, + SMLoc EL, MemoryBuffer *I) + : TheMacro(M), Instantiation(I), InstantiationLoc(IL), ExitBuffer(EB), + ExitLoc(EL) {} + +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::Percent: + case AsmToken::Less: + case AsmToken::LessEqual: + case AsmToken::LessLess: + case AsmToken::LessGreater: + case AsmToken::Greater: + case AsmToken::GreaterEqual: + case AsmToken::GreaterGreater: + return true; + } +} + +bool AsmParser::parseMacroArgument(MCAsmMacroArgument &MA, + AsmToken::TokenKind &ArgumentDelimiter) { + unsigned ParenLevel = 0; + unsigned AddTokens = 0; + + // gas accepts arguments separated by whitespace, except on Darwin + if (!IsDarwin) + Lexer.setSkipSpace(false); + + for (;;) { + if (Lexer.is(AsmToken::Eof) || Lexer.is(AsmToken::Equal)) { + Lexer.setSkipSpace(true); + return TokError("unexpected token in macro instantiation"); + } + + if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) { + // Spaces and commas cannot be mixed to delimit parameters + if (ArgumentDelimiter == AsmToken::Eof) + ArgumentDelimiter = AsmToken::Comma; + else if (ArgumentDelimiter != AsmToken::Comma) { + Lexer.setSkipSpace(true); + return TokError("expected ' ' for macro argument separator"); + } + break; + } + + if (Lexer.is(AsmToken::Space)) { + 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 (ArgumentDelimiter == AsmToken::Space || + ArgumentDelimiter == AsmToken::Eof) { + if (isOperator(Lexer.getKind())) { + // Check to see whether the token is used as an operator, + // or part of an identifier + const char *NextChar = getTok().getEndLoc().getPointer(); + if (*NextChar == ' ') + AddTokens = 2; + } + + if (!AddTokens && ParenLevel == 0) { + if (ArgumentDelimiter == AsmToken::Eof && + !isOperator(Lexer.getKind())) + ArgumentDelimiter = AsmToken::Space; + 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()); + if (AddTokens) + AddTokens--; + Lex(); + } + + Lexer.setSkipSpace(true); + 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; + // Argument delimiter is initially unknown. It will be set by + // parseMacroArgument() + AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof; + + // 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 + for (unsigned Parameter = 0; !NParameters || Parameter < NParameters; + ++Parameter) { + MCAsmMacroArgument MA; + + if (parseMacroArgument(MA, ArgumentDelimiter)) + return true; + + if (!MA.empty() || !NParameters) + A.push_back(MA); + else if (NParameters) { + if (!M->Parameters[Parameter].second.empty()) + A.push_back(M->Parameters[Parameter].second); + } + + // 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)) { + if (NParameters && Parameter < NParameters - 1) { + if (M->Parameters[Parameter + 1].second.empty()) + return TokError("macro argument '" + + Twine(M->Parameters[Parameter + 1].first) + + "' is missing"); + else + continue; + } + return false; + } + + if (Lexer.is(AsmToken::Comma)) + Lex(); + } + return TokError("Too many arguments"); +} + +const MCAsmMacro *AsmParser::lookupMacro(StringRef Name) { + StringMap<MCAsmMacro *>::iterator I = MacroMap.find(Name); + return (I == MacroMap.end()) ? NULL : I->getValue(); +} + +void AsmParser::defineMacro(StringRef Name, const MCAsmMacro &Macro) { + MacroMap[Name] = new MCAsmMacro(Macro); +} + +void AsmParser::undefineMacro(StringRef Name) { + StringMap<MCAsmMacro *>::iterator I = MacroMap.find(Name); + if (I != MacroMap.end()) { + delete I->getValue(); + MacroMap.erase(I); + } +} + +bool AsmParser::handleMacroEntry(const MCAsmMacro *M, SMLoc NameLoc) { + // Arbitrarily limit macro nesting depth, to match 'as'. We can eliminate + // this, although we should protect against infinite loops. + if (ActiveMacros.size() == 20) + return TokError("macros cannot be nested more than 20 levels deep"); + + MCAsmMacroArguments A; + if (parseMacroArguments(M, A)) + return true; + + // Remove any trailing empty arguments. Do this after-the-fact as we have + // to keep empty arguments in the middle of the list or positionality + // gets off. e.g., "foo 1, , 2" vs. "foo 1, 2," + while (!A.empty() && A.back().empty()) + A.pop_back(); + + // 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, getTok().getLoc())) + return true; + + // We include the .endmacro in the buffer as our cue to exit the macro + // instantiation. + OS << ".endmacro\n"; + + MemoryBuffer *Instantiation = + MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>"); + + // Create the macro instantiation object and add to the current macro + // instantiation stack. + MacroInstantiation *MI = new MacroInstantiation( + M, NameLoc, CurBuffer, getTok().getLoc(), Instantiation); + ActiveMacros.push_back(MI); + + // Jump to the macro instantiation and prime the lexer. + CurBuffer = SrcMgr.AddNewSourceBuffer(MI->Instantiation, SMLoc()); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + 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(); +} + +static bool isUsedIn(const MCSymbol *Sym, const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Binary: { + const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(Value); + return isUsedIn(Sym, BE->getLHS()) || isUsedIn(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 isUsedIn(Sym, S.getVariableValue()); + return &S == Sym; + } + case MCExpr::Unary: + return isUsedIn(Sym, static_cast<const MCUnaryExpr *>(Value)->getSubExpr()); + } + + llvm_unreachable("Unknown expr kind!"); +} + +bool AsmParser::parseAssignment(StringRef Name, bool allow_redef, + bool NoDeadStrip) { + // FIXME: Use better location, we should use proper tokens. + SMLoc EqualLoc = Lexer.getLoc(); + + const MCExpr *Value; + if (parseExpression(Value)) + return true; + + // Note: we don't count b as used in "a = b". This is to allow + // a = b + // b = c + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in assignment"); + + // Error on assignment to '.'. + if (Name == ".") { + return Error(EqualLoc, ("assignment to pseudo-symbol '.' is unsupported " + "(use '.space' or '.org').)")); + } + + // Eat the end of statement marker. + Lex(); + + // 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). + MCSymbol *Sym = 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 (isUsedIn(Sym, Value)) + return Error(EqualLoc, "Recursive use of '" + Name + "'"); + else if (Sym->isUndefined() && !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 Error(EqualLoc, "redefinition of '" + Name + "'"); + else if (!Sym->isVariable()) + return Error(EqualLoc, "invalid assignment to '" + Name + "'"); + else if (!isa<MCConstantExpr>(Sym->getVariableValue())) + return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + + Name + "'"); + + // Don't count these checks as uses. + Sym->setUsed(false); + } else + Sym = getContext().GetOrCreateSymbol(Name); + + // FIXME: Handle '.'. + + // 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. + Lex(); + if (Lexer.isNot(AsmToken::Identifier)) + return true; + + // We have a '$' or '@' followed by an identifier, make sure they are adjacent. + if (PrefixLoc.getPointer() + 1 != getTok().getLoc().getPointer()) + return true; + + // Construct the joined identifier and consume the token. + Res = + StringRef(PrefixLoc.getPointer(), getTok().getIdentifier().size() + 1); + Lex(); + 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 (parseIdentifier(Name)) + return TokError("expected identifier after '" + Twine(IDVal) + "'"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '" + Twine(IDVal) + "'"); + Lex(); + + return parseAssignment(Name, allow_redef, true); +} + +bool AsmParser::parseEscapedString(std::string &Data) { + assert(getLexer().is(AsmToken::String) && "Unexpected current token!"); + + 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; + } + } + + return false; +} + +/// parseDirectiveAscii: +/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ] +bool AsmParser::parseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + checkForValidSection(); + + for (;;) { + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in '" + Twine(IDVal) + "' directive"); + + std::string Data; + if (parseEscapedString(Data)) + return true; + + getStreamer().EmitBytes(Data); + if (ZeroTerminated) + getStreamer().EmitBytes(StringRef("\0", 1)); + + Lex(); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// parseDirectiveValue +/// ::= (.byte | .short | ... ) [ expression (, expression)* ] +bool AsmParser::parseDirectiveValue(unsigned Size) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + checkForValidSection(); + + for (;;) { + 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"); + getStreamer().EmitIntValue(IntValue, Size); + } else + getStreamer().EmitValue(Value, Size); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + // FIXME: Improve diagnostic. + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// parseDirectiveRealValue +/// ::= (.single | .double) [ expression (, expression)* ] +bool AsmParser::parseDirectiveRealValue(const fltSemantics &Semantics) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + checkForValidSection(); + + for (;;) { + // 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)) { + Lex(); + IsNeg = true; + } else if (getLexer().is(AsmToken::Plus)) + Lex(); + + if (getLexer().isNot(AsmToken::Integer) && + getLexer().isNot(AsmToken::Real) && + getLexer().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(); + + // Emit the value as an integer. + APInt AsInt = Value.bitcastToAPInt(); + getStreamer().EmitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// parseDirectiveZero +/// ::= .zero expression +bool AsmParser::parseDirectiveZero() { + checkForValidSection(); + + int64_t NumBytes; + if (parseAbsoluteExpression(NumBytes)) + return true; + + int64_t Val = 0; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (parseAbsoluteExpression(Val)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.zero' directive"); + + Lex(); + + getStreamer().EmitFill(NumBytes, Val); + + return false; +} + +/// parseDirectiveFill +/// ::= .fill expression [ , expression [ , expression ] ] +bool AsmParser::parseDirectiveFill() { + checkForValidSection(); + + int64_t NumValues; + if (parseAbsoluteExpression(NumValues)) + return true; + + int64_t FillSize = 1; + int64_t FillExpr = 0; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.fill' directive"); + Lex(); + + if (parseAbsoluteExpression(FillSize)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.fill' directive"); + Lex(); + + if (parseAbsoluteExpression(FillExpr)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.fill' directive"); + + Lex(); + } + } + + if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8) + return TokError("invalid '.fill' size, expected 1, 2, 4, or 8"); + + for (uint64_t i = 0, e = NumValues; i != e; ++i) + getStreamer().EmitIntValue(FillExpr, FillSize); + + return false; +} + +/// parseDirectiveOrg +/// ::= .org expression [ , expression ] +bool AsmParser::parseDirectiveOrg() { + checkForValidSection(); + + const MCExpr *Offset; + SMLoc Loc = getTok().getLoc(); + if (parseExpression(Offset)) + return true; + + // Parse optional fill expression. + int64_t FillExpr = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.org' directive"); + Lex(); + + if (parseAbsoluteExpression(FillExpr)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.org' directive"); + } + + Lex(); + + // Only limited forms of relocatable expressions are accepted here, it + // has to be relative to the current section. The streamer will return + // 'true' if the expression wasn't evaluatable. + if (getStreamer().EmitValueToOffset(Offset, FillExpr)) + return Error(Loc, "expected assembly-time absolute expression"); + + return false; +} + +/// parseDirectiveAlign +/// ::= {.align, ...} expression [ , expression [ , expression ]] +bool AsmParser::parseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + checkForValidSection(); + + SMLoc AlignmentLoc = getLexer().getLoc(); + int64_t Alignment; + if (parseAbsoluteExpression(Alignment)) + return true; + + SMLoc MaxBytesLoc; + bool HasFillExpr = false; + int64_t FillExpr = 0; + int64_t MaxBytesToFill = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + // The fill expression can be omitted while specifying a maximum number of + // alignment bytes, e.g: + // .align 3,,4 + if (getLexer().isNot(AsmToken::Comma)) { + HasFillExpr = true; + if (parseAbsoluteExpression(FillExpr)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + MaxBytesLoc = getLexer().getLoc(); + if (parseAbsoluteExpression(MaxBytesToFill)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + } + } + + Lex(); + + if (!HasFillExpr) + FillExpr = 0; + + // Compute alignment in bytes. + if (IsPow2) { + // FIXME: Diagnose overflow. + if (Alignment >= 32) { + Error(AlignmentLoc, "invalid alignment value"); + Alignment = 31; + } + + Alignment = 1ULL << Alignment; + } else { + // Reject alignments that aren't a power of two, for gas compatibility. + if (!isPowerOf2_64(Alignment)) + Error(AlignmentLoc, "alignment must be a power of 2"); + } + + // Diagnose non-sensical max bytes to align. + if (MaxBytesLoc.isValid()) { + if (MaxBytesToFill < 1) { + 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. + bool UseCodeAlign = getStreamer().getCurrentSection().first->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 false; +} + +/// parseDirectiveFile +/// ::= .file [number] filename +/// ::= .file number directory filename +bool AsmParser::parseDirectiveFile(SMLoc DirectiveLoc) { + // FIXME: I'm not sure what this is. + int64_t FileNumber = -1; + SMLoc FileNumberLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Integer)) { + FileNumber = getTok().getIntVal(); + Lex(); + + if (FileNumber < 1) + return TokError("file number less than one"); + } + + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.file' directive"); + + // Usually the directory and filename together, otherwise just the directory. + // Allow the strings to have escaped octal character sequence. + std::string Path = getTok().getString(); + if (parseEscapedString(Path)) + return true; + Lex(); + + StringRef Directory; + StringRef Filename; + std::string FilenameData; + if (getLexer().is(AsmToken::String)) { + if (FileNumber == -1) + return TokError("explicit path specified, but no file number"); + if (parseEscapedString(FilenameData)) + return true; + Filename = FilenameData; + Directory = Path; + Lex(); + } else { + Filename = Path; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.file' directive"); + + if (FileNumber == -1) + getStreamer().EmitFileDirective(Filename); + else { + if (getContext().getGenDwarfForAssembly() == true) + Error(DirectiveLoc, + "input can't have .file dwarf directives when -g is " + "used to generate dwarf debug info for assembly code"); + + if (getStreamer().EmitDwarfFileDirective(FileNumber, Directory, Filename)) + Error(FileNumberLoc, "file number already allocated"); + } + + return false; +} + +/// parseDirectiveLine +/// ::= .line [number] +bool AsmParser::parseDirectiveLine() { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Integer)) + return TokError("unexpected token in '.line' directive"); + + int64_t LineNumber = getTok().getIntVal(); + (void)LineNumber; + Lex(); + + // FIXME: Do something with the .line. + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.line' directive"); + + 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() { + if (getLexer().isNot(AsmToken::Integer)) + return TokError("unexpected token in '.loc' directive"); + int64_t FileNumber = getTok().getIntVal(); + if (FileNumber < 1) + return TokError("file number less than one in '.loc' directive"); + if (!getContext().isValidDwarfFileNumber(FileNumber)) + return TokError("unassigned file number in '.loc' directive"); + Lex(); + + int64_t LineNumber = 0; + 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; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + 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"); + } + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + } + } + + 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'"); +} + +/// 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 +bool AsmParser::parseDirectiveCFIStartProc() { + getStreamer().EmitCFIStartProc(); + return false; +} + +/// parseDirectiveCFIEndProc +/// ::= .cfi_endproc +bool AsmParser::parseDirectiveCFIEndProc() { + getStreamer().EmitCFIEndProc(); + return false; +} + +/// \brief 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; + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Offset = 0; + if (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; + if (parseRegisterOrRegisterNumber(Register1, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Register2 = 0; + if (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)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + if (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; + + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Offset = 0; + if (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; + + if (!isValidEncoding(Encoding)) + return TokError("unsupported encoding."); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + StringRef Name; + if (parseIdentifier(Name)) + return TokError("expected identifier in directive"); + + 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; +} + +/// parseDirectiveCFISignalFrame +/// ::= .cfi_signal_frame +bool AsmParser::parseDirectiveCFISignalFrame() { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token in '.cfi_signal_frame'"); + + 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; +} + +/// parseDirectiveMacrosOnOff +/// ::= .macros_on +/// ::= .macros_off +bool AsmParser::parseDirectiveMacrosOnOff(StringRef Directive) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(getLexer().getLoc(), + "unexpected token in '" + Directive + "' directive"); + + 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"); + + MCAsmMacroParameters Parameters; + // Argument delimiter is initially unknown. It will be set by + // parseMacroArgument() + AsmToken::TokenKind ArgumentDelimiter = AsmToken::Eof; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + MCAsmMacroParameter Parameter; + if (parseIdentifier(Parameter.first)) + return TokError("expected identifier in '.macro' directive"); + + if (getLexer().is(AsmToken::Equal)) { + Lex(); + if (parseMacroArgument(Parameter.second, ArgumentDelimiter)) + return true; + } + + Parameters.push_back(Parameter); + + if (getLexer().is(AsmToken::Comma)) + Lex(); + else if (getLexer().is(AsmToken::EndOfStatement)) + break; + } + } + + // Eat the end of statement. + Lex(); + + AsmToken EndToken, StartToken = getTok(); + + // Lex the macro definition. + for (;;) { + // 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) && + (getTok().getIdentifier() == ".endm" || + getTok().getIdentifier() == ".endmacro")) { + EndToken = getTok(); + Lex(); + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + EndToken.getIdentifier() + + "' directive"); + break; + } + + // Otherwise, scan til the end of the statement. + eatToEndOfStatement(); + } + + if (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); + defineMacro(Name, MCAsmMacro(Name, Body, Parameters)); + 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 defintion. +/// But to support both styles of parameters this is not possible so if a macro +/// defintion 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 +/// definiton 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, + MCAsmMacroParameters 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].first == 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"); +} + +/// 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; + if (parseIdentifier(Name)) + return TokError("expected identifier in '.purgem' directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.purgem' directive"); + + if (!lookupMacro(Name)) + return Error(DirectiveLoc, "macro '" + Name + "' is not defined"); + + undefineMacro(Name); + return false; +} + +/// parseDirectiveBundleAlignMode +/// ::= {.bundle_align_mode} expression +bool AsmParser::parseDirectiveBundleAlignMode() { + checkForValidSection(); + + // 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 (parseAbsoluteExpression(AlignSizePow2)) + return true; + else if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token after expression in" + " '.bundle_align_mode' directive"); + else if (AlignSizePow2 < 0 || AlignSizePow2 > 30) + return Error(ExprLoc, + "invalid bundle alignment size (expected between 0 and 30)"); + + Lex(); + + // 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() { + checkForValidSection(); + bool AlignToEnd = false; + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + StringRef Option; + SMLoc Loc = getTok().getLoc(); + const char *kInvalidOptionError = + "invalid option for '.bundle_lock' directive"; + + if (parseIdentifier(Option)) + return Error(Loc, kInvalidOptionError); + + if (Option != "align_to_end") + return Error(Loc, kInvalidOptionError); + else if (getLexer().isNot(AsmToken::EndOfStatement)) + return Error(Loc, + "unexpected token after '.bundle_lock' directive option"); + AlignToEnd = true; + } + + Lex(); + + getStreamer().EmitBundleLock(AlignToEnd); + return false; +} + +/// parseDirectiveBundleLock +/// ::= {.bundle_lock} +bool AsmParser::parseDirectiveBundleUnlock() { + checkForValidSection(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.bundle_unlock' directive"); + Lex(); + + getStreamer().EmitBundleUnlock(); + return false; +} + +/// parseDirectiveSpace +/// ::= (.skip | .space) expression [ , expression ] +bool AsmParser::parseDirectiveSpace(StringRef IDVal) { + checkForValidSection(); + + int64_t NumBytes; + if (parseAbsoluteExpression(NumBytes)) + return true; + + int64_t FillExpr = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); + Lex(); + + if (parseAbsoluteExpression(FillExpr)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); + } + + Lex(); + + if (NumBytes <= 0) + return TokError("invalid number of bytes in '" + Twine(IDVal) + + "' directive"); + + // FIXME: Sometimes the fill expr is 'nop' if it isn't supplied, instead of 0. + getStreamer().EmitFill(NumBytes, FillExpr); + + return false; +} + +/// parseDirectiveLEB128 +/// ::= (.sleb128 | .uleb128) expression +bool AsmParser::parseDirectiveLEB128(bool Signed) { + checkForValidSection(); + const MCExpr *Value; + + if (parseExpression(Value)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + if (Signed) + getStreamer().EmitSLEB128Value(Value); + else + getStreamer().EmitULEB128Value(Value); + + return false; +} + +/// parseDirectiveSymbolAttribute +/// ::= { ".globl", ".weak", ... } [ identifier ( , identifier )* ] +bool AsmParser::parseDirectiveSymbolAttribute(MCSymbolAttr Attr) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + StringRef Name; + SMLoc Loc = getTok().getLoc(); + + if (parseIdentifier(Name)) + return Error(Loc, "expected identifier in directive"); + + 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 in directive"); + + if (!getStreamer().EmitSymbolAttribute(Sym, Attr)) + return Error(Loc, "unable to emit symbol attribute"); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + +/// parseDirectiveComm +/// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] +bool AsmParser::parseDirectiveComm(bool IsLocal) { + checkForValidSection(); + + 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 (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.comm' or '.lcomm' directive"); + + Lex(); + + // 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"); + + 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 (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.abort' directive"); + + Lex(); + + if (Str.empty()) + Error(Loc, ".abort detected. Assembly stopping."); + else + Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + // FIXME: Actually abort assembly here. + + return false; +} + +/// parseDirectiveInclude +/// ::= .include "filename" +bool AsmParser::parseDirectiveInclude() { + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in '.include' directive"); + + // Allow the strings to have escaped octal character sequence. + std::string Filename; + if (parseEscapedString(Filename)) + return true; + SMLoc IncludeLoc = getLexer().getLoc(); + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("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. + if (enterIncludeFile(Filename)) { + Error(IncludeLoc, "Could not find include file '" + Filename + "'"); + return true; + } + + return false; +} + +/// parseDirectiveIncbin +/// ::= .incbin "filename" +bool AsmParser::parseDirectiveIncbin() { + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in '.incbin' directive"); + + // Allow the strings to have escaped octal character sequence. + std::string Filename; + if (parseEscapedString(Filename)) + return true; + SMLoc IncbinLoc = getLexer().getLoc(); + Lex(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.incbin' directive"); + + // Attempt to process the included file. + if (processIncbinFile(Filename)) { + Error(IncbinLoc, "Could not find incbin file '" + Filename + "'"); + return true; + } + + return false; +} + +/// parseDirectiveIf +/// ::= .if expression +bool AsmParser::parseDirectiveIf(SMLoc DirectiveLoc) { + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + if (TheCondState.Ignore) { + eatToEndOfStatement(); + } else { + int64_t ExprValue; + if (parseAbsoluteExpression(ExprValue)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.if' directive"); + + Lex(); + + 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 (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.ifb' directive"); + + Lex(); + + TheCondState.CondMet = ExpectBlank == Str.empty(); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveIfc +/// ::= .ifc 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 (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.ifc' directive"); + + Lex(); + + StringRef Str2 = parseStringToEndOfStatement(); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.ifc' directive"); + + Lex(); + + TheCondState.CondMet = ExpectEqual == (Str1 == Str2); + 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 (parseIdentifier(Name)) + return TokError("expected identifier after '.ifdef'"); + + Lex(); + + MCSymbol *Sym = getContext().LookupSymbol(Name); + + if (expect_defined) + TheCondState.CondMet = (Sym != NULL && !Sym->isUndefined()); + else + TheCondState.CondMet = (Sym == NULL || 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) + Error(DirectiveLoc, "Encountered a .elseif that doesn't follow a .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 (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.elseif' directive"); + + Lex(); + TheCondState.CondMet = ExprValue; + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + +/// parseDirectiveElse +/// ::= .else +bool AsmParser::parseDirectiveElse(SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.else' directive"); + + Lex(); + + if (TheCondState.TheCond != AsmCond::IfCond && + TheCondState.TheCond != AsmCond::ElseIfCond) + Error(DirectiveLoc, "Encountered a .else that doesn't follow a .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; +} + +/// parseDirectiveEndIf +/// ::= .endif +bool AsmParser::parseDirectiveEndIf(SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.endif' directive"); + + Lex(); + + if ((TheCondState.TheCond == AsmCond::NoCond) || TheCondStack.empty()) + Error(DirectiveLoc, "Encountered a .endif that doesn't follow a .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[".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[".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[".ifb"] = DK_IFB; + DirectiveKindMap[".ifnb"] = DK_IFNB; + DirectiveKindMap[".ifc"] = DK_IFC; + DirectiveKindMap[".ifnc"] = DK_IFNC; + DirectiveKindMap[".ifdef"] = DK_IFDEF; + DirectiveKindMap[".ifndef"] = DK_IFNDEF; + DirectiveKindMap[".ifnotdef"] = DK_IFNOTDEF; + DirectiveKindMap[".elseif"] = DK_ELSEIF; + DirectiveKindMap[".else"] = DK_ELSE; + 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[".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_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[".macros_on"] = DK_MACROS_ON; + DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; + DirectiveKindMap[".macro"] = DK_MACRO; + DirectiveKindMap[".endm"] = DK_ENDM; + DirectiveKindMap[".endmacro"] = DK_ENDMACRO; + DirectiveKindMap[".purgem"] = DK_PURGEM; +} + +MCAsmMacro *AsmParser::parseMacroLikeBody(SMLoc DirectiveLoc) { + AsmToken EndToken, StartToken = getTok(); + + unsigned NestLevel = 0; + for (;;) { + // Check whether we have reached the end of the file. + if (getLexer().is(AsmToken::Eof)) { + Error(DirectiveLoc, "no matching '.endr' in definition"); + return 0; + } + + if (Lexer.is(AsmToken::Identifier) && + (getTok().getIdentifier() == ".rept")) { + ++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)) { + TokError("unexpected token in '.endr' directive"); + return 0; + } + 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. + StringRef Name; + MCAsmMacroParameters Parameters; + MacroLikeBodies.push_back(MCAsmMacro(Name, Body, Parameters)); + return &MacroLikeBodies.back(); +} + +void AsmParser::instantiateMacroLikeBody(MCAsmMacro *M, SMLoc DirectiveLoc, + raw_svector_ostream &OS) { + OS << ".endr\n"; + + MemoryBuffer *Instantiation = + MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>"); + + // Create the macro instantiation object and add to the current macro + // instantiation stack. + MacroInstantiation *MI = new MacroInstantiation( + M, DirectiveLoc, CurBuffer, getTok().getLoc(), Instantiation); + ActiveMacros.push_back(MI); + + // Jump to the macro instantiation and prime the lexer. + CurBuffer = SrcMgr.AddNewSourceBuffer(MI->Instantiation, SMLoc()); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); + Lex(); +} + +bool AsmParser::parseDirectiveRept(SMLoc DirectiveLoc) { + int64_t Count; + if (parseAbsoluteExpression(Count)) + return TokError("unexpected token in '.rept' directive"); + + if (Count < 0) + return TokError("Count is negative"); + + if (Lexer.isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.rept' directive"); + + // Eat the end of statement. + Lex(); + + // 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; + MCAsmMacroParameters Parameters; + MCAsmMacroArguments A; + raw_svector_ostream OS(Buf); + while (Count--) { + if (expandMacro(OS, M->Body, Parameters, A, getTok().getLoc())) + return true; + } + instantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + +/// parseDirectiveIrp +/// ::= .irp symbol,values +bool AsmParser::parseDirectiveIrp(SMLoc DirectiveLoc) { + MCAsmMacroParameters Parameters; + MCAsmMacroParameter Parameter; + + if (parseIdentifier(Parameter.first)) + return TokError("expected identifier in '.irp' directive"); + + Parameters.push_back(Parameter); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("expected comma in '.irp' directive"); + + Lex(); + + MCAsmMacroArguments A; + if (parseMacroArguments(0, A)) + return true; + + // Eat the end of statement. + Lex(); + + // 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 (MCAsmMacroArguments::iterator i = A.begin(), e = A.end(); i != e; ++i) { + MCAsmMacroArguments Args; + Args.push_back(*i); + + if (expandMacro(OS, M->Body, Parameters, Args, getTok().getLoc())) + return true; + } + + instantiateMacroLikeBody(M, DirectiveLoc, OS); + + return false; +} + +/// parseDirectiveIrpc +/// ::= .irpc symbol,values +bool AsmParser::parseDirectiveIrpc(SMLoc DirectiveLoc) { + MCAsmMacroParameters Parameters; + MCAsmMacroParameter Parameter; + + if (parseIdentifier(Parameter.first)) + return TokError("expected identifier in '.irpc' directive"); + + Parameters.push_back(Parameter); + + if (Lexer.isNot(AsmToken::Comma)) + return TokError("expected comma in '.irpc' directive"); + + Lex(); + + MCAsmMacroArguments A; + if (parseMacroArguments(0, A)) + return true; + + if (A.size() != 1 || A.front().size() != 1) + return TokError("unexpected token in '.irpc' directive"); + + // Eat the end of statement. + Lex(); + + // 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(); + std::size_t I, End = Values.size(); + for (I = 0; I < End; ++I) { + MCAsmMacroArgument Arg; + Arg.push_back(AsmToken(AsmToken::Identifier, Values.slice(I, I + 1))); + + MCAsmMacroArguments Args; + Args.push_back(Arg); + + if (expandMacro(OS, M->Body, Parameters, Args, 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 (!isUIntN(8, IntValue) && !isIntN(8, IntValue)) + return Error(ExprLoc, "literal value out of range for directive"); + + Info.AsmRewrites->push_back(AsmRewrite(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->push_back( + AsmRewrite(AOK_Align, IDLoc, 5, Log2_64(IntValue))); + 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)) { + ParseStatementInfo Info(&AsmStrRewrites); + if (parseStatement(Info)) + return true; + + if (Info.ParseError) + return true; + + 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()) { + 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.push_back(AsmRewrite(AOK_Output, Start, SymName.size())); + } else { + InputDecls.push_back(OpDecl); + InputDeclsAddressOf.push_back(Operand->needAddressOf()); + InputConstraints.push_back(Operand->getConstraint().str()); + AsmStrRewrites.push_back(AsmRewrite(AOK_Input, Start, SymName.size())); + } + } + } + + // 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); + const char *AsmStart = SrcMgr.getMemoryBuffer(0)->getBufferStart(); + const char *AsmEnd = SrcMgr.getMemoryBuffer(0)->getBufferEnd(); + array_pod_sort(AsmStrRewrites.begin(), AsmStrRewrites.end(), rewritesSort); + for (SmallVectorImpl<AsmRewrite>::iterator I = AsmStrRewrites.begin(), + E = AsmStrRewrites.end(); + I != E; ++I) { + AsmRewriteKind Kind = (*I).Kind; + if (Kind == AOK_Delete) + continue; + + const char *Loc = (*I).Loc.getPointer(); + assert(Loc >= AsmStart && "Expected Loc to be at or after Start!"); + + // Emit everything up to the immediate/expression. + unsigned Len = Loc - AsmStart; + if (Len) + OS << StringRef(AsmStart, Len); + + // Skip the original expression. + if (Kind == AOK_Skip) { + AsmStart = Loc + (*I).Len; + continue; + } + + unsigned AdditionalSkip = 0; + // Rewrite expressions in $N notation. + switch (Kind) { + default: + break; + case AOK_Imm: + OS << "$$" << (*I).Val; + break; + case AOK_ImmPrefix: + OS << "$$"; + break; + case AOK_Input: + OS << '$' << InputIdx++; + break; + case AOK_Output: + OS << '$' << OutputIdx++; + break; + case AOK_SizeDirective: + switch ((*I).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: { + unsigned Val = (*I).Val; + OS << ".align " << Val; + + // Skip the original immediate. + assert(Val < 10 && "Expected alignment less then 2^10."); + AdditionalSkip = (Val < 4) ? 2 : Val < 7 ? 3 : 4; + break; + } + case AOK_DotOperator: + OS << (*I).Val; + break; + } + + // Skip the original expression. + AsmStart = Loc + (*I).Len + AdditionalSkip; + } + + // Emit the remainder of the asm string. + if (AsmStart != AsmEnd) + OS << StringRef(AsmStart, AsmEnd - AsmStart); + + AsmString = OS.str(); + return false; +} + +/// \brief Create an MCAsmParser instance. +MCAsmParser *llvm::createMCAsmParser(SourceMgr &SM, MCContext &C, + MCStreamer &Out, const MCAsmInfo &MAI) { + return new AsmParser(SM, C, Out, MAI); +} diff --git a/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp new file mode 100644 index 000000000000..d8343a3eea1b --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/COFFAsmParser.cpp @@ -0,0 +1,777 @@ +//===- 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/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/COFF.h" +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, const MCSectionCOFF *Assoc); + + bool ParseSectionName(StringRef &SectionName); + bool ParseSectionFlags(StringRef FlagsString, unsigned* Flags); + + virtual void Initialize(MCAsmParser &Parser) { + // 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::ParseDirectiveLinkOnce>(".linkonce"); + + // 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::getDataRel()); + } + 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 parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, + const MCSectionCOFF *&Assoc); + bool ParseDirectiveLinkOnce(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() {} +}; + +} // 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::getDataRel(); +} + +bool COFFAsmParser::ParseSectionFlags(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 + }; + + bool ReadOnlyRemoved = false; + unsigned SecFlags = None; + + for (unsigned i = 0; i < FlagsString.size(); ++i) { + switch (FlagsString[i]) { + 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 '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 & 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)) { + for (;;) { + 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::IMAGE_COMDAT_SELECT_ANY, 0); +} + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind, + StringRef COMDATSymName, + COFF::COMDATType Type, + const MCSectionCOFF *Assoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in section switching directive"); + Lex(); + + getStreamer().SwitchSection(getContext().getCOFFSection( + Section, Characteristics, Kind, COMDATSymName, Type, Assoc)); + + 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: 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(FlagsStr, &Flags)) + return true; + } + + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + const MCSectionCOFF *Assoc = 0; + StringRef COMDATSymName; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + Flags |= COFF::IMAGE_SCN_LNK_COMDAT; + + if (parseCOMDATTypeAndAssoc(Type, Assoc)) + 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); + ParseSectionSwitch(SectionName, Flags, Kind, COMDATSymName, Type, Assoc); + 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 true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + MCSymbol *Symbol = getContext().GetOrCreateSymbol(SymbolID); + + Lex(); + getStreamer().EmitCOFFSecRel32(Symbol); + return false; +} + +/// ::= [ identifier [ identifier ] ] +bool COFFAsmParser::parseCOMDATTypeAndAssoc(COFF::COMDATType &Type, + const MCSectionCOFF *&Assoc) { + 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(); + + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + SMLoc Loc = getTok().getLoc(); + StringRef AssocName; + if (ParseSectionName(AssocName)) + return TokError("expected associated section name"); + + Assoc = static_cast<const MCSectionCOFF*>( + getContext().getCOFFSection(AssocName)); + if (!Assoc) + return Error(Loc, "cannot associate unknown section '" + AssocName + "'"); + if (!(Assoc->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT)) + return Error(Loc, "associated section must be a COMDAT section"); + if (Assoc->getSelection() == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + return Error(Loc, "associated section cannot be itself associative"); + } + + return false; +} + +/// ParseDirectiveLinkOnce +/// ::= .linkonce [ identifier [ identifier ] ] +bool COFFAsmParser::ParseDirectiveLinkOnce(StringRef, SMLoc Loc) { + COFF::COMDATType Type = COFF::IMAGE_COMDAT_SELECT_ANY; + const MCSectionCOFF *Assoc = 0; + if (getLexer().is(AsmToken::Identifier)) + if (parseCOMDATTypeAndAssoc(Type, Assoc)) + return true; + + const MCSectionCOFF *Current = static_cast<const MCSectionCOFF*>( + getStreamer().getCurrentSection().first); + + + if (Type == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { + if (Assoc == Current) + return Error(Loc, "cannot associate a section with itself"); + } + + if (Current->getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) + return Error(Loc, Twine("section '") + Current->getSectionName() + + "' is already linkonce"); + + Current->setSelection(Type, Assoc); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartProc(StringRef, SMLoc) { + 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().EmitWin64EHStartProc(Symbol); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProc(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHEndProc(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveStartChained(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHStartChained(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndChained(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHEndChained(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandler(StringRef, SMLoc) { + 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().EmitWin64EHHandler(handler, unwind, except); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveHandlerData(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHHandlerData(); + return false; +} + +bool COFFAsmParser::ParseSEHDirectivePushReg(StringRef, SMLoc L) { + unsigned Reg; + if (ParseSEHRegisterNumber(Reg)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHPushReg(Reg); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveSetFrame(StringRef, SMLoc L) { + unsigned Reg; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify a stack pointer offset"); + + Lex(); + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (Off & 0x0F) + return Error(startLoc, "offset is not a multiple of 16"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHSetFrame(Reg, Off); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveAllocStack(StringRef, SMLoc) { + int64_t Size; + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Size)) + return true; + + if (Size & 7) + return Error(startLoc, "size is not a multiple of 8"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitWin64EHAllocStack(Size); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveSaveReg(StringRef, SMLoc L) { + unsigned Reg; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify an offset on the stack"); + + Lex(); + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (Off & 7) + return Error(startLoc, "size is not a multiple of 8"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + // FIXME: Err on %xmm* registers + getStreamer().EmitWin64EHSaveReg(Reg, Off); + return false; +} + +// FIXME: This method is inherently x86-specific. It should really be in the +// x86 backend. +bool COFFAsmParser::ParseSEHDirectiveSaveXMM(StringRef, SMLoc L) { + unsigned Reg; + int64_t Off; + if (ParseSEHRegisterNumber(Reg)) + return true; + if (getLexer().isNot(AsmToken::Comma)) + return TokError("you must specify an offset on the stack"); + + Lex(); + SMLoc startLoc = getLexer().getLoc(); + if (getParser().parseAbsoluteExpression(Off)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + if (Off & 0x0F) + return Error(startLoc, "offset is not a multiple of 16"); + + Lex(); + // FIXME: Err on non-%xmm* registers + getStreamer().EmitWin64EHSaveXMM(Reg, Off); + return false; +} + +bool COFFAsmParser::ParseSEHDirectivePushFrame(StringRef, SMLoc) { + 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().EmitWin64EHPushFrame(Code); + return false; +} + +bool COFFAsmParser::ParseSEHDirectiveEndProlog(StringRef, SMLoc) { + Lex(); + getStreamer().EmitWin64EHEndProlog(); + 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; +} + +} diff --git a/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp new file mode 100644 index 000000000000..4c9bafa76eff --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp @@ -0,0 +1,867 @@ +//===- 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/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +using namespace llvm; + +namespace { + +/// \brief 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(const char *Segment, const char *Section, + unsigned TAA = 0, unsigned ImplicitAlign = 0, + unsigned StubSize = 0); + +public: + DarwinAsmParser() {} + + virtual void Initialize(MCAsmParser &Parser) { + // Call the base implementation. + this->MCAsmParserExtension::Initialize(Parser); + + 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::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"); + } + + 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", + MCSectionMachO::S_CSTRING_LITERALS); + } + bool ParseSectionDirectiveLiteral4(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT", "__literal4", + MCSectionMachO::S_4BYTE_LITERALS, 4); + } + bool ParseSectionDirectiveLiteral8(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT", "__literal8", + MCSectionMachO::S_8BYTE_LITERALS, 8); + } + bool ParseSectionDirectiveLiteral16(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT","__literal16", + MCSectionMachO::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", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + // FIXME: Different on PPC and ARM. + 0, 16); + } + bool ParseSectionDirectivePICSymbolStub(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT","__picsymbol_stub", + MCSectionMachO::S_SYMBOL_STUBS | + MCSectionMachO::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", + MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS, 4); + } + bool ParseSectionDirectiveLazySymbolPointers(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__la_symbol_ptr", + MCSectionMachO::S_LAZY_SYMBOL_POINTERS, 4); + } + bool ParseSectionDirectiveDyld(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__dyld"); + } + bool ParseSectionDirectiveModInitFunc(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__mod_init_func", + MCSectionMachO::S_MOD_INIT_FUNC_POINTERS, 4); + } + bool ParseSectionDirectiveModTermFunc(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__mod_term_func", + MCSectionMachO::S_MOD_TERM_FUNC_POINTERS, 4); + } + bool ParseSectionDirectiveConstData(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__const"); + } + bool ParseSectionDirectiveObjCClass(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__class", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCMetaClass(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__meta_class", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCCatClsMeth(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__cat_cls_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCCatInstMeth(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__cat_inst_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCProtocol(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__protocol", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCStringObject(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__string_object", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCClsMeth(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__cls_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCInstMeth(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__inst_meth", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCClsRefs(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__cls_refs", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP | + MCSectionMachO::S_LITERAL_POINTERS, 4); + } + bool ParseSectionDirectiveObjCMessageRefs(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__message_refs", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP | + MCSectionMachO::S_LITERAL_POINTERS, 4); + } + bool ParseSectionDirectiveObjCSymbols(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__symbols", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCCategory(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__category", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCClassVars(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__class_vars", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCInstanceVars(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__instance_vars", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCModuleInfo(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__module_info", + MCSectionMachO::S_ATTR_NO_DEAD_STRIP); + } + bool ParseSectionDirectiveObjCClassNames(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + } + bool ParseSectionDirectiveObjCMethVarTypes(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + } + bool ParseSectionDirectiveObjCMethVarNames(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT", "__cstring", + MCSectionMachO::S_CSTRING_LITERALS); + } + bool ParseSectionDirectiveObjCSelectorStrs(StringRef, SMLoc) { + return ParseSectionSwitch("__OBJC", "__selector_strs", + MCSectionMachO::S_CSTRING_LITERALS); + } + bool ParseSectionDirectiveTData(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__thread_data", + MCSectionMachO::S_THREAD_LOCAL_REGULAR); + } + bool ParseSectionDirectiveText(StringRef, SMLoc) { + return ParseSectionSwitch("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + } + bool ParseSectionDirectiveTLV(StringRef, SMLoc) { + return ParseSectionSwitch("__DATA", "__thread_vars", + MCSectionMachO::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", + MCSectionMachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS); + } + +}; + +} // end anonymous namespace + +bool DarwinAsmParser::ParseSectionSwitch(const char *Segment, + const char *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 & MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS; + getStreamer().SwitchSection(getContext().getMachOSection( + Segment, Section, TAA, StubSize, + isText ? SectionKind::getText() + : SectionKind::getDataRel())); + + // 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, 0, 1, 0); + + 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().getCurrentSection().first); + unsigned SectionType = Current->getType(); + if (SectionType != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS && + SectionType != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + SectionType != MCSectionMachO::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; + for (;;) { + 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); + + Lex(); + 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.c_str()); + + // FIXME: Arch specific. + bool isText = Segment == "__TEXT"; // FIXME: Hack. + getStreamer().SwitchSection(getContext().getMachOSection( + Segment, Section, TAA, StubSize, + isText ? SectionKind::getText() + : SectionKind::getDataRel())); + 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 == NULL) + 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() != false) + return Error(IDLoc, ".secure_log_unique specified multiple times"); + + // Get the secure log path. + const char *SecureLogFile = getContext().getSecureLogFile(); + if (SecureLogFile == NULL) + 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_ostream *OS = getContext().getSecureLog(); + if (OS == NULL) { + std::string Err; + OS = new raw_fd_ostream(SecureLogFile, Err, sys::fs::F_Append); + if (!Err.empty()) { + delete OS; + return Error(IDLoc, Twine("can't open secure log file: ") + + SecureLogFile + " (" + Err + ")"); + } + getContext().setSecureLog(OS); + } + + // Write the message. + int 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", + MCSectionMachO::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; + 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, MCSectionMachO::S_ZEROFILL, + 0, SectionKind::getBSS())); + 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, MCSectionMachO::S_ZEROFILL, + 0, SectionKind::getBSS()), + Sym, Size, 1 << Pow2Alignment); + + 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; +} + +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..8807975e8545 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -0,0 +1,682 @@ +//===- 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/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" +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; } + + virtual void Initialize(MCAsmParser &Parser) { + // 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::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local"); + 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"); + } + + // 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::getDataRel()); + } + 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::getDataRel()); + } + bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, + SectionKind::getReadOnlyWithRel()); + } + bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, + SectionKind::getReadOnlyWithRelLocal()); + } + bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { + return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, + SectionKind::getDataRel()); + } + 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); + +private: + bool ParseSectionName(StringRef &SectionName); + bool ParseSectionArguments(bool IsPush); +}; + +} + +/// 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)) { + for (;;) { + 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 = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getParser().parseExpression(Subsection)) + return true; + } + + getStreamer().SwitchSection(getContext().getELFSection( + Section, Type, Flags, Kind), + Subsection); + + return false; +} + +bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { + StringRef Name; + if (getParser().parseIdentifier(Name)) + return TokError("expected identifier in directive"); + MCSymbol *Sym = 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"); + + 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; + } + + for (;;) { + unsigned CurSize; + + SMLoc PrevLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Minus)) { + CurSize = 1; + Lex(); // Consume the "-". + } else if (getLexer().is(AsmToken::String)) { + CurSize = getTok().getIdentifier().size() + 2; + Lex(); + } else if (getLexer().is(AsmToken::Identifier)) { + CurSize = getTok().getIdentifier().size(); + Lex(); + } else { + break; + } + + 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 SectionKind computeSectionKind(unsigned Flags) { + if (Flags & ELF::SHF_EXECINSTR) + return SectionKind::getText(); + if (Flags & ELF::SHF_TLS) + return SectionKind::getThreadData(); + return SectionKind::getDataRel(); +} + +static unsigned parseSectionFlags(StringRef flagsStr, bool *UseLastGroup) { + unsigned flags = 0; + + for (unsigned i = 0; i < flagsStr.size(); i++) { + switch (flagsStr[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 '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 'G': + flags |= ELF::SHF_GROUP; + break; + case '?': + *UseLastGroup = true; + break; + default: + return -1U; + } + } + + return flags; +} + +bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { + getStreamer().PushSection(); + + if (ParseSectionArguments(/*IsPush=*/true)) { + getStreamer().PopSection(); + return true; + } + + return false; +} + +bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { + if (!getStreamer().PopSection()) + return TokError(".popsection without corresponding .pushsection"); + return false; +} + +// FIXME: This is a work in progress. +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + return ParseSectionArguments(/*IsPush=*/false); +} + +bool ELFAsmParser::ParseSectionArguments(bool IsPush) { + 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 = 0; + bool UseLastGroup = false; + + // Set the defaults first. + if (SectionName == ".fini" || SectionName == ".init" || + SectionName == ".rodata") + Flags |= ELF::SHF_ALLOC; + if (SectionName == ".fini" || SectionName == ".init") + Flags |= ELF::SHF_EXECINSTR; + + 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(); + } + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + + unsigned 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 (getLexer().isNot(AsmToken::Comma)) { + if (Mergeable) + return TokError("Mergeable section must specify the type"); + if (Group) + return TokError("Group section must specify the type"); + } else { + Lex(); + if (getLexer().is(AsmToken::At) || getLexer().is(AsmToken::Percent) || + getLexer().is(AsmToken::String)) { + if (!getLexer().is(AsmToken::String)) + Lex(); + } else + return TokError("expected '@<type>', '%<type>' or \"<type>\""); + + if (getParser().parseIdentifier(TypeName)) + return TokError("expected identifier in directive"); + + if (Mergeable) { + 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"); + } + + if (Group) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected group name"); + Lex(); + if (getParser().parseIdentifier(GroupName)) + return true; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + StringRef Linkage; + if (getParser().parseIdentifier(Linkage)) + return true; + if (Linkage != "comdat") + return TokError("Linkage must be 'comdat'"); + } + } + } + } + +EndStmt: + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + unsigned Type = ELF::SHT_PROGBITS; + + if (TypeName.empty()) { + if (SectionName.startswith(".note")) + Type = ELF::SHT_NOTE; + else if (SectionName == ".init_array") + Type = ELF::SHT_INIT_ARRAY; + else if (SectionName == ".fini_array") + Type = ELF::SHT_FINI_ARRAY; + else if (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 + 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; + } + } + + SectionKind Kind = computeSectionKind(Flags); + getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type, + Flags, Kind, Size, + GroupName), + Subsection); + return false; +} + +bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { + MCSectionSubPair PreviousSection = getStreamer().getPreviousSection(); + if (PreviousSection.first == NULL) + return TokError(".previous without corresponding .section"); + getStreamer().SwitchSection(PreviousSection.first, PreviousSection.second); + + return false; +} + +/// 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); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.type' directive"); + Lex(); + + StringRef Type; + SMLoc TypeLoc; + MCSymbolAttr Attr; + if (getLexer().is(AsmToken::Identifier)) { + TypeLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(Type)) + return TokError("expected symbol type in directive"); + Attr = StringSwitch<MCSymbolAttr>(Type) + .Case("STT_FUNC", MCSA_ELF_TypeFunction) + .Case("STT_OBJECT", MCSA_ELF_TypeObject) + .Case("STT_TLS", MCSA_ELF_TypeTLS) + .Case("STT_COMMON", MCSA_ELF_TypeCommon) + .Case("STT_NOTYPE", MCSA_ELF_TypeNoType) + .Case("STT_GNU_IFUNC", MCSA_ELF_TypeIndFunction) + .Default(MCSA_Invalid); + } else if (getLexer().is(AsmToken::Hash) || getLexer().is(AsmToken::At) || + getLexer().is(AsmToken::Percent) || + getLexer().is(AsmToken::String)) { + if (!getLexer().is(AsmToken::String)) + Lex(); + + TypeLoc = getLexer().getLoc(); + if (getParser().parseIdentifier(Type)) + return TokError("expected symbol type in directive"); + Attr = StringSwitch<MCSymbolAttr>(Type) + .Case("function", MCSA_ELF_TypeFunction) + .Case("object", MCSA_ELF_TypeObject) + .Case("tls_object", MCSA_ELF_TypeTLS) + .Case("common", MCSA_ELF_TypeCommon) + .Case("notype", MCSA_ELF_TypeNoType) + .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) + .Case("gnu_indirect_function", MCSA_ELF_TypeIndFunction) + .Default(MCSA_Invalid); + } else + return TokError("expected STT_<TYPE_IN_UPPER_CASE>, '#<type>', '@<type>', " + "'%<type>' or \"<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(); + + 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"); + + Lex(); + + 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 *Alias = getContext().GetOrCreateSymbol(AliasName); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + const MCExpr *Value = MCSymbolRefExpr::Create(Sym, getContext()); + + getStreamer().EmitAssignment(Alias, Value); + 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(); + + const MCSection *Note = + getContext().getELFSection(".note", ELF::SHT_NOTE, 0, + SectionKind::getReadOnly()); + + 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 = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + if (getParser().parseExpression(Subsection)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + getStreamer().SubSection(Subsection); + return false; +} + +namespace llvm { + +MCAsmParserExtension *createELFAsmParser() { + return new ELFAsmParser; +} + +} diff --git a/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp new file mode 100644 index 000000000000..3867691107fb --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCAsmLexer.cpp @@ -0,0 +1,32 @@ +//===-- 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/Support/SourceMgr.h" + +using namespace llvm; + +MCAsmLexer::MCAsmLexer() : CurTok(AsmToken::Error, StringRef()), + TokStart(0), SkipSpace(true) { +} + +MCAsmLexer::~MCAsmLexer() { +} + +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()); +} diff --git a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp new file mode 100644 index 000000000000..6e1ebad36c0d --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -0,0 +1,50 @@ +//===-- 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/Twine.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +MCAsmParser::MCAsmParser() : TargetParser(0), ShowParsedOperands(0) { +} + +MCAsmParser::~MCAsmParser() { +} + +void MCAsmParser::setTargetParser(MCTargetAsmParser &P) { + assert(!TargetParser && "Target parser is already initialized!"); + TargetParser = &P; + TargetParser->Initialize(*this); +} + +const AsmToken &MCAsmParser::getTok() { + return getLexer().getTok(); +} + +bool MCAsmParser::TokError(const Twine &Msg, ArrayRef<SMRange> Ranges) { + Error(getLexer().getLoc(), Msg, Ranges); + return true; +} + +bool MCAsmParser::parseExpression(const MCExpr *&Res) { + SMLoc L; + return parseExpression(Res, L); +} + +void MCParsedAsmOperand::dump() const { +#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..3f25a14926b6 --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParserExtension.cpp @@ -0,0 +1,22 @@ +//===-- 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() : + BracketExpressionsSupported(false) { +} + +MCAsmParserExtension::~MCAsmParserExtension() { +} + +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..60a3a3b59a3d --- /dev/null +++ b/contrib/llvm/lib/MC/MCParser/MCTargetAsmParser.cpp @@ -0,0 +1,19 @@ +//===-- 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/MCTargetAsmParser.h" +using namespace llvm; + +MCTargetAsmParser::MCTargetAsmParser() + : AvailableFeatures(0), ParsingInlineAsm(false) +{ +} + +MCTargetAsmParser::~MCTargetAsmParser() { +} diff --git a/contrib/llvm/lib/MC/MCPureStreamer.cpp b/contrib/llvm/lib/MC/MCPureStreamer.cpp new file mode 100644 index 000000000000..f7bf002fbc67 --- /dev/null +++ b/contrib/llvm/lib/MC/MCPureStreamer.cpp @@ -0,0 +1,235 @@ +//===- lib/MC/MCPureStreamer.cpp - MC "Pure" Object 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/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { + +class MCPureStreamer : public MCObjectStreamer { +private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + +public: + MCPureStreamer(MCContext &Context, MCAsmBackend &TAB, raw_ostream &OS, + MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, 0, TAB, OS, Emitter) {} + + /// @name MCStreamer Interface + /// @{ + + virtual void InitSections(); + virtual void InitToTextSection(); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitDebugLabel(MCSymbol *Symbol); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + uint64_t Size = 0, unsigned ByteAlignment = 0); + virtual void EmitBytes(StringRef Data); + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + virtual bool EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + virtual void FinishImpl(); + + + virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + report_fatal_error("unsupported directive in pure streamer"); + return false; + } + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitThumbFunc(MCSymbol *Func) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCOFFSymbolStorageClass(int StorageClass) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCOFFSymbolType(int Type) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EndCOFFSymbolDef() { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitFileDirective(StringRef Filename) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitIdent(StringRef IdentString) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Directory, + StringRef Filename, unsigned CUID = 0) { + report_fatal_error("unsupported directive in pure streamer"); + } +}; + +} // end anonymous namespace. + +void MCPureStreamer::InitSections() { + InitToTextSection(); +} + +void MCPureStreamer::InitToTextSection() { + SwitchSection(getContext().getObjectFileInfo()->getTextSection()); +} + +void MCPureStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection().first && "Cannot emit before setting section!"); + + AssignSection(Symbol, getCurrentSection().first); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // We have to create a new fragment if this is an atom defining symbol, + // fragments cannot span atoms. + if (getAssembler().isSymbolLinkerVisible(SD.getSymbol())) + insert(new MCDataFragment()); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); +} + + +void MCPureStreamer::EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); +} + +void MCPureStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + report_fatal_error("not yet implemented in pure streamer"); +} + +void MCPureStreamer::EmitBytes(StringRef Data) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); +} + +void MCPureStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, unsigned ValueSize, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + insert(new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit)); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCPureStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit); + insert(F); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +bool MCPureStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + insert(new MCOrgFragment(*Offset, Value)); + return false; +} + +void MCPureStreamer::EmitInstToFragment(const MCInst &Inst) { + MCRelaxableFragment *IF = new MCRelaxableFragment(Inst); + insert(IF); + + // Add the fixups and data. + // + // FIXME: Revisit this design decision when relaxation is done, we may be + // able to get away with not storing any extra data in the MCInst. + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + IF->getContents() = Code; + IF->getFixups() = Fixups; +} + +void MCPureStreamer::EmitInstToData(const MCInst &Inst) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // 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->getContents().append(Code.begin(), Code.end()); +} + +void MCPureStreamer::FinishImpl() { + // FIXME: Handle DWARF tables? + + this->MCObjectStreamer::FinishImpl(); +} + +MCStreamer *llvm::createPureStreamer(MCContext &Context, MCAsmBackend &MAB, + raw_ostream &OS, MCCodeEmitter *CE) { + return new MCPureStreamer(Context, MAB, OS, CE); +} diff --git a/contrib/llvm/lib/MC/MCRegisterInfo.cpp b/contrib/llvm/lib/MC/MCRegisterInfo.cpp new file mode 100644 index 000000000000..ce79cd5c2c6b --- /dev/null +++ b/contrib/llvm/lib/MC/MCRegisterInfo.cpp @@ -0,0 +1,86 @@ +//=== MC/MCRegisterInfo.cpp - Target Register Description -------*- C++ -*-===// +// +// 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" + +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; + + 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; + + 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::getSEHRegNum(unsigned RegNum) const { + const DenseMap<unsigned, int>::const_iterator I = L2SEHRegs.find(RegNum); + if (I == L2SEHRegs.end()) return (int)RegNum; + return I->second; +} diff --git a/contrib/llvm/lib/MC/MCRelocationInfo.cpp b/contrib/llvm/lib/MC/MCRelocationInfo.cpp new file mode 100644 index 000000000000..53c48deded18 --- /dev/null +++ b/contrib/llvm/lib/MC/MCRelocationInfo.cpp @@ -0,0 +1,39 @@ +//==-- lib/MC/MCRelocationInfo.cpp -------------------------------*- 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/MCRelocationInfo.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm-c/Disassembler.h" + +using namespace llvm; + +MCRelocationInfo::MCRelocationInfo(MCContext &Ctx) + : Ctx(Ctx) { +} + +MCRelocationInfo::~MCRelocationInfo() { +} + +const MCExpr * +MCRelocationInfo::createExprForRelocation(object::RelocationRef Rel) { + return 0; +} + +const MCExpr * +MCRelocationInfo::createExprForCAPIVariantKind(const MCExpr *SubExpr, + unsigned VariantKind) { + if (VariantKind != LLVMDisassembler_VariantKind_None) + return 0; + return SubExpr; +} + +MCRelocationInfo *llvm::createMCRelocationInfo(StringRef TT, MCContext &Ctx) { + return new MCRelocationInfo(Ctx); +} diff --git a/contrib/llvm/lib/MC/MCSection.cpp b/contrib/llvm/lib/MC/MCSection.cpp new file mode 100644 index 000000000000..ccf4a7dddf73 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSection.cpp @@ -0,0 +1,22 @@ +//===- 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/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// MCSection +//===----------------------------------------------------------------------===// + +MCSection::~MCSection() { +} + diff --git a/contrib/llvm/lib/MC/MCSectionCOFF.cpp b/contrib/llvm/lib/MC/MCSectionCOFF.cpp new file mode 100644 index 000000000000..64aa2c5c49ea --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionCOFF.cpp @@ -0,0 +1,99 @@ +//===- 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/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +MCSectionCOFF::~MCSectionCOFF() {} // anchor. + +// ShouldOmitSectionDirective - Decides whether a '.section' directive +// should be printed before the section name +bool MCSectionCOFF::ShouldOmitSectionDirective(StringRef Name, + const MCAsmInfo &MAI) const { + + // 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 MCSectionCOFF *Assoc) const { + assert(Selection != 0 && "invalid COMDAT selection type"); + assert((Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) == + (Assoc != 0) && + "associative COMDAT section must have an associated section"); + this->Selection = Selection; + this->Assoc = Assoc; + Characteristics |= COFF::IMAGE_SCN_LNK_COMDAT; +} + +void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, + 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 (getKind().isText()) + OS << 'x'; + if (getKind().isWriteable()) + OS << 'w'; + else + OS << 'r'; + if (getCharacteristics() & COFF::IMAGE_SCN_MEM_DISCARDABLE) + OS << 'n'; + OS << "\"\n"; + + if (getCharacteristics() & COFF::IMAGE_SCN_LNK_COMDAT) { + switch (Selection) { + case COFF::IMAGE_COMDAT_SELECT_NODUPLICATES: + OS << "\t.linkonce one_only\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_ANY: + OS << "\t.linkonce discard\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_SAME_SIZE: + OS << "\t.linkonce same_size\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH: + OS << "\t.linkonce same_contents\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE: + OS << "\t.linkonce associative " << Assoc->getSectionName() << "\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_LARGEST: + OS << "\t.linkonce largest\n"; + break; + case COFF::IMAGE_COMDAT_SELECT_NEWEST: + OS << "\t.linkonce newest\n"; + break; + default: + assert (0 && "unsupported COFF selection type"); + break; + } + } +} + +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..09eb3e782958 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionELF.cpp @@ -0,0 +1,169 @@ +//===- 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/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +MCSectionELF::~MCSectionELF() {} // anchor. + +// ShouldOmitSectionDirective - Decides whether a '.section' directive +// should be printed before the section name +bool MCSectionELF::ShouldOmitSectionDirective(StringRef Name, + const MCAsmInfo &MAI) const { + + // FIXME: Does .section .bss/.data/.text work everywhere?? + if (Name == ".text" || Name == ".data" || + (Name == ".bss" && !MAI.usesELFSectionDirectiveForBSS())) + return true; + + return false; +} + +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, + raw_ostream &OS, + const MCExpr *Subsection) const { + + if (ShouldOmitSectionDirective(SectionName, MAI)) { + OS << '\t' << getSectionName(); + if (Subsection) + OS << '\t' << *Subsection; + 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 there are target-specific flags, print them. + if (Flags & ELF::XCORE_SHF_CP_SECTION) + OS << 'c'; + if (Flags & ELF::XCORE_SHF_DP_SECTION) + OS << 'd'; + + 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"; + + if (EntrySize) { + assert(Flags & ELF::SHF_MERGE); + OS << "," << EntrySize; + } + + if (Flags & ELF::SHF_GROUP) { + OS << ","; + printName(OS, Group->getName()); + OS << ",comdat"; + } + OS << '\n'; + + if (Subsection) + OS << "\t.subsection\t" << *Subsection << '\n'; +} + +bool MCSectionELF::UseCodeAlign() const { + return getFlags() & ELF::SHF_EXECINSTR; +} + +bool MCSectionELF::isVirtualSection() const { + return getType() == ELF::SHT_NOBITS; +} + +unsigned MCSectionELF::DetermineEntrySize(SectionKind Kind) { + if (Kind.isMergeable1ByteCString()) return 1; + if (Kind.isMergeable2ByteCString()) return 2; + if (Kind.isMergeable4ByteCString()) return 4; + if (Kind.isMergeableConst4()) return 4; + if (Kind.isMergeableConst8()) return 8; + if (Kind.isMergeableConst16()) return 16; + return 0; +} diff --git a/contrib/llvm/lib/MC/MCSectionMachO.cpp b/contrib/llvm/lib/MC/MCSectionMachO.cpp new file mode 100644 index 000000000000..870451313bb1 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSectionMachO.cpp @@ -0,0 +1,304 @@ +//===- 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 const struct { + const char *AssemblerName, *EnumName; +} SectionTypeDescriptors[MCSectionMachO::LAST_KNOWN_SECTION_TYPE+1] = { + { "regular", "S_REGULAR" }, // 0x00 + { 0, "S_ZEROFILL" }, // 0x01 + { "cstring_literals", "S_CSTRING_LITERALS" }, // 0x02 + { "4byte_literals", "S_4BYTE_LITERALS" }, // 0x03 + { "8byte_literals", "S_8BYTE_LITERALS" }, // 0x04 + { "literal_pointers", "S_LITERAL_POINTERS" }, // 0x05 + { "non_lazy_symbol_pointers", "S_NON_LAZY_SYMBOL_POINTERS" }, // 0x06 + { "lazy_symbol_pointers", "S_LAZY_SYMBOL_POINTERS" }, // 0x07 + { "symbol_stubs", "S_SYMBOL_STUBS" }, // 0x08 + { "mod_init_funcs", "S_MOD_INIT_FUNC_POINTERS" }, // 0x09 + { "mod_term_funcs", "S_MOD_TERM_FUNC_POINTERS" }, // 0x0A + { "coalesced", "S_COALESCED" }, // 0x0B + { 0, /*FIXME??*/ "S_GB_ZEROFILL" }, // 0x0C + { "interposing", "S_INTERPOSING" }, // 0x0D + { "16byte_literals", "S_16BYTE_LITERALS" }, // 0x0E + { 0, /*FIXME??*/ "S_DTRACE_DOF" }, // 0x0F + { 0, /*FIXME??*/ "S_LAZY_DYLIB_SYMBOL_POINTERS" }, // 0x10 + { "thread_local_regular", "S_THREAD_LOCAL_REGULAR" }, // 0x11 + { "thread_local_zerofill", "S_THREAD_LOCAL_ZEROFILL" }, // 0x12 + { "thread_local_variables", "S_THREAD_LOCAL_VARIABLES" }, // 0x13 + { "thread_local_variable_pointers", + "S_THREAD_LOCAL_VARIABLE_POINTERS" }, // 0x14 + { "thread_local_init_function_pointers", + "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. The last entry has an AttrFlagEnd +/// AttrFlag value. +static const struct { + unsigned AttrFlag; + const char *AssemblerName, *EnumName; +} SectionAttrDescriptors[] = { +#define ENTRY(ASMNAME, ENUM) \ + { MCSectionMachO::ENUM, ASMNAME, #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(0 /*FIXME*/, S_ATTR_SOME_INSTRUCTIONS) +ENTRY(0 /*FIXME*/, S_ATTR_EXT_RELOC) +ENTRY(0 /*FIXME*/, S_ATTR_LOC_RELOC) +#undef ENTRY + { 0, "none", 0 }, // used if section has no attributes but has a stub size +#define AttrFlagEnd 0xffffffff // non legal value, multiple attribute bits set + { AttrFlagEnd, 0, 0 } +}; + +MCSectionMachO::MCSectionMachO(StringRef Segment, StringRef Section, + unsigned TAA, unsigned reserved2, SectionKind K) + : MCSection(SV_MachO, K), 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, + 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; + } + + unsigned SectionType = TAA & MCSectionMachO::SECTION_TYPE; + assert(SectionType <= MCSectionMachO::LAST_KNOWN_SECTION_TYPE && + "Invalid SectionType specified!"); + + if (SectionTypeDescriptors[SectionType].AssemblerName) { + 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 & MCSectionMachO::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) + 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(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); +} + +bool MCSectionMachO::isVirtualSection() const { + return (getType() == MCSectionMachO::S_ZEROFILL || + getType() == MCSectionMachO::S_GB_ZEROFILL || + getType() == MCSectionMachO::S_THREAD_LOCAL_ZEROFILL); +} + +/// StripSpaces - This removes leading and trailing spaces from the StringRef. +static void StripSpaces(StringRef &Str) { + while (!Str.empty() && isspace(static_cast<unsigned char>(Str[0]))) + Str = Str.substr(1); + while (!Str.empty() && isspace(static_cast<unsigned char>(Str.back()))) + Str = Str.substr(0, Str.size()-1); +} + +/// 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; + // Find the first comma. + std::pair<StringRef, StringRef> Comma = Spec.split(','); + + // If there is no comma, we fail. + if (Comma.second.empty()) + return "mach-o section specifier requires a segment and section " + "separated by a comma"; + + // Capture segment, remove leading and trailing whitespace. + Segment = Comma.first; + StripSpaces(Segment); + + // 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"; + + // Split the section name off from any attributes if present. + Comma = Comma.second.split(','); + + // Capture section, remove leading and trailing whitespace. + Section = Comma.first; + StripSpaces(Section); + + // Verify that the section is present and not too long. + if (Section.empty() || 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 (Comma.second.empty()) + return ""; + + // Otherwise, we need to parse the section type and attributes. + Comma = Comma.second.split(','); + + // Get the section type. + StringRef SectionType = Comma.first; + StripSpaces(SectionType); + + // Figure out which section type it is. + unsigned TypeID; + for (TypeID = 0; TypeID !=MCSectionMachO::LAST_KNOWN_SECTION_TYPE+1; ++TypeID) + if (SectionTypeDescriptors[TypeID].AssemblerName && + SectionType == SectionTypeDescriptors[TypeID].AssemblerName) + break; + + // If we didn't find the section type, reject it. + if (TypeID > MCSectionMachO::LAST_KNOWN_SECTION_TYPE) + return "mach-o section specifier uses an unknown section type"; + + // Remember the TypeID. + TAA = TypeID; + TAAParsed = true; + + // If we have no comma after the section type, there are no attributes. + if (Comma.second.empty()) { + // S_SYMBOL_STUBS always require a symbol stub size specifier. + if (TAA == MCSectionMachO::S_SYMBOL_STUBS) + return "mach-o section specifier of type 'symbol_stubs' requires a size " + "specifier"; + return ""; + } + + // Otherwise, we do have some attributes. Split off the size specifier if + // present. + Comma = Comma.second.split(','); + StringRef Attrs = Comma.first; + + // The attribute list is a '+' separated list of attributes. + std::pair<StringRef, StringRef> Plus = Attrs.split('+'); + + while (1) { + StringRef Attr = Plus.first; + StripSpaces(Attr); + + // Look up the attribute. + for (unsigned i = 0; ; ++i) { + if (SectionAttrDescriptors[i].AttrFlag == AttrFlagEnd) + return "mach-o section specifier has invalid attribute"; + + if (SectionAttrDescriptors[i].AssemblerName && + Attr == SectionAttrDescriptors[i].AssemblerName) { + TAA |= SectionAttrDescriptors[i].AttrFlag; + break; + } + } + + if (Plus.second.empty()) break; + Plus = Plus.second.split('+'); + }; + + // Okay, we've parsed the section attributes, see if we have a stub size spec. + if (Comma.second.empty()) { + // S_SYMBOL_STUBS always require a symbol stub size specifier. + if (TAA == MCSectionMachO::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 & MCSectionMachO::SECTION_TYPE) != MCSectionMachO::S_SYMBOL_STUBS) + return "mach-o section specifier cannot have a stub size specified because " + "it does not have type 'symbol_stubs'"; + + // Okay, if we do, it must be a number. + StringRef StubSizeStr = Comma.second; + StripSpaces(StubSizeStr); + + // 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/MCStreamer.cpp b/contrib/llvm/lib/MC/MCStreamer.cpp new file mode 100644 index 000000000000..2e1d69b77f6f --- /dev/null +++ b/contrib/llvm/lib/MC/MCStreamer.cpp @@ -0,0 +1,615 @@ +//===- 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/SmallString.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdlib> +using namespace llvm; + +// Pin the vtables to this file. +MCTargetStreamer::~MCTargetStreamer() {} +void ARMTargetStreamer::anchor() {} + +MCStreamer::MCStreamer(MCContext &Ctx, MCTargetStreamer *TargetStreamer) + : Context(Ctx), TargetStreamer(TargetStreamer), EmitEHFrame(true), + EmitDebugFrame(false), CurrentW64UnwindInfo(0), LastSymbol(0), + AutoInitSections(false) { + SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>()); + if (TargetStreamer) + TargetStreamer->setStreamer(this); +} + +MCStreamer::~MCStreamer() { + for (unsigned i = 0; i < getNumW64UnwindInfos(); ++i) + delete W64UnwindInfos[i]; +} + +void MCStreamer::reset() { + for (unsigned i = 0; i < getNumW64UnwindInfos(); ++i) + delete W64UnwindInfos[i]; + W64UnwindInfos.clear(); + EmitEHFrame = true; + EmitDebugFrame = false; + CurrentW64UnwindInfo = 0; + LastSymbol = 0; + SectionStack.clear(); + SectionStack.push_back(std::pair<MCSectionSubPair, MCSectionSubPair>()); +} + +const MCExpr *MCStreamer::BuildSymbolDiff(MCContext &Context, + const MCSymbol *A, + const MCSymbol *B) { + 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; +} + +const MCExpr *MCStreamer::ForceExpAbs(const MCExpr* Expr) { + if (Context.getAsmInfo()->hasAggressiveSymbolFolding() || + isa<MCSymbolRefExpr>(Expr)) + return Expr; + + MCSymbol *ABS = Context.CreateTempSymbol(); + EmitAssignment(ABS, Expr); + return MCSymbolRefExpr::Create(ABS, Context); +} + +raw_ostream &MCStreamer::GetCommentOS() { + // By default, discard comments. + return nulls(); +} + +void MCStreamer::generateCompactUnwindEncodings(MCAsmBackend *MAB) { + for (std::vector<MCDwarfFrameInfo>::iterator I = FrameInfos.begin(), + E = FrameInfos.end(); I != E; ++I) + I->CompactUnwindEncoding = + (MAB ? MAB->generateCompactUnwindEncoding(I->Instructions) : 0); +} + +void MCStreamer::EmitDwarfSetLineAddr(int64_t LineDelta, + const MCSymbol *Label, int PointerSize) { + // emit the sequence to set the address + EmitIntValue(dwarf::DW_LNS_extended_op, 1); + EmitULEB128IntValue(PointerSize + 1); + EmitIntValue(dwarf::DW_LNE_set_address, 1); + EmitSymbolValue(Label, PointerSize); + + // emit the sequence for the LineDelta (from 1) and a zero address delta. + MCDwarfLineAddr::Emit(this, LineDelta, 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(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)); +} + +/// EmitULEB128Value - Special case of EmitULEB128Value that avoids the +/// client having to pass in a MCExpr for constant integers. +void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned Padding) { + SmallString<128> Tmp; + raw_svector_ostream OSE(Tmp); + encodeULEB128(Value, OSE, Padding); + EmitBytes(OSE.str()); +} + +/// EmitSLEB128Value - 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::EmitAbsValue(const MCExpr *Value, unsigned Size) { + const MCExpr *ABS = ForceExpAbs(Value); + EmitValue(ABS, Size); +} + + +void MCStreamer::EmitValue(const MCExpr *Value, unsigned Size) { + EmitValueImpl(Value, Size); +} + +void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size) { + EmitValueImpl(MCSymbolRefExpr::Create(Sym, getContext()), Size); +} + +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"); +} + +/// EmitFill - 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) { + const MCExpr *E = MCConstantExpr::Create(FillValue, getContext()); + for (uint64_t i = 0, e = NumBytes; i != e; ++i) + EmitValue(E, 1); +} + +/// The implementation in this class just redirects to EmitFill. +void MCStreamer::EmitZeros(uint64_t NumBytes) { + EmitFill(NumBytes, 0); +} + +bool MCStreamer::EmitDwarfFileDirective(unsigned FileNo, + StringRef Directory, + StringRef Filename, unsigned CUID) { + return getContext().GetDwarfFile(Directory, Filename, FileNo, CUID) == 0; +} + +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); +} + +MCDwarfFrameInfo *MCStreamer::getCurrentFrameInfo() { + if (FrameInfos.empty()) + return 0; + return &FrameInfos.back(); +} + +void MCStreamer::EnsureValidFrame() { + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + if (!CurFrame || CurFrame->End) + report_fatal_error("No open frame"); +} + +void MCStreamer::EmitEHSymAttributes(const MCSymbol *Symbol, + MCSymbol *EHSymbol) { +} + +void MCStreamer::AssignSection(MCSymbol *Symbol, const MCSection *Section) { + if (Section) + Symbol->setSection(*Section); + else + Symbol->setUndefined(); + + // 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) { + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection().first && "Cannot emit before setting section!"); + AssignSection(Symbol, getCurrentSection().first); + LastSymbol = Symbol; +} + +void MCStreamer::EmitDebugLabel(MCSymbol *Symbol) { + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection().first && "Cannot emit before setting section!"); + AssignSection(Symbol, getCurrentSection().first); + LastSymbol = Symbol; +} + +void MCStreamer::EmitCompactUnwindEncoding(uint32_t CompactUnwindEncoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->CompactUnwindEncoding = CompactUnwindEncoding; +} + +void MCStreamer::EmitCFISections(bool EH, bool Debug) { + assert(EH || Debug); + EmitEHFrame = EH; + EmitDebugFrame = Debug; +} + +void MCStreamer::EmitCFIStartProc() { + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + if (CurFrame && !CurFrame->End) + report_fatal_error("Starting a frame before finishing the previous one!"); + + MCDwarfFrameInfo Frame; + EmitCFIStartProcImpl(Frame); + + FrameInfos.push_back(Frame); +} + +void MCStreamer::EmitCFIStartProcImpl(MCDwarfFrameInfo &Frame) { +} + +void MCStreamer::RecordProcStart(MCDwarfFrameInfo &Frame) { + Frame.Function = LastSymbol; + // If the function is externally visible, we need to create a local + // symbol to avoid relocations. + StringRef Prefix = getContext().getAsmInfo()->getPrivateGlobalPrefix(); + if (LastSymbol && LastSymbol->getName().startswith(Prefix)) { + Frame.Begin = LastSymbol; + } else { + Frame.Begin = getContext().CreateTempSymbol(); + EmitLabel(Frame.Begin); + } +} + +void MCStreamer::EmitCFIEndProc() { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + EmitCFIEndProcImpl(*CurFrame); +} + +void MCStreamer::EmitCFIEndProcImpl(MCDwarfFrameInfo &Frame) { +} + +void MCStreamer::RecordProcEnd(MCDwarfFrameInfo &Frame) { + Frame.End = getContext().CreateTempSymbol(); + EmitLabel(Frame.End); +} + +MCSymbol *MCStreamer::EmitCFICommon() { + EnsureValidFrame(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + return Label; +} + +void MCStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createDefCfa(Label, Register, Offset); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIDefCfaOffset(int64_t Offset) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createDefCfaOffset(Label, Offset); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIAdjustCfaOffset(int64_t Adjustment) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createAdjustCfaOffset(Label, Adjustment); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIDefCfaRegister(int64_t Register) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createDefCfaRegister(Label, Register); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createOffset(Label, Register, Offset); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIRelOffset(int64_t Register, int64_t Offset) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createRelOffset(Label, Register, Offset); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Personality = Sym; + CurFrame->PersonalityEncoding = Encoding; +} + +void MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Lsda = Sym; + CurFrame->LsdaEncoding = Encoding; +} + +void MCStreamer::EmitCFIRememberState() { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = MCCFIInstruction::createRememberState(Label); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIRestoreState() { + // FIXME: Error if there is no matching cfi_remember_state. + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = MCCFIInstruction::createRestoreState(Label); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFISameValue(int64_t Register) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createSameValue(Label, Register); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIRestore(int64_t Register) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createRestore(Label, Register); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIEscape(StringRef Values) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = MCCFIInstruction::createEscape(Label, Values); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFISignalFrame() { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->IsSignalFrame = true; +} + +void MCStreamer::EmitCFIUndefined(int64_t Register) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createUndefined(Label, Register); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIRegister(int64_t Register1, int64_t Register2) { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createRegister(Label, Register1, Register2); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::EmitCFIWindowSave() { + MCSymbol *Label = EmitCFICommon(); + MCCFIInstruction Instruction = + MCCFIInstruction::createWindowSave(Label); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Instructions.push_back(Instruction); +} + +void MCStreamer::setCurrentW64UnwindInfo(MCWin64EHUnwindInfo *Frame) { + W64UnwindInfos.push_back(Frame); + CurrentW64UnwindInfo = W64UnwindInfos.back(); +} + +void MCStreamer::EnsureValidW64UnwindInfo() { + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (!CurFrame || CurFrame->End) + report_fatal_error("No open Win64 EH frame function!"); +} + +void MCStreamer::EmitWin64EHStartProc(const MCSymbol *Symbol) { + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (CurFrame && !CurFrame->End) + report_fatal_error("Starting a function before ending the previous one!"); + MCWin64EHUnwindInfo *Frame = new MCWin64EHUnwindInfo; + Frame->Begin = getContext().CreateTempSymbol(); + Frame->Function = Symbol; + EmitLabel(Frame->Begin); + setCurrentW64UnwindInfo(Frame); +} + +void MCStreamer::EmitWin64EHEndProc() { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (CurFrame->ChainedParent) + report_fatal_error("Not all chained regions terminated!"); + CurFrame->End = getContext().CreateTempSymbol(); + EmitLabel(CurFrame->End); +} + +void MCStreamer::EmitWin64EHStartChained() { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *Frame = new MCWin64EHUnwindInfo; + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + Frame->Begin = getContext().CreateTempSymbol(); + Frame->Function = CurFrame->Function; + Frame->ChainedParent = CurFrame; + EmitLabel(Frame->Begin); + setCurrentW64UnwindInfo(Frame); +} + +void MCStreamer::EmitWin64EHEndChained() { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (!CurFrame->ChainedParent) + report_fatal_error("End of a chained region outside a chained region!"); + CurFrame->End = getContext().CreateTempSymbol(); + EmitLabel(CurFrame->End); + CurrentW64UnwindInfo = CurFrame->ChainedParent; +} + +void MCStreamer::EmitWin64EHHandler(const MCSymbol *Sym, bool Unwind, + bool Except) { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (CurFrame->ChainedParent) + report_fatal_error("Chained unwind areas can't have handlers!"); + CurFrame->ExceptionHandler = Sym; + if (!Except && !Unwind) + report_fatal_error("Don't know what kind of handler this is!"); + if (Unwind) + CurFrame->HandlesUnwind = true; + if (Except) + CurFrame->HandlesExceptions = true; +} + +void MCStreamer::EmitWin64EHHandlerData() { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (CurFrame->ChainedParent) + report_fatal_error("Chained unwind areas can't have handlers!"); +} + +void MCStreamer::EmitWin64EHPushReg(unsigned Register) { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Win64EH::UOP_PushNonVol, Label, Register); + EmitLabel(Label); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWin64EHSetFrame(unsigned Register, unsigned Offset) { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (CurFrame->LastFrameInst >= 0) + report_fatal_error("Frame register and offset already specified!"); + if (Offset & 0x0F) + report_fatal_error("Misaligned frame pointer offset!"); + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Win64EH::UOP_SetFPReg, Label, Register, Offset); + EmitLabel(Label); + CurFrame->LastFrameInst = CurFrame->Instructions.size(); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWin64EHAllocStack(unsigned Size) { + EnsureValidW64UnwindInfo(); + if (Size & 7) + report_fatal_error("Misaligned stack allocation!"); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Label, Size); + EmitLabel(Label); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWin64EHSaveReg(unsigned Register, unsigned Offset) { + EnsureValidW64UnwindInfo(); + if (Offset & 7) + report_fatal_error("Misaligned saved register offset!"); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst( + Offset > 512*1024-8 ? Win64EH::UOP_SaveNonVolBig : Win64EH::UOP_SaveNonVol, + Label, Register, Offset); + EmitLabel(Label); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWin64EHSaveXMM(unsigned Register, unsigned Offset) { + EnsureValidW64UnwindInfo(); + if (Offset & 0x0F) + report_fatal_error("Misaligned saved vector register offset!"); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst( + Offset > 512*1024-16 ? Win64EH::UOP_SaveXMM128Big : Win64EH::UOP_SaveXMM128, + Label, Register, Offset); + EmitLabel(Label); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWin64EHPushFrame(bool Code) { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + if (CurFrame->Instructions.size() > 0) + report_fatal_error("If present, PushMachFrame must be the first UOP"); + MCSymbol *Label = getContext().CreateTempSymbol(); + MCWin64EHInstruction Inst(Win64EH::UOP_PushMachFrame, Label, Code); + EmitLabel(Label); + CurFrame->Instructions.push_back(Inst); +} + +void MCStreamer::EmitWin64EHEndProlog() { + EnsureValidW64UnwindInfo(); + MCWin64EHUnwindInfo *CurFrame = CurrentW64UnwindInfo; + CurFrame->PrologEnd = getContext().CreateTempSymbol(); + EmitLabel(CurFrame->PrologEnd); +} + +void MCStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) { + llvm_unreachable("This file format doesn't support this directive"); +} + +/// 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) { + errs() << "EmitRawText called on an MCStreamer that doesn't support it, " + " something must not be fully mc'ized\n"; + abort(); +} + +void MCStreamer::EmitRawText(const Twine &T) { + SmallString<128> Str; + EmitRawTextImpl(T.toStringRef(Str)); +} + +void MCStreamer::EmitFrames(MCAsmBackend *MAB, bool usingCFI) { + if (!getNumFrameInfos()) + return; + + if (EmitEHFrame) + MCDwarfFrameEmitter::Emit(*this, MAB, usingCFI, true); + + if (EmitDebugFrame) + MCDwarfFrameEmitter::Emit(*this, MAB, usingCFI, false); +} + +void MCStreamer::EmitW64Tables() { + if (!getNumW64UnwindInfos()) + return; + + MCWin64EHUnwindEmitter::Emit(*this); +} + +void MCStreamer::Finish() { + if (!FrameInfos.empty() && !FrameInfos.back().End) + report_fatal_error("Unfinished frame!"); + + FinishImpl(); +} + +MCSymbolData &MCStreamer::getOrCreateSymbolData(MCSymbol *Symbol) { + report_fatal_error("Not supported!"); + return *(static_cast<MCSymbolData*>(0)); +} diff --git a/contrib/llvm/lib/MC/MCSubtargetInfo.cpp b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp new file mode 100644 index 000000000000..8d8e2900b678 --- /dev/null +++ b/contrib/llvm/lib/MC/MCSubtargetInfo.cpp @@ -0,0 +1,121 @@ +//===-- 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/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/MC/MCInstrItineraries.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> + +using namespace llvm; + +MCSchedModel MCSchedModel::DefaultSchedModel; // For unknown processors. + +/// InitMCProcessorInfo - Set or change the CPU (optionally supplemented +/// with feature string). Recompute feature bits and scheduling model. +void +MCSubtargetInfo::InitMCProcessorInfo(StringRef CPU, StringRef FS) { + SubtargetFeatures Features(FS); + FeatureBits = Features.getFeatureBits(CPU, ProcDesc, NumProcs, + ProcFeatures, NumFeatures); + + InitCPUSchedModel(CPU); +} + +void +MCSubtargetInfo::InitCPUSchedModel(StringRef CPU) { + if (!CPU.empty()) + CPUSchedModel = getSchedModelForCPU(CPU); + else + CPUSchedModel = &MCSchedModel::DefaultSchedModel; +} + +void +MCSubtargetInfo::InitMCSubtargetInfo(StringRef TT, StringRef CPU, StringRef FS, + const SubtargetFeatureKV *PF, + const SubtargetFeatureKV *PD, + const SubtargetInfoKV *ProcSched, + const MCWriteProcResEntry *WPR, + const MCWriteLatencyEntry *WL, + const MCReadAdvanceEntry *RA, + const InstrStage *IS, + const unsigned *OC, + const unsigned *FP, + unsigned NF, unsigned NP) { + TargetTriple = TT; + ProcFeatures = PF; + ProcDesc = PD; + ProcSchedModels = ProcSched; + WriteProcResTable = WPR; + WriteLatencyTable = WL; + ReadAdvanceTable = RA; + + Stages = IS; + OperandCycles = OC; + ForwardingPaths = FP; + NumFeatures = NF; + NumProcs = NP; + + InitMCProcessorInfo(CPU, FS); +} + +/// ToggleFeature - Toggle a feature and returns the re-computed feature +/// bits. This version does not change the implied bits. +uint64_t MCSubtargetInfo::ToggleFeature(uint64_t FB) { + FeatureBits ^= FB; + return FeatureBits; +} + +/// ToggleFeature - Toggle a feature and returns the re-computed feature +/// bits. This version will also change all implied bits. +uint64_t MCSubtargetInfo::ToggleFeature(StringRef FS) { + SubtargetFeatures Features; + FeatureBits = Features.ToggleFeature(FeatureBits, FS, + ProcFeatures, NumFeatures); + return FeatureBits; +} + + +const MCSchedModel * +MCSubtargetInfo::getSchedModelForCPU(StringRef CPU) const { + assert(ProcSchedModels && "Processor machine model not available!"); + +#ifndef NDEBUG + for (size_t i = 1; i < NumProcs; i++) { + assert(strcmp(ProcSchedModels[i - 1].Key, ProcSchedModels[i].Key) < 0 && + "Processor machine model table is not sorted"); + } +#endif + + // Find entry + const SubtargetInfoKV *Found = + std::lower_bound(ProcSchedModels, ProcSchedModels+NumProcs, CPU); + if (Found == ProcSchedModels+NumProcs || StringRef(Found->Key) != CPU) { + errs() << "'" << CPU + << "' is not a recognized processor for this target" + << " (ignoring processor)\n"; + return &MCSchedModel::DefaultSchedModel; + } + 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); +} + +/// Initialize an InstrItineraryData instance. +void MCSubtargetInfo::initInstrItins(InstrItineraryData &InstrItins) const { + InstrItins = + InstrItineraryData(CPUSchedModel, 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..24165254e56a --- /dev/null +++ b/contrib/llvm/lib/MC/MCSymbol.cpp @@ -0,0 +1,94 @@ +//===- 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/MC/MCExpr.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +// Sentinel value for the absolute pseudo section. +const MCSection *MCSymbol::AbsolutePseudoSection = + reinterpret_cast<const MCSection *>(1); + +static bool isAcceptableChar(char C) { + if ((C < 'a' || C > 'z') && + (C < 'A' || C > 'Z') && + (C < '0' || C > '9') && + C != '_' && C != '$' && C != '.' && C != '@') + return false; + return true; +} + +/// NameNeedsQuoting - Return true if the identifier \p Str needs quotes to be +/// syntactically correct. +static bool NameNeedsQuoting(StringRef Str) { + assert(!Str.empty() && "Cannot create an empty MCSymbol"); + + // If any of the characters in the string is an unacceptable character, force + // quotes. + for (unsigned i = 0, e = Str.size(); i != e; ++i) + if (!isAcceptableChar(Str[i])) + return true; + return false; +} + +const MCSymbol &MCSymbol::AliasedSymbol() const { + const MCSymbol *S = this; + while (S->isVariable()) { + const MCExpr *Value = S->getVariableValue(); + if (Value->getKind() != MCExpr::SymbolRef) + return *S; + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr*>(Value); + S = &Ref->getSymbol(); + } + return *S; +} + +void MCSymbol::setVariableValue(const MCExpr *Value) { + assert(!IsUsed && "Cannot set a variable that has already been used."); + assert(Value && "Invalid variable value!"); + this->Value = Value; + + // Variables should always be marked as in the same "section" as the value. + const MCSection *Section = Value->FindAssociatedSection(); + if (Section) + setSection(*Section); + else + setUndefined(); +} + +void MCSymbol::print(raw_ostream &OS) 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 (!NameNeedsQuoting(Name)) { + OS << Name; + return; + } + + OS << '"'; + for (unsigned I = 0, E = Name.size(); I != E; ++I) { + char C = Name[I]; + if (C == '\n') + OS << "\\n"; + else if (C == '"') + OS << "\\\""; + else + OS << C; + } + OS << '"'; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCSymbol::dump() const { + print(dbgs()); +} +#endif diff --git a/contrib/llvm/lib/MC/MCSymbolizer.cpp b/contrib/llvm/lib/MC/MCSymbolizer.cpp new file mode 100644 index 000000000000..1020b74b342c --- /dev/null +++ b/contrib/llvm/lib/MC/MCSymbolizer.cpp @@ -0,0 +1,20 @@ +//===-- llvm/MC/MCSymbolizer.cpp - MCSymbolizer class -----------*- 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/MCSymbolizer.h" +#include "llvm/MC/MCRelocationInfo.h" + +using namespace llvm; + +MCSymbolizer::MCSymbolizer(MCContext &Ctx, OwningPtr<MCRelocationInfo> &RelInfo) + : Ctx(Ctx), RelInfo(RelInfo.take()) { +} + +MCSymbolizer::~MCSymbolizer() { +} diff --git a/contrib/llvm/lib/MC/MCValue.cpp b/contrib/llvm/lib/MC/MCValue.cpp new file mode 100644 index 000000000000..4393777211e8 --- /dev/null +++ b/contrib/llvm/lib/MC/MCValue.cpp @@ -0,0 +1,38 @@ +//===- 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/MC/MCExpr.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void MCValue::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + if (isAbsolute()) { + OS << getConstant(); + return; + } + + getSymA()->print(OS); + + if (getSymB()) { + OS << " - "; + getSymB()->print(OS); + } + + if (getConstant()) + OS << " + " << getConstant(); +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +void MCValue::dump() const { + print(dbgs(), 0); +} +#endif diff --git a/contrib/llvm/lib/MC/MCWin64EH.cpp b/contrib/llvm/lib/MC/MCWin64EH.cpp new file mode 100644 index 000000000000..b8b07d3a1808 --- /dev/null +++ b/contrib/llvm/lib/MC/MCWin64EH.cpp @@ -0,0 +1,298 @@ +//===- 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/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" + +namespace llvm { + +// NOTE: All relocations generated here are 4-byte image-relative. + +static uint8_t CountOfUnwindCodes(std::vector<MCWin64EHInstruction> &instArray){ + uint8_t count = 0; + for (std::vector<MCWin64EHInstruction>::const_iterator I = instArray.begin(), + E = instArray.end(); I != E; ++I) { + switch (I->getOperation()) { + 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: + if (I->getSize() > 512*1024-8) + count += 3; + else + count += 2; + break; + } + } + return count; +} + +static void EmitAbsDifference(MCStreamer &streamer, MCSymbol *lhs, + MCSymbol *rhs) { + MCContext &context = streamer.getContext(); + const MCExpr *diff = MCBinaryExpr::CreateSub(MCSymbolRefExpr::Create( + lhs, context), + MCSymbolRefExpr::Create( + rhs, context), + context); + streamer.EmitAbsValue(diff, 1); + +} + +static void EmitUnwindCode(MCStreamer &streamer, MCSymbol *begin, + MCWin64EHInstruction &inst) { + uint8_t b2; + uint16_t w; + b2 = (inst.getOperation() & 0x0F); + switch (inst.getOperation()) { + case Win64EH::UOP_PushNonVol: + EmitAbsDifference(streamer, inst.getLabel(), begin); + b2 |= (inst.getRegister() & 0x0F) << 4; + streamer.EmitIntValue(b2, 1); + break; + case Win64EH::UOP_AllocLarge: + EmitAbsDifference(streamer, inst.getLabel(), begin); + if (inst.getSize() > 512*1024-8) { + b2 |= 0x10; + streamer.EmitIntValue(b2, 1); + w = inst.getSize() & 0xFFF8; + streamer.EmitIntValue(w, 2); + w = inst.getSize() >> 16; + } else { + streamer.EmitIntValue(b2, 1); + w = inst.getSize() >> 3; + } + streamer.EmitIntValue(w, 2); + break; + case Win64EH::UOP_AllocSmall: + b2 |= (((inst.getSize()-8) >> 3) & 0x0F) << 4; + EmitAbsDifference(streamer, inst.getLabel(), begin); + streamer.EmitIntValue(b2, 1); + break; + case Win64EH::UOP_SetFPReg: + EmitAbsDifference(streamer, inst.getLabel(), begin); + streamer.EmitIntValue(b2, 1); + break; + case Win64EH::UOP_SaveNonVol: + case Win64EH::UOP_SaveXMM128: + b2 |= (inst.getRegister() & 0x0F) << 4; + EmitAbsDifference(streamer, inst.getLabel(), begin); + streamer.EmitIntValue(b2, 1); + w = inst.getOffset() >> 3; + if (inst.getOperation() == Win64EH::UOP_SaveXMM128) + w >>= 1; + streamer.EmitIntValue(w, 2); + break; + case Win64EH::UOP_SaveNonVolBig: + case Win64EH::UOP_SaveXMM128Big: + b2 |= (inst.getRegister() & 0x0F) << 4; + EmitAbsDifference(streamer, inst.getLabel(), begin); + streamer.EmitIntValue(b2, 1); + if (inst.getOperation() == Win64EH::UOP_SaveXMM128Big) + w = inst.getOffset() & 0xFFF0; + else + w = inst.getOffset() & 0xFFF8; + streamer.EmitIntValue(w, 2); + w = inst.getOffset() >> 16; + streamer.EmitIntValue(w, 2); + break; + case Win64EH::UOP_PushMachFrame: + if (inst.isPushCodeFrame()) + b2 |= 0x10; + EmitAbsDifference(streamer, inst.getLabel(), 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 MCWin64EHUnwindInfo *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, MCWin64EHUnwindInfo *info) { + // If this UNWIND_INFO already has a symbol, it's already been emitted. + if (info->Symbol) return; + + MCContext &context = streamer.getContext(); + streamer.EmitValueToAlignment(4); + info->Symbol = context.CreateTempSymbol(); + streamer.EmitLabel(info->Symbol); + + // 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) { + MCWin64EHInstruction &frameInst = info->Instructions[info->LastFrameInst]; + assert(frameInst.getOperation() == Win64EH::UOP_SetFPReg); + frame = (frameInst.getRegister() & 0x0F) | + (frameInst.getOffset() & 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) { + MCWin64EHInstruction 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); + } +} + +StringRef MCWin64EHUnwindEmitter::GetSectionSuffix(const MCSymbol *func) { + if (!func || !func->isInSection()) return ""; + const MCSection *section = &func->getSection(); + const MCSectionCOFF *COFFSection; + if ((COFFSection = dyn_cast<MCSectionCOFF>(section))) { + StringRef name = COFFSection->getSectionName(); + size_t dollar = name.find('$'); + size_t dot = name.find('.', 1); + if (dollar == StringRef::npos && dot == StringRef::npos) + return ""; + if (dot == StringRef::npos) + return name.substr(dollar); + if (dollar == StringRef::npos || dot < dollar) + return name.substr(dot); + return name.substr(dollar); + } + return ""; +} + +static const MCSection *getWin64EHTableSection(StringRef suffix, + MCContext &context) { + if (suffix == "") + return context.getObjectFileInfo()->getXDataSection(); + + return context.getCOFFSection((".xdata"+suffix).str(), + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getDataRel()); +} + +static const MCSection *getWin64EHFuncTableSection(StringRef suffix, + MCContext &context) { + if (suffix == "") + return context.getObjectFileInfo()->getPDataSection(); + return context.getCOFFSection((".pdata"+suffix).str(), + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ, + SectionKind::getDataRel()); +} + +void MCWin64EHUnwindEmitter::EmitUnwindInfo(MCStreamer &streamer, + MCWin64EHUnwindInfo *info) { + // Switch sections (the static function above is meant to be called from + // here and from Emit(). + MCContext &context = streamer.getContext(); + const MCSection *xdataSect = + getWin64EHTableSection(GetSectionSuffix(info->Function), context); + streamer.SwitchSection(xdataSect); + + llvm::EmitUnwindInfo(streamer, info); +} + +void MCWin64EHUnwindEmitter::Emit(MCStreamer &streamer) { + MCContext &context = streamer.getContext(); + // Emit the unwind info structs first. + for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { + MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); + const MCSection *xdataSect = + getWin64EHTableSection(GetSectionSuffix(info.Function), context); + streamer.SwitchSection(xdataSect); + llvm::EmitUnwindInfo(streamer, &info); + } + // Now emit RUNTIME_FUNCTION entries. + for (unsigned i = 0; i < streamer.getNumW64UnwindInfos(); ++i) { + MCWin64EHUnwindInfo &info = streamer.getW64UnwindInfo(i); + const MCSection *pdataSect = + getWin64EHFuncTableSection(GetSectionSuffix(info.Function), context); + streamer.SwitchSection(pdataSect); + EmitRuntimeFunction(streamer, &info); + } +} + +} // End of namespace llvm + diff --git a/contrib/llvm/lib/MC/MachObjectWriter.cpp b/contrib/llvm/lib/MC/MachObjectWriter.cpp new file mode 100644 index 000000000000..8234affc54da --- /dev/null +++ b/contrib/llvm/lib/MC/MachObjectWriter.cpp @@ -0,0 +1,958 @@ +//===- 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/MC/MCMachObjectWriter.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCMachOSymbolFlags.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MachO.h" +#include <vector> +using namespace llvm; + +void MachObjectWriter::reset() { + Relocations.clear(); + IndirectSymBase.clear(); + StringTable.clear(); + LocalSymbolData.clear(); + ExternalSymbolData.clear(); + UndefinedSymbolData.clear(); + MCObjectWriter::reset(); +} + +bool MachObjectWriter:: +doesSymbolRequireExternRelocation(const MCSymbolData *SD) { + // Undefined symbols are always extern. + if (SD->Symbol->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 (SD->getFlags() & SF_WeakDefinition) + return true; + + // Otherwise, we can use an internal relocation. + return false; +} + +bool MachObjectWriter:: +MachSymbolData::operator<(const MachSymbolData &RHS) const { + return SymbolData->getSymbol().getName() < + RHS.SymbolData->getSymbol().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 MCSymbolData* SD, + const MCAsmLayout &Layout) const { + const MCSymbol &S = SD->getSymbol(); + + // 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)) + 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(&Layout.getAssembler().getSymbolData( + Target.getSymA()->getSymbol()), Layout); + if (Target.getSymB()) + Address += getSymbolAddress(&Layout.getAssembler().getSymbolData( + Target.getSymB()->getSymbol()), Layout); + return Address; + } + + return getSectionAddress(SD->getFragment()->getParent()) + + Layout.getSymbolOffset(SD); +} + +uint64_t MachObjectWriter::getPaddingSize(const MCSectionData *SD, + const MCAsmLayout &Layout) const { + uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD); + unsigned Next = SD->getLayoutOrder() + 1; + if (Next >= Layout.getSectionOrder().size()) + return 0; + + const MCSectionData &NextSD = *Layout.getSectionOrder()[Next]; + if (NextSD.getSection().isVirtualSection()) + return 0; + return OffsetToAlignment(EndAddr, NextSD.getAlignment()); +} + +void MachObjectWriter::WriteHeader(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 = OS.tell(); + (void) Start; + + Write32(is64Bit() ? MachO::MH_MAGIC_64 : MachO::MH_MAGIC); + + Write32(TargetObjectWriter->getCPUType()); + Write32(TargetObjectWriter->getCPUSubtype()); + + Write32(MachO::MH_OBJECT); + Write32(NumLoadCommands); + Write32(LoadCommandsSize); + Write32(Flags); + if (is64Bit()) + Write32(0); // reserved + + assert(OS.tell() - Start == + (is64Bit()?sizeof(MachO::mach_header_64): sizeof(MachO::mach_header))); +} + +/// 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(unsigned NumSections, + uint64_t VMSize, + uint64_t SectionDataStartOffset, + uint64_t SectionDataSize) { + // struct segment_command (56 bytes) or + // struct segment_command_64 (72 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + unsigned SegmentLoadCommandSize = + is64Bit() ? sizeof(MachO::segment_command_64): + sizeof(MachO::segment_command); + Write32(is64Bit() ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT); + Write32(SegmentLoadCommandSize + + NumSections * (is64Bit() ? sizeof(MachO::section_64) : + sizeof(MachO::section))); + + WriteBytes("", 16); + if (is64Bit()) { + Write64(0); // vmaddr + Write64(VMSize); // vmsize + Write64(SectionDataStartOffset); // file offset + Write64(SectionDataSize); // file size + } else { + Write32(0); // vmaddr + Write32(VMSize); // vmsize + Write32(SectionDataStartOffset); // file offset + Write32(SectionDataSize); // file size + } + // maxprot + Write32(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE); + // initprot + Write32(MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE); + Write32(NumSections); + Write32(0); // flags + + assert(OS.tell() - Start == SegmentLoadCommandSize); +} + +void MachObjectWriter::WriteSection(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCSectionData &SD, + uint64_t FileOffset, + uint64_t RelocationsStart, + unsigned NumRelocations) { + uint64_t SectionSize = Layout.getSectionAddressSize(&SD); + + // The offset is unused for virtual sections. + if (SD.getSection().isVirtualSection()) { + assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); + FileOffset = 0; + } + + // struct section (68 bytes) or + // struct section_64 (80 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection()); + WriteBytes(Section.getSectionName(), 16); + WriteBytes(Section.getSegmentName(), 16); + if (is64Bit()) { + Write64(getSectionAddress(&SD)); // address + Write64(SectionSize); // size + } else { + Write32(getSectionAddress(&SD)); // address + Write32(SectionSize); // size + } + Write32(FileOffset); + + unsigned Flags = Section.getTypeAndAttributes(); + if (SD.hasInstructions()) + Flags |= MCSectionMachO::S_ATTR_SOME_INSTRUCTIONS; + + assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); + Write32(Log2_32(SD.getAlignment())); + Write32(NumRelocations ? RelocationsStart : 0); + Write32(NumRelocations); + Write32(Flags); + Write32(IndirectSymBase.lookup(&SD)); // reserved1 + Write32(Section.getStubSize()); // reserved2 + if (is64Bit()) + Write32(0); // reserved3 + + assert(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 = OS.tell(); + (void) Start; + + Write32(MachO::LC_SYMTAB); + Write32(sizeof(MachO::symtab_command)); + Write32(SymbolOffset); + Write32(NumSymbols); + Write32(StringTableOffset); + Write32(StringTableSize); + + assert(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 = OS.tell(); + (void) Start; + + Write32(MachO::LC_DYSYMTAB); + Write32(sizeof(MachO::dysymtab_command)); + Write32(FirstLocalSymbol); + Write32(NumLocalSymbols); + Write32(FirstExternalSymbol); + Write32(NumExternalSymbols); + Write32(FirstUndefinedSymbol); + Write32(NumUndefinedSymbols); + Write32(0); // tocoff + Write32(0); // ntoc + Write32(0); // modtaboff + Write32(0); // nmodtab + Write32(0); // extrefsymoff + Write32(0); // nextrefsyms + Write32(IndirectSymbolOffset); + Write32(NumIndirectSymbols); + Write32(0); // extreloff + Write32(0); // nextrel + Write32(0); // locreloff + Write32(0); // nlocrel + + assert(OS.tell() - Start == sizeof(MachO::dysymtab_command)); +} + +void MachObjectWriter::WriteNlist(MachSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &Data = *MSD.SymbolData; + const MCSymbol &Symbol = Data.getSymbol(); + uint8_t Type = 0; + uint16_t Flags = Data.getFlags(); + uint64_t Address = 0; + + // Set the N_TYPE bits. See <mach-o/nlist.h>. + // + // FIXME: Are the prebound or indirect fields possible here? + 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() || Symbol.isUndefined()) + Type |= MachO::N_EXT; + + // Compute the symbol address. + if (Symbol.isDefined()) { + Address = getSymbolAddress(&Data, Layout); + } else if (Data.isCommon()) { + // Common symbols are encoded with the size in the address + // field, and their alignment in the flags. + Address = Data.getCommonSize(); + + // Common alignment is packed into the 'desc' bits. + if (unsigned Align = Data.getCommonAlignment()) { + unsigned Log2Size = Log2_32(Align); + assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); + if (Log2Size > 15) + report_fatal_error("invalid 'common' alignment '" + + Twine(Align) + "' for '" + Symbol.getName() + "'", + false); + // FIXME: Keep this mask with the SymbolFlags enumeration. + Flags = (Flags & 0xF0FF) | (Log2Size << 8); + } + } + + // struct nlist (12 bytes) + + Write32(MSD.StringIndex); + Write8(Type); + Write8(MSD.SectionIndex); + + // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' + // value. + Write16(Flags); + if (is64Bit()) + Write64(Address); + else + Write32(Address); +} + +void MachObjectWriter::WriteLinkeditLoadCommand(uint32_t Type, + uint32_t DataOffset, + uint32_t DataSize) { + uint64_t Start = OS.tell(); + (void) Start; + + Write32(Type); + Write32(sizeof(MachO::linkedit_data_command)); + Write32(DataOffset); + Write32(DataSize); + + assert(OS.tell() - Start == sizeof(MachO::linkedit_data_command)); +} + +static unsigned ComputeLinkerOptionsLoadCommandSize( + const std::vector<std::string> &Options, bool is64Bit) +{ + unsigned Size = sizeof(MachO::linker_options_command); + for (unsigned i = 0, e = Options.size(); i != e; ++i) + Size += Options[i].size() + 1; + return RoundUpToAlignment(Size, is64Bit ? 8 : 4); +} + +void MachObjectWriter::WriteLinkerOptionsLoadCommand( + const std::vector<std::string> &Options) +{ + unsigned Size = ComputeLinkerOptionsLoadCommandSize(Options, is64Bit()); + uint64_t Start = OS.tell(); + (void) Start; + + Write32(MachO::LC_LINKER_OPTIONS); + Write32(Size); + Write32(Options.size()); + uint64_t BytesWritten = sizeof(MachO::linker_options_command); + for (unsigned i = 0, e = Options.size(); i != e; ++i) { + // Write each string, including the null byte. + const std::string &Option = Options[i]; + WriteBytes(Option.c_str(), Option.size() + 1); + BytesWritten += Option.size() + 1; + } + + // Pad to a multiple of the pointer size. + WriteBytes("", OffsetToAlignment(BytesWritten, is64Bit() ? 8 : 4)); + + assert(OS.tell() - Start == Size); +} + + +void MachObjectWriter::RecordRelocation(const 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->SectionData->getSection()); + + if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS && + Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + Section.getType() != MCSectionMachO::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->SectionData->getSection()); + + if (Section.getType() != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) + continue; + + // Initialize the section indirect symbol base, if necessary. + IndirectSymBase.insert(std::make_pair(it->SectionData, IndirectIndex)); + + Asm.getOrCreateSymbolData(*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->SectionData->getSection()); + + if (Section.getType() != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + Section.getType() != MCSectionMachO::S_SYMBOL_STUBS) + continue; + + // Initialize the section indirect symbol base, if necessary. + IndirectSymBase.insert(std::make_pair(it->SectionData, IndirectIndex)); + + // Set the symbol type to undefined lazy, but only on construction. + // + // FIXME: Do not hardcode. + bool Created; + MCSymbolData &Entry = Asm.getOrCreateSymbolData(*it->Symbol, &Created); + if (Created) + Entry.setFlags(Entry.getFlags() | 0x0001); + } +} + +/// ComputeSymbolTable - Compute the symbol table data +/// +/// \param StringTable [out] - The string table data. +/// \param StringIndexMap [out] - Map from symbol names to offsets in the +/// string table. +void MachObjectWriter:: +ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, + 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->getSection()] = Index; + assert(Index <= 256 && "Too many sections!"); + + // Index 0 is always the empty string. + StringMap<uint64_t> StringIndexMap; + StringTable += '\x00'; + + // Build the symbol arrays and the string table, but only for non-local + // symbols. + // + // The particular order that we collect the symbols and create the string + // table, 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 (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore non-linker visible symbols. + if (!Asm.isSymbolLinkerVisible(it->getSymbol())) + continue; + + if (!it->isExternal() && !Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + MachSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + 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 (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore non-linker visible symbols. + if (!Asm.isSymbolLinkerVisible(it->getSymbol())) + continue; + + if (it->isExternal() || Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + MachSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + 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. + std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); + std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + + // Set the symbol indices. + Index = 0; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + LocalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + ExternalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + UndefinedSymbolData[i].SymbolData->setIndex(Index++); + + // The string table is padded to a multiple of 4. + while (StringTable.size() % 4) + StringTable += '\x00'; +} + +void MachObjectWriter::computeSectionAddresses(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartAddress = 0; + const SmallVectorImpl<MCSectionData*> &Order = Layout.getSectionOrder(); + for (int i = 0, n = Order.size(); i != n ; ++i) { + const MCSectionData *SD = Order[i]; + StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); + SectionAddress[SD] = StartAddress; + StartAddress += Layout.getSectionAddressSize(SD); + + // 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(SD, Layout); + } +} + +void MachObjectWriter::markAbsoluteVariableSymbols(MCAssembler &Asm, + const MCAsmLayout &Layout) { + for (MCAssembler::symbol_iterator i = Asm.symbol_begin(), + e = Asm.symbol_end(); + i != e; ++i) { + MCSymbolData &SD = *i; + if (!SD.getSymbol().isVariable()) + continue; + + // Is the variable is a symbol difference (SA - SB + C) expression, + // and neither symbol is external, mark the variable as absolute. + const MCExpr *Expr = SD.getSymbol().getVariableValue(); + MCValue Value; + if (Expr->EvaluateAsRelocatable(Value, Layout)) { + if (Value.getSymA() && Value.getSymB()) + const_cast<MCSymbol*>(&SD.getSymbol())->setAbsolute(); + } + } +} + +void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + computeSectionAddresses(Asm, Layout); + + // Create symbol data for any indirect symbols. + BindIndirectSymbols(Asm); + + // Mark symbol difference expressions in variables (from .set or = directives) + // as absolute. + markAbsoluteVariableSymbols(Asm, Layout); + + // Compute symbol table information and bind symbol indices. + ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, + UndefinedSymbolData); +} + +bool MachObjectWriter:: +IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + 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 MCSymbolData *A_Base = 0, *B_Base = 0; + + const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); + const MCSection &SecA = SA.getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + + 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. + + if (!Asm.getBackend().hasReliableSymbolDifference()) { + if (!SA.isInSection() || &SecA != &SecB || + (!SA.isTemporary() && + FB.getAtom() != Asm.getSymbolData(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; + } + } else { + if (!TargetObjectWriter->useAggressiveSymbolFolding()) + return false; + } + + const MCFragment *FA = Asm.getSymbolData(SA).getFragment(); + + // Bail if the symbol has no fragment. + if (!FA) + return false; + + A_Base = FA->getAtom(); + if (!A_Base) + return false; + + B_Base = FB.getAtom(); + if (!B_Base) + return false; + + // If the atoms are the same, they are guaranteed to have the same address. + if (A_Base == B_Base) + return true; + + // Otherwise, we can't prove this is fully resolved. + return false; +} + +void MachObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + unsigned NumSections = Asm.size(); + + // 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 data-in-code load command size, if used. + unsigned NumDataRegions = Asm.getDataRegions().size(); + if (NumDataRegions) { + ++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. + const std::vector<std::vector<std::string> > &LinkerOptions = + Asm.getLinkerOptions(); + for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) { + ++NumLoadCommands; + LoadCommandsSize += ComputeLinkerOptionsLoadCommandSize(LinkerOptions[i], + 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 (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + uint64_t Address = getSectionAddress(&SD); + uint64_t Size = Layout.getSectionAddressSize(&SD); + uint64_t FileSize = Layout.getSectionFileSize(&SD); + FileSize += getPaddingSize(&SD, Layout); + + VMSize = std::max(VMSize, Address + Size); + + if (SD.getSection().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(NumLoadCommands, LoadCommandsSize, + Asm.getSubsectionsViaSymbols()); + WriteSegmentLoadCommand(NumSections, VMSize, + SectionDataStart, SectionDataSize); + + // ... and then the section headers. + uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + std::vector<MachO::any_relocation_info> &Relocs = Relocations[it]; + unsigned NumRelocs = Relocs.size(); + uint64_t SectionStart = SectionDataStart + getSectionAddress(it); + WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); + RelocTableEnd += NumRelocs * sizeof(MachO::any_relocation_info); + } + + // 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 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 = DataInCodeTableEnd; + + // The symbol table is written after the indirect symbol data. + uint64_t SymbolTableOffset = DataInCodeTableEnd + 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.size()); + + WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, + FirstExternalSymbol, NumExternalSymbols, + FirstUndefinedSymbol, NumUndefinedSymbols, + IndirectSymbolOffset, NumIndirectSymbols); + } + + // Write the linker options load commands. + for (unsigned i = 0, e = LinkerOptions.size(); i != e; ++i) { + WriteLinkerOptionsLoadCommand(LinkerOptions[i]); + } + + // Write the actual section data. + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + Asm.writeSectionData(it, Layout); + + uint64_t Pad = getPaddingSize(it, Layout); + for (unsigned int i = 0; i < Pad; ++i) + Write8(0); + } + + // Write the extra padding. + WriteZeros(SectionDataPadding); + + // Write the relocation entries. + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + // Write the section relocation entries, in reverse order to match 'as' + // (approximately, the exact algorithm is more complicated than this). + std::vector<MachO::any_relocation_info> &Relocs = Relocations[it]; + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { + Write32(Relocs[e - i - 1].r_word0); + Write32(Relocs[e - i - 1].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(&Layout.getAssembler().getSymbolData(*Data->Start), + Layout); + uint64_t End = + getSymbolAddress(&Layout.getAssembler().getSymbolData(*Data->End), + Layout); + DEBUG(dbgs() << "data in code region-- kind: " << Data->Kind + << " start: " << Start << "(" << Data->Start->getName() << ")" + << " end: " << End << "(" << Data->End->getName() << ")" + << " size: " << End - Start + << "\n"); + Write32(Start); + Write16(End - Start); + Write16(Data->Kind); + } + + // 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->SectionData->getSection()); + if (Section.getType() == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { + // If this symbol is defined and internal, mark it as such. + if (it->Symbol->isDefined() && + !Asm.getSymbolData(*it->Symbol).isExternal()) { + uint32_t Flags = MachO::INDIRECT_SYMBOL_LOCAL; + if (it->Symbol->isAbsolute()) + Flags |= MachO::INDIRECT_SYMBOL_ABS; + Write32(Flags); + continue; + } + } + + Write32(Asm.getSymbolData(*it->Symbol).getIndex()); + } + + // FIXME: Check that offsets match computed ones. + + // Write the symbol table entries. + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + WriteNlist(LocalSymbolData[i], Layout); + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + WriteNlist(ExternalSymbolData[i], Layout); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + WriteNlist(UndefinedSymbolData[i], Layout); + + // Write the string table. + OS << StringTable.str(); + } +} + +MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW, + raw_ostream &OS, + bool IsLittleEndian) { + return new MachObjectWriter(MOTW, OS, IsLittleEndian); +} diff --git a/contrib/llvm/lib/MC/SubtargetFeature.cpp b/contrib/llvm/lib/MC/SubtargetFeature.cpp new file mode 100644 index 000000000000..2fb91f2125b1 --- /dev/null +++ b/contrib/llvm/lib/MC/SubtargetFeature.cpp @@ -0,0 +1,370 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SubtargetFeature interface. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cstdlib> +using namespace llvm; + +//===----------------------------------------------------------------------===// +// Static Helper Functions +//===----------------------------------------------------------------------===// + +/// hasFlag - Determine if a feature has a flag; '+' or '-' +/// +static inline bool hasFlag(const StringRef Feature) { + assert(!Feature.empty() && "Empty string"); + // Get first character + char Ch = Feature[0]; + // Check if first character is '+' or '-' flag + return Ch == '+' || Ch =='-'; +} + +/// StripFlag - Return string stripped of flag. +/// +static inline std::string StripFlag(const StringRef Feature) { + return hasFlag(Feature) ? Feature.substr(1) : Feature; +} + +/// isEnabled - Return true if enable flag; '+'. +/// +static inline bool isEnabled(const StringRef Feature) { + assert(!Feature.empty() && "Empty string"); + // Get first character + char Ch = Feature[0]; + // Check if first character is '+' for enabled + return Ch == '+'; +} + +/// PrependFlag - Return a string with a prepended flag; '+' or '-'. +/// +static inline std::string PrependFlag(const StringRef Feature, + bool IsEnabled) { + assert(!Feature.empty() && "Empty string"); + if (hasFlag(Feature)) + return Feature; + std::string Prefix = IsEnabled ? "+" : "-"; + Prefix += Feature; + return Prefix; +} + +/// Split - Splits a string of comma separated items in to a vector of strings. +/// +static void Split(std::vector<std::string> &V, const StringRef S) { + if (S.empty()) + return; + + // Start at beginning of string. + size_t Pos = 0; + while (true) { + // Find the next comma + size_t Comma = S.find(',', Pos); + // If no comma found then the rest of the string is used + if (Comma == std::string::npos) { + // Add string to vector + V.push_back(S.substr(Pos)); + break; + } + // Otherwise add substring to vector + V.push_back(S.substr(Pos, Comma - Pos)); + // Advance to next item + Pos = Comma + 1; + } +} + +/// Join a vector of strings to a string with a comma separating each element. +/// +static std::string Join(const std::vector<std::string> &V) { + // Start with empty string. + std::string Result; + // If the vector is not empty + if (!V.empty()) { + // Start with the first feature + Result = V[0]; + // For each successive feature + for (size_t i = 1; i < V.size(); i++) { + // Add a comma + Result += ","; + // Add the feature + Result += V[i]; + } + } + // Return the features string + return Result; +} + +/// Adding features. +void SubtargetFeatures::AddFeature(const StringRef String, + bool IsEnabled) { + // Don't add empty features + if (!String.empty()) { + // Convert to lowercase, prepend flag and add to vector + Features.push_back(PrependFlag(String.lower(), IsEnabled)); + } +} + +/// Find KV in array using binary search. +static const SubtargetFeatureKV *Find(StringRef S, const SubtargetFeatureKV *A, + size_t L) { + // Determine the end of the array + const SubtargetFeatureKV *Hi = A + L; + // Binary search the array + const SubtargetFeatureKV *F = std::lower_bound(A, Hi, S); + // If not found then return NULL + if (F == Hi || StringRef(F->Key) != S) return NULL; + // Return the found array item + return F; +} + +/// getLongestEntryLength - Return the length of the longest entry in the table. +/// +static size_t getLongestEntryLength(const SubtargetFeatureKV *Table, + size_t Size) { + size_t MaxLen = 0; + for (size_t i = 0; i < Size; i++) + MaxLen = std::max(MaxLen, std::strlen(Table[i].Key)); + return MaxLen; +} + +/// Display help for feature choices. +/// +static void Help(const SubtargetFeatureKV *CPUTable, size_t CPUTableSize, + const SubtargetFeatureKV *FeatTable, size_t FeatTableSize) { + // Determine the length of the longest CPU and Feature entries. + unsigned MaxCPULen = getLongestEntryLength(CPUTable, CPUTableSize); + unsigned MaxFeatLen = getLongestEntryLength(FeatTable, FeatTableSize); + + // Print the CPU table. + errs() << "Available CPUs for this target:\n\n"; + for (size_t i = 0; i != CPUTableSize; i++) + errs() << format(" %-*s - %s.\n", + MaxCPULen, CPUTable[i].Key, CPUTable[i].Desc); + errs() << '\n'; + + // Print the Feature table. + errs() << "Available features for this target:\n\n"; + for (size_t i = 0; i != FeatTableSize; i++) + errs() << format(" %-*s - %s.\n", + MaxFeatLen, FeatTable[i].Key, FeatTable[i].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"; + std::exit(1); +} + +//===----------------------------------------------------------------------===// +// SubtargetFeatures Implementation +//===----------------------------------------------------------------------===// + +SubtargetFeatures::SubtargetFeatures(const StringRef Initial) { + // Break up string into separate features + Split(Features, Initial); +} + + +std::string SubtargetFeatures::getString() const { + return Join(Features); +} + +/// SetImpliedBits - For each feature that is (transitively) implied by this +/// feature, set it. +/// +static +void SetImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + for (size_t i = 0; i < FeatureTableSize; ++i) { + const SubtargetFeatureKV &FE = FeatureTable[i]; + + if (FeatureEntry->Value == FE.Value) continue; + + if (FeatureEntry->Implies & FE.Value) { + Bits |= FE.Value; + SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); + } + } +} + +/// ClearImpliedBits - For each feature that (transitively) implies this +/// feature, clear it. +/// +static +void ClearImpliedBits(uint64_t &Bits, const SubtargetFeatureKV *FeatureEntry, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + for (size_t i = 0; i < FeatureTableSize; ++i) { + const SubtargetFeatureKV &FE = FeatureTable[i]; + + if (FeatureEntry->Value == FE.Value) continue; + + if (FE.Implies & FeatureEntry->Value) { + Bits &= ~FE.Value; + ClearImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); + } + } +} + +/// ToggleFeature - Toggle a feature and returns the newly updated feature +/// bits. +uint64_t +SubtargetFeatures::ToggleFeature(uint64_t Bits, const StringRef Feature, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable, FeatureTableSize); + // 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, FeatureTableSize); + } else { + Bits |= FeatureEntry->Value; + + // For each feature that this implies, set it. + SetImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); + } + } else { + errs() << "'" << Feature + << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } + + return Bits; +} + + +/// getFeatureBits - Get feature bits a CPU. +/// +uint64_t SubtargetFeatures::getFeatureBits(const StringRef CPU, + const SubtargetFeatureKV *CPUTable, + size_t CPUTableSize, + const SubtargetFeatureKV *FeatureTable, + size_t FeatureTableSize) { + if (!FeatureTableSize || !CPUTableSize) + return 0; + +#ifndef NDEBUG + for (size_t i = 1; i < CPUTableSize; i++) { + assert(strcmp(CPUTable[i - 1].Key, CPUTable[i].Key) < 0 && + "CPU table is not sorted"); + } + for (size_t i = 1; i < FeatureTableSize; i++) { + assert(strcmp(FeatureTable[i - 1].Key, FeatureTable[i].Key) < 0 && + "CPU features table is not sorted"); + } +#endif + uint64_t Bits = 0; // Resulting bits + + // Check if help is needed + if (CPU == "help") + Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize); + + // Find CPU entry if CPU name is specified. + if (!CPU.empty()) { + const SubtargetFeatureKV *CPUEntry = Find(CPU, CPUTable, CPUTableSize); + // 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 (size_t i = 0; i < FeatureTableSize; ++i) { + const SubtargetFeatureKV &FE = FeatureTable[i]; + if (CPUEntry->Value & FE.Value) + SetImpliedBits(Bits, &FE, FeatureTable, FeatureTableSize); + } + } else { + errs() << "'" << CPU + << "' is not a recognized processor for this target" + << " (ignoring processor)\n"; + } + } + + // Iterate through each feature + for (size_t i = 0, E = Features.size(); i < E; i++) { + const StringRef Feature = Features[i]; + + // Check for help + if (Feature == "+help") + Help(CPUTable, CPUTableSize, FeatureTable, FeatureTableSize); + + // Find feature in table. + const SubtargetFeatureKV *FeatureEntry = + Find(StripFlag(Feature), FeatureTable, FeatureTableSize); + // 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, FeatureTableSize); + } else { + Bits &= ~FeatureEntry->Value; + + // For each feature that implies this, clear it. + ClearImpliedBits(Bits, FeatureEntry, FeatureTable, FeatureTableSize); + } + } else { + errs() << "'" << Feature + << "' is not a recognized feature for this target" + << " (ignoring feature)\n"; + } + } + + return Bits; +} + +/// print - Print feature string. +/// +void SubtargetFeatures::print(raw_ostream &OS) const { + for (size_t i = 0, e = Features.size(); i != e; ++i) + OS << Features[i] << " "; + OS << "\n"; +} + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +/// dump - Dump feature info. +/// +void SubtargetFeatures::dump() const { + print(dbgs()); +} +#endif + +/// Adds the default features for the specified target 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>. +/// +void SubtargetFeatures::getDefaultSubtargetFeatures(const Triple& Triple) { + 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/WinCOFFObjectWriter.cpp b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp new file mode 100644 index 000000000000..d9ca86d8af93 --- /dev/null +++ b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -0,0 +1,929 @@ +//===-- llvm/MC/WinCOFFObjectWriter.cpp -------------------------*- C++ -*-===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "WinCOFFObjectWriter" + +#include "llvm/MC/MCWinCOFFObjectWriter.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TimeValue.h" +#include <cstdio> + +using namespace llvm; + +namespace { +typedef SmallString<COFF::NameSize> name; + +enum AuxiliaryType { + ATFunctionDefinition, + ATbfAndefSymbol, + ATWeakExternal, + ATFile, + ATSectionDefinition +}; + +struct AuxSymbol { + AuxiliaryType AuxType; + COFF::Auxiliary Aux; +}; + +class COFFSymbol; +class COFFSection; + +class COFFSymbol { +public: + COFF::symbol Data; + + typedef SmallVector<AuxSymbol, 1> AuxiliarySymbols; + + name Name; + int Index; + AuxiliarySymbols Aux; + COFFSymbol *Other; + COFFSection *Section; + int Relocations; + + MCSymbolData const *MCData; + + COFFSymbol(StringRef name); + size_t size() const; + void set_name_offset(uint32_t Offset); + + bool should_keep() const; +}; + +// This class contains staging data for a COFF relocation entry. +struct COFFRelocation { + COFF::relocation Data; + COFFSymbol *Symb; + + COFFRelocation() : Symb(NULL) {} + static size_t size() { return COFF::RelocationSize; } +}; + +typedef std::vector<COFFRelocation> relocations; + +class COFFSection { +public: + COFF::section Header; + + std::string Name; + int Number; + MCSectionData const *MCData; + COFFSymbol *Symbol; + relocations Relocations; + + COFFSection(StringRef name); + static size_t size(); +}; + +// This class holds the COFF string table. +class StringTable { + typedef StringMap<size_t> map; + map Map; + + void update_length(); +public: + std::vector<char> Data; + + StringTable(); + size_t size() const; + size_t insert(StringRef String); +}; + +class WinCOFFObjectWriter : public MCObjectWriter { +public: + + typedef std::vector<COFFSymbol*> symbols; + typedef std::vector<COFFSection*> sections; + + typedef DenseMap<MCSymbol const *, COFFSymbol *> symbol_map; + typedef DenseMap<MCSection const *, COFFSection *> section_map; + + llvm::OwningPtr<MCWinCOFFObjectTargetWriter> TargetObjectWriter; + + // Root level file contents. + COFF::header Header; + sections Sections; + symbols Symbols; + StringTable Strings; + + // Maps used during object file creation. + section_map SectionMap; + symbol_map SymbolMap; + + WinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, raw_ostream &OS); + virtual ~WinCOFFObjectWriter(); + + COFFSymbol *createSymbol(StringRef Name); + COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol * Symbol); + COFFSection *createSection(StringRef Name); + + template <typename object_t, typename list_t> + object_t *createCOFFEntity(StringRef Name, list_t &List); + + void DefineSection(MCSectionData const &SectionData); + void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler, + const MCAsmLayout &Layout); + + void MakeSymbolReal(COFFSymbol &S, size_t Index); + void MakeSectionReal(COFFSection &S, size_t Number); + + bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm); + + 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 WriteSectionHeader(const COFF::section &S); + void WriteRelocation(const COFF::relocation &R); + + // MCObjectWriter interface implementation. + + void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout); + + void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue); + + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); +}; +} + +static inline void write_uint32_le(void *Data, uint32_t const &Value) { + uint8_t *Ptr = reinterpret_cast<uint8_t *>(Data); + Ptr[0] = (Value & 0x000000FF) >> 0; + Ptr[1] = (Value & 0x0000FF00) >> 8; + Ptr[2] = (Value & 0x00FF0000) >> 16; + Ptr[3] = (Value & 0xFF000000) >> 24; +} + +//------------------------------------------------------------------------------ +// Symbol class implementation + +COFFSymbol::COFFSymbol(StringRef name) + : Name(name.begin(), name.end()) + , Other(NULL) + , Section(NULL) + , Relocations(0) + , MCData(NULL) { + memset(&Data, 0, sizeof(Data)); +} + +size_t COFFSymbol::size() const { + return COFF::SymbolSize + (Data.NumberOfAuxSymbols * COFF::SymbolSize); +} + +// 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) { + write_uint32_le(Data.Name + 0, 0); + write_uint32_le(Data.Name + 4, Offset); +} + +/// logic to decide if the symbol should be reported in the symbol table +bool COFFSymbol::should_keep() const { + // no section means its external, keep it + if (Section == NULL) + return true; + + // if it has relocations pointing at it, keep it + if (Relocations > 0) { + assert(Section->Number != -1 && "Sections with relocations must be real!"); + return true; + } + + // if the section its in is being droped, drop it + if (Section->Number == -1) + return false; + + // if it is the section symbol, keep it + if (Section->Symbol == this) + return true; + + // if its temporary, drop it + if (MCData && MCData->getSymbol().isTemporary()) + return false; + + // otherwise, keep it + return true; +} + +//------------------------------------------------------------------------------ +// Section class implementation + +COFFSection::COFFSection(StringRef name) + : Name(name) + , MCData(NULL) + , Symbol(NULL) { + memset(&Header, 0, sizeof(Header)); +} + +size_t COFFSection::size() { + return COFF::SectionSize; +} + +//------------------------------------------------------------------------------ +// StringTable class implementation + +/// Write the length of the string table into Data. +/// The length of the string table includes uint32 length header. +void StringTable::update_length() { + write_uint32_le(&Data.front(), Data.size()); +} + +StringTable::StringTable() { + // The string table data begins with the length of the entire string table + // including the length header. Allocate space for this header. + Data.resize(4); + update_length(); +} + +size_t StringTable::size() const { + return Data.size(); +} + +/// Add String to the table iff it is not already there. +/// @returns the index into the string table where the string is now located. +size_t StringTable::insert(StringRef String) { + map::iterator i = Map.find(String); + + if (i != Map.end()) + return i->second; + + size_t Offset = Data.size(); + + // Insert string data into string table. + Data.insert(Data.end(), String.begin(), String.end()); + Data.push_back('\0'); + + // Put a reference to it in the map. + Map[String] = Offset; + + // Update the internal length field. + update_length(); + + return Offset; +} + +//------------------------------------------------------------------------------ +// WinCOFFObjectWriter class implementation + +WinCOFFObjectWriter::WinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, + raw_ostream &OS) + : MCObjectWriter(OS, true) + , TargetObjectWriter(MOTW) { + memset(&Header, 0, sizeof(Header)); + + Header.Machine = TargetObjectWriter->getMachine(); +} + +WinCOFFObjectWriter::~WinCOFFObjectWriter() { + for (symbols::iterator I = Symbols.begin(), E = Symbols.end(); I != E; ++I) + delete *I; + for (sections::iterator I = Sections.begin(), E = Sections.end(); I != E; ++I) + delete *I; +} + +COFFSymbol *WinCOFFObjectWriter::createSymbol(StringRef Name) { + return createCOFFEntity<COFFSymbol>(Name, Symbols); +} + +COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol * Symbol){ + symbol_map::iterator i = SymbolMap.find(Symbol); + if (i != SymbolMap.end()) + return i->second; + COFFSymbol *RetSymbol + = createCOFFEntity<COFFSymbol>(Symbol->getName(), Symbols); + SymbolMap[Symbol] = RetSymbol; + return RetSymbol; +} + +COFFSection *WinCOFFObjectWriter::createSection(StringRef Name) { + return createCOFFEntity<COFFSection>(Name, Sections); +} + +/// A template used to lookup or create a symbol/section, and initialize it if +/// needed. +template <typename object_t, typename list_t> +object_t *WinCOFFObjectWriter::createCOFFEntity(StringRef Name, + list_t &List) { + object_t *Object = new object_t(Name); + + List.push_back(Object); + + return Object; +} + +/// This function takes a section data object from the assembler +/// and creates the associated COFF section staging object. +void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { + assert(SectionData.getSection().getVariant() == MCSection::SV_COFF + && "Got non COFF section in the COFF backend!"); + // FIXME: Not sure how to verify this (at least in a debug build). + MCSectionCOFF const &Sec = + static_cast<MCSectionCOFF const &>(SectionData.getSection()); + + COFFSection *coff_section = createSection(Sec.getSectionName()); + COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName()); + + coff_section->Symbol = coff_symbol; + coff_symbol->Section = coff_section; + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; + + // In this case the auxiliary symbol is a Section Definition. + coff_symbol->Aux.resize(1); + memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); + coff_symbol->Aux[0].AuxType = ATSectionDefinition; + coff_symbol->Aux[0].Aux.SectionDefinition.Selection = Sec.getSelection(); + + coff_section->Header.Characteristics = Sec.getCharacteristics(); + + uint32_t &Characteristics = coff_section->Header.Characteristics; + switch (SectionData.getAlignment()) { + case 1: Characteristics |= COFF::IMAGE_SCN_ALIGN_1BYTES; break; + case 2: Characteristics |= COFF::IMAGE_SCN_ALIGN_2BYTES; break; + case 4: Characteristics |= COFF::IMAGE_SCN_ALIGN_4BYTES; break; + case 8: Characteristics |= COFF::IMAGE_SCN_ALIGN_8BYTES; break; + case 16: Characteristics |= COFF::IMAGE_SCN_ALIGN_16BYTES; break; + case 32: Characteristics |= COFF::IMAGE_SCN_ALIGN_32BYTES; break; + case 64: Characteristics |= COFF::IMAGE_SCN_ALIGN_64BYTES; break; + case 128: Characteristics |= COFF::IMAGE_SCN_ALIGN_128BYTES; break; + case 256: Characteristics |= COFF::IMAGE_SCN_ALIGN_256BYTES; break; + case 512: Characteristics |= COFF::IMAGE_SCN_ALIGN_512BYTES; break; + case 1024: Characteristics |= COFF::IMAGE_SCN_ALIGN_1024BYTES; break; + case 2048: Characteristics |= COFF::IMAGE_SCN_ALIGN_2048BYTES; break; + case 4096: Characteristics |= COFF::IMAGE_SCN_ALIGN_4096BYTES; break; + case 8192: Characteristics |= COFF::IMAGE_SCN_ALIGN_8192BYTES; break; + default: + llvm_unreachable("unsupported section alignment"); + } + + // Bind internal COFF section to MC section. + coff_section->MCData = &SectionData; + SectionMap[&SectionData.getSection()] = coff_section; +} + +/// This function takes a section data object from the assembler +/// and creates the associated COFF symbol staging object. +void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, + MCAssembler &Assembler, + const MCAsmLayout &Layout) { + MCSymbol const &Symbol = SymbolData.getSymbol(); + COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&Symbol); + SymbolMap[&Symbol] = coff_symbol; + + if (SymbolData.getFlags() & COFF::SF_WeakExternal) { + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + + if (Symbol.isVariable()) { + const MCSymbolRefExpr *SymRef = + dyn_cast<MCSymbolRefExpr>(Symbol.getVariableValue()); + + if (!SymRef) + report_fatal_error("Weak externals may only alias symbols"); + + coff_symbol->Other = GetOrCreateCOFFSymbol(&SymRef->getSymbol()); + } else { + std::string WeakName = std::string(".weak.") + + Symbol.getName().str() + + ".default"; + COFFSymbol *WeakDefault = createSymbol(WeakName); + WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; + WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL; + WeakDefault->Data.Type = 0; + WeakDefault->Data.Value = 0; + coff_symbol->Other = WeakDefault; + } + + // Setup the Weak External auxiliary symbol. + coff_symbol->Aux.resize(1); + memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); + coff_symbol->Aux[0].AuxType = ATWeakExternal; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; + coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = + COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; + + coff_symbol->MCData = &SymbolData; + } else { + const MCSymbolData &ResSymData = + Assembler.getSymbolData(Symbol.AliasedSymbol()); + + if (Symbol.isVariable()) { + int64_t Addr; + if (Symbol.getVariableValue()->EvaluateAsAbsolute(Addr, Layout)) + coff_symbol->Data.Value = Addr; + } + + coff_symbol->Data.Type = (ResSymData.getFlags() & 0x0000FFFF) >> 0; + coff_symbol->Data.StorageClass = (ResSymData.getFlags() & 0x00FF0000) >> 16; + + // If no storage class was specified in the streamer, define it here. + if (coff_symbol->Data.StorageClass == 0) { + bool external = ResSymData.isExternal() || (ResSymData.Fragment == NULL); + + coff_symbol->Data.StorageClass = + external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; + } + + if (Symbol.isAbsolute() || Symbol.AliasedSymbol().isVariable()) + coff_symbol->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; + else if (ResSymData.Fragment != NULL) + coff_symbol->Section = + SectionMap[&ResSymData.Fragment->getParent()->getSection()]; + + coff_symbol->MCData = &ResSymData; + } +} + +/// making a section real involves assigned it a number and putting +/// name into the string table if needed +void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) { + if (S.Name.size() > COFF::NameSize) { + const unsigned Max6DecimalSize = 999999; + const unsigned Max7DecimalSize = 9999999; + uint64_t StringTableEntry = Strings.insert(S.Name.c_str()); + + if (StringTableEntry <= Max6DecimalSize) { + std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry)); + } else if (StringTableEntry <= Max7DecimalSize) { + // With seven digits, we have to skip the terminating null. Because + // sprintf always appends it, we use a larger temporary buffer. + char buffer[9] = { }; + std::sprintf(buffer, "/%d", unsigned(StringTableEntry)); + std::memcpy(S.Header.Name, buffer, 8); + } else { + report_fatal_error("COFF string table is greater than 9,999,999 bytes."); + } + } else + std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); + + S.Number = Number; + S.Symbol->Data.SectionNumber = S.Number; + S.Symbol->Aux[0].Aux.SectionDefinition.Number = S.Number; +} + +void WinCOFFObjectWriter::MakeSymbolReal(COFFSymbol &S, size_t Index) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + S.set_name_offset(StringTableEntry); + } else + std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); + S.Index = Index; +} + +bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, + MCAssembler &Asm) { + // This doesn't seem to be right. Strings referred to from the .data section + // need symbols so they can be linked to code in the .text section right? + + // return Asm.isSymbolLinkerVisible (&SymbolData); + + // For now, all non-variable symbols are exported, + // the linker will sort the rest out for us. + return SymbolData.isExternal() || !SymbolData.getSymbol().isVariable(); +} + +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) { + WriteLE16(Header.Machine); + WriteLE16(Header.NumberOfSections); + WriteLE32(Header.TimeDateStamp); + WriteLE32(Header.PointerToSymbolTable); + WriteLE32(Header.NumberOfSymbols); + WriteLE16(Header.SizeOfOptionalHeader); + WriteLE16(Header.Characteristics); +} + +void WinCOFFObjectWriter::WriteSymbol(const COFFSymbol *S) { + WriteBytes(StringRef(S->Data.Name, COFF::NameSize)); + WriteLE32(S->Data.Value); + WriteLE16(S->Data.SectionNumber); + WriteLE16(S->Data.Type); + Write8(S->Data.StorageClass); + Write8(S->Data.NumberOfAuxSymbols); + WriteAuxiliarySymbols(S->Aux); +} + +void WinCOFFObjectWriter::WriteAuxiliarySymbols( + const COFFSymbol::AuxiliarySymbols &S) { + for(COFFSymbol::AuxiliarySymbols::const_iterator i = S.begin(), e = S.end(); + i != e; ++i) { + switch(i->AuxType) { + case ATFunctionDefinition: + WriteLE32(i->Aux.FunctionDefinition.TagIndex); + WriteLE32(i->Aux.FunctionDefinition.TotalSize); + WriteLE32(i->Aux.FunctionDefinition.PointerToLinenumber); + WriteLE32(i->Aux.FunctionDefinition.PointerToNextFunction); + WriteZeros(sizeof(i->Aux.FunctionDefinition.unused)); + break; + case ATbfAndefSymbol: + WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused1)); + WriteLE16(i->Aux.bfAndefSymbol.Linenumber); + WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused2)); + WriteLE32(i->Aux.bfAndefSymbol.PointerToNextFunction); + WriteZeros(sizeof(i->Aux.bfAndefSymbol.unused3)); + break; + case ATWeakExternal: + WriteLE32(i->Aux.WeakExternal.TagIndex); + WriteLE32(i->Aux.WeakExternal.Characteristics); + WriteZeros(sizeof(i->Aux.WeakExternal.unused)); + break; + case ATFile: + WriteBytes(StringRef(reinterpret_cast<const char *>(i->Aux.File.FileName), + sizeof(i->Aux.File.FileName))); + break; + case ATSectionDefinition: + WriteLE32(i->Aux.SectionDefinition.Length); + WriteLE16(i->Aux.SectionDefinition.NumberOfRelocations); + WriteLE16(i->Aux.SectionDefinition.NumberOfLinenumbers); + WriteLE32(i->Aux.SectionDefinition.CheckSum); + WriteLE16(i->Aux.SectionDefinition.Number); + Write8(i->Aux.SectionDefinition.Selection); + WriteZeros(sizeof(i->Aux.SectionDefinition.unused)); + break; + } + } +} + +void WinCOFFObjectWriter::WriteSectionHeader(const COFF::section &S) { + WriteBytes(StringRef(S.Name, COFF::NameSize)); + + WriteLE32(S.VirtualSize); + WriteLE32(S.VirtualAddress); + WriteLE32(S.SizeOfRawData); + WriteLE32(S.PointerToRawData); + WriteLE32(S.PointerToRelocations); + WriteLE32(S.PointerToLineNumbers); + WriteLE16(S.NumberOfRelocations); + WriteLE16(S.NumberOfLineNumbers); + WriteLE32(S.Characteristics); +} + +void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { + WriteLE32(R.VirtualAddress); + WriteLE32(R.SymbolTableIndex); + WriteLE16(R.Type); +} + +//////////////////////////////////////////////////////////////////////////////// +// MCObjectWriter interface implementations + +void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // "Define" each section & symbol. This creates section & symbol + // entries in the staging area. + + for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) + DefineSection(*i); + + for (MCAssembler::const_symbol_iterator i = Asm.symbol_begin(), + e = Asm.symbol_end(); + i != e; i++) { + if (ExportSymbol(*i, Asm)) { + DefineSymbol(*i, Asm, Layout); + } + } +} + +void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { + assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); + + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &A = Symbol.AliasedSymbol(); + MCSymbolData &A_SD = Asm.getSymbolData(A); + + MCSectionData const *SectionData = Fragment->getParent(); + + // Mark this symbol as requiring an entry in the symbol table. + assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && + "Section must already have been defined in ExecutePostLayoutBinding!"); + assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && + "Symbol must already have been defined in ExecutePostLayoutBinding!"); + + COFFSection *coff_section = SectionMap[&SectionData->getSection()]; + COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; + const MCSymbolRefExpr *SymA = Target.getSymA(); + const MCSymbolRefExpr *SymB = Target.getSymB(); + const bool CrossSection = SymB && + &SymA->getSymbol().getSection() != &SymB->getSymbol().getSection(); + + if (Target.getSymB()) { + const MCSymbol *B = &Target.getSymB()->getSymbol(); + MCSymbolData &B_SD = Asm.getSymbolData(*B); + + // Offset of the symbol in the section + int64_t a = Layout.getSymbolOffset(&B_SD); + + // Ofeset of the relocation in the section + int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + + FixedValue = b - a; + // In the case where we have SymbA and SymB, we just need to store the delta + // between the two symbols. Update FixedValue to account for the delta, and + // skip recording the relocation. + if (!CrossSection) + return; + } 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 (coff_symbol->MCData->getSymbol().isTemporary() || CrossSection) { + Reloc.Symb = coff_symbol->Section->Symbol; + FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + + coff_symbol->MCData->getOffset(); + } else + Reloc.Symb = coff_symbol; + + ++Reloc.Symb->Relocations; + + Reloc.Data.VirtualAddress += Fixup.getOffset(); + Reloc.Data.Type = TargetObjectWriter->getRelocType(Target, Fixup, + CrossSection); + + // FIXME: Can anyone explain what this does other than adjust for the size + // of the offset? + if (Reloc.Data.Type == COFF::IMAGE_REL_AMD64_REL32 || + Reloc.Data.Type == COFF::IMAGE_REL_I386_REL32) + FixedValue += 4; + + coff_section->Relocations.push_back(Reloc); +} + +void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // Assign symbol and section indexes and offsets. + Header.NumberOfSections = 0; + + DenseMap<COFFSection *, uint16_t> SectionIndices; + for (sections::iterator i = Sections.begin(), + e = Sections.end(); i != e; i++) { + if (Layout.getSectionAddressSize((*i)->MCData) > 0) { + size_t Number = ++Header.NumberOfSections; + SectionIndices[*i] = Number; + MakeSectionReal(**i, Number); + } else { + (*i)->Number = -1; + } + } + + Header.NumberOfSymbols = 0; + + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { + COFFSymbol *coff_symbol = *i; + MCSymbolData const *SymbolData = coff_symbol->MCData; + + // Update section number & offset for symbols that have them. + if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { + assert(coff_symbol->Section != NULL); + + coff_symbol->Data.SectionNumber = coff_symbol->Section->Number; + coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + + SymbolData->Offset; + } + + if (coff_symbol->should_keep()) { + MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); + + // Update auxiliary symbol info. + coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); + Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + } else + coff_symbol->Index = -1; + } + + // Fixup weak external references. + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { + COFFSymbol *coff_symbol = *i; + if (coff_symbol->Other != NULL) { + assert(coff_symbol->Index != -1); + assert(coff_symbol->Aux.size() == 1 && + "Symbol must contain one aux symbol!"); + assert(coff_symbol->Aux[0].AuxType == ATWeakExternal && + "Symbol's aux symbol must be a Weak External!"); + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index; + } + } + + // Fixup associative COMDAT sections. + for (sections::iterator i = Sections.begin(), + e = Sections.end(); i != e; i++) { + if ((*i)->Symbol->Aux[0].Aux.SectionDefinition.Selection != + COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) + continue; + + const MCSectionCOFF &MCSec = static_cast<const MCSectionCOFF &>( + (*i)->MCData->getSection()); + + COFFSection *Assoc = SectionMap.lookup(MCSec.getAssocSection()); + if (!Assoc) { + report_fatal_error(Twine("Missing associated COMDAT section ") + + MCSec.getAssocSection()->getSectionName() + + " for section " + MCSec.getSectionName()); + } + + // Skip this section if the associated section is unused. + if (Assoc->Number == -1) + continue; + + (*i)->Symbol->Aux[0].Aux.SectionDefinition.Number = SectionIndices[Assoc]; + } + + + // Assign file offsets to COFF object file structures. + + unsigned offset = 0; + + offset += COFF::HeaderSize; + offset += COFF::SectionSize * Header.NumberOfSections; + + for (MCAssembler::const_iterator i = Asm.begin(), + e = Asm.end(); + i != e; i++) { + COFFSection *Sec = SectionMap[&i->getSection()]; + + if (Sec->Number == -1) + continue; + + Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(i); + + if (IsPhysicalSection(Sec)) { + Sec->Header.PointerToRawData = offset; + + offset += Sec->Header.SizeOfRawData; + } + + if (Sec->Relocations.size() > 0) { + bool RelocationsOverflow = Sec->Relocations.size() >= 0xffff; + + if (RelocationsOverflow) { + // Signal overflow by setting NumberOfSections 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 (relocations::iterator cr = Sec->Relocations.begin(), + er = Sec->Relocations.end(); + cr != er; ++cr) { + assert((*cr).Symb->Index != -1); + (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; + } + } + + 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; + + Header.TimeDateStamp = sys::TimeValue::now().toEpochTime(); + + // Write it all to disk... + WriteFileHeader(Header); + + { + sections::iterator i, ie; + MCAssembler::const_iterator j, je; + + for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) + if ((*i)->Number != -1) { + if ((*i)->Relocations.size() >= 0xffff) { + (*i)->Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; + } + WriteSectionHeader((*i)->Header); + } + + for (i = Sections.begin(), ie = Sections.end(), + j = Asm.begin(), je = Asm.end(); + (i != ie) && (j != je); ++i, ++j) { + + if ((*i)->Number == -1) + continue; + + if ((*i)->Header.PointerToRawData != 0) { + assert(OS.tell() == (*i)->Header.PointerToRawData && + "Section::PointerToRawData is insane!"); + + Asm.writeSectionData(j, Layout); + } + + if ((*i)->Relocations.size() > 0) { + assert(OS.tell() == (*i)->Header.PointerToRelocations && + "Section::PointerToRelocations is insane!"); + + if ((*i)->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 = (*i)->Relocations.size() + 1; + r.SymbolTableIndex = 0; + r.Type = 0; + WriteRelocation(r); + } + + for (relocations::const_iterator k = (*i)->Relocations.begin(), + ke = (*i)->Relocations.end(); + k != ke; k++) { + WriteRelocation(k->Data); + } + } else + assert((*i)->Header.PointerToRelocations == 0 && + "Section::PointerToRelocations is insane!"); + } + } + + assert(OS.tell() == Header.PointerToSymbolTable && + "Header::PointerToSymbolTable is insane!"); + + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) + if ((*i)->Index != -1) + WriteSymbol(*i); + + OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); +} + +MCWinCOFFObjectTargetWriter::MCWinCOFFObjectTargetWriter(unsigned Machine_) : + Machine(Machine_) { +} + +// Pin the vtable to this file. +void MCWinCOFFObjectTargetWriter::anchor() {} + +//------------------------------------------------------------------------------ +// WinCOFFObjectWriter factory function + +namespace llvm { + MCObjectWriter *createWinCOFFObjectWriter(MCWinCOFFObjectTargetWriter *MOTW, + raw_ostream &OS) { + return new WinCOFFObjectWriter(MOTW, OS); + } +} diff --git a/contrib/llvm/lib/MC/WinCOFFStreamer.cpp b/contrib/llvm/lib/MC/WinCOFFStreamer.cpp new file mode 100644 index 000000000000..5b5aad7a79ea --- /dev/null +++ b/contrib/llvm/lib/MC/WinCOFFStreamer.cpp @@ -0,0 +1,341 @@ +//===-- llvm/MC/WinCOFFStreamer.cpp -----------------------------*- C++ -*-===// +// +// 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 streamer. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "WinCOFFStreamer" + +#include "llvm/MC/MCStreamer.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/MCObjectStreamer.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCWin64EH.h" +#include "llvm/Support/COFF.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; + +namespace { +class WinCOFFStreamer : public MCObjectStreamer { +public: + MCSymbol const *CurSymbol; + + WinCOFFStreamer(MCContext &Context, + MCAsmBackend &MAB, + MCCodeEmitter &CE, + raw_ostream &OS); + + void AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment, bool External); + + // MCStreamer interface + + virtual void InitSections(); + virtual void InitToTextSection(); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitDebugLabel(MCSymbol *Symbol); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); + virtual bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); + virtual void BeginCOFFSymbolDef(MCSymbol const *Symbol); + virtual void EmitCOFFSymbolStorageClass(int StorageClass); + virtual void EmitCOFFSymbolType(int Type); + virtual void EndCOFFSymbolDef(); + virtual void EmitCOFFSecRel32(MCSymbol const *Symbol); + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size,unsigned ByteAlignment); + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment); + virtual void EmitFileDirective(StringRef Filename); + virtual void EmitIdent(StringRef IdentString); + virtual void EmitWin64EHHandlerData(); + virtual void FinishImpl(); + +private: + virtual void EmitInstToData(const MCInst &Inst) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // 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->getContents().append(Code.begin(), Code.end()); + } + + void SetSection(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + SwitchSection(getContext().getCOFFSection(Section, Characteristics, Kind)); + } + + void SetSectionText() { + SetSection(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + + void SetSectionData() { + SetSection(".data", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + + void SetSectionBSS() { + SetSection(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + EmitCodeAlignment(4, 0); + } +}; +} // end anonymous namespace. + +WinCOFFStreamer::WinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB, + MCCodeEmitter &CE, raw_ostream &OS) + : MCObjectStreamer(Context, 0, MAB, OS, &CE), CurSymbol(NULL) {} + +void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment, bool External) { + assert(!Symbol->isInSection() && "Symbol must not already have a section!"); + + std::string SectionName(".bss$linkonce"); + SectionName.append(Symbol->getName().begin(), Symbol->getName().end()); + + MCSymbolData &SymbolData = getAssembler().getOrCreateSymbolData(*Symbol); + + unsigned Characteristics = + COFF::IMAGE_SCN_LNK_COMDAT | + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | + COFF::IMAGE_SCN_MEM_READ | + COFF::IMAGE_SCN_MEM_WRITE; + + int Selection = COFF::IMAGE_COMDAT_SELECT_LARGEST; + + const MCSection *Section = MCStreamer::getContext().getCOFFSection( + SectionName, Characteristics, SectionKind::getBSS(), Symbol->getName(), + Selection); + + MCSectionData &SectionData = getAssembler().getOrCreateSectionData(*Section); + + if (SectionData.getAlignment() < ByteAlignment) + SectionData.setAlignment(ByteAlignment); + + SymbolData.setExternal(External); + + AssignSection(Symbol, Section); + + if (ByteAlignment != 1) + new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, &SectionData); + + SymbolData.setFragment(new MCFillFragment(0, 0, Size, &SectionData)); +} + +// MCStreamer interface + +void WinCOFFStreamer::InitToTextSection() { + SetSectionText(); +} + +void WinCOFFStreamer::InitSections() { + SetSectionText(); + SetSectionData(); + SetSectionBSS(); + SetSectionText(); +} + +void WinCOFFStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + MCObjectStreamer::EmitLabel(Symbol); +} + +void WinCOFFStreamer::EmitDebugLabel(MCSymbol *Symbol) { + EmitLabel(Symbol); +} +void WinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + llvm_unreachable("not implemented"); +} + +void WinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) { + llvm_unreachable("not implemented"); +} + +bool WinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + MCSymbolAttr Attribute) { + assert(Symbol && "Symbol must be non-null!"); + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); + switch (Attribute) { + case MCSA_WeakReference: + case MCSA_Weak: { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.modifyFlags(COFF::SF_WeakExternal, COFF::SF_WeakExternal); + SD.setExternal(true); + } + break; + + case MCSA_Global: + getAssembler().getOrCreateSymbolData(*Symbol).setExternal(true); + break; + + default: + return false; + } + + return true; +} + +void WinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + llvm_unreachable("not implemented"); +} + +void WinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); + assert(CurSymbol == NULL && "EndCOFFSymbolDef must be called between calls " + "to BeginCOFFSymbolDef!"); + CurSymbol = Symbol; +} + +void WinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + assert(CurSymbol != NULL && "BeginCOFFSymbolDef must be called first!"); + assert((StorageClass & ~0xFF) == 0 && "StorageClass must only have data in " + "the first byte!"); + + getAssembler().getOrCreateSymbolData(*CurSymbol).modifyFlags( + StorageClass << COFF::SF_ClassShift, + COFF::SF_ClassMask); +} + +void WinCOFFStreamer::EmitCOFFSymbolType(int Type) { + assert(CurSymbol != NULL && "BeginCOFFSymbolDef must be called first!"); + assert((Type & ~0xFFFF) == 0 && "Type must only have data in the first 2 " + "bytes"); + + getAssembler().getOrCreateSymbolData(*CurSymbol).modifyFlags( + Type << COFF::SF_TypeShift, + COFF::SF_TypeMask); +} + +void WinCOFFStreamer::EndCOFFSymbolDef() { + assert(CurSymbol != NULL && "BeginCOFFSymbolDef must be called first!"); + CurSymbol = NULL; +} + +void WinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) +{ + MCDataFragment *DF = getOrCreateDataFragment(); + + DF->getFixups().push_back( + MCFixup::Create(DF->getContents().size(), + MCSymbolRefExpr::Create (Symbol, getContext ()), + FK_SecRel_4)); + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +void WinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + llvm_unreachable("not implemented"); +} + +void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); + AddCommonSymbol(Symbol, Size, ByteAlignment, true); +} + +void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); + AddCommonSymbol(Symbol, Size, ByteAlignment, false); +} + +void WinCOFFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size,unsigned ByteAlignment) { + llvm_unreachable("not implemented"); +} + +void WinCOFFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("not implemented"); +} + +void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { + // Ignore for now, linkers don't care, and proper debug + // info will be a much large effort. +} + +// TODO: Implement this if you want to emit .comment section in COFF obj files. +void WinCOFFStreamer::EmitIdent(StringRef IdentString) { + llvm_unreachable("unsupported directive"); +} + +void WinCOFFStreamer::EmitWin64EHHandlerData() { + MCStreamer::EmitWin64EHHandlerData(); + + // We have to emit the unwind info now, because this directive + // actually switches to the .xdata section! + MCWin64EHUnwindEmitter::EmitUnwindInfo(*this, getCurrentW64UnwindInfo()); +} + +void WinCOFFStreamer::FinishImpl() { + EmitFrames(NULL, true); + EmitW64Tables(); + MCObjectStreamer::FinishImpl(); +} + +namespace llvm +{ + MCStreamer *createWinCOFFStreamer(MCContext &Context, + MCAsmBackend &MAB, + MCCodeEmitter &CE, + raw_ostream &OS, + bool RelaxAll) { + WinCOFFStreamer *S = new WinCOFFStreamer(Context, MAB, CE, OS); + S->getAssembler().setRelaxAll(RelaxAll); + return S; + } +} |