diff options
Diffstat (limited to 'contrib/llvm/lib/MC')
34 files changed, 5588 insertions, 377 deletions
diff --git a/contrib/llvm/lib/MC/CMakeLists.txt b/contrib/llvm/lib/MC/CMakeLists.txt index fc4f3c6..60a3a3e 100644 --- a/contrib/llvm/lib/MC/CMakeLists.txt +++ b/contrib/llvm/lib/MC/CMakeLists.txt @@ -1,4 +1,5 @@ add_llvm_library(LLVMMC + ELFObjectWriter.cpp MCAsmInfo.cpp MCAsmInfoCOFF.cpp MCAsmInfoDarwin.cpp @@ -7,10 +8,12 @@ add_llvm_library(LLVMMC MCCodeEmitter.cpp MCContext.cpp MCDisassembler.cpp + MCELFStreamer.cpp MCExpr.cpp MCInst.cpp MCInstPrinter.cpp MCLabel.cpp + MCDwarf.cpp MCLoggingStreamer.cpp MCMachOStreamer.cpp MCNullStreamer.cpp diff --git a/contrib/llvm/lib/MC/ELFObjectWriter.cpp b/contrib/llvm/lib/MC/ELFObjectWriter.cpp new file mode 100644 index 0000000..cf35b45 --- /dev/null +++ b/contrib/llvm/lib/MC/ELFObjectWriter.cpp @@ -0,0 +1,973 @@ +//===- 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/ELFObjectWriter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCELFSymbolFlags.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ELF.h" +#include "llvm/Target/TargetAsmBackend.h" + +#include "../Target/X86/X86FixupKinds.h" + +#include <vector> +using namespace llvm; + +namespace { + + class ELFObjectWriterImpl { + static bool isFixupKindX86PCRel(unsigned Kind) { + switch (Kind) { + default: + return false; + case X86::reloc_pcrel_1byte: + case X86::reloc_pcrel_4byte: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + return true; + } + } + + /*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(); + } + }; + + /// @name Relocation Data + /// @{ + + struct ELFRelocationEntry { + // Make these big enough for both 32-bit and 64-bit + uint64_t r_offset; + uint64_t r_info; + uint64_t r_addend; + + // Support lexicographic sorting. + bool operator<(const ELFRelocationEntry &RE) const { + return RE.r_offset < r_offset; + } + }; + + llvm::DenseMap<const MCSectionData*, + std::vector<ELFRelocationEntry> > Relocations; + DenseMap<const MCSection*, uint64_t> SectionStringTableIndex; + + /// @} + /// @name Symbol Table Data + /// @{ + + SmallString<256> StringTable; + std::vector<ELFSymbolData> LocalSymbolData; + std::vector<ELFSymbolData> ExternalSymbolData; + std::vector<ELFSymbolData> UndefinedSymbolData; + + /// @} + + ELFObjectWriter *Writer; + + raw_ostream &OS; + + // This holds the current offset into the object file. + size_t FileOff; + + unsigned Is64Bit : 1; + + bool HasRelocationAddend; + + // This holds the symbol table index of the last local symbol. + unsigned LastLocalSymbolIndex; + // This holds the .strtab section index. + unsigned StringTableIndex; + + unsigned ShstrtabIndex; + + public: + ELFObjectWriterImpl(ELFObjectWriter *_Writer, bool _Is64Bit, + bool _HasRelAddend) + : Writer(_Writer), OS(Writer->getStream()), FileOff(0), + Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend) { + } + + void Write8(uint8_t Value) { Writer->Write8(Value); } + void Write16(uint16_t Value) { Writer->Write16(Value); } + void Write32(uint32_t Value) { Writer->Write32(Value); } + //void Write64(uint64_t Value) { Writer->Write64(Value); } + void WriteZeros(unsigned N) { Writer->WriteZeros(N); } + //void WriteBytes(StringRef Str, unsigned ZeroFillSize = 0) { + // Writer->WriteBytes(Str, ZeroFillSize); + //} + + void WriteWord(uint64_t W) { + if (Is64Bit) + Writer->Write64(W); + else + Writer->Write32(W); + } + + void String8(char *buf, uint8_t Value) { + buf[0] = Value; + } + + 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 String16(char *buf, uint16_t Value) { + if (Writer->isLittleEndian()) + StringLE16(buf, Value); + else + StringBE16(buf, Value); + } + + void String32(char *buf, uint32_t Value) { + if (Writer->isLittleEndian()) + StringLE32(buf, Value); + else + StringBE32(buf, Value); + } + + void String64(char *buf, uint64_t Value) { + if (Writer->isLittleEndian()) + StringLE64(buf, Value); + else + StringBE64(buf, Value); + } + + void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); + + void WriteSymbolEntry(MCDataFragment *F, uint64_t name, uint8_t info, + uint64_t value, uint64_t size, + uint8_t other, uint16_t shndx); + + void WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, + const MCAsmLayout &Layout); + + void WriteSymbolTable(MCDataFragment *F, const MCAssembler &Asm, + const MCAsmLayout &Layout); + + 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); + + /// 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 ComputeSymbolTable(MCAssembler &Asm); + + void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + const MCSectionData &SD); + + void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + WriteRelocation(Asm, Layout, *it); + } + } + + void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout); + + void ExecutePostLayoutBinding(MCAssembler &Asm) { + // Compute symbol table information. + ComputeSymbolTable(Asm); + } + + 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); + + void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + }; + +} + +// Emit the ELF header. +void ELFObjectWriterImpl::WriteHeader(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(Writer->isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + + Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] + Write8(ELF::ELFOSABI_LINUX); // e_ident[EI_OSABI] + Write8(0); // e_ident[EI_ABIVERSION] + + WriteZeros(ELF::EI_NIDENT - ELF::EI_PAD); + + Write16(ELF::ET_REL); // e_type + + // FIXME: Make this configurable + Write16(Is64Bit ? ELF::EM_X86_64 : ELF::EM_386); // 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 + + // FIXME: Make this configurable. + Write32(0); // e_flags = whatever the target wants + + // 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 + Write16(NumberOfSections); + + // e_shstrndx = Section # of '.shstrtab' + Write16(ShstrtabIndex); +} + +void ELFObjectWriterImpl::WriteSymbolEntry(MCDataFragment *F, uint64_t name, + uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint16_t shndx) { + if (Is64Bit) { + char buf[8]; + + String32(buf, name); + F->getContents() += StringRef(buf, 4); // st_name + + String8(buf, info); + F->getContents() += StringRef(buf, 1); // st_info + + String8(buf, other); + F->getContents() += StringRef(buf, 1); // st_other + + String16(buf, shndx); + F->getContents() += StringRef(buf, 2); // st_shndx + + String64(buf, value); + F->getContents() += StringRef(buf, 8); // st_value + + String64(buf, size); + F->getContents() += StringRef(buf, 8); // st_size + } else { + char buf[4]; + + String32(buf, name); + F->getContents() += StringRef(buf, 4); // st_name + + String32(buf, value); + F->getContents() += StringRef(buf, 4); // st_value + + String32(buf, size); + F->getContents() += StringRef(buf, 4); // st_size + + String8(buf, info); + F->getContents() += StringRef(buf, 1); // st_info + + String8(buf, other); + F->getContents() += StringRef(buf, 1); // st_other + + String16(buf, shndx); + F->getContents() += StringRef(buf, 2); // st_shndx + } +} + +void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &Data = *MSD.SymbolData; + uint8_t Info = (Data.getFlags() & 0xff); + uint8_t Other = ((Data.getFlags() & 0xf00) >> ELF_STV_Shift); + uint64_t Value = 0; + uint64_t Size = 0; + const MCExpr *ESize; + + if (Data.isCommon() && Data.isExternal()) + Value = Data.getCommonAlignment(); + + if (!Data.isCommon()) + if (MCFragment *FF = Data.getFragment()) + Value = Layout.getSymbolAddress(&Data) - + Layout.getSectionAddress(FF->getParent()); + + ESize = Data.getSize(); + if (Data.getSize()) { + MCValue Res; + if (ESize->getKind() == MCExpr::Binary) { + const MCBinaryExpr *BE = static_cast<const MCBinaryExpr *>(ESize); + + if (BE->EvaluateAsRelocatable(Res, &Layout)) { + MCSymbolData &A = + Layout.getAssembler().getSymbolData(Res.getSymA()->getSymbol()); + MCSymbolData &B = + Layout.getAssembler().getSymbolData(Res.getSymB()->getSymbol()); + + Size = Layout.getSymbolAddress(&A) - Layout.getSymbolAddress(&B); + } + } else if (ESize->getKind() == MCExpr::Constant) { + Size = static_cast<const MCConstantExpr *>(ESize)->getValue(); + } else { + assert(0 && "Unsupported size expression"); + } + } + + // Write out the symbol table entry + WriteSymbolEntry(F, MSD.StringIndex, Info, Value, + Size, Other, MSD.SectionIndex); +} + +void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, + const MCAssembler &Asm, + const MCAsmLayout &Layout) { + // 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. + unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + F->getContents().append(EntrySize, '\x00'); + + // Write the symbol table entries. + LastLocalSymbolIndex = LocalSymbolData.size() + 1; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = LocalSymbolData[i]; + WriteSymbol(F, MSD, Layout); + } + + // Write out a symbol table entry for each section. + // leaving out the just added .symtab which is at + // the very end + unsigned Index = 1; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it, ++Index) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + // Leave out relocations so we don't have indexes within + // the relocations messed up + if (Section.getType() == ELF::SHT_RELA || Section.getType() == ELF::SHT_REL) + continue; + if (Index == Asm.size()) + continue; + WriteSymbolEntry(F, 0, ELF::STT_SECTION, 0, 0, ELF::STV_DEFAULT, Index); + 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) && + "External symbol requires STB_GLOBAL flag"); + WriteSymbol(F, MSD, Layout); + if (Data.getFlags() & ELF_STB_Local) + LastLocalSymbolIndex++; + } + + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) { + ELFSymbolData &MSD = UndefinedSymbolData[i]; + MCSymbolData &Data = *MSD.SymbolData; + Data.setFlags(Data.getFlags() | ELF_STB_Global); + WriteSymbol(F, MSD, Layout); + if (Data.getFlags() & ELF_STB_Local) + LastLocalSymbolIndex++; + } +} + +// FIXME: this is currently X86/X86_64 only +void ELFObjectWriterImpl::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { + int64_t Addend = 0; + unsigned Index = 0; + int64_t Value = Target.getConstant(); + + if (!Target.isAbsolute()) { + const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); + MCSymbolData &SD = Asm.getSymbolData(*Symbol); + const MCSymbolData *Base = Asm.getAtom(Layout, &SD); + MCFragment *F = SD.getFragment(); + + if (Base) { + if (F && (!Symbol->isInSection() || SD.isCommon()) && !SD.isExternal()) { + Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; + Value += Layout.getSymbolAddress(&SD); + } else + Index = getSymbolIndexInSymbolTable(Asm, Symbol); + if (Base != &SD) + Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); + Addend = Value; + // Compensate for the addend on i386. + if (Is64Bit) + Value = 0; + } else { + if (F) { + // Index of the section in .symtab against this symbol + // is being relocated + 2 (empty section + abs. symbols). + Index = F->getParent()->getOrdinal() + LocalSymbolData.size() + 1; + + MCSectionData *FSD = F->getParent(); + // Offset of the symbol in the section + Addend = Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); + } else { + FixedValue = Value; + return; + } + } + } + + FixedValue = Value; + + // determine the type of the relocation + bool IsPCRel = isFixupKindX86PCRel(Fixup.getKind()); + unsigned Type; + if (Is64Bit) { + if (IsPCRel) { + Type = ELF::R_X86_64_PC32; + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_8: Type = ELF::R_X86_64_64; break; + case X86::reloc_pcrel_4byte: + case FK_Data_4: + // check that the offset fits within a signed long + if (isInt<32>(Target.getConstant())) + Type = ELF::R_X86_64_32S; + else + Type = ELF::R_X86_64_32; + break; + case FK_Data_2: Type = ELF::R_X86_64_16; break; + case X86::reloc_pcrel_1byte: + case FK_Data_1: Type = ELF::R_X86_64_8; break; + } + } + } else { + if (IsPCRel) { + Type = ELF::R_386_PC32; + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case X86::reloc_pcrel_4byte: + case FK_Data_4: Type = ELF::R_386_32; break; + case FK_Data_2: Type = ELF::R_386_16; break; + case X86::reloc_pcrel_1byte: + case FK_Data_1: Type = ELF::R_386_8; break; + } + } + } + + ELFRelocationEntry ERE; + + if (Is64Bit) { + struct ELF::Elf64_Rela ERE64; + ERE64.setSymbolAndType(Index, Type); + ERE.r_info = ERE64.r_info; + } else { + struct ELF::Elf32_Rela ERE32; + ERE32.setSymbolAndType(Index, Type); + ERE.r_info = ERE32.r_info; + } + + ERE.r_offset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + + if (HasRelocationAddend) + ERE.r_addend = Addend; + else + ERE.r_addend = 0; // Silence compiler warning. + + Relocations[Fragment->getParent()].push_back(ERE); +} + +uint64_t +ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S) { + MCSymbolData &SD = Asm.getSymbolData(*S); + + // Local symbol. + if (!SD.isExternal() && !S->isUndefined()) + return SD.getIndex() + /* empty symbol */ 1; + + // External or undefined symbol. + return SD.getIndex() + Asm.size() + /* empty symbol */ 1; +} + +void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { + // 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; + + // Index 0 is always the empty string. + StringMap<uint64_t> StringIndexMap; + StringTable += '\x00'; + + // 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(Symbol)) + continue; + + if (it->isExternal() || Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + ELFSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + if (Symbol.isAbsolute()) { + MSD.SectionIndex = ELF::SHN_ABS; + LocalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + LocalSymbolData.push_back(MSD); + } + } + + // Now add non-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(Symbol)) + continue; + + if (!it->isExternal() && !Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + ELFSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + if (Symbol.isUndefined()) { + MSD.SectionIndex = ELF::SHN_UNDEF; + // XXX: for some reason we dont Emit* this + it->setFlags(it->getFlags() | ELF_STB_Global); + UndefinedSymbolData.push_back(MSD); + } else if (Symbol.isAbsolute()) { + MSD.SectionIndex = ELF::SHN_ABS; + ExternalSymbolData.push_back(MSD); + } else if (it->isCommon()) { + MSD.SectionIndex = ELF::SHN_COMMON; + ExternalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + 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. + 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++); +} + +void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + const MCSectionData &SD) { + if (!Relocations[&SD].empty()) { + MCContext &Ctx = Asm.getContext(); + const MCSection *RelaSection; + 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); + + RelaSection = Ctx.getELFSection(RelaSectionName, HasRelocationAddend ? + ELF::SHT_RELA : ELF::SHT_REL, 0, + SectionKind::getReadOnly(), + false, EntrySize); + + MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); + RelaSD.setAlignment(1); + + MCDataFragment *F = new MCDataFragment(&RelaSD); + + WriteRelocationsFragment(Asm, F, &SD); + + Asm.AddSectionToTheEnd(RelaSD, Layout); + } +} + +void ELFObjectWriterImpl::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 ELFObjectWriterImpl::WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD) { + std::vector<ELFRelocationEntry> &Relocs = Relocations[SD]; + // sort by the r_offset just like gnu as does + array_pod_sort(Relocs.begin(), Relocs.end()); + + for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { + ELFRelocationEntry entry = Relocs[e - i - 1]; + + unsigned WordSize = Is64Bit ? 8 : 4; + F->getContents() += StringRef((const char *)&entry.r_offset, WordSize); + F->getContents() += StringRef((const char *)&entry.r_info, WordSize); + + if (HasRelocationAddend) + F->getContents() += StringRef((const char *)&entry.r_addend, WordSize); + } +} + +void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm, + MCAsmLayout &Layout) { + MCContext &Ctx = Asm.getContext(); + MCDataFragment *F; + + WriteRelocations(Asm, Layout); + + const MCSection *SymtabSection; + unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + + SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + false, EntrySize); + + MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); + + SymtabSD.setAlignment(Is64Bit ? 8 : 4); + + F = new MCDataFragment(&SymtabSD); + + // Symbol table + WriteSymbolTable(F, Asm, Layout); + Asm.AddSectionToTheEnd(SymtabSD, Layout); + + const MCSection *StrtabSection; + StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly(), false); + + MCSectionData &StrtabSD = Asm.getOrCreateSectionData(*StrtabSection); + StrtabSD.setAlignment(1); + + // FIXME: This isn't right. If the sections get rearranged this will + // be wrong. We need a proper lookup. + StringTableIndex = Asm.size(); + + F = new MCDataFragment(&StrtabSD); + F->getContents().append(StringTable.begin(), StringTable.end()); + Asm.AddSectionToTheEnd(StrtabSD, Layout); + + const MCSection *ShstrtabSection; + ShstrtabSection = Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly(), false); + + MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); + ShstrtabSD.setAlignment(1); + + F = new MCDataFragment(&ShstrtabSD); + + // FIXME: This isn't right. If the sections get rearranged this will + // be wrong. We need a proper lookup. + ShstrtabIndex = Asm.size(); + + // 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() += '\x00'; + + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + + // Remember the index into the string table so we can write it + // into the sh_name field of the section header table. + SectionStringTableIndex[&it->getSection()] = Index; + + Index += Section.getSectionName().size() + 1; + F->getContents() += Section.getSectionName(); + F->getContents() += '\x00'; + } + + Asm.AddSectionToTheEnd(ShstrtabSD, Layout); +} + +void ELFObjectWriterImpl::WriteObject(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + CreateMetadataSections(const_cast<MCAssembler&>(Asm), + const_cast<MCAsmLayout&>(Layout)); + + // Add 1 for the null section. + unsigned NumSections = Asm.size() + 1; + + uint64_t SectionDataSize = 0; + + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionData &SD = *it; + + // Get the size of the section in the output file (including padding). + uint64_t Size = Layout.getSectionFileSize(&SD); + SectionDataSize += Size; + } + + // Write out the ELF header ... + WriteHeader(SectionDataSize, NumSections); + FileOff = Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr); + + // ... then all of the sections ... + DenseMap<const MCSection*, uint64_t> SectionOffsetMap; + + DenseMap<const MCSection*, uint8_t> SectionIndexMap; + + unsigned Index = 1; + for (MCAssembler::const_iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + // Remember the offset into the file for this section. + SectionOffsetMap[&it->getSection()] = FileOff; + + SectionIndexMap[&it->getSection()] = Index++; + + const MCSectionData &SD = *it; + FileOff += Layout.getSectionFileSize(&SD); + + Asm.WriteSectionData(it, Layout, Writer); + } + + // ... and then the section header table. + // Should we align the section header table? + // + // Null section first. + WriteSecHdrEntry(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + + 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()); + + uint64_t sh_link = 0; + uint64_t sh_info = 0; + + switch(Section.getType()) { + case ELF::SHT_DYNAMIC: + sh_link = SectionStringTableIndex[&it->getSection()]; + sh_info = 0; + break; + + case ELF::SHT_REL: + case ELF::SHT_RELA: { + const MCSection *SymtabSection; + const MCSection *InfoSection; + + SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + false); + sh_link = SectionIndexMap[SymtabSection]; + + // Remove ".rel" and ".rela" prefixes. + unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; + StringRef SectionName = Section.getSectionName().substr(SecNameLen); + + InfoSection = Asm.getContext().getELFSection(SectionName, + ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly(), + false); + sh_info = SectionIndexMap[InfoSection]; + break; + } + + case ELF::SHT_SYMTAB: + case ELF::SHT_DYNSYM: + sh_link = StringTableIndex; + sh_info = LastLocalSymbolIndex; + break; + + case ELF::SHT_PROGBITS: + case ELF::SHT_STRTAB: + case ELF::SHT_NOBITS: + case ELF::SHT_NULL: + // Nothing to do. + break; + + case ELF::SHT_HASH: + case ELF::SHT_GROUP: + case ELF::SHT_SYMTAB_SHNDX: + default: + assert(0 && "FIXME: sh_type value not supported!"); + break; + } + + WriteSecHdrEntry(SectionStringTableIndex[&it->getSection()], + Section.getType(), Section.getFlags(), + Layout.getSectionAddress(&SD), + SectionOffsetMap.lookup(&SD.getSection()), + Layout.getSectionSize(&SD), sh_link, + sh_info, SD.getAlignment(), + Section.getEntrySize()); + } +} + +ELFObjectWriter::ELFObjectWriter(raw_ostream &OS, + bool Is64Bit, + bool IsLittleEndian, + bool HasRelocationAddend) + : MCObjectWriter(OS, IsLittleEndian) +{ + Impl = new ELFObjectWriterImpl(this, Is64Bit, HasRelocationAddend); +} + +ELFObjectWriter::~ELFObjectWriter() { + delete (ELFObjectWriterImpl*) Impl; +} + +void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { + ((ELFObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); +} + +void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + ((ELFObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, + Target, FixedValue); +} + +void ELFObjectWriter::WriteObject(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + ((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); +} diff --git a/contrib/llvm/lib/MC/MCAsmInfo.cpp b/contrib/llvm/lib/MC/MCAsmInfo.cpp index a275be2..670b2e9 100644 --- a/contrib/llvm/lib/MC/MCAsmInfo.cpp +++ b/contrib/llvm/lib/MC/MCAsmInfo.cpp @@ -68,7 +68,9 @@ MCAsmInfo::MCAsmInfo() { ExceptionsType = ExceptionHandling::None; DwarfRequiresFrameSection = true; DwarfUsesInlineInfoSection = false; + DwarfUsesAbsoluteLabelForStmtList = true; DwarfSectionOffsetDirective = 0; + DwarfUsesLabelOffsetForRanges = true; HasMicrosoftFastStdCallMangling = false; AsmTransCBE = 0; diff --git a/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp b/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp index 0bd3b2d..e0e261a 100644 --- a/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp +++ b/contrib/llvm/lib/MC/MCAsmInfoDarwin.cpp @@ -44,5 +44,8 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { HasDotTypeDotSizeDirective = false; HasNoDeadStrip = true; + + DwarfUsesAbsoluteLabelForStmtList = false; + DwarfUsesLabelOffsetForRanges = false; } diff --git a/contrib/llvm/lib/MC/MCAsmStreamer.cpp b/contrib/llvm/lib/MC/MCAsmStreamer.cpp index e272b60..1cc8fb0 100644 --- a/contrib/llvm/lib/MC/MCAsmStreamer.cpp +++ b/contrib/llvm/lib/MC/MCAsmStreamer.cpp @@ -31,7 +31,7 @@ class MCAsmStreamer : public MCStreamer { formatted_raw_ostream &OS; const MCAsmInfo &MAI; OwningPtr<MCInstPrinter> InstPrinter; - MCCodeEmitter *Emitter; + OwningPtr<MCCodeEmitter> Emitter; SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; @@ -217,6 +217,7 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { void MCAsmStreamer::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); if (Section != CurSection) { + PrevSection = CurSection; CurSection = Section; Section->PrintSwitchToSection(MAI, OS); } diff --git a/contrib/llvm/lib/MC/MCAssembler.cpp b/contrib/llvm/lib/MC/MCAssembler.cpp index 7d84554..f0e1d7f 100644 --- a/contrib/llvm/lib/MC/MCAssembler.cpp +++ b/contrib/llvm/lib/MC/MCAssembler.cpp @@ -178,8 +178,12 @@ uint64_t MCAsmLayout::getSectionSize(const MCSectionData *SD) const { MCFragment::MCFragment() : Kind(FragmentType(~0)) { } +MCFragment::~MCFragment() { +} + MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent) - : Kind(_Kind), Parent(_Parent), Atom(0), EffectiveSize(~UINT64_C(0)) + : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)), + EffectiveSize(~UINT64_C(0)) { if (Parent) Parent->getFragmentList().push_back(this); @@ -207,7 +211,8 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, uint64_t _Offset, MCAssembler *A) : Symbol(&_Symbol), Fragment(_Fragment), Offset(_Offset), IsExternal(false), IsPrivateExtern(false), - CommonSize(0), CommonAlign(0), Flags(0), Index(0) + CommonSize(0), SymbolSize(0), CommonAlign(0), + Flags(0), Index(0) { if (A) A->getSymbolList().push_back(this); @@ -623,8 +628,23 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, switch (it->getKind()) { default: assert(0 && "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. + 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: - assert(!cast<MCAlignFragment>(it)->getValueSize() && + // Check that we aren't trying to write a non-zero value into a virtual + // section. + assert((!cast<MCAlignFragment>(it)->getValueSize() || + !cast<MCAlignFragment>(it)->getValue()) && "Invalid align in virtual section!"); break; case MCFragment::FT_Fill: @@ -647,7 +667,41 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD)); } -void MCAssembler::Finish() { +void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) { + // Create dummy fragments and assign section ordinals. + unsigned SectionIndex = 0; + for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) + SectionIndex++; + + SD.setOrdinal(SectionIndex); + + // Assign layout order indices to sections and fragments. + unsigned FragmentIndex = 0; + unsigned i = 0; + for (unsigned e = Layout.getSectionOrder().size(); i != e; ++i) { + MCSectionData *SD = Layout.getSectionOrder()[i]; + + for (MCSectionData::iterator it2 = SD->begin(), + ie2 = SD->end(); it2 != ie2; ++it2) + FragmentIndex++; + } + + SD.setLayoutOrder(i); + for (MCSectionData::iterator it2 = SD.begin(), + ie2 = SD.end(); it2 != ie2; ++it2) { + it2->setLayoutOrder(FragmentIndex++); + } + Layout.getSectionOrder().push_back(&SD); + + Layout.LayoutSection(&SD); + + // Layout until everything fits. + while (LayoutOnce(Layout)) + continue; + +} + +void MCAssembler::Finish(MCObjectWriter *Writer) { DEBUG_WITH_TYPE("mc-dump", { llvm::errs() << "assembler backend - pre-layout\n--\n"; dump(); }); @@ -717,9 +771,15 @@ void MCAssembler::Finish() { dump(); }); uint64_t StartOffset = OS.tell(); - llvm::OwningPtr<MCObjectWriter> Writer(getBackend().createObjectWriter(OS)); - if (!Writer) - report_fatal_error("unable to create object writer!"); + + llvm::OwningPtr<MCObjectWriter> OwnWriter(0); + if (Writer == 0) { + //no custom Writer_ : create the default one life-managed by OwningPtr + OwnWriter.reset(getBackend().createObjectWriter(OS)); + Writer = OwnWriter.get(); + if (!Writer) + report_fatal_error("unable to create object writer!"); + } // Allow the object writer a chance to perform post-layout binding (for // example, to set the index fields in the symbol data). diff --git a/contrib/llvm/lib/MC/MCContext.cpp b/contrib/llvm/lib/MC/MCContext.cpp index 1137064..e5586a0 100644 --- a/contrib/llvm/lib/MC/MCContext.cpp +++ b/contrib/llvm/lib/MC/MCContext.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCSectionCOFF.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCLabel.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" using namespace llvm; @@ -23,7 +24,8 @@ typedef StringMap<const MCSectionELF*> ELFUniqueMapTy; typedef StringMap<const MCSectionCOFF*> COFFUniqueMapTy; -MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0) { +MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), + CurrentDwarfLoc(0,0,0,0,0) { MachOUniquingMap = 0; ELFUniquingMap = 0; COFFUniquingMap = 0; @@ -31,6 +33,8 @@ MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0) { SecureLogFile = getenv("AS_SECURE_LOG_FILE"); SecureLog = 0; SecureLogUsed = false; + + DwarfLocSeen = false; } MCContext::~MCContext() { @@ -147,7 +151,7 @@ getMachOSection(StringRef Segment, StringRef Section, const MCSection *MCContext:: getELFSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind, bool IsExplicit) { + SectionKind Kind, bool IsExplicit, unsigned EntrySize) { if (ELFUniquingMap == 0) ELFUniquingMap = new ELFUniqueMapTy(); ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; @@ -157,7 +161,7 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags, if (Entry.getValue()) return Entry.getValue(); MCSectionELF *Result = new (*this) MCSectionELF(Entry.getKey(), Type, Flags, - Kind, IsExplicit); + Kind, IsExplicit, EntrySize); Entry.setValue(Result); return Result; } @@ -181,3 +185,81 @@ const MCSection *MCContext::getCOFFSection(StringRef Section, Entry.setValue(Result); return Result; } + +//===----------------------------------------------------------------------===// +// 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 FileName, unsigned FileNumber) { + // 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. + + // 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]; + + // Separate the directory part from the basename of the FileName. + std::pair<StringRef, StringRef> Slash = FileName.rsplit('/'); + + // Find or make a entry in the MCDwarfDirs vector for this Directory. + StringRef Name; + unsigned DirIndex; + // Capture directory name. + if (Slash.second.empty()) { + Name = Slash.first; + DirIndex = 0; // For FileNames with no directories a DirIndex of 0 is used. + } else { + StringRef Directory = Slash.first; + Name = Slash.second; + for (DirIndex = 0; DirIndex < MCDwarfDirs.size(); 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(Name.size())); + memcpy(Buf, Name.data(), Name.size()); + File = new (*this) MCDwarfFile(StringRef(Buf, Name.size()), DirIndex); + + // return the allocated FileNumber. + return FileNumber; +} + +/// ValidateDwarfFileNumber - takes a dwarf file number and returns true if it +/// currently is assigned and false otherwise. +bool MCContext::ValidateDwarfFileNumber(unsigned FileNumber) { + if(FileNumber == 0 || FileNumber >= MCDwarfFiles.size()) + return false; + + MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; + if (ExistingFile) + return true; + else + return false; +} diff --git a/contrib/llvm/lib/MC/MCDisassembler/CMakeLists.txt b/contrib/llvm/lib/MC/MCDisassembler/CMakeLists.txt new file mode 100644 index 0000000..5fa7b70 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/CMakeLists.txt @@ -0,0 +1,7 @@ + +add_llvm_library(LLVMMCDisassembler + EDDisassembler.cpp + EDOperand.cpp + EDInst.cpp + EDToken.cpp + ) diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp new file mode 100644 index 0000000..697b3d9 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.cpp @@ -0,0 +1,402 @@ +//===-EDDisassembler.cpp - LLVM Enhanced Disassembler ---------------------===// +// +// 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 Enhanced Disassembly library's disassembler class. +// The disassembler is responsible for vending individual instructions according +// to a given architecture and disassembly syntax. +// +//===----------------------------------------------------------------------===// + +#include "EDDisassembler.h" +#include "EDInst.h" +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCParser/AsmLexer.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryObject.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Target/TargetAsmLexer.h" +#include "llvm/Target/TargetAsmParser.h" +#include "llvm/Target/TargetRegistry.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetRegisterInfo.h" +#include "llvm/Target/TargetSelect.h" +using namespace llvm; + +bool EDDisassembler::sInitialized = false; +EDDisassembler::DisassemblerMap_t EDDisassembler::sDisassemblers; + +struct TripleMap { + Triple::ArchType Arch; + const char *String; +}; + +static struct TripleMap triplemap[] = { + { Triple::x86, "i386-unknown-unknown" }, + { Triple::x86_64, "x86_64-unknown-unknown" }, + { Triple::arm, "arm-unknown-unknown" }, + { Triple::thumb, "thumb-unknown-unknown" }, + { Triple::InvalidArch, NULL, } +}; + +/// infoFromArch - Returns the TripleMap corresponding to a given architecture, +/// or NULL if there is an error +/// +/// @arg arch - The Triple::ArchType for the desired architecture +static const char *tripleFromArch(Triple::ArchType arch) { + unsigned int infoIndex; + + for (infoIndex = 0; triplemap[infoIndex].String != NULL; ++infoIndex) { + if (arch == triplemap[infoIndex].Arch) + return triplemap[infoIndex].String; + } + + return NULL; +} + +/// getLLVMSyntaxVariant - gets the constant to use to get an assembly printer +/// for the desired assembly syntax, suitable for passing to +/// Target::createMCInstPrinter() +/// +/// @arg arch - The target architecture +/// @arg syntax - The assembly syntax in sd form +static int getLLVMSyntaxVariant(Triple::ArchType arch, + EDDisassembler::AssemblySyntax syntax) { + switch (syntax) { + default: + return -1; + // Mappings below from X86AsmPrinter.cpp + case EDDisassembler::kEDAssemblySyntaxX86ATT: + if (arch == Triple::x86 || arch == Triple::x86_64) + return 0; + else + return -1; + case EDDisassembler::kEDAssemblySyntaxX86Intel: + if (arch == Triple::x86 || arch == Triple::x86_64) + return 1; + else + return -1; + case EDDisassembler::kEDAssemblySyntaxARMUAL: + if (arch == Triple::arm || arch == Triple::thumb) + return 0; + else + return -1; + } +} + +void EDDisassembler::initialize() { + if (sInitialized) + return; + + sInitialized = true; + + InitializeAllTargetInfos(); + InitializeAllTargets(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); + InitializeAllDisassemblers(); +} + +#undef BRINGUP_TARGET + +EDDisassembler *EDDisassembler::getDisassembler(Triple::ArchType arch, + AssemblySyntax syntax) { + CPUKey key; + key.Arch = arch; + key.Syntax = syntax; + + EDDisassembler::DisassemblerMap_t::iterator i = sDisassemblers.find(key); + + if (i != sDisassemblers.end()) { + return i->second; + } else { + EDDisassembler* sdd = new EDDisassembler(key); + if (!sdd->valid()) { + delete sdd; + return NULL; + } + + sDisassemblers[key] = sdd; + + return sdd; + } + + return NULL; +} + +EDDisassembler *EDDisassembler::getDisassembler(StringRef str, + AssemblySyntax syntax) { + return getDisassembler(Triple(str).getArch(), syntax); +} + +EDDisassembler::EDDisassembler(CPUKey &key) : + Valid(false), + HasSemantics(false), + ErrorStream(nulls()), + Key(key) { + const char *triple = tripleFromArch(key.Arch); + + if (!triple) + return; + + LLVMSyntaxVariant = getLLVMSyntaxVariant(key.Arch, key.Syntax); + + if (LLVMSyntaxVariant < 0) + return; + + std::string tripleString(triple); + std::string errorString; + + Tgt = TargetRegistry::lookupTarget(tripleString, + errorString); + + if (!Tgt) + return; + + std::string featureString; + + TargetMachine.reset(Tgt->createTargetMachine(tripleString, + featureString)); + + const TargetRegisterInfo *registerInfo = TargetMachine->getRegisterInfo(); + + if (!registerInfo) + return; + + initMaps(*registerInfo); + + AsmInfo.reset(Tgt->createAsmInfo(tripleString)); + + if (!AsmInfo) + return; + + Disassembler.reset(Tgt->createMCDisassembler()); + + if (!Disassembler) + return; + + InstInfos = Disassembler->getEDInfo(); + + InstString.reset(new std::string); + InstStream.reset(new raw_string_ostream(*InstString)); + InstPrinter.reset(Tgt->createMCInstPrinter(LLVMSyntaxVariant, *AsmInfo)); + + if (!InstPrinter) + return; + + GenericAsmLexer.reset(new AsmLexer(*AsmInfo)); + SpecificAsmLexer.reset(Tgt->createAsmLexer(*AsmInfo)); + SpecificAsmLexer->InstallLexer(*GenericAsmLexer); + + initMaps(*TargetMachine->getRegisterInfo()); + + Valid = true; +} + +EDDisassembler::~EDDisassembler() { + if (!valid()) + return; +} + +namespace { + /// EDMemoryObject - a subclass of MemoryObject that allows use of a callback + /// as provided by the sd interface. See MemoryObject. + class EDMemoryObject : public llvm::MemoryObject { + private: + EDByteReaderCallback Callback; + void *Arg; + public: + EDMemoryObject(EDByteReaderCallback callback, + void *arg) : Callback(callback), Arg(arg) { } + ~EDMemoryObject() { } + uint64_t getBase() const { return 0x0; } + uint64_t getExtent() const { return (uint64_t)-1; } + int readByte(uint64_t address, uint8_t *ptr) const { + if (!Callback) + return -1; + + if (Callback(ptr, address, Arg)) + return -1; + + return 0; + } + }; +} + +EDInst *EDDisassembler::createInst(EDByteReaderCallback byteReader, + uint64_t address, + void *arg) { + EDMemoryObject memoryObject(byteReader, arg); + + MCInst* inst = new MCInst; + uint64_t byteSize; + + if (!Disassembler->getInstruction(*inst, + byteSize, + memoryObject, + address, + ErrorStream)) { + delete inst; + return NULL; + } else { + const llvm::EDInstInfo *thisInstInfo; + + thisInstInfo = &InstInfos[inst->getOpcode()]; + + EDInst* sdInst = new EDInst(inst, byteSize, *this, thisInstInfo); + return sdInst; + } +} + +void EDDisassembler::initMaps(const TargetRegisterInfo ®isterInfo) { + unsigned numRegisters = registerInfo.getNumRegs(); + unsigned registerIndex; + + for (registerIndex = 0; registerIndex < numRegisters; ++registerIndex) { + const char* registerName = registerInfo.get(registerIndex).Name; + + RegVec.push_back(registerName); + RegRMap[registerName] = registerIndex; + } + + switch (Key.Arch) { + default: + break; + case Triple::x86: + case Triple::x86_64: + stackPointers.insert(registerIDWithName("SP")); + stackPointers.insert(registerIDWithName("ESP")); + stackPointers.insert(registerIDWithName("RSP")); + + programCounters.insert(registerIDWithName("IP")); + programCounters.insert(registerIDWithName("EIP")); + programCounters.insert(registerIDWithName("RIP")); + break; + case Triple::arm: + case Triple::thumb: + stackPointers.insert(registerIDWithName("SP")); + + programCounters.insert(registerIDWithName("PC")); + break; + } +} + +const char *EDDisassembler::nameWithRegisterID(unsigned registerID) const { + if (registerID >= RegVec.size()) + return NULL; + else + return RegVec[registerID].c_str(); +} + +unsigned EDDisassembler::registerIDWithName(const char *name) const { + regrmap_t::const_iterator iter = RegRMap.find(std::string(name)); + if (iter == RegRMap.end()) + return 0; + else + return (*iter).second; +} + +bool EDDisassembler::registerIsStackPointer(unsigned registerID) { + return (stackPointers.find(registerID) != stackPointers.end()); +} + +bool EDDisassembler::registerIsProgramCounter(unsigned registerID) { + return (programCounters.find(registerID) != programCounters.end()); +} + +int EDDisassembler::printInst(std::string &str, MCInst &inst) { + PrinterMutex.acquire(); + + InstPrinter->printInst(&inst, *InstStream); + InstStream->flush(); + str = *InstString; + InstString->clear(); + + PrinterMutex.release(); + + return 0; +} + +int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, + SmallVectorImpl<AsmToken> &tokens, + const std::string &str) { + int ret = 0; + + switch (Key.Arch) { + default: + return -1; + case Triple::x86: + case Triple::x86_64: + case Triple::arm: + case Triple::thumb: + break; + } + + const char *cStr = str.c_str(); + MemoryBuffer *buf = MemoryBuffer::getMemBuffer(cStr, cStr + strlen(cStr)); + + StringRef instName; + SMLoc instLoc; + + SourceMgr sourceMgr; + sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over + MCContext context(*AsmInfo); + OwningPtr<MCStreamer> streamer(createNullStreamer(context)); + OwningPtr<MCAsmParser> genericParser(createMCAsmParser(*Tgt, sourceMgr, + context, *streamer, + *AsmInfo)); + OwningPtr<TargetAsmParser> TargetParser(Tgt->createAsmParser(*genericParser, + *TargetMachine)); + + AsmToken OpcodeToken = genericParser->Lex(); + AsmToken NextToken = genericParser->Lex(); // consume next token, because specificParser expects us to + + if (OpcodeToken.is(AsmToken::Identifier)) { + instName = OpcodeToken.getString(); + instLoc = OpcodeToken.getLoc(); + + if (NextToken.isNot(AsmToken::Eof) && + TargetParser->ParseInstruction(instName, instLoc, operands)) + ret = -1; + } else { + ret = -1; + } + + ParserMutex.acquire(); + + if (!ret) { + GenericAsmLexer->setBuffer(buf); + + while (SpecificAsmLexer->Lex(), + SpecificAsmLexer->isNot(AsmToken::Eof) && + SpecificAsmLexer->isNot(AsmToken::EndOfStatement)) { + if (SpecificAsmLexer->is(AsmToken::Error)) { + ret = -1; + break; + } + tokens.push_back(SpecificAsmLexer->getTok()); + } + } + + ParserMutex.release(); + + return ret; +} + +int EDDisassembler::llvmSyntaxVariant() const { + return LLVMSyntaxVariant; +} diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h new file mode 100644 index 0000000..e2f850b --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDDisassembler.h @@ -0,0 +1,271 @@ +//===-- EDDisassembler.h - LLVM Enhanced 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 Enhanced Disassembly library's +// disassembler class. The disassembler is responsible for vending individual +// instructions according to a given architecture and disassembly syntax. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDDISASSEMBLER_H +#define LLVM_EDDISASSEMBLER_H + +#include "EDInfo.h" + +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/System/Mutex.h" + +#include <map> +#include <set> +#include <vector> + +namespace llvm { +class AsmLexer; +class AsmToken; +class MCContext; +class MCAsmInfo; +class MCAsmLexer; +class AsmParser; +class TargetAsmLexer; +class TargetAsmParser; +class MCDisassembler; +class MCInstPrinter; +class MCInst; +class MCParsedAsmOperand; +class MCStreamer; +template <typename T> class SmallVectorImpl; +class SourceMgr; +class Target; +class TargetMachine; +class TargetRegisterInfo; + +struct EDInstInfo; +struct EDInst; +struct EDOperand; +struct EDToken; + +typedef int (*EDByteReaderCallback)(uint8_t *byte, uint64_t address, void *arg); + +/// EDDisassembler - Encapsulates a disassembler for a single architecture and +/// disassembly syntax. Also manages the static disassembler registry. +struct EDDisassembler { + typedef enum { + /*! @constant kEDAssemblySyntaxX86Intel Intel syntax for i386 and x86_64. */ + kEDAssemblySyntaxX86Intel = 0, + /*! @constant kEDAssemblySyntaxX86ATT AT&T syntax for i386 and x86_64. */ + kEDAssemblySyntaxX86ATT = 1, + kEDAssemblySyntaxARMUAL = 2 + } AssemblySyntax; + + + //////////////////// + // Static members // + //////////////////// + + /// CPUKey - Encapsulates the descriptor of an architecture/disassembly-syntax + /// pair + struct CPUKey { + /// The architecture type + llvm::Triple::ArchType Arch; + + /// The assembly syntax + AssemblySyntax Syntax; + + /// operator== - Equality operator + bool operator==(const CPUKey &key) const { + return (Arch == key.Arch && + Syntax == key.Syntax); + } + + /// operator< - Less-than operator + bool operator<(const CPUKey &key) const { + if(Arch > key.Arch) + return false; + if(Syntax >= key.Syntax) + return false; + return true; + } + }; + + typedef std::map<CPUKey, EDDisassembler*> DisassemblerMap_t; + + /// True if the disassembler registry has been initialized; false if not + static bool sInitialized; + /// A map from disassembler specifications to disassemblers. Populated + /// lazily. + static DisassemblerMap_t sDisassemblers; + + /// getDisassembler - Returns the specified disassemble, or NULL on failure + /// + /// @arg arch - The desired architecture + /// @arg syntax - The desired disassembly syntax + static EDDisassembler *getDisassembler(llvm::Triple::ArchType arch, + AssemblySyntax syntax); + + /// getDisassembler - Returns the disassembler for a given combination of + /// CPU type, CPU subtype, and assembly syntax, or NULL on failure + /// + /// @arg str - The string representation of the architecture triple, e.g., + /// "x86_64-apple-darwin" + /// @arg syntax - The disassembly syntax for the required disassembler + static EDDisassembler *getDisassembler(llvm::StringRef str, + AssemblySyntax syntax); + + /// initialize - Initializes the disassembler registry and the LLVM backend + static void initialize(); + + //////////////////////// + // Per-object members // + //////////////////////// + + /// True only if the object has been successfully initialized + bool Valid; + /// True if the disassembler can provide semantic information + bool HasSemantics; + + /// The stream to write errors to + llvm::raw_ostream &ErrorStream; + + /// The architecture/syntax pair for the current architecture + CPUKey Key; + /// The LLVM target corresponding to the disassembler + const llvm::Target *Tgt; + /// The target machine instance. + llvm::OwningPtr<llvm::TargetMachine> TargetMachine; + /// The assembly information for the target architecture + llvm::OwningPtr<const llvm::MCAsmInfo> AsmInfo; + /// The disassembler for the target architecture + llvm::OwningPtr<const llvm::MCDisassembler> Disassembler; + /// The output string for the instruction printer; must be guarded with + /// PrinterMutex + llvm::OwningPtr<std::string> InstString; + /// The output stream for the disassembler; must be guarded with + /// PrinterMutex + llvm::OwningPtr<llvm::raw_string_ostream> InstStream; + /// The instruction printer for the target architecture; must be guarded with + /// PrinterMutex when printing + llvm::OwningPtr<llvm::MCInstPrinter> InstPrinter; + /// The mutex that guards the instruction printer's printing functions, which + /// use a shared stream + llvm::sys::Mutex PrinterMutex; + /// The array of instruction information provided by the TableGen backend for + /// the target architecture + const llvm::EDInstInfo *InstInfos; + /// The target-specific lexer for use in tokenizing strings, in + /// target-independent and target-specific portions + llvm::OwningPtr<llvm::AsmLexer> GenericAsmLexer; + llvm::OwningPtr<llvm::TargetAsmLexer> SpecificAsmLexer; + /// The guard for the above + llvm::sys::Mutex ParserMutex; + /// The LLVM number used for the target disassembly syntax variant + int LLVMSyntaxVariant; + + typedef std::vector<std::string> regvec_t; + typedef std::map<std::string, unsigned> regrmap_t; + + /// A vector of registers for quick mapping from LLVM register IDs to names + regvec_t RegVec; + /// A map of registers for quick mapping from register names to LLVM IDs + regrmap_t RegRMap; + + /// A set of register IDs for aliases of the stack pointer for the current + /// architecture + std::set<unsigned> stackPointers; + /// A set of register IDs for aliases of the program counter for the current + /// architecture + std::set<unsigned> programCounters; + + /// Constructor - initializes a disassembler with all the necessary objects, + /// which come pre-allocated from the registry accessor function + /// + /// @arg key - the architecture and disassembly syntax for the + /// disassembler + EDDisassembler(CPUKey& key); + + /// valid - reports whether there was a failure in the constructor. + bool valid() { + return Valid; + } + + /// hasSemantics - reports whether the disassembler can provide operands and + /// tokens. + bool hasSemantics() { + return HasSemantics; + } + + ~EDDisassembler(); + + /// createInst - creates and returns an instruction given a callback and + /// memory address, or NULL on failure + /// + /// @arg byteReader - A callback function that provides machine code bytes + /// @arg address - The address of the first byte of the instruction, + /// suitable for passing to byteReader + /// @arg arg - An opaque argument for byteReader + EDInst *createInst(EDByteReaderCallback byteReader, + uint64_t address, + void *arg); + + /// initMaps - initializes regVec and regRMap using the provided register + /// info + /// + /// @arg registerInfo - the register information to use as a source + void initMaps(const llvm::TargetRegisterInfo ®isterInfo); + /// nameWithRegisterID - Returns the name (owned by the EDDisassembler) of a + /// register for a given register ID, or NULL on failure + /// + /// @arg registerID - the ID of the register to be queried + const char *nameWithRegisterID(unsigned registerID) const; + /// registerIDWithName - Returns the ID of a register for a given register + /// name, or (unsigned)-1 on failure + /// + /// @arg name - The name of the register + unsigned registerIDWithName(const char *name) const; + + /// registerIsStackPointer - reports whether a register ID is an alias for the + /// stack pointer register + /// + /// @arg registerID - The LLVM register ID + bool registerIsStackPointer(unsigned registerID); + /// registerIsStackPointer - reports whether a register ID is an alias for the + /// stack pointer register + /// + /// @arg registerID - The LLVM register ID + bool registerIsProgramCounter(unsigned registerID); + + /// printInst - prints an MCInst to a string, returning 0 on success, or -1 + /// otherwise + /// + /// @arg str - A reference to a string which is filled in with the string + /// representation of the instruction + /// @arg inst - A reference to the MCInst to be printed + int printInst(std::string& str, + llvm::MCInst& inst); + + /// parseInst - extracts operands and tokens from a string for use in + /// tokenizing the string. Returns 0 on success, or -1 otherwise. + /// + /// @arg operands - A reference to a vector that will be filled in with the + /// parsed operands + /// @arg tokens - A reference to a vector that will be filled in with the + /// tokens + /// @arg str - The string representation of the instruction + int parseInst(llvm::SmallVectorImpl<llvm::MCParsedAsmOperand*> &operands, + llvm::SmallVectorImpl<llvm::AsmToken> &tokens, + const std::string &str); + + /// llvmSyntaxVariant - returns the LLVM syntax variant for this disassembler + int llvmSyntaxVariant() const; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h b/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h new file mode 100644 index 0000000..627c066 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDInfo.h @@ -0,0 +1,73 @@ +//===-- EDInfo.h - LLVM Enhanced Disassembler -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDINFO_H +#define LLVM_EDINFO_H + +enum { + EDIS_MAX_OPERANDS = 13, + EDIS_MAX_SYNTAXES = 2 +}; + +enum OperandTypes { + kOperandTypeNone, + kOperandTypeImmediate, + kOperandTypeRegister, + kOperandTypeX86Memory, + kOperandTypeX86EffectiveAddress, + kOperandTypeX86PCRelative, + kOperandTypeARMBranchTarget, + kOperandTypeARMSoReg, + kOperandTypeARMSoImm, + kOperandTypeARMSoImm2Part, + kOperandTypeARMPredicate, + kOperandTypeARMAddrMode2, + kOperandTypeARMAddrMode2Offset, + kOperandTypeARMAddrMode3, + kOperandTypeARMAddrMode3Offset, + kOperandTypeARMAddrMode4, + kOperandTypeARMAddrMode5, + kOperandTypeARMAddrMode6, + kOperandTypeARMAddrMode6Offset, + kOperandTypeARMAddrModePC, + kOperandTypeARMRegisterList, + kOperandTypeARMTBAddrMode, + kOperandTypeThumbITMask, + kOperandTypeThumbAddrModeS1, + kOperandTypeThumbAddrModeS2, + kOperandTypeThumbAddrModeS4, + kOperandTypeThumbAddrModeRR, + kOperandTypeThumbAddrModeSP, + kOperandTypeThumb2SoReg, + kOperandTypeThumb2SoImm, + kOperandTypeThumb2AddrModeImm8, + kOperandTypeThumb2AddrModeImm8Offset, + kOperandTypeThumb2AddrModeImm12, + kOperandTypeThumb2AddrModeSoReg, + kOperandTypeThumb2AddrModeImm8s4, + kOperandTypeThumb2AddrModeImm8s4Offset +}; + +enum OperandFlags { + kOperandFlagSource = 0x1, + kOperandFlagTarget = 0x2 +}; + +enum InstructionTypes { + kInstructionTypeNone, + kInstructionTypeMove, + kInstructionTypeBranch, + kInstructionTypePush, + kInstructionTypePop, + kInstructionTypeCall, + kInstructionTypeReturn +}; + + +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDInst.cpp b/contrib/llvm/lib/MC/MCDisassembler/EDInst.cpp new file mode 100644 index 0000000..e22408f --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDInst.cpp @@ -0,0 +1,207 @@ +//===-EDInst.cpp - LLVM Enhanced Disassembler -----------------------------===// +// +// 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 Enhanced Disassembly library's instruction class. +// The instruction is responsible for vending the string representation, +// individual tokens, and operands for a single instruction. +// +//===----------------------------------------------------------------------===// + +#include "EDInst.h" +#include "EDDisassembler.h" +#include "EDOperand.h" +#include "EDToken.h" + +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCInst.h" + +using namespace llvm; + +EDInst::EDInst(llvm::MCInst *inst, + uint64_t byteSize, + EDDisassembler &disassembler, + const llvm::EDInstInfo *info) : + Disassembler(disassembler), + Inst(inst), + ThisInstInfo(info), + ByteSize(byteSize), + BranchTarget(-1), + MoveSource(-1), + MoveTarget(-1) { + OperandOrder = ThisInstInfo->operandOrders[Disassembler.llvmSyntaxVariant()]; +} + +EDInst::~EDInst() { + unsigned int index; + unsigned int numOperands = Operands.size(); + + for (index = 0; index < numOperands; ++index) + delete Operands[index]; + + unsigned int numTokens = Tokens.size(); + + for (index = 0; index < numTokens; ++index) + delete Tokens[index]; + + delete Inst; +} + +uint64_t EDInst::byteSize() { + return ByteSize; +} + +int EDInst::stringify() { + if (StringifyResult.valid()) + return StringifyResult.result(); + + if (Disassembler.printInst(String, *Inst)) + return StringifyResult.setResult(-1); + + return StringifyResult.setResult(0); +} + +int EDInst::getString(const char*& str) { + if (stringify()) + return -1; + + str = String.c_str(); + + return 0; +} + +unsigned EDInst::instID() { + return Inst->getOpcode(); +} + +bool EDInst::isBranch() { + if (ThisInstInfo) + return + ThisInstInfo->instructionType == kInstructionTypeBranch || + ThisInstInfo->instructionType == kInstructionTypeCall; + else + return false; +} + +bool EDInst::isMove() { + if (ThisInstInfo) + return ThisInstInfo->instructionType == kInstructionTypeMove; + else + return false; +} + +int EDInst::parseOperands() { + if (ParseResult.valid()) + return ParseResult.result(); + + if (!ThisInstInfo) + return ParseResult.setResult(-1); + + unsigned int opIndex; + unsigned int mcOpIndex = 0; + + for (opIndex = 0; opIndex < ThisInstInfo->numOperands; ++opIndex) { + if (isBranch() && + (ThisInstInfo->operandFlags[opIndex] & kOperandFlagTarget)) { + BranchTarget = opIndex; + } + else if (isMove()) { + if (ThisInstInfo->operandFlags[opIndex] & kOperandFlagSource) + MoveSource = opIndex; + else if (ThisInstInfo->operandFlags[opIndex] & kOperandFlagTarget) + MoveTarget = opIndex; + } + + EDOperand *operand = new EDOperand(Disassembler, *this, opIndex, mcOpIndex); + + Operands.push_back(operand); + } + + return ParseResult.setResult(0); +} + +int EDInst::branchTargetID() { + if (parseOperands()) + return -1; + return BranchTarget; +} + +int EDInst::moveSourceID() { + if (parseOperands()) + return -1; + return MoveSource; +} + +int EDInst::moveTargetID() { + if (parseOperands()) + return -1; + return MoveTarget; +} + +int EDInst::numOperands() { + if (parseOperands()) + return -1; + return Operands.size(); +} + +int EDInst::getOperand(EDOperand *&operand, unsigned int index) { + if (parseOperands()) + return -1; + + if (index >= Operands.size()) + return -1; + + operand = Operands[index]; + return 0; +} + +int EDInst::tokenize() { + if (TokenizeResult.valid()) + return TokenizeResult.result(); + + if (stringify()) + return TokenizeResult.setResult(-1); + + return TokenizeResult.setResult(EDToken::tokenize(Tokens, + String, + OperandOrder, + Disassembler)); + +} + +int EDInst::numTokens() { + if (tokenize()) + return -1; + return Tokens.size(); +} + +int EDInst::getToken(EDToken *&token, unsigned int index) { + if (tokenize()) + return -1; + token = Tokens[index]; + return 0; +} + +#ifdef __BLOCKS__ +int EDInst::visitTokens(EDTokenVisitor_t visitor) { + if (tokenize()) + return -1; + + tokvec_t::iterator iter; + + for (iter = Tokens.begin(); iter != Tokens.end(); ++iter) { + int ret = visitor(*iter); + if (ret == 1) + return 0; + if (ret != 0) + return -1; + } + + return 0; +} +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDInst.h b/contrib/llvm/lib/MC/MCDisassembler/EDInst.h new file mode 100644 index 0000000..39d264f --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDInst.h @@ -0,0 +1,182 @@ +//===-- EDInst.h - LLVM Enhanced 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 Enhanced Disassembly library's +// instruction class. The instruction is responsible for vending the string +// representation, individual tokens and operands for a single instruction. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDINST_H +#define LLVM_EDINST_H + +#include "llvm/System/DataTypes.h" +#include "llvm/ADT/SmallVector.h" +#include <string> +#include <vector> + +namespace llvm { + class MCInst; + struct EDInstInfo; + struct EDToken; + struct EDDisassembler; + struct EDOperand; + +#ifdef __BLOCKS__ + typedef int (^EDTokenVisitor_t)(EDToken *token); +#endif + +/// CachedResult - Encapsulates the result of a function along with the validity +/// of that result, so that slow functions don't need to run twice +struct CachedResult { + /// True if the result has been obtained by executing the function + bool Valid; + /// The result last obtained from the function + int Result; + + /// Constructor - Initializes an invalid result + CachedResult() : Valid(false) { } + /// valid - Returns true if the result has been obtained by executing the + /// function and false otherwise + bool valid() { return Valid; } + /// result - Returns the result of the function or an undefined value if + /// valid() is false + int result() { return Result; } + /// setResult - Sets the result of the function and declares it valid + /// returning the result (so that setResult() can be called from inside a + /// return statement) + /// @arg result - The result of the function + int setResult(int result) { Result = result; Valid = true; return result; } +}; + +/// EDInst - Encapsulates a single instruction, which can be queried for its +/// string representation, as well as its operands and tokens +struct EDInst { + /// The parent disassembler + EDDisassembler &Disassembler; + /// The containing MCInst + llvm::MCInst *Inst; + /// The instruction information provided by TableGen for this instruction + const llvm::EDInstInfo *ThisInstInfo; + /// The number of bytes for the machine code representation of the instruction + uint64_t ByteSize; + + /// The result of the stringify() function + CachedResult StringifyResult; + /// The string representation of the instruction + std::string String; + /// The order in which operands from the InstInfo's operand information appear + /// in String + const char* OperandOrder; + + /// The result of the parseOperands() function + CachedResult ParseResult; + typedef llvm::SmallVector<EDOperand*, 5> opvec_t; + /// The instruction's operands + opvec_t Operands; + /// The operand corresponding to the target, if the instruction is a branch + int BranchTarget; + /// The operand corresponding to the source, if the instruction is a move + int MoveSource; + /// The operand corresponding to the target, if the instruction is a move + int MoveTarget; + + /// The result of the tokenize() function + CachedResult TokenizeResult; + typedef std::vector<EDToken*> tokvec_t; + /// The instruction's tokens + tokvec_t Tokens; + + /// Constructor - initializes an instruction given the output of the LLVM + /// C++ disassembler + /// + /// @arg inst - The MCInst, which will now be owned by this object + /// @arg byteSize - The size of the consumed instruction, in bytes + /// @arg disassembler - The parent disassembler + /// @arg instInfo - The instruction information produced by the table + /// generator for this instruction + EDInst(llvm::MCInst *inst, + uint64_t byteSize, + EDDisassembler &disassembler, + const llvm::EDInstInfo *instInfo); + ~EDInst(); + + /// byteSize - returns the number of bytes consumed by the machine code + /// representation of the instruction + uint64_t byteSize(); + /// instID - returns the LLVM instruction ID of the instruction + unsigned instID(); + + /// stringify - populates the String and AsmString members of the instruction, + /// returning 0 on success or -1 otherwise + int stringify(); + /// getString - retrieves a pointer to the string representation of the + /// instructinon, returning 0 on success or -1 otherwise + /// + /// @arg str - A reference to a pointer that, on success, is set to point to + /// the string representation of the instruction; this string is still owned + /// by the instruction and will be deleted when it is + int getString(const char *&str); + + /// isBranch - Returns true if the instruction is a branch + bool isBranch(); + /// isMove - Returns true if the instruction is a move + bool isMove(); + + /// parseOperands - populates the Operands member of the instruction, + /// returning 0 on success or -1 otherwise + int parseOperands(); + /// branchTargetID - returns the ID (suitable for use with getOperand()) of + /// the target operand if the instruction is a branch, or -1 otherwise + int branchTargetID(); + /// moveSourceID - returns the ID of the source operand if the instruction + /// is a move, or -1 otherwise + int moveSourceID(); + /// moveTargetID - returns the ID of the target operand if the instruction + /// is a move, or -1 otherwise + int moveTargetID(); + + /// numOperands - returns the number of operands available to retrieve, or -1 + /// on error + int numOperands(); + /// getOperand - retrieves an operand from the instruction's operand list by + /// index, returning 0 on success or -1 on error + /// + /// @arg operand - A reference whose target is pointed at the operand on + /// success, although the operand is still owned by the EDInst + /// @arg index - The index of the operand in the instruction + int getOperand(EDOperand *&operand, unsigned int index); + + /// tokenize - populates the Tokens member of the instruction, returning 0 on + /// success or -1 otherwise + int tokenize(); + /// numTokens - returns the number of tokens in the instruction, or -1 on + /// error + int numTokens(); + /// getToken - retrieves a token from the instruction's token list by index, + /// returning 0 on success or -1 on error + /// + /// @arg token - A reference whose target is pointed at the token on success, + /// although the token is still owned by the EDInst + /// @arg index - The index of the token in the instrcutino + int getToken(EDToken *&token, unsigned int index); + +#ifdef __BLOCKS__ + /// visitTokens - Visits each token in turn and applies a block to it, + /// returning 0 if all blocks are visited and/or the block signals + /// termination by returning 1; returns -1 on error + /// + /// @arg visitor - The visitor block to apply to all tokens. + int visitTokens(EDTokenVisitor_t visitor); +#endif +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp b/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp new file mode 100644 index 0000000..2aed123 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDOperand.cpp @@ -0,0 +1,282 @@ +//===-- EDOperand.cpp - LLVM Enhanced Disassembler ------------------------===// +// +// 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 Enhanced Disassembly library's operand class. The +// operand is responsible for allowing evaluation given a particular register +// context. +// +//===----------------------------------------------------------------------===// + +#include "EDOperand.h" +#include "EDDisassembler.h" +#include "EDInst.h" +#include "llvm/MC/EDInstInfo.h" +#include "llvm/MC/MCInst.h" +using namespace llvm; + +EDOperand::EDOperand(const EDDisassembler &disassembler, + const EDInst &inst, + unsigned int opIndex, + unsigned int &mcOpIndex) : + Disassembler(disassembler), + Inst(inst), + OpIndex(opIndex), + MCOpIndex(mcOpIndex) { + unsigned int numMCOperands = 0; + + if (Disassembler.Key.Arch == Triple::x86 || + Disassembler.Key.Arch == Triple::x86_64) { + uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; + + switch (operandType) { + default: + break; + case kOperandTypeImmediate: + numMCOperands = 1; + break; + case kOperandTypeRegister: + numMCOperands = 1; + break; + case kOperandTypeX86Memory: + numMCOperands = 5; + break; + case kOperandTypeX86EffectiveAddress: + numMCOperands = 4; + break; + case kOperandTypeX86PCRelative: + numMCOperands = 1; + break; + } + } + else if (Disassembler.Key.Arch == Triple::arm || + Disassembler.Key.Arch == Triple::thumb) { + uint8_t operandType = inst.ThisInstInfo->operandTypes[opIndex]; + + switch (operandType) { + default: + case kOperandTypeARMRegisterList: + break; + case kOperandTypeImmediate: + case kOperandTypeRegister: + case kOperandTypeARMBranchTarget: + case kOperandTypeARMSoImm: + case kOperandTypeThumb2SoImm: + case kOperandTypeARMSoImm2Part: + case kOperandTypeARMPredicate: + case kOperandTypeThumbITMask: + case kOperandTypeThumb2AddrModeImm8Offset: + case kOperandTypeARMTBAddrMode: + case kOperandTypeThumb2AddrModeImm8s4Offset: + numMCOperands = 1; + break; + case kOperandTypeThumb2SoReg: + case kOperandTypeARMAddrMode2Offset: + case kOperandTypeARMAddrMode3Offset: + case kOperandTypeARMAddrMode4: + case kOperandTypeARMAddrMode5: + case kOperandTypeARMAddrModePC: + case kOperandTypeThumb2AddrModeImm8: + case kOperandTypeThumb2AddrModeImm12: + case kOperandTypeThumb2AddrModeImm8s4: + case kOperandTypeThumbAddrModeRR: + case kOperandTypeThumbAddrModeSP: + numMCOperands = 2; + break; + case kOperandTypeARMSoReg: + case kOperandTypeARMAddrMode2: + case kOperandTypeARMAddrMode3: + case kOperandTypeThumb2AddrModeSoReg: + case kOperandTypeThumbAddrModeS1: + case kOperandTypeThumbAddrModeS2: + case kOperandTypeThumbAddrModeS4: + case kOperandTypeARMAddrMode6Offset: + numMCOperands = 3; + break; + case kOperandTypeARMAddrMode6: + numMCOperands = 4; + break; + } + } + + mcOpIndex += numMCOperands; +} + +EDOperand::~EDOperand() { +} + +int EDOperand::evaluate(uint64_t &result, + EDRegisterReaderCallback callback, + void *arg) { + uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex]; + + switch (Disassembler.Key.Arch) { + default: + return -1; + case Triple::x86: + case Triple::x86_64: + switch (operandType) { + default: + return -1; + case kOperandTypeImmediate: + result = Inst.Inst->getOperand(MCOpIndex).getImm(); + return 0; + case kOperandTypeRegister: + { + unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); + return callback(&result, reg, arg); + } + case kOperandTypeX86PCRelative: + { + int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); + + uint64_t ripVal; + + // TODO fix how we do this + + if (callback(&ripVal, Disassembler.registerIDWithName("RIP"), arg)) + return -1; + + result = ripVal + displacement; + return 0; + } + case kOperandTypeX86Memory: + case kOperandTypeX86EffectiveAddress: + { + unsigned baseReg = Inst.Inst->getOperand(MCOpIndex).getReg(); + uint64_t scaleAmount = Inst.Inst->getOperand(MCOpIndex+1).getImm(); + unsigned indexReg = Inst.Inst->getOperand(MCOpIndex+2).getReg(); + int64_t displacement = Inst.Inst->getOperand(MCOpIndex+3).getImm(); + //unsigned segmentReg = Inst.Inst->getOperand(MCOpIndex+4).getReg(); + + uint64_t addr = 0; + + if (baseReg) { + uint64_t baseVal; + if (callback(&baseVal, baseReg, arg)) + return -1; + addr += baseVal; + } + + if (indexReg) { + uint64_t indexVal; + if (callback(&indexVal, indexReg, arg)) + return -1; + addr += (scaleAmount * indexVal); + } + + addr += displacement; + + result = addr; + return 0; + } + } + break; + case Triple::arm: + case Triple::thumb: + switch (operandType) { + default: + return -1; + case kOperandTypeImmediate: + result = Inst.Inst->getOperand(MCOpIndex).getImm(); + return 0; + case kOperandTypeRegister: + { + unsigned reg = Inst.Inst->getOperand(MCOpIndex).getReg(); + return callback(&result, reg, arg); + } + case kOperandTypeARMBranchTarget: + { + int64_t displacement = Inst.Inst->getOperand(MCOpIndex).getImm(); + + uint64_t pcVal; + + if (callback(&pcVal, Disassembler.registerIDWithName("PC"), arg)) + return -1; + + result = pcVal + displacement; + return 0; + } + } + } + + return -1; +} + +int EDOperand::isRegister() { + return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeRegister); +} + +unsigned EDOperand::regVal() { + return Inst.Inst->getOperand(MCOpIndex).getReg(); +} + +int EDOperand::isImmediate() { + return(Inst.ThisInstInfo->operandFlags[OpIndex] == kOperandTypeImmediate); +} + +uint64_t EDOperand::immediateVal() { + return Inst.Inst->getOperand(MCOpIndex).getImm(); +} + +int EDOperand::isMemory() { + uint8_t operandType = Inst.ThisInstInfo->operandTypes[OpIndex]; + + switch (operandType) { + default: + return 0; + case kOperandTypeX86Memory: + case kOperandTypeX86PCRelative: + case kOperandTypeX86EffectiveAddress: + case kOperandTypeARMSoReg: + case kOperandTypeARMSoImm: + case kOperandTypeARMAddrMode2: + case kOperandTypeARMAddrMode2Offset: + case kOperandTypeARMAddrMode3: + case kOperandTypeARMAddrMode3Offset: + case kOperandTypeARMAddrMode4: + case kOperandTypeARMAddrMode5: + case kOperandTypeARMAddrMode6: + case kOperandTypeARMAddrModePC: + case kOperandTypeARMBranchTarget: + case kOperandTypeThumbAddrModeS1: + case kOperandTypeThumbAddrModeS2: + case kOperandTypeThumbAddrModeS4: + case kOperandTypeThumbAddrModeRR: + case kOperandTypeThumbAddrModeSP: + case kOperandTypeThumb2SoImm: + case kOperandTypeThumb2AddrModeImm8: + case kOperandTypeThumb2AddrModeImm8Offset: + case kOperandTypeThumb2AddrModeImm12: + case kOperandTypeThumb2AddrModeSoReg: + case kOperandTypeThumb2AddrModeImm8s4: + return 1; + } +} + +#ifdef __BLOCKS__ +struct RegisterReaderWrapper { + EDOperand::EDRegisterBlock_t regBlock; +}; + +int readerWrapperCallback(uint64_t *value, + unsigned regID, + void *arg) { + struct RegisterReaderWrapper *wrapper = (struct RegisterReaderWrapper *)arg; + return wrapper->regBlock(value, regID); +} + +int EDOperand::evaluate(uint64_t &result, + EDRegisterBlock_t regBlock) { + struct RegisterReaderWrapper wrapper; + wrapper.regBlock = regBlock; + return evaluate(result, + readerWrapperCallback, + (void*)&wrapper); +} +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDOperand.h b/contrib/llvm/lib/MC/MCDisassembler/EDOperand.h new file mode 100644 index 0000000..6e69522 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDOperand.h @@ -0,0 +1,91 @@ +//===-EDOperand.h - LLVM Enhanced 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 Enhanced Disassembly library's +// operand class. The operand is responsible for allowing evaluation given a +// particular register context. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDOPERAND_H +#define LLVM_EDOPERAND_H + +#include "llvm/System/DataTypes.h" + +namespace llvm { + +struct EDDisassembler; +struct EDInst; + +typedef int (*EDRegisterReaderCallback)(uint64_t *value, unsigned regID, + void* arg); + + +/// EDOperand - Encapsulates a single operand, which can be evaluated by the +/// client +struct EDOperand { + /// The parent disassembler + const EDDisassembler &Disassembler; + /// The parent instruction + const EDInst &Inst; + + /// The index of the operand in the EDInst + unsigned int OpIndex; + /// The index of the first component of the operand in the MCInst + unsigned int MCOpIndex; + + /// Constructor - Initializes an EDOperand + /// + /// @arg disassembler - The disassembler responsible for the operand + /// @arg inst - The instruction containing this operand + /// @arg opIndex - The index of the operand in inst + /// @arg mcOpIndex - The index of the operand in the original MCInst + EDOperand(const EDDisassembler &disassembler, + const EDInst &inst, + unsigned int opIndex, + unsigned int &mcOpIndex); + ~EDOperand(); + + /// evaluate - Returns the numeric value of an operand to the extent possible, + /// returning 0 on success or -1 if there was some problem (such as a + /// register not being readable) + /// + /// @arg result - A reference whose target is filled in with the value of + /// the operand (the address if it is a memory operand) + /// @arg callback - A function to call to obtain register values + /// @arg arg - An opaque argument to pass to callback + int evaluate(uint64_t &result, + EDRegisterReaderCallback callback, + void *arg); + + /// isRegister - Returns 1 if the operand is a register or 0 otherwise + int isRegister(); + /// regVal - Returns the register value. + unsigned regVal(); + + /// isImmediate - Returns 1 if the operand is an immediate or 0 otherwise + int isImmediate(); + /// immediateVal - Returns the immediate value. + uint64_t immediateVal(); + + /// isMemory - Returns 1 if the operand is a memory location or 0 otherwise + int isMemory(); + +#ifdef __BLOCKS__ + typedef int (^EDRegisterBlock_t)(uint64_t *value, unsigned regID); + + /// evaluate - Like evaluate for a callback, but uses a block instead + int evaluate(uint64_t &result, + EDRegisterBlock_t regBlock); +#endif +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDToken.cpp b/contrib/llvm/lib/MC/MCDisassembler/EDToken.cpp new file mode 100644 index 0000000..400e164 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDToken.cpp @@ -0,0 +1,206 @@ +//===-- EDToken.cpp - LLVM Enhanced Disassembler --------------------------===// +// +// 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 Enhanced Disassembler library's token class. The +// token is responsible for vending information about the token, such as its +// type and logical value. +// +//===----------------------------------------------------------------------===// + +#include "EDToken.h" +#include "EDDisassembler.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/ADT/SmallVector.h" +using namespace llvm; + +EDToken::EDToken(StringRef str, + enum tokenType type, + uint64_t localType, + EDDisassembler &disassembler) : + Disassembler(disassembler), + Str(str), + Type(type), + LocalType(localType), + OperandID(-1) { +} + +EDToken::~EDToken() { +} + +void EDToken::makeLiteral(bool sign, uint64_t absoluteValue) { + Type = kTokenLiteral; + LiteralSign = sign; + LiteralAbsoluteValue = absoluteValue; +} + +void EDToken::makeRegister(unsigned registerID) { + Type = kTokenRegister; + RegisterID = registerID; +} + +void EDToken::setOperandID(int operandID) { + OperandID = operandID; +} + +enum EDToken::tokenType EDToken::type() const { + return Type; +} + +uint64_t EDToken::localType() const { + return LocalType; +} + +StringRef EDToken::string() const { + return Str; +} + +int EDToken::operandID() const { + return OperandID; +} + +int EDToken::literalSign() const { + if (Type != kTokenLiteral) + return -1; + return (LiteralSign ? 1 : 0); +} + +int EDToken::literalAbsoluteValue(uint64_t &value) const { + if (Type != kTokenLiteral) + return -1; + value = LiteralAbsoluteValue; + return 0; +} + +int EDToken::registerID(unsigned ®isterID) const { + if (Type != kTokenRegister) + return -1; + registerID = RegisterID; + return 0; +} + +int EDToken::tokenize(std::vector<EDToken*> &tokens, + std::string &str, + const char *operandOrder, + EDDisassembler &disassembler) { + SmallVector<MCParsedAsmOperand*, 5> parsedOperands; + SmallVector<AsmToken, 10> asmTokens; + + if (disassembler.parseInst(parsedOperands, asmTokens, str)) + return -1; + + SmallVectorImpl<MCParsedAsmOperand*>::iterator operandIterator; + unsigned int operandIndex; + SmallVectorImpl<AsmToken>::iterator tokenIterator; + + operandIterator = parsedOperands.begin(); + operandIndex = 0; + + bool readOpcode = false; + + const char *wsPointer = asmTokens.begin()->getLoc().getPointer(); + + for (tokenIterator = asmTokens.begin(); + tokenIterator != asmTokens.end(); + ++tokenIterator) { + SMLoc tokenLoc = tokenIterator->getLoc(); + + const char *tokenPointer = tokenLoc.getPointer(); + + if (tokenPointer > wsPointer) { + unsigned long wsLength = tokenPointer - wsPointer; + + EDToken *whitespaceToken = new EDToken(StringRef(wsPointer, wsLength), + EDToken::kTokenWhitespace, + 0, + disassembler); + + tokens.push_back(whitespaceToken); + } + + wsPointer = tokenPointer + tokenIterator->getString().size(); + + while (operandIterator != parsedOperands.end() && + tokenLoc.getPointer() > + (*operandIterator)->getEndLoc().getPointer()) { + ++operandIterator; + ++operandIndex; + } + + EDToken *token; + + switch (tokenIterator->getKind()) { + case AsmToken::Identifier: + if (!readOpcode) { + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenOpcode, + (uint64_t)tokenIterator->getKind(), + disassembler); + readOpcode = true; + break; + } + // any identifier that isn't an opcode is mere punctuation; so we fall + // through + default: + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenPunctuation, + (uint64_t)tokenIterator->getKind(), + disassembler); + break; + case AsmToken::Integer: + { + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenLiteral, + (uint64_t)tokenIterator->getKind(), + disassembler); + + int64_t intVal = tokenIterator->getIntVal(); + + if (intVal < 0) + token->makeLiteral(true, -intVal); + else + token->makeLiteral(false, intVal); + break; + } + case AsmToken::Register: + { + token = new EDToken(tokenIterator->getString(), + EDToken::kTokenLiteral, + (uint64_t)tokenIterator->getKind(), + disassembler); + + token->makeRegister((unsigned)tokenIterator->getRegVal()); + break; + } + } + + if (operandIterator != parsedOperands.end() && + tokenLoc.getPointer() >= + (*operandIterator)->getStartLoc().getPointer()) { + /// operandIndex == 0 means the operand is the instruction (which the + /// AsmParser treats as an operand but edis does not). We therefore skip + /// operandIndex == 0 and subtract 1 from all other operand indices. + + if (operandIndex > 0) + token->setOperandID(operandOrder[operandIndex - 1]); + } + + tokens.push_back(token); + } + + return 0; +} + +int EDToken::getString(const char*& buf) { + if (PermStr.length() == 0) { + PermStr = Str.str(); + } + buf = PermStr.c_str(); + return 0; +} diff --git a/contrib/llvm/lib/MC/MCDisassembler/EDToken.h b/contrib/llvm/lib/MC/MCDisassembler/EDToken.h new file mode 100644 index 0000000..6b2aeac --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/EDToken.h @@ -0,0 +1,139 @@ +//===-EDToken.h - LLVM Enhanced 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 Enhanced Disassembly library's token +// class. The token is responsible for vending information about the token, +// such as its type and logical value. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_EDTOKEN_H +#define LLVM_EDTOKEN_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/System/DataTypes.h" +#include <string> +#include <vector> + +namespace llvm { + +struct EDDisassembler; + +/// EDToken - Encapsulates a single token, which can provide a string +/// representation of itself or interpret itself in various ways, depending +/// on the token type. +struct EDToken { + enum tokenType { + kTokenWhitespace, + kTokenOpcode, + kTokenLiteral, + kTokenRegister, + kTokenPunctuation + }; + + /// The parent disassembler + EDDisassembler &Disassembler; + + /// The token's string representation + llvm::StringRef Str; + /// The token's string representation, but in a form suitable for export + std::string PermStr; + /// The type of the token, as exposed through the external API + enum tokenType Type; + /// The type of the token, as recorded by the syntax-specific tokenizer + uint64_t LocalType; + /// The operand corresponding to the token, or (unsigned int)-1 if not + /// part of an operand. + int OperandID; + + /// The sign if the token is a literal (1 if negative, 0 otherwise) + bool LiteralSign; + /// The absolute value if the token is a literal + uint64_t LiteralAbsoluteValue; + /// The LLVM register ID if the token is a register name + unsigned RegisterID; + + /// Constructor - Initializes an EDToken with the information common to all + /// tokens + /// + /// @arg str - The string corresponding to the token + /// @arg type - The token's type as exposed through the public API + /// @arg localType - The token's type as recorded by the tokenizer + /// @arg disassembler - The disassembler responsible for the token + EDToken(llvm::StringRef str, + enum tokenType type, + uint64_t localType, + EDDisassembler &disassembler); + + /// makeLiteral - Adds the information specific to a literal + /// @arg sign - The sign of the literal (1 if negative, 0 + /// otherwise) + /// + /// @arg absoluteValue - The absolute value of the literal + void makeLiteral(bool sign, uint64_t absoluteValue); + /// makeRegister - Adds the information specific to a register + /// + /// @arg registerID - The LLVM register ID + void makeRegister(unsigned registerID); + + /// setOperandID - Links the token to a numbered operand + /// + /// @arg operandID - The operand ID to link to + void setOperandID(int operandID); + + ~EDToken(); + + /// type - Returns the public type of the token + enum tokenType type() const; + /// localType - Returns the tokenizer-specific type of the token + uint64_t localType() const; + /// string - Returns the string representation of the token + llvm::StringRef string() const; + /// operandID - Returns the operand ID of the token + int operandID() const; + + /// literalSign - Returns the sign of the token + /// (1 if negative, 0 if positive or unsigned, -1 if it is not a literal) + int literalSign() const; + /// literalAbsoluteValue - Retrieves the absolute value of the token, and + /// returns -1 if the token is not a literal + /// @arg value - A reference to a value that is filled in with the absolute + /// value, if it is valid + int literalAbsoluteValue(uint64_t &value) const; + /// registerID - Retrieves the register ID of the token, and returns -1 if the + /// token is not a register + /// + /// @arg registerID - A reference to a value that is filled in with the + /// register ID, if it is valid + int registerID(unsigned ®isterID) const; + + /// tokenize - Tokenizes a string using the platform- and syntax-specific + /// tokenizer, and returns 0 on success (-1 on failure) + /// + /// @arg tokens - A vector that will be filled in with pointers to + /// allocated tokens + /// @arg str - The string, as outputted by the AsmPrinter + /// @arg operandOrder - The order of the operands from the operandFlags array + /// as they appear in str + /// @arg disassembler - The disassembler for the desired target and + // assembly syntax + static int tokenize(std::vector<EDToken*> &tokens, + std::string &str, + const char *operandOrder, + EDDisassembler &disassembler); + + /// getString - Directs a character pointer to the string, returning 0 on + /// success (-1 on failure) + /// @arg buf - A reference to a pointer that is set to point to the string. + /// The string is still owned by the token. + int getString(const char*& buf); +}; + +} // end namespace llvm +#endif diff --git a/contrib/llvm/lib/MC/MCDisassembler/Makefile b/contrib/llvm/lib/MC/MCDisassembler/Makefile new file mode 100644 index 0000000..7d71cd3 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDisassembler/Makefile @@ -0,0 +1,14 @@ +##===- lib/MC/MCDisassembler/Makefile ----------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../.. +LIBRARYNAME = LLVMMCDisassembler + +include $(LEVEL)/Makefile.common + diff --git a/contrib/llvm/lib/MC/MCDwarf.cpp b/contrib/llvm/lib/MC/MCDwarf.cpp new file mode 100644 index 0000000..2da71f9 --- /dev/null +++ b/contrib/llvm/lib/MC/MCDwarf.cpp @@ -0,0 +1,21 @@ +//===- 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/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +void MCDwarfFile::print(raw_ostream &OS) const { + OS << '"' << getName() << '"'; +} + +void MCDwarfFile::dump() const { + print(dbgs()); +} diff --git a/contrib/llvm/lib/MC/MCELFStreamer.cpp b/contrib/llvm/lib/MC/MCELFStreamer.cpp new file mode 100644 index 0000000..570c391 --- /dev/null +++ b/contrib/llvm/lib/MC/MCELFStreamer.cpp @@ -0,0 +1,408 @@ +//===- 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/MCStreamer.h" + +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCCodeEmitter.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/Support/Debug.h" +#include "llvm/Support/ELF.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" + +using namespace llvm; + +namespace { + +class MCELFStreamer : public MCObjectStreamer { + void EmitInstToFragment(const MCInst &Inst); + void EmitInstToData(const MCInst &Inst); +public: + MCELFStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter) {} + + ~MCELFStreamer() {} + + /// @name MCStreamer Interface + /// @{ + + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment); + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EmitCOFFSymbolStorageClass(int StorageClass) { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EmitCOFFSymbolType(int Type) { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EndCOFFSymbolDef() { + assert(0 && "ELF doesn't support this directive"); + } + + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setSize(Value); + } + + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); + virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); + virtual void EmitGPRel32Value(const MCExpr *Value) { + assert(0 && "ELF doesn't support this directive"); + } + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + + virtual void EmitFileDirective(StringRef Filename); + virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { + DEBUG(dbgs() << "FIXME: MCELFStreamer:EmitDwarfFileDirective not implemented\n"); + } + + virtual void EmitInstruction(const MCInst &Inst); + virtual void Finish(); + + /// @} +}; + +} // end anonymous namespace. + +void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + // 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(); + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); + + Symbol->setSection(*CurSection); +} + +void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + switch (Flag) { + case MCAF_SubsectionsViaSymbols: + getAssembler().setSubsectionsViaSymbols(true); + return; + } + + assert(0 && "invalid assembler flag!"); +} + +void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + // FIXME: Lift context changes into super class. + getAssembler().getOrCreateSymbolData(*Symbol); + Symbol->setVariableValue(AddValueSymbols(Value)); +} + +void 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; + } + + // 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_NoDeadStrip: + case MCSA_PrivateExtern: + case MCSA_WeakDefinition: + case MCSA_WeakDefAutoPrivate: + case MCSA_Invalid: + case MCSA_ELF_TypeIndFunction: + case MCSA_IndirectSymbol: + assert(0 && "Invalid symbol attribute for ELF!"); + break; + + case MCSA_Global: + SD.setFlags(SD.getFlags() | ELF_STB_Global); + SD.setExternal(true); + break; + + case MCSA_WeakReference: + case MCSA_Weak: + SD.setFlags(SD.getFlags() | ELF_STB_Weak); + break; + + case MCSA_Local: + SD.setFlags(SD.getFlags() | ELF_STB_Local); + break; + + case MCSA_ELF_TypeFunction: + SD.setFlags(SD.getFlags() | ELF_STT_Func); + break; + + case MCSA_ELF_TypeObject: + SD.setFlags(SD.getFlags() | ELF_STT_Object); + break; + + case MCSA_ELF_TypeTLS: + SD.setFlags(SD.getFlags() | ELF_STT_Tls); + break; + + case MCSA_ELF_TypeCommon: + SD.setFlags(SD.getFlags() | ELF_STT_Common); + break; + + case MCSA_ELF_TypeNoType: + SD.setFlags(SD.getFlags() | ELF_STT_Notype); + break; + + case MCSA_Protected: + SD.setFlags(SD.getFlags() | ELF_STV_Protected); + break; + + case MCSA_Hidden: + SD.setFlags(SD.getFlags() | ELF_STV_Hidden); + break; + + case MCSA_Internal: + SD.setFlags(SD.getFlags() | ELF_STV_Internal); + break; + } +} + +void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + if ((SD.getFlags() & (0xf << ELF_STB_Shift)) == ELF_STB_Local) { + const MCSection *Section = getAssembler().getContext().getELFSection(".bss", + MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE | + MCSectionELF::SHF_ALLOC, + SectionKind::getBSS()); + + MCSectionData &SectData = getAssembler().getOrCreateSectionData(*Section); + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD.setFragment(F); + Symbol->setSection(*Section); + SD.setSize(MCConstantExpr::Create(Size, getContext())); + } + + SD.setFlags(SD.getFlags() | ELF_STB_Global); + SD.setExternal(true); + + SD.setCommon(Size, ByteAlignment); +} + +void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); +} + +void MCELFStreamer::EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { + // FIXME: Endianness assumption. + for (unsigned i = 0; i != Size; ++i) + DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); + } else { + DF->addFixup(MCFixup::Create(DF->getContents().size(), AddValueSymbols(Value), + MCFixup::getKindForSize(Size))); + DF->getContents().resize(DF->getContents().size() + Size, 0); + } +} + +void MCELFStreamer::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; + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, + getCurrentSectionData()); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCELFStreamer::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, + getCurrentSectionData()); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCELFStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + // TODO: This is exactly the same as MCMachOStreamer. Consider merging into + // MCObjectStreamer. + new MCOrgFragment(*Offset, Value, getCurrentSectionData()); +} + +// Add a symbol for the file name of this module. This is the second +// entry in the module's symbol table (the first being the null symbol). +void MCELFStreamer::EmitFileDirective(StringRef Filename) { + MCSymbol *Symbol = getAssembler().getContext().GetOrCreateSymbol(Filename); + Symbol->setSection(*CurSection); + Symbol->setAbsolute(); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); +} + +void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { + MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); + + // 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->getCode() = Code; + IF->getFixups() = Fixups; +} + +void MCELFStreamer::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->addFixup(Fixups[i]); + } + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCELFStreamer::EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = 0; i != Inst.getNumOperands(); ++i) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + + getCurrentSectionData()->setHasInstructions(true); + + // If this instruction doesn't need relaxation, just emit it as data. + if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { + EmitInstToData(Inst); + return; + } + + // Otherwise, if we are relaxing everything, relax the instruction as much as + // possible and emit it as data. + if (getAssembler().getRelaxAll()) { + 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 MCELFStreamer::Finish() { + getAssembler().Finish(); +} + +MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll) { + MCELFStreamer *S = new MCELFStreamer(Context, TAB, OS, CE); + if (RelaxAll) + S->getAssembler().setRelaxAll(true); + return S; +} diff --git a/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp index 44bc267..671874d 100644 --- a/contrib/llvm/lib/MC/MCMachOStreamer.cpp +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -18,6 +18,8 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCMachOSymbolFlags.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" @@ -28,58 +30,19 @@ namespace { class MCMachOStreamer : public MCObjectStreamer { private: - MCFragment *getCurrentFragment() const { - assert(getCurrentSectionData() && "No current section!"); - - if (!getCurrentSectionData()->empty()) - return &getCurrentSectionData()->getFragmentList().back(); - - return 0; - } - - /// Get a data fragment to write into, creating a new one if the current - /// fragment is not a data fragment. - MCDataFragment *getOrCreateDataFragment() const { - MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); - if (!F) - F = new MCDataFragment(getCurrentSectionData()); - return F; - } - void EmitInstToFragment(const MCInst &Inst); void EmitInstToData(const MCInst &Inst); + // FIXME: These will likely moved to a better place. + void MakeLineEntryForSection(const MCSection *Section); + const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, + int IntVal); + void EmitDwarfFileTable(void); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) : MCObjectStreamer(Context, TAB, OS, Emitter) {} - const MCExpr *AddValueSymbols(const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Target: assert(0 && "Can't handle target exprs yet!"); - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); - AddValueSymbols(BE->getLHS()); - AddValueSymbols(BE->getRHS()); - break; - } - - case MCExpr::SymbolRef: - getAssembler().getOrCreateSymbolData( - cast<MCSymbolRefExpr>(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); - break; - } - - return Value; - } - /// @name MCStreamer Interface /// @{ @@ -126,10 +89,16 @@ public: unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename) { - report_fatal_error("unsupported directive: '.file'"); + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + //report_fatal_error("unsupported directive: '.file'"); } virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - report_fatal_error("unsupported directive: '.file'"); + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + //report_fatal_error("unsupported directive: '.file'"); } virtual void EmitInstruction(const MCInst &Inst); @@ -142,6 +111,8 @@ public: } // end anonymous namespace. void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + // TODO: This is almost exactly the same as WinCOFFStreamer. Consider merging + // into MCObjectStreamer. assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); assert(CurSection && "Cannot emit before setting section!"); @@ -185,6 +156,8 @@ void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. // FIXME: Lift context changes into super class. getAssembler().getOrCreateSymbolData(*Symbol); Symbol->setVariableValue(AddValueSymbols(Value)); @@ -335,11 +308,15 @@ void MCMachOStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, } void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. MCDataFragment *DF = getOrCreateDataFragment(); // Avoid fixups when possible. @@ -359,6 +336,8 @@ void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, void MCMachOStreamer::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; new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, @@ -371,6 +350,8 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, void MCMachOStreamer::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, @@ -429,6 +410,10 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { getCurrentSectionData()->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. + MakeLineEntryForSection(getCurrentSection()); + // If this instruction doesn't need relaxation, just emit it as data. if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { EmitInstToData(Inst); @@ -450,7 +435,207 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { EmitInstToFragment(Inst); } +// +// 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 MCMachOStreamer::MakeLineEntryForSection(const MCSection *Section) { + if (!getContext().getDwarfLocSeen()) + return; + + // Create a symbol at in the current section for use in the line entry. + MCSymbol *LineSym = getContext().CreateTempSymbol(); + // Set the value of the symbol to use for the MCLineEntry. + EmitLabel(LineSym); + + // Get the current .loc info saved in the context. + const MCDwarfLoc &DwarfLoc = 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. + getContext().clearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections[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. + MCLineSections[Section] = LineSection; + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry); +} + +// +// This helper routine returns an expression of End - Start + IntVal for use +// by EmitDwarfFileTable() below. +// +const MCExpr * MCMachOStreamer::MakeStartMinusEndExpr(MCSymbol *Start, + MCSymbol *End, + int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Res = + MCSymbolRefExpr::Create(End, Variant, getContext()); + const MCExpr *RHS = + MCSymbolRefExpr::Create(Start, Variant, getContext()); + const MCExpr *Res1 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS,getContext()); + const MCExpr *Res2 = + MCConstantExpr::Create(IntVal, getContext()); + const MCExpr *Res3 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, getContext()); + return Res3; +} + +// +// This emits the Dwarf file (and eventually the line) table. +// +void MCMachOStreamer::EmitDwarfFileTable(void) { + // For now make sure we don't put out the Dwarf file table if no .file + // directives were seen. + const std::vector<MCDwarfFile *> &MCDwarfFiles = + getContext().getMCDwarfFiles(); + if (MCDwarfFiles.size() == 0) + return; + + // This is the Mach-O section, for ELF it is the .debug_line section. + SwitchSection(getContext().getMachOSection("__DWARF", "__debug_line", + MCSectionMachO::S_ATTR_DEBUG, + 0, SectionKind::getDataRelLocal())); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = getContext().CreateTempSymbol(); + // Set the value of the symbol, as we are at the start of the section. + EmitLabel(LineStartSym); + + // Create a symbol for the end of the section (to be set when we get there). + MCSymbol *LineEndSym = getContext().CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + EmitValue(MakeStartMinusEndExpr(LineStartSym, LineEndSym, 4), 4, 0); + + // Next 2 bytes is the Version, which is Dwarf 2. + EmitIntValue(2, 2); + + // Create a symbol for the end of the prologue (to be set when we get there). + MCSymbol *ProEndSym = getContext().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. + EmitValue(MakeStartMinusEndExpr(LineStartSym, ProEndSym, (4 + 2 + 4)), 4, 0); + + // Parameters of the state machine, are next. + // Define the architecture-dependent minimum instruction length (in + // bytes). This value should be rather too small than too big. */ + // DWARF2_LINE_MIN_INSN_LENGTH + EmitIntValue(1, 1); + // Flag that indicates the initial value of the is_stmt_start flag. + // DWARF2_LINE_DEFAULT_IS_STMT + EmitIntValue(1, 1); + // Minimum line offset in a special line info. opcode. This value + // was chosen to give a reasonable range of values. */ + // DWARF2_LINE_BASE + EmitIntValue(uint64_t(-5), 1); + // Range of line offsets in a special line info. opcode. + // DWARF2_LINE_RANGE + EmitIntValue(14, 1); + // First special line opcode - leave room for the standard opcodes. + // DWARF2_LINE_OPCODE_BASE + EmitIntValue(13, 1); + + // Standard opcode lengths + EmitIntValue(0, 1); // length of DW_LNS_copy + EmitIntValue(1, 1); // length of DW_LNS_advance_pc + EmitIntValue(1, 1); // length of DW_LNS_advance_line + EmitIntValue(1, 1); // length of DW_LNS_set_file + EmitIntValue(1, 1); // length of DW_LNS_set_column + EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const std::vector<StringRef> &MCDwarfDirs = + getContext().getMCDwarfDirs(); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName + EmitBytes(StringRef("\0", 1), 0); // the null termination of the string + } + EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName + EmitBytes(StringRef("\0", 1), 0); // the null termination of the string + // FIXME the Directory number should be a .uleb128 not a .byte + EmitIntValue(MCDwarfFiles[i]->getDirIndex(), 1); + EmitIntValue(0, 1); // last modification timestamp (always 0) + EmitIntValue(0, 1); // filesize (always 0) + } + 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). + EmitLabel(ProEndSym); + + // TODO: This is the point where the line tables would be emitted. + + // Delete the MCLineSections that were created in + // MCMachOStreamer::MakeLineEntryForSection() and used to emit the line + // tables. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + getContext().getMCLineSections(); + for (DenseMap<const MCSection *, MCLineSection *>::iterator it = + MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { + delete it->second; + } + + // If there are no line tables emited then we emit: + // The following DW_LNE_set_address sequence to set the address to zero + // TODO test for 32-bit or 64-bit output + // This is the sequence for 32-bit code + EmitIntValue(0, 1); + EmitIntValue(5, 1); + EmitIntValue(2, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + + // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' + // (00 is the code for extended opcodes, followed by a ULEB128 length of the + // extended opcode (01), and the DW_LNE_end_sequence (01). + EmitIntValue(0, 1); // DW_LNS_extended_op + EmitIntValue(1, 1); // ULEB128 length of the extended opcode + EmitIntValue(1, 1); // DW_LNE_end_sequence + + // 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). + EmitLabel(LineEndSym); +} + void MCMachOStreamer::Finish() { + // Dump out the dwarf file and directory tables (soon to include line table) + EmitDwarfFileTable(); + // We have to set the fragment atom associations so we can relax properly for // Mach-O. diff --git a/contrib/llvm/lib/MC/MCNullStreamer.cpp b/contrib/llvm/lib/MC/MCNullStreamer.cpp index 5332ade..f7a2f20 100644 --- a/contrib/llvm/lib/MC/MCNullStreamer.cpp +++ b/contrib/llvm/lib/MC/MCNullStreamer.cpp @@ -26,6 +26,7 @@ namespace { /// @{ virtual void SwitchSection(const MCSection *Section) { + PrevSection = CurSection; CurSection = Section; } diff --git a/contrib/llvm/lib/MC/MCObjectStreamer.cpp b/contrib/llvm/lib/MC/MCObjectStreamer.cpp index d3f7f77..2b2385e 100644 --- a/contrib/llvm/lib/MC/MCObjectStreamer.cpp +++ b/contrib/llvm/lib/MC/MCObjectStreamer.cpp @@ -9,7 +9,11 @@ #include "llvm/MC/MCObjectStreamer.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Target/TargetAsmBackend.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -21,15 +25,59 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, } MCObjectStreamer::~MCObjectStreamer() { + delete &Assembler->getBackend(); + delete &Assembler->getEmitter(); delete Assembler; } +MCFragment *MCObjectStreamer::getCurrentFragment() const { + assert(getCurrentSectionData() && "No current section!"); + + if (!getCurrentSectionData()->empty()) + return &getCurrentSectionData()->getFragmentList().back(); + + return 0; +} + +MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { + MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); + if (!F) + F = new MCDataFragment(getCurrentSectionData()); + return F; +} + +const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + 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::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); // If already in this section, then this is a noop. if (Section == CurSection) return; + PrevSection = CurSection; CurSection = Section; CurSectionData = &getAssembler().getOrCreateSectionData(*Section); } diff --git a/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp b/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp index 465d983..086df08 100644 --- a/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp +++ b/contrib/llvm/lib/MC/MCParser/AsmLexer.cpp @@ -117,6 +117,13 @@ AsmToken AsmLexer::LexLineComment() { return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); } +static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { + if (CurPtr[0] == 'L' && CurPtr[1] == 'L') + CurPtr += 2; + if (CurPtr[0] == 'U' && CurPtr[1] == 'L' && CurPtr[2] == 'L') + CurPtr += 3; +} + /// LexDigit: First character is [0-9]. /// Local Label: [0-9][:] @@ -133,7 +140,7 @@ AsmToken AsmLexer::LexDigit() { ++CurPtr; StringRef Result(TokStart, CurPtr - TokStart); - + long long Value; if (Result.getAsInteger(10, Value)) { // We have to handle minint_as_a_positive_value specially, because @@ -143,6 +150,11 @@ AsmToken AsmLexer::LexDigit() { else return ReturnError(TokStart, "Invalid decimal 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); } @@ -165,9 +177,13 @@ AsmToken AsmLexer::LexDigit() { StringRef Result(TokStart, CurPtr - TokStart); long long Value; - if (Result.getAsInteger(2, 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); } @@ -185,6 +201,10 @@ AsmToken AsmLexer::LexDigit() { if (StringRef(TokStart, CurPtr - TokStart).getAsInteger(0, Result)) return ReturnError(TokStart, "Invalid hexadecimal number"); + // 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); } @@ -198,6 +218,10 @@ AsmToken AsmLexer::LexDigit() { if (Result.getAsInteger(8, Value)) return ReturnError(TokStart, "Invalid octal 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); } diff --git a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp index e0949bd..f83cd5e 100644 --- a/contrib/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/AsmParser.cpp @@ -11,47 +11,237 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MCParser/AsmParser.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.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/MCInst.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/MCSectionMachO.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/Support/Compiler.h" -#include "llvm/Support/SourceMgr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmParser.h" +#include <vector> using namespace llvm; namespace { +/// \brief Helper class for tracking macro definitions. +struct Macro { + StringRef Name; + StringRef Body; + +public: + Macro(StringRef N, StringRef B) : Name(N), Body(B) {} +}; + +/// \brief Helper class for storing information about an active macro +/// instantiation. +struct MacroInstantiation { + /// The macro being instantiated. + const Macro *TheMacro; + + /// The macro instantiation with substitutions. + MemoryBuffer *Instantiation; + + /// The location of the instantiation. + SMLoc InstantiationLoc; + + /// The location where parsing should resume upon instantiation completion. + SMLoc ExitLoc; + +public: + MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, + const std::vector<std::vector<AsmToken> > &A); +}; + +/// \brief The concrete assembly parser instance. +class AsmParser : public MCAsmParser { + friend class GenericAsmParser; + + AsmParser(const AsmParser &); // DO NOT IMPLEMENT + void operator=(const AsmParser &); // DO NOT IMPLEMENT +private: + AsmLexer Lexer; + MCContext &Ctx; + MCStreamer &Out; + SourceMgr &SrcMgr; + MCAsmParserExtension *GenericParser; + 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; + + /// DirectiveMap - This is a table handlers for directives. Each handler is + /// invoked after the directive identifier is read and is responsible for + /// parsing and validating the rest of the directive. The handler is passed + /// in the directive name and the location of the directive keyword. + StringMap<std::pair<MCAsmParserExtension*, DirectiveHandler> > DirectiveMap; + + /// MacroMap - Map of currently defined macros. + StringMap<Macro*> MacroMap; + + /// ActiveMacros - Stack of active macro instantiations. + std::vector<MacroInstantiation*> ActiveMacros; + + /// Boolean tracking whether macro substitution is enabled. + unsigned MacrosEnabled : 1; + +public: + AsmParser(const Target &T, SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, + const MCAsmInfo &MAI); + ~AsmParser(); + + virtual bool Run(bool NoInitialTextSection, bool NoFinalize = false); + + void AddDirectiveHandler(MCAsmParserExtension *Object, + StringRef Directive, + DirectiveHandler Handler) { + DirectiveMap[Directive] = std::make_pair(Object, 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 void Warning(SMLoc L, const Twine &Meg); + virtual bool Error(SMLoc L, const Twine &Msg); + + const AsmToken &Lex(); + + bool ParseExpression(const MCExpr *&Res); + virtual bool ParseExpression(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool ParseParenExpression(const MCExpr *&Res, SMLoc &EndLoc); + virtual bool ParseAbsoluteExpression(int64_t &Res); + + /// } + +private: + bool ParseStatement(); + + bool HandleMacroEntry(StringRef Name, SMLoc NameLoc, const Macro *M); + void HandleMacroExit(); + + void PrintMacroInstantiations(); + void PrintMessage(SMLoc Loc, const std::string &Msg, const char *Type) const; + + /// EnterIncludeFile - Enter the specified file. This returns true on failure. + bool EnterIncludeFile(const std::string &Filename); + + /// \brief Reset the current lexer position to that given by \arg Loc. The + /// current token is not set; clients should ensure Lex() is called + /// subsequently. + void JumpToLoc(SMLoc Loc); + + void EatToEndOfStatement(); + + /// \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. + StringRef ParseStringToEndOfStatement(); + + bool ParseAssignment(StringRef Name); + + bool ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); + bool ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); + bool ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); + + /// ParseIdentifier - Parse an identifier or string (as a quoted identifier) + /// and set \arg Res to the identifier contents. + bool ParseIdentifier(StringRef &Res); + + // Directive Parsing. + bool ParseDirectiveAscii(bool ZeroTerminated); // ".ascii", ".asciiz" + bool ParseDirectiveValue(unsigned Size); // ".byte", ".long", ... + bool ParseDirectiveFill(); // ".fill" + bool ParseDirectiveSpace(); // ".space" + bool ParseDirectiveSet(); // ".set" + bool ParseDirectiveOrg(); // ".org" + // ".align{,32}", ".p2align{,w,l}" + bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); + + /// ParseDirectiveSymbolAttribute - Parse a directive like ".globl" which + /// accepts a single symbol (which should be a label or an external). + bool ParseDirectiveSymbolAttribute(MCSymbolAttr Attr); + bool ParseDirectiveELFType(); // ELF specific ".type" + + bool ParseDirectiveComm(bool IsLocal); // ".comm" and ".lcomm" + + bool ParseDirectiveAbort(); // ".abort" + bool ParseDirectiveInclude(); // ".include" + + bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" + bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" + bool ParseDirectiveElse(SMLoc DirectiveLoc); // ".else" + bool ParseDirectiveEndIf(SMLoc DirectiveLoc); // .endif + + /// ParseEscapedString - Parse the current token as a string which may include + /// escaped characters and return the string contents. + bool ParseEscapedString(std::string &Data); +}; + /// \brief Generic implementations of directive handling, etc. which is shared /// (or the default, at least) for all assembler parser. class GenericAsmParser : public MCAsmParserExtension { + template<bool (GenericAsmParser::*Handler)(StringRef, SMLoc)> + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective<GenericAsmParser, Handler>); + } + public: GenericAsmParser() {} + AsmParser &getParser() { + return (AsmParser&) this->MCAsmParserExtension::getParser(); + } + virtual void Initialize(MCAsmParser &Parser) { // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); // Debugging directives. - Parser.AddDirectiveHandler(this, ".file", MCAsmParser::DirectiveHandler( - &GenericAsmParser::ParseDirectiveFile)); - Parser.AddDirectiveHandler(this, ".line", MCAsmParser::DirectiveHandler( - &GenericAsmParser::ParseDirectiveLine)); - Parser.AddDirectiveHandler(this, ".loc", MCAsmParser::DirectiveHandler( - &GenericAsmParser::ParseDirectiveLoc)); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveFile>(".file"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLine>(".line"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLoc>(".loc"); + + // Macro directives. + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( + ".macros_on"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( + ".macros_off"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacro>(".macro"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endm"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endmacro"); } - bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); // ".file" - bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); // ".line" - bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); // ".loc" + bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); + + bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); }; } @@ -69,7 +259,7 @@ AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, MCStreamer &_Out, const MCAsmInfo &_MAI) : Lexer(_MAI), Ctx(_Ctx), Out(_Out), SrcMgr(_SM), GenericParser(new GenericAsmParser), PlatformParser(0), - TargetParser(0), CurBuffer(0) { + CurBuffer(0), MacrosEnabled(true) { Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); // Initialize the generic parser. @@ -89,22 +279,33 @@ AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, } AsmParser::~AsmParser() { + assert(ActiveMacros.empty() && "Unexpected active macro instantiation!"); + + // Destroy any macros. + for (StringMap<Macro*>::iterator it = MacroMap.begin(), + ie = MacroMap.end(); it != ie; ++it) + delete it->getValue(); + delete PlatformParser; delete GenericParser; } -void AsmParser::setTargetParser(TargetAsmParser &P) { - assert(!TargetParser && "Target parser is already initialized!"); - TargetParser = &P; - TargetParser->Initialize(*this); +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, "while in macro instantiation", + "note"); } void AsmParser::Warning(SMLoc L, const Twine &Msg) { PrintMessage(L, Msg.str(), "warning"); + PrintMacroInstantiations(); } bool AsmParser::Error(SMLoc L, const Twine &Msg) { PrintMessage(L, Msg.str(), "error"); + PrintMacroInstantiations(); return true; } @@ -124,7 +325,12 @@ bool AsmParser::EnterIncludeFile(const std::string &Filename) { return false; } - + +void AsmParser::JumpToLoc(SMLoc Loc) { + CurBuffer = SrcMgr.FindBufferContainingLoc(Loc); + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), Loc.getPointer()); +} + const AsmToken &AsmParser::Lex() { const AsmToken *tok = &Lexer.Lex(); @@ -133,15 +339,13 @@ const AsmToken &AsmParser::Lex() { // include stack. SMLoc ParentIncludeLoc = SrcMgr.getParentIncludeLoc(CurBuffer); if (ParentIncludeLoc != SMLoc()) { - CurBuffer = SrcMgr.FindBufferContainingLoc(ParentIncludeLoc); - Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer), - ParentIncludeLoc.getPointer()); + JumpToLoc(ParentIncludeLoc); tok = &Lexer.Lex(); } } if (tok->is(AsmToken::Error)) - PrintMessage(Lexer.getErrLoc(), Lexer.getErr(), "error"); + Error(Lexer.getErrLoc(), Lexer.getErr()); return *tok; } @@ -174,6 +378,16 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { 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 std::vector<MCDwarfFile *> &MCDwarfFiles = + getContext().getMCDwarfFiles(); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + if (!MCDwarfFiles[i]){ + TokError("unassigned file number: " + Twine(i) + " for .file directives"); + HadError = true; + } + } // Finalize the output stream if there are no errors and if the client wants // us to. @@ -194,6 +408,16 @@ void AsmParser::EatToEndOfStatement() { 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); +} /// ParseParenExpr - Parse a paren expression and return it. /// NOTE: This assumes the leading '(' has already been consumed. @@ -225,10 +449,17 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { return true; Res = MCUnaryExpr::CreateLNot(Res, getContext()); return false; + case AsmToken::Dollar: case AsmToken::String: case AsmToken::Identifier: { + EndLoc = Lexer.getLoc(); + + StringRef Identifier; + if (ParseIdentifier(Identifier)) + return false; + // This is a symbol reference. - std::pair<StringRef, StringRef> Split = getTok().getIdentifier().split('@'); + std::pair<StringRef, StringRef> Split = Identifier.split('@'); MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first); // Mark the symbol as used in an expression. @@ -236,12 +467,9 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { // Lookup the symbol variant if used. MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - if (Split.first.size() != getTok().getIdentifier().size()) + if (Split.first.size() != Identifier.size()) Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); - EndLoc = Lexer.getLoc(); - Lex(); // Eat identifier. - // 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())) { @@ -568,7 +796,12 @@ bool AsmParser::ParseStatement() { default: // Normal instruction or directive. break; } - + + // If macros are enabled, check to see if this is a macro instantiation. + if (MacrosEnabled) + if (const Macro *M = MacroMap.lookup(IDVal)) + return HandleMacroEntry(IDVal, IDLoc, M); + // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.') { // Assembler features @@ -591,11 +824,14 @@ bool AsmParser::ParseStatement() { if (IDVal == ".quad") return ParseDirectiveValue(8); - // FIXME: Target hooks for IsPow2. - if (IDVal == ".align") - return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/1); - if (IDVal == ".align32") - return ParseDirectiveAlign(/*IsPow2=*/true, /*ExprSize=*/4); + if (IDVal == ".align") { + bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); + return ParseDirectiveAlign(IsPow2, /*ExprSize=*/1); + } + if (IDVal == ".align32") { + bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); + return ParseDirectiveAlign(IsPow2, /*ExprSize=*/4); + } if (IDVal == ".balign") return ParseDirectiveAlign(/*IsPow2=*/false, /*ExprSize=*/1); if (IDVal == ".balignw") @@ -662,7 +898,7 @@ bool AsmParser::ParseStatement() { std::pair<MCAsmParserExtension*, DirectiveHandler> Handler = DirectiveMap.lookup(IDVal); if (Handler.first) - return (Handler.first->*Handler.second)(IDVal, IDLoc); + return (*Handler.second)(Handler.first, IDVal, IDLoc); // Target hook for parsing target specific directives. if (!getTargetParser().ParseDirective(ID)) @@ -684,20 +920,29 @@ bool AsmParser::ParseStatement() { if (!HadError && Lexer.isNot(AsmToken::EndOfStatement)) HadError = TokError("unexpected token in argument list"); + // Dump the parsed representation, if requested. + if (getShowParsedOperands()) { + SmallString<256> Str; + raw_svector_ostream OS(Str); + OS << "parsed instruction: ["; + for (unsigned i = 0; i != ParsedOperands.size(); ++i) { + if (i != 0) + OS << ", "; + ParsedOperands[i]->dump(OS); + } + OS << "]"; + + PrintMessage(IDLoc, OS.str(), "note"); + } + // If parsing succeeded, match the instruction. if (!HadError) { MCInst Inst; - if (!getTargetParser().MatchInstruction(ParsedOperands, Inst)) { + if (!getTargetParser().MatchInstruction(IDLoc, ParsedOperands, Inst)) { // Emit the instruction on success. Out.EmitInstruction(Inst); - } else { - // Otherwise emit a diagnostic about the match failure and set the error - // flag. - // - // FIXME: We should give nicer diagnostics about the exact failure. - Error(IDLoc, "unrecognized instruction"); + } else HadError = true; - } } // If there was no error, consume the end-of-statement token. Otherwise this @@ -712,6 +957,132 @@ bool AsmParser::ParseStatement() { return HadError; } +MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, + const std::vector<std::vector<AsmToken> > &A) + : TheMacro(M), InstantiationLoc(IL), ExitLoc(EL) +{ + // 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 Body = M->Body; + 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 (Body[Pos] != '$' || Pos + 1 == End) + continue; + + char Next = Body[Pos + 1]; + if (Next == '$' || Next == 'n' || isdigit(Next)) + break; + } + + // Add the prefix. + OS << Body.slice(0, Pos); + + // Check if we reached the end. + if (Pos == End) + break; + + 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 (std::vector<AsmToken>::const_iterator it = A[Index].begin(), + ie = A[Index].end(); it != ie; ++it) + OS << it->getString(); + break; + } + } + + // Update the scan point. + Body = Body.substr(Pos + 2); + } + + // We include the .endmacro in the buffer as our queue to exit the macro + // instantiation. + OS << ".endmacro\n"; + + Instantiation = MemoryBuffer::getMemBufferCopy(OS.str(), "<instantiation>"); +} + +bool AsmParser::HandleMacroEntry(StringRef Name, SMLoc NameLoc, + const Macro *M) { + // 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"); + + // Parse the macro instantiation arguments. + std::vector<std::vector<AsmToken> > MacroArguments; + MacroArguments.push_back(std::vector<AsmToken>()); + unsigned ParenLevel = 0; + for (;;) { + if (Lexer.is(AsmToken::Eof)) + return TokError("unexpected token in macro instantiation"); + if (Lexer.is(AsmToken::EndOfStatement)) + break; + + // If we aren't inside parentheses and this is a comma, start a new token + // list. + if (ParenLevel == 0 && Lexer.is(AsmToken::Comma)) { + MacroArguments.push_back(std::vector<AsmToken>()); + } else { + // 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. + MacroArguments.back().push_back(getTok()); + } + Lex(); + } + + // Create the macro instantiation object and add to the current macro + // instantiation stack. + MacroInstantiation *MI = new MacroInstantiation(M, NameLoc, + getTok().getLoc(), + MacroArguments); + 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); + Lex(); + + // Pop the instantiation entry. + delete ActiveMacros.back(); + ActiveMacros.pop_back(); +} + bool AsmParser::ParseAssignment(StringRef Name) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); @@ -760,6 +1131,30 @@ bool AsmParser::ParseAssignment(StringRef Name) { /// ::= identifier /// ::= string bool AsmParser::ParseIdentifier(StringRef &Res) { + // The assembler has relaxed rules for accepting identifiers, in particular we + // allow things like '.globl $foo', 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)) { + SMLoc DollarLoc = getLexer().getLoc(); + + // Consume the dollar sign, and check for a following identifier. + Lex(); + if (Lexer.isNot(AsmToken::Identifier)) + return true; + + // We have a '$' followed by an identifier, make sure they are adjacent. + if (DollarLoc.getPointer() + 1 != getTok().getLoc().getPointer()) + return true; + + // Construct the joined identifier and consume the token. + Res = StringRef(DollarLoc.getPointer(), + getTok().getIdentifier().size() + 1); + Lex(); + return false; + } + if (Lexer.isNot(AsmToken::Identifier) && Lexer.isNot(AsmToken::String)) return true; @@ -1081,13 +1476,14 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { bool UseCodeAlign = false; if (const MCSectionMachO *S = dyn_cast<MCSectionMachO>( getStreamer().getCurrentSection())) - UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); 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); + getStreamer().EmitValueToAlignment(Alignment, FillExpr, ValueSize, + MaxBytesToFill); } return false; @@ -1238,31 +1634,22 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { } /// ParseDirectiveAbort -/// ::= .abort [ "abort_string" ] +/// ::= .abort [... message ...] bool AsmParser::ParseDirectiveAbort() { // FIXME: Use loc from directive. SMLoc Loc = getLexer().getLoc(); - StringRef Str = ""; - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in '.abort' directive"); - - Str = getTok().getString(); - - Lex(); - } - + StringRef Str = ParseStringToEndOfStatement(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.abort' directive"); - + Lex(); - // FIXME: Handle here. if (Str.empty()) Error(Loc, ".abort detected. Assembly stopping."); else Error(Loc, ".abort '" + Str + "' detected. Assembly stopping."); + // FIXME: Actually abort assembly here. return false; } @@ -1286,9 +1673,7 @@ bool AsmParser::ParseDirectiveInclude() { // 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)) { - PrintMessage(IncludeLoc, - "Could not find include file '" + Filename + "'", - "error"); + Error(IncludeLoc, "Could not find include file '" + Filename + "'"); return true; } @@ -1401,6 +1786,7 @@ bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { bool GenericAsmParser::ParseDirectiveFile(StringRef, 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(); @@ -1421,8 +1807,11 @@ bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); - else + else { + if (getContext().GetDwarfFile(Filename, FileNumber) == 0) + Error(FileNumberLoc, "file number already allocated"); getStreamer().EmitDwarfFileDirective(FileNumber, Filename); + } return false; } @@ -1449,40 +1838,193 @@ bool GenericAsmParser::ParseDirectiveLine(StringRef, SMLoc DirectiveLoc) { /// ParseDirectiveLoc -/// ::= .loc number [number [number]] +/// ::= .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 GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::Integer)) return TokError("unexpected token in '.loc' directive"); - - // FIXME: What are these fields? int64_t FileNumber = getTok().getIntVal(); - (void) FileNumber; - // FIXME: Validate file. - + if (FileNumber < 1) + return TokError("file number less than one in '.loc' directive"); + if (!getContext().ValidateDwarfFileNumber(FileNumber)) + return TokError("unassigned file number in '.loc' directive"); Lex(); - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::Integer)) - return TokError("unexpected token in '.loc' directive"); - int64_t Param2 = getTok().getIntVal(); - (void) Param2; + int64_t LineNumber = 0; + if (getLexer().is(AsmToken::Integer)) { + LineNumber = getTok().getIntVal(); + if (LineNumber < 1) + return TokError("line number less than one in '.loc' directive"); Lex(); + } - if (getLexer().isNot(AsmToken::EndOfStatement)) { - if (getLexer().isNot(AsmToken::Integer)) + 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 = 0; + unsigned Isa = 0; + if (getLexer().isNot(AsmToken::EndOfStatement)) { + for (;;) { + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + StringRef Name; + SMLoc Loc = getTok().getLoc(); + if (getParser().ParseIdentifier(Name)) return TokError("unexpected token in '.loc' directive"); - int64_t Param3 = getTok().getIntVal(); - (void) Param3; - Lex(); + 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") { + SMLoc Loc = getTok().getLoc(); + const MCExpr *Value; + if (getParser().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") { + SMLoc Loc = getTok().getLoc(); + const MCExpr *Value; + if (getParser().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 { + return Error(Loc, "unknown sub-directive in '.loc' directive"); + } - // FIXME: Do something with the .loc. + if (getLexer().is(AsmToken::EndOfStatement)) + break; } } + getContext().setCurrentDwarfLoc(FileNumber, LineNumber, ColumnPos, Flags,Isa); + + return false; +} + +/// ParseDirectiveMacrosOnOff +/// ::= .macros_on +/// ::= .macros_off +bool GenericAsmParser::ParseDirectiveMacrosOnOff(StringRef Directive, + SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.file' directive"); + return Error(getLexer().getLoc(), + "unexpected token in '" + Directive + "' directive"); + + getParser().MacrosEnabled = Directive == ".macros_on"; return false; } +/// ParseDirectiveMacro +/// ::= .macro name +bool GenericAsmParser::ParseDirectiveMacro(StringRef Directive, + SMLoc DirectiveLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.macro' directive"); + + // 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. + getParser().EatToEndOfStatement(); + } + + if (getParser().MacroMap.lookup(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); + getParser().MacroMap[Name] = new Macro(Name, Body); + return false; +} + +/// ParseDirectiveEndMacro +/// ::= .endm +/// ::= .endmacro +bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, + SMLoc DirectiveLoc) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '" + Directive + "' directive"); + + // If we are inside a macro instantiation, terminate the current + // instantiation. + if (!getParser().ActiveMacros.empty()) { + getParser().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"); +} + +/// \brief Create an MCAsmParser instance. +MCAsmParser *llvm::createMCAsmParser(const Target &T, SourceMgr &SM, + MCContext &C, MCStreamer &Out, + const MCAsmInfo &MAI) { + return new AsmParser(T, SM, C, Out, MAI); +} diff --git a/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp index 7d8639e..54ddb44 100644 --- a/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/DarwinAsmParser.cpp @@ -25,6 +25,12 @@ namespace { /// \brief Implementation of directive handling which is shared across all /// Darwin targets. class DarwinAsmParser : public MCAsmParserExtension { + template<bool (DarwinAsmParser::*Handler)(StringRef, SMLoc)> + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective<DarwinAsmParser, Handler>); + } + bool ParseSectionSwitch(const char *Segment, const char *Section, unsigned TAA = 0, unsigned ImplicitAlign = 0, unsigned StubSize = 0); @@ -36,168 +42,70 @@ public: // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); - Parser.AddDirectiveHandler(this, ".desc", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveDesc)); - Parser.AddDirectiveHandler(this, ".lsym", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveLsym)); - Parser.AddDirectiveHandler(this, ".subsections_via_symbols", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSubsectionsViaSymbols)); - Parser.AddDirectiveHandler(this, ".dump", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveDumpOrLoad)); - Parser.AddDirectiveHandler(this, ".load", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveDumpOrLoad)); - Parser.AddDirectiveHandler(this, ".section", MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSection)); - Parser.AddDirectiveHandler(this, ".secure_log_unique", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSecureLogUnique)); - Parser.AddDirectiveHandler(this, ".secure_log_reset", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveSecureLogReset)); - Parser.AddDirectiveHandler(this, ".tbss", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveTBSS)); - Parser.AddDirectiveHandler(this, ".zerofill", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseDirectiveZerofill)); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDesc>(".desc"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveLsym>(".lsym"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSubsectionsViaSymbols>( + ".subsections_via_symbols"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDumpOrLoad>(".dump"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveDumpOrLoad>(".load"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSection>(".section"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSecureLogUnique>( + ".secure_log_unique"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveSecureLogReset>( + ".secure_log_reset"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveTBSS>(".tbss"); + AddDirectiveHandler<&DarwinAsmParser::ParseDirectiveZerofill>(".zerofill"); // Special section directives. - Parser.AddDirectiveHandler(this, ".const", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveConst)); - Parser.AddDirectiveHandler(this, ".const_data", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveConstData)); - Parser.AddDirectiveHandler(this, ".constructor", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveConstructor)); - Parser.AddDirectiveHandler(this, ".cstring", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveCString)); - Parser.AddDirectiveHandler(this, ".data", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveData)); - Parser.AddDirectiveHandler(this, ".destructor", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveDestructor)); - Parser.AddDirectiveHandler(this, ".dyld", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveDyld)); - Parser.AddDirectiveHandler(this, ".fvmlib_init0", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveFVMLibInit0)); - Parser.AddDirectiveHandler(this, ".fvmlib_init1", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveFVMLibInit1)); - Parser.AddDirectiveHandler(this, ".lazy_symbol_pointer", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLazySymbolPointers)); - Parser.AddDirectiveHandler(this, ".literal16", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLiteral16)); - Parser.AddDirectiveHandler(this, ".literal4", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLiteral4)); - Parser.AddDirectiveHandler(this, ".literal8", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveLiteral8)); - Parser.AddDirectiveHandler(this, ".mod_init_func", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveModInitFunc)); - Parser.AddDirectiveHandler(this, ".mod_term_func", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveModTermFunc)); - Parser.AddDirectiveHandler(this, ".non_lazy_symbol_pointer", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveNonLazySymbolPointers)); - Parser.AddDirectiveHandler(this, ".objc_cat_cls_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCCatClsMeth)); - Parser.AddDirectiveHandler(this, ".objc_cat_inst_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCCatInstMeth)); - Parser.AddDirectiveHandler(this, ".objc_category", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCCategory)); - Parser.AddDirectiveHandler(this, ".objc_class", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClass)); - Parser.AddDirectiveHandler(this, ".objc_class_names", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClassNames)); - Parser.AddDirectiveHandler(this, ".objc_class_vars", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClassVars)); - Parser.AddDirectiveHandler(this, ".objc_cls_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClsMeth)); - Parser.AddDirectiveHandler(this, ".objc_cls_refs", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCClsRefs)); - Parser.AddDirectiveHandler(this, ".objc_inst_meth", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCInstMeth)); - Parser.AddDirectiveHandler(this, ".objc_instance_vars", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCInstanceVars)); - Parser.AddDirectiveHandler(this, ".objc_message_refs", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMessageRefs)); - Parser.AddDirectiveHandler(this, ".objc_meta_class", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMetaClass)); - Parser.AddDirectiveHandler(this, ".objc_meth_var_names", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMethVarNames)); - Parser.AddDirectiveHandler(this, ".objc_meth_var_types", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCMethVarTypes)); - Parser.AddDirectiveHandler(this, ".objc_module_info", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCModuleInfo)); - Parser.AddDirectiveHandler(this, ".objc_protocol", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCProtocol)); - Parser.AddDirectiveHandler(this, ".objc_selector_strs", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCSelectorStrs)); - Parser.AddDirectiveHandler(this, ".objc_string_object", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCStringObject)); - Parser.AddDirectiveHandler(this, ".objc_symbols", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveObjCSymbols)); - Parser.AddDirectiveHandler(this, ".picsymbol_stub", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectivePICSymbolStub)); - Parser.AddDirectiveHandler(this, ".static_const", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveStaticConst)); - Parser.AddDirectiveHandler(this, ".static_data", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveStaticData)); - Parser.AddDirectiveHandler(this, ".symbol_stub", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveSymbolStub)); - Parser.AddDirectiveHandler(this, ".tdata", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveTData)); - Parser.AddDirectiveHandler(this, ".text", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveText)); - Parser.AddDirectiveHandler(this, ".thread_init_func", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveThreadInitFunc)); - Parser.AddDirectiveHandler(this, ".tlv", - MCAsmParser::DirectiveHandler( - &DarwinAsmParser::ParseSectionDirectiveTLV)); + 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::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"); } bool ParseDirectiveDesc(StringRef, SMLoc); bool ParseDirectiveDumpOrLoad(StringRef, SMLoc); bool ParseDirectiveLsym(StringRef, SMLoc); - bool ParseDirectiveSection(); + bool ParseDirectiveSection(StringRef, SMLoc); bool ParseDirectiveSecureLogReset(StringRef, SMLoc); bool ParseDirectiveSecureLogUnique(StringRef, SMLoc); bool ParseDirectiveSubsectionsViaSymbols(StringRef, SMLoc); @@ -493,7 +401,7 @@ bool DarwinAsmParser::ParseDirectiveLsym(StringRef, SMLoc) { /// ParseDirectiveSection: /// ::= .section identifier (',' identifier)* -bool DarwinAsmParser::ParseDirectiveSection() { +bool DarwinAsmParser::ParseDirectiveSection(StringRef, SMLoc) { SMLoc Loc = getLexer().getLoc(); StringRef SectionName; @@ -537,28 +445,22 @@ bool DarwinAsmParser::ParseDirectiveSection() { } /// ParseDirectiveSecureLogUnique -/// ::= .secure_log_unique "log message" +/// ::= .secure_log_unique ... message ... bool DarwinAsmParser::ParseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { - std::string LogMessage; - - if (getLexer().isNot(AsmToken::String)) - LogMessage = ""; - else{ - LogMessage = getTok().getString(); - Lex(); - } - + 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"); - char *SecureLogFile = getContext().getSecureLogFile(); + // 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; @@ -571,6 +473,7 @@ bool DarwinAsmParser::ParseDirectiveSecureLogUnique(StringRef, SMLoc IDLoc) { getContext().setSecureLog(OS); } + // Write the message. int CurBuf = getSourceManager().FindBufferContainingLoc(IDLoc); *OS << getSourceManager().getBufferInfo(CurBuf).Buffer->getBufferIdentifier() << ":" << getSourceManager().FindLineNumber(IDLoc, CurBuf) << ":" diff --git a/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp index 7a54dd3..f982fda 100644 --- a/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/ELFAsmParser.cpp @@ -8,15 +8,24 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCParser/MCAsmParserExtension.h" -#include "llvm/MC/MCSectionELF.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" -#include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/Twine.h" using namespace llvm; namespace { class ELFAsmParser : public MCAsmParserExtension { + template<bool (ELFAsmParser::*Handler)(StringRef, SMLoc)> + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective<ELFAsmParser, Handler>); + } + bool ParseSectionSwitch(StringRef Section, unsigned Type, unsigned Flags, SectionKind Kind); @@ -27,10 +36,21 @@ public: // Call the base implementation. this->MCAsmParserExtension::Initialize(Parser); - Parser.AddDirectiveHandler(this, ".data", MCAsmParser::DirectiveHandler( - &ELFAsmParser::ParseSectionDirectiveData)); - Parser.AddDirectiveHandler(this, ".text", MCAsmParser::DirectiveHandler( - &ELFAsmParser::ParseSectionDirectiveText)); + 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::ParseDirectiveSize>(".size"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".sleb128"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".uleb128"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); } bool ParseSectionDirectiveData(StringRef, SMLoc) { @@ -43,6 +63,56 @@ public: MCSectionELF::SHF_EXECINSTR | MCSectionELF::SHF_ALLOC, SectionKind::getText()); } + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE | + MCSectionELF::SHF_ALLOC, SectionKind::getBSS()); + } + bool ParseSectionDirectiveRoData(StringRef, SMLoc) { + return ParseSectionSwitch(".rodata", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC, + SectionKind::getReadOnly()); + } + bool ParseSectionDirectiveTData(StringRef, SMLoc) { + return ParseSectionSwitch(".tdata", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + SectionKind::getThreadData()); + } + bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".tbss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + SectionKind::getThreadBSS()); + } + bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getDataRel()); + } + bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getReadOnlyWithRel()); + } + bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) { + return ParseSectionSwitch(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getReadOnlyWithRelLocal()); + } + bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { + return ParseSectionSwitch(".eh_frame", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_ALLOC | + MCSectionELF::SHF_WRITE, + SectionKind::getDataRel()); + } + bool ParseDirectiveLEB128(StringRef, SMLoc); + bool ParseDirectiveSection(StringRef, SMLoc); + bool ParseDirectiveSize(StringRef, SMLoc); + bool ParseDirectivePrevious(StringRef, SMLoc); }; } @@ -59,6 +129,159 @@ bool ELFAsmParser::ParseSectionSwitch(StringRef Section, unsigned Type, 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; +} + +// FIXME: This is a work in progress. +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + // FIXME: This doesn't parse section names like ".note.GNU-stack" correctly. + if (getParser().ParseIdentifier(SectionName)) + return TokError("expected identifier in directive"); + + std::string FlagsStr; + StringRef TypeName; + int64_t Size = 0; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + FlagsStr = getTok().getStringContents(); + Lex(); + + AsmToken::TokenKind TypeStartToken; + if (getContext().getAsmInfo().getCommentString()[0] == '@') + TypeStartToken = AsmToken::Percent; + else + TypeStartToken = AsmToken::At; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (getLexer().is(TypeStartToken)) { + Lex(); + if (getParser().ParseIdentifier(TypeName)) + return TokError("expected identifier in directive"); + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getParser().ParseAbsoluteExpression(Size)) + return true; + + if (Size <= 0) + return TokError("section size must be positive"); + } + } + } + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + unsigned Flags = 0; + for (unsigned i = 0; i < FlagsStr.size(); i++) { + switch (FlagsStr[i]) { + case 'a': + Flags |= MCSectionELF::SHF_ALLOC; + break; + case 'x': + Flags |= MCSectionELF::SHF_EXECINSTR; + break; + case 'w': + Flags |= MCSectionELF::SHF_WRITE; + break; + case 'M': + Flags |= MCSectionELF::SHF_MERGE; + break; + case 'S': + Flags |= MCSectionELF::SHF_STRINGS; + break; + case 'T': + Flags |= MCSectionELF::SHF_TLS; + break; + case 'c': + Flags |= MCSectionELF::XCORE_SHF_CP_SECTION; + break; + case 'd': + Flags |= MCSectionELF::XCORE_SHF_DP_SECTION; + break; + default: + return TokError("unknown flag"); + } + } + + unsigned Type = MCSectionELF::SHT_NULL; + if (!TypeName.empty()) { + if (TypeName == "init_array") + Type = MCSectionELF::SHT_INIT_ARRAY; + else if (TypeName == "fini_array") + Type = MCSectionELF::SHT_FINI_ARRAY; + else if (TypeName == "preinit_array") + Type = MCSectionELF::SHT_PREINIT_ARRAY; + else if (TypeName == "nobits") + Type = MCSectionELF::SHT_NOBITS; + else if (TypeName == "progbits") + Type = MCSectionELF::SHT_PROGBITS; + else + return TokError("unknown section type"); + } + + SectionKind Kind = (Flags & MCSectionELF::SHF_EXECINSTR) + ? SectionKind::getText() + : SectionKind::getDataRel(); + getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type, + Flags, Kind, false)); + return false; +} + +bool ELFAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { + int64_t Value; + if (getParser().ParseAbsoluteExpression(Value)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + // FIXME: Add proper MC support. + if (getContext().getAsmInfo().hasLEB128()) { + if (DirName[1] == 's') + getStreamer().EmitRawText("\t.sleb128\t" + Twine(Value)); + else + getStreamer().EmitRawText("\t.uleb128\t" + Twine(Value)); + return false; + } + // FIXME: This shouldn't be an error! + return TokError("LEB128 not supported yet"); +} + +bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { + const MCSection *PreviousSection = getStreamer().getPreviousSection(); + if (PreviousSection != NULL) + getStreamer().SwitchSection(PreviousSection); + + return false; +} + namespace llvm { MCAsmParserExtension *createELFAsmParser() { diff --git a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp index bee3064..70295ef 100644 --- a/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/MCAsmParser.cpp @@ -12,19 +12,26 @@ #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/Support/SourceMgr.h" +#include "llvm/Target/TargetAsmParser.h" using namespace llvm; -MCAsmParser::MCAsmParser() { +MCAsmParser::MCAsmParser() : TargetParser(0), ShowParsedOperands(0) { } MCAsmParser::~MCAsmParser() { } +void MCAsmParser::setTargetParser(TargetAsmParser &P) { + assert(!TargetParser && "Target parser is already initialized!"); + TargetParser = &P; + TargetParser->Initialize(*this); +} + const AsmToken &MCAsmParser::getTok() { return getLexer().getTok(); } -bool MCAsmParser::TokError(const char *Msg) { +bool MCAsmParser::TokError(const Twine &Msg) { Error(getLexer().getLoc(), Msg); return true; } @@ -34,8 +41,4 @@ bool MCAsmParser::ParseExpression(const MCExpr *&Res) { return ParseExpression(Res, L); } -/// getStartLoc - Get the location of the first token of this operand. -SMLoc MCParsedAsmOperand::getStartLoc() const { return SMLoc(); } -SMLoc MCParsedAsmOperand::getEndLoc() const { return SMLoc(); } - diff --git a/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp b/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp index 05760c9..8d43c21 100644 --- a/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp +++ b/contrib/llvm/lib/MC/MCParser/TargetAsmParser.cpp @@ -11,7 +11,7 @@ using namespace llvm; TargetAsmParser::TargetAsmParser(const Target &T) - : TheTarget(T) + : TheTarget(T), AvailableFeatures(0) { } diff --git a/contrib/llvm/lib/MC/MCStreamer.cpp b/contrib/llvm/lib/MC/MCStreamer.cpp index 573f2a3..3e9d02e 100644 --- a/contrib/llvm/lib/MC/MCStreamer.cpp +++ b/contrib/llvm/lib/MC/MCStreamer.cpp @@ -15,7 +15,8 @@ #include <cstdlib> using namespace llvm; -MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context), CurSection(0) { +MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurSection(0), + PrevSection(0) { } MCStreamer::~MCStreamer() { diff --git a/contrib/llvm/lib/MC/MachObjectWriter.cpp b/contrib/llvm/lib/MC/MachObjectWriter.cpp index 7ca0951..cffabfa 100644 --- a/contrib/llvm/lib/MC/MachObjectWriter.cpp +++ b/contrib/llvm/lib/MC/MachObjectWriter.cpp @@ -769,7 +769,7 @@ public: IsPCRel = 1; FixedValue = (FixupAddress - Layout.getSymbolAddress(SD_B) + Target.getConstant()); - FixedValue += 1 << Log2Size; + FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } diff --git a/contrib/llvm/lib/MC/Makefile b/contrib/llvm/lib/MC/Makefile index a661fa6..bf8b7c0 100644 --- a/contrib/llvm/lib/MC/Makefile +++ b/contrib/llvm/lib/MC/Makefile @@ -10,7 +10,7 @@ LEVEL = ../.. LIBRARYNAME = LLVMMC BUILD_ARCHIVE := 1 -PARALLEL_DIRS := MCParser +PARALLEL_DIRS := MCParser MCDisassembler include $(LEVEL)/Makefile.common diff --git a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp index 6804766..eeb2b96 100644 --- a/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp +++ b/contrib/llvm/lib/MC/WinCOFFObjectWriter.cpp @@ -12,41 +12,552 @@ //===----------------------------------------------------------------------===// #define DEBUG_TYPE "WinCOFFObjectWriter" + #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCValue.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmLayout.h" +#include "llvm/MC/MCSectionCOFF.h" + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +#include "llvm/Support/COFF.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" + +#include "llvm/System/TimeValue.h" + +#include "../Target/X86/X86FixupKinds.h" + +#include <cstdio> + using namespace llvm; namespace { +typedef llvm::SmallString<COFF::NameSize> name; + +enum AuxiliaryType { + ATFunctionDefinition, + ATbfAndefSymbol, + ATWeakExternal, + ATFile, + ATSectionDefinition +}; + +struct AuxSymbol { + AuxiliaryType AuxType; + COFF::Auxiliary Aux; +}; + +class COFFSymbol { +public: + COFF::symbol Data; + + typedef llvm::SmallVector<AuxSymbol, 1> AuxiliarySymbols; + + name Name; + size_t Index; + AuxiliarySymbols Aux; + COFFSymbol *Other; + + MCSymbolData const *MCData; + + COFFSymbol(llvm::StringRef name, size_t index); + size_t size() const; + void set_name_offset(uint32_t Offset); +}; + +// 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; + size_t Number; + MCSectionData const *MCData; + COFFSymbol *Symb; + relocations Relocations; + + COFFSection(llvm::StringRef name, size_t Index); + static size_t size(); +}; + +// This class holds the COFF string table. +class StringTable { + typedef llvm::StringMap<size_t> map; + map Map; + + void update_length(); +public: + std::vector<char> Data; + + StringTable(); + size_t size() const; + size_t insert(llvm::StringRef String); +}; + +class WinCOFFObjectWriter : public MCObjectWriter { +public: + + typedef std::vector<COFFSymbol*> symbols; + typedef std::vector<COFFSection*> sections; + + typedef StringMap<COFFSymbol *> name_symbol_map; + typedef StringMap<COFFSection *> name_section_map; + + typedef DenseMap<MCSymbolData const *, COFFSymbol *> symbol_map; + typedef DenseMap<MCSectionData const *, COFFSection *> section_map; + + // Root level file contents. + bool Is64Bit; + COFF::header Header; + sections Sections; + symbols Symbols; + StringTable Strings; + + // Maps used during object file creation. + section_map SectionMap; + symbol_map SymbolMap; + + WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit); + ~WinCOFFObjectWriter(); + + COFFSymbol *createSymbol(llvm::StringRef Name); + COFFSection *createSection(llvm::StringRef Name); + + void InitCOFFEntity(COFFSymbol &Symbol); + void InitCOFFEntity(COFFSection &Section); + + template <typename object_t, typename list_t> + object_t *createCOFFEntity(llvm::StringRef Name, list_t &List); + + void DefineSection(MCSectionData const &SectionData); + void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler); + + bool ExportSection(COFFSection *S); + bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm); + + // 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); + + void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue); + + void WriteObject(const 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; +} + +static inline void write_uint16_le(void *Data, uint16_t const &Value) { + uint8_t *Ptr = reinterpret_cast<uint8_t *>(Data); + Ptr[0] = (Value & 0x00FF) >> 0; + Ptr[1] = (Value & 0xFF00) >> 8; +} + +static inline void write_uint8_le(void *Data, uint8_t const &Value) { + uint8_t *Ptr = reinterpret_cast<uint8_t *>(Data); + Ptr[0] = (Value & 0xFF) >> 0; +} - class WinCOFFObjectWriter : public MCObjectWriter { - public: - WinCOFFObjectWriter(raw_ostream &OS); +//------------------------------------------------------------------------------ +// Symbol class implementation + +COFFSymbol::COFFSymbol(llvm::StringRef name, size_t index) + : Name(name.begin(), name.end()), Index(-1) + , Other(NULL), 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); +} + +//------------------------------------------------------------------------------ +// Section class implementation + +COFFSection::COFFSection(llvm::StringRef name, size_t Index) + : Name(name), Number(Index + 1) + , MCData(NULL), Symb(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); +} + +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(llvm::StringRef String) { + map::iterator i = Map.find(String); + + if (i != Map.end()) + return i->second; + + size_t Offset = Data.size(); - // MCObjectWriter interface implementation. + // Insert string data into string table. + Data.insert(Data.end(), String.begin(), String.end()); + Data.push_back('\0'); - void ExecutePostLayoutBinding(MCAssembler &Asm); + // Put a reference to it in the map. + Map[String] = Offset; - void RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, - MCValue Target, - uint64_t &FixedValue); + // Update the internal length field. + update_length(); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); - }; + return Offset; } -WinCOFFObjectWriter::WinCOFFObjectWriter(raw_ostream &OS) - : MCObjectWriter(OS, true) { +//------------------------------------------------------------------------------ +// WinCOFFObjectWriter class implementation + +WinCOFFObjectWriter::WinCOFFObjectWriter(raw_ostream &OS, bool is64Bit) + : MCObjectWriter(OS, true) + , Is64Bit(is64Bit) { + memset(&Header, 0, sizeof(Header)); + + Is64Bit ? Header.Machine = COFF::IMAGE_FILE_MACHINE_AMD64 + : Header.Machine = COFF::IMAGE_FILE_MACHINE_I386; +} + +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(llvm::StringRef Name) { + return createCOFFEntity<COFFSymbol>(Name, Symbols); +} + +COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) { + return createCOFFEntity<COFFSection>(Name, Sections); +} + +/// This function initializes a symbol by entering its name into the string +/// table if it is too long to fit in the symbol table header. +void WinCOFFObjectWriter::InitCOFFEntity(COFFSymbol &S) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + S.set_name_offset(StringTableEntry); + } else + memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); +} + +/// This function initializes a section by entering its name into the string +/// table if it is too long to fit in the section table header. +void WinCOFFObjectWriter::InitCOFFEntity(COFFSection &S) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); + + // FIXME: Why is this number 999999? This number is never mentioned in the + // spec. I'm assuming this is due to the printed value needing to fit into + // the S.Header.Name field. In which case why not 9999999 (7 9's instead of + // 6)? The spec does not state if this entry should be null terminated in + // this case, and thus this seems to be the best way to do it. I think I + // just solved my own FIXME... + if (StringTableEntry > 999999) + report_fatal_error("COFF string table is greater than 999999 bytes."); + + sprintf(S.Header.Name, "/%d", (unsigned)StringTableEntry); + } else + memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); +} + +/// 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(llvm::StringRef Name, + list_t &List) { + object_t *Object = new object_t(Name, List.size()); + + InitCOFFEntity(*Object); + + 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) { + // 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->Symb = coff_symbol; + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_STATIC; + coff_symbol->Data.SectionNumber = coff_section->Number; + + // 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.Number = coff_section->Number; + 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] = 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) { + COFFSymbol *coff_symbol = createSymbol(SymbolData.getSymbol().getName()); + + coff_symbol->Data.Type = (SymbolData.getFlags() & 0x0000FFFF) >> 0; + coff_symbol->Data.StorageClass = (SymbolData.getFlags() & 0x00FF0000) >> 16; + + // If no storage class was specified in the streamer, define it here. + if (coff_symbol->Data.StorageClass == 0) { + bool external = SymbolData.isExternal() || (SymbolData.Fragment == NULL); + + coff_symbol->Data.StorageClass = + external ? COFF::IMAGE_SYM_CLASS_EXTERNAL : COFF::IMAGE_SYM_CLASS_STATIC; + } + + if (SymbolData.getFlags() & COFF::SF_WeakReference) { + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + + const MCExpr *Value = SymbolData.getSymbol().getVariableValue(); + + // FIXME: This assert message isn't very good. + assert(Value->getKind() == MCExpr::SymbolRef && + "Value must be a SymbolRef!"); + + const MCSymbolRefExpr *SymbolRef = + static_cast<const MCSymbolRefExpr *>(Value); + + const MCSymbolData &OtherSymbolData = + Assembler.getSymbolData(SymbolRef->getSymbol()); + + // FIXME: This assert message isn't very good. + assert(SymbolMap.find(&OtherSymbolData) != SymbolMap.end() && + "OtherSymbolData must be in the symbol map!"); + + coff_symbol->Other = SymbolMap[&OtherSymbolData]; + + // 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; + } + + // Bind internal COFF symbol to MC symbol. + coff_symbol->MCData = &SymbolData; + SymbolMap[&SymbolData] = coff_symbol; +} + +bool WinCOFFObjectWriter::ExportSection(COFFSection *S) { + return (S->Header.Characteristics + & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; +} + +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 symbols are exported, the linker will sort it out for us. + return true; +} + +//------------------------------------------------------------------------------ +// 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) { + // "Define" each section & symbol. This creates section & symbol + // entries in the staging area and gives them their final indexes. + + 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); + } } void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, @@ -55,17 +566,209 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { + assert(Target.getSymA() != NULL && "Relocation must reference a symbol!"); + + const MCSymbol *A = &Target.getSymA()->getSymbol(); + 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) != SectionMap.end() && + "Section must already have been defined in ExecutePostLayoutBinding!"); + assert(SymbolMap.find(&A_SD) != SymbolMap.end() && + "Symbol must already have been defined in ExecutePostLayoutBinding!"); + + COFFSection *coff_section = SectionMap[SectionData]; + COFFSymbol *coff_symbol = SymbolMap[&A_SD]; + + if (Target.getSymB()) { + const MCSymbol *B = &Target.getSymB()->getSymbol(); + MCSymbolData &B_SD = Asm.getSymbolData(*B); + + FixedValue = Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(&B_SD); + + // 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. + return; + } else { + FixedValue = Target.getConstant(); + } + + COFFRelocation Reloc; + + Reloc.Data.SymbolTableIndex = 0; + Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); + Reloc.Symb = coff_symbol; + + Reloc.Data.VirtualAddress += Fixup.getOffset(); + + switch (Fixup.getKind()) { + case X86::reloc_pcrel_4byte: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32 + : COFF::IMAGE_REL_I386_REL32; + // FIXME: Can anyone explain what this does other than adjust for the size + // of the offset? + FixedValue += 4; + break; + case FK_Data_4: + Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32 + : COFF::IMAGE_REL_I386_DIR32; + break; + case FK_Data_8: + if (Is64Bit) + Reloc.Data.Type = COFF::IMAGE_REL_AMD64_ADDR64; + else + llvm_unreachable("unsupported relocation type"); + break; + default: + llvm_unreachable("unsupported relocation type"); + } + + coff_section->Relocations.push_back(Reloc); } void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { + // Assign symbol and section indexes and offsets. + + 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; + + coff_symbol->Index = Header.NumberOfSymbols++; + + // Update section number & offset for symbols that have them. + if ((SymbolData != NULL) && (SymbolData->Fragment != NULL)) { + COFFSection *coff_section = SectionMap[SymbolData->Fragment->getParent()]; + + coff_symbol->Data.SectionNumber = coff_section->Number; + coff_symbol->Data.Value = Layout.getFragmentOffset(SymbolData->Fragment) + + SymbolData->Offset; + } + + // Update auxiliary symbol info. + coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); + Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + } + + // Fixup weak external references. + for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { + COFFSymbol *symb = *i; + + if (symb->Other != NULL) { + assert(symb->Aux.size() == 1 && + "Symbol must contain one aux symbol!"); + assert(symb->Aux[0].AuxType == ATWeakExternal && + "Symbol's aux symbol must be a Weak External!"); + symb->Aux[0].Aux.WeakExternal.TagIndex = symb->Other->Index; + } + } + + // Assign file offsets to COFF object file structures. + + unsigned offset = 0; + + offset += COFF::HeaderSize; + offset += COFF::SectionSize * Asm.size(); + + Header.NumberOfSections = Sections.size(); + + for (MCAssembler::const_iterator i = Asm.begin(), + e = Asm.end(); + i != e; i++) { + COFFSection *Sec = SectionMap[i]; + + Sec->Header.SizeOfRawData = Layout.getSectionFileSize(i); + + if (ExportSection(Sec)) { + Sec->Header.PointerToRawData = offset; + + offset += Sec->Header.SizeOfRawData; + } + + if (Sec->Relocations.size() > 0) { + Sec->Header.NumberOfRelocations = Sec->Relocations.size(); + Sec->Header.PointerToRelocations = offset; + + offset += COFF::RelocationSize * Sec->Relocations.size(); + + for (relocations::iterator cr = Sec->Relocations.begin(), + er = Sec->Relocations.end(); + cr != er; cr++) { + (*cr).Data.SymbolTableIndex = (*cr).Symb->Index; + } + } + + assert(Sec->Symb->Aux.size() == 1 && "Section's symbol must have one aux!"); + AuxSymbol &Aux = Sec->Symb->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++) + WriteSectionHeader((*i)->Header); + + for (i = Sections.begin(), ie = Sections.end(), + j = Asm.begin(), je = Asm.end(); + (i != ie) && (j != je); i++, j++) { + if ((*i)->Header.PointerToRawData != 0) { + assert(OS.tell() == (*i)->Header.PointerToRawData && + "Section::PointerToRawData is insane!"); + + Asm.WriteSectionData(j, Layout, this); + } + + if ((*i)->Relocations.size() > 0) { + assert(OS.tell() == (*i)->Header.PointerToRelocations && + "Section::PointerToRelocations is insane!"); + + 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++) + WriteSymbol(*i); + + OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); } //------------------------------------------------------------------------------ // WinCOFFObjectWriter factory function namespace llvm { - MCObjectWriter *createWinCOFFObjectWriter(raw_ostream &OS) { - return new WinCOFFObjectWriter(OS); + MCObjectWriter *createWinCOFFObjectWriter(raw_ostream &OS, bool is64Bit) { + return new WinCOFFObjectWriter(OS, is64Bit); } } diff --git a/contrib/llvm/lib/MC/WinCOFFStreamer.cpp b/contrib/llvm/lib/MC/WinCOFFStreamer.cpp index 1030cdb..8a194bf 100644 --- a/contrib/llvm/lib/MC/WinCOFFStreamer.cpp +++ b/contrib/llvm/lib/MC/WinCOFFStreamer.cpp @@ -18,27 +18,34 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCValue.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCSectionCOFF.h" +#include "llvm/Target/TargetRegistry.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/ADT/StringMap.h" + #include "llvm/Support/COFF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; -#define dbg_notimpl(x) \ - do { dbgs() << "not implemented, " << __FUNCTION__ << " (" << x << ")"; \ - abort(); } while (false); - namespace { class WinCOFFStreamer : public MCObjectStreamer { public: + MCSymbol const *CurSymbol; + WinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, raw_ostream &OS); + void AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment, bool External); + // MCStreamer interface virtual void EmitLabel(MCSymbol *Symbol); @@ -52,18 +59,18 @@ public: virtual void EndCOFFSymbolDef(); virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment); + unsigned ByteAlignment); virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - unsigned Size,unsigned ByteAlignment); + unsigned Size,unsigned ByteAlignment); virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, - uint64_t Size, unsigned ByteAlignment); + uint64_t Size, unsigned ByteAlignment); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size, + virtual void EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace); virtual void EmitGPRel32Value(const MCExpr *Value); virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, - unsigned ValueSize, unsigned MaxBytesToEmit); + unsigned ValueSize, unsigned MaxBytesToEmit); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit); virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value); @@ -78,96 +85,224 @@ WinCOFFStreamer::WinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, raw_ostream &OS) - : MCObjectStreamer(Context, TAB, OS, &CE) { + : MCObjectStreamer(Context, TAB, 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, Selection, SectionKind::getBSS()); + + MCSectionData &SectionData = getAssembler().getOrCreateSectionData(*Section); + + if (SectionData.getAlignment() < ByteAlignment) + SectionData.setAlignment(ByteAlignment); + + SymbolData.setExternal(External); + + Symbol->setSection(*Section); + + if (ByteAlignment != 1) + new MCAlignFragment(ByteAlignment, 0, 0, ByteAlignment, &SectionData); + + SymbolData.setFragment(new MCFillFragment(0, 0, Size, &SectionData)); } // MCStreamer interface void WinCOFFStreamer::EmitLabel(MCSymbol *Symbol) { + // TODO: This is copied almost exactly from the MachOStreamer. Consider + // merging into MCObjectStreamer? + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(CurSection && "Cannot emit before setting section!"); + + Symbol->setSection(*CurSection); + + 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 *DF = getOrCreateDataFragment(); + + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(DF); + SD.setOffset(DF->getContents().size()); } void WinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { - dbg_notimpl("Flag = " << Flag); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as MachOStreamer. Consider merging into + // MCObjectStreamer. + getAssembler().getOrCreateSymbolData(*Symbol); + AddValueSymbols(Value); + Symbol->setVariableValue(Value); } void WinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + switch (Attribute) { + case MCSA_WeakReference: + getAssembler().getOrCreateSymbolData(*Symbol).modifyFlags( + COFF::SF_WeakReference, + COFF::SF_WeakReference); + break; + + case MCSA_Global: + getAssembler().getOrCreateSymbolData(*Symbol).setExternal(true); + break; + + default: + llvm_unreachable("unsupported attribute"); + break; + } } void WinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { - dbg_notimpl("Symbol = " << Symbol->getName() << ", DescValue = "<< DescValue); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) { + 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::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { - dbg_notimpl("Symbol = " << Symbol->getName() << ", Value = " << *Value); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, - unsigned ByteAlignment) { + unsigned ByteAlignment) { + AddCommonSymbol(Symbol, Size, ByteAlignment, true); } void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + AddCommonSymbol(Symbol, Size, 1, false); } void WinCOFFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, - unsigned Size,unsigned ByteAlignment) { - MCSectionCOFF const *SectionCOFF = - static_cast<MCSectionCOFF const *>(Section); - - dbg_notimpl("Section = " << SectionCOFF->getSectionName() << ", Symbol = " << - Symbol->getName() << ", Size = " << Size << ", ByteAlignment = " - << ByteAlignment); + unsigned Size,unsigned ByteAlignment) { + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { - MCSectionCOFF const *SectionCOFF = - static_cast<MCSectionCOFF const *>(Section); - - dbg_notimpl("Section = " << SectionCOFF->getSectionName() << ", Symbol = " << - Symbol->getName() << ", Size = " << Size << ", ByteAlignment = " - << ByteAlignment); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } void WinCOFFStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { + unsigned AddrSpace) { + assert(AddrSpace == 0 && "Address space must be 0!"); + + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { + // FIXME: Endianness assumption. + for (unsigned i = 0; i != Size; ++i) + DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); + } else { + DF->addFixup(MCFixup::Create(DF->getContents().size(), + AddValueSymbols(Value), + MCFixup::getKindForSize(Size))); + DF->getContents().resize(DF->getContents().size() + Size, 0); + } } void WinCOFFStreamer::EmitGPRel32Value(const MCExpr *Value) { - dbg_notimpl("Value = '" << *Value); + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitValueToAlignment(unsigned ByteAlignment, - int64_t Value, - unsigned ValueSize, - unsigned MaxBytesToEmit) { + int64_t Value, + unsigned ValueSize, + unsigned MaxBytesToEmit) { + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, + getCurrentSectionData()); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); } void WinCOFFStreamer::EmitCodeAlignment(unsigned ByteAlignment, - unsigned MaxBytesToEmit = 0) { + unsigned MaxBytesToEmit) { + // TODO: This is copied exactly from the MachOStreamer. Consider merging into + // MCObjectStreamer? + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, + getCurrentSectionData()); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); } void WinCOFFStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0) { - dbg_notimpl("Offset = '" << *Offset << "', Value = " << Value); + unsigned char Value) { + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { @@ -176,11 +311,24 @@ void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { } void WinCOFFStreamer::EmitDwarfFileDirective(unsigned FileNo, - StringRef Filename) { - dbg_notimpl("FileNo = " << FileNo << ", Filename = '" << Filename << "'"); + StringRef Filename) { + llvm_unreachable("not implemented"); } void WinCOFFStreamer::EmitInstruction(const MCInst &Instruction) { + for (unsigned i = 0, e = Instruction.getNumOperands(); i != e; ++i) + if (Instruction.getOperand(i).isExpr()) + AddValueSymbols(Instruction.getOperand(i).getExpr()); + + getCurrentSectionData()->setHasInstructions(true); + + MCInstFragment *Fragment = + new MCInstFragment(Instruction, getCurrentSectionData()); + + raw_svector_ostream VecOS(Fragment->getCode()); + + getAssembler().getEmitter().EncodeInstruction(Instruction, VecOS, + Fragment->getFixups()); } void WinCOFFStreamer::Finish() { @@ -192,7 +340,10 @@ namespace llvm MCStreamer *createWinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, - raw_ostream &OS) { - return new WinCOFFStreamer(Context, TAB, CE, OS); + raw_ostream &OS, + bool RelaxAll) { + WinCOFFStreamer *S = new WinCOFFStreamer(Context, TAB, CE, OS); + S->getAssembler().setRelaxAll(RelaxAll); + return S; } } |