diff options
Diffstat (limited to 'lib/MC')
41 files changed, 6651 insertions, 2590 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 60a3a3e..f1811a1 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -8,6 +8,7 @@ add_llvm_library(LLVMMC MCCodeEmitter.cpp MCContext.cpp MCDisassembler.cpp + MCELFObjectTargetWriter.cpp MCELFStreamer.cpp MCExpr.cpp MCInst.cpp @@ -16,9 +17,11 @@ add_llvm_library(LLVMMC MCDwarf.cpp MCLoggingStreamer.cpp MCMachOStreamer.cpp + MCMachObjectTargetWriter.cpp MCNullStreamer.cpp MCObjectStreamer.cpp MCObjectWriter.cpp + MCPureStreamer.cpp MCSection.cpp MCSectionCOFF.cpp MCSectionELF.cpp @@ -31,3 +34,6 @@ add_llvm_library(LLVMMC WinCOFFObjectWriter.cpp TargetAsmBackend.cpp ) + +add_subdirectory(MCParser) +add_subdirectory(MCDisassembler) diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index cf35b45..8a00a16 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -11,7 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/ELFObjectWriter.h" +#include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" @@ -20,6 +21,7 @@ #include "llvm/MC/MCContext.h" #include "llvm/MC/MCELFSymbolFlags.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCELFObjectWriter.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" @@ -28,27 +30,76 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ELF.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/ADT/StringSwitch.h" #include "../Target/X86/X86FixupKinds.h" +#include "../Target/ARM/ARMFixupKinds.h" #include <vector> using namespace llvm; -namespace { +static unsigned GetType(const MCSymbolData &SD) { + uint32_t Type = (SD.getFlags() & (0xf << ELF_STT_Shift)) >> ELF_STT_Shift; + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_FILE || Type == ELF::STT_COMMON || + Type == ELF::STT_TLS); + return Type; +} - 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 unsigned GetBinding(const MCSymbolData &SD) { + uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + return Binding; +} + +static void SetBinding(MCSymbolData &SD, unsigned Binding) { + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); + SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); +} +static unsigned GetVisibility(MCSymbolData &SD) { + unsigned Visibility = + (SD.getFlags() & (0xf << ELF_STV_Shift)) >> ELF_STV_Shift; + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + return Visibility; +} + + +static bool RelocNeedsGOT(MCSymbolRefExpr::VariantKind Variant) { + switch (Variant) { + default: + return false; + case MCSymbolRefExpr::VK_GOT: + case MCSymbolRefExpr::VK_PLT: + case MCSymbolRefExpr::VK_GOTPCREL: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_INDNTPOFF: + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_TLSLD: + return true; + } +} + +static bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { + const MCFixupKindInfo &FKI = + Asm.getBackend().getFixupKindInfo((MCFixupKind) Kind); + + return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; +} + +namespace { + class ELFObjectWriter : public MCObjectWriter { + protected: /*static bool isFixupKindX86RIPRel(unsigned Kind) { return Kind == X86::reloc_riprel_4byte || Kind == X86::reloc_riprel_4byte_movq_load; @@ -64,6 +115,10 @@ namespace { // Support lexicographic sorting. bool operator<(const ELFSymbolData &RHS) const { + if (GetType(*SymbolData) == ELF::STT_FILE) + return true; + if (GetType(*RHS.SymbolData) == ELF::STT_FILE) + return false; return SymbolData->getSymbol().getName() < RHS.SymbolData->getSymbol().getName(); } @@ -75,15 +130,33 @@ namespace { struct ELFRelocationEntry { // Make these big enough for both 32-bit and 64-bit uint64_t r_offset; - uint64_t r_info; + int Index; + unsigned Type; + const MCSymbol *Symbol; uint64_t r_addend; + ELFRelocationEntry() + : r_offset(0), Index(0), Type(0), Symbol(0), r_addend(0) {} + + ELFRelocationEntry(uint64_t RelocOffset, int Idx, + unsigned RelType, const MCSymbol *Sym, + uint64_t Addend) + : r_offset(RelocOffset), Index(Idx), Type(RelType), + Symbol(Sym), r_addend(Addend) {} + // Support lexicographic sorting. bool operator<(const ELFRelocationEntry &RE) const { return RE.r_offset < r_offset; } }; + /// The target specific ELF writer instance. + llvm::OwningPtr<MCELFObjectTargetWriter> TargetObjectWriter; + + SmallPtrSet<const MCSymbol *, 16> UsedInReloc; + SmallPtrSet<const MCSymbol *, 16> WeakrefUsedInReloc; + DenseMap<const MCSymbol *, const MCSymbol *> Renames; + llvm::DenseMap<const MCSectionData*, std::vector<ELFRelocationEntry> > Relocations; DenseMap<const MCSection*, uint64_t> SectionStringTableIndex; @@ -99,49 +172,52 @@ namespace { /// @} - ELFObjectWriter *Writer; - - raw_ostream &OS; - - // This holds the current offset into the object file. - size_t FileOff; - - unsigned Is64Bit : 1; + bool NeedsGOT; - bool HasRelocationAddend; + bool NeedsSymtabShndx; // This holds the symbol table index of the last local symbol. unsigned LastLocalSymbolIndex; // This holds the .strtab section index. unsigned StringTableIndex; + // This holds the .symtab section index. + unsigned SymbolTableIndex; unsigned ShstrtabIndex; + + const MCSymbol *SymbolToReloc(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F) const; + + // For arch-specific emission of explicit reloc symbol + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const { + return NULL; + } + + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool hasRelocationAddend() const { + return TargetObjectWriter->hasRelocationAddend(); + } + public: - ELFObjectWriterImpl(ELFObjectWriter *_Writer, bool _Is64Bit, - bool _HasRelAddend) - : Writer(_Writer), OS(Writer->getStream()), FileOff(0), - Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend) { + ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, bool IsLittleEndian) + : MCObjectWriter(_OS, IsLittleEndian), + TargetObjectWriter(MOTW), + NeedsGOT(false), NeedsSymtabShndx(false){ } - 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); - //} + virtual ~ELFObjectWriter(); void WriteWord(uint64_t W) { - if (Is64Bit) - Writer->Write64(W); + if (is64Bit()) + Write64(W); else - Writer->Write32(W); - } - - void String8(char *buf, uint8_t Value) { - buf[0] = Value; + Write32(W); } void StringLE16(char *buf, uint16_t Value) { @@ -174,86 +250,191 @@ namespace { StringBE32(buf + 4, uint32_t(Value >> 0)); } - void String16(char *buf, uint16_t Value) { - if (Writer->isLittleEndian()) + void String8(MCDataFragment &F, uint8_t Value) { + char buf[1]; + buf[0] = Value; + F.getContents() += StringRef(buf, 1); + } + + void String16(MCDataFragment &F, uint16_t Value) { + char buf[2]; + if (isLittleEndian()) StringLE16(buf, Value); else StringBE16(buf, Value); + F.getContents() += StringRef(buf, 2); } - void String32(char *buf, uint32_t Value) { - if (Writer->isLittleEndian()) + void String32(MCDataFragment &F, uint32_t Value) { + char buf[4]; + if (isLittleEndian()) StringLE32(buf, Value); else StringBE32(buf, Value); + F.getContents() += StringRef(buf, 4); } - void String64(char *buf, uint64_t Value) { - if (Writer->isLittleEndian()) + void String64(MCDataFragment &F, uint64_t Value) { + char buf[8]; + if (isLittleEndian()) StringLE64(buf, Value); else StringBE64(buf, Value); + F.getContents() += StringRef(buf, 8); } - void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); + virtual void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections); + + /// Default e_flags = 0 + virtual void WriteEFlags() { Write32(0); } - void WriteSymbolEntry(MCDataFragment *F, uint64_t name, uint8_t info, + virtual void WriteSymbolEntry(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + uint64_t name, uint8_t info, uint64_t value, uint64_t size, - uint8_t other, uint16_t shndx); + uint8_t other, uint32_t shndx, + bool Reserved); - void WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, + virtual void WriteSymbol(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + ELFSymbolData &MSD, const MCAsmLayout &Layout); - void WriteSymbolTable(MCDataFragment *F, const MCAssembler &Asm, - const MCAsmLayout &Layout); + typedef DenseMap<const MCSectionELF*, uint32_t> SectionIndexMapTy; + virtual void WriteSymbolTable(MCDataFragment *SymtabF, MCDataFragment *ShndxF, + const MCAssembler &Asm, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap); - void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue); + virtual void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue); - uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, + virtual uint64_t getSymbolIndexInSymbolTable(const MCAssembler &Asm, const MCSymbol *S); + // Map from a group section to the signature symbol + typedef DenseMap<const MCSectionELF*, const MCSymbol*> GroupMapTy; + // Map from a signature symbol to the group section + typedef DenseMap<const MCSymbol*, const MCSectionELF*> RevGroupMapTy; + /// 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); + virtual void ComputeSymbolTable(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + RevGroupMapTy RevGroupMap); - void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + virtual void ComputeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap); + + virtual void WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, const MCSectionData &SD); - void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) { + virtual 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); + virtual void CreateMetadataSections(MCAssembler &Asm, MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap); - void ExecutePostLayoutBinding(MCAssembler &Asm) { - // Compute symbol table information. - ComputeSymbolTable(Asm); - } + // Create the sections that show up in the symbol table. Currently + // those are the .note.GNU-stack section and the group sections. + virtual void CreateIndexedSections(MCAssembler &Asm, MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap); - void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, + virtual void ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout); + + virtual void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, uint64_t Address, uint64_t Offset, uint64_t Size, uint32_t Link, uint32_t Info, uint64_t Alignment, uint64_t EntrySize); - void WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F, - const MCSectionData *SD); + virtual void WriteRelocationsFragment(const MCAssembler &Asm, + MCDataFragment *F, + const MCSectionData *SD); + + virtual void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); + virtual void WriteSection(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, + uint64_t Offset, uint64_t Size, uint64_t Alignment, + const MCSectionELF &Section); + + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend) = 0; + }; + + //===- X86ELFObjectWriter -------------------------------------------===// + + class X86ELFObjectWriter : public ELFObjectWriter { + public: + X86ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian); + + virtual ~X86ELFObjectWriter(); + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend); + }; + + + //===- ARMELFObjectWriter -------------------------------------------===// + + class ARMELFObjectWriter : public ELFObjectWriter { + public: + // FIXME: MCAssembler can't yet return the Subtarget, + enum { DefaultEABIVersion = 0x05000000U }; + + ARMELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + virtual ~ARMELFObjectWriter(); + + virtual void WriteEFlags(); + protected: + virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const; + + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend); }; + //===- MBlazeELFObjectWriter -------------------------------------------===// + + class MBlazeELFObjectWriter : public ELFObjectWriter { + public: + MBlazeELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian); + + virtual ~MBlazeELFObjectWriter(); + protected: + virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, + bool IsPCRel, bool IsRelocWithSymbol, + int64_t Addend); + }; } +ELFObjectWriter::~ELFObjectWriter() +{} + // Emit the ELF header. -void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, - unsigned NumberOfSections) { +void ELFObjectWriter::WriteHeader(uint64_t SectionDataSize, + unsigned NumberOfSections) { // ELF Header // ---------- // @@ -267,140 +448,193 @@ void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, Write8('L'); // e_ident[EI_MAG2] Write8('F'); // e_ident[EI_MAG3] - Write8(Is64Bit ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] + Write8(is64Bit() ? ELF::ELFCLASS64 : ELF::ELFCLASS32); // e_ident[EI_CLASS] // e_ident[EI_DATA] - Write8(Writer->isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); + Write8(isLittleEndian() ? ELF::ELFDATA2LSB : ELF::ELFDATA2MSB); Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION] - Write8(ELF::ELFOSABI_LINUX); // e_ident[EI_OSABI] + // e_ident[EI_OSABI] + switch (TargetObjectWriter->getOSType()) { + case Triple::FreeBSD: Write8(ELF::ELFOSABI_FREEBSD); break; + case Triple::Linux: Write8(ELF::ELFOSABI_LINUX); break; + default: Write8(ELF::ELFOSABI_NONE); break; + } 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 + Write16(TargetObjectWriter->getEMachine()); // e_machine = target Write32(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file WriteWord(0); // e_phoff, no program header for .o - WriteWord(SectionDataSize + (Is64Bit ? sizeof(ELF::Elf64_Ehdr) : + 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_flags = whatever the target wants + WriteEFlags(); // e_ehsize = ELF header size - Write16(Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr)); + 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)); + Write16(is64Bit() ? sizeof(ELF::Elf64_Shdr) : sizeof(ELF::Elf32_Shdr)); // e_shnum = # of section header ents - Write16(NumberOfSections); + if (NumberOfSections >= ELF::SHN_LORESERVE) + Write16(0); + else + Write16(NumberOfSections); // e_shstrndx = Section # of '.shstrtab' - Write16(ShstrtabIndex); + if (NumberOfSections >= ELF::SHN_LORESERVE) + Write16(ELF::SHN_XINDEX); + else + 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]; +void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + uint64_t name, + uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint32_t shndx, + bool Reserved) { + if (ShndxF) { + if (shndx >= ELF::SHN_LORESERVE && !Reserved) + String32(*ShndxF, shndx); + else + String32(*ShndxF, 0); + } - String32(buf, name); - F->getContents() += StringRef(buf, 4); // st_name + uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ? + uint16_t(ELF::SHN_XINDEX) : shndx; - String8(buf, info); - F->getContents() += StringRef(buf, 1); // st_info + if (is64Bit()) { + String32(*SymtabF, name); // st_name + String8(*SymtabF, info); // st_info + String8(*SymtabF, other); // st_other + String16(*SymtabF, Index); // st_shndx + String64(*SymtabF, value); // st_value + String64(*SymtabF, size); // st_size + } else { + String32(*SymtabF, name); // st_name + String32(*SymtabF, value); // st_value + String32(*SymtabF, size); // st_size + String8(*SymtabF, info); // st_info + String8(*SymtabF, other); // st_other + String16(*SymtabF, Index); // st_shndx + } +} - String8(buf, other); - F->getContents() += StringRef(buf, 1); // st_other +static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout) { + if (Data.isCommon() && Data.isExternal()) + return Data.getCommonAlignment(); - String16(buf, shndx); - F->getContents() += StringRef(buf, 2); // st_shndx + const MCSymbol &Symbol = Data.getSymbol(); - String64(buf, value); - F->getContents() += StringRef(buf, 8); // st_value + if (Symbol.isAbsolute() && Symbol.isVariable()) { + if (const MCExpr *Value = Symbol.getVariableValue()) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, Layout)) + return (uint64_t)IntValue; + } + } - String64(buf, size); - F->getContents() += StringRef(buf, 8); // st_size - } else { - char buf[4]; + if (!Symbol.isInSection()) + return 0; + + if (Data.getFragment()) + return Layout.getSymbolOffset(&Data); + + return 0; +} - String32(buf, name); - F->getContents() += StringRef(buf, 4); // st_name +void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. - String32(buf, value); - F->getContents() += StringRef(buf, 4); // st_value + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Alias = it->getSymbol(); + const MCSymbol &Symbol = Alias.AliasedSymbol(); + MCSymbolData &SD = Asm.getSymbolData(Symbol); + + // Not an alias. + if (&Symbol == &Alias) + continue; + + StringRef AliasName = Alias.getName(); + size_t Pos = AliasName.find('@'); + if (Pos == StringRef::npos) + continue; - String32(buf, size); - F->getContents() += StringRef(buf, 4); // st_size + // Aliases defined with .symvar copy the binding from the symbol they alias. + // This is the first place we are able to copy this information. + it->setExternal(SD.isExternal()); + SetBinding(*it, GetBinding(SD)); - String8(buf, info); - F->getContents() += StringRef(buf, 1); // st_info + StringRef Rest = AliasName.substr(Pos); + if (!Symbol.isUndefined() && !Rest.startswith("@@@")) + continue; - String8(buf, other); - F->getContents() += StringRef(buf, 1); // st_other + // FIXME: produce a better error message. + if (Symbol.isUndefined() && Rest.startswith("@@") && + !Rest.startswith("@@@")) + report_fatal_error("A @@ version cannot be undefined"); - String16(buf, shndx); - F->getContents() += StringRef(buf, 2); // st_shndx + Renames.insert(std::make_pair(&Symbol, &Alias)); } } -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; +void ELFObjectWriter::WriteSymbol(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + ELFSymbolData &MSD, + const MCAsmLayout &Layout) { + MCSymbolData &OrigData = *MSD.SymbolData; + MCSymbolData &Data = + Layout.getAssembler().getSymbolData(OrigData.getSymbol().AliasedSymbol()); + + bool IsReserved = Data.isCommon() || Data.getSymbol().isAbsolute() || + Data.getSymbol().isVariable(); + + uint8_t Binding = GetBinding(OrigData); + uint8_t Visibility = GetVisibility(OrigData); + uint8_t Type = GetType(Data); + + uint8_t Info = (Binding << ELF_STB_Shift) | (Type << ELF_STT_Shift); + uint8_t Other = Visibility; + + uint64_t Value = SymbolValue(Data, Layout); 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"); - } + assert(!(Data.isCommon() && !Data.isExternal())); + + const MCExpr *ESize = Data.getSize(); + if (ESize) { + int64_t Res; + if (!ESize->EvaluateAsAbsolute(Res, Layout)) + report_fatal_error("Size expression must be absolute."); + Size = Res; } // Write out the symbol table entry - WriteSymbolEntry(F, MSD.StringIndex, Info, Value, - Size, Other, MSD.SectionIndex); + WriteSymbolEntry(SymtabF, ShndxF, MSD.StringIndex, Info, Value, + Size, Other, MSD.SectionIndex, IsReserved); } -void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, - const MCAssembler &Asm, - const MCAsmLayout &Layout) { +void ELFObjectWriter::WriteSymbolTable(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + const MCAssembler &Asm, + const MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap) { // The string table must be emitted first because we need the index // into the string table for all the symbol names. assert(StringTable.size() && "Missing string table"); @@ -408,258 +642,343 @@ void ELFObjectWriterImpl::WriteSymbolTable(MCDataFragment *F, // 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'); + WriteSymbolEntry(SymtabF, ShndxF, 0, 0, 0, 0, 0, 0, false); // 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); + WriteSymbol(SymtabF, ShndxF, 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) { + // Write out a symbol table entry for each regular section. + for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; + ++i) { const MCSectionELF &Section = - static_cast<const MCSectionELF&>(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()) + static_cast<const MCSectionELF&>(i->getSection()); + if (Section.getType() == ELF::SHT_RELA || + Section.getType() == ELF::SHT_REL || + Section.getType() == ELF::SHT_STRTAB || + Section.getType() == ELF::SHT_SYMTAB) continue; - WriteSymbolEntry(F, 0, ELF::STT_SECTION, 0, 0, ELF::STV_DEFAULT, Index); + WriteSymbolEntry(SymtabF, ShndxF, 0, ELF::STT_SECTION, 0, 0, + ELF::STV_DEFAULT, SectionIndexMap.lookup(&Section), false); LastLocalSymbolIndex++; } for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) { ELFSymbolData &MSD = ExternalSymbolData[i]; MCSymbolData &Data = *MSD.SymbolData; - assert((Data.getFlags() & ELF_STB_Global) && - "External symbol requires STB_GLOBAL flag"); - WriteSymbol(F, MSD, Layout); - if (Data.getFlags() & ELF_STB_Local) + assert(((Data.getFlags() & ELF_STB_Global) || + (Data.getFlags() & ELF_STB_Weak)) && + "External symbol requires STB_GLOBAL or STB_WEAK flag"); + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + if (GetBinding(Data) == 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) + WriteSymbol(SymtabF, ShndxF, MSD, Layout); + if (GetBinding(Data) == 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) { +const MCSymbol *ELFObjectWriter::SymbolToReloc(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + const MCSymbol *Renamed = Renames.lookup(&Symbol); + const MCSymbolData &SD = Asm.getSymbolData(Symbol); + + if (ASymbol.isUndefined()) { + if (Renamed) + return Renamed; + return &ASymbol; + } + + if (SD.isExternal()) { + if (Renamed) + return Renamed; + return &Symbol; + } + + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(ASymbol.getSection()); + const SectionKind secKind = Section.getKind(); + + if (secKind.isBSS()) + return ExplicitRelSym(Asm, Target, F, true); + + if (secKind.isThreadLocal()) { + if (Renamed) + return Renamed; + return &Symbol; + } + + MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); + const MCSectionELF &Sec2 = + static_cast<const MCSectionELF&>(F.getParent()->getSection()); + + if (&Sec2 != &Section && + (Kind == MCSymbolRefExpr::VK_PLT || + Kind == MCSymbolRefExpr::VK_GOTPCREL || + Kind == MCSymbolRefExpr::VK_GOTOFF)) { + if (Renamed) + return Renamed; + return &Symbol; + } + + if (Section.getFlags() & ELF::SHF_MERGE) { + if (Target.getConstant() == 0) + return NULL; + if (Renamed) + return Renamed; + return &Symbol; + } + + return ExplicitRelSym(Asm, Target, F, false); +} + + +void ELFObjectWriter::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; + int Index = 0; int64_t Value = Target.getConstant(); + const MCSymbol *RelocSymbol = NULL; + bool IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); if (!Target.isAbsolute()) { - const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); - 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; - } - } - } + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + RelocSymbol = SymbolToReloc(Asm, Target, *Fragment); - FixedValue = Value; + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + const MCSymbol &SymbolB = RefB->getSymbol(); + MCSymbolData &SDB = Asm.getSymbolData(SymbolB); + IsPCRel = true; - // 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; - } + // Offset of the symbol in the section + int64_t a = Layout.getSymbolOffset(&SDB); + + // Ofeset of the relocation in the section + int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + Value += b - a; } - } else { - if (IsPCRel) { - Type = ELF::R_386_PC32; + + if (!RelocSymbol) { + MCSymbolData &SD = Asm.getSymbolData(ASymbol); + MCFragment *F = SD.getFragment(); + + Index = F->getParent()->getOrdinal() + 1; + + // Offset of the symbol in the section + Value += Layout.getSymbolOffset(&SD); } 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; - } + if (Asm.getSymbolData(Symbol).getFlags() & ELF_Other_Weakref) + WeakrefUsedInReloc.insert(RelocSymbol); + else + UsedInReloc.insert(RelocSymbol); + Index = -1; } + Addend = Value; + // Compensate for the addend on i386. + if (is64Bit()) + Value = 0; } - ELFRelocationEntry ERE; + FixedValue = Value; + unsigned Type = GetRelocType(Target, Fixup, IsPCRel, + (RelocSymbol != 0), Addend); + + uint64_t RelocOffset = Layout.getFragmentOffset(Fragment) + + Fixup.getOffset(); + + if (!hasRelocationAddend()) + Addend = 0; + ELFRelocationEntry ERE(RelocOffset, Index, Type, RelocSymbol, Addend); + Relocations[Fragment->getParent()].push_back(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(); +uint64_t +ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S) { + MCSymbolData &SD = Asm.getSymbolData(*S); + return SD.getIndex(); +} - if (HasRelocationAddend) - ERE.r_addend = Addend; - else - ERE.r_addend = 0; // Silence compiler warning. +static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, + bool Used, bool Renamed) { + if (Data.getFlags() & ELF_Other_Weakref) + return false; - Relocations[Fragment->getParent()].push_back(ERE); + if (Used) + return true; + + if (Renamed) + return false; + + const MCSymbol &Symbol = Data.getSymbol(); + + if (Symbol.getName() == "_GLOBAL_OFFSET_TABLE_") + return true; + + const MCSymbol &A = Symbol.AliasedSymbol(); + if (!A.isVariable() && A.isUndefined() && !Data.isCommon()) + return false; + + if (!Asm.isSymbolLinkerVisible(Symbol) && !Symbol.isUndefined()) + return false; + + if (Symbol.isTemporary()) + return false; + + return true; } -uint64_t -ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, - const MCSymbol *S) { - MCSymbolData &SD = Asm.getSymbolData(*S); +static bool isLocal(const MCSymbolData &Data, bool isSignature, + bool isUsedInReloc) { + if (Data.isExternal()) + return false; + + const MCSymbol &Symbol = Data.getSymbol(); + const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); - // Local symbol. - if (!SD.isExternal() && !S->isUndefined()) - return SD.getIndex() + /* empty symbol */ 1; + if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) { + if (isSignature && !isUsedInReloc) + return true; - // External or undefined symbol. - return SD.getIndex() + Asm.size() + /* empty symbol */ 1; + return false; + } + + return true; } -void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { - // Build section lookup table. - DenseMap<const MCSection*, uint8_t> SectionIndexMap; +void ELFObjectWriter::ComputeIndexMap(MCAssembler &Asm, + SectionIndexMapTy &SectionIndexMap) { unsigned Index = 1; for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it, ++Index) - SectionIndexMap[&it->getSection()] = Index; + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() != ELF::SHT_GROUP) + continue; + SectionIndexMap[&Section] = Index++; + } + + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF &>(it->getSection()); + if (Section.getType() == ELF::SHT_GROUP) + continue; + SectionIndexMap[&Section] = Index++; + } +} + +void ELFObjectWriter::ComputeSymbolTable(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + RevGroupMapTy RevGroupMap) { + // FIXME: Is this the correct place to do this? + if (NeedsGOT) { + llvm::StringRef Name = "_GLOBAL_OFFSET_TABLE_"; + MCSymbol *Sym = Asm.getContext().GetOrCreateSymbol(Name); + MCSymbolData &Data = Asm.getOrCreateSymbolData(*Sym); + Data.setExternal(true); + SetBinding(Data, ELF::STB_GLOBAL); + } + + // Build section lookup table. + int NumRegularSections = Asm.size(); // Index 0 is always the empty string. StringMap<uint64_t> StringIndexMap; StringTable += '\x00'; - // Add the data for local symbols. + // Add the data for the symbols. for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), ie = Asm.symbol_end(); it != ie; ++it) { const MCSymbol &Symbol = it->getSymbol(); - // Ignore non-linker visible symbols. - if (!Asm.isSymbolLinkerVisible(Symbol)) - continue; + bool Used = UsedInReloc.count(&Symbol); + bool WeakrefUsed = WeakrefUsedInReloc.count(&Symbol); + bool isSignature = RevGroupMap.count(&Symbol); - if (it->isExternal() || Symbol.isUndefined()) + if (!isInSymtab(Asm, *it, + Used || WeakrefUsed || isSignature, + Renames.count(&Symbol))) 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; + const MCSymbol &RefSymbol = Symbol.AliasedSymbol(); + + // Undefined symbols are global, but this is the first place we + // are able to set it. + bool Local = isLocal(*it, isSignature, Used); + if (!Local && GetBinding(*it) == ELF::STB_LOCAL) { + MCSymbolData &SD = Asm.getSymbolData(RefSymbol); + SetBinding(*it, ELF::STB_GLOBAL); + SetBinding(SD, ELF::STB_GLOBAL); + } + + if (RefSymbol.isUndefined() && !Used && WeakrefUsed) + SetBinding(*it, ELF::STB_WEAK); - if (Symbol.isAbsolute()) { + if (it->isCommon()) { + assert(!Local); + MSD.SectionIndex = ELF::SHN_COMMON; + } else if (Symbol.isAbsolute() || RefSymbol.isVariable()) { MSD.SectionIndex = ELF::SHN_ABS; - LocalSymbolData.push_back(MSD); + } else if (RefSymbol.isUndefined()) { + if (isSignature && !Used) + MSD.SectionIndex = SectionIndexMap.lookup(RevGroupMap[&Symbol]); + else + MSD.SectionIndex = ELF::SHN_UNDEF; } else { - MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(RefSymbol.getSection()); + MSD.SectionIndex = SectionIndexMap.lookup(&Section); + if (MSD.SectionIndex >= ELF::SHN_LORESERVE) + NeedsSymtabShndx = true; assert(MSD.SectionIndex && "Invalid section index!"); - 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; + // The @@@ in symbol version is replaced with @ in undefined symbols and + // @@ in defined ones. + StringRef Name = Symbol.getName(); + SmallString<32> Buf; + + size_t Pos = Name.find("@@@"); + if (Pos != StringRef::npos) { + Buf += Name.substr(0, Pos); + unsigned Skip = MSD.SectionIndex == ELF::SHN_UNDEF ? 2 : 1; + Buf += Name.substr(Pos + Skip); + Name = Buf; + } - uint64_t &Entry = StringIndexMap[Symbol.getName()]; + uint64_t &Entry = StringIndexMap[Name]; if (!Entry) { Entry = StringTable.size(); - StringTable += Symbol.getName(); + StringTable += Name; 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); + if (MSD.SectionIndex == ELF::SHN_UNDEF) 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!"); + else if (Local) + LocalSymbolData.push_back(MSD); + else ExternalSymbolData.push_back(MSD); - } } // Symbols are required to be in lexicographic order. @@ -669,55 +988,56 @@ void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { // Set the symbol indices. Local symbols must come before all other // symbols with non-local bindings. - Index = 0; + unsigned Index = 1; for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) LocalSymbolData[i].SymbolData->setIndex(Index++); + + Index += NumRegularSections; + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) ExternalSymbolData[i].SymbolData->setIndex(Index++); for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) UndefinedSymbolData[i].SymbolData->setIndex(Index++); } -void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, - const MCSectionData &SD) { +void ELFObjectWriter::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, + const MCSectionData &SD) { if (!Relocations[&SD].empty()) { MCContext &Ctx = Asm.getContext(); - const MCSection *RelaSection; + const MCSectionELF *RelaSection; const MCSectionELF &Section = static_cast<const MCSectionELF&>(SD.getSection()); const StringRef SectionName = Section.getSectionName(); - std::string RelaSectionName = HasRelocationAddend ? ".rela" : ".rel"; + std::string RelaSectionName = hasRelocationAddend() ? ".rela" : ".rel"; RelaSectionName += SectionName; unsigned EntrySize; - if (HasRelocationAddend) - EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); + if (hasRelocationAddend()) + EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rela) : sizeof(ELF::Elf32_Rela); else - EntrySize = Is64Bit ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); + EntrySize = is64Bit() ? sizeof(ELF::Elf64_Rel) : sizeof(ELF::Elf32_Rel); - RelaSection = Ctx.getELFSection(RelaSectionName, HasRelocationAddend ? + RelaSection = Ctx.getELFSection(RelaSectionName, hasRelocationAddend() ? ELF::SHT_RELA : ELF::SHT_REL, 0, SectionKind::getReadOnly(), - false, EntrySize); + EntrySize, ""); MCSectionData &RelaSD = Asm.getOrCreateSectionData(*RelaSection); - RelaSD.setAlignment(1); + RelaSD.setAlignment(is64Bit() ? 8 : 4); 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) { +void ELFObjectWriter::WriteSecHdrEntry(uint32_t Name, uint32_t Type, + uint64_t Flags, uint64_t Address, + uint64_t Offset, uint64_t Size, + uint32_t Link, uint32_t Info, + uint64_t Alignment, + uint64_t EntrySize) { Write32(Name); // sh_name: index into string table Write32(Type); // sh_type WriteWord(Flags); // sh_flags @@ -730,9 +1050,9 @@ void ELFObjectWriterImpl::WriteSecHdrEntry(uint32_t Name, uint32_t Type, WriteWord(EntrySize); // sh_entsize } -void ELFObjectWriterImpl::WriteRelocationsFragment(const MCAssembler &Asm, - MCDataFragment *F, - const MCSectionData *SD) { +void ELFObjectWriter::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()); @@ -740,67 +1060,90 @@ void ELFObjectWriterImpl::WriteRelocationsFragment(const MCAssembler &Asm, 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 (!entry.Index) + ; + else if (entry.Index < 0) + entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol); + else + entry.Index += LocalSymbolData.size(); + if (is64Bit()) { + String64(*F, entry.r_offset); + + struct ELF::Elf64_Rela ERE64; + ERE64.setSymbolAndType(entry.Index, entry.Type); + String64(*F, ERE64.r_info); - if (HasRelocationAddend) - F->getContents() += StringRef((const char *)&entry.r_addend, WordSize); + if (hasRelocationAddend()) + String64(*F, entry.r_addend); + } else { + String32(*F, entry.r_offset); + + struct ELF::Elf32_Rela ERE32; + ERE32.setSymbolAndType(entry.Index, entry.Type); + String32(*F, ERE32.r_info); + + if (hasRelocationAddend()) + String32(*F, entry.r_addend); + } } } -void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm, - MCAsmLayout &Layout) { +void ELFObjectWriter::CreateMetadataSections(MCAssembler &Asm, + MCAsmLayout &Layout, + const SectionIndexMapTy &SectionIndexMap) { MCContext &Ctx = Asm.getContext(); MCDataFragment *F; - WriteRelocations(Asm, Layout); - - const MCSection *SymtabSection; - unsigned EntrySize = Is64Bit ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; + unsigned EntrySize = is64Bit() ? ELF::SYMENTRY_SIZE64 : ELF::SYMENTRY_SIZE32; - SymtabSection = Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, - SectionKind::getReadOnly(), - false, EntrySize); + // We construct .shstrtab, .symtab and .strtab in this order to match gnu as. + const MCSectionELF *ShstrtabSection = + Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, + SectionKind::getReadOnly()); + MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); + ShstrtabSD.setAlignment(1); + ShstrtabIndex = Asm.size(); + const MCSectionELF *SymtabSection = + Ctx.getELFSection(".symtab", ELF::SHT_SYMTAB, 0, + SectionKind::getReadOnly(), + EntrySize, ""); MCSectionData &SymtabSD = Asm.getOrCreateSectionData(*SymtabSection); + SymtabSD.setAlignment(is64Bit() ? 8 : 4); + SymbolTableIndex = Asm.size(); - SymtabSD.setAlignment(Is64Bit ? 8 : 4); + MCSectionData *SymtabShndxSD = NULL; - F = new MCDataFragment(&SymtabSD); - - // Symbol table - WriteSymbolTable(F, Asm, Layout); - Asm.AddSectionToTheEnd(SymtabSD, Layout); + if (NeedsSymtabShndx) { + const MCSectionELF *SymtabShndxSection = + Ctx.getELFSection(".symtab_shndx", ELF::SHT_SYMTAB_SHNDX, 0, + SectionKind::getReadOnly(), 4, ""); + SymtabShndxSD = &Asm.getOrCreateSectionData(*SymtabShndxSection); + SymtabShndxSD->setAlignment(4); + } const MCSection *StrtabSection; StrtabSection = Ctx.getELFSection(".strtab", ELF::SHT_STRTAB, 0, - SectionKind::getReadOnly(), false); - + SectionKind::getReadOnly()); 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); + WriteRelocations(Asm, Layout); - const MCSection *ShstrtabSection; - ShstrtabSection = Ctx.getELFSection(".shstrtab", ELF::SHT_STRTAB, 0, - SectionKind::getReadOnly(), false); + // Symbol table + F = new MCDataFragment(&SymtabSD); + MCDataFragment *ShndxF = NULL; + if (NeedsSymtabShndx) { + ShndxF = new MCDataFragment(SymtabShndxSD); + } + WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap); - MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); - ShstrtabSD.setAlignment(1); + F = new MCDataFragment(&StrtabSD); + F->getContents().append(StringTable.begin(), StringTable.end()); 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 @@ -808,166 +1151,691 @@ void ELFObjectWriterImpl::CreateMetadataSections(MCAssembler &Asm, uint64_t Index = 1; F->getContents() += '\x00'; + StringMap<uint64_t> SecStringMap; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionELF &Section = static_cast<const MCSectionELF&>(it->getSection()); + // FIXME: We could merge suffixes like in .text and .rela.text. + StringRef Name = Section.getSectionName(); + if (SecStringMap.count(Name)) { + SectionStringTableIndex[&Section] = SecStringMap[Name]; + continue; + } // 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; + SectionStringTableIndex[&Section] = Index; + SecStringMap[Name] = Index; - Index += Section.getSectionName().size() + 1; - F->getContents() += Section.getSectionName(); + Index += Name.size() + 1; + F->getContents() += Name; F->getContents() += '\x00'; } +} + +void ELFObjectWriter::CreateIndexedSections(MCAssembler &Asm, + MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap) { + // Create the .note.GNU-stack section if needed. + MCContext &Ctx = Asm.getContext(); + if (Asm.getNoExecStack()) { + const MCSectionELF *GnuStackSection = + Ctx.getELFSection(".note.GNU-stack", ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly()); + Asm.getOrCreateSectionData(*GnuStackSection); + } + + // Build the groups + for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); + it != ie; ++it) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + if (!(Section.getFlags() & ELF::SHF_GROUP)) + continue; + + const MCSymbol *SignatureSymbol = Section.getGroup(); + Asm.getOrCreateSymbolData(*SignatureSymbol); + const MCSectionELF *&Group = RevGroupMap[SignatureSymbol]; + if (!Group) { + Group = Ctx.CreateELFGroupSection(); + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + Data.setAlignment(4); + MCDataFragment *F = new MCDataFragment(&Data); + String32(*F, ELF::GRP_COMDAT); + } + GroupMap[Group] = SignatureSymbol; + } + + // Add sections to the groups + unsigned Index = 1; + unsigned NumGroups = RevGroupMap.size(); + for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); + it != ie; ++it, ++Index) { + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(it->getSection()); + if (!(Section.getFlags() & ELF::SHF_GROUP)) + continue; + const MCSectionELF *Group = RevGroupMap[Section.getGroup()]; + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + // FIXME: we could use the previous fragment + MCDataFragment *F = new MCDataFragment(&Data); + String32(*F, NumGroups + Index); + } +} + +void ELFObjectWriter::WriteSection(MCAssembler &Asm, + const SectionIndexMapTy &SectionIndexMap, + uint32_t GroupSymbolIndex, + uint64_t Offset, uint64_t Size, + uint64_t Alignment, + const MCSectionELF &Section) { + uint64_t sh_link = 0; + uint64_t sh_info = 0; + + switch(Section.getType()) { + case ELF::SHT_DYNAMIC: + sh_link = SectionStringTableIndex[&Section]; + sh_info = 0; + break; + + case ELF::SHT_REL: + case ELF::SHT_RELA: { + const MCSectionELF *SymtabSection; + const MCSectionELF *InfoSection; + SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, + 0, + SectionKind::getReadOnly()); + sh_link = SectionIndexMap.lookup(SymtabSection); + assert(sh_link && ".symtab not found"); + + // Remove ".rel" and ".rela" prefixes. + unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; + StringRef SectionName = Section.getSectionName().substr(SecNameLen); + + InfoSection = Asm.getContext().getELFSection(SectionName, + ELF::SHT_PROGBITS, 0, + SectionKind::getReadOnly()); + sh_info = SectionIndexMap.lookup(InfoSection); + break; + } + + case ELF::SHT_SYMTAB: + case ELF::SHT_DYNSYM: + sh_link = StringTableIndex; + sh_info = LastLocalSymbolIndex; + break; + + case ELF::SHT_SYMTAB_SHNDX: + sh_link = SymbolTableIndex; + break; + + case ELF::SHT_PROGBITS: + case ELF::SHT_STRTAB: + case ELF::SHT_NOBITS: + case ELF::SHT_NOTE: + case ELF::SHT_NULL: + case ELF::SHT_ARM_ATTRIBUTES: + case ELF::SHT_INIT_ARRAY: + case ELF::SHT_FINI_ARRAY: + case ELF::SHT_PREINIT_ARRAY: + case ELF::SHT_X86_64_UNWIND: + // Nothing to do. + break; + + case ELF::SHT_GROUP: { + sh_link = SymbolTableIndex; + sh_info = GroupSymbolIndex; + break; + } + + default: + assert(0 && "FIXME: sh_type value not supported!"); + break; + } - Asm.AddSectionToTheEnd(ShstrtabSD, Layout); + WriteSecHdrEntry(SectionStringTableIndex[&Section], Section.getType(), + Section.getFlags(), 0, Offset, Size, sh_link, sh_info, + Alignment, Section.getEntrySize()); } -void ELFObjectWriterImpl::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { +static bool IsELFMetaDataSection(const MCSectionData &SD) { + return SD.getOrdinal() == ~UINT32_C(0) && + !SD.getSection().isVirtualSection(); +} + +static uint64_t DataSectionSize(const MCSectionData &SD) { + uint64_t Ret = 0; + for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; + ++i) { + const MCFragment &F = *i; + assert(F.getKind() == MCFragment::FT_Data); + Ret += cast<MCDataFragment>(F).getContents().size(); + } + return Ret; +} + +static uint64_t GetSectionFileSize(const MCAsmLayout &Layout, + const MCSectionData &SD) { + if (IsELFMetaDataSection(SD)) + return DataSectionSize(SD); + return Layout.getSectionFileSize(&SD); +} + +static uint64_t GetSectionAddressSize(const MCAsmLayout &Layout, + const MCSectionData &SD) { + if (IsELFMetaDataSection(SD)) + return DataSectionSize(SD); + return Layout.getSectionAddressSize(&SD); +} + +static void WriteDataSectionData(ELFObjectWriter *W, const MCSectionData &SD) { + for (MCSectionData::const_iterator i = SD.begin(), e = SD.end(); i != e; + ++i) { + const MCFragment &F = *i; + assert(F.getKind() == MCFragment::FT_Data); + W->WriteBytes(cast<MCDataFragment>(F).getContents().str()); + } +} + +void ELFObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + GroupMapTy GroupMap; + RevGroupMapTy RevGroupMap; + CreateIndexedSections(Asm, const_cast<MCAsmLayout&>(Layout), GroupMap, + RevGroupMap); + + SectionIndexMapTy SectionIndexMap; + + ComputeIndexMap(Asm, SectionIndexMap); + + // Compute symbol table information. + ComputeSymbolTable(Asm, SectionIndexMap, RevGroupMap); + CreateMetadataSections(const_cast<MCAssembler&>(Asm), - const_cast<MCAsmLayout&>(Layout)); + const_cast<MCAsmLayout&>(Layout), + SectionIndexMap); + + // Update to include the metadata sections. + ComputeIndexMap(Asm, SectionIndexMap); // Add 1 for the null section. unsigned NumSections = Asm.size() + 1; + uint64_t NaturalAlignment = is64Bit() ? 8 : 4; + uint64_t HeaderSize = is64Bit() ? sizeof(ELF::Elf64_Ehdr) : + sizeof(ELF::Elf32_Ehdr); + uint64_t FileOff = HeaderSize; + + std::vector<const MCSectionELF*> Sections; + Sections.resize(NumSections); + + for (SectionIndexMapTy::const_iterator i= + SectionIndexMap.begin(), e = SectionIndexMap.end(); i != e; ++i) { + const std::pair<const MCSectionELF*, uint32_t> &p = *i; + Sections[p.second] = p.first; + } - uint64_t SectionDataSize = 0; + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; + FileOff = RoundUpToAlignment(FileOff, SD.getAlignment()); // Get the size of the section in the output file (including padding). - uint64_t Size = Layout.getSectionFileSize(&SD); - SectionDataSize += Size; + FileOff += GetSectionFileSize(Layout, SD); } + FileOff = RoundUpToAlignment(FileOff, NaturalAlignment); + // Write out the ELF header ... - WriteHeader(SectionDataSize, NumSections); - FileOff = Is64Bit ? sizeof(ELF::Elf64_Ehdr) : sizeof(ELF::Elf32_Ehdr); + WriteHeader(FileOff - HeaderSize, NumSections); + + FileOff = HeaderSize; // ... then all of the sections ... DenseMap<const MCSection*, uint64_t> SectionOffsetMap; - DenseMap<const MCSection*, uint8_t> SectionIndexMap; + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); - 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; + uint64_t Padding = OffsetToAlignment(FileOff, SD.getAlignment()); + WriteZeros(Padding); + FileOff += Padding; - SectionIndexMap[&it->getSection()] = Index++; + // Remember the offset into the file for this section. + SectionOffsetMap[&Section] = FileOff; - const MCSectionData &SD = *it; - FileOff += Layout.getSectionFileSize(&SD); + FileOff += GetSectionFileSize(Layout, SD); - Asm.WriteSectionData(it, Layout, Writer); + if (IsELFMetaDataSection(SD)) + WriteDataSectionData(this, SD); + else + Asm.WriteSectionData(&SD, Layout); } + uint64_t Padding = OffsetToAlignment(FileOff, NaturalAlignment); + WriteZeros(Padding); + FileOff += Padding; + // ... 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); + uint64_t FirstSectionSize = + NumSections >= ELF::SHN_LORESERVE ? NumSections : 0; + uint32_t FirstSectionLink = + ShstrtabIndex >= ELF::SHN_LORESERVE ? ShstrtabIndex : 0; + WriteSecHdrEntry(0, 0, 0, 0, 0, FirstSectionSize, FirstSectionLink, 0, 0, 0); + + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + uint32_t GroupSymbolIndex; + if (Section.getType() != ELF::SHT_GROUP) + GroupSymbolIndex = 0; + else + GroupSymbolIndex = getSymbolIndexInSymbolTable(Asm, GroupMap[&Section]); - 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 Size = GetSectionAddressSize(Layout, SD); - uint64_t sh_link = 0; - uint64_t sh_info = 0; + WriteSection(Asm, SectionIndexMap, GroupSymbolIndex, + SectionOffsetMap[&Section], Size, + SD.getAlignment(), Section); + } +} - switch(Section.getType()) { - case ELF::SHT_DYNAMIC: - sh_link = SectionStringTableIndex[&it->getSection()]; - sh_info = 0; - break; +MCObjectWriter *llvm::createELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &OS, + bool IsLittleEndian) { + switch (MOTW->getEMachine()) { + case ELF::EM_386: + case ELF::EM_X86_64: + return new X86ELFObjectWriter(MOTW, OS, IsLittleEndian); break; + case ELF::EM_ARM: + return new ARMELFObjectWriter(MOTW, OS, IsLittleEndian); break; + case ELF::EM_MBLAZE: + return new MBlazeELFObjectWriter(MOTW, OS, IsLittleEndian); break; + default: llvm_unreachable("Unsupported architecture"); break; + } +} + + +/// START OF SUBCLASSES for ELFObjectWriter +//===- ARMELFObjectWriter -------------------------------------------===// + +ARMELFObjectWriter::ARMELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian) + : ELFObjectWriter(MOTW, _OS, IsLittleEndian) +{} + +ARMELFObjectWriter::~ARMELFObjectWriter() +{} - 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]; +// FIXME: get the real EABI Version from the Triple. +void ARMELFObjectWriter::WriteEFlags() { + Write32(ELF::EF_ARM_EABIMASK & DefaultEABIVersion); +} + +// In ARM, _MergedGlobals and other most symbols get emitted directly. +// I.e. not as an offset to a section symbol. +// This code is a first-cut approximation of what ARM/gcc does. + +const MCSymbol *ARMELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm, + const MCValue &Target, + const MCFragment &F, + bool IsBSS) const { + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + bool EmitThisSym = false; + + if (IsBSS) { + EmitThisSym = StringSwitch<bool>(Symbol.getName()) + .Case("_MergedGlobals", true) + .Default(false); + } else { + EmitThisSym = StringSwitch<bool>(Symbol.getName()) + .Case("_MergedGlobals", true) + .StartsWith(".L.str", true) + .Default(false); + } + if (EmitThisSym) + return &Symbol; + if (! Symbol.isTemporary()) + return &Symbol; + return NULL; +} + +unsigned ARMELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) { + MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + + unsigned Type = 0; + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: assert(0 && "Unimplemented"); + case FK_Data_4: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_ARM_BASE_PREL; + break; + case MCSymbolRefExpr::VK_ARM_TLSGD: + assert(0 && "unimplemented"); + break; + case MCSymbolRefExpr::VK_ARM_GOTTPOFF: + Type = ELF::R_ARM_TLS_IE32; + break; + } + break; + case ARM::fixup_arm_uncondbranch: + switch (Modifier) { + case MCSymbolRefExpr::VK_ARM_PLT: + Type = ELF::R_ARM_PLT32; + break; + default: + Type = ELF::R_ARM_CALL; + break; + } + break; + case ARM::fixup_arm_condbranch: + Type = ELF::R_ARM_JUMP24; + break; + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + Type = ELF::R_ARM_MOVT_PREL; + break; + case ARM::fixup_arm_movw_lo16: + case ARM::fixup_arm_movw_lo16_pcrel: + Type = ELF::R_ARM_MOVW_PREL_NC; + break; + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + Type = ELF::R_ARM_THM_MOVT_PREL; + break; + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: + Type = ELF::R_ARM_THM_MOVW_PREL_NC; break; } - - case ELF::SHT_SYMTAB: - case ELF::SHT_DYNSYM: - sh_link = StringTableIndex; - sh_info = LastLocalSymbolIndex; + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + switch (Modifier) { + default: llvm_unreachable("Unsupported Modifier"); break; + case MCSymbolRefExpr::VK_ARM_GOT: + Type = ELF::R_ARM_GOT_BREL; + break; + case MCSymbolRefExpr::VK_ARM_TLSGD: + Type = ELF::R_ARM_TLS_GD32; + break; + case MCSymbolRefExpr::VK_ARM_TPOFF: + Type = ELF::R_ARM_TLS_LE32; + break; + case MCSymbolRefExpr::VK_ARM_GOTTPOFF: + Type = ELF::R_ARM_TLS_IE32; + break; + case MCSymbolRefExpr::VK_None: + Type = ELF::R_ARM_ABS32; + break; + case MCSymbolRefExpr::VK_ARM_GOTOFF: + Type = ELF::R_ARM_GOTOFF32; + break; + } break; - - case ELF::SHT_PROGBITS: - case ELF::SHT_STRTAB: - case ELF::SHT_NOBITS: - case ELF::SHT_NULL: - // Nothing to do. + case ARM::fixup_arm_ldst_pcrel_12: + case ARM::fixup_arm_pcrel_10: + case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_thumb_bl: + case ARM::fixup_arm_thumb_cb: + case ARM::fixup_arm_thumb_cp: + case ARM::fixup_arm_thumb_br: + assert(0 && "Unimplemented"); break; - - case ELF::SHT_HASH: - case ELF::SHT_GROUP: - case ELF::SHT_SYMTAB_SHNDX: - default: - assert(0 && "FIXME: sh_type value not supported!"); + case ARM::fixup_arm_uncondbranch: + Type = ELF::R_ARM_CALL; + break; + case ARM::fixup_arm_condbranch: + Type = ELF::R_ARM_JUMP24; + break; + case ARM::fixup_arm_movt_hi16: + Type = ELF::R_ARM_MOVT_ABS; + break; + case ARM::fixup_arm_movw_lo16: + Type = ELF::R_ARM_MOVW_ABS_NC; + break; + case ARM::fixup_t2_movt_hi16: + Type = ELF::R_ARM_THM_MOVT_ABS; + break; + case ARM::fixup_t2_movw_lo16: + Type = ELF::R_ARM_THM_MOVW_ABS_NC; 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); + if (RelocNeedsGOT(Modifier)) + NeedsGOT = true; + + return Type; } -ELFObjectWriter::~ELFObjectWriter() { - delete (ELFObjectWriterImpl*) Impl; +//===- MBlazeELFObjectWriter -------------------------------------------===// + +MBlazeELFObjectWriter::MBlazeELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian) + : ELFObjectWriter(MOTW, _OS, IsLittleEndian) { } -void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { - ((ELFObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); +MBlazeELFObjectWriter::~MBlazeELFObjectWriter() { } -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); +unsigned MBlazeELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) { + // determine the type of the relocation + unsigned Type; + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: + llvm_unreachable("Unimplemented"); + case FK_PCRel_4: + Type = ELF::R_MICROBLAZE_64_PCREL; + break; + case FK_PCRel_2: + Type = ELF::R_MICROBLAZE_32_PCREL; + break; + } + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_Data_4: + Type = ((IsRelocWithSymbol || Addend !=0) + ? ELF::R_MICROBLAZE_32 + : ELF::R_MICROBLAZE_64); + break; + case FK_Data_2: + Type = ELF::R_MICROBLAZE_32; + break; + } + } + return Type; } -void ELFObjectWriter::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - ((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); +//===- X86ELFObjectWriter -------------------------------------------===// + + +X86ELFObjectWriter::X86ELFObjectWriter(MCELFObjectTargetWriter *MOTW, + raw_ostream &_OS, + bool IsLittleEndian) + : ELFObjectWriter(MOTW, _OS, IsLittleEndian) +{} + +X86ELFObjectWriter::~X86ELFObjectWriter() +{} + +unsigned X86ELFObjectWriter::GetRelocType(const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel, + bool IsRelocWithSymbol, + int64_t Addend) { + // determine the type of the relocation + + MCSymbolRefExpr::VariantKind Modifier = Target.isAbsolute() ? + MCSymbolRefExpr::VK_None : Target.getSymA()->getKind(); + unsigned Type; + if (is64Bit()) { + if (IsPCRel) { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + case FK_PCRel_8: + assert(Modifier == MCSymbolRefExpr::VK_None); + Type = ELF::R_X86_64_PC64; + break; + case X86::reloc_signed_4byte: + case X86::reloc_riprel_4byte_movq_load: + case FK_Data_4: // FIXME? + case X86::reloc_riprel_4byte: + case FK_PCRel_4: + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_X86_64_PC32; + break; + case MCSymbolRefExpr::VK_PLT: + Type = ELF::R_X86_64_PLT32; + break; + case MCSymbolRefExpr::VK_GOTPCREL: + Type = ELF::R_X86_64_GOTPCREL; + break; + case MCSymbolRefExpr::VK_GOTTPOFF: + Type = ELF::R_X86_64_GOTTPOFF; + break; + case MCSymbolRefExpr::VK_TLSGD: + Type = ELF::R_X86_64_TLSGD; + break; + case MCSymbolRefExpr::VK_TLSLD: + Type = ELF::R_X86_64_TLSLD; + break; + } + break; + case FK_PCRel_2: + assert(Modifier == MCSymbolRefExpr::VK_None); + Type = ELF::R_X86_64_PC16; + break; + } + } 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_signed_4byte: + assert(isInt<32>(Target.getConstant())); + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_X86_64_32S; + break; + case MCSymbolRefExpr::VK_GOT: + Type = ELF::R_X86_64_GOT32; + break; + case MCSymbolRefExpr::VK_GOTPCREL: + Type = ELF::R_X86_64_GOTPCREL; + break; + case MCSymbolRefExpr::VK_TPOFF: + Type = ELF::R_X86_64_TPOFF32; + break; + case MCSymbolRefExpr::VK_DTPOFF: + Type = ELF::R_X86_64_DTPOFF32; + break; + } + break; + case FK_Data_4: + Type = ELF::R_X86_64_32; + break; + case FK_Data_2: Type = ELF::R_X86_64_16; break; + case FK_PCRel_1: + case FK_Data_1: Type = ELF::R_X86_64_8; break; + } + } + } else { + if (IsPCRel) { + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_386_PC32; + break; + case MCSymbolRefExpr::VK_PLT: + Type = ELF::R_386_PLT32; + break; + } + } else { + switch ((unsigned)Fixup.getKind()) { + default: llvm_unreachable("invalid fixup kind!"); + + case X86::reloc_global_offset_table: + Type = ELF::R_386_GOTPC; + break; + + // FIXME: Should we avoid selecting reloc_signed_4byte in 32 bit mode + // instead? + case X86::reloc_signed_4byte: + case FK_PCRel_4: + case FK_Data_4: + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + Type = ELF::R_386_32; + break; + case MCSymbolRefExpr::VK_GOT: + Type = ELF::R_386_GOT32; + break; + case MCSymbolRefExpr::VK_GOTOFF: + Type = ELF::R_386_GOTOFF; + break; + case MCSymbolRefExpr::VK_TLSGD: + Type = ELF::R_386_TLS_GD; + break; + case MCSymbolRefExpr::VK_TPOFF: + Type = ELF::R_386_TLS_LE_32; + break; + case MCSymbolRefExpr::VK_INDNTPOFF: + Type = ELF::R_386_TLS_IE; + break; + case MCSymbolRefExpr::VK_NTPOFF: + Type = ELF::R_386_TLS_LE; + break; + case MCSymbolRefExpr::VK_GOTNTPOFF: + Type = ELF::R_386_TLS_GOTIE; + break; + case MCSymbolRefExpr::VK_TLSLDM: + Type = ELF::R_386_TLS_LDM; + break; + case MCSymbolRefExpr::VK_DTPOFF: + Type = ELF::R_386_TLS_LDO_32; + break; + } + break; + case FK_Data_2: Type = ELF::R_386_16; break; + case FK_PCRel_1: + case FK_Data_1: Type = ELF::R_386_8; break; + } + } + } + + if (RelocNeedsGOT(Modifier)) + NeedsGOT = true; + + return Type; } diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index 670b2e9..cc1afbd 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -13,7 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCAsmInfo.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <cctype> #include <cstring> using namespace llvm; @@ -23,11 +23,13 @@ MCAsmInfo::MCAsmInfo() { HasMachoZeroFillDirective = false; HasMachoTBSSDirective = false; HasStaticCtorDtorReferenceInStaticMode = false; + LinkerRequiresNonEmptyDwarfLines = false; MaxInstLength = 4; PCSymbol = "$"; SeparatorChar = ';'; CommentColumn = 40; CommentString = "#"; + LabelSuffix = ":"; GlobalPrefix = ""; PrivateGlobalPrefix = "."; LinkerPrivateGlobalPrefix = ""; @@ -52,18 +54,19 @@ MCAsmInfo::MCAsmInfo() { GPRel32Directive = 0; GlobalDirective = "\t.globl\t"; HasSetDirective = true; + HasAggressiveSymbolFolding = true; HasLCOMMDirective = false; COMMDirectiveAlignmentIsInBytes = true; HasDotTypeDotSizeDirective = true; HasSingleParameterDotFile = true; HasNoDeadStrip = false; + HasSymbolResolver = false; WeakRefDirective = 0; WeakDefDirective = 0; LinkOnceDirective = 0; HiddenVisibilityAttr = MCSA_Hidden; ProtectedVisibilityAttr = MCSA_Protected; HasLEB128 = false; - HasDotLocAndDotFile = false; SupportsDebugInformation = false; ExceptionsType = ExceptionHandling::None; DwarfRequiresFrameSection = true; diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp index e0e261a..13776f0 100644 --- a/lib/MC/MCAsmInfoDarwin.cpp +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -37,13 +37,20 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { HasMachoZeroFillDirective = true; // Uses .zerofill HasMachoTBSSDirective = true; // Uses .tbss HasStaticCtorDtorReferenceInStaticMode = true; - + + // FIXME: Darwin 10 and newer don't need this. + LinkerRequiresNonEmptyDwarfLines = true; + + // FIXME: Change this once MC is the system assembler. + HasAggressiveSymbolFolding = false; + HiddenVisibilityAttr = MCSA_PrivateExtern; // Doesn't support protected visibility. ProtectedVisibilityAttr = MCSA_Global; HasDotTypeDotSizeDirective = false; HasNoDeadStrip = true; + HasSymbolResolver = true; DwarfUsesAbsoluteLabelForStmtList = false; DwarfUsesLabelOffsetForRanges = false; diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 1cc8fb0..8d06982 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -12,6 +12,7 @@ #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstPrinter.h" #include "llvm/MC/MCSectionMachO.h" @@ -23,6 +24,10 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" +#include "llvm/Target/TargetLoweringObjectFile.h" +#include <cctype> using namespace llvm; namespace { @@ -32,29 +37,33 @@ class MCAsmStreamer : public MCStreamer { const MCAsmInfo &MAI; OwningPtr<MCInstPrinter> InstPrinter; OwningPtr<MCCodeEmitter> Emitter; - + OwningPtr<TargetAsmBackend> AsmBackend; + SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; - unsigned IsLittleEndian : 1; unsigned IsVerboseAsm : 1; unsigned ShowInst : 1; + unsigned UseLoc : 1; + + bool needsSet(const MCExpr *Value); public: MCAsmStreamer(MCContext &Context, formatted_raw_ostream &os, - bool isLittleEndian, bool isVerboseAsm, MCInstPrinter *printer, - MCCodeEmitter *emitter, bool showInst) + bool isVerboseAsm, + bool useLoc, + MCInstPrinter *printer, MCCodeEmitter *emitter, + TargetAsmBackend *asmbackend, + bool showInst) : MCStreamer(Context), OS(os), MAI(Context.getAsmInfo()), - InstPrinter(printer), Emitter(emitter), CommentStream(CommentToEmit), - IsLittleEndian(isLittleEndian), IsVerboseAsm(isVerboseAsm), - ShowInst(showInst) { + InstPrinter(printer), Emitter(emitter), AsmBackend(asmbackend), + CommentStream(CommentToEmit), IsVerboseAsm(isVerboseAsm), + ShowInst(showInst), UseLoc(useLoc) { if (InstPrinter && IsVerboseAsm) InstPrinter->setCommentStream(CommentStream); } ~MCAsmStreamer() {} - bool isLittleEndian() const { return IsLittleEndian; } - inline void EmitEOL() { // If we don't have any comments, just emit a \n. if (!IsVerboseAsm) { @@ -68,7 +77,7 @@ public: /// isVerboseAsm - Return true if this streamer supports verbose assembly at /// all. virtual bool isVerboseAsm() const { return IsVerboseAsm; } - + /// hasRawTextSupport - We support EmitRawText. virtual bool hasRawTextSupport() const { return true; } @@ -98,13 +107,26 @@ public: /// @name MCStreamer Interface /// @{ - virtual void SwitchSection(const MCSection *Section); + virtual void ChangeSection(const MCSection *Section); + + virtual void InitSections() { + // FIXME, this is MachO specific, but the testsuite + // expects this. + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + } virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); @@ -122,19 +144,26 @@ public: /// @param Symbol - The common symbol to emit. /// @param Size - The size of the common symbol. virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); - + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0); virtual void EmitTBSSSymbol (const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0); - + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); - virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace); + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace); + virtual void EmitIntValue(uint64_t Value, unsigned Size, + unsigned AddrSpace = 0); + + virtual void EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); + + virtual void EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace = 0); + virtual void EmitGPRel32Value(const MCExpr *Value); - + virtual void EmitFill(uint64_t NumBytes, uint8_t FillValue, unsigned AddrSpace); @@ -150,17 +179,28 @@ public: unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename); - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename); + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename); + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator); + + virtual bool EmitCFIStartProc(); + virtual bool EmitCFIEndProc(); + virtual bool EmitCFIDefCfaOffset(int64_t Offset); + virtual bool EmitCFIDefCfaRegister(int64_t Register); + virtual bool EmitCFIOffset(int64_t Register, int64_t Offset); + virtual bool EmitCFIPersonality(const MCSymbol *Sym, unsigned Encoding); + virtual bool EmitCFILsda(const MCSymbol *Sym, unsigned Encoding); virtual void EmitInstruction(const MCInst &Inst); - - /// EmitRawText - If this file is backed by a assembly streamer, this dumps + + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. virtual void EmitRawText(StringRef String); - + virtual void Finish(); - + /// @} }; @@ -172,14 +212,14 @@ public: /// verbose assembly output is enabled. void MCAsmStreamer::AddComment(const Twine &T) { if (!IsVerboseAsm) return; - + // Make sure that CommentStream is flushed. CommentStream.flush(); - + T.toVector(CommentToEmit); // Each comment goes on its own line. CommentToEmit.push_back('\n'); - + // Tell the comment stream that the vector changed underneath it. CommentStream.resync(); } @@ -189,10 +229,10 @@ void MCAsmStreamer::EmitCommentsAndEOL() { OS << '\n'; return; } - + CommentStream.flush(); StringRef Comments = CommentToEmit.str(); - + assert(Comments.back() == '\n' && "Comment array not newline terminated"); do { @@ -200,10 +240,10 @@ void MCAsmStreamer::EmitCommentsAndEOL() { OS.PadToColumn(MAI.getCommentColumn()); size_t Position = Comments.find('\n'); OS << MAI.getCommentString() << ' ' << Comments.substr(0, Position) << '\n'; - + Comments = Comments.substr(Position+1); } while (!Comments.empty()); - + CommentToEmit.clear(); // Tell the comment stream that the vector changed underneath it. CommentStream.resync(); @@ -214,33 +254,41 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); } -void MCAsmStreamer::SwitchSection(const MCSection *Section) { +void MCAsmStreamer::ChangeSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); - if (Section != CurSection) { - PrevSection = CurSection; - CurSection = Section; - Section->PrintSwitchToSection(MAI, OS); - } + Section->PrintSwitchToSection(MAI, OS); } void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); - assert(CurSection && "Cannot emit before setting section!"); + assert(getCurrentSection() && "Cannot emit before setting section!"); - OS << *Symbol << ":"; + OS << *Symbol << MAI.getLabelSuffix(); EmitEOL(); - Symbol->setSection(*CurSection); + Symbol->setSection(*getCurrentSection()); } void MCAsmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { default: assert(0 && "Invalid flag!"); + case MCAF_SyntaxUnified: OS << "\t.syntax unified"; break; case MCAF_SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; + case MCAF_Code16: OS << "\t.code\t16"; break; + case MCAF_Code32: OS << "\t.code\t32"; break; } EmitEOL(); } +void MCAsmStreamer::EmitThumbFunc(MCSymbol *Func) { + // This needs to emit to a temporary string to get properly quoted + // MCSymbols when they have spaces in them. + OS << "\t.thumb_func"; + if (Func) + OS << '\t' << *Func; + EmitEOL(); +} + void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { OS << *Symbol << " = " << *Value; EmitEOL(); @@ -249,6 +297,18 @@ void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(Value); } +void MCAsmStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + OS << ".weakref " << *Alias << ", " << *Symbol; + EmitEOL(); +} + +void MCAsmStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + EmitDwarfSetLineAddr(LineDelta, Label, + getContext().getTargetAsmInfo().getPointerSize()); +} + void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { switch (Attribute) { @@ -259,6 +319,7 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: /// .type _foo, STT_TLS # aka @tls_object case MCSA_ELF_TypeCommon: /// .type _foo, STT_COMMON # aka @common case MCSA_ELF_TypeNoType: /// .type _foo, STT_NOTYPE # aka @notype + case MCSA_ELF_TypeGnuUniqueObject: /// .type _foo, @gnu_unique_object assert(MAI.hasDotTypeDotSizeDirective() && "Symbol Attr not supported"); OS << "\t.type\t" << *Symbol << ',' << ((MAI.getCommentString()[0] != '@') ? '@' : '%'); @@ -270,6 +331,7 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: OS << "tls_object"; break; case MCSA_ELF_TypeCommon: OS << "common"; break; case MCSA_ELF_TypeNoType: OS << "no_type"; break; + case MCSA_ELF_TypeGnuUniqueObject: OS << "gnu_unique_object"; break; } EmitEOL(); return; @@ -282,6 +344,7 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_LazyReference: OS << "\t.lazy_reference\t"; break; case MCSA_Local: OS << "\t.local\t"; break; case MCSA_NoDeadStrip: OS << "\t.no_dead_strip\t"; break; + case MCSA_SymbolResolver: OS << "\t.symbol_resolver\t"; break; case MCSA_PrivateExtern: OS << "\t.private_extern\t"; break; case MCSA_Protected: OS << "\t.protected\t"; break; case MCSA_Reference: OS << "\t.reference\t"; break; @@ -352,11 +415,11 @@ void MCAsmStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, unsigned Size, unsigned ByteAlignment) { // Note: a .zerofill directive does not switch sections. OS << ".zerofill "; - + // This is a mach-o specific directive. const MCSectionMachO *MOSection = ((const MCSectionMachO*)Section); OS << MOSection->getSegmentName() << "," << MOSection->getSectionName(); - + if (Symbol != NULL) { OS << ',' << *Symbol << ',' << Size; if (ByteAlignment != 0) @@ -374,11 +437,11 @@ void MCAsmStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, // Instead of using the Section we'll just use the shortcut. // This is a mach-o specific directive and section. OS << ".tbss " << *Symbol << ", " << Size; - + // Output align if we have it. We default to 1 so don't bother printing // that. if (ByteAlignment > 1) OS << ", " << Log2_32(ByteAlignment); - + EmitEOL(); } @@ -386,19 +449,19 @@ static inline char toOctal(int X) { return (X&7)+'0'; } static void PrintQuotedString(StringRef Data, raw_ostream &OS) { OS << '"'; - + for (unsigned i = 0, e = Data.size(); i != e; ++i) { unsigned char C = Data[i]; if (C == '"' || C == '\\') { OS << '\\' << (char)C; continue; } - + if (isprint((unsigned char)C)) { OS << (char)C; continue; } - + switch (C) { case '\b': OS << "\\b"; break; case '\f': OS << "\\f"; break; @@ -413,15 +476,15 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) { break; } } - + OS << '"'; } void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { - assert(CurSection && "Cannot emit contents before setting section!"); + assert(getCurrentSection() && "Cannot emit contents before setting section!"); if (Data.empty()) return; - + if (Data.size() == 1) { OS << MAI.getData8bitsDirective(AddrSpace); OS << (unsigned)(unsigned char)Data[0]; @@ -443,11 +506,15 @@ void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { EmitEOL(); } -/// EmitIntValue - Special case of EmitValue that avoids the client having -/// to pass in a MCExpr for constant integers. void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) { - assert(CurSection && "Cannot emit contents before setting section!"); + EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace); +} + +void MCAsmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) { + assert(getCurrentSection() && "Cannot emit contents before setting section!"); + assert(!isPCRel && "Cannot emit pc relative relocations!"); const char *Directive = 0; switch (Size) { default: break; @@ -458,35 +525,43 @@ void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, Directive = MAI.getData64bitsDirective(AddrSpace); // If the target doesn't support 64-bit data, emit as two 32-bit halves. if (Directive) break; - if (isLittleEndian()) { - EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); - EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); + int64_t IntValue; + if (!Value->EvaluateAsAbsolute(IntValue)) + report_fatal_error("Don't know how to emit this value."); + if (getContext().getTargetAsmInfo().isLittleEndian()) { + EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace); + EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace); } else { - EmitIntValue((uint32_t)(Value >> 32), 4, AddrSpace); - EmitIntValue((uint32_t)(Value >> 0 ), 4, AddrSpace); + EmitIntValue((uint32_t)(IntValue >> 32), 4, AddrSpace); + EmitIntValue((uint32_t)(IntValue >> 0 ), 4, AddrSpace); } return; } - + assert(Directive && "Invalid size for machine code value!"); - OS << Directive << truncateToSize(Value, Size); + OS << Directive << *Value; EmitEOL(); } -void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - assert(CurSection && "Cannot emit contents before setting section!"); - const char *Directive = 0; - switch (Size) { - default: break; - case 1: Directive = MAI.getData8bitsDirective(AddrSpace); break; - case 2: Directive = MAI.getData16bitsDirective(AddrSpace); break; - case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; - case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break; +void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue)) { + EmitULEB128IntValue(IntValue, AddrSpace); + return; } - - assert(Directive && "Invalid size for machine code value!"); - OS << Directive << *Value; + assert(MAI.hasLEB128() && "Cannot print a .uleb"); + OS << ".uleb128 " << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue)) { + EmitSLEB128IntValue(IntValue, AddrSpace); + return; + } + assert(MAI.hasLEB128() && "Cannot print a .sleb"); + OS << ".sleb128 " << *Value; EmitEOL(); } @@ -502,7 +577,7 @@ void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { void MCAsmStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, unsigned AddrSpace) { if (NumBytes == 0) return; - + if (AddrSpace == 0) if (const char *ZeroDirective = MAI.getZeroDirective()) { OS << ZeroDirective << NumBytes; @@ -530,7 +605,7 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, case 4: OS << ".p2alignl "; break; case 8: llvm_unreachable("Unsupported alignment size!"); } - + if (MAI.getAlignmentIsInBytes()) OS << ByteAlignment; else @@ -540,13 +615,13 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, OS << ", 0x"; OS.write_hex(truncateToSize(Value, ValueSize)); - if (MaxBytesToEmit) + if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; } EmitEOL(); return; } - + // Non-power of two alignment. This is not widely supported by assemblers. // FIXME: Parameterize this based on MAI. switch (ValueSize) { @@ -559,7 +634,7 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, OS << ' ' << ByteAlignment; OS << ", " << truncateToSize(Value, ValueSize); - if (MaxBytesToEmit) + if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; EmitEOL(); } @@ -586,10 +661,118 @@ void MCAsmStreamer::EmitFileDirective(StringRef Filename) { EmitEOL(); } -void MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){ - OS << "\t.file\t" << FileNo << ' '; - PrintQuotedString(Filename, OS); +bool MCAsmStreamer::EmitDwarfFileDirective(unsigned FileNo, StringRef Filename){ + if (UseLoc) { + OS << "\t.file\t" << FileNo << ' '; + PrintQuotedString(Filename, OS); + EmitEOL(); + } + return this->MCStreamer::EmitDwarfFileDirective(FileNo, Filename); +} + +void MCAsmStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, + unsigned Discriminator) { + this->MCStreamer::EmitDwarfLocDirective(FileNo, Line, Column, Flags, + Isa, Discriminator); + if (!UseLoc) + return; + + OS << "\t.loc\t" << FileNo << " " << Line << " " << Column; + if (Flags & DWARF2_FLAG_BASIC_BLOCK) + OS << " basic_block"; + if (Flags & DWARF2_FLAG_PROLOGUE_END) + OS << " prologue_end"; + if (Flags & DWARF2_FLAG_EPILOGUE_BEGIN) + OS << " epilogue_begin"; + + unsigned OldFlags = getContext().getCurrentDwarfLoc().getFlags(); + if ((Flags & DWARF2_FLAG_IS_STMT) != (OldFlags & DWARF2_FLAG_IS_STMT)) { + OS << " is_stmt "; + + if (Flags & DWARF2_FLAG_IS_STMT) + OS << "1"; + else + OS << "0"; + } + + if (Isa) + OS << "isa " << Isa; + if (Discriminator) + OS << "discriminator " << Discriminator; + EmitEOL(); +} + +bool MCAsmStreamer::EmitCFIStartProc() { + if (this->MCStreamer::EmitCFIStartProc()) + return true; + + OS << "\t.cfi_startproc"; EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIEndProc() { + if (this->MCStreamer::EmitCFIEndProc()) + return true; + + OS << "\t.cfi_endproc"; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIDefCfaOffset(int64_t Offset) { + if (this->MCStreamer::EmitCFIDefCfaOffset(Offset)) + return true; + + OS << "\t.cfi_def_cfa_offset " << Offset; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIDefCfaRegister(int64_t Register) { + if (this->MCStreamer::EmitCFIDefCfaRegister(Register)) + return true; + + OS << "\t.cfi_def_cfa_register " << Register; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { + if (this->MCStreamer::EmitCFIOffset(Register, Offset)) + return true; + + OS << "\t.cfi_offset " << Register << ", " << Offset; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding) { + if (this->MCStreamer::EmitCFIPersonality(Sym, Encoding)) + return true; + + OS << "\t.cfi_personality " << Encoding << ", " << *Sym; + EmitEOL(); + + return false; +} + +bool MCAsmStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { + if (this->MCStreamer::EmitCFILsda(Sym, Encoding)) + return true; + + OS << "\t.cfi_lsda " << Encoding << ", " << *Sym; + EmitEOL(); + + return false; } void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { @@ -610,7 +793,7 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); for (unsigned j = 0; j != Info.TargetSize; ++j) { unsigned Index = F.getOffset() * 8 + Info.TargetOffset + j; assert(Index < Code.size() * 8 && "Invalid offset in fixup!"); @@ -618,6 +801,8 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { } } + // FIXME: Node the fixup comments for Thumb2 are completely bogus since the + // high order halfword of a 32-bit Thumb2 instruction is emitted first. OS << "encoding: ["; for (unsigned i = 0, e = Code.size(); i != e; ++i) { if (i) @@ -637,15 +822,26 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { if (MapEntry == 0) { OS << format("0x%02x", uint8_t(Code[i])); } else { - assert(Code[i] == 0 && "Encoder wrote into fixed up bit!"); - OS << char('A' + MapEntry - 1); + if (Code[i]) { + // FIXME: Some of the 8 bits require fix up. + OS << format("0x%02x", uint8_t(Code[i])) << '\'' + << char('A' + MapEntry - 1) << '\''; + } else + OS << char('A' + MapEntry - 1); } } else { // Otherwise, write out in binary. OS << "0b"; for (unsigned j = 8; j--;) { unsigned Bit = (Code[i] >> j) & 1; - if (uint8_t MapEntry = FixupMap[i * 8 + j]) { + + unsigned FixupBit; + if (getContext().getTargetAsmInfo().isLittleEndian()) + FixupBit = i * 8 + j; + else + FixupBit = i * 8 + (7-j); + + if (uint8_t MapEntry = FixupMap[FixupBit]) { assert(Bit == 0 && "Encoder wrote into fixed up bit!"); OS << char('A' + MapEntry - 1); } else @@ -657,14 +853,17 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { MCFixup &F = Fixups[i]; - const MCFixupKindInfo &Info = Emitter->getFixupKindInfo(F.getKind()); + const MCFixupKindInfo &Info = AsmBackend->getFixupKindInfo(F.getKind()); OS << " fixup " << char('A' + i) << " - " << "offset: " << F.getOffset() << ", value: " << *F.getValue() << ", kind: " << Info.Name << "\n"; } } void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { - assert(CurSection && "Cannot emit contents before setting section!"); + assert(getCurrentSection() && "Cannot emit contents before setting section!"); + + if (!UseLoc) + MCLineEntry::Make(this, getCurrentSection()); // Show the encoding in a comment if we have a code emitter. if (Emitter) @@ -684,7 +883,7 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { EmitEOL(); } -/// EmitRawText - If this file is backed by a assembly streamer, this dumps +/// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. void MCAsmStreamer::EmitRawText(StringRef String) { @@ -695,13 +894,16 @@ void MCAsmStreamer::EmitRawText(StringRef String) { } void MCAsmStreamer::Finish() { + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles() && !UseLoc) + MCDwarfFileTable::Emit(this); } MCStreamer *llvm::createAsmStreamer(MCContext &Context, formatted_raw_ostream &OS, - bool isLittleEndian, - bool isVerboseAsm, MCInstPrinter *IP, - MCCodeEmitter *CE, bool ShowInst) { - return new MCAsmStreamer(Context, OS, isLittleEndian, isVerboseAsm, - IP, CE, ShowInst); + bool isVerboseAsm, bool useLoc, + MCInstPrinter *IP, MCCodeEmitter *CE, + TargetAsmBackend *TAB, bool ShowInst) { + return new MCAsmStreamer(Context, OS, isVerboseAsm, useLoc, + IP, CE, TAB, ShowInst); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index f0e1d7f..9992646 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -11,10 +11,13 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" @@ -36,7 +39,6 @@ STATISTIC(FragmentLayouts, "Number of fragment layouts"); STATISTIC(ObjectBytes, "Number of emitted object file bytes"); STATISTIC(RelaxationSteps, "Number of assembler layout and relaxation steps"); STATISTIC(RelaxedInstructions, "Number of relaxed instructions"); -STATISTIC(SectionLayouts, "Number of section layouts"); } } @@ -48,131 +50,78 @@ STATISTIC(SectionLayouts, "Number of section layouts"); /* *** */ MCAsmLayout::MCAsmLayout(MCAssembler &Asm) - : Assembler(Asm), LastValidFragment(0) + : Assembler(Asm), LastValidFragment() { // Compute the section layout order. Virtual sections must go last. for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) - if (!Asm.getBackend().isVirtualSection(it->getSection())) + if (!it->getSection().isVirtualSection()) SectionOrder.push_back(&*it); for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) - if (Asm.getBackend().isVirtualSection(it->getSection())) + if (it->getSection().isVirtualSection()) SectionOrder.push_back(&*it); } -bool MCAsmLayout::isSectionUpToDate(const MCSectionData *SD) const { - // The first section is always up-to-date. - unsigned Index = SD->getLayoutOrder(); - if (!Index) - return true; - - // Otherwise, sections are always implicitly computed when the preceeding - // fragment is layed out. - const MCSectionData *Prev = getSectionOrder()[Index - 1]; - return isFragmentUpToDate(&(Prev->getFragmentList().back())); -} - bool MCAsmLayout::isFragmentUpToDate(const MCFragment *F) const { - return (LastValidFragment && - F->getLayoutOrder() <= LastValidFragment->getLayoutOrder()); + const MCSectionData &SD = *F->getParent(); + const MCFragment *LastValid = LastValidFragment.lookup(&SD); + if (!LastValid) + return false; + assert(LastValid->getParent() == F->getParent()); + return F->getLayoutOrder() <= LastValid->getLayoutOrder(); } -void MCAsmLayout::UpdateForSlide(MCFragment *F, int SlideAmount) { +void MCAsmLayout::Invalidate(MCFragment *F) { // If this fragment wasn't already up-to-date, we don't need to do anything. if (!isFragmentUpToDate(F)) return; - // Otherwise, reset the last valid fragment to the predecessor of the - // invalidated fragment. - LastValidFragment = F->getPrevNode(); - if (!LastValidFragment) { - unsigned Index = F->getParent()->getLayoutOrder(); - if (Index != 0) { - MCSectionData *Prev = getSectionOrder()[Index - 1]; - LastValidFragment = &(Prev->getFragmentList().back()); - } - } + // Otherwise, reset the last valid fragment to this fragment. + const MCSectionData &SD = *F->getParent(); + LastValidFragment[&SD] = F; } void MCAsmLayout::EnsureValid(const MCFragment *F) const { + MCSectionData &SD = *F->getParent(); + + MCFragment *Cur = LastValidFragment[&SD]; + if (!Cur) + Cur = &*SD.begin(); + else + Cur = Cur->getNextNode(); + // Advance the layout position until the fragment is up-to-date. while (!isFragmentUpToDate(F)) { - // Advance to the next fragment. - MCFragment *Cur = LastValidFragment; - if (Cur) - Cur = Cur->getNextNode(); - if (!Cur) { - unsigned NextIndex = 0; - if (LastValidFragment) - NextIndex = LastValidFragment->getParent()->getLayoutOrder() + 1; - Cur = SectionOrder[NextIndex]->begin(); - } - const_cast<MCAsmLayout*>(this)->LayoutFragment(Cur); + Cur = Cur->getNextNode(); } } -void MCAsmLayout::FragmentReplaced(MCFragment *Src, MCFragment *Dst) { - if (LastValidFragment == Src) - LastValidFragment = Dst; - - Dst->Offset = Src->Offset; - Dst->EffectiveSize = Src->EffectiveSize; -} - -uint64_t MCAsmLayout::getFragmentAddress(const MCFragment *F) const { - assert(F->getParent() && "Missing section()!"); - return getSectionAddress(F->getParent()) + getFragmentOffset(F); -} - -uint64_t MCAsmLayout::getFragmentEffectiveSize(const MCFragment *F) const { - EnsureValid(F); - assert(F->EffectiveSize != ~UINT64_C(0) && "Address not set!"); - return F->EffectiveSize; -} - uint64_t MCAsmLayout::getFragmentOffset(const MCFragment *F) const { EnsureValid(F); assert(F->Offset != ~UINT64_C(0) && "Address not set!"); return F->Offset; } -uint64_t MCAsmLayout::getSymbolAddress(const MCSymbolData *SD) const { - assert(SD->getFragment() && "Invalid getAddress() on undefined symbol!"); - return getFragmentAddress(SD->getFragment()) + SD->getOffset(); -} - -uint64_t MCAsmLayout::getSectionAddress(const MCSectionData *SD) const { - EnsureValid(SD->begin()); - assert(SD->Address != ~UINT64_C(0) && "Address not set!"); - return SD->Address; +uint64_t MCAsmLayout::getSymbolOffset(const MCSymbolData *SD) const { + assert(SD->getFragment() && "Invalid getOffset() on undefined symbol!"); + return getFragmentOffset(SD->getFragment()) + SD->getOffset(); } uint64_t MCAsmLayout::getSectionAddressSize(const MCSectionData *SD) const { // The size is the last fragment's end offset. const MCFragment &F = SD->getFragmentList().back(); - return getFragmentOffset(&F) + getFragmentEffectiveSize(&F); + return getFragmentOffset(&F) + getAssembler().ComputeFragmentSize(*this, F); } uint64_t MCAsmLayout::getSectionFileSize(const MCSectionData *SD) const { // Virtual sections have no file size. - if (getAssembler().getBackend().isVirtualSection(SD->getSection())) + if (SD->getSection().isVirtualSection()) return 0; // Otherwise, the file size is the same as the address space size. return getSectionAddressSize(SD); } -uint64_t MCAsmLayout::getSectionSize(const MCSectionData *SD) const { - // The logical size is the address space size minus any tail padding. - uint64_t Size = getSectionAddressSize(SD); - const MCAlignFragment *AF = - dyn_cast<MCAlignFragment>(&(SD->getFragmentList().back())); - if (AF && AF->hasOnlyAlignAddress()) - Size -= getFragmentEffectiveSize(AF); - - return Size; -} - /* *** */ MCFragment::MCFragment() : Kind(FragmentType(~0)) { @@ -182,8 +131,7 @@ MCFragment::~MCFragment() { } MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent) - : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)), - EffectiveSize(~UINT64_C(0)) + : Kind(_Kind), Parent(_Parent), Atom(0), Offset(~UINT64_C(0)) { if (Parent) Parent->getFragmentList().push_back(this); @@ -195,8 +143,8 @@ MCSectionData::MCSectionData() : Section(0) {} MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) : Section(&_Section), + Ordinal(~UINT32_C(0)), Alignment(1), - Address(~UINT64_C(0)), HasInstructions(false) { if (A) @@ -220,99 +168,17 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, /* *** */ -MCAssembler::MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend, - MCCodeEmitter &_Emitter, raw_ostream &_OS) - : Context(_Context), Backend(_Backend), Emitter(_Emitter), - OS(_OS), RelaxAll(false), SubsectionsViaSymbols(false) +MCAssembler::MCAssembler(MCContext &Context_, TargetAsmBackend &Backend_, + MCCodeEmitter &Emitter_, MCObjectWriter &Writer_, + raw_ostream &OS_) + : Context(Context_), Backend(Backend_), Emitter(Emitter_), Writer(Writer_), + OS(OS_), RelaxAll(false), NoExecStack(false), SubsectionsViaSymbols(false) { } MCAssembler::~MCAssembler() { } -static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm, - const MCFixup &Fixup, - const MCValue Target, - const MCSection *BaseSection) { - // The effective fixup address is - // addr(atom(A)) + offset(A) - // - addr(atom(B)) - offset(B) - // - addr(<base symbol>) + <fixup offset from base symbol> - // and the offsets are not relocatable, so the fixup is fully resolved when - // addr(atom(A)) - addr(atom(B)) - addr(<base symbol>)) == 0. - // - // The simple (Darwin, except on x86_64) way of dealing with this was to - // assume that any reference to a temporary symbol *must* be a temporary - // symbol in the same atom, unless the sections differ. Therefore, any PCrel - // relocation to a temporary symbol (in the same section) is fully - // resolved. This also works in conjunction with absolutized .set, which - // requires the compiler to use .set to absolutize the differences between - // symbols which the compiler knows to be assembly time constants, so we don't - // need to worry about considering symbol differences fully resolved. - - // Non-relative fixups are only resolved if constant. - if (!BaseSection) - return Target.isAbsolute(); - - // Otherwise, relative fixups are only resolved if not a difference and the - // target is a temporary in the same section. - if (Target.isAbsolute() || Target.getSymB()) - return false; - - const MCSymbol *A = &Target.getSymA()->getSymbol(); - if (!A->isTemporary() || !A->isInSection() || - &A->getSection() != BaseSection) - return false; - - return true; -} - -static bool isScatteredFixupFullyResolved(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFixup &Fixup, - const MCValue Target, - const MCSymbolData *BaseSymbol) { - // The effective fixup address is - // addr(atom(A)) + offset(A) - // - addr(atom(B)) - offset(B) - // - addr(BaseSymbol) + <fixup offset from base symbol> - // and the offsets are not relocatable, so the fixup is fully resolved when - // addr(atom(A)) - addr(atom(B)) - addr(BaseSymbol) == 0. - // - // Note that "false" is almost always conservatively correct (it means we emit - // a relocation which is unnecessary), except when it would force us to emit a - // relocation which the target cannot encode. - - const MCSymbolData *A_Base = 0, *B_Base = 0; - if (const MCSymbolRefExpr *A = Target.getSymA()) { - // Modified symbol references cannot be resolved. - if (A->getKind() != MCSymbolRefExpr::VK_None) - return false; - - A_Base = Asm.getAtom(Layout, &Asm.getSymbolData(A->getSymbol())); - if (!A_Base) - return false; - } - - if (const MCSymbolRefExpr *B = Target.getSymB()) { - // Modified symbol references cannot be resolved. - if (B->getKind() != MCSymbolRefExpr::VK_None) - return false; - - B_Base = Asm.getAtom(Layout, &Asm.getSymbolData(B->getSymbol())); - if (!B_Base) - return false; - } - - // If there is no base, A and B have to be the same atom for this fixup to be - // fully resolved. - if (!BaseSymbol) - return A_Base == B_Base; - - // Otherwise, B must be missing and A must be the base. - return !B_Base && BaseSymbol == A_Base; -} - bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const { // Non-temporary labels should always be visible to the linker. if (!Symbol.isTemporary()) @@ -326,8 +192,7 @@ bool MCAssembler::isSymbolLinkerVisible(const MCSymbol &Symbol) const { return getBackend().doesSectionRequireSymbols(Symbol.getSection()); } -const MCSymbolData *MCAssembler::getAtom(const MCAsmLayout &Layout, - const MCSymbolData *SD) const { +const MCSymbolData *MCAssembler::getAtom(const MCSymbolData *SD) const { // Linker visible symbols define atoms. if (isSymbolLinkerVisible(SD->getSymbol())) return SD; @@ -351,67 +216,78 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, MCValue &Target, uint64_t &Value) const { ++stats::EvaluateFixup; - if (!Fixup.getValue()->EvaluateAsRelocatable(Target, &Layout)) + if (!Fixup.getValue()->EvaluateAsRelocatable(Target, Layout)) report_fatal_error("expected relocatable expression"); - // FIXME: How do non-scattered symbols work in ELF? I presume the linker - // doesn't support small relocations, but then under what criteria does the - // assembler allow symbol differences? + bool IsPCRel = Backend.getFixupKindInfo( + Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; + + bool IsResolved; + if (IsPCRel) { + if (Target.getSymB()) { + IsResolved = false; + } else if (!Target.getSymA()) { + IsResolved = false; + } else { + const MCSymbolRefExpr *A = Target.getSymA(); + const MCSymbol &SA = A->getSymbol(); + if (A->getKind() != MCSymbolRefExpr::VK_None || + SA.AliasedSymbol().isUndefined()) { + IsResolved = false; + } else { + const MCSymbolData &DataA = getSymbolData(SA); + IsResolved = + getWriter().IsSymbolRefDifferenceFullyResolvedImpl(*this, DataA, + *DF, false, true); + } + } + } else { + IsResolved = Target.isAbsolute(); + } Value = Target.getConstant(); - bool IsPCRel = Emitter.getFixupKindInfo( - Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; - bool IsResolved = true; + bool IsThumb = false; if (const MCSymbolRefExpr *A = Target.getSymA()) { - if (A->getSymbol().isDefined()) - Value += Layout.getSymbolAddress(&getSymbolData(A->getSymbol())); - else - IsResolved = false; + const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value += Layout.getSymbolOffset(&getSymbolData(Sym)); + if (isThumbFunc(&Sym)) + IsThumb = true; } if (const MCSymbolRefExpr *B = Target.getSymB()) { - if (B->getSymbol().isDefined()) - Value -= Layout.getSymbolAddress(&getSymbolData(B->getSymbol())); - else - IsResolved = false; + const MCSymbol &Sym = B->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value -= Layout.getSymbolOffset(&getSymbolData(Sym)); } - // If we are using scattered symbols, determine whether this value is actually - // resolved; scattering may cause atoms to move. - if (IsResolved && getBackend().hasScatteredSymbols()) { - if (getBackend().hasReliableSymbolDifference()) { - // If this is a PCrel relocation, find the base atom (identified by its - // symbol) that the fixup value is relative to. - const MCSymbolData *BaseSymbol = 0; - if (IsPCRel) { - BaseSymbol = DF->getAtom(); - if (!BaseSymbol) - IsResolved = false; - } - if (IsResolved) - IsResolved = isScatteredFixupFullyResolved(*this, Layout, Fixup, Target, - BaseSymbol); - } else { - const MCSection *BaseSection = 0; - if (IsPCRel) - BaseSection = &DF->getParent()->getSection(); + bool ShouldAlignPC = Backend.getFixupKindInfo(Fixup.getKind()).Flags & + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits; + assert((ShouldAlignPC ? IsPCRel : true) && + "FKF_IsAlignedDownTo32Bits is only allowed on PC-relative fixups!"); - IsResolved = isScatteredFixupFullyResolvedSimple(*this, Fixup, Target, - BaseSection); - } + if (IsPCRel) { + uint32_t Offset = Layout.getFragmentOffset(DF) + Fixup.getOffset(); + + // A number of ARM fixups in Thumb mode require that the effective PC + // address be determined as the 32-bit aligned version of the actual offset. + if (ShouldAlignPC) Offset &= ~0x3; + Value -= Offset; } - if (IsPCRel) - Value -= Layout.getFragmentAddress(DF) + Fixup.getOffset(); + // ARM fixups based from a thumb function address need to have the low + // bit set. The actual value is always at least 16-bit aligned, so the + // low bit is normally clear and available for use as an ISA flag for + // interworking. + if (IsThumb) + Value |= 1; return IsResolved; } -uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, - const MCFragment &F, - uint64_t SectionAddress, - uint64_t FragmentOffset) const { +uint64_t MCAssembler::ComputeFragmentSize(const MCAsmLayout &Layout, + const MCFragment &F) const { switch (F.getKind()) { case MCFragment::FT_Data: return cast<MCDataFragment>(F).getContents().size(); @@ -420,62 +296,48 @@ uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, case MCFragment::FT_Inst: return cast<MCInstFragment>(F).getInstSize(); + case MCFragment::FT_LEB: + return cast<MCLEBFragment>(F).getContents().size(); + case MCFragment::FT_Align: { const MCAlignFragment &AF = cast<MCAlignFragment>(F); - - assert((!AF.hasOnlyAlignAddress() || !AF.getNextNode()) && - "Invalid OnlyAlignAddress bit, not the last fragment!"); - - uint64_t Size = OffsetToAlignment(SectionAddress + FragmentOffset, - AF.getAlignment()); - - // Honor MaxBytesToEmit. + unsigned Offset = Layout.getFragmentOffset(&AF); + unsigned Size = OffsetToAlignment(Offset, AF.getAlignment()); if (Size > AF.getMaxBytesToEmit()) return 0; - return Size; } case MCFragment::FT_Org: { - const MCOrgFragment &OF = cast<MCOrgFragment>(F); - - // FIXME: We should compute this sooner, we don't want to recurse here, and - // we would like to be more functional. + MCOrgFragment &OF = cast<MCOrgFragment>(F); int64_t TargetLocation; - if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout)) + if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, Layout)) report_fatal_error("expected assembly-time absolute expression"); // FIXME: We need a way to communicate this error. - int64_t Offset = TargetLocation - FragmentOffset; - if (Offset < 0) + uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); + int64_t Size = TargetLocation - FragmentOffset; + if (Size < 0 || Size >= 0x40000000) report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + - "' (at offset '" + Twine(FragmentOffset) + "'"); - - return Offset; + "' (at offset '" + Twine(FragmentOffset) + "')"); + return Size; } + + case MCFragment::FT_Dwarf: + return cast<MCDwarfLineAddrFragment>(F).getContents().size(); + case MCFragment::FT_DwarfFrame: + return cast<MCDwarfCallFrameFragment>(F).getContents().size(); } assert(0 && "invalid fragment kind"); return 0; } -void MCAsmLayout::LayoutFile() { - // Initialize the first section and set the valid fragment layout point. All - // actual layout computations are done lazily. - LastValidFragment = 0; - if (!getSectionOrder().empty()) - getSectionOrder().front()->Address = 0; -} - void MCAsmLayout::LayoutFragment(MCFragment *F) { MCFragment *Prev = F->getPrevNode(); // We should never try to recompute something which is up-to-date. assert(!isFragmentUpToDate(F) && "Attempt to recompute up-to-date fragment!"); - // We should never try to compute the fragment layout if the section isn't - // up-to-date. - assert(isSectionUpToDate(F->getParent()) && - "Attempt to compute fragment before it's section!"); // We should never try to compute the fragment layout if it's predecessor // isn't up-to-date. assert((!Prev || isFragmentUpToDate(Prev)) && @@ -483,55 +345,26 @@ void MCAsmLayout::LayoutFragment(MCFragment *F) { ++stats::FragmentLayouts; - // Compute the fragment start address. - uint64_t StartAddress = F->getParent()->Address; - uint64_t Address = StartAddress; - if (Prev) - Address += Prev->Offset + Prev->EffectiveSize; - // Compute fragment offset and size. - F->Offset = Address - StartAddress; - F->EffectiveSize = getAssembler().ComputeFragmentSize(*this, *F, StartAddress, - F->Offset); - LastValidFragment = F; - - // If this is the last fragment in a section, update the next section address. - if (!F->getNextNode()) { - unsigned NextIndex = F->getParent()->getLayoutOrder() + 1; - if (NextIndex != getSectionOrder().size()) - LayoutSection(getSectionOrder()[NextIndex]); - } -} - -void MCAsmLayout::LayoutSection(MCSectionData *SD) { - unsigned SectionOrderIndex = SD->getLayoutOrder(); - - ++stats::SectionLayouts; - - // Compute the section start address. - uint64_t StartAddress = 0; - if (SectionOrderIndex) { - MCSectionData *Prev = getSectionOrder()[SectionOrderIndex - 1]; - StartAddress = getSectionAddress(Prev) + getSectionAddressSize(Prev); - } - - // Honor the section alignment requirements. - StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); + uint64_t Offset = 0; + if (Prev) + Offset += Prev->Offset + getAssembler().ComputeFragmentSize(*this, *Prev); - // Set the section address. - SD->Address = StartAddress; + F->Offset = Offset; + LastValidFragment[F->getParent()] = F; } /// WriteFragmentData - Write the \arg F data to the output file. static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, - const MCFragment &F, MCObjectWriter *OW) { + const MCFragment &F) { + MCObjectWriter *OW = &Asm.getWriter(); uint64_t Start = OW->getStream().tell(); (void) Start; ++stats::EmittedFragments; // FIXME: Embed in fragments instead? - uint64_t FragmentSize = Layout.getFragmentEffectiveSize(&F); + uint64_t FragmentSize = Asm.ComputeFragmentSize(Layout, F); switch (F.getKind()) { case MCFragment::FT_Align: { MCAlignFragment &AF = cast<MCAlignFragment>(F); @@ -598,9 +431,17 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } - case MCFragment::FT_Inst: - llvm_unreachable("unexpected inst fragment after lowering"); + case MCFragment::FT_Inst: { + MCInstFragment &IF = cast<MCInstFragment>(F); + OW->WriteBytes(StringRef(IF.getCode().begin(), IF.getCode().size())); + break; + } + + case MCFragment::FT_LEB: { + MCLEBFragment &LF = cast<MCLEBFragment>(F); + OW->WriteBytes(LF.getContents().str()); break; + } case MCFragment::FT_Org: { MCOrgFragment &OF = cast<MCOrgFragment>(F); @@ -610,16 +451,26 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } + + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); + OW->WriteBytes(OF.getContents().str()); + break; + } + case MCFragment::FT_DwarfFrame: { + const MCDwarfCallFrameFragment &CF = cast<MCDwarfCallFrameFragment>(F); + OW->WriteBytes(CF.getContents().str()); + break; + } } assert(OW->getStream().tell() - Start == FragmentSize); } void MCAssembler::WriteSectionData(const MCSectionData *SD, - const MCAsmLayout &Layout, - MCObjectWriter *OW) const { + const MCAsmLayout &Layout) const { // Ignore virtual sections. - if (getBackend().isVirtualSection(SD->getSection())) { + if (SD->getSection().isVirtualSection()) { assert(Layout.getSectionFileSize(SD) == 0 && "Invalid size for section!"); // Check that contents are only things legal inside a virtual section. @@ -657,51 +508,34 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, return; } - uint64_t Start = OW->getStream().tell(); + uint64_t Start = getWriter().getStream().tell(); (void) Start; for (MCSectionData::const_iterator it = SD->begin(), ie = SD->end(); it != ie; ++it) - WriteFragmentData(*this, Layout, *it, OW); + WriteFragmentData(*this, Layout, *it); - assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD)); + assert(getWriter().getStream().tell() - Start == + Layout.getSectionAddressSize(SD)); } -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++; - } +uint64_t MCAssembler::HandleFixup(const MCAsmLayout &Layout, + MCFragment &F, + const MCFixup &Fixup) { + // Evaluate the fixup. + MCValue Target; + uint64_t FixedValue; + if (!EvaluateFixup(Layout, Fixup, &F, Target, FixedValue)) { + // The fixup was unresolved, we need a relocation. Inform the object + // writer of the relocation, and give it an opportunity to adjust the + // fixup value if need be. + getWriter().RecordRelocation(*this, Layout, &F, Fixup, Target, FixedValue); + } + return FixedValue; + } - 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) { +void MCAssembler::Finish() { DEBUG_WITH_TYPE("mc-dump", { llvm::errs() << "assembler backend - pre-layout\n--\n"; dump(); }); @@ -709,47 +543,23 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { // Create the layout object. MCAsmLayout Layout(*this); - // Insert additional align fragments for concrete sections to explicitly pad - // the previous section to match their alignment requirements. This is for - // 'gas' compatibility, it shouldn't strictly be necessary. - // - // FIXME: This may be Mach-O specific. - for (unsigned i = 1, e = Layout.getSectionOrder().size(); i < e; ++i) { - MCSectionData *SD = Layout.getSectionOrder()[i]; - - // Ignore sections without alignment requirements. - unsigned Align = SD->getAlignment(); - if (Align <= 1) - continue; - - // Ignore virtual sections, they don't cause file size modifications. - if (getBackend().isVirtualSection(SD->getSection())) - continue; - - // Otherwise, create a new align fragment at the end of the previous - // section. - MCAlignFragment *AF = new MCAlignFragment(Align, 0, 1, Align, - Layout.getSectionOrder()[i - 1]); - AF->setOnlyAlignAddress(true); - } - // Create dummy fragments and assign section ordinals. unsigned SectionIndex = 0; for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { // Create dummy fragments to eliminate any empty sections, this simplifies // layout. if (it->getFragmentList().empty()) - new MCFillFragment(0, 1, 0, it); + new MCDataFragment(it); it->setOrdinal(SectionIndex++); } // Assign layout order indices to sections and fragments. - unsigned FragmentIndex = 0; for (unsigned i = 0, e = Layout.getSectionOrder().size(); i != e; ++i) { MCSectionData *SD = Layout.getSectionOrder()[i]; SD->setLayoutOrder(i); + unsigned FragmentIndex = 0; for (MCSectionData::iterator it2 = SD->begin(), ie2 = SD->end(); it2 != ie2; ++it2) it2->setLayoutOrder(FragmentIndex++); @@ -772,48 +582,39 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { uint64_t StartOffset = OS.tell(); - 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). - Writer->ExecutePostLayoutBinding(*this); + getWriter().ExecutePostLayoutBinding(*this, Layout); // Evaluate and apply the fixups, generating relocation entries as necessary. for (MCAssembler::iterator it = begin(), ie = end(); it != ie; ++it) { for (MCSectionData::iterator it2 = it->begin(), ie2 = it->end(); it2 != ie2; ++it2) { MCDataFragment *DF = dyn_cast<MCDataFragment>(it2); - if (!DF) - continue; - - for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(), - ie3 = DF->fixup_end(); it3 != ie3; ++it3) { - MCFixup &Fixup = *it3; - - // Evaluate the fixup. - MCValue Target; - uint64_t FixedValue; - if (!EvaluateFixup(Layout, Fixup, DF, Target, FixedValue)) { - // The fixup was unresolved, we need a relocation. Inform the object - // writer of the relocation, and give it an opportunity to adjust the - // fixup value if need be. - Writer->RecordRelocation(*this, Layout, DF, Fixup, Target,FixedValue); + if (DF) { + for (MCDataFragment::fixup_iterator it3 = DF->fixup_begin(), + ie3 = DF->fixup_end(); it3 != ie3; ++it3) { + MCFixup &Fixup = *it3; + uint64_t FixedValue = HandleFixup(Layout, *DF, Fixup); + getBackend().ApplyFixup(Fixup, DF->getContents().data(), + DF->getContents().size(), FixedValue); + } + } + MCInstFragment *IF = dyn_cast<MCInstFragment>(it2); + if (IF) { + for (MCInstFragment::fixup_iterator it3 = IF->fixup_begin(), + ie3 = IF->fixup_end(); it3 != ie3; ++it3) { + MCFixup &Fixup = *it3; + uint64_t FixedValue = HandleFixup(Layout, *IF, Fixup); + getBackend().ApplyFixup(Fixup, IF->getCode().data(), + IF->getCode().size(), FixedValue); } - - getBackend().ApplyFixup(Fixup, *DF, FixedValue); } } } // Write the object file. - Writer->WriteObject(*this, Layout); + getWriter().WriteObject(*this, Layout); stats::ObjectBytes += OS.tell() - StartOffset; } @@ -852,100 +653,144 @@ bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF, return false; } -bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { - ++stats::RelaxationSteps; +bool MCAssembler::RelaxInstruction(MCAsmLayout &Layout, + MCInstFragment &IF) { + if (!FragmentNeedsRelaxation(&IF, Layout)) + return false; - // Layout the sections in order. - Layout.LayoutFile(); + ++stats::RelaxedInstructions; + // FIXME-PERF: We could immediately lower out instructions if we can tell + // they are fully resolved, to avoid retesting on later passes. + + // Relax the fragment. + + MCInst Relaxed; + getBackend().RelaxInstruction(IF.getInst(), Relaxed); + + // Encode the new instruction. + // + // FIXME-PERF: If it matters, we could let the target do this. It can + // probably do so more efficiently in many cases. + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups); + VecOS.flush(); + + // Update the instruction fragment. + IF.setInst(Relaxed); + IF.getCode() = Code; + IF.getFixups().clear(); + // FIXME: Eliminate copy. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) + IF.getFixups().push_back(Fixups[i]); + + return true; +} + +bool MCAssembler::RelaxLEB(MCAsmLayout &Layout, MCLEBFragment &LF) { + int64_t Value = 0; + uint64_t OldSize = LF.getContents().size(); + LF.getValue().EvaluateAsAbsolute(Value, Layout); + SmallString<8> &Data = LF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + if (LF.isSigned()) + MCObjectWriter::EncodeSLEB128(Value, OSE); + else + MCObjectWriter::EncodeULEB128(Value, OSE); + OSE.flush(); + return OldSize != LF.getContents().size(); +} + +bool MCAssembler::RelaxDwarfLineAddr(MCAsmLayout &Layout, + MCDwarfLineAddrFragment &DF) { + int64_t AddrDelta = 0; + uint64_t OldSize = DF.getContents().size(); + bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + int64_t LineDelta; + LineDelta = DF.getLineDelta(); + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OSE); + OSE.flush(); + return OldSize != Data.size(); +} + +bool MCAssembler::RelaxDwarfCallFrameFragment(MCAsmLayout &Layout, + MCDwarfCallFrameFragment &DF) { + int64_t AddrDelta = 0; + uint64_t OldSize = DF.getContents().size(); + bool IsAbs = DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, Layout); + (void)IsAbs; + assert(IsAbs); + SmallString<8> &Data = DF.getContents(); + Data.clear(); + raw_svector_ostream OSE(Data); + MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OSE); + OSE.flush(); + return OldSize != Data.size(); +} + +bool MCAssembler::LayoutSectionOnce(MCAsmLayout &Layout, + MCSectionData &SD) { + MCFragment *FirstInvalidFragment = NULL; // Scan for fragments that need relaxation. + for (MCSectionData::iterator it2 = SD.begin(), + ie2 = SD.end(); it2 != ie2; ++it2) { + // Check if this is an fragment that needs relaxation. + bool relaxedFrag = false; + switch(it2->getKind()) { + default: + break; + case MCFragment::FT_Inst: + relaxedFrag = RelaxInstruction(Layout, *cast<MCInstFragment>(it2)); + break; + case MCFragment::FT_Dwarf: + relaxedFrag = RelaxDwarfLineAddr(Layout, + *cast<MCDwarfLineAddrFragment>(it2)); + break; + case MCFragment::FT_DwarfFrame: + relaxedFrag = + RelaxDwarfCallFrameFragment(Layout, + *cast<MCDwarfCallFrameFragment>(it2)); + break; + case MCFragment::FT_LEB: + relaxedFrag = RelaxLEB(Layout, *cast<MCLEBFragment>(it2)); + break; + } + // Update the layout, and remember that we relaxed. + if (relaxedFrag && !FirstInvalidFragment) + FirstInvalidFragment = it2; + } + if (FirstInvalidFragment) { + Layout.Invalidate(FirstInvalidFragment); + return true; + } + return false; +} + +bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { + ++stats::RelaxationSteps; + bool WasRelaxed = false; for (iterator it = begin(), ie = end(); it != ie; ++it) { MCSectionData &SD = *it; - - for (MCSectionData::iterator it2 = SD.begin(), - ie2 = SD.end(); it2 != ie2; ++it2) { - // Check if this is an instruction fragment that needs relaxation. - MCInstFragment *IF = dyn_cast<MCInstFragment>(it2); - if (!IF || !FragmentNeedsRelaxation(IF, Layout)) - continue; - - ++stats::RelaxedInstructions; - - // FIXME-PERF: We could immediately lower out instructions if we can tell - // they are fully resolved, to avoid retesting on later passes. - - // Relax the fragment. - - MCInst Relaxed; - getBackend().RelaxInstruction(IF->getInst(), Relaxed); - - // Encode the new instruction. - // - // FIXME-PERF: If it matters, we could let the target do this. It can - // probably do so more efficiently in many cases. - SmallVector<MCFixup, 4> Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getEmitter().EncodeInstruction(Relaxed, VecOS, Fixups); - VecOS.flush(); - - // Update the instruction fragment. - int SlideAmount = Code.size() - IF->getInstSize(); - IF->setInst(Relaxed); - IF->getCode() = Code; - IF->getFixups().clear(); - // FIXME: Eliminate copy. - for (unsigned i = 0, e = Fixups.size(); i != e; ++i) - IF->getFixups().push_back(Fixups[i]); - - // Update the layout, and remember that we relaxed. - Layout.UpdateForSlide(IF, SlideAmount); + while(LayoutSectionOnce(Layout, SD)) WasRelaxed = true; - } } return WasRelaxed; } void MCAssembler::FinishLayout(MCAsmLayout &Layout) { - // Lower out any instruction fragments, to simplify the fixup application and - // output. - // - // FIXME-PERF: We don't have to do this, but the assumption is that it is - // cheap (we will mostly end up eliminating fragments and appending on to data - // fragments), so the extra complexity downstream isn't worth it. Evaluate - // this assumption. - for (iterator it = begin(), ie = end(); it != ie; ++it) { - MCSectionData &SD = *it; - - for (MCSectionData::iterator it2 = SD.begin(), - ie2 = SD.end(); it2 != ie2; ++it2) { - MCInstFragment *IF = dyn_cast<MCInstFragment>(it2); - if (!IF) - continue; - - // Create a new data fragment for the instruction. - // - // FIXME-PERF: Reuse previous data fragment if possible. - MCDataFragment *DF = new MCDataFragment(); - SD.getFragmentList().insert(it2, DF); - - // Update the data fragments layout data. - DF->setParent(IF->getParent()); - DF->setAtom(IF->getAtom()); - DF->setLayoutOrder(IF->getLayoutOrder()); - Layout.FragmentReplaced(IF, DF); - - // Copy in the data and the fixups. - DF->getContents().append(IF->getCode().begin(), IF->getCode().end()); - for (unsigned i = 0, e = IF->getFixups().size(); i != e; ++i) - DF->getFixups().push_back(IF->getFixups()[i]); - - // Delete the instruction fragment and update the iterator. - SD.getFragmentList().erase(IF); - it2 = DF; - } + // The layout is done. Mark every fragment as valid. + for (unsigned int i = 0, n = Layout.getSectionOrder().size(); i != n; ++i) { + Layout.getFragmentOffset(&*Layout.getSectionOrder()[i]->rbegin()); } } @@ -972,18 +817,19 @@ void MCFragment::dump() { case MCFragment::FT_Fill: OS << "MCFillFragment"; break; case MCFragment::FT_Inst: OS << "MCInstFragment"; break; case MCFragment::FT_Org: OS << "MCOrgFragment"; break; + case MCFragment::FT_Dwarf: OS << "MCDwarfFragment"; break; + case MCFragment::FT_DwarfFrame: OS << "MCDwarfCallFrameFragment"; break; + case MCFragment::FT_LEB: OS << "MCLEBFragment"; break; } OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder - << " Offset:" << Offset << " EffectiveSize:" << EffectiveSize << ">"; + << " Offset:" << Offset << ">"; switch (getKind()) { case MCFragment::FT_Align: { const MCAlignFragment *AF = cast<MCAlignFragment>(this); if (AF->hasEmitNops()) OS << " (emit nops)"; - if (AF->hasOnlyAlignAddress()) - OS << " (only align section)"; OS << "\n "; OS << " Alignment:" << AF->getAlignment() << " Value:" << AF->getValue() << " ValueSize:" << AF->getValueSize() @@ -1032,6 +878,25 @@ void MCFragment::dump() { OS << " Offset:" << OF->getOffset() << " Value:" << OF->getValue(); break; } + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment *OF = cast<MCDwarfLineAddrFragment>(this); + OS << "\n "; + OS << " AddrDelta:" << OF->getAddrDelta() + << " LineDelta:" << OF->getLineDelta(); + break; + } + case MCFragment::FT_DwarfFrame: { + const MCDwarfCallFrameFragment *CF = cast<MCDwarfCallFrameFragment>(this); + OS << "\n "; + OS << " AddrDelta:" << CF->getAddrDelta(); + break; + } + case MCFragment::FT_LEB: { + const MCLEBFragment *LF = cast<MCLEBFragment>(this); + OS << "\n "; + OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned(); + break; + } } OS << ">"; } @@ -1040,8 +905,7 @@ void MCSectionData::dump() { raw_ostream &OS = llvm::errs(); OS << "<MCSectionData"; - OS << " Alignment:" << getAlignment() << " Address:" << Address - << " Fragments:[\n "; + OS << " Alignment:" << getAlignment() << " Fragments:[\n "; for (iterator it = begin(), ie = end(); it != ie; ++it) { if (it != begin()) OS << ",\n "; it->dump(); diff --git a/lib/MC/MCCodeEmitter.cpp b/lib/MC/MCCodeEmitter.cpp index d513237..c122763 100644 --- a/lib/MC/MCCodeEmitter.cpp +++ b/lib/MC/MCCodeEmitter.cpp @@ -16,15 +16,3 @@ MCCodeEmitter::MCCodeEmitter() { MCCodeEmitter::~MCCodeEmitter() { } - -const MCFixupKindInfo &MCCodeEmitter::getFixupKindInfo(MCFixupKind Kind) const { - static const MCFixupKindInfo Builtins[] = { - { "FK_Data_1", 0, 8, 0 }, - { "FK_Data_2", 0, 16, 0 }, - { "FK_Data_4", 0, 32, 0 }, - { "FK_Data_8", 0, 64, 0 } - }; - - assert(Kind <= 3 && "Unknown fixup kind"); - return Builtins[Kind]; -} diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index e5586a0..018f00c 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -15,8 +15,10 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCLabel.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/Target/TargetAsmInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/ELF.h" using namespace llvm; typedef StringMap<const MCSectionMachO*> MachOUniqueMapTy; @@ -24,8 +26,9 @@ typedef StringMap<const MCSectionELF*> ELFUniqueMapTy; typedef StringMap<const MCSectionCOFF*> COFFUniqueMapTy; -MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), - CurrentDwarfLoc(0,0,0,0,0) { +MCContext::MCContext(const MCAsmInfo &mai, const TargetAsmInfo *tai) : + MAI(mai), TAI(tai), NextUniqueID(0), + CurrentDwarfLoc(0,0,0,DWARF2_FLAG_IS_STMT,0,0) { MachOUniquingMap = 0; ELFUniquingMap = 0; COFFUniquingMap = 0; @@ -40,7 +43,7 @@ MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), MCContext::~MCContext() { // NOTE: The symbols are all allocated out of a bump pointer allocator, // we don't need to free them here. - + // If we have the MachO uniquing map, free it. delete (MachOUniqueMapTy*)MachOUniquingMap; delete (ELFUniqueMapTy*)ELFUniquingMap; @@ -48,6 +51,8 @@ MCContext::~MCContext() { // If the stream for the .secure_log_unique directive was created free it. delete (raw_ostream*)SecureLog; + + delete TAI; } //===----------------------------------------------------------------------===// @@ -56,20 +61,42 @@ MCContext::~MCContext() { MCSymbol *MCContext::GetOrCreateSymbol(StringRef Name) { assert(!Name.empty() && "Normal symbols cannot be unnamed!"); - - // Determine whether this is an assembler temporary or normal label. - bool isTemporary = Name.startswith(MAI.getPrivateGlobalPrefix()); - + // Do the lookup and get the entire StringMapEntry. We want access to the // key if we are creating the entry. StringMapEntry<MCSymbol*> &Entry = Symbols.GetOrCreateValue(Name); - if (Entry.getValue()) return Entry.getValue(); + MCSymbol *Sym = Entry.getValue(); + + if (Sym) + return Sym; + + Sym = CreateSymbol(Name); + Entry.setValue(Sym); + return Sym; +} + +MCSymbol *MCContext::CreateSymbol(StringRef Name) { + // Determine whether this is an assembler temporary or normal label. + bool isTemporary = Name.startswith(MAI.getPrivateGlobalPrefix()); + + StringMapEntry<bool> *NameEntry = &UsedNames.GetOrCreateValue(Name); + if (NameEntry->getValue()) { + assert(isTemporary && "Cannot rename non temporary symbols"); + SmallString<128> NewName; + do { + Twine T = Name + Twine(NextUniqueID++); + T.toVector(NewName); + StringRef foo = NewName; + NameEntry = &UsedNames.GetOrCreateValue(foo); + } while (NameEntry->getValue()); + } + NameEntry->setValue(true); // Ok, the entry doesn't already exist. Have the MCSymbol object itself refer - // to the copy of the string that is embedded in the StringMapEntry. - MCSymbol *Result = new (*this) MCSymbol(Entry.getKey(), isTemporary); - Entry.setValue(Result); - return Result; + // to the copy of the string that is embedded in the UsedNames entry. + MCSymbol *Result = new (*this) MCSymbol(NameEntry->getKey(), isTemporary); + + return Result; } MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { @@ -79,8 +106,11 @@ MCSymbol *MCContext::GetOrCreateSymbol(const Twine &Name) { } MCSymbol *MCContext::CreateTempSymbol() { - return GetOrCreateSymbol(Twine(MAI.getPrivateGlobalPrefix()) + - "tmp" + Twine(NextUniqueID++)); + SmallString<128> NameSV; + Twine Name = Twine(MAI.getPrivateGlobalPrefix()) + "tmp" + + Twine(NextUniqueID++); + Name.toVector(NameSV); + return CreateSymbol(NameSV); } unsigned MCContext::NextInstance(int64_t LocalLabelVal) { @@ -123,49 +153,70 @@ const MCSectionMachO *MCContext:: getMachOSection(StringRef Segment, StringRef Section, unsigned TypeAndAttributes, unsigned Reserved2, SectionKind Kind) { - + // We unique sections by their segment/section pair. The returned section // may not have the same flags as the requested section, if so this should be // diagnosed by the client as an error. - + // Create the map if it doesn't already exist. if (MachOUniquingMap == 0) MachOUniquingMap = new MachOUniqueMapTy(); MachOUniqueMapTy &Map = *(MachOUniqueMapTy*)MachOUniquingMap; - + // Form the name to look up. SmallString<64> Name; Name += Segment; Name.push_back(','); Name += Section; - + // Do the lookup, if we have a hit, return it. const MCSectionMachO *&Entry = Map[Name.str()]; if (Entry) return Entry; - + // Otherwise, return a new section. return Entry = new (*this) MCSectionMachO(Segment, Section, TypeAndAttributes, Reserved2, Kind); } +const MCSectionELF *MCContext:: +getELFSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind) { + return getELFSection(Section, Type, Flags, Kind, 0, ""); +} -const MCSection *MCContext:: +const MCSectionELF *MCContext:: getELFSection(StringRef Section, unsigned Type, unsigned Flags, - SectionKind Kind, bool IsExplicit, unsigned EntrySize) { + SectionKind Kind, unsigned EntrySize, StringRef Group) { if (ELFUniquingMap == 0) ELFUniquingMap = new ELFUniqueMapTy(); ELFUniqueMapTy &Map = *(ELFUniqueMapTy*)ELFUniquingMap; - + // Do the lookup, if we have a hit, return it. StringMapEntry<const MCSectionELF*> &Entry = Map.GetOrCreateValue(Section); if (Entry.getValue()) return Entry.getValue(); - + + // Possibly refine the entry size first. + if (!EntrySize) { + EntrySize = MCSectionELF::DetermineEntrySize(Kind); + } + + MCSymbol *GroupSym = NULL; + if (!Group.empty()) + GroupSym = GetOrCreateSymbol(Group); + MCSectionELF *Result = new (*this) MCSectionELF(Entry.getKey(), Type, Flags, - Kind, IsExplicit, EntrySize); + Kind, EntrySize, GroupSym); Entry.setValue(Result); return Result; } +const MCSectionELF *MCContext::CreateELFGroupSection() { + MCSectionELF *Result = + new (*this) MCSectionELF(".group", ELF::SHT_GROUP, 0, + SectionKind::getReadOnly(), 4, NULL); + return Result; +} + const MCSection *MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, int Selection, @@ -173,15 +224,15 @@ const MCSection *MCContext::getCOFFSection(StringRef Section, if (COFFUniquingMap == 0) COFFUniquingMap = new COFFUniqueMapTy(); COFFUniqueMapTy &Map = *(COFFUniqueMapTy*)COFFUniquingMap; - + // Do the lookup, if we have a hit, return it. StringMapEntry<const MCSectionCOFF*> &Entry = Map.GetOrCreateValue(Section); if (Entry.getValue()) return Entry.getValue(); - + MCSectionCOFF *Result = new (*this) MCSectionCOFF(Entry.getKey(), Characteristics, Selection, Kind); - + Entry.setValue(Result); return Result; } @@ -240,7 +291,7 @@ unsigned MCContext::GetDwarfFile(StringRef FileName, unsigned FileNumber) { // 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())); @@ -251,15 +302,11 @@ unsigned MCContext::GetDwarfFile(StringRef FileName, unsigned FileNumber) { return FileNumber; } -/// ValidateDwarfFileNumber - takes a dwarf file number and returns true if it +/// isValidDwarfFileNumber - takes a dwarf file number and returns true if it /// currently is assigned and false otherwise. -bool MCContext::ValidateDwarfFileNumber(unsigned FileNumber) { +bool MCContext::isValidDwarfFileNumber(unsigned FileNumber) { if(FileNumber == 0 || FileNumber >= MCDwarfFiles.size()) return false; - MCDwarfFile *&ExistingFile = MCDwarfFiles[FileNumber]; - if (ExistingFile) - return true; - else - return false; + return MCDwarfFiles[FileNumber] != 0; } diff --git a/lib/MC/MCDisassembler/EDDisassembler.cpp b/lib/MC/MCDisassembler/EDDisassembler.cpp index 697b3d9..2fd14db 100644 --- a/lib/MC/MCDisassembler/EDDisassembler.cpp +++ b/lib/MC/MCDisassembler/EDDisassembler.cpp @@ -354,7 +354,7 @@ int EDDisassembler::parseInst(SmallVectorImpl<MCParsedAsmOperand*> &operands, SourceMgr sourceMgr; sourceMgr.AddNewSourceBuffer(buf, SMLoc()); // ownership of buf handed over - MCContext context(*AsmInfo); + MCContext context(*AsmInfo, NULL); OwningPtr<MCStreamer> streamer(createNullStreamer(context)); OwningPtr<MCAsmParser> genericParser(createMCAsmParser(*Tgt, sourceMgr, context, *streamer, diff --git a/lib/MC/MCDisassembler/EDDisassembler.h b/lib/MC/MCDisassembler/EDDisassembler.h index e2f850b..71e45f0 100644 --- a/lib/MC/MCDisassembler/EDDisassembler.h +++ b/lib/MC/MCDisassembler/EDDisassembler.h @@ -21,7 +21,7 @@ #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/System/Mutex.h" +#include "llvm/Support/Mutex.h" #include <map> #include <set> @@ -89,8 +89,10 @@ struct EDDisassembler { bool operator<(const CPUKey &key) const { if(Arch > key.Arch) return false; - if(Syntax >= key.Syntax) - return false; + else if (Arch == key.Arch) { + if(Syntax > key.Syntax) + return false; + } return true; } }; diff --git a/lib/MC/MCDisassembler/EDInst.cpp b/lib/MC/MCDisassembler/EDInst.cpp index e22408f..63b049f 100644 --- a/lib/MC/MCDisassembler/EDInst.cpp +++ b/lib/MC/MCDisassembler/EDInst.cpp @@ -62,6 +62,8 @@ int EDInst::stringify() { if (Disassembler.printInst(String, *Inst)) return StringifyResult.setResult(-1); + + String.push_back('\n'); return StringifyResult.setResult(0); } diff --git a/lib/MC/MCDisassembler/EDInst.h b/lib/MC/MCDisassembler/EDInst.h index 39d264f..ceb9505 100644 --- a/lib/MC/MCDisassembler/EDInst.h +++ b/lib/MC/MCDisassembler/EDInst.h @@ -16,7 +16,7 @@ #ifndef LLVM_EDINST_H #define LLVM_EDINST_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include "llvm/ADT/SmallVector.h" #include <string> #include <vector> diff --git a/lib/MC/MCDisassembler/EDOperand.cpp b/lib/MC/MCDisassembler/EDOperand.cpp index 2aed123..cfeb56f 100644 --- a/lib/MC/MCDisassembler/EDOperand.cpp +++ b/lib/MC/MCDisassembler/EDOperand.cpp @@ -260,23 +260,20 @@ int EDOperand::isMemory() { } #ifdef __BLOCKS__ -struct RegisterReaderWrapper { - EDOperand::EDRegisterBlock_t regBlock; -}; +namespace { + struct RegisterReaderWrapper { + EDOperand::EDRegisterBlock_t regBlock; + }; +} -int readerWrapperCallback(uint64_t *value, - unsigned regID, - void *arg) { - struct RegisterReaderWrapper *wrapper = (struct RegisterReaderWrapper *)arg; +static int readerWrapperCallback(uint64_t *value, unsigned regID, void *arg) { + RegisterReaderWrapper *wrapper = (RegisterReaderWrapper *)arg; return wrapper->regBlock(value, regID); } -int EDOperand::evaluate(uint64_t &result, - EDRegisterBlock_t regBlock) { - struct RegisterReaderWrapper wrapper; +int EDOperand::evaluate(uint64_t &result, EDRegisterBlock_t regBlock) { + RegisterReaderWrapper wrapper; wrapper.regBlock = regBlock; - return evaluate(result, - readerWrapperCallback, - (void*)&wrapper); + return evaluate(result, readerWrapperCallback, (void*)&wrapper); } #endif diff --git a/lib/MC/MCDisassembler/EDOperand.h b/lib/MC/MCDisassembler/EDOperand.h index 6e69522..50260ec 100644 --- a/lib/MC/MCDisassembler/EDOperand.h +++ b/lib/MC/MCDisassembler/EDOperand.h @@ -16,7 +16,7 @@ #ifndef LLVM_EDOPERAND_H #define LLVM_EDOPERAND_H -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" namespace llvm { diff --git a/lib/MC/MCDisassembler/EDToken.h b/lib/MC/MCDisassembler/EDToken.h index 6b2aeac..ba46707 100644 --- a/lib/MC/MCDisassembler/EDToken.h +++ b/lib/MC/MCDisassembler/EDToken.h @@ -17,7 +17,7 @@ #define LLVM_EDTOKEN_H #include "llvm/ADT/StringRef.h" -#include "llvm/System/DataTypes.h" +#include "llvm/Support/DataTypes.h" #include <string> #include <vector> diff --git a/lib/MC/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 2da71f9..112d7d8 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -7,11 +7,420 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/FoldingSet.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; +// Given a special op, return the address skip amount (in units of +// DWARF2_LINE_MIN_INSN_LENGTH. +#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE) + +// The maximum address skip amount that can be encoded with a special op. +#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255) + +// First special line opcode - leave room for the standard opcodes. +// Note: If you want to change this, you'll have to update the +// "standard_opcode_lengths" table that is emitted in DwarfFileTable::Emit(). +#define DWARF2_LINE_OPCODE_BASE 13 + +// Minimum line offset in a special line info. opcode. This value +// was chosen to give a reasonable range of values. +#define DWARF2_LINE_BASE -5 + +// Range of line offsets in a special line info. opcode. +# define DWARF2_LINE_RANGE 14 + +// Define the architecture-dependent minimum instruction length (in bytes). +// This value should be rather too small than too big. +# define DWARF2_LINE_MIN_INSN_LENGTH 1 + +// Note: when DWARF2_LINE_MIN_INSN_LENGTH == 1 which is the current setting, +// this routine is a nop and will be optimized away. +static inline uint64_t ScaleAddrDelta(uint64_t AddrDelta) +{ + if (DWARF2_LINE_MIN_INSN_LENGTH == 1) + return AddrDelta; + if (AddrDelta % DWARF2_LINE_MIN_INSN_LENGTH != 0) { + // TODO: report this error, but really only once. + ; + } + return AddrDelta / DWARF2_LINE_MIN_INSN_LENGTH; +} + +// +// This is called when an instruction is assembled into the specified section +// and if there is information from the last .loc directive that has yet to have +// a line entry made for it is made. +// +void MCLineEntry::Make(MCStreamer *MCOS, const MCSection *Section) { + if (!MCOS->getContext().getDwarfLocSeen()) + return; + + // Create a symbol at in the current section for use in the line entry. + MCSymbol *LineSym = MCOS->getContext().CreateTempSymbol(); + // Set the value of the symbol to use for the MCLineEntry. + MCOS->EmitLabel(LineSym); + + // Get the current .loc info saved in the context. + const MCDwarfLoc &DwarfLoc = MCOS->getContext().getCurrentDwarfLoc(); + + // Create a (local) line entry with the symbol and the current .loc info. + MCLineEntry LineEntry(LineSym, DwarfLoc); + + // clear DwarfLocSeen saying the current .loc info is now used. + MCOS->getContext().ClearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections.lookup(Section); + if (!LineSection) { + // Create a new MCLineSection. This will be deleted after the dwarf line + // table is created using it by iterating through the MCLineSections + // DenseMap. + LineSection = new MCLineSection; + // Save a pointer to the new LineSection into the MCLineSections DenseMap. + MCOS->getContext().addMCLineSection(Section, LineSection); + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry); +} + +// +// This helper routine returns an expression of End - Start + IntVal . +// +static inline const MCExpr *MakeStartMinusEndExpr(const MCStreamer &MCOS, + const MCSymbol &Start, + const MCSymbol &End, + int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Res = + MCSymbolRefExpr::Create(&End, Variant, MCOS.getContext()); + const MCExpr *RHS = + MCSymbolRefExpr::Create(&Start, Variant, MCOS.getContext()); + const MCExpr *Res1 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS, MCOS.getContext()); + const MCExpr *Res2 = + MCConstantExpr::Create(IntVal, MCOS.getContext()); + const MCExpr *Res3 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, MCOS.getContext()); + return Res3; +} + +// +// This emits the Dwarf line table for the specified section from the entries +// in the LineSection. +// +static inline void EmitDwarfLineTable(MCStreamer *MCOS, + const MCSection *Section, + const MCLineSection *LineSection) { + unsigned FileNum = 1; + unsigned LastLine = 1; + unsigned Column = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; + unsigned Isa = 0; + MCSymbol *LastLabel = NULL; + + // Loop through each MCLineEntry and encode the dwarf line number table. + for (MCLineSection::const_iterator + it = LineSection->getMCLineEntries()->begin(), + ie = LineSection->getMCLineEntries()->end(); it != ie; ++it) { + + if (FileNum != it->getFileNum()) { + FileNum = it->getFileNum(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_file, 1); + MCOS->EmitULEB128IntValue(FileNum); + } + if (Column != it->getColumn()) { + Column = it->getColumn(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_column, 1); + MCOS->EmitULEB128IntValue(Column); + } + if (Isa != it->getIsa()) { + Isa = it->getIsa(); + MCOS->EmitIntValue(dwarf::DW_LNS_set_isa, 1); + MCOS->EmitULEB128IntValue(Isa); + } + if ((it->getFlags() ^ Flags) & DWARF2_FLAG_IS_STMT) { + Flags = it->getFlags(); + MCOS->EmitIntValue(dwarf::DW_LNS_negate_stmt, 1); + } + if (it->getFlags() & DWARF2_FLAG_BASIC_BLOCK) + MCOS->EmitIntValue(dwarf::DW_LNS_set_basic_block, 1); + if (it->getFlags() & DWARF2_FLAG_PROLOGUE_END) + MCOS->EmitIntValue(dwarf::DW_LNS_set_prologue_end, 1); + if (it->getFlags() & DWARF2_FLAG_EPILOGUE_BEGIN) + MCOS->EmitIntValue(dwarf::DW_LNS_set_epilogue_begin, 1); + + int64_t LineDelta = static_cast<int64_t>(it->getLine()) - LastLine; + MCSymbol *Label = it->getLabel(); + + // At this point we want to emit/create the sequence to encode the delta in + // line numbers and the increment of the address from the previous Label + // and the current Label. + MCOS->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + + LastLine = it->getLine(); + LastLabel = Label; + } + + // Emit a DW_LNE_end_sequence for the end of the section. + // Using the pointer Section create a temporary label at the end of the + // section and use that and the LastLabel to compute the address delta + // and use INT64_MAX as the line delta which is the signal that this is + // actually a DW_LNE_end_sequence. + + // Switch to the section to be able to create a symbol at its end. + MCOS->SwitchSection(Section); + + MCContext &context = MCOS->getContext(); + // Create a symbol at the end of the section. + MCSymbol *SectionEnd = context.CreateTempSymbol(); + // Set the value of the symbol, as we are at the end of the section. + MCOS->EmitLabel(SectionEnd); + + // Switch back the the dwarf line section. + MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); + + MCOS->EmitDwarfAdvanceLineAddr(INT64_MAX, LastLabel, SectionEnd); +} + +// +// This emits the Dwarf file and the line tables. +// +void MCDwarfFileTable::Emit(MCStreamer *MCOS) { + MCContext &context = MCOS->getContext(); + // Switch to the section where the table will be emitted into. + MCOS->SwitchSection(context.getTargetAsmInfo().getDwarfLineSection()); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = context.CreateTempSymbol(); + // Set the value of the symbol, as we are at the start of the section. + MCOS->EmitLabel(LineStartSym); + + // Create a symbol for the end of the section (to be set when we get there). + MCSymbol *LineEndSym = context.CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *LineEndSym,4), + 4); + + // Next 2 bytes is the Version, which is Dwarf 2. + MCOS->EmitIntValue(2, 2); + + // Create a symbol for the end of the prologue (to be set when we get there). + MCSymbol *ProEndSym = context.CreateTempSymbol(); // Lprologue_end + + // Length of the prologue, is the next 4 bytes. Which is the start of the + // section to the end of the prologue. Not including the 4 bytes for the + // total length, the 2 bytes for the version, and these 4 bytes for the + // length of the prologue. + MCOS->EmitAbsValue(MakeStartMinusEndExpr(*MCOS, *LineStartSym, *ProEndSym, + (4 + 2 + 4)), + 4, 0); + + // Parameters of the state machine, are next. + MCOS->EmitIntValue(DWARF2_LINE_MIN_INSN_LENGTH, 1); + MCOS->EmitIntValue(DWARF2_LINE_DEFAULT_IS_STMT, 1); + MCOS->EmitIntValue(DWARF2_LINE_BASE, 1); + MCOS->EmitIntValue(DWARF2_LINE_RANGE, 1); + MCOS->EmitIntValue(DWARF2_LINE_OPCODE_BASE, 1); + + // Standard opcode lengths + MCOS->EmitIntValue(0, 1); // length of DW_LNS_copy + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_advance_line + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_file + MCOS->EmitIntValue(1, 1); // length of DW_LNS_set_column + MCOS->EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + MCOS->EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + MCOS->EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + MCOS->EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + MCOS->EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const std::vector<StringRef> &MCDwarfDirs = + context.getMCDwarfDirs(); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + MCOS->EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName + MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string + } + MCOS->EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + const std::vector<MCDwarfFile *> &MCDwarfFiles = + MCOS->getContext().getMCDwarfFiles(); + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + MCOS->EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName + MCOS->EmitBytes(StringRef("\0", 1), 0); // the null term. of the string + // the Directory num + MCOS->EmitULEB128IntValue(MCDwarfFiles[i]->getDirIndex()); + MCOS->EmitIntValue(0, 1); // last modification timestamp (always 0) + MCOS->EmitIntValue(0, 1); // filesize (always 0) + } + MCOS->EmitIntValue(0, 1); // Terminate the file list + + // This is the end of the prologue, so set the value of the symbol at the + // end of the prologue (that was used in a previous expression). + MCOS->EmitLabel(ProEndSym); + + // Put out the line tables. + const DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + const std::vector<const MCSection *> &MCLineSectionOrder = + MCOS->getContext().getMCLineSectionOrder(); + for (std::vector<const MCSection*>::const_iterator it = + MCLineSectionOrder.begin(), ie = MCLineSectionOrder.end(); it != ie; + ++it) { + const MCSection *Sec = *it; + const MCLineSection *Line = MCLineSections.lookup(Sec); + EmitDwarfLineTable(MCOS, Sec, Line); + + // Now delete the MCLineSections that were created in MCLineEntry::Make() + // and used to emit the line table. + delete Line; + } + + if (MCOS->getContext().getAsmInfo().getLinkerRequiresNonEmptyDwarfLines() + && MCLineSectionOrder.begin() == MCLineSectionOrder.end()) { + // The darwin9 linker has a bug (see PR8715). For for 32-bit architectures + // it requires: + // total_length >= prologue_length + 10 + // We are 4 bytes short, since we have total_length = 51 and + // prologue_length = 45 + + // The regular end_sequence should be sufficient. + MCDwarfLineAddr::Emit(MCOS, INT64_MAX, 0); + } + + // This is the end of the section, so set the value of the symbol at the end + // of this section (that was used in a previous expression). + MCOS->EmitLabel(LineEndSym); +} + +/// Utility function to write the encoding to an object writer. +void MCDwarfLineAddr::Write(MCObjectWriter *OW, int64_t LineDelta, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + OW->WriteBytes(OS.str()); +} + +/// Utility function to emit the encoding to a streamer. +void MCDwarfLineAddr::Emit(MCStreamer *MCOS, int64_t LineDelta, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + MCOS->EmitBytes(OS.str(), /*AddrSpace=*/0); +} + +/// Utility function to encode a Dwarf pair of LineDelta and AddrDeltas. +void MCDwarfLineAddr::Encode(int64_t LineDelta, uint64_t AddrDelta, + raw_ostream &OS) { + uint64_t Temp, Opcode; + bool NeedCopy = false; + + // Scale the address delta by the minimum instruction length. + AddrDelta = ScaleAddrDelta(AddrDelta); + + // A LineDelta of INT64_MAX is a signal that this is actually a + // DW_LNE_end_sequence. We cannot use special opcodes here, since we want the + // end_sequence to emit the matrix entry. + if (LineDelta == INT64_MAX) { + if (AddrDelta == MAX_SPECIAL_ADDR_DELTA) + OS << char(dwarf::DW_LNS_const_add_pc); + else { + OS << char(dwarf::DW_LNS_advance_pc); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(AddrDelta, OSE); + OS << OSE.str(); + } + OS << char(dwarf::DW_LNS_extended_op); + OS << char(1); + OS << char(dwarf::DW_LNE_end_sequence); + return; + } + + // Bias the line delta by the base. + Temp = LineDelta - DWARF2_LINE_BASE; + + // If the line increment is out of range of a special opcode, we must encode + // it with DW_LNS_advance_line. + if (Temp >= DWARF2_LINE_RANGE) { + OS << char(dwarf::DW_LNS_advance_line); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeSLEB128(LineDelta, OSE); + OS << OSE.str(); + + LineDelta = 0; + Temp = 0 - DWARF2_LINE_BASE; + NeedCopy = true; + } + + // Use DW_LNS_copy instead of a "line +0, addr +0" special opcode. + if (LineDelta == 0 && AddrDelta == 0) { + OS << char(dwarf::DW_LNS_copy); + return; + } + + // Bias the opcode by the special opcode base. + Temp += DWARF2_LINE_OPCODE_BASE; + + // Avoid overflow when addr_delta is large. + if (AddrDelta < 256 + MAX_SPECIAL_ADDR_DELTA) { + // Try using a special opcode. + Opcode = Temp + AddrDelta * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(Opcode); + return; + } + + // Try using DW_LNS_const_add_pc followed by special op. + Opcode = Temp + (AddrDelta - MAX_SPECIAL_ADDR_DELTA) * DWARF2_LINE_RANGE; + if (Opcode <= 255) { + OS << char(dwarf::DW_LNS_const_add_pc); + OS << char(Opcode); + return; + } + } + + // Otherwise use DW_LNS_advance_pc. + OS << char(dwarf::DW_LNS_advance_pc); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(AddrDelta, OSE); + OS << OSE.str(); + + if (NeedCopy) + OS << char(dwarf::DW_LNS_copy); + else + OS << char(Temp); +} + void MCDwarfFile::print(raw_ostream &OS) const { OS << '"' << getName() << '"'; } @@ -19,3 +428,387 @@ void MCDwarfFile::print(raw_ostream &OS) const { void MCDwarfFile::dump() const { print(dbgs()); } + +static int getDataAlignmentFactor(MCStreamer &streamer) { + MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + int size = asmInfo.getPointerSize(); + if (asmInfo.getStackGrowthDirection() == TargetFrameLowering::StackGrowsUp) + return size; + else + return -size; +} + +static void EmitCFIInstruction(MCStreamer &Streamer, + const MCCFIInstruction &Instr) { + int dataAlignmentFactor = getDataAlignmentFactor(Streamer); + + switch (Instr.getOperation()) { + case MCCFIInstruction::Move: { + const MachineLocation &Dst = Instr.getDestination(); + const MachineLocation &Src = Instr.getSource(); + + // If advancing cfa. + if (Dst.isReg() && Dst.getReg() == MachineLocation::VirtualFP) { + assert(!Src.isReg() && "Machine move not supported yet."); + + if (Src.getReg() == MachineLocation::VirtualFP) { + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_offset, 1); + } else { + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa, 1); + Streamer.EmitULEB128IntValue(Src.getReg()); + } + + Streamer.EmitULEB128IntValue(-Src.getOffset(), 1); + return; + } + + if (Src.isReg() && Src.getReg() == MachineLocation::VirtualFP) { + assert(Dst.isReg() && "Machine move not supported yet."); + Streamer.EmitIntValue(dwarf::DW_CFA_def_cfa_register, 1); + Streamer.EmitULEB128IntValue(Dst.getReg()); + return; + } + + unsigned Reg = Src.getReg(); + int Offset = Dst.getOffset() / dataAlignmentFactor; + + if (Offset < 0) { + Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended_sf, 1); + Streamer.EmitULEB128IntValue(Reg); + Streamer.EmitSLEB128IntValue(Offset); + } else if (Reg < 64) { + Streamer.EmitIntValue(dwarf::DW_CFA_offset + Reg, 1); + Streamer.EmitULEB128IntValue(Offset, 1); + } else { + Streamer.EmitIntValue(dwarf::DW_CFA_offset_extended, 1); + Streamer.EmitULEB128IntValue(Reg, 1); + Streamer.EmitULEB128IntValue(Offset, 1); + } + return; + } + case MCCFIInstruction::Remember: + Streamer.EmitIntValue(dwarf::DW_CFA_remember_state, 1); + return; + case MCCFIInstruction::Restore: + Streamer.EmitIntValue(dwarf::DW_CFA_restore_state, 1); + return; + } + llvm_unreachable("Unhandled case in switch"); +} + +/// EmitFrameMoves - Emit frame instructions to describe the layout of the +/// frame. +static void EmitCFIInstructions(MCStreamer &streamer, + const std::vector<MCCFIInstruction> &Instrs, + MCSymbol *BaseLabel) { + for (unsigned i = 0, N = Instrs.size(); i < N; ++i) { + const MCCFIInstruction &Instr = Instrs[i]; + MCSymbol *Label = Instr.getLabel(); + // Throw out move if the label is invalid. + if (Label && !Label->isDefined()) continue; // Not emitted, in dead code. + + // Advance row if new location. + if (BaseLabel && Label) { + MCSymbol *ThisSym = Label; + if (ThisSym != BaseLabel) { + streamer.EmitDwarfAdvanceFrameAddr(BaseLabel, ThisSym); + BaseLabel = ThisSym; + } + } + + EmitCFIInstruction(streamer, Instr); + } +} + +static void EmitSymbol(MCStreamer &streamer, const MCSymbol &symbol, + unsigned symbolEncoding) { + MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + unsigned format = symbolEncoding & 0x0f; + unsigned application = symbolEncoding & 0x70; + unsigned size; + switch (format) { + default: + assert(0 && "Unknown Encoding"); + case dwarf::DW_EH_PE_absptr: + case dwarf::DW_EH_PE_signed: + size = asmInfo.getPointerSize(); + break; + case dwarf::DW_EH_PE_udata2: + case dwarf::DW_EH_PE_sdata2: + size = 2; + break; + case dwarf::DW_EH_PE_udata4: + case dwarf::DW_EH_PE_sdata4: + size = 4; + break; + case dwarf::DW_EH_PE_udata8: + case dwarf::DW_EH_PE_sdata8: + size = 8; + break; + } + switch (application) { + default: + assert(0 && "Unknown Encoding"); + break; + case 0: + streamer.EmitSymbolValue(&symbol, size); + break; + case dwarf::DW_EH_PE_pcrel: + streamer.EmitPCRelSymbolValue(&symbol, size); + break; + } +} + +static const MachineLocation TranslateMachineLocation( + const TargetAsmInfo &AsmInfo, + const MachineLocation &Loc) { + unsigned Reg = Loc.getReg() == MachineLocation::VirtualFP ? + MachineLocation::VirtualFP : + unsigned(AsmInfo.getDwarfRegNum(Loc.getReg(), true)); + const MachineLocation &NewLoc = Loc.isReg() ? + MachineLocation(Reg) : MachineLocation(Reg, Loc.getOffset()); + return NewLoc; +} + +static const MCSymbol &EmitCIE(MCStreamer &streamer, + const MCSymbol *personality, + unsigned personalityEncoding, + const MCSymbol *lsda, + unsigned lsdaEncoding) { + MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + const MCSection §ion = *asmInfo.getEHFrameSection(); + streamer.SwitchSection(§ion); + MCSymbol *sectionStart = streamer.getContext().CreateTempSymbol(); + MCSymbol *sectionEnd = streamer.getContext().CreateTempSymbol(); + + // Length + const MCExpr *Length = MakeStartMinusEndExpr(streamer, *sectionStart, + *sectionEnd, 4); + streamer.EmitLabel(sectionStart); + streamer.EmitValue(Length, 4); + + // CIE ID + streamer.EmitIntValue(0, 4); + + // Version + streamer.EmitIntValue(dwarf::DW_CIE_VERSION, 1); + + // Augmentation String + SmallString<8> Augmentation; + Augmentation += "z"; + if (personality) + Augmentation += "P"; + if (lsda) + Augmentation += "L"; + Augmentation += "R"; + streamer.EmitBytes(Augmentation.str(), 0); + streamer.EmitIntValue(0, 1); + + // Code Alignment Factor + streamer.EmitULEB128IntValue(1); + + // Data Alignment Factor + streamer.EmitSLEB128IntValue(getDataAlignmentFactor(streamer)); + + // Return Address Register + streamer.EmitULEB128IntValue(asmInfo.getDwarfRARegNum(true)); + + // Augmentation Data Length (optional) + MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol(); + MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol(); + const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer, + *augmentationStart, + *augmentationEnd, 0); + streamer.EmitULEB128Value(augmentationLength); + + // Augmentation Data (optional) + streamer.EmitLabel(augmentationStart); + if (personality) { + // Personality Encoding + streamer.EmitIntValue(personalityEncoding, 1); + // Personality + EmitSymbol(streamer, *personality, personalityEncoding); + } + if (lsda) { + // LSDA Encoding + streamer.EmitIntValue(lsdaEncoding, 1); + } + // Encoding of the FDE pointers + streamer.EmitIntValue(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4, 1); + streamer.EmitLabel(augmentationEnd); + + // Initial Instructions + + const std::vector<MachineMove> Moves = asmInfo.getInitialFrameState(); + std::vector<MCCFIInstruction> Instructions; + + for (int i = 0, n = Moves.size(); i != n; ++i) { + MCSymbol *Label = Moves[i].getLabel(); + const MachineLocation &Dst = + TranslateMachineLocation(asmInfo, Moves[i].getDestination()); + const MachineLocation &Src = + TranslateMachineLocation(asmInfo, Moves[i].getSource()); + MCCFIInstruction Inst(Label, Dst, Src); + Instructions.push_back(Inst); + } + + EmitCFIInstructions(streamer, Instructions, NULL); + + // Padding + streamer.EmitValueToAlignment(4); + + streamer.EmitLabel(sectionEnd); + return *sectionStart; +} + +static MCSymbol *EmitFDE(MCStreamer &streamer, + const MCSymbol &cieStart, + const MCDwarfFrameInfo &frame) { + MCContext &context = streamer.getContext(); + MCSymbol *fdeStart = context.CreateTempSymbol(); + MCSymbol *fdeEnd = context.CreateTempSymbol(); + + // Length + const MCExpr *Length = MakeStartMinusEndExpr(streamer, *fdeStart, *fdeEnd, 0); + streamer.EmitValue(Length, 4); + + streamer.EmitLabel(fdeStart); + // CIE Pointer + const MCExpr *offset = MakeStartMinusEndExpr(streamer, cieStart, *fdeStart, + 0); + streamer.EmitValue(offset, 4); + + // PC Begin + streamer.EmitPCRelSymbolValue(frame.Begin, 4); + + // PC Range + const MCExpr *Range = MakeStartMinusEndExpr(streamer, *frame.Begin, + *frame.End, 0); + streamer.EmitValue(Range, 4); + + // Augmentation Data Length + MCSymbol *augmentationStart = streamer.getContext().CreateTempSymbol(); + MCSymbol *augmentationEnd = streamer.getContext().CreateTempSymbol(); + const MCExpr *augmentationLength = MakeStartMinusEndExpr(streamer, + *augmentationStart, + *augmentationEnd, 0); + streamer.EmitULEB128Value(augmentationLength); + + // Augmentation Data + streamer.EmitLabel(augmentationStart); + if (frame.Lsda) + EmitSymbol(streamer, *frame.Lsda, frame.LsdaEncoding); + streamer.EmitLabel(augmentationEnd); + // Call Frame Instructions + + EmitCFIInstructions(streamer, frame.Instructions, frame.Begin); + + // Padding + streamer.EmitValueToAlignment(4); + + return fdeEnd; +} + +namespace { + struct CIEKey { + static const CIEKey getEmptyKey() { return CIEKey(0, 0, -1); } + static const CIEKey getTombstoneKey() { return CIEKey(0, -1, 0); } + + CIEKey(const MCSymbol* Personality_, unsigned PersonalityEncoding_, + unsigned LsdaEncoding_) : Personality(Personality_), + PersonalityEncoding(PersonalityEncoding_), + LsdaEncoding(LsdaEncoding_) { + } + const MCSymbol* Personality; + unsigned PersonalityEncoding; + unsigned LsdaEncoding; + }; +} + +namespace llvm { + template <> + struct DenseMapInfo<CIEKey> { + static CIEKey getEmptyKey() { + return CIEKey::getEmptyKey(); + } + static CIEKey getTombstoneKey() { + return CIEKey::getTombstoneKey(); + } + static unsigned getHashValue(const CIEKey &Key) { + FoldingSetNodeID ID; + ID.AddPointer(Key.Personality); + ID.AddInteger(Key.PersonalityEncoding); + ID.AddInteger(Key.LsdaEncoding); + return ID.ComputeHash(); + } + static bool isEqual(const CIEKey &LHS, + const CIEKey &RHS) { + return LHS.Personality == RHS.Personality && + LHS.PersonalityEncoding == RHS.PersonalityEncoding && + LHS.LsdaEncoding == RHS.LsdaEncoding; + } + }; +} + +void MCDwarfFrameEmitter::Emit(MCStreamer &streamer) { + const MCContext &context = streamer.getContext(); + const TargetAsmInfo &asmInfo = context.getTargetAsmInfo(); + MCSymbol *fdeEnd = NULL; + DenseMap<CIEKey, const MCSymbol*> CIEStarts; + + for (unsigned i = 0, n = streamer.getNumFrameInfos(); i < n; ++i) { + const MCDwarfFrameInfo &frame = streamer.getFrameInfo(i); + CIEKey key(frame.Personality, frame.PersonalityEncoding, + frame.LsdaEncoding); + const MCSymbol *&cieStart = CIEStarts[key]; + if (!cieStart) + cieStart = &EmitCIE(streamer, frame.Personality, + frame.PersonalityEncoding, frame.Lsda, + frame.LsdaEncoding); + fdeEnd = EmitFDE(streamer, *cieStart, frame); + if (i != n - 1) + streamer.EmitLabel(fdeEnd); + } + + streamer.EmitValueToAlignment(asmInfo.getPointerSize()); + if (fdeEnd) + streamer.EmitLabel(fdeEnd); +} + +void MCDwarfFrameEmitter::EmitAdvanceLoc(MCStreamer &Streamer, + uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfFrameEmitter::EncodeAdvanceLoc(AddrDelta, OS); + Streamer.EmitBytes(OS.str(), /*AddrSpace=*/0); +} + +void MCDwarfFrameEmitter::EncodeAdvanceLoc(uint64_t AddrDelta, + raw_ostream &OS) { + // FIXME: Assumes the code alignment factor is 1. + if (AddrDelta == 0) { + } else if (isUIntN(6, AddrDelta)) { + uint8_t Opcode = dwarf::DW_CFA_advance_loc | AddrDelta; + OS << Opcode; + } else if (isUInt<8>(AddrDelta)) { + OS << uint8_t(dwarf::DW_CFA_advance_loc1); + OS << uint8_t(AddrDelta); + } else if (isUInt<16>(AddrDelta)) { + // FIXME: check what is the correct behavior on a big endian machine. + OS << uint8_t(dwarf::DW_CFA_advance_loc2); + OS << uint8_t( AddrDelta & 0xff); + OS << uint8_t((AddrDelta >> 8) & 0xff); + } else { + // FIXME: check what is the correct behavior on a big endian machine. + assert(isUInt<32>(AddrDelta)); + OS << uint8_t(dwarf::DW_CFA_advance_loc4); + OS << uint8_t( AddrDelta & 0xff); + OS << uint8_t((AddrDelta >> 8) & 0xff); + OS << uint8_t((AddrDelta >> 16) & 0xff); + OS << uint8_t((AddrDelta >> 24) & 0xff); + + } +} diff --git a/lib/MC/MCELFObjectTargetWriter.cpp b/lib/MC/MCELFObjectTargetWriter.cpp new file mode 100644 index 0000000..12a02a9 --- /dev/null +++ b/lib/MC/MCELFObjectTargetWriter.cpp @@ -0,0 +1,23 @@ +//===-- MCELFObjectTargetWriter.cpp - ELF Target Writer Subclass ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCELFObjectWriter.h" + +using namespace llvm; + +MCELFObjectTargetWriter::MCELFObjectTargetWriter(bool Is64Bit_, + Triple::OSType OSType_, + uint16_t EMachine_, + bool HasRelocationAddend_) + : OSType(OSType_), EMachine(EMachine_), + HasRelocationAddend(HasRelocationAddend_), Is64Bit(Is64Bit_) { +} + +MCELFObjectTargetWriter::~MCELFObjectTargetWriter() { +} diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index 570c391..e49074d 100644 --- a/lib/MC/MCELFStreamer.cpp +++ b/lib/MC/MCELFStreamer.cpp @@ -13,6 +13,7 @@ #include "llvm/MC/MCStreamer.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCCodeEmitter.h" @@ -23,19 +24,51 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ELF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; namespace { +static void SetBinding(MCSymbolData &SD, unsigned Binding) { + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STB_Shift); + SD.setFlags(OtherFlags | (Binding << ELF_STB_Shift)); +} + +static unsigned GetBinding(const MCSymbolData &SD) { + uint32_t Binding = (SD.getFlags() & (0xf << ELF_STB_Shift)) >> ELF_STB_Shift; + assert(Binding == ELF::STB_LOCAL || Binding == ELF::STB_GLOBAL || + Binding == ELF::STB_WEAK); + return Binding; +} + +static void SetType(MCSymbolData &SD, unsigned Type) { + assert(Type == ELF::STT_NOTYPE || Type == ELF::STT_OBJECT || + Type == ELF::STT_FUNC || Type == ELF::STT_SECTION || + Type == ELF::STT_FILE || Type == ELF::STT_COMMON || + Type == ELF::STT_TLS); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STT_Shift); + SD.setFlags(OtherFlags | (Type << ELF_STT_Shift)); +} + +static void SetVisibility(MCSymbolData &SD, unsigned Visibility) { + assert(Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_INTERNAL || + Visibility == ELF::STV_HIDDEN || Visibility == ELF::STV_PROTECTED); + + uint32_t OtherFlags = SD.getFlags() & ~(0xf << ELF_STV_Shift); + SD.setFlags(OtherFlags | (Visibility << ELF_STV_Shift)); +} + 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) @@ -46,9 +79,13 @@ public: /// @name MCStreamer Interface /// @{ + virtual void InitSections(); + virtual void ChangeSection(const MCSection *Section); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { assert(0 && "ELF doesn't support this directive"); @@ -76,9 +113,8 @@ public: SD.setSize(Value); } - virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { - assert(0 && "ELF doesn't support this directive"); - } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, unsigned Size = 0, unsigned ByteAlignment = 0) { assert(0 && "ELF doesn't support this directive"); @@ -88,49 +124,84 @@ public: 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(); +private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + + void fixSymbolsInTLSFixups(const MCExpr *expr); + + struct LocalCommon { + MCSymbolData *SD; + uint64_t Size; + unsigned ByteAlignment; + }; + std::vector<LocalCommon> LocalCommons; + + SmallPtrSet<MCSymbol *, 16> BindingExplicitlySet; /// @} + void SetSection(StringRef Section, unsigned Type, unsigned Flags, + SectionKind Kind) { + SwitchSection(getContext().getELFSection(Section, Type, Flags, Kind)); + } + + void SetSectionData() { + SetSection(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + void SetSectionText() { + SetSection(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + void SetSectionBss() { + SetSection(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); + EmitCodeAlignment(4, 0); + } }; } // end anonymous namespace. +void MCELFStreamer::InitSections() { + // This emulates the same behavior of GNU as. This makes it easier + // to compare the output as the major sections are in the same order. + SetSectionText(); + SetSectionData(); + SetSectionBss(); + SetSectionText(); +} + void MCELFStreamer::EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - // 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()); + MCObjectStreamer::EmitLabel(Symbol); - Symbol->setSection(*CurSection); + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(Symbol->getSection()); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); + if (Section.getFlags() & ELF::SHF_TLS) + SetType(SD, ELF::STT_TLS); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // no-op here. + case MCAF_Code32: return; // no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; @@ -139,6 +210,10 @@ void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { assert(0 && "invalid assembler flag!"); } +void MCELFStreamer::EmitThumbFunc(MCSymbol *Func) { + // FIXME: Anything needed here to flag the function as thumb? +} + void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into // MCObjectStreamer. @@ -147,6 +222,21 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(AddValueSymbols(Value)); } +void MCELFStreamer::ChangeSection(const MCSection *Section) { + const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::ChangeSection(Section); +} + +void MCELFStreamer::EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + getAssembler().getOrCreateSymbolData(*Symbol); + MCSymbolData &AliasSD = getAssembler().getOrCreateSymbolData(*Alias); + AliasSD.setFlags(AliasSD.getFlags() | ELF_Other_Weakref); + const MCExpr *Value = MCSymbolRefExpr::Create(Symbol, getContext()); + Alias->setVariableValue(Value); +} + void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { // Indirect symbols are handled differently, to match how 'as' handles @@ -176,6 +266,7 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_LazyReference: case MCSA_Reference: case MCSA_NoDeadStrip: + case MCSA_SymbolResolver: case MCSA_PrivateExtern: case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: @@ -185,50 +276,59 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, assert(0 && "Invalid symbol attribute for ELF!"); break; + case MCSA_ELF_TypeGnuUniqueObject: + // Ignore for now. + break; + case MCSA_Global: - SD.setFlags(SD.getFlags() | ELF_STB_Global); + SetBinding(SD, ELF::STB_GLOBAL); SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); break; case MCSA_WeakReference: case MCSA_Weak: - SD.setFlags(SD.getFlags() | ELF_STB_Weak); + SetBinding(SD, ELF::STB_WEAK); + SD.setExternal(true); + BindingExplicitlySet.insert(Symbol); break; case MCSA_Local: - SD.setFlags(SD.getFlags() | ELF_STB_Local); + SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); break; case MCSA_ELF_TypeFunction: - SD.setFlags(SD.getFlags() | ELF_STT_Func); + SetType(SD, ELF::STT_FUNC); break; case MCSA_ELF_TypeObject: - SD.setFlags(SD.getFlags() | ELF_STT_Object); + SetType(SD, ELF::STT_OBJECT); break; case MCSA_ELF_TypeTLS: - SD.setFlags(SD.getFlags() | ELF_STT_Tls); + SetType(SD, ELF::STT_TLS); break; case MCSA_ELF_TypeCommon: - SD.setFlags(SD.getFlags() | ELF_STT_Common); + SetType(SD, ELF::STT_COMMON); break; case MCSA_ELF_TypeNoType: - SD.setFlags(SD.getFlags() | ELF_STT_Notype); + SetType(SD, ELF::STT_NOTYPE); break; case MCSA_Protected: - SD.setFlags(SD.getFlags() | ELF_STV_Protected); + SetVisibility(SD, ELF::STV_PROTECTED); break; case MCSA_Hidden: - SD.setFlags(SD.getFlags() | ELF_STV_Hidden); + SetVisibility(SD, ELF::STV_HIDDEN); break; case MCSA_Internal: - SD.setFlags(SD.getFlags() | ELF_STV_Internal); + SetVisibility(SD, ELF::STV_INTERNAL); break; } } @@ -237,24 +337,38 @@ 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) { + if (!BindingExplicitlySet.count(Symbol)) { + SetBinding(SD, ELF::STB_GLOBAL); + SD.setExternal(true); + } + + SetType(SD, ELF::STT_OBJECT); + + if (GetBinding(SD) == ELF_STB_Local) { const MCSection *Section = getAssembler().getContext().getELFSection(".bss", - MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, + ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::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())); + + struct LocalCommon L = {&SD, Size, ByteAlignment}; + LocalCommons.push_back(L); + } else { + SD.setCommon(Size, ByteAlignment); } - SD.setFlags(SD.getFlags() | ELF_STB_Global); - SD.setExternal(true); + SD.setSize(MCConstantExpr::Create(Size, getContext())); +} - SD.setCommon(Size, ByteAlignment); +void MCELFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + // FIXME: Should this be caught and done earlier? + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SetBinding(SD, ELF::STB_LOCAL); + SD.setExternal(false); + BindingExplicitlySet.insert(Symbol); + // FIXME: ByteAlignment is not needed here, but is required. + EmitCommonSymbol(Symbol, Size, 1); } void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { @@ -263,25 +377,6 @@ void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { 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) { @@ -312,18 +407,11 @@ void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment, 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->setSection(*getCurrentSection()); Symbol->setAbsolute(); MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); @@ -331,21 +419,52 @@ void MCELFStreamer::EmitFileDirective(StringRef Filename) { SD.setFlags(ELF_STT_File | ELF_STB_Local | ELF_STV_Default); } -void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { - MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); +void MCELFStreamer::fixSymbolsInTLSFixups(const MCExpr *expr) { + switch (expr->getKind()) { + case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Constant: + break; - // 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(); + case MCExpr::Binary: { + const MCBinaryExpr *be = cast<MCBinaryExpr>(expr); + fixSymbolsInTLSFixups(be->getLHS()); + fixSymbolsInTLSFixups(be->getRHS()); + break; + } + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr &symRef = *cast<MCSymbolRefExpr>(expr); + switch (symRef.getKind()) { + default: + return; + case MCSymbolRefExpr::VK_NTPOFF: + case MCSymbolRefExpr::VK_GOTNTPOFF: + case MCSymbolRefExpr::VK_TLSGD: + case MCSymbolRefExpr::VK_TLSLDM: + case MCSymbolRefExpr::VK_TPOFF: + case MCSymbolRefExpr::VK_DTPOFF: + case MCSymbolRefExpr::VK_GOTTPOFF: + case MCSymbolRefExpr::VK_TLSLD: + case MCSymbolRefExpr::VK_ARM_TLSGD: + break; + } + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(symRef.getSymbol()); + SetType(SD, ELF::STT_TLS); + break; + } + + case MCExpr::Unary: + fixSymbolsInTLSFixups(cast<MCUnaryExpr>(expr)->getSubExpr()); + break; + } +} + +void MCELFStreamer::EmitInstToFragment(const MCInst &Inst) { + this->MCObjectStreamer::EmitInstToFragment(Inst); + MCInstFragment &F = *cast<MCInstFragment>(getCurrentFragment()); - IF->getCode() = Code; - IF->getFixups() = Fixups; + for (unsigned i = 0, e = F.getFixups().size(); i != e; ++i) + fixSymbolsInTLSFixups(F.getFixups()[i].getValue()); } void MCELFStreamer::EmitInstToData(const MCInst &Inst) { @@ -357,6 +476,9 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) + fixSymbolsInTLSFixups(Fixups[i].getValue()); + // Add the fixups and data. for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); @@ -365,44 +487,40 @@ void MCELFStreamer::EmitInstToData(const MCInst &Inst) { 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()); +void MCELFStreamer::Finish() { + if (getNumFrameInfos()) + MCDwarfFrameEmitter::Emit(*this); - getCurrentSectionData()->setHasInstructions(true); + for (std::vector<LocalCommon>::const_iterator i = LocalCommons.begin(), + e = LocalCommons.end(); + i != e; ++i) { + MCSymbolData *SD = i->SD; + uint64_t Size = i->Size; + unsigned ByteAlignment = i->ByteAlignment; + const MCSymbol &Symbol = SD->getSymbol(); + const MCSection &Section = Symbol.getSection(); - // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { - EmitInstToData(Inst); - return; - } + MCSectionData &SectData = getAssembler().getOrCreateSectionData(Section); + new MCAlignFragment(ByteAlignment, 0, 1, ByteAlignment, &SectData); - // 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; - } + MCFragment *F = new MCFillFragment(0, 0, Size, &SectData); + SD->setFragment(F); - // Otherwise emit to a separate fragment. - EmitInstToFragment(Inst); -} + // Update the maximum alignment of the section if necessary. + if (ByteAlignment > SectData.getAlignment()) + SectData.setAlignment(ByteAlignment); + } -void MCELFStreamer::Finish() { - getAssembler().Finish(); + this->MCObjectStreamer::Finish(); } MCStreamer *llvm::createELFStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &OS, MCCodeEmitter *CE, - bool RelaxAll) { + raw_ostream &OS, MCCodeEmitter *CE, + bool RelaxAll, bool NoExecStack) { MCELFStreamer *S = new MCELFStreamer(Context, TAB, OS, CE); if (RelaxAll) S->getAssembler().setRelaxAll(true); + if (NoExecStack) + S->getAssembler().setNoExecStack(true); return S; } diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 343f334..54d3743 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -38,21 +38,31 @@ void MCExpr::print(raw_ostream &OS) const { case MCExpr::SymbolRef: { const MCSymbolRefExpr &SRE = cast<MCSymbolRefExpr>(*this); const MCSymbol &Sym = SRE.getSymbol(); + // Parenthesize names that start with $ so that they don't look like + // absolute names. + bool UseParens = Sym.getName()[0] == '$'; - if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_HI16 || - SRE.getKind() == MCSymbolRefExpr::VK_ARM_LO16) + if (SRE.getKind() == MCSymbolRefExpr::VK_PPC_HA16 || + SRE.getKind() == MCSymbolRefExpr::VK_PPC_LO16) { OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + UseParens = true; + } - // Parenthesize names that start with $ so that they don't look like - // absolute names. - if (Sym.getName()[0] == '$') + if (UseParens) OS << '(' << Sym << ')'; else OS << Sym; - if (SRE.getKind() != MCSymbolRefExpr::VK_None && - SRE.getKind() != MCSymbolRefExpr::VK_ARM_HI16 && - SRE.getKind() != MCSymbolRefExpr::VK_ARM_LO16) + if (SRE.getKind() == MCSymbolRefExpr::VK_ARM_PLT || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TLSGD || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOT || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_TPOFF || + SRE.getKind() == MCSymbolRefExpr::VK_ARM_GOTTPOFF) + OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + else if (SRE.getKind() != MCSymbolRefExpr::VK_None && + SRE.getKind() != MCSymbolRefExpr::VK_PPC_HA16 && + SRE.getKind() != MCSymbolRefExpr::VK_PPC_LO16) OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); return; @@ -172,12 +182,23 @@ StringRef MCSymbolRefExpr::getVariantKindName(VariantKind Kind) { case VK_GOTTPOFF: return "GOTTPOFF"; case VK_INDNTPOFF: return "INDNTPOFF"; case VK_NTPOFF: return "NTPOFF"; + case VK_GOTNTPOFF: return "GOTNTPOFF"; case VK_PLT: return "PLT"; case VK_TLSGD: return "TLSGD"; + case VK_TLSLD: return "TLSLD"; + case VK_TLSLDM: return "TLSLDM"; case VK_TPOFF: return "TPOFF"; - case VK_ARM_HI16: return ":upper16:"; - case VK_ARM_LO16: return ":lower16:"; + case VK_DTPOFF: return "DTPOFF"; case VK_TLVP: return "TLVP"; + case VK_ARM_PLT: return "(PLT)"; + case VK_ARM_GOT: return "(GOT)"; + case VK_ARM_GOTOFF: return "(GOTOFF)"; + case VK_ARM_TPOFF: return "(tpoff)"; + case VK_ARM_GOTTPOFF: return "(gottpoff)"; + case VK_ARM_TLSGD: return "(tlsgd)"; + case VK_PPC_TOC: return "toc"; + case VK_PPC_HA16: return "ha16"; + case VK_PPC_LO16: return "lo16"; } } @@ -185,15 +206,33 @@ MCSymbolRefExpr::VariantKind MCSymbolRefExpr::getVariantKindForName(StringRef Name) { return StringSwitch<VariantKind>(Name) .Case("GOT", VK_GOT) + .Case("got", VK_GOT) .Case("GOTOFF", VK_GOTOFF) + .Case("gotoff", VK_GOTOFF) .Case("GOTPCREL", VK_GOTPCREL) + .Case("gotpcrel", VK_GOTPCREL) .Case("GOTTPOFF", VK_GOTTPOFF) + .Case("gottpoff", VK_GOTTPOFF) .Case("INDNTPOFF", VK_INDNTPOFF) + .Case("indntpoff", VK_INDNTPOFF) .Case("NTPOFF", VK_NTPOFF) + .Case("ntpoff", VK_NTPOFF) + .Case("GOTNTPOFF", VK_GOTNTPOFF) + .Case("gotntpoff", VK_GOTNTPOFF) .Case("PLT", VK_PLT) + .Case("plt", VK_PLT) .Case("TLSGD", VK_TLSGD) + .Case("tlsgd", VK_TLSGD) + .Case("TLSLD", VK_TLSLD) + .Case("tlsld", VK_TLSLD) + .Case("TLSLDM", VK_TLSLDM) + .Case("tlsldm", VK_TLSLDM) .Case("TPOFF", VK_TPOFF) + .Case("tpoff", VK_TPOFF) + .Case("DTPOFF", VK_DTPOFF) + .Case("dtpoff", VK_DTPOFF) .Case("TLVP", VK_TLVP) + .Case("tlvp", VK_TLVP) .Default(VK_Invalid); } @@ -203,7 +242,28 @@ void MCTargetExpr::Anchor() {} /* *** */ -bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { +bool MCExpr::EvaluateAsAbsolute(int64_t &Res) const { + return EvaluateAsAbsolute(Res, 0, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout) const { + return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, + const MCAsmLayout &Layout, + const SectionAddrMap &Addrs) const { + return EvaluateAsAbsolute(Res, &Layout.getAssembler(), &Layout, &Addrs); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler &Asm) const { + return EvaluateAsAbsolute(Res, &Asm, 0, 0); +} + +bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs) const { MCValue Value; // Fast path constants. @@ -212,37 +272,159 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { return true; } - if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) - return false; + // FIXME: The use if InSet = Addrs is a hack. Setting InSet causes us + // absolutize differences across sections and that is what the MachO writer + // uses Addrs for. + bool IsRelocatable = + EvaluateAsRelocatableImpl(Value, Asm, Layout, Addrs, /*InSet*/ Addrs); + // Record the current value. Res = Value.getConstant(); - return true; + + return IsRelocatable && Value.isAbsolute(); +} + +/// \brief Helper method for \see EvaluateSymbolAdd(). +static void AttemptToFoldSymbolOffsetDifference(const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet, + const MCSymbolRefExpr *&A, + const MCSymbolRefExpr *&B, + int64_t &Addend) { + if (!A || !B) + return; + + const MCSymbol &SA = A->getSymbol(); + const MCSymbol &SB = B->getSymbol(); + + if (SA.isUndefined() || SB.isUndefined()) + return; + + if (!Asm->getWriter().IsSymbolRefDifferenceFullyResolved(*Asm, A, B, InSet)) + return; + + MCSymbolData &AD = Asm->getSymbolData(SA); + MCSymbolData &BD = Asm->getSymbolData(SB); + + if (AD.getFragment() == BD.getFragment()) { + Addend += (AD.getOffset() - BD.getOffset()); + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = 0; + return; + } + + if (!Layout) + return; + + const MCSectionData &SecA = *AD.getFragment()->getParent(); + const MCSectionData &SecB = *BD.getFragment()->getParent(); + + if ((&SecA != &SecB) && !Addrs) + return; + + // Eagerly evaluate. + Addend += (Layout->getSymbolOffset(&Asm->getSymbolData(A->getSymbol())) - + Layout->getSymbolOffset(&Asm->getSymbolData(B->getSymbol()))); + if (Addrs && (&SecA != &SecB)) + Addend += (Addrs->lookup(&SecA) - Addrs->lookup(&SecB)); + + // Clear the symbol expr pointers to indicate we have folded these + // operands. + A = B = 0; } -static bool EvaluateSymbolicAdd(const MCValue &LHS,const MCSymbolRefExpr *RHS_A, +/// \brief Evaluate the result of an add between (conceptually) two MCValues. +/// +/// This routine conceptually attempts to construct an MCValue: +/// Result = (Result_A - Result_B + Result_Cst) +/// from two MCValue's LHS and RHS where +/// Result = LHS + RHS +/// and +/// Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). +/// +/// This routine attempts to aggresively fold the operands such that the result +/// is representable in an MCValue, but may not always succeed. +/// +/// \returns True on success, false if the result is not representable in an +/// MCValue. + +/// NOTE: It is really important to have both the Asm and Layout arguments. +/// They might look redundant, but this function can be used before layout +/// is done (see the object streamer for example) and having the Asm argument +/// lets us avoid relaxations early. +static bool EvaluateSymbolicAdd(const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet, + const MCValue &LHS,const MCSymbolRefExpr *RHS_A, const MCSymbolRefExpr *RHS_B, int64_t RHS_Cst, MCValue &Res) { - // We can't add or subtract two symbols. - if ((LHS.getSymA() && RHS_A) || - (LHS.getSymB() && RHS_B)) + // FIXME: This routine (and other evaluation parts) are *incredibly* sloppy + // about dealing with modifiers. This will ultimately bite us, one day. + const MCSymbolRefExpr *LHS_A = LHS.getSymA(); + const MCSymbolRefExpr *LHS_B = LHS.getSymB(); + int64_t LHS_Cst = LHS.getConstant(); + + // Fold the result constant immediately. + int64_t Result_Cst = LHS_Cst + RHS_Cst; + + assert((!Layout || Asm) && + "Must have an assembler object if layout is given!"); + + // If we have a layout, we can fold resolved differences. + if (Asm) { + // First, fold out any differences which are fully resolved. By + // reassociating terms in + // Result = (LHS_A - LHS_B + LHS_Cst) + (RHS_A - RHS_B + RHS_Cst). + // we have the four possible differences: + // (LHS_A - LHS_B), + // (LHS_A - RHS_B), + // (RHS_A - LHS_B), + // (RHS_A - RHS_B). + // Since we are attempting to be as aggresive as possible about folding, we + // attempt to evaluate each possible alternative. + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, LHS_B, + Result_Cst); + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, LHS_A, RHS_B, + Result_Cst); + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, LHS_B, + Result_Cst); + AttemptToFoldSymbolOffsetDifference(Asm, Layout, Addrs, InSet, RHS_A, RHS_B, + Result_Cst); + } + + // We can't represent the addition or subtraction of two symbols. + if ((LHS_A && RHS_A) || (LHS_B && RHS_B)) return false; - const MCSymbolRefExpr *A = LHS.getSymA() ? LHS.getSymA() : RHS_A; - const MCSymbolRefExpr *B = LHS.getSymB() ? LHS.getSymB() : RHS_B; - if (B) { - // If we have a negated symbol, then we must have also have a non-negated - // symbol in order to encode the expression. We can do this check later to - // permit expressions which eventually fold to a representable form -- such - // as (a + (0 - b)) -- if necessary. - if (!A) - return false; - } - Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst); + // At this point, we have at most one additive symbol and one subtractive + // symbol -- find them. + const MCSymbolRefExpr *A = LHS_A ? LHS_A : RHS_A; + const MCSymbolRefExpr *B = LHS_B ? LHS_B : RHS_B; + + // If we have a negated symbol, then we must have also have a non-negated + // symbol in order to encode the expression. + if (B && !A) + return false; + + Res = MCValue::get(A, B, Result_Cst); return true; } bool MCExpr::EvaluateAsRelocatable(MCValue &Res, - const MCAsmLayout *Layout) const { + const MCAsmLayout &Layout) const { + return EvaluateAsRelocatableImpl(Res, &Layout.getAssembler(), &Layout, + 0, false); +} + +bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAssembler *Asm, + const MCAsmLayout *Layout, + const SectionAddrMap *Addrs, + bool InSet) const { ++stats::MCExprEvaluate; switch (getKind()) { @@ -258,26 +440,15 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCSymbol &Sym = SRE->getSymbol(); // Evaluate recursively if this is a variable. - if (Sym.isVariable()) { - if (!Sym.getVariableValue()->EvaluateAsRelocatable(Res, Layout)) - return false; - - // Absolutize symbol differences between defined symbols when we have a - // layout object and the target requests it. - if (Layout && Res.getSymB() && - Layout->getAssembler().getBackend().hasAbsolutizedSet() && - Res.getSymA()->getSymbol().isDefined() && - Res.getSymB()->getSymbol().isDefined()) { - MCSymbolData &A = - Layout->getAssembler().getSymbolData(Res.getSymA()->getSymbol()); - MCSymbolData &B = - Layout->getAssembler().getSymbolData(Res.getSymB()->getSymbol()); - Res = MCValue::get(+ Layout->getSymbolAddress(&A) - - Layout->getSymbolAddress(&B) - + Res.getConstant()); - } - - return true; + if (Sym.isVariable() && SRE->getKind() == MCSymbolRefExpr::VK_None) { + bool Ret = Sym.getVariableValue()->EvaluateAsRelocatableImpl(Res, Asm, + Layout, + Addrs, + true); + // If we failed to simplify this to a constant, let the target + // handle it. + if (Ret && !Res.getSymA() && !Res.getSymB()) + return true; } Res = MCValue::get(SRE, 0, 0); @@ -288,7 +459,8 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this); MCValue Value; - if (!AUE->getSubExpr()->EvaluateAsRelocatable(Value, Layout)) + if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Asm, Layout, + Addrs, InSet)) return false; switch (AUE->getOpcode()) { @@ -321,8 +493,10 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this); MCValue LHSValue, RHSValue; - if (!ABE->getLHS()->EvaluateAsRelocatable(LHSValue, Layout) || - !ABE->getRHS()->EvaluateAsRelocatable(RHSValue, Layout)) + if (!ABE->getLHS()->EvaluateAsRelocatableImpl(LHSValue, Asm, Layout, + Addrs, InSet) || + !ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Asm, Layout, + Addrs, InSet)) return false; // We only support a few operations on non-constant expressions, handle @@ -333,13 +507,13 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, return false; case MCBinaryExpr::Sub: // Negate RHS and add. - return EvaluateSymbolicAdd(LHSValue, + return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymB(), RHSValue.getSymA(), -RHSValue.getConstant(), Res); case MCBinaryExpr::Add: - return EvaluateSymbolicAdd(LHSValue, + return EvaluateSymbolicAdd(Asm, Layout, Addrs, InSet, LHSValue, RHSValue.getSymA(), RHSValue.getSymB(), RHSValue.getConstant(), Res); diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp index b96040a..012c7f6 100644 --- a/lib/MC/MCLoggingStreamer.cpp +++ b/lib/MC/MCLoggingStreamer.cpp @@ -48,10 +48,14 @@ public: return Child->AddBlankLine(); } - virtual void SwitchSection(const MCSection *Section) { - CurSection = Section; - LogCall("SwitchSection"); - return Child->SwitchSection(Section); + virtual void ChangeSection(const MCSection *Section) { + LogCall("ChangeSection"); + return Child->ChangeSection(Section); + } + + virtual void InitSections() { + LogCall("InitSections"); + return Child->InitSections(); } virtual void EmitLabel(MCSymbol *Symbol) { @@ -64,11 +68,28 @@ public: return Child->EmitAssemblerFlag(Flag); } + virtual void EmitThumbFunc(MCSymbol *Func) { + LogCall("EmitThumbFunc"); + return Child->EmitThumbFunc(Func); + } + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { LogCall("EmitAssignment"); return Child->EmitAssignment(Symbol, Value); } + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) { + LogCall("EmitWeakReference"); + return Child->EmitWeakReference(Alias, Symbol); + } + + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + LogCall("EmitDwarfAdvanceLineAddr"); + return Child->EmitDwarfAdvanceLineAddr(LineDelta, LastLabel, Label); + } + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { LogCall("EmitSymbolAttribute"); return Child->EmitSymbolAttribute(Symbol, Attribute); @@ -132,14 +153,22 @@ public: return Child->EmitBytes(Data, AddrSpace); } - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace){ + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace){ LogCall("EmitValue"); - return Child->EmitValue(Value, Size, AddrSpace); + return Child->EmitValueImpl(Value, Size, isPCRel, AddrSpace); + } + + virtual void EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) { + LogCall("EmitULEB128Value"); + return Child->EmitULEB128Value(Value, AddrSpace); } - virtual void EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) { - LogCall("EmitIntValue"); - return Child->EmitIntValue(Value, Size, AddrSpace); + virtual void EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) { + LogCall("EmitSLEB128Value"); + return Child->EmitSLEB128Value(Value, AddrSpace); } virtual void EmitGPRel32Value(const MCExpr *Value) { @@ -178,12 +207,23 @@ public: return Child->EmitFileDirective(Filename); } - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { LogCall("EmitDwarfFileDirective", "FileNo:" + Twine(FileNo) + " Filename:" + Filename); return Child->EmitDwarfFileDirective(FileNo, Filename); } + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator) { + LogCall("EmitDwarfLocDirective", + "FileNo:" + Twine(FileNo) + " Line:" + Twine(Line) + + " Column:" + Twine(Column) + " Flags:" + Twine(Flags) + + " Isa:" + Twine(Isa) + " Discriminator:" + Twine(Discriminator)); + return Child->EmitDwarfLocDirective(FileNo, Line, Column, Flags, + Isa, Discriminator); + } + virtual void EmitInstruction(const MCInst &Inst) { LogCall("EmitInstruction"); return Child->EmitInstruction(Inst); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 671874d..d1f9f5c 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -20,9 +20,11 @@ #include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; @@ -30,13 +32,7 @@ namespace { class MCMachOStreamer : public MCObjectStreamer { private: - 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); + virtual void EmitInstToData(const MCInst &Inst); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -46,8 +42,10 @@ public: /// @name MCStreamer Interface /// @{ + virtual void InitSections(); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); @@ -76,17 +74,11 @@ public: virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0); 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 && "macho 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) { // FIXME: Just ignore the .file; it isn't important enough to fail the @@ -94,14 +86,6 @@ public: //report_fatal_error("unsupported directive: '.file'"); } - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - // FIXME: Just ignore the .file; it isn't important enough to fail the - // entire assembly. - - //report_fatal_error("unsupported directive: '.file'"); - } - - virtual void EmitInstruction(const MCInst &Inst); virtual void Finish(); @@ -110,31 +94,26 @@ 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!"); +void MCMachOStreamer::InitSections() { + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); - Symbol->setSection(*CurSection); +} - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); +void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + // isSymbolLinkerVisible uses the section. + Symbol->setSection(*getCurrentSection()); // We have to create a new fragment if this is an atom defining symbol, // fragments cannot span atoms. - if (getAssembler().isSymbolLinkerVisible(SD.getSymbol())) + if (getAssembler().isSymbolLinkerVisible(*Symbol)) new MCDataFragment(getCurrentSectionData()); - // FIXME: This is wasteful, we don't necessarily need to create a data - // fragment. Instead, we should mark the symbol as pointing into the data - // fragment if it exists, otherwise we should just queue the label and set its - // fragment pointer when we emit the next fragment. - MCDataFragment *F = getOrCreateDataFragment(); - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); + MCObjectStreamer::EmitLabel(Symbol); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); // This causes the reference type flag to be cleared. Darwin 'as' was "trying" // to clear the weak reference and weak definition bits too, but the // implementation was buggy. For now we just try to match 'as', for @@ -146,13 +125,31 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { } void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().HandleAssemblerFlag(Flag); + // Do any generic stuff we need to do. switch (Flag) { + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // no-op here. + case MCAF_Code32: return; // no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; + default: + llvm_unreachable("invalid assembler flag!"); } +} + +void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { + // FIXME: Flag the function ISA as thumb with DW_AT_APPLE_isa. - assert(0 && "invalid assembler flag!"); + // Remember that the function is a thumb function. Fixup and relocation + // values will need adjusted. + getAssembler().setIsThumbFunc(Symbol); + + // Mark the thumb bit on the symbol. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setFlags(SD.getFlags() | SF_ThumbFunc); } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { @@ -196,6 +193,7 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: case MCSA_ELF_TypeCommon: case MCSA_ELF_TypeNoType: + case MCSA_ELF_TypeGnuUniqueObject: case MCSA_IndirectSymbol: case MCSA_Hidden: case MCSA_Internal: @@ -230,6 +228,10 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, SD.setFlags(SD.getFlags() | SF_NoDeadStrip); break; + case MCSA_SymbolResolver: + SD.setFlags(SD.getFlags() | SF_SymbolResolver); + break; + case MCSA_PrivateExtern: SD.setExternal(true); SD.setPrivateExtern(true); @@ -313,26 +315,6 @@ void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { 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. - 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 MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { @@ -363,28 +345,6 @@ void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - new MCOrgFragment(*Offset, Value, getCurrentSectionData()); -} - -void MCMachOStreamer::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 MCMachOStreamer::EmitInstToData(const MCInst &Inst) { MCDataFragment *DF = getOrCreateDataFragment(); @@ -402,240 +362,7 @@ void MCMachOStreamer::EmitInstToData(const MCInst &Inst) { DF->getContents().append(Code.begin(), Code.end()); } -void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = Inst.getNumOperands(); i--; ) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - - 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); - 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); -} - -// -// 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/lib/MC/MCMachObjectTargetWriter.cpp b/lib/MC/MCMachObjectTargetWriter.cpp new file mode 100644 index 0000000..146cebf --- /dev/null +++ b/lib/MC/MCMachObjectTargetWriter.cpp @@ -0,0 +1,22 @@ +//===-- MCMachObjectTargetWriter.cpp - Mach-O Target Writer Subclass ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCMachObjectWriter.h" + +using namespace llvm; + +MCMachObjectTargetWriter::MCMachObjectTargetWriter( + bool Is64Bit_, uint32_t CPUType_, uint32_t CPUSubtype_, + bool UseAggressiveSymbolFolding_) + : Is64Bit(Is64Bit_), CPUType(CPUType_), CPUSubtype(CPUSubtype_), + UseAggressiveSymbolFolding(UseAggressiveSymbolFolding_) { +} + +MCMachObjectTargetWriter::~MCMachObjectTargetWriter() { +} diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index f7a2f20..08ddf01 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -25,20 +25,26 @@ namespace { /// @name MCStreamer Interface /// @{ - virtual void SwitchSection(const MCSection *Section) { - PrevSection = CurSection; - CurSection = Section; + virtual void InitSections() { + } + + virtual void ChangeSection(const MCSection *Section) { } virtual void EmitLabel(MCSymbol *Symbol) { assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - assert(CurSection && "Cannot emit before setting section!"); - Symbol->setSection(*CurSection); + assert(getCurrentSection() && "Cannot emit before setting section!"); + Symbol->setSection(*getCurrentSection()); } virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) {} + virtual void EmitThumbFunc(MCSymbol *Func) {} virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} + virtual void EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol){} + virtual void EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) {} virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute){} @@ -60,8 +66,12 @@ namespace { uint64_t Size, unsigned ByteAlignment) {} virtual void EmitBytes(StringRef Data, unsigned AddrSpace) {} - virtual void EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) {} + virtual void EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) {} + virtual void EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) {} + virtual void EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) {} virtual void EmitGPRel32Value(const MCExpr *Value) {} virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, @@ -74,7 +84,12 @@ namespace { unsigned char Value = 0) {} virtual void EmitFileDirective(StringRef Filename) {} - virtual void EmitDwarfFileDirective(unsigned FileNo,StringRef Filename) {} + virtual bool EmitDwarfFileDirective(unsigned FileNo,StringRef Filename) { + return false; + } + virtual void EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, unsigned Discriminator) {} virtual void EmitInstruction(const MCInst &Inst) {} virtual void Finish() {} diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index 2b2385e..0358266 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -7,19 +7,26 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCObjectStreamer.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCSymbol.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &_OS, MCCodeEmitter *_Emitter) - : MCStreamer(Context), Assembler(new MCAssembler(Context, TAB, - *_Emitter, _OS)), + raw_ostream &OS, MCCodeEmitter *Emitter_) + : MCStreamer(Context), + Assembler(new MCAssembler(Context, TAB, + *Emitter_, *TAB.createObjectWriter(OS), + OS)), CurSectionData(0) { } @@ -27,6 +34,7 @@ MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, MCObjectStreamer::~MCObjectStreamer() { delete &Assembler->getBackend(); delete &Assembler->getEmitter(); + delete &Assembler->getWriter(); delete Assembler; } @@ -48,7 +56,10 @@ MCDataFragment *MCObjectStreamer::getOrCreateDataFragment() const { const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { switch (Value->getKind()) { - case MCExpr::Target: llvm_unreachable("Can't handle target exprs yet!"); + case MCExpr::Target: + cast<MCTargetExpr>(Value)->AddValueSymbols(Assembler); + break; + case MCExpr::Constant: break; @@ -71,17 +82,173 @@ const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { return Value; } -void MCObjectStreamer::SwitchSection(const MCSection *Section) { - assert(Section && "Cannot switch to a null section!"); +void MCObjectStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, + bool isPCRel, unsigned AddrSpace) { + assert(AddrSpace == 0 && "Address space must be 0!"); + MCDataFragment *DF = getOrCreateDataFragment(); + + // Avoid fixups when possible. + int64_t AbsValue; + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue, getAssembler())) { + EmitIntValue(AbsValue, Size, AddrSpace); + return; + } + DF->addFixup(MCFixup::Create(DF->getContents().size(), + Value, + MCFixup::getKindForSize(Size, isPCRel))); + DF->getContents().resize(DF->getContents().size() + Size, 0); +} + +void MCObjectStreamer::EmitLabel(MCSymbol *Symbol) { + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection() && "Cannot emit before setting section!"); + + Symbol->setSection(*getCurrentSection()); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); +} + +void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, getAssembler())) { + EmitULEB128IntValue(IntValue, AddrSpace); + return; + } + new MCLEBFragment(*Value, false, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace) { + int64_t IntValue; + if (Value->EvaluateAsAbsolute(IntValue, getAssembler())) { + EmitSLEB128IntValue(IntValue, AddrSpace); + return; + } + new MCLEBFragment(*Value, true, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitWeakReference(MCSymbol *Alias, + const MCSymbol *Symbol) { + report_fatal_error("This file format doesn't support weak aliases."); +} - // If already in this section, then this is a noop. - if (Section == CurSection) return; +void MCObjectStreamer::ChangeSection(const MCSection *Section) { + assert(Section && "Cannot switch to a null section!"); - PrevSection = CurSection; - CurSection = Section; CurSectionData = &getAssembler().getOrCreateSectionData(*Section); } +void MCObjectStreamer::EmitInstruction(const MCInst &Inst) { + // Scan for values. + for (unsigned i = Inst.getNumOperands(); i--; ) + if (Inst.getOperand(i).isExpr()) + AddValueSymbols(Inst.getOperand(i).getExpr()); + + 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. + MCLineEntry::Make(this, getCurrentSection()); + + // 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 MCObjectStreamer::EmitInstToFragment(const MCInst &Inst) { + MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); + + raw_svector_ostream VecOS(IF->getCode()); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, IF->getFixups()); +} + +static const MCExpr *BuildSymbolDiff(MCContext &Context, + const MCSymbol *A, const MCSymbol *B) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *ARef = + MCSymbolRefExpr::Create(A, Variant, Context); + const MCExpr *BRef = + MCSymbolRefExpr::Create(B, Variant, Context); + const MCExpr *AddrDelta = + MCBinaryExpr::Create(MCBinaryExpr::Sub, ARef, BRef, Context); + return AddrDelta; +} + +static const MCExpr *ForceExpAbs(MCObjectStreamer *Streamer, + MCContext &Context, const MCExpr* Expr) { + if (Context.getAsmInfo().hasAggressiveSymbolFolding()) + return Expr; + + MCSymbol *ABS = Context.CreateTempSymbol(); + Streamer->EmitAssignment(ABS, Expr); + return MCSymbolRefExpr::Create(ABS, Context); +} + +void MCObjectStreamer::EmitDwarfAdvanceLineAddr(int64_t LineDelta, + const MCSymbol *LastLabel, + const MCSymbol *Label) { + if (!LastLabel) { + int PointerSize = getContext().getTargetAsmInfo().getPointerSize(); + EmitDwarfSetLineAddr(LineDelta, Label, PointerSize); + return; + } + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + MCDwarfLineAddr::Emit(this, LineDelta, Res); + return; + } + AddrDelta = ForceExpAbs(this, getContext(), AddrDelta); + new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitDwarfAdvanceFrameAddr(const MCSymbol *LastLabel, + const MCSymbol *Label) { + const MCExpr *AddrDelta = BuildSymbolDiff(getContext(), Label, LastLabel); + int64_t Res; + if (AddrDelta->EvaluateAsAbsolute(Res, getAssembler())) { + MCDwarfFrameEmitter::EmitAdvanceLoc(*this, Res); + return; + } + AddrDelta = ForceExpAbs(this, getContext(), AddrDelta); + new MCDwarfCallFrameFragment(*AddrDelta, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + new MCOrgFragment(*Offset, Value, getCurrentSectionData()); +} + void MCObjectStreamer::Finish() { + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles()) + MCDwarfFileTable::Emit(this); + getAssembler().Finish(); } diff --git a/lib/MC/MCObjectWriter.cpp b/lib/MC/MCObjectWriter.cpp index d117e82..efe9f68 100644 --- a/lib/MC/MCObjectWriter.cpp +++ b/lib/MC/MCObjectWriter.cpp @@ -7,9 +7,74 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbol.h" using namespace llvm; MCObjectWriter::~MCObjectWriter() { } + +/// Utility function to encode a SLEB128 value. +void MCObjectWriter::EncodeSLEB128(int64_t Value, raw_ostream &OS) { + bool More; + do { + uint8_t Byte = Value & 0x7f; + // NOTE: this assumes that this signed shift is an arithmetic right shift. + Value >>= 7; + More = !((((Value == 0 ) && ((Byte & 0x40) == 0)) || + ((Value == -1) && ((Byte & 0x40) != 0)))); + if (More) + Byte |= 0x80; // Mark this byte that that more bytes will follow. + OS << char(Byte); + } while (More); +} + +/// Utility function to encode a ULEB128 value. +void MCObjectWriter::EncodeULEB128(uint64_t Value, raw_ostream &OS) { + do { + uint8_t Byte = Value & 0x7f; + Value >>= 7; + if (Value != 0) + Byte |= 0x80; // Mark this byte that that more bytes will follow. + OS << char(Byte); + } while (Value != 0); +} + +bool +MCObjectWriter::IsSymbolRefDifferenceFullyResolved(const MCAssembler &Asm, + const MCSymbolRefExpr *A, + const MCSymbolRefExpr *B, + bool InSet) const { + // Modified symbol references cannot be resolved. + if (A->getKind() != MCSymbolRefExpr::VK_None || + B->getKind() != MCSymbolRefExpr::VK_None) + return false; + + const MCSymbol &SA = A->getSymbol(); + const MCSymbol &SB = B->getSymbol(); + if (SA.AliasedSymbol().isUndefined() || SB.AliasedSymbol().isUndefined()) + return false; + + const MCSymbolData &DataA = Asm.getSymbolData(SA); + const MCSymbolData &DataB = Asm.getSymbolData(SB); + + return IsSymbolRefDifferenceFullyResolvedImpl(Asm, DataA, + *DataB.getFragment(), + InSet, + false); +} + +bool +MCObjectWriter::IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + const MCSection &SecA = DataA.getSymbol().AliasedSymbol().getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + // On ELF and COFF A - B is absolute if A and B are in the same section. + return &SecA == &SecB; +} diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 086df08..89374d0 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -15,6 +15,7 @@ #include "llvm/Support/SMLoc.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/MC/MCAsmInfo.h" +#include <cctype> #include <cerrno> #include <cstdio> #include <cstdlib> @@ -30,12 +31,12 @@ AsmLexer::~AsmLexer() { void AsmLexer::setBuffer(const MemoryBuffer *buf, const char *ptr) { CurBuf = buf; - + if (ptr) CurPtr = ptr; else CurPtr = CurBuf->getBufferStart(); - + TokStart = 0; } @@ -43,7 +44,7 @@ void AsmLexer::setBuffer(const MemoryBuffer *buf, const char *ptr) { /// location. This is defined to always return AsmToken::Error. AsmToken AsmLexer::ReturnError(const char *Loc, const std::string &Msg) { SetError(SMLoc::getFromPointer(Loc), Msg); - + return AsmToken(AsmToken::Error, StringRef(Loc, 0)); } @@ -57,23 +58,59 @@ int AsmLexer::getNextChar() { // a random nul in the file. Disambiguate that here. if (CurPtr-1 != CurBuf->getBufferEnd()) return 0; // Just whitespace. - + // Otherwise, return end of file. - --CurPtr; // Another call to lex will return EOF again. + --CurPtr; // Another call to lex will return EOF again. return EOF; } } +/// LexFloatLiteral: [0-9]*[.][0-9]*([eE][+-]?[0-9]*)? +/// +/// The leading integral digit sequence and dot should have already been +/// consumed, some or all of the fractional digit sequence *can* have been +/// consumed. +AsmToken AsmLexer::LexFloatLiteral() { + // Skip the fractional digit sequence. + while (isdigit(*CurPtr)) + ++CurPtr; + + // Check for exponent; we intentionally accept a slighlty wider set of + // literals here and rely on the upstream client to reject invalid ones (e.g., + // "1e+"). + if (*CurPtr == 'e' || *CurPtr == 'E') { + ++CurPtr; + if (*CurPtr == '-' || *CurPtr == '+') + ++CurPtr; + while (isdigit(*CurPtr)) + ++CurPtr; + } + + return AsmToken(AsmToken::Real, + StringRef(TokStart, CurPtr - TokStart)); +} + /// LexIdentifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* +static bool IsIdentifierChar(char c) { + return isalnum(c) || c == '_' || c == '$' || c == '.' || c == '@'; +} AsmToken AsmLexer::LexIdentifier() { - while (isalnum(*CurPtr) || *CurPtr == '_' || *CurPtr == '$' || - *CurPtr == '.' || *CurPtr == '@') + // Check for floating point literals. + if (CurPtr[-1] == '.' && isdigit(*CurPtr)) { + // Disambiguate a .1243foo identifier from a floating literal. + while (isdigit(*CurPtr)) + ++CurPtr; + if (*CurPtr == 'e' || *CurPtr == 'E' || !IsIdentifierChar(*CurPtr)) + return LexFloatLiteral(); + } + + while (IsIdentifierChar(*CurPtr)) ++CurPtr; - + // Handle . as a special case. if (CurPtr == TokStart+1 && TokStart[0] == '.') return AsmToken(AsmToken::Dot, StringRef(TokStart, 1)); - + return AsmToken(AsmToken::Identifier, StringRef(TokStart, CurPtr - TokStart)); } @@ -83,7 +120,7 @@ AsmToken AsmLexer::LexSlash() { switch (*CurPtr) { case '*': break; // C style comment. case '/': return ++CurPtr, LexLineComment(); - default: return AsmToken(AsmToken::Slash, StringRef(CurPtr, 1)); + default: return AsmToken(AsmToken::Slash, StringRef(CurPtr-1, 1)); } // C Style comment. @@ -96,7 +133,7 @@ AsmToken AsmLexer::LexSlash() { case '*': // End of the comment? if (CurPtr[0] != '/') break; - + ++CurPtr; // End the */. return LexToken(); } @@ -111,7 +148,7 @@ AsmToken AsmLexer::LexLineComment() { int CurChar = getNextChar(); while (CurChar != '\n' && CurChar != '\n' && CurChar != EOF) CurChar = getNextChar(); - + if (CurChar == EOF) return AsmToken(AsmToken::Eof, StringRef(CurPtr, 0)); return AsmToken(AsmToken::EndOfStatement, StringRef(CurPtr, 0)); @@ -124,7 +161,6 @@ static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { CurPtr += 3; } - /// LexDigit: First character is [0-9]. /// Local Label: [0-9][:] /// Forward/Backward Label: [0-9][fb] @@ -132,32 +168,37 @@ static void SkipIgnoredIntegerSuffix(const char *&CurPtr) { /// Octal integer: 0[0-7]+ /// Hex integer: 0x[0-9a-fA-F]+ /// Decimal integer: [1-9][0-9]* -/// TODO: FP literal. AsmToken AsmLexer::LexDigit() { // Decimal integer: [1-9][0-9]* - if (CurPtr[-1] != '0') { + if (CurPtr[-1] != '0' || CurPtr[0] == '.') { while (isdigit(*CurPtr)) ++CurPtr; - + + // Check for floating point literals. + if (*CurPtr == '.' || *CurPtr == 'e') { + ++CurPtr; + return LexFloatLiteral(); + } + StringRef Result(TokStart, CurPtr - TokStart); long long Value; if (Result.getAsInteger(10, Value)) { - // We have to handle minint_as_a_positive_value specially, because - // - minint_as_a_positive_value = minint and it is valid. - if (Result == "9223372036854775808") - Value = -9223372036854775808ULL; - else - return ReturnError(TokStart, "Invalid decimal number"); + // Allow positive values that are too large to fit into a signed 64-bit + // integer, but that do fit in an unsigned one, we just convert them over. + unsigned long long UValue; + if (Result.getAsInteger(10, UValue)) + return ReturnError(TokStart, "invalid decimal number"); + Value = (long long)UValue; } - + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL // suffixes on integer literals. SkipIgnoredIntegerSuffix(CurPtr); - + return AsmToken(AsmToken::Integer, Result, Value); } - + if (*CurPtr == 'b') { ++CurPtr; // See if we actually have "0b" as part of something like "jmp 0b\n" @@ -169,30 +210,30 @@ AsmToken AsmLexer::LexDigit() { const char *NumStart = CurPtr; while (CurPtr[0] == '0' || CurPtr[0] == '1') ++CurPtr; - + // Requires at least one binary digit. if (CurPtr == NumStart) return ReturnError(TokStart, "Invalid binary number"); - + StringRef Result(TokStart, CurPtr - TokStart); - + long long Value; if (Result.substr(2).getAsInteger(2, Value)) return ReturnError(TokStart, "Invalid binary number"); - + // The darwin/x86 (and x86-64) assembler accepts and ignores ULL and LL // suffixes on integer literals. SkipIgnoredIntegerSuffix(CurPtr); - + return AsmToken(AsmToken::Integer, Result, Value); } - + if (*CurPtr == 'x') { ++CurPtr; const char *NumStart = CurPtr; while (isxdigit(CurPtr[0])) ++CurPtr; - + // Requires at least one hex digit. if (CurPtr == NumStart) return ReturnError(CurPtr-2, "Invalid hexadecimal number"); @@ -200,31 +241,67 @@ AsmToken AsmLexer::LexDigit() { unsigned long long Result; 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); } - + // Must be an octal number, it starts with 0. while (*CurPtr >= '0' && *CurPtr <= '7') ++CurPtr; - + StringRef Result(TokStart, CurPtr - TokStart); long long Value; 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); } +/// LexSingleQuote: Integer: 'b' +AsmToken AsmLexer::LexSingleQuote() { + int CurChar = getNextChar(); + + if (CurChar == '\\') + CurChar = getNextChar(); + + if (CurChar == EOF) + return ReturnError(TokStart, "unterminated single quote"); + + CurChar = getNextChar(); + + if (CurChar != '\'') + return ReturnError(TokStart, "single quote way too long"); + + // The idea here being that 'c' is basically just an integral + // constant. + StringRef Res = StringRef(TokStart,CurPtr - TokStart); + long long Value; + + if (Res.startswith("\'\\")) { + char theChar = Res[2]; + switch (theChar) { + default: Value = theChar; break; + case '\'': Value = '\''; break; + case 't': Value = '\t'; break; + case 'n': Value = '\n'; break; + case 'b': Value = '\b'; break; + } + } else + Value = TokStart[1]; + + return AsmToken(AsmToken::Integer, Res, Value); +} + + /// LexQuote: String: "..." AsmToken AsmLexer::LexQuote() { int CurChar = getNextChar(); @@ -234,13 +311,13 @@ AsmToken AsmLexer::LexQuote() { // Allow \", etc. CurChar = getNextChar(); } - + if (CurChar == EOF) return ReturnError(TokStart, "unterminated string constant"); CurChar = getNextChar(); } - + return AsmToken(AsmToken::String, StringRef(TokStart, CurPtr - TokStart)); } @@ -266,7 +343,7 @@ AsmToken AsmLexer::LexToken() { TokStart = CurPtr; // This always consumes at least one character. int CurChar = getNextChar(); - + if (isAtStartOfComment(CurChar)) return LexLineComment(); @@ -275,7 +352,7 @@ AsmToken AsmLexer::LexToken() { // Handle identifier: [a-zA-Z_.][a-zA-Z0-9_$.@]* if (isalpha(CurChar) || CurChar == '_' || CurChar == '.') return LexIdentifier(); - + // Unknown character, emit an error. return ReturnError(TokStart, "invalid character in input"); case EOF: return AsmToken(AsmToken::Eof, StringRef(TokStart, 0)); @@ -301,49 +378,50 @@ AsmToken AsmLexer::LexToken() { case ',': return AsmToken(AsmToken::Comma, StringRef(TokStart, 1)); case '$': return AsmToken(AsmToken::Dollar, StringRef(TokStart, 1)); case '@': return AsmToken(AsmToken::At, StringRef(TokStart, 1)); - case '=': + case '=': if (*CurPtr == '=') return ++CurPtr, AsmToken(AsmToken::EqualEqual, StringRef(TokStart, 2)); return AsmToken(AsmToken::Equal, StringRef(TokStart, 1)); - case '|': + case '|': if (*CurPtr == '|') return ++CurPtr, AsmToken(AsmToken::PipePipe, StringRef(TokStart, 2)); return AsmToken(AsmToken::Pipe, StringRef(TokStart, 1)); case '^': return AsmToken(AsmToken::Caret, StringRef(TokStart, 1)); - case '&': + case '&': if (*CurPtr == '&') return ++CurPtr, AsmToken(AsmToken::AmpAmp, StringRef(TokStart, 2)); return AsmToken(AsmToken::Amp, StringRef(TokStart, 1)); - case '!': + case '!': if (*CurPtr == '=') return ++CurPtr, AsmToken(AsmToken::ExclaimEqual, StringRef(TokStart, 2)); return AsmToken(AsmToken::Exclaim, StringRef(TokStart, 1)); case '%': return AsmToken(AsmToken::Percent, StringRef(TokStart, 1)); case '/': return LexSlash(); case '#': return AsmToken(AsmToken::Hash, StringRef(TokStart, 1)); + case '\'': return LexSingleQuote(); case '"': return LexQuote(); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return LexDigit(); case '<': switch (*CurPtr) { - case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, + case '<': return ++CurPtr, AsmToken(AsmToken::LessLess, StringRef(TokStart, 2)); - case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, + case '=': return ++CurPtr, AsmToken(AsmToken::LessEqual, StringRef(TokStart, 2)); - case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, + case '>': return ++CurPtr, AsmToken(AsmToken::LessGreater, StringRef(TokStart, 2)); default: return AsmToken(AsmToken::Less, StringRef(TokStart, 1)); } case '>': switch (*CurPtr) { - case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, + case '>': return ++CurPtr, AsmToken(AsmToken::GreaterGreater, StringRef(TokStart, 2)); - case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, + case '=': return ++CurPtr, AsmToken(AsmToken::GreaterEqual, StringRef(TokStart, 2)); default: return AsmToken(AsmToken::Greater, StringRef(TokStart, 1)); } - + // TODO: Quoted identifiers (objc methods etc) // local labels: [0-9][:] // Forward/backward labels: [0-9][fb] diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index f83cd5e..c6d0da6 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/APFloat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" @@ -18,7 +19,6 @@ #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" @@ -27,11 +27,12 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCDwarf.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Target/TargetAsmInfo.h" #include "llvm/Target/TargetAsmParser.h" +#include <cctype> #include <vector> using namespace llvm; @@ -102,6 +103,9 @@ private: /// Boolean tracking whether macro substitution is enabled. unsigned MacrosEnabled : 1; + /// Flag tracking whether any errors have been encountered. + unsigned HadError : 1; + public: AsmParser(const Target &T, SourceMgr &SM, MCContext &Ctx, MCStreamer &Out, const MCAsmInfo &MAI); @@ -137,14 +141,18 @@ public: /// } private: + void CheckForValidSection(); + 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; - + void PrintMessage(SMLoc Loc, const Twine &Msg, const char *Type) const { + SrcMgr.PrintMessage(Loc, Msg, Type); + } + /// EnterIncludeFile - Enter the specified file. This returns true on failure. bool EnterIncludeFile(const std::string &Filename); @@ -160,22 +168,27 @@ private: /// will be either the EndOfStatement or EOF. StringRef ParseStringToEndOfStatement(); - bool ParseAssignment(StringRef Name); + bool ParseAssignment(StringRef Name, bool allow_redef); bool ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc); bool ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, SMLoc &EndLoc); bool ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc); + bool ParseBracketExpr(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" + + // ".ascii", ".asciiz", ".string" + bool ParseDirectiveAscii(StringRef IDVal, bool ZeroTerminated); bool ParseDirectiveValue(unsigned Size); // ".byte", ".long", ... + bool ParseDirectiveRealValue(const fltSemantics &); // ".single", ... bool ParseDirectiveFill(); // ".fill" bool ParseDirectiveSpace(); // ".space" - bool ParseDirectiveSet(); // ".set" + bool ParseDirectiveZero(); // ".zero" + bool ParseDirectiveSet(StringRef IDVal, bool allow_redef); // ".set", ".equ", ".equiv" bool ParseDirectiveOrg(); // ".org" // ".align{,32}", ".p2align{,w,l}" bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); @@ -183,7 +196,6 @@ private: /// 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" @@ -191,6 +203,8 @@ private: bool ParseDirectiveInclude(); // ".include" bool ParseDirectiveIf(SMLoc DirectiveLoc); // ".if" + // ".ifdef" or ".ifndef", depending on expect_defined + bool ParseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined); bool ParseDirectiveElseIf(SMLoc DirectiveLoc); // ".elseif" bool ParseDirectiveElse(SMLoc DirectiveLoc); // ".else" bool ParseDirectiveEndIf(SMLoc DirectiveLoc); // .endif @@ -198,6 +212,9 @@ private: /// ParseEscapedString - Parse the current token as a string which may include /// escaped characters and return the string contents. bool ParseEscapedString(std::string &Data); + + const MCExpr *ApplyModifierToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant); }; /// \brief Generic implementations of directive handling, etc. which is shared @@ -208,7 +225,6 @@ class GenericAsmParser : public MCAsmParserExtension { getParser().AddDirectiveHandler(this, Directive, HandleDirective<GenericAsmParser, Handler>); } - public: GenericAsmParser() {} @@ -224,6 +240,29 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveFile>(".file"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLine>(".line"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLoc>(".loc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveStabs>(".stabs"); + + // CFI directives. + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIStartProc>( + ".cfi_startproc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIEndProc>( + ".cfi_endproc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIDefCfa>( + ".cfi_def_cfa"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIDefCfaOffset>( + ".cfi_def_cfa_offset"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIDefCfaRegister>( + ".cfi_def_cfa_register"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveCFIOffset>( + ".cfi_offset"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda>(".cfi_personality"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda>(".cfi_lsda"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIRememberState>(".cfi_remember_state"); + AddDirectiveHandler< + &GenericAsmParser::ParseDirectiveCFIRestoreState>(".cfi_restore_state"); // Macro directives. AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( @@ -233,15 +272,32 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacro>(".macro"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endm"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endmacro"); + + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".sleb128"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".uleb128"); } + bool ParseRegisterOrRegisterNumber(int64_t &Register, SMLoc DirectiveLoc); + bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveStabs(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIStartProc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIEndProc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIDefCfa(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIDefCfaOffset(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIDefCfaRegister(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIOffset(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIPersonalityOrLsda(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIRememberState(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveCFIRestoreState(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); + + bool ParseDirectiveLEB128(StringRef, SMLoc); }; } @@ -250,6 +306,7 @@ namespace llvm { extern MCAsmParserExtension *createDarwinAsmParser(); extern MCAsmParserExtension *createELFAsmParser(); +extern MCAsmParserExtension *createCOFFAsmParser(); } @@ -269,7 +326,10 @@ AsmParser::AsmParser(const Target &T, SourceMgr &_SM, MCContext &_Ctx, // // FIXME: This is a hack, we need to (majorly) cleanup how these objects are // created. - if (_MAI.hasSubsectionsViaSymbols()) { + if (_MAI.hasMicrosoftFastStdCallMangling()) { + PlatformParser = createCOFFAsmParser(); + PlatformParser->Initialize(*this); + } else if (_MAI.hasSubsectionsViaSymbols()) { PlatformParser = createDarwinAsmParser(); PlatformParser->Initialize(*this); } else { @@ -299,30 +359,26 @@ void AsmParser::PrintMacroInstantiations() { } void AsmParser::Warning(SMLoc L, const Twine &Msg) { - PrintMessage(L, Msg.str(), "warning"); + PrintMessage(L, Msg, "warning"); PrintMacroInstantiations(); } bool AsmParser::Error(SMLoc L, const Twine &Msg) { - PrintMessage(L, Msg.str(), "error"); + HadError = true; + PrintMessage(L, Msg, "error"); PrintMacroInstantiations(); return true; } -void AsmParser::PrintMessage(SMLoc Loc, const std::string &Msg, - const char *Type) const { - SrcMgr.PrintMessage(Loc, Msg, Type); -} - bool AsmParser::EnterIncludeFile(const std::string &Filename) { int NewBuf = SrcMgr.AddIncludeFile(Filename, Lexer.getLoc()); if (NewBuf == -1) return true; - + CurBuffer = NewBuf; - + Lexer.setBuffer(SrcMgr.getMemoryBuffer(CurBuffer)); - + return false; } @@ -333,7 +389,7 @@ void AsmParser::JumpToLoc(SMLoc Loc) { const AsmToken &AsmParser::Lex() { const AsmToken *tok = &Lexer.Lex(); - + if (tok->is(AsmToken::Eof)) { // If this is the end of an included file, pop the parent file off the // include stack. @@ -343,35 +399,31 @@ const AsmToken &AsmParser::Lex() { tok = &Lexer.Lex(); } } - + if (tok->is(AsmToken::Error)) Error(Lexer.getErrLoc(), Lexer.getErr()); - + return *tok; } bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { // Create the initial section, if requested. - // - // FIXME: Target hook & command line option for initial section. if (!NoInitialTextSection) - Out.SwitchSection(Ctx.getMachOSection("__TEXT", "__text", - MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 0, SectionKind::getText())); + Out.InitSections(); // Prime the lexer. Lex(); - - bool HadError = false; - + + HadError = false; AsmCond StartingCondState = TheCondState; // While we have input, parse each statement. while (Lexer.isNot(AsmToken::Eof)) { if (!ParseStatement()) continue; - - // We had an error, remember it and recover by skipping to the next line. - HadError = true; + + // We had an error, validate that one was emitted and recover by skipping to + // the next line. + assert(HadError && "Parse statement returned an error, but none emitted!"); EatToEndOfStatement(); } @@ -383,26 +435,34 @@ bool AsmParser::Run(bool NoInitialTextSection, bool NoFinalize) { const std::vector<MCDwarfFile *> &MCDwarfFiles = getContext().getMCDwarfFiles(); for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { - if (!MCDwarfFiles[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. - if (!HadError && !NoFinalize) + if (!HadError && !NoFinalize) Out.Finish(); return HadError; } +void AsmParser::CheckForValidSection() { + if (!getStreamer().getCurrentSection()) { + TokError("expected section directive before assembly directive"); + Out.SwitchSection(Ctx.getMachOSection( + "__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + } +} + /// EatToEndOfStatement - Throw away the rest of the line for testing purposes. void AsmParser::EatToEndOfStatement() { while (Lexer.isNot(AsmToken::EndOfStatement) && Lexer.isNot(AsmToken::Eof)) Lex(); - + // Eat EOL. if (Lexer.is(AsmToken::EndOfStatement)) Lex(); @@ -433,6 +493,20 @@ bool AsmParser::ParseParenExpr(const MCExpr *&Res, SMLoc &EndLoc) { return false; } +/// ParseBracketExpr - Parse a bracket expression and return it. +/// NOTE: This assumes the leading '[' has already been consumed. +/// +/// bracketexpr ::= expr] +/// +bool AsmParser::ParseBracketExpr(const MCExpr *&Res, SMLoc &EndLoc) { + if (ParseExpression(Res)) return true; + if (Lexer.isNot(AsmToken::RBrac)) + return TokError("expected ']' in brackets expression"); + EndLoc = Lexer.getLoc(); + Lex(); + return false; +} + /// ParsePrimaryExpr - Parse a primary expression and return it. /// primaryexpr ::= (parenexpr /// primaryexpr ::= symbol @@ -462,19 +536,21 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { std::pair<StringRef, StringRef> Split = Identifier.split('@'); MCSymbol *Sym = getContext().GetOrCreateSymbol(Split.first); - // Mark the symbol as used in an expression. - Sym->setUsedInExpr(true); - // Lookup the symbol variant if used. MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - if (Split.first.size() != Identifier.size()) + if (Split.first.size() != Identifier.size()) { Variant = MCSymbolRefExpr::getVariantKindForName(Split.second); + if (Variant == MCSymbolRefExpr::VK_Invalid) { + Variant = MCSymbolRefExpr::VK_None; + return TokError("invalid variant '" + Split.second + "'"); + } + } // If this is an absolute variable reference, substitute it now to preserve // semantics in the face of reassignment. if (Sym->isVariable() && isa<MCConstantExpr>(Sym->getVariableValue())) { if (Variant) - return Error(EndLoc, "unexpected modified on variable reference"); + return Error(EndLoc, "unexpected modifier on variable reference"); Res = Sym->getVariableValue(); return false; @@ -506,6 +582,13 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { } return false; } + case AsmToken::Real: { + APFloat RealVal(APFloat::IEEEdouble, getTok().getString()); + uint64_t IntVal = RealVal.bitcastToAPInt().getZExtValue(); + Res = MCConstantExpr::Create(IntVal, getContext()); + Lex(); // Eat token. + return false; + } case AsmToken::Dot: { // This is a '.' reference, which references the current PC. Emit a // temporary label to the streamer and refer to it. @@ -516,10 +599,12 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { Lex(); // Eat identifier. return false; } - case AsmToken::LParen: Lex(); // Eat the '('. return ParseParenExpr(Res, EndLoc); + case AsmToken::LBrac: + Lex(); // Eat the '['. + return ParseBracketExpr(Res, EndLoc); case AsmToken::Minus: Lex(); // Eat the operator. if (ParsePrimaryExpr(Res, EndLoc)) @@ -546,8 +631,57 @@ bool AsmParser::ParseExpression(const MCExpr *&Res) { return ParseExpression(Res, EndLoc); } +const MCExpr * +AsmParser::ApplyModifierToExpr(const MCExpr *E, + MCSymbolRefExpr::VariantKind Variant) { + // Recurse over the given expression, rebuilding it to apply the given variant + // if there is exactly one symbol. + switch (E->getKind()) { + case MCExpr::Target: + case MCExpr::Constant: + return 0; + + case MCExpr::SymbolRef: { + const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(E); + + if (SRE->getKind() != MCSymbolRefExpr::VK_None) { + TokError("invalid variant on expression '" + + getTok().getIdentifier() + "' (already modified)"); + return E; + } + + return MCSymbolRefExpr::Create(&SRE->getSymbol(), Variant, getContext()); + } + + case MCExpr::Unary: { + const MCUnaryExpr *UE = cast<MCUnaryExpr>(E); + const MCExpr *Sub = ApplyModifierToExpr(UE->getSubExpr(), Variant); + if (!Sub) + return 0; + return MCUnaryExpr::Create(UE->getOpcode(), Sub, getContext()); + } + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(E); + const MCExpr *LHS = ApplyModifierToExpr(BE->getLHS(), Variant); + const MCExpr *RHS = ApplyModifierToExpr(BE->getRHS(), Variant); + + if (!LHS && !RHS) + return 0; + + if (!LHS) LHS = BE->getLHS(); + if (!RHS) RHS = BE->getRHS(); + + return MCBinaryExpr::Create(BE->getOpcode(), LHS, RHS, getContext()); + } + } + + assert(0 && "Invalid expression kind!"); + return 0; +} + /// ParseExpression - Parse an expression and return it. -/// +/// /// expr ::= expr +,- expr -> lowest. /// expr ::= expr |,^,&,! expr -> middle. /// expr ::= expr *,/,%,<<,>> expr -> highest. @@ -559,6 +693,31 @@ bool AsmParser::ParseExpression(const MCExpr *&Res, SMLoc &EndLoc) { if (ParsePrimaryExpr(Res, EndLoc) || ParseBinOpRHS(1, Res, EndLoc)) return true; + // As a special case, we support 'a op b @ modifier' by rewriting the + // expression to include the modifier. This is inefficient, but in general we + // expect users to use 'a@modifier op b'. + if (Lexer.getKind() == AsmToken::At) { + Lex(); + + if (Lexer.isNot(AsmToken::Identifier)) + return TokError("unexpected symbol modifier following '@'"); + + MCSymbolRefExpr::VariantKind Variant = + MCSymbolRefExpr::getVariantKindForName(getTok().getIdentifier()); + if (Variant == MCSymbolRefExpr::VK_Invalid) + return TokError("invalid variant '" + getTok().getIdentifier() + "'"); + + const MCExpr *ModifiedRes = ApplyModifierToExpr(Res, Variant); + if (!ModifiedRes) { + return TokError("invalid modifier '" + getTok().getIdentifier() + + "' (no symbols present)"); + return true; + } + + Res = ModifiedRes; + Lex(); + } + // Try to constant fold it up front, if possible. int64_t Value; if (Res->EvaluateAsAbsolute(Value)) @@ -575,7 +734,7 @@ bool AsmParser::ParseParenExpression(const MCExpr *&Res, SMLoc &EndLoc) { bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { const MCExpr *Expr; - + SMLoc StartLoc = Lexer.getLoc(); if (ParseExpression(Expr)) return true; @@ -586,13 +745,13 @@ bool AsmParser::ParseAbsoluteExpression(int64_t &Res) { return false; } -static unsigned getBinOpPrecedence(AsmToken::TokenKind K, +static unsigned getBinOpPrecedence(AsmToken::TokenKind K, MCBinaryExpr::Opcode &Kind) { switch (K) { default: return 0; // not a binop. - // Lowest Precedence: &&, || + // Lowest Precedence: &&, ||, @ case AsmToken::AmpAmp: Kind = MCBinaryExpr::LAnd; return 1; @@ -600,62 +759,65 @@ static unsigned getBinOpPrecedence(AsmToken::TokenKind K, Kind = MCBinaryExpr::LOr; return 1; - // Low Precedence: +, -, ==, !=, <>, <, <=, >, >= - case AsmToken::Plus: - Kind = MCBinaryExpr::Add; + + // Low Precedence: |, &, ^ + // + // FIXME: gas seems to support '!' as an infix operator? + case AsmToken::Pipe: + Kind = MCBinaryExpr::Or; return 2; - case AsmToken::Minus: - Kind = MCBinaryExpr::Sub; + case AsmToken::Caret: + Kind = MCBinaryExpr::Xor; + return 2; + case AsmToken::Amp: + Kind = MCBinaryExpr::And; return 2; + + // Low Intermediate Precedence: ==, !=, <>, <, <=, >, >= case AsmToken::EqualEqual: Kind = MCBinaryExpr::EQ; - return 2; + return 3; case AsmToken::ExclaimEqual: case AsmToken::LessGreater: Kind = MCBinaryExpr::NE; - return 2; + return 3; case AsmToken::Less: Kind = MCBinaryExpr::LT; - return 2; + return 3; case AsmToken::LessEqual: Kind = MCBinaryExpr::LTE; - return 2; + return 3; case AsmToken::Greater: Kind = MCBinaryExpr::GT; - return 2; + return 3; case AsmToken::GreaterEqual: Kind = MCBinaryExpr::GTE; - return 2; - - // Intermediate Precedence: |, &, ^ - // - // FIXME: gas seems to support '!' as an infix operator? - case AsmToken::Pipe: - Kind = MCBinaryExpr::Or; - return 3; - case AsmToken::Caret: - Kind = MCBinaryExpr::Xor; - return 3; - case AsmToken::Amp: - Kind = MCBinaryExpr::And; return 3; + // High Intermediate Precedence: +, - + case AsmToken::Plus: + Kind = MCBinaryExpr::Add; + return 4; + case AsmToken::Minus: + Kind = MCBinaryExpr::Sub; + return 4; + // Highest Precedence: *, /, %, <<, >> case AsmToken::Star: Kind = MCBinaryExpr::Mul; - return 4; + return 5; case AsmToken::Slash: Kind = MCBinaryExpr::Div; - return 4; + return 5; case AsmToken::Percent: Kind = MCBinaryExpr::Mod; - return 4; + return 5; case AsmToken::LessLess: Kind = MCBinaryExpr::Shl; - return 4; + return 5; case AsmToken::GreaterGreater: Kind = MCBinaryExpr::Shr; - return 4; + return 5; } } @@ -667,18 +829,18 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, while (1) { MCBinaryExpr::Opcode Kind = MCBinaryExpr::Add; unsigned TokPrec = getBinOpPrecedence(Lexer.getKind(), Kind); - + // If the next token is lower precedence than we are allowed to eat, return // successfully with what we ate already. if (TokPrec < Precedence) return false; - + Lex(); - + // Eat the next primary expression. const MCExpr *RHS; if (ParsePrimaryExpr(RHS, EndLoc)) return true; - + // If BinOp binds less tightly with RHS than the operator after RHS, let // the pending operator take RHS as its LHS. MCBinaryExpr::Opcode Dummy; @@ -692,9 +854,9 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, } } - - - + + + /// ParseStatement: /// ::= EndOfStatement /// ::= Label* Directive ...Operands... EndOfStatement @@ -706,12 +868,17 @@ bool AsmParser::ParseStatement() { return false; } - // Statements always start with an identifier. + // Statements always start with an identifier or are a full line comment. AsmToken ID = getTok(); SMLoc IDLoc = ID.getLoc(); StringRef IDVal; int64_t LocalLabelVal = -1; - // GUESS allow an integer followed by a ':' as a directional local label + // A full line comment is a '#' as the first token. + if (Lexer.is(AsmToken::Hash)) { + EatToEndOfStatement(); + return false; + } + // Allow an integer followed by a ':' as a directional local label. if (Lexer.is(AsmToken::Integer)) { LocalLabelVal = getTok().getIntVal(); if (LocalLabelVal < 0) { @@ -739,24 +906,30 @@ bool AsmParser::ParseStatement() { // example. if (IDVal == ".if") return ParseDirectiveIf(IDLoc); + if (IDVal == ".ifdef") + return ParseDirectiveIfdef(IDLoc, true); + if (IDVal == ".ifndef" || IDVal == ".ifnotdef") + return ParseDirectiveIfdef(IDLoc, false); if (IDVal == ".elseif") return ParseDirectiveElseIf(IDLoc); if (IDVal == ".else") return ParseDirectiveElse(IDLoc); if (IDVal == ".endif") return ParseDirectiveEndIf(IDLoc); - + // If we are in a ".if 0" block, ignore this statement. if (TheCondState.Ignore) { EatToEndOfStatement(); return false; } - + // FIXME: Recurse on local labels? // See what kind of statement we have. switch (Lexer.getKind()) { case AsmToken::Colon: { + CheckForValidSection(); + // identifier ':' -> Label. Lex(); @@ -772,10 +945,10 @@ bool AsmParser::ParseStatement() { Sym = Ctx.CreateDirectionalLocalSymbol(LocalLabelVal); if (!Sym->isUndefined() || Sym->isVariable()) return Error(IDLoc, "invalid symbol redefinition"); - + // Emit the label. Out.EmitLabel(Sym); - + // Consume any end of statement token, if present, to avoid spurious // AddBlankLine calls(). if (Lexer.is(AsmToken::EndOfStatement)) { @@ -791,7 +964,7 @@ bool AsmParser::ParseStatement() { // identifier '=' ... -> assignment statement Lex(); - return ParseAssignment(IDVal); + return ParseAssignment(IDVal, true); default: // Normal instruction or directive. break; @@ -802,27 +975,43 @@ bool AsmParser::ParseStatement() { if (const Macro *M = MacroMap.lookup(IDVal)) return HandleMacroEntry(IDVal, IDLoc, M); - // Otherwise, we have a normal instruction or directive. + // Otherwise, we have a normal instruction or directive. if (IDVal[0] == '.') { // Assembler features - if (IDVal == ".set") - return ParseDirectiveSet(); + if (IDVal == ".set" || IDVal == ".equ") + return ParseDirectiveSet(IDVal, true); + if (IDVal == ".equiv") + return ParseDirectiveSet(IDVal, false); // Data directives if (IDVal == ".ascii") - return ParseDirectiveAscii(false); - if (IDVal == ".asciz") - return ParseDirectiveAscii(true); + return ParseDirectiveAscii(IDVal, false); + if (IDVal == ".asciz" || IDVal == ".string") + return ParseDirectiveAscii(IDVal, true); if (IDVal == ".byte") return ParseDirectiveValue(1); if (IDVal == ".short") return ParseDirectiveValue(2); + if (IDVal == ".value") + return ParseDirectiveValue(2); + if (IDVal == ".2byte") + return ParseDirectiveValue(2); if (IDVal == ".long") return ParseDirectiveValue(4); + if (IDVal == ".int") + return ParseDirectiveValue(4); + if (IDVal == ".4byte") + return ParseDirectiveValue(4); if (IDVal == ".quad") return ParseDirectiveValue(8); + if (IDVal == ".8byte") + return ParseDirectiveValue(8); + if (IDVal == ".single" || IDVal == ".float") + return ParseDirectiveRealValue(APFloat::IEEEsingle); + if (IDVal == ".double") + return ParseDirectiveRealValue(APFloat::IEEEdouble); if (IDVal == ".align") { bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); @@ -852,11 +1041,16 @@ bool AsmParser::ParseStatement() { return ParseDirectiveFill(); if (IDVal == ".space") return ParseDirectiveSpace(); + if (IDVal == ".zero") + return ParseDirectiveZero(); // Symbol attribute directives if (IDVal == ".globl" || IDVal == ".global") return ParseDirectiveSymbolAttribute(MCSA_Global); + // ELF only? Should it be here? + if (IDVal == ".local") + return ParseDirectiveSymbolAttribute(MCSA_Local); if (IDVal == ".hidden") return ParseDirectiveSymbolAttribute(MCSA_Hidden); if (IDVal == ".indirect_symbol") @@ -867,14 +1061,14 @@ bool AsmParser::ParseStatement() { return ParseDirectiveSymbolAttribute(MCSA_LazyReference); if (IDVal == ".no_dead_strip") return ParseDirectiveSymbolAttribute(MCSA_NoDeadStrip); + if (IDVal == ".symbol_resolver") + return ParseDirectiveSymbolAttribute(MCSA_SymbolResolver); if (IDVal == ".private_extern") return ParseDirectiveSymbolAttribute(MCSA_PrivateExtern); if (IDVal == ".protected") return ParseDirectiveSymbolAttribute(MCSA_Protected); if (IDVal == ".reference") return ParseDirectiveSymbolAttribute(MCSA_Reference); - if (IDVal == ".type") - return ParseDirectiveELFType(); if (IDVal == ".weak") return ParseDirectiveSymbolAttribute(MCSA_Weak); if (IDVal == ".weak_definition") @@ -894,6 +1088,9 @@ bool AsmParser::ParseStatement() { if (IDVal == ".include") return ParseDirectiveInclude(); + if (IDVal == ".code16" || IDVal == ".code32" || IDVal == ".code64") + return TokError(Twine(IDVal) + " not supported yet"); + // Look up the handler in the handler table. std::pair<MCAsmParserExtension*, DirectiveHandler> Handler = DirectiveMap.lookup(IDVal); @@ -909,16 +1106,16 @@ bool AsmParser::ParseStatement() { return false; } + CheckForValidSection(); + // Canonicalize the opcode to lower case. SmallString<128> Opcode; for (unsigned i = 0, e = IDVal.size(); i != e; ++i) Opcode.push_back(tolower(IDVal[i])); - + SmallVector<MCParsedAsmOperand*, 8> ParsedOperands; bool HadError = getTargetParser().ParseInstruction(Opcode.str(), IDLoc, ParsedOperands); - if (!HadError && Lexer.isNot(AsmToken::EndOfStatement)) - HadError = TokError("unexpected token in argument list"); // Dump the parsed representation, if requested. if (getShowParsedOperands()) { @@ -936,25 +1133,17 @@ bool AsmParser::ParseStatement() { } // If parsing succeeded, match the instruction. - if (!HadError) { - MCInst Inst; - if (!getTargetParser().MatchInstruction(IDLoc, ParsedOperands, Inst)) { - // Emit the instruction on success. - Out.EmitInstruction(Inst); - } else - HadError = true; - } - - // If there was no error, consume the end-of-statement token. Otherwise this - // will be done by our caller. if (!HadError) - Lex(); + HadError = getTargetParser().MatchAndEmitInstruction(IDLoc, ParsedOperands, + Out); // Free any parsed operands. for (unsigned i = 0, e = ParsedOperands.size(); i != e; ++i) delete ParsedOperands[i]; - return HadError; + // Don't skip the rest of the line, the instruction parser is responsible for + // that. + return false; } MacroInstantiation::MacroInstantiation(const Macro *M, SMLoc IL, SMLoc EL, @@ -1083,14 +1272,35 @@ void AsmParser::HandleMacroExit() { ActiveMacros.pop_back(); } -bool AsmParser::ParseAssignment(StringRef Name) { +static void MarkUsed(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Binary: + MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getLHS()); + MarkUsed(static_cast<const MCBinaryExpr*>(Value)->getRHS()); + break; + case MCExpr::Target: + case MCExpr::Constant: + break; + case MCExpr::SymbolRef: { + static_cast<const MCSymbolRefExpr*>(Value)->getSymbol().setUsed(true); + break; + } + case MCExpr::Unary: + MarkUsed(static_cast<const MCUnaryExpr*>(Value)->getSubExpr()); + break; + } +} + +bool AsmParser::ParseAssignment(StringRef Name, bool allow_redef) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); const MCExpr *Value; if (ParseExpression(Value)) return true; - + + MarkUsed(Value); + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in assignment"); @@ -1105,22 +1315,23 @@ bool AsmParser::ParseAssignment(StringRef Name) { // // FIXME: Diagnostics. Note the location of the definition as a label. // FIXME: Diagnose assignment to protected identifier (e.g., register name). - if (Sym->isUndefined() && !Sym->isUsedInExpr()) + if (Sym->isUndefined() && !Sym->isUsed() && !Sym->isVariable()) ; // Allow redefinitions of undefined symbols only used in directives. - else if (!Sym->isUndefined() && !Sym->isAbsolute()) + else if (!Sym->isUndefined() && (!Sym->isAbsolute() || !allow_redef)) return Error(EqualLoc, "redefinition of '" + Name + "'"); else if (!Sym->isVariable()) return Error(EqualLoc, "invalid assignment to '" + Name + "'"); else if (!isa<MCConstantExpr>(Sym->getVariableValue())) return Error(EqualLoc, "invalid reassignment of non-absolute variable '" + Name + "'"); + + // Don't count these checks as uses. + Sym->setUsed(false); } else Sym = getContext().GetOrCreateSymbol(Name); // FIXME: Handle '.'. - Sym->setUsedInExpr(true); - // Do the assignment. Out.EmitAssignment(Sym, Value); @@ -1167,18 +1378,20 @@ bool AsmParser::ParseIdentifier(StringRef &Res) { } /// ParseDirectiveSet: +/// ::= .equ identifier ',' expression +/// ::= .equiv identifier ',' expression /// ::= .set identifier ',' expression -bool AsmParser::ParseDirectiveSet() { +bool AsmParser::ParseDirectiveSet(StringRef IDVal, bool allow_redef) { StringRef Name; if (ParseIdentifier(Name)) - return TokError("expected identifier after '.set' directive"); - + return TokError("expected identifier after '" + Twine(IDVal) + "'"); + if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '.set'"); + return TokError("unexpected token in '" + Twine(IDVal) + "'"); Lex(); - return ParseAssignment(Name); + return ParseAssignment(Name, allow_redef); } bool AsmParser::ParseEscapedString(std::string &Data) { @@ -1240,12 +1453,14 @@ bool AsmParser::ParseEscapedString(std::string &Data) { } /// ParseDirectiveAscii: -/// ::= ( .ascii | .asciz ) [ "string" ( , "string" )* ] -bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { +/// ::= ( .ascii | .asciz | .string ) [ "string" ( , "string" )* ] +bool AsmParser::ParseDirectiveAscii(StringRef IDVal, bool ZeroTerminated) { if (getLexer().isNot(AsmToken::EndOfStatement)) { + CheckForValidSection(); + for (;;) { if (getLexer().isNot(AsmToken::String)) - return TokError("expected string in '.ascii' or '.asciz' directive"); + return TokError("expected string in '" + Twine(IDVal) + "' directive"); std::string Data; if (ParseEscapedString(Data)) @@ -1261,7 +1476,7 @@ bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { break; if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '.ascii' or '.asciz' directive"); + return TokError("unexpected token in '" + Twine(IDVal) + "' directive"); Lex(); } } @@ -1274,9 +1489,10 @@ bool AsmParser::ParseDirectiveAscii(bool ZeroTerminated) { /// ::= (.byte | .short | ... ) [ expression (, expression)* ] bool AsmParser::ParseDirectiveValue(unsigned Size) { if (getLexer().isNot(AsmToken::EndOfStatement)) { + CheckForValidSection(); + for (;;) { const MCExpr *Value; - SMLoc ATTRIBUTE_UNUSED StartLoc = getLexer().getLoc(); if (ParseExpression(Value)) return true; @@ -1288,7 +1504,7 @@ bool AsmParser::ParseDirectiveValue(unsigned Size) { if (getLexer().is(AsmToken::EndOfStatement)) break; - + // FIXME: Improve diagnostic. if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in directive"); @@ -1300,9 +1516,61 @@ bool AsmParser::ParseDirectiveValue(unsigned Size) { return false; } +/// ParseDirectiveRealValue +/// ::= (.single | .double) [ expression (, expression)* ] +bool AsmParser::ParseDirectiveRealValue(const fltSemantics &Semantics) { + if (getLexer().isNot(AsmToken::EndOfStatement)) { + CheckForValidSection(); + + for (;;) { + // We don't truly support arithmetic on floating point expressions, so we + // have to manually parse unary prefixes. + bool IsNeg = false; + if (getLexer().is(AsmToken::Minus)) { + Lex(); + IsNeg = true; + } else if (getLexer().is(AsmToken::Plus)) + Lex(); + + if (getLexer().isNot(AsmToken::Integer) && + getLexer().isNot(AsmToken::Real)) + return TokError("unexpected token in directive"); + + // Convert to an APFloat. + APFloat Value(Semantics); + if (Value.convertFromString(getTok().getString(), + APFloat::rmNearestTiesToEven) == + APFloat::opInvalidOp) + return TokError("invalid floating point literal"); + if (IsNeg) + Value.changeSign(); + + // Consume the numeric token. + Lex(); + + // Emit the value as an integer. + APInt AsInt = Value.bitcastToAPInt(); + getStreamer().EmitIntValue(AsInt.getLimitedValue(), + AsInt.getBitWidth() / 8, DEFAULT_ADDRSPACE); + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + } + } + + Lex(); + return false; +} + /// ParseDirectiveSpace /// ::= .space expression [ , expression ] bool AsmParser::ParseDirectiveSpace() { + CheckForValidSection(); + int64_t NumBytes; if (ParseAbsoluteExpression(NumBytes)) return true; @@ -1312,7 +1580,7 @@ bool AsmParser::ParseDirectiveSpace() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.space' directive"); Lex(); - + if (ParseAbsoluteExpression(FillExpr)) return true; @@ -1331,9 +1599,37 @@ bool AsmParser::ParseDirectiveSpace() { return false; } +/// ParseDirectiveZero +/// ::= .zero expression +bool AsmParser::ParseDirectiveZero() { + CheckForValidSection(); + + int64_t NumBytes; + if (ParseAbsoluteExpression(NumBytes)) + return true; + + int64_t Val = 0; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + if (ParseAbsoluteExpression(Val)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in '.zero' directive"); + + Lex(); + + getStreamer().EmitFill(NumBytes, Val, DEFAULT_ADDRSPACE); + + return false; +} + /// ParseDirectiveFill /// ::= .fill expression , expression , expression bool AsmParser::ParseDirectiveFill() { + CheckForValidSection(); + int64_t NumValues; if (ParseAbsoluteExpression(NumValues)) return true; @@ -1341,7 +1637,7 @@ bool AsmParser::ParseDirectiveFill() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.fill' directive"); Lex(); - + int64_t FillSize; if (ParseAbsoluteExpression(FillSize)) return true; @@ -1349,14 +1645,14 @@ bool AsmParser::ParseDirectiveFill() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.fill' directive"); Lex(); - + int64_t FillExpr; if (ParseAbsoluteExpression(FillExpr)) return true; if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.fill' directive"); - + Lex(); if (FillSize != 1 && FillSize != 2 && FillSize != 4 && FillSize != 8) @@ -1371,6 +1667,8 @@ bool AsmParser::ParseDirectiveFill() { /// ParseDirectiveOrg /// ::= .org expression [ , expression ] bool AsmParser::ParseDirectiveOrg() { + CheckForValidSection(); + const MCExpr *Offset; if (ParseExpression(Offset)) return true; @@ -1381,7 +1679,7 @@ bool AsmParser::ParseDirectiveOrg() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.org' directive"); Lex(); - + if (ParseAbsoluteExpression(FillExpr)) return true; @@ -1401,6 +1699,8 @@ bool AsmParser::ParseDirectiveOrg() { /// ParseDirectiveAlign /// ::= {.align, ...} expression [ , expression [ , expression ]] bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { + CheckForValidSection(); + SMLoc AlignmentLoc = getLexer().getLoc(); int64_t Alignment; if (ParseAbsoluteExpression(Alignment)) @@ -1432,7 +1732,7 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { MaxBytesLoc = getLexer().getLoc(); if (ParseAbsoluteExpression(MaxBytesToFill)) return true; - + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in directive"); } @@ -1471,12 +1771,7 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { // Check whether we should use optimal code alignment for this .align // directive. - // - // FIXME: This should be using a target hook. - bool UseCodeAlign = false; - if (const MCSectionMachO *S = dyn_cast<MCSectionMachO>( - getStreamer().getCurrentSection())) - UseCodeAlign = S->hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); + bool UseCodeAlign = getStreamer().getCurrentSection()->UseCodeAlign(); if ((!HasFillExpr || Lexer.getMAI().getTextAlignFillValue() == FillExpr) && ValueSize == 1 && UseCodeAlign) { getStreamer().EmitCodeAlignment(Alignment, MaxBytesToFill); @@ -1498,7 +1793,7 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { if (ParseIdentifier(Name)) return TokError("expected identifier in directive"); - + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); getStreamer().EmitSymbolAttribute(Sym, Attr); @@ -1513,63 +1808,19 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { } Lex(); - return false; -} - -/// ParseDirectiveELFType -/// ::= .type identifier , @attribute -bool AsmParser::ParseDirectiveELFType() { - StringRef Name; - if (ParseIdentifier(Name)) - return TokError("expected identifier in directive"); - - // Handle the identifier as the key symbol. - MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); - - if (getLexer().isNot(AsmToken::Comma)) - return TokError("unexpected token in '.type' directive"); - Lex(); - - if (getLexer().isNot(AsmToken::At)) - return TokError("expected '@' before type"); - Lex(); - - StringRef Type; - SMLoc TypeLoc; - - TypeLoc = getLexer().getLoc(); - if (ParseIdentifier(Type)) - return TokError("expected symbol type in directive"); - - MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Type) - .Case("function", MCSA_ELF_TypeFunction) - .Case("object", MCSA_ELF_TypeObject) - .Case("tls_object", MCSA_ELF_TypeTLS) - .Case("common", MCSA_ELF_TypeCommon) - .Case("notype", MCSA_ELF_TypeNoType) - .Default(MCSA_Invalid); - - if (Attr == MCSA_Invalid) - return Error(TypeLoc, "unsupported attribute in '.type' directive"); - - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in '.type' directive"); - - Lex(); - - getStreamer().EmitSymbolAttribute(Sym, Attr); - return false; } /// ParseDirectiveComm /// ::= ( .comm | .lcomm ) identifier , size_expression [ , align_expression ] bool AsmParser::ParseDirectiveComm(bool IsLocal) { + CheckForValidSection(); + SMLoc IDLoc = getLexer().getLoc(); StringRef Name; if (ParseIdentifier(Name)) return TokError("expected identifier in directive"); - + // Handle the identifier as the key symbol. MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); @@ -1589,7 +1840,7 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { Pow2AlignmentLoc = getLexer().getLoc(); if (ParseAbsoluteExpression(Pow2Alignment)) return true; - + // If this target takes alignments in bytes (not log) validate and convert. if (Lexer.getMAI().getAlignmentIsInBytes()) { if (!isPowerOf2_64(Pow2Alignment)) @@ -1597,10 +1848,10 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { Pow2Alignment = Log2_64(Pow2Alignment); } } - + if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.comm' or '.lcomm' directive"); - + Lex(); // NOTE: a size of zero for a .comm should create a undefined symbol @@ -1659,17 +1910,17 @@ bool AsmParser::ParseDirectiveAbort() { bool AsmParser::ParseDirectiveInclude() { if (getLexer().isNot(AsmToken::String)) return TokError("expected string in '.include' directive"); - + std::string Filename = getTok().getString(); SMLoc IncludeLoc = getLexer().getLoc(); Lex(); if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.include' directive"); - + // Strip the quotes. Filename = Filename.substr(1, Filename.size()-2); - + // 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)) { @@ -1695,7 +1946,7 @@ bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.if' directive"); - + Lex(); TheCondState.CondMet = ExprValue; @@ -1705,6 +1956,31 @@ bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { return false; } +bool AsmParser::ParseDirectiveIfdef(SMLoc DirectiveLoc, bool expect_defined) { + StringRef Name; + TheCondStack.push_back(TheCondState); + TheCondState.TheCond = AsmCond::IfCond; + + if (TheCondState.Ignore) { + EatToEndOfStatement(); + } else { + if (ParseIdentifier(Name)) + return TokError("expected identifier after '.ifdef'"); + + Lex(); + + MCSymbol *Sym = getContext().LookupSymbol(Name); + + if (expect_defined) + TheCondState.CondMet = (Sym != NULL && !Sym->isUndefined()); + else + TheCondState.CondMet = (Sym == NULL || Sym->isUndefined()); + TheCondState.Ignore = !TheCondState.CondMet; + } + + return false; +} + /// ParseDirectiveElseIf /// ::= .elseif expression bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { @@ -1728,7 +2004,7 @@ bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.elseif' directive"); - + Lex(); TheCondState.CondMet = ExprValue; TheCondState.Ignore = !TheCondState.CondMet; @@ -1742,7 +2018,7 @@ bool AsmParser::ParseDirectiveElseIf(SMLoc DirectiveLoc) { bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.else' directive"); - + Lex(); if (TheCondState.TheCond != AsmCond::IfCond && @@ -1766,7 +2042,7 @@ bool AsmParser::ParseDirectiveElse(SMLoc DirectiveLoc) { bool AsmParser::ParseDirectiveEndIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.endif' directive"); - + Lex(); if ((TheCondState.TheCond == AsmCond::NoCond) || @@ -1808,9 +2084,8 @@ bool GenericAsmParser::ParseDirectiveFile(StringRef, SMLoc DirectiveLoc) { if (FileNumber == -1) getStreamer().EmitFileDirective(Filename); else { - if (getContext().GetDwarfFile(Filename, FileNumber) == 0) - Error(FileNumberLoc, "file number already allocated"); - getStreamer().EmitDwarfFileDirective(FileNumber, Filename); + if (getStreamer().EmitDwarfFileDirective(FileNumber, Filename)) + Error(FileNumberLoc, "file number already allocated"); } return false; @@ -1851,7 +2126,7 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { int64_t FileNumber = getTok().getIntVal(); if (FileNumber < 1) return TokError("file number less than one in '.loc' directive"); - if (!getContext().ValidateDwarfFileNumber(FileNumber)) + if (!getContext().isValidDwarfFileNumber(FileNumber)) return TokError("unassigned file number in '.loc' directive"); Lex(); @@ -1871,8 +2146,9 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { Lex(); } - unsigned Flags = 0; + unsigned Flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0; unsigned Isa = 0; + int64_t Discriminator = 0; if (getLexer().isNot(AsmToken::EndOfStatement)) { for (;;) { if (getLexer().is(AsmToken::EndOfStatement)) @@ -1903,7 +2179,7 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { 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"); } @@ -1919,11 +2195,15 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { if (Value < 0) return Error(Loc, "isa number less than zero"); Isa = Value; - } + } else { return Error(Loc, "isa number not a constant value"); } } + else if (Name == "discriminator") { + if (getParser().ParseAbsoluteExpression(Discriminator)) + return true; + } else { return Error(Loc, "unknown sub-directive in '.loc' directive"); } @@ -1933,11 +2213,176 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { } } - getContext().setCurrentDwarfLoc(FileNumber, LineNumber, ColumnPos, Flags,Isa); + getStreamer().EmitDwarfLocDirective(FileNumber, LineNumber, ColumnPos, Flags, + Isa, Discriminator); return false; } +/// ParseDirectiveStabs +/// ::= .stabs string, number, number, number +bool GenericAsmParser::ParseDirectiveStabs(StringRef Directive, + SMLoc DirectiveLoc) { + return TokError("unsupported directive '" + Directive + "'"); +} + +/// ParseDirectiveCFIStartProc +/// ::= .cfi_startproc +bool GenericAsmParser::ParseDirectiveCFIStartProc(StringRef, + SMLoc DirectiveLoc) { + return getStreamer().EmitCFIStartProc(); +} + +/// ParseDirectiveCFIEndProc +/// ::= .cfi_endproc +bool GenericAsmParser::ParseDirectiveCFIEndProc(StringRef, SMLoc DirectiveLoc) { + return getStreamer().EmitCFIEndProc(); +} + +/// ParseRegisterOrRegisterNumber - parse register name or number. +bool GenericAsmParser::ParseRegisterOrRegisterNumber(int64_t &Register, + SMLoc DirectiveLoc) { + unsigned RegNo; + + if (getLexer().is(AsmToken::Percent)) { + if (getParser().getTargetParser().ParseRegister(RegNo, DirectiveLoc, + DirectiveLoc)) + return true; + Register = getContext().getTargetAsmInfo().getDwarfRegNum(RegNo, true); + } else + return getParser().ParseAbsoluteExpression(Register); + + return false; +} + +/// ParseDirectiveCFIDefCfa +/// ::= .cfi_def_cfa register, offset +bool GenericAsmParser::ParseDirectiveCFIDefCfa(StringRef, + SMLoc DirectiveLoc) { + int64_t Register = 0; + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + int64_t Offset = 0; + if (getParser().ParseAbsoluteExpression(Offset)) + return true; + + return getStreamer().EmitCFIDefCfa(Register, Offset); +} + +/// ParseDirectiveCFIDefCfaOffset +/// ::= .cfi_def_cfa_offset offset +bool GenericAsmParser::ParseDirectiveCFIDefCfaOffset(StringRef, + SMLoc DirectiveLoc) { + int64_t Offset = 0; + if (getParser().ParseAbsoluteExpression(Offset)) + return true; + + return getStreamer().EmitCFIDefCfaOffset(Offset); +} + +/// ParseDirectiveCFIDefCfaRegister +/// ::= .cfi_def_cfa_register register +bool GenericAsmParser::ParseDirectiveCFIDefCfaRegister(StringRef, + SMLoc DirectiveLoc) { + int64_t Register = 0; + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + return getStreamer().EmitCFIDefCfaRegister(Register); +} + +/// ParseDirectiveCFIOffset +/// ::= .cfi_off register, offset +bool GenericAsmParser::ParseDirectiveCFIOffset(StringRef, SMLoc DirectiveLoc) { + int64_t Register = 0; + int64_t Offset = 0; + + if (ParseRegisterOrRegisterNumber(Register, DirectiveLoc)) + return true; + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + if (getParser().ParseAbsoluteExpression(Offset)) + return true; + + return getStreamer().EmitCFIOffset(Register, Offset); +} + +static bool isValidEncoding(int64_t Encoding) { + if (Encoding & ~0xff) + return false; + + if (Encoding == dwarf::DW_EH_PE_omit) + return true; + + const unsigned Format = Encoding & 0xf; + if (Format != dwarf::DW_EH_PE_absptr && Format != dwarf::DW_EH_PE_udata2 && + Format != dwarf::DW_EH_PE_udata4 && Format != dwarf::DW_EH_PE_udata8 && + Format != dwarf::DW_EH_PE_sdata2 && Format != dwarf::DW_EH_PE_sdata4 && + Format != dwarf::DW_EH_PE_sdata8 && Format != dwarf::DW_EH_PE_signed) + return false; + + const unsigned Application = Encoding & 0x70; + if (Application != dwarf::DW_EH_PE_absptr && + Application != dwarf::DW_EH_PE_pcrel) + return false; + + return true; +} + +/// ParseDirectiveCFIPersonalityOrLsda +/// ::= .cfi_personality encoding, [symbol_name] +/// ::= .cfi_lsda encoding, [symbol_name] +bool GenericAsmParser::ParseDirectiveCFIPersonalityOrLsda(StringRef IDVal, + SMLoc DirectiveLoc) { + int64_t Encoding = 0; + if (getParser().ParseAbsoluteExpression(Encoding)) + return true; + if (Encoding == dwarf::DW_EH_PE_omit) + return false; + + if (!isValidEncoding(Encoding)) + return TokError("unsupported encoding."); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in directive"); + Lex(); + + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + if (IDVal == ".cfi_personality") + return getStreamer().EmitCFIPersonality(Sym, Encoding); + else { + assert(IDVal == ".cfi_lsda"); + return getStreamer().EmitCFILsda(Sym, Encoding); + } +} + +/// ParseDirectiveCFIRememberState +/// ::= .cfi_remember_state +bool GenericAsmParser::ParseDirectiveCFIRememberState(StringRef IDVal, + SMLoc DirectiveLoc) { + return getStreamer().EmitCFIRememberState(); +} + +/// ParseDirectiveCFIRestoreState +/// ::= .cfi_remember_state +bool GenericAsmParser::ParseDirectiveCFIRestoreState(StringRef IDVal, + SMLoc DirectiveLoc) { + return getStreamer().EmitCFIRestoreState(); +} + /// ParseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off @@ -2022,6 +2467,26 @@ bool GenericAsmParser::ParseDirectiveEndMacro(StringRef Directive, "no current macro definition"); } +bool GenericAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { + getParser().CheckForValidSection(); + + const MCExpr *Value; + + if (getParser().ParseExpression(Value)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + if (DirName[1] == 's') + getStreamer().EmitSLEB128Value(Value); + else + getStreamer().EmitULEB128Value(Value); + + return false; +} + + /// \brief Create an MCAsmParser instance. MCAsmParser *llvm::createMCAsmParser(const Target &T, SourceMgr &SM, MCContext &C, MCStreamer &Out, diff --git a/lib/MC/MCParser/CMakeLists.txt b/lib/MC/MCParser/CMakeLists.txt index 25a7bf4..eaea9f6 100644 --- a/lib/MC/MCParser/CMakeLists.txt +++ b/lib/MC/MCParser/CMakeLists.txt @@ -1,6 +1,7 @@ add_llvm_library(LLVMMCParser AsmLexer.cpp AsmParser.cpp + COFFAsmParser.cpp DarwinAsmParser.cpp ELFAsmParser.cpp MCAsmLexer.cpp diff --git a/lib/MC/MCParser/COFFAsmParser.cpp b/lib/MC/MCParser/COFFAsmParser.cpp new file mode 100644 index 0000000..5ecab03 --- /dev/null +++ b/lib/MC/MCParser/COFFAsmParser.cpp @@ -0,0 +1,144 @@ +//===- COFFAsmParser.cpp - COFF Assembly Parser ---------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/Twine.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCParser/MCAsmLexer.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/Support/COFF.h" +using namespace llvm; + +namespace { + +class COFFAsmParser : public MCAsmParserExtension { + template<bool (COFFAsmParser::*Handler)(StringRef, SMLoc)> + void AddDirectiveHandler(StringRef Directive) { + getParser().AddDirectiveHandler(this, Directive, + HandleDirective<COFFAsmParser, Handler>); + } + + bool ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind); + + virtual void Initialize(MCAsmParser &Parser) { + // Call the base implementation. + MCAsmParserExtension::Initialize(Parser); + + AddDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveText>(".text"); + AddDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveData>(".data"); + AddDirectiveHandler<&COFFAsmParser::ParseSectionDirectiveBSS>(".bss"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveDef>(".def"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveScl>(".scl"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveType>(".type"); + AddDirectiveHandler<&COFFAsmParser::ParseDirectiveEndef>(".endef"); + } + + bool ParseSectionDirectiveText(StringRef, SMLoc) { + return ParseSectionSwitch(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + } + bool ParseSectionDirectiveData(StringRef, SMLoc) { + return ParseSectionSwitch(".data", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + } + bool ParseSectionDirectiveBSS(StringRef, SMLoc) { + return ParseSectionSwitch(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + } + + bool ParseDirectiveDef(StringRef, SMLoc); + bool ParseDirectiveScl(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveEndef(StringRef, SMLoc); + +public: + COFFAsmParser() {} +}; + +} // end annonomous namespace. + +bool COFFAsmParser::ParseSectionSwitch(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in section switching directive"); + Lex(); + + getStreamer().SwitchSection(getContext().getCOFFSection( + Section, Characteristics, Kind)); + + return false; +} + +bool COFFAsmParser::ParseDirectiveDef(StringRef, SMLoc) { + StringRef SymbolName; + + if (getParser().ParseIdentifier(SymbolName)) + return TokError("expected identifier in directive"); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(SymbolName); + + getStreamer().BeginCOFFSymbolDef(Sym); + + Lex(); + return false; +} + +bool COFFAsmParser::ParseDirectiveScl(StringRef, SMLoc) { + int64_t SymbolStorageClass; + if (getParser().ParseAbsoluteExpression(SymbolStorageClass)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolStorageClass(SymbolStorageClass); + return false; +} + +bool COFFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + int64_t Type; + if (getParser().ParseAbsoluteExpression(Type)) + return true; + + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + Lex(); + getStreamer().EmitCOFFSymbolType(Type); + return false; +} + +bool COFFAsmParser::ParseDirectiveEndef(StringRef, SMLoc) { + Lex(); + getStreamer().EndCOFFSymbolDef(); + return false; +} + +namespace llvm { + +MCAsmParserExtension *createCOFFAsmParser() { + return new COFFAsmParser; +} + +} diff --git a/lib/MC/MCParser/DarwinAsmParser.cpp b/lib/MC/MCParser/DarwinAsmParser.cpp index 54ddb44..44f2345 100644 --- a/lib/MC/MCParser/DarwinAsmParser.cpp +++ b/lib/MC/MCParser/DarwinAsmParser.cpp @@ -305,7 +305,7 @@ bool DarwinAsmParser::ParseSectionSwitch(const char *Segment, // // FIXME: This isn't really what 'as' does; I think it just uses the implicit // alignment on the section (e.g., if one manually inserts bytes into the - // section, then just issueing the section switch directive will not realign + // section, then just issuing the section switch directive will not realign // the section. However, this is arguably more reasonable behavior, and there // is no good reason for someone to intentionally emit incorrectly sized // values into the implicitly aligned sections. diff --git a/lib/MC/MCParser/ELFAsmParser.cpp b/lib/MC/MCParser/ELFAsmParser.cpp index f982fda..bfaf36a 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -8,13 +8,15 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCParser/MCAsmParserExtension.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCParser/MCAsmLexer.h" #include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/ADT/Twine.h" +#include "llvm/Support/ELF.h" using namespace llvm; namespace { @@ -47,72 +49,86 @@ public: AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveDataRelRoLocal>(".data.rel.ro.local"); AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePushSection>(".pushsection"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePopSection>(".popsection"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); - AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".sleb128"); - AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".uleb128"); AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveType>(".type"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveIdent>(".ident"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSymver>(".symver"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectiveWeakref>(".weakref"); } + // FIXME: Part of this logic is duplicated in the MCELFStreamer. What is + // the best way for us to get access to it? bool ParseSectionDirectiveData(StringRef, SMLoc) { - return ParseSectionSwitch(".data", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + return ParseSectionSwitch(".data", ELF::SHT_PROGBITS, + ELF::SHF_WRITE |ELF::SHF_ALLOC, SectionKind::getDataRel()); } bool ParseSectionDirectiveText(StringRef, SMLoc) { - return ParseSectionSwitch(".text", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_EXECINSTR | - MCSectionELF::SHF_ALLOC, SectionKind::getText()); + return ParseSectionSwitch(".text", ELF::SHT_PROGBITS, + ELF::SHF_EXECINSTR | + ELF::SHF_ALLOC, SectionKind::getText()); } bool ParseSectionDirectiveBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".bss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_WRITE | - MCSectionELF::SHF_ALLOC, SectionKind::getBSS()); + return ParseSectionSwitch(".bss", ELF::SHT_NOBITS, + ELF::SHF_WRITE | + ELF::SHF_ALLOC, SectionKind::getBSS()); } bool ParseSectionDirectiveRoData(StringRef, SMLoc) { - return ParseSectionSwitch(".rodata", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC, + return ParseSectionSwitch(".rodata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC, SectionKind::getReadOnly()); } bool ParseSectionDirectiveTData(StringRef, SMLoc) { - return ParseSectionSwitch(".tdata", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".tdata", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_TLS | ELF::SHF_WRITE, SectionKind::getThreadData()); } bool ParseSectionDirectiveTBSS(StringRef, SMLoc) { - return ParseSectionSwitch(".tbss", MCSectionELF::SHT_NOBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_TLS | MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".tbss", ELF::SHT_NOBITS, + ELF::SHF_ALLOC | + ELF::SHF_TLS | ELF::SHF_WRITE, SectionKind::getThreadBSS()); } bool ParseSectionDirectiveDataRel(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".data.rel", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getDataRel()); } bool ParseSectionDirectiveDataRelRo(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel.ro", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".data.rel.ro", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getReadOnlyWithRel()); } bool ParseSectionDirectiveDataRelRoLocal(StringRef, SMLoc) { - return ParseSectionSwitch(".data.rel.ro.local", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".data.rel.ro.local", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getReadOnlyWithRelLocal()); } bool ParseSectionDirectiveEhFrame(StringRef, SMLoc) { - return ParseSectionSwitch(".eh_frame", MCSectionELF::SHT_PROGBITS, - MCSectionELF::SHF_ALLOC | - MCSectionELF::SHF_WRITE, + return ParseSectionSwitch(".eh_frame", ELF::SHT_PROGBITS, + ELF::SHF_ALLOC | + ELF::SHF_WRITE, SectionKind::getDataRel()); } - bool ParseDirectiveLEB128(StringRef, SMLoc); + bool ParseDirectivePushSection(StringRef, SMLoc); + bool ParseDirectivePopSection(StringRef, SMLoc); bool ParseDirectiveSection(StringRef, SMLoc); bool ParseDirectiveSize(StringRef, SMLoc); bool ParseDirectivePrevious(StringRef, SMLoc); + bool ParseDirectiveType(StringRef, SMLoc); + bool ParseDirectiveIdent(StringRef, SMLoc); + bool ParseDirectiveSymver(StringRef, SMLoc); + bool ParseDirectiveWeakref(StringRef, SMLoc); + +private: + bool ParseSectionName(StringRef &SectionName); }; } @@ -150,135 +166,359 @@ bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { 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"); +bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { + // A section name can contain -, so we cannot just use + // ParseIdentifier. + SMLoc FirstLoc = getLexer().getLoc(); + unsigned Size = 0; - FlagsStr = getTok().getStringContents(); + if (getLexer().is(AsmToken::String)) { + SectionName = getTok().getIdentifier(); Lex(); + return false; + } - AsmToken::TokenKind TypeStartToken; - if (getContext().getAsmInfo().getCommentString()[0] == '@') - TypeStartToken = AsmToken::Percent; - else - TypeStartToken = AsmToken::At; + for (;;) { + StringRef Tmp; + unsigned CurSize; - if (getLexer().is(AsmToken::Comma)) { + SMLoc PrevLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Minus)) { + CurSize = 1; + Lex(); // Consume the "-". + } else if (getLexer().is(AsmToken::String)) { + CurSize = getTok().getIdentifier().size() + 2; Lex(); - if (getLexer().is(TypeStartToken)) { - Lex(); - if (getParser().ParseIdentifier(TypeName)) - return TokError("expected identifier in directive"); - - if (getLexer().is(AsmToken::Comma)) { - Lex(); + } else if (getLexer().is(AsmToken::Identifier)) { + CurSize = getTok().getIdentifier().size(); + Lex(); + } else { + break; + } - if (getParser().ParseAbsoluteExpression(Size)) - return true; + Size += CurSize; + SectionName = StringRef(FirstLoc.getPointer(), Size); - if (Size <= 0) - return TokError("section size must be positive"); - } - } - } + // Make sure the following token is adjacent. + if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) + break; } + if (Size == 0) + return true; - if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); + return false; +} - unsigned Flags = 0; - for (unsigned i = 0; i < FlagsStr.size(); i++) { - switch (FlagsStr[i]) { +static SectionKind computeSectionKind(unsigned Flags) { + if (Flags & ELF::SHF_EXECINSTR) + return SectionKind::getText(); + if (Flags & ELF::SHF_TLS) + return SectionKind::getThreadData(); + return SectionKind::getDataRel(); +} + +static int parseSectionFlags(StringRef flagsStr) { + int flags = 0; + + for (unsigned i = 0; i < flagsStr.size(); i++) { + switch (flagsStr[i]) { case 'a': - Flags |= MCSectionELF::SHF_ALLOC; + flags |= ELF::SHF_ALLOC; break; case 'x': - Flags |= MCSectionELF::SHF_EXECINSTR; + flags |= ELF::SHF_EXECINSTR; break; case 'w': - Flags |= MCSectionELF::SHF_WRITE; + flags |= ELF::SHF_WRITE; break; case 'M': - Flags |= MCSectionELF::SHF_MERGE; + flags |= ELF::SHF_MERGE; break; case 'S': - Flags |= MCSectionELF::SHF_STRINGS; + flags |= ELF::SHF_STRINGS; break; case 'T': - Flags |= MCSectionELF::SHF_TLS; + flags |= ELF::SHF_TLS; break; case 'c': - Flags |= MCSectionELF::XCORE_SHF_CP_SECTION; + flags |= ELF::XCORE_SHF_CP_SECTION; break; case 'd': - Flags |= MCSectionELF::XCORE_SHF_DP_SECTION; + flags |= ELF::XCORE_SHF_DP_SECTION; + break; + case 'G': + flags |= ELF::SHF_GROUP; break; default: + return -1; + } + } + + return flags; +} + +bool ELFAsmParser::ParseDirectivePushSection(StringRef s, SMLoc loc) { + getStreamer().PushSection(); + + if (ParseDirectiveSection(s, loc)) { + getStreamer().PopSection(); + return true; + } + + return false; +} + +bool ELFAsmParser::ParseDirectivePopSection(StringRef, SMLoc) { + if (!getStreamer().PopSection()) + return TokError(".popsection without corresponding .pushsection"); + return false; +} + +// FIXME: This is a work in progress. +bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { + StringRef SectionName; + + if (ParseSectionName(SectionName)) + return TokError("expected identifier in directive"); + + StringRef TypeName; + int64_t Size = 0; + StringRef GroupName; + unsigned Flags = 0; + + // Set the defaults first. + if (SectionName == ".fini" || SectionName == ".init" || + SectionName == ".rodata") + Flags |= ELF::SHF_ALLOC; + if (SectionName == ".fini" || SectionName == ".init") + Flags |= ELF::SHF_EXECINSTR; + + if (getLexer().is(AsmToken::Comma)) { + Lex(); + + if (getLexer().isNot(AsmToken::String)) + return TokError("expected string in directive"); + + StringRef FlagsStr = getTok().getStringContents(); + Lex(); + + int extraFlags = parseSectionFlags(FlagsStr); + if (extraFlags < 0) return TokError("unknown flag"); + Flags |= extraFlags; + + bool Mergeable = Flags & ELF::SHF_MERGE; + bool Group = Flags & ELF::SHF_GROUP; + + if (getLexer().isNot(AsmToken::Comma)) { + if (Mergeable) + return TokError("Mergeable section must specify the type"); + if (Group) + return TokError("Group section must specify the type"); + } else { + Lex(); + if (getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::At)) + return TokError("expected '@' or '%' before type"); + + Lex(); + if (getParser().ParseIdentifier(TypeName)) + return TokError("expected identifier in directive"); + + if (Mergeable) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected the entry size"); + Lex(); + if (getParser().ParseAbsoluteExpression(Size)) + return true; + if (Size <= 0) + return TokError("entry size must be positive"); + } + + if (Group) { + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected group name"); + Lex(); + if (getParser().ParseIdentifier(GroupName)) + return true; + if (getLexer().is(AsmToken::Comma)) { + Lex(); + StringRef Linkage; + if (getParser().ParseIdentifier(Linkage)) + return true; + if (Linkage != "comdat") + return TokError("Linkage must be 'comdat'"); + } + } } } - unsigned Type = MCSectionELF::SHT_NULL; + if (getLexer().isNot(AsmToken::EndOfStatement)) + return TokError("unexpected token in directive"); + + unsigned Type = ELF::SHT_PROGBITS; + if (!TypeName.empty()) { if (TypeName == "init_array") - Type = MCSectionELF::SHT_INIT_ARRAY; + Type = ELF::SHT_INIT_ARRAY; else if (TypeName == "fini_array") - Type = MCSectionELF::SHT_FINI_ARRAY; + Type = ELF::SHT_FINI_ARRAY; else if (TypeName == "preinit_array") - Type = MCSectionELF::SHT_PREINIT_ARRAY; + Type = ELF::SHT_PREINIT_ARRAY; else if (TypeName == "nobits") - Type = MCSectionELF::SHT_NOBITS; + Type = ELF::SHT_NOBITS; else if (TypeName == "progbits") - Type = MCSectionELF::SHT_PROGBITS; + Type = ELF::SHT_PROGBITS; + else if (TypeName == "note") + Type = ELF::SHT_NOTE; + else if (TypeName == "unwind") + Type = ELF::SHT_X86_64_UNWIND; else return TokError("unknown section type"); } - SectionKind Kind = (Flags & MCSectionELF::SHF_EXECINSTR) - ? SectionKind::getText() - : SectionKind::getDataRel(); + SectionKind Kind = computeSectionKind(Flags); getStreamer().SwitchSection(getContext().getELFSection(SectionName, Type, - Flags, Kind, false)); + Flags, Kind, Size, + GroupName)); return false; } -bool ELFAsmParser::ParseDirectiveLEB128(StringRef DirName, SMLoc) { - int64_t Value; - if (getParser().ParseAbsoluteExpression(Value)) - return true; +bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { + const MCSection *PreviousSection = getStreamer().getPreviousSection(); + if (PreviousSection == NULL) + return TokError(".previous without corresponding .section"); + getStreamer().SwitchSection(PreviousSection); + + return false; +} + +/// ParseDirectiveELFType +/// ::= .type identifier , @attribute +bool ELFAsmParser::ParseDirectiveType(StringRef, SMLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + // Handle the identifier as the key symbol. + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("unexpected token in '.type' directive"); + Lex(); + + if (getLexer().isNot(AsmToken::Percent) && getLexer().isNot(AsmToken::At)) + return TokError("expected '@' or '%' before type"); + Lex(); + + StringRef Type; + SMLoc TypeLoc; + + TypeLoc = getLexer().getLoc(); + if (getParser().ParseIdentifier(Type)) + return TokError("expected symbol type in directive"); + + MCSymbolAttr Attr = StringSwitch<MCSymbolAttr>(Type) + .Case("function", MCSA_ELF_TypeFunction) + .Case("object", MCSA_ELF_TypeObject) + .Case("tls_object", MCSA_ELF_TypeTLS) + .Case("common", MCSA_ELF_TypeCommon) + .Case("notype", MCSA_ELF_TypeNoType) + .Case("gnu_unique_object", MCSA_ELF_TypeGnuUniqueObject) + .Default(MCSA_Invalid); + + if (Attr == MCSA_Invalid) + return Error(TypeLoc, "unsupported attribute in '.type' directive"); if (getLexer().isNot(AsmToken::EndOfStatement)) - return TokError("unexpected token in directive"); + return TokError("unexpected token in '.type' 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"); + Lex(); + + getStreamer().EmitSymbolAttribute(Sym, Attr); + + return false; } -bool ELFAsmParser::ParseDirectivePrevious(StringRef DirName, SMLoc) { - const MCSection *PreviousSection = getStreamer().getPreviousSection(); - if (PreviousSection != NULL) - getStreamer().SwitchSection(PreviousSection); +/// ParseDirectiveIdent +/// ::= .ident string +bool ELFAsmParser::ParseDirectiveIdent(StringRef, SMLoc) { + if (getLexer().isNot(AsmToken::String)) + return TokError("unexpected token in '.ident' directive"); + + StringRef Data = getTok().getIdentifier(); + + Lex(); + + const MCSection *Comment = + getContext().getELFSection(".comment", ELF::SHT_PROGBITS, + ELF::SHF_MERGE | + ELF::SHF_STRINGS, + SectionKind::getReadOnly(), + 1, ""); + + static bool First = true; + + getStreamer().PushSection(); + getStreamer().SwitchSection(Comment); + if (First) + getStreamer().EmitIntValue(0, 1); + First = false; + getStreamer().EmitBytes(Data, 0); + getStreamer().EmitIntValue(0, 1); + getStreamer().PopSection(); + return false; +} + +/// ParseDirectiveSymver +/// ::= .symver foo, bar2@zed +bool ELFAsmParser::ParseDirectiveSymver(StringRef, SMLoc) { + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef AliasName; + if (getParser().ParseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (AliasName.find('@') == StringRef::npos) + return TokError("expected a '@' in the name"); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + const MCExpr *Value = MCSymbolRefExpr::Create(Sym, getContext()); + + getStreamer().EmitAssignment(Alias, Value); + return false; +} + +/// ParseDirectiveWeakref +/// ::= .weakref foo, bar +bool ELFAsmParser::ParseDirectiveWeakref(StringRef, SMLoc) { + // FIXME: Share code with the other alias building directives. + + StringRef AliasName; + if (getParser().ParseIdentifier(AliasName)) + return TokError("expected identifier in directive"); + + if (getLexer().isNot(AsmToken::Comma)) + return TokError("expected a comma"); + + Lex(); + + StringRef Name; + if (getParser().ParseIdentifier(Name)) + return TokError("expected identifier in directive"); + + MCSymbol *Alias = getContext().GetOrCreateSymbol(AliasName); + + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); + getStreamer().EmitWeakReference(Alias, Sym); return false; } diff --git a/lib/MC/MCPureStreamer.cpp b/lib/MC/MCPureStreamer.cpp new file mode 100644 index 0000000..6098e6b --- /dev/null +++ b/lib/MC/MCPureStreamer.cpp @@ -0,0 +1,234 @@ +//===- lib/MC/MCPureStreamer.cpp - MC "Pure" Object Output ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectStreamer.h" +// FIXME: Remove this. +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { + +class MCPureStreamer : public MCObjectStreamer { +private: + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); + +public: + MCPureStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *Emitter) + : MCObjectStreamer(Context, TAB, OS, Emitter) {} + + /// @name MCStreamer Interface + /// @{ + + virtual void InitSections(); + virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0); + virtual void EmitBytes(StringRef Data, unsigned AddrSpace); + 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 Finish(); + + + virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitAssemblerFlag(MCAssemblerFlag Flag) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment = 0) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, + unsigned ByteAlignment) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitThumbFunc(MCSymbol *Func) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void BeginCOFFSymbolDef(const MCSymbol *Symbol) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCOFFSymbolStorageClass(int StorageClass) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitCOFFSymbolType(int Type) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EndCOFFSymbolDef() { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual void EmitFileDirective(StringRef Filename) { + report_fatal_error("unsupported directive in pure streamer"); + } + virtual bool EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { + report_fatal_error("unsupported directive in pure streamer"); + return false; + } + + /// @} +}; + +} // end anonymous namespace. + +void MCPureStreamer::InitSections() { + // FIMXE: To what!? + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + +} + +void MCPureStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); + assert(getCurrentSection() && "Cannot emit before setting section!"); + + Symbol->setSection(*getCurrentSection()); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + // We have to create a new fragment if this is an atom defining symbol, + // fragments cannot span atoms. + if (getAssembler().isSymbolLinkerVisible(SD.getSymbol())) + new MCDataFragment(getCurrentSectionData()); + + // FIXME: This is wasteful, we don't necessarily need to create a data + // fragment. Instead, we should mark the symbol as pointing into the data + // fragment if it exists, otherwise we should just queue the label and set its + // fragment pointer when we emit the next fragment. + MCDataFragment *F = getOrCreateDataFragment(); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); +} + +void MCPureStreamer::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 MCPureStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + unsigned Size, unsigned ByteAlignment) { + report_fatal_error("not yet implemented in pure streamer"); +} + +void MCPureStreamer::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 MCPureStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, unsigned ValueSize, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + 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 MCPureStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, + getCurrentSectionData()); + F->setEmitNops(true); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > getCurrentSectionData()->getAlignment()) + getCurrentSectionData()->setAlignment(ByteAlignment); +} + +void MCPureStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + new MCOrgFragment(*Offset, Value, getCurrentSectionData()); +} + +void MCPureStreamer::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 MCPureStreamer::EmitInstToData(const MCInst &Inst) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); + VecOS.flush(); + + // Add the fixups and data. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); + DF->addFixup(Fixups[i]); + } + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCPureStreamer::Finish() { + // FIXME: Handle DWARF tables? + + this->MCObjectStreamer::Finish(); +} + +MCStreamer *llvm::createPureStreamer(MCContext &Context, TargetAsmBackend &TAB, + raw_ostream &OS, MCCodeEmitter *CE) { + return new MCPureStreamer(Context, TAB, OS, CE); +} diff --git a/lib/MC/MCSectionCOFF.cpp b/lib/MC/MCSectionCOFF.cpp index eb53160..90091f0 100644 --- a/lib/MC/MCSectionCOFF.cpp +++ b/lib/MC/MCSectionCOFF.cpp @@ -74,3 +74,11 @@ void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, } } } + +bool MCSectionCOFF::UseCodeAlign() const { + return getKind().isText(); +} + +bool MCSectionCOFF::isVirtualSection() const { + return getCharacteristics() & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA; +} diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index a7599de..d32aea1 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -11,7 +11,9 @@ #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ELF.h" #include "llvm/Support/raw_ostream.h" + using namespace llvm; MCSectionELF::~MCSectionELF() {} // anchor. @@ -29,14 +31,6 @@ bool MCSectionELF::ShouldOmitSectionDirective(StringRef Name, return false; } -// ShouldPrintSectionType - Only prints the section type if supported -bool MCSectionELF::ShouldPrintSectionType(unsigned Ty) const { - if (IsExplicit && !(Ty == SHT_NOBITS || Ty == SHT_PROGBITS)) - return false; - - return true; -} - void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const { @@ -49,87 +43,88 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, // Handle the weird solaris syntax if desired. if (MAI.usesSunStyleELFSectionSwitchSyntax() && - !(Flags & MCSectionELF::SHF_MERGE)) { - if (Flags & MCSectionELF::SHF_ALLOC) + !(Flags & ELF::SHF_MERGE)) { + if (Flags & ELF::SHF_ALLOC) OS << ",#alloc"; - if (Flags & MCSectionELF::SHF_EXECINSTR) + if (Flags & ELF::SHF_EXECINSTR) OS << ",#execinstr"; - if (Flags & MCSectionELF::SHF_WRITE) + if (Flags & ELF::SHF_WRITE) OS << ",#write"; - if (Flags & MCSectionELF::SHF_TLS) + if (Flags & ELF::SHF_TLS) OS << ",#tls"; OS << '\n'; return; } OS << ",\""; - if (Flags & MCSectionELF::SHF_ALLOC) + if (Flags & ELF::SHF_ALLOC) OS << 'a'; - if (Flags & MCSectionELF::SHF_EXECINSTR) + if (Flags & ELF::SHF_EXECINSTR) OS << 'x'; - if (Flags & MCSectionELF::SHF_WRITE) + if (Flags & ELF::SHF_GROUP) + OS << 'G'; + if (Flags & ELF::SHF_WRITE) OS << 'w'; - if (Flags & MCSectionELF::SHF_MERGE) + if (Flags & ELF::SHF_MERGE) OS << 'M'; - if (Flags & MCSectionELF::SHF_STRINGS) + if (Flags & ELF::SHF_STRINGS) OS << 'S'; - if (Flags & MCSectionELF::SHF_TLS) + if (Flags & ELF::SHF_TLS) OS << 'T'; // If there are target-specific flags, print them. - if (Flags & MCSectionELF::XCORE_SHF_CP_SECTION) + if (Flags & ELF::XCORE_SHF_CP_SECTION) OS << 'c'; - if (Flags & MCSectionELF::XCORE_SHF_DP_SECTION) + if (Flags & ELF::XCORE_SHF_DP_SECTION) OS << 'd'; OS << '"'; - if (ShouldPrintSectionType(Type)) { - OS << ','; - - // If comment string is '@', e.g. as on ARM - use '%' instead - if (MAI.getCommentString()[0] == '@') - OS << '%'; - else - OS << '@'; - - if (Type == MCSectionELF::SHT_INIT_ARRAY) - OS << "init_array"; - else if (Type == MCSectionELF::SHT_FINI_ARRAY) - OS << "fini_array"; - else if (Type == MCSectionELF::SHT_PREINIT_ARRAY) - OS << "preinit_array"; - else if (Type == MCSectionELF::SHT_NOBITS) - OS << "nobits"; - else if (Type == MCSectionELF::SHT_PROGBITS) - OS << "progbits"; - - if (getKind().isMergeable1ByteCString()) { - OS << ",1"; - } else if (getKind().isMergeable2ByteCString()) { - OS << ",2"; - } else if (getKind().isMergeable4ByteCString() || - getKind().isMergeableConst4()) { - OS << ",4"; - } else if (getKind().isMergeableConst8()) { - OS << ",8"; - } else if (getKind().isMergeableConst16()) { - OS << ",16"; - } + OS << ','; + + // If comment string is '@', e.g. as on ARM - use '%' instead + if (MAI.getCommentString()[0] == '@') + OS << '%'; + else + OS << '@'; + + if (Type == ELF::SHT_INIT_ARRAY) + OS << "init_array"; + else if (Type == ELF::SHT_FINI_ARRAY) + OS << "fini_array"; + else if (Type == ELF::SHT_PREINIT_ARRAY) + OS << "preinit_array"; + else if (Type == ELF::SHT_NOBITS) + OS << "nobits"; + else if (Type == ELF::SHT_NOTE) + OS << "note"; + else if (Type == ELF::SHT_PROGBITS) + OS << "progbits"; + + if (EntrySize) { + assert(Flags & ELF::SHF_MERGE); + OS << "," << EntrySize; } - + + if (Flags & ELF::SHF_GROUP) + OS << "," << Group->getName() << ",comdat"; OS << '\n'; } -// HasCommonSymbols - True if this section holds common symbols, this is -// indicated on the ELF object file by a symbol with SHN_COMMON section -// header index. -bool MCSectionELF::HasCommonSymbols() const { - - if (StringRef(SectionName).startswith(".gnu.linkonce.")) - return true; - - return false; +bool MCSectionELF::UseCodeAlign() const { + return getFlags() & ELF::SHF_EXECINSTR; } +bool MCSectionELF::isVirtualSection() const { + return getType() == ELF::SHT_NOBITS; +} +unsigned MCSectionELF::DetermineEntrySize(SectionKind Kind) { + if (Kind.isMergeable1ByteCString()) return 1; + if (Kind.isMergeable2ByteCString()) return 2; + if (Kind.isMergeable4ByteCString()) return 4; + if (Kind.isMergeableConst4()) return 4; + if (Kind.isMergeableConst8()) return 8; + if (Kind.isMergeableConst16()) return 16; + return 0; +} diff --git a/lib/MC/MCSectionMachO.cpp b/lib/MC/MCSectionMachO.cpp index ded3b20..b897c0b 100644 --- a/lib/MC/MCSectionMachO.cpp +++ b/lib/MC/MCSectionMachO.cpp @@ -10,6 +10,7 @@ #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/raw_ostream.h" +#include <cctype> using namespace llvm; /// SectionTypeDescriptors - These are strings that describe the various section @@ -81,18 +82,18 @@ MCSectionMachO::MCSectionMachO(StringRef Segment, StringRef Section, SegmentName[i] = Segment[i]; else SegmentName[i] = 0; - + if (i < Section.size()) SectionName[i] = Section[i]; else SectionName[i] = 0; - } + } } void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, raw_ostream &OS) const { OS << "\t.section\t" << getSegmentName() << ',' << getSectionName(); - + // Get the section type and attributes. unsigned TAA = getTypeAndAttributes(); if (TAA == 0) { @@ -101,7 +102,7 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, } OS << ','; - + unsigned SectionType = TAA & MCSectionMachO::SECTION_TYPE; assert(SectionType <= MCSectionMachO::LAST_KNOWN_SECTION_TYPE && "Invalid SectionType specified!"); @@ -110,7 +111,7 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, OS << SectionTypeDescriptors[SectionType].AssemblerName; else OS << "<<" << SectionTypeDescriptors[SectionType].EnumName << ">>"; - + // If we don't have any attributes, we're done. unsigned SectionAttrs = TAA & MCSectionMachO::SECTION_ATTRIBUTES; if (SectionAttrs == 0) { @@ -128,10 +129,10 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, // Check to see if we have this attribute. if ((SectionAttrDescriptors[i].AttrFlag & SectionAttrs) == 0) continue; - + // Yep, clear it and print it. SectionAttrs &= ~SectionAttrDescriptors[i].AttrFlag; - + OS << Separator; if (SectionAttrDescriptors[i].AssemblerName) OS << SectionAttrDescriptors[i].AssemblerName; @@ -139,15 +140,25 @@ void MCSectionMachO::PrintSwitchToSection(const MCAsmInfo &MAI, OS << "<<" << SectionAttrDescriptors[i].EnumName << ">>"; Separator = '+'; } - + assert(SectionAttrs == 0 && "Unknown section attributes!"); - + // If we have a S_SYMBOL_STUBS size specified, print it. if (Reserved2 != 0) OS << ',' << Reserved2; OS << '\n'; } +bool MCSectionMachO::UseCodeAlign() const { + return hasAttribute(MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS); +} + +bool MCSectionMachO::isVirtualSection() const { + return (getType() == MCSectionMachO::S_ZEROFILL || + getType() == MCSectionMachO::S_GB_ZEROFILL || + getType() == MCSectionMachO::S_THREAD_LOCAL_ZEROFILL); +} + /// StripSpaces - This removes leading and trailing spaces from the StringRef. static void StripSpaces(StringRef &Str) { while (!Str.empty() && isspace(Str[0])) @@ -168,12 +179,12 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. unsigned &StubSize) { // Out. // Find the first comma. std::pair<StringRef, StringRef> Comma = Spec.split(','); - + // If there is no comma, we fail. if (Comma.second.empty()) return "mach-o section specifier requires a segment and section " "separated by a comma"; - + // Capture segment, remove leading and trailing whitespace. Segment = Comma.first; StripSpaces(Segment); @@ -182,14 +193,14 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. if (Segment.empty() || Segment.size() > 16) return "mach-o section specifier requires a segment whose length is " "between 1 and 16 characters"; - + // Split the section name off from any attributes if present. Comma = Comma.second.split(','); // Capture section, remove leading and trailing whitespace. Section = Comma.first; StripSpaces(Section); - + // Verify that the section is present and not too long. if (Section.empty() || Section.size() > 16) return "mach-o section specifier requires a section whose length is " @@ -200,25 +211,25 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. StubSize = 0; if (Comma.second.empty()) return ""; - + // Otherwise, we need to parse the section type and attributes. Comma = Comma.second.split(','); - + // Get the section type. StringRef SectionType = Comma.first; StripSpaces(SectionType); - + // Figure out which section type it is. unsigned TypeID; for (TypeID = 0; TypeID !=MCSectionMachO::LAST_KNOWN_SECTION_TYPE+1; ++TypeID) if (SectionTypeDescriptors[TypeID].AssemblerName && SectionType == SectionTypeDescriptors[TypeID].AssemblerName) break; - + // If we didn't find the section type, reject it. if (TypeID > MCSectionMachO::LAST_KNOWN_SECTION_TYPE) return "mach-o section specifier uses an unknown section type"; - + // Remember the TypeID. TAA = TypeID; @@ -235,10 +246,10 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. // present. Comma = Comma.second.split(','); StringRef Attrs = Comma.first; - + // The attribute list is a '+' separated list of attributes. std::pair<StringRef, StringRef> Plus = Attrs.split('+'); - + while (1) { StringRef Attr = Plus.first; StripSpaces(Attr); @@ -247,14 +258,14 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. for (unsigned i = 0; ; ++i) { if (SectionAttrDescriptors[i].AttrFlag == AttrFlagEnd) return "mach-o section specifier has invalid attribute"; - + if (SectionAttrDescriptors[i].AssemblerName && Attr == SectionAttrDescriptors[i].AssemblerName) { TAA |= SectionAttrDescriptors[i].AttrFlag; break; } } - + if (Plus.second.empty()) break; Plus = Plus.second.split('+'); }; @@ -272,15 +283,14 @@ std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. if ((TAA & MCSectionMachO::SECTION_TYPE) != MCSectionMachO::S_SYMBOL_STUBS) return "mach-o section specifier cannot have a stub size specified because " "it does not have type 'symbol_stubs'"; - + // Okay, if we do, it must be a number. StringRef StubSizeStr = Comma.second; StripSpaces(StubSizeStr); - + // Convert the stub size from a string to an integer. if (StubSizeStr.getAsInteger(0, StubSize)) return "mach-o section specifier has a malformed stub size"; - + return ""; } - diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index 3e9d02e..3dcdba1 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -7,16 +7,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include <cstdlib> using namespace llvm; -MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurSection(0), - PrevSection(0) { +MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx) { + PrevSectionStack.push_back(NULL); + CurSectionStack.push_back(NULL); } MCStreamer::~MCStreamer() { @@ -27,17 +32,90 @@ raw_ostream &MCStreamer::GetCommentOS() { return nulls(); } +void MCStreamer::EmitDwarfSetLineAddr(int64_t LineDelta, + const MCSymbol *Label, int PointerSize) { + // emit the sequence to set the address + EmitIntValue(dwarf::DW_LNS_extended_op, 1); + EmitULEB128IntValue(PointerSize + 1); + EmitIntValue(dwarf::DW_LNE_set_address, 1); + EmitSymbolValue(Label, PointerSize); + + // emit the sequence for the LineDelta (from 1) and a zero address delta. + MCDwarfLineAddr::Emit(this, LineDelta, 0); +} /// EmitIntValue - Special case of EmitValue that avoids the client having to /// pass in a MCExpr for constant integers. void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size, unsigned AddrSpace) { - EmitValue(MCConstantExpr::Create(Value, getContext()), Size, AddrSpace); + assert(Size <= 8 && "Invalid size"); + assert((isUIntN(8 * Size, Value) || isIntN(8 * Size, Value)) && + "Invalid size"); + char buf[8]; + // FIXME: Endianness assumption. + for (unsigned i = 0; i != Size; ++i) + buf[i] = uint8_t(Value >> (i * 8)); + EmitBytes(StringRef(buf, Size), AddrSpace); +} + +/// EmitULEB128Value - Special case of EmitULEB128Value that avoids the +/// client having to pass in a MCExpr for constant integers. +void MCStreamer::EmitULEB128IntValue(uint64_t Value, unsigned AddrSpace) { + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeULEB128(Value, OSE); + EmitBytes(OSE.str(), AddrSpace); +} + +/// EmitSLEB128Value - Special case of EmitSLEB128Value that avoids the +/// client having to pass in a MCExpr for constant integers. +void MCStreamer::EmitSLEB128IntValue(int64_t Value, unsigned AddrSpace) { + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + MCObjectWriter::EncodeSLEB128(Value, OSE); + EmitBytes(OSE.str(), AddrSpace); +} + +void MCStreamer::EmitAbsValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + if (getContext().getAsmInfo().hasAggressiveSymbolFolding()) { + EmitValue(Value, Size, AddrSpace); + return; + } + MCSymbol *ABS = getContext().CreateTempSymbol(); + EmitAssignment(ABS, Value); + EmitSymbolValue(ABS, Size, AddrSpace); +} + + +void MCStreamer::EmitValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + EmitValueImpl(Value, Size, false, AddrSpace); +} + +void MCStreamer::EmitPCRelValue(const MCExpr *Value, unsigned Size, + unsigned AddrSpace) { + EmitValueImpl(Value, Size, true, AddrSpace); +} + +void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, + bool isPCRel, unsigned AddrSpace) { + EmitValueImpl(MCSymbolRefExpr::Create(Sym, getContext()), Size, isPCRel, + AddrSpace); } void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, unsigned AddrSpace) { - EmitValue(MCSymbolRefExpr::Create(Sym, getContext()), Size, AddrSpace); + EmitSymbolValue(Sym, Size, false, AddrSpace); +} + +void MCStreamer::EmitPCRelSymbolValue(const MCSymbol *Sym, unsigned Size, + unsigned AddrSpace) { + EmitSymbolValue(Sym, Size, true, AddrSpace); +} + +void MCStreamer::EmitGPRel32Value(const MCExpr *Value) { + report_fatal_error("unsupported directive in streamer"); } /// EmitFill - Emit NumBytes bytes worth of the value specified by @@ -49,6 +127,138 @@ void MCStreamer::EmitFill(uint64_t NumBytes, uint8_t FillValue, EmitValue(E, 1, AddrSpace); } +bool MCStreamer::EmitDwarfFileDirective(unsigned FileNo, + StringRef Filename) { + return getContext().GetDwarfFile(Filename, FileNo) == 0; +} + +void MCStreamer::EmitDwarfLocDirective(unsigned FileNo, unsigned Line, + unsigned Column, unsigned Flags, + unsigned Isa, + unsigned Discriminator) { + getContext().setCurrentDwarfLoc(FileNo, Line, Column, Flags, Isa, + Discriminator); +} + +MCDwarfFrameInfo *MCStreamer::getCurrentFrameInfo() { + if (FrameInfos.empty()) + return NULL; + return &FrameInfos.back(); +} + +void MCStreamer::EnsureValidFrame() { + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + if (!CurFrame || CurFrame->End) + report_fatal_error("No open frame"); +} + +bool MCStreamer::EmitCFIStartProc() { + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + if (CurFrame && !CurFrame->End) { + report_fatal_error("Starting a frame before finishing the previous one!"); + return true; + } + MCDwarfFrameInfo Frame; + Frame.Begin = getContext().CreateTempSymbol(); + EmitLabel(Frame.Begin); + FrameInfos.push_back(Frame); + return false; +} + +bool MCStreamer::EmitCFIEndProc() { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->End = getContext().CreateTempSymbol(); + EmitLabel(CurFrame->End); + return false; +} + +bool MCStreamer::EmitCFIDefCfa(int64_t Register, int64_t Offset) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(MachineLocation::VirtualFP); + MachineLocation Source(Register, -Offset); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIDefCfaOffset(int64_t Offset) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(MachineLocation::VirtualFP); + MachineLocation Source(MachineLocation::VirtualFP, -Offset); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIDefCfaRegister(int64_t Register) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(Register); + MachineLocation Source(MachineLocation::VirtualFP); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIOffset(int64_t Register, int64_t Offset) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MachineLocation Dest(Register, Offset); + MachineLocation Source(Register, Offset); + MCCFIInstruction Instruction(Label, Dest, Source); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIPersonality(const MCSymbol *Sym, + unsigned Encoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Personality = Sym; + CurFrame->PersonalityEncoding = Encoding; + return false; +} + +bool MCStreamer::EmitCFILsda(const MCSymbol *Sym, unsigned Encoding) { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + CurFrame->Lsda = Sym; + CurFrame->LsdaEncoding = Encoding; + return false; +} + +bool MCStreamer::EmitCFIRememberState() { + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MCCFIInstruction Instruction(MCCFIInstruction::Remember, Label); + CurFrame->Instructions.push_back(Instruction); + return false; +} + +bool MCStreamer::EmitCFIRestoreState() { + // FIXME: Error if there is no matching cfi_remember_state. + EnsureValidFrame(); + MCDwarfFrameInfo *CurFrame = getCurrentFrameInfo(); + MCSymbol *Label = getContext().CreateTempSymbol(); + EmitLabel(Label); + MCCFIInstruction Instruction(MCCFIInstruction::Restore, Label); + CurFrame->Instructions.push_back(Instruction); + return false; +} + /// EmitRawText - If this file is backed by an assembly streamer, this dumps /// the specified string in the output .s file. This capability is /// indicated by the hasRawTextSupport() predicate. diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp index 07751f7..1c71f26 100644 --- a/lib/MC/MCSymbol.cpp +++ b/lib/MC/MCSymbol.cpp @@ -39,7 +39,20 @@ static bool NameNeedsQuoting(StringRef Str) { return false; } +const MCSymbol &MCSymbol::AliasedSymbol() const { + const MCSymbol *S = this; + while (S->isVariable()) { + const MCExpr *Value = S->getVariableValue(); + if (Value->getKind() != MCExpr::SymbolRef) + return *S; + const MCSymbolRefExpr *Ref = static_cast<const MCSymbolRefExpr*>(Value); + S = &Ref->getSymbol(); + } + return *S; +} + void MCSymbol::setVariableValue(const MCExpr *Value) { + assert(!IsUsed && "Cannot set a variable that has already been used."); assert(Value && "Invalid variable value!"); assert((isUndefined() || (isAbsolute() && isa<MCConstantExpr>(Value))) && "Invalid redefinition!"); diff --git a/lib/MC/MachObjectWriter.cpp b/lib/MC/MachObjectWriter.cpp index cffabfa..8af07c7 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MachObjectWriter.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAssembler.h" @@ -18,49 +19,37 @@ #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCValue.h" +#include "llvm/Object/MachOFormat.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MachO.h" #include "llvm/Target/TargetAsmBackend.h" // FIXME: Gross. +#include "../Target/ARM/ARMFixupKinds.h" #include "../Target/X86/X86FixupKinds.h" #include <vector> using namespace llvm; +using namespace llvm::object; +// FIXME: this has been copied from (or to) X86AsmBackend.cpp static unsigned getFixupKindLog2Size(unsigned Kind) { switch (Kind) { - default: llvm_unreachable("invalid fixup kind!"); - case X86::reloc_pcrel_1byte: + default: + llvm_unreachable("invalid fixup kind!"); + case FK_PCRel_1: case FK_Data_1: return 0; - case X86::reloc_pcrel_2byte: + case FK_PCRel_2: case FK_Data_2: return 1; - case X86::reloc_pcrel_4byte: + case FK_PCRel_4: + // FIXME: Remove these!!! case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: + case X86::reloc_signed_4byte: case FK_Data_4: return 2; case FK_Data_8: return 3; } } -static bool isFixupKindPCRel(unsigned Kind) { - switch (Kind) { - default: - return false; - case X86::reloc_pcrel_1byte: - case X86::reloc_pcrel_2byte: - case X86::reloc_pcrel_4byte: - case X86::reloc_riprel_4byte: - case X86::reloc_riprel_4byte_movq_load: - return true; - } -} - -static bool isFixupKindRIPRel(unsigned Kind) { - return Kind == X86::reloc_riprel_4byte || - Kind == X86::reloc_riprel_4byte_movq_load; -} - static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { // Undefined symbols are always extern. if (SD->Symbol->isUndefined()) @@ -77,94 +66,7 @@ static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { namespace { -class MachObjectWriterImpl { - // See <mach-o/loader.h>. - enum { - Header_Magic32 = 0xFEEDFACE, - Header_Magic64 = 0xFEEDFACF - }; - - enum { - Header32Size = 28, - Header64Size = 32, - SegmentLoadCommand32Size = 56, - SegmentLoadCommand64Size = 72, - Section32Size = 68, - Section64Size = 80, - SymtabLoadCommandSize = 24, - DysymtabLoadCommandSize = 80, - Nlist32Size = 12, - Nlist64Size = 16, - RelocationInfoSize = 8 - }; - - enum HeaderFileType { - HFT_Object = 0x1 - }; - - enum HeaderFlags { - HF_SubsectionsViaSymbols = 0x2000 - }; - - enum LoadCommandType { - LCT_Segment = 0x1, - LCT_Symtab = 0x2, - LCT_Dysymtab = 0xb, - LCT_Segment64 = 0x19 - }; - - // See <mach-o/nlist.h>. - enum SymbolTypeType { - STT_Undefined = 0x00, - STT_Absolute = 0x02, - STT_Section = 0x0e - }; - - enum SymbolTypeFlags { - // If any of these bits are set, then the entry is a stab entry number (see - // <mach-o/stab.h>. Otherwise the other masks apply. - STF_StabsEntryMask = 0xe0, - - STF_TypeMask = 0x0e, - STF_External = 0x01, - STF_PrivateExtern = 0x10 - }; - - /// IndirectSymbolFlags - Flags for encoding special values in the indirect - /// symbol entry. - enum IndirectSymbolFlags { - ISF_Local = 0x80000000, - ISF_Absolute = 0x40000000 - }; - - /// RelocationFlags - Special flags for addresses. - enum RelocationFlags { - RF_Scattered = 0x80000000 - }; - - enum RelocationInfoType { - RIT_Vanilla = 0, - RIT_Pair = 1, - RIT_Difference = 2, - RIT_PreboundLazyPointer = 3, - RIT_LocalDifference = 4, - RIT_TLV = 5 - }; - - /// X86_64 uses its own relocation types. - enum RelocationInfoTypeX86_64 { - RIT_X86_64_Unsigned = 0, - RIT_X86_64_Signed = 1, - RIT_X86_64_Branch = 2, - RIT_X86_64_GOTLoad = 3, - RIT_X86_64_GOT = 4, - RIT_X86_64_Subtractor = 5, - RIT_X86_64_Signed1 = 6, - RIT_X86_64_Signed2 = 7, - RIT_X86_64_Signed4 = 8, - RIT_X86_64_TLV = 9 - }; - +class MachObjectWriter : public MCObjectWriter { /// MachSymbolData - Helper struct for containing some precomputed information /// on symbols. struct MachSymbolData { @@ -179,16 +81,14 @@ class MachObjectWriterImpl { } }; + /// The target specific Mach-O writer instance. + llvm::OwningPtr<MCMachObjectTargetWriter> TargetObjectWriter; + /// @name Relocation Data /// @{ - struct MachRelocationEntry { - uint32_t Word0; - uint32_t Word1; - }; - llvm::DenseMap<const MCSectionData*, - std::vector<MachRelocationEntry> > Relocations; + std::vector<macho::RelocationEntry> > Relocations; llvm::DenseMap<const MCSectionData*, unsigned> IndirectSymBase; /// @} @@ -202,32 +102,70 @@ class MachObjectWriterImpl { /// @} - MachObjectWriter *Writer; +private: + /// @name Utility Methods + /// @{ - raw_ostream &OS; + bool isFixupKindPCRel(const MCAssembler &Asm, unsigned Kind) { + const MCFixupKindInfo &FKI = Asm.getBackend().getFixupKindInfo( + (MCFixupKind) Kind); - unsigned Is64Bit : 1; + return FKI.Flags & MCFixupKindInfo::FKF_IsPCRel; + } + + /// @} + + SectionAddrMap SectionAddress; + uint64_t getSectionAddress(const MCSectionData* SD) const { + return SectionAddress.lookup(SD); + } + uint64_t getSymbolAddress(const MCSymbolData* SD, + const MCAsmLayout &Layout) const { + return getSectionAddress(SD->getFragment()->getParent()) + + Layout.getSymbolOffset(SD); + } + uint64_t getFragmentAddress(const MCFragment *Fragment, + const MCAsmLayout &Layout) const { + return getSectionAddress(Fragment->getParent()) + + Layout.getFragmentOffset(Fragment); + } + + uint64_t getPaddingSize(const MCSectionData *SD, + const MCAsmLayout &Layout) const { + uint64_t EndAddr = getSectionAddress(SD) + Layout.getSectionAddressSize(SD); + unsigned Next = SD->getLayoutOrder() + 1; + if (Next >= Layout.getSectionOrder().size()) + return 0; + + const MCSectionData &NextSD = *Layout.getSectionOrder()[Next]; + if (NextSD.getSection().isVirtualSection()) + return 0; + return OffsetToAlignment(EndAddr, NextSD.getAlignment()); + } public: - MachObjectWriterImpl(MachObjectWriter *_Writer, bool _Is64Bit) - : Writer(_Writer), OS(Writer->getStream()), Is64Bit(_Is64Bit) { + MachObjectWriter(MCMachObjectTargetWriter *MOTW, raw_ostream &_OS, + bool _IsLittleEndian) + : MCObjectWriter(_OS, _IsLittleEndian), TargetObjectWriter(MOTW) { } - 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); + /// @name Target Writer Proxy Accessors + /// @{ + + bool is64Bit() const { return TargetObjectWriter->is64Bit(); } + bool isARM() const { + uint32_t CPUType = TargetObjectWriter->getCPUType() & ~mach::CTFM_ArchMask; + return CPUType == mach::CTM_ARM; } + /// @} + void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, bool SubsectionsViaSymbols) { uint32_t Flags = 0; if (SubsectionsViaSymbols) - Flags |= HF_SubsectionsViaSymbols; + Flags |= macho::HF_SubsectionsViaSymbols; // struct mach_header (28 bytes) or // struct mach_header_64 (32 bytes) @@ -235,21 +173,20 @@ public: uint64_t Start = OS.tell(); (void) Start; - Write32(Is64Bit ? Header_Magic64 : Header_Magic32); + Write32(is64Bit() ? macho::HM_Object64 : macho::HM_Object32); + + Write32(TargetObjectWriter->getCPUType()); + Write32(TargetObjectWriter->getCPUSubtype()); - // FIXME: Support cputype. - Write32(Is64Bit ? MachO::CPUTypeX86_64 : MachO::CPUTypeI386); - // FIXME: Support cpusubtype. - Write32(MachO::CPUSubType_I386_ALL); - Write32(HFT_Object); - Write32(NumLoadCommands); // Object files have a single load command, the - // segment. + Write32(macho::HFT_Object); + Write32(NumLoadCommands); Write32(LoadCommandsSize); Write32(Flags); - if (Is64Bit) + if (is64Bit()) Write32(0); // reserved - assert(OS.tell() - Start == Is64Bit ? Header64Size : Header32Size); + assert(OS.tell() - Start == + (is64Bit() ? macho::Header64Size : macho::Header32Size)); } /// WriteSegmentLoadCommand - Write a segment load command. @@ -266,14 +203,16 @@ public: uint64_t Start = OS.tell(); (void) Start; - unsigned SegmentLoadCommandSize = Is64Bit ? SegmentLoadCommand64Size : - SegmentLoadCommand32Size; - Write32(Is64Bit ? LCT_Segment64 : LCT_Segment); + unsigned SegmentLoadCommandSize = + is64Bit() ? macho::SegmentLoadCommand64Size: + macho::SegmentLoadCommand32Size; + Write32(is64Bit() ? macho::LCT_Segment64 : macho::LCT_Segment); Write32(SegmentLoadCommandSize + - NumSections * (Is64Bit ? Section64Size : Section32Size)); + NumSections * (is64Bit() ? macho::Section64Size : + macho::Section32Size)); WriteBytes("", 16); - if (Is64Bit) { + if (is64Bit()) { Write64(0); // vmaddr Write64(VMSize); // vmsize Write64(SectionDataStartOffset); // file offset @@ -295,10 +234,10 @@ public: void WriteSection(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCSectionData &SD, uint64_t FileOffset, uint64_t RelocationsStart, unsigned NumRelocations) { - uint64_t SectionSize = Layout.getSectionSize(&SD); + uint64_t SectionSize = Layout.getSectionAddressSize(&SD); // The offset is unused for virtual sections. - if (Asm.getBackend().isVirtualSection(SD.getSection())) { + if (SD.getSection().isVirtualSection()) { assert(Layout.getSectionFileSize(&SD) == 0 && "Invalid file size!"); FileOffset = 0; } @@ -312,11 +251,11 @@ public: const MCSectionMachO &Section = cast<MCSectionMachO>(SD.getSection()); WriteBytes(Section.getSectionName(), 16); WriteBytes(Section.getSegmentName(), 16); - if (Is64Bit) { - Write64(Layout.getSectionAddress(&SD)); // address + if (is64Bit()) { + Write64(getSectionAddress(&SD)); // address Write64(SectionSize); // size } else { - Write32(Layout.getSectionAddress(&SD)); // address + Write32(getSectionAddress(&SD)); // address Write32(SectionSize); // size } Write32(FileOffset); @@ -332,10 +271,11 @@ public: Write32(Flags); Write32(IndirectSymBase.lookup(&SD)); // reserved1 Write32(Section.getStubSize()); // reserved2 - if (Is64Bit) + if (is64Bit()) Write32(0); // reserved3 - assert(OS.tell() - Start == Is64Bit ? Section64Size : Section32Size); + assert(OS.tell() - Start == is64Bit() ? macho::Section64Size : + macho::Section32Size); } void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, @@ -346,14 +286,14 @@ public: uint64_t Start = OS.tell(); (void) Start; - Write32(LCT_Symtab); - Write32(SymtabLoadCommandSize); + Write32(macho::LCT_Symtab); + Write32(macho::SymtabLoadCommandSize); Write32(SymbolOffset); Write32(NumSymbols); Write32(StringTableOffset); Write32(StringTableSize); - assert(OS.tell() - Start == SymtabLoadCommandSize); + assert(OS.tell() - Start == macho::SymtabLoadCommandSize); } void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, @@ -369,8 +309,8 @@ public: uint64_t Start = OS.tell(); (void) Start; - Write32(LCT_Dysymtab); - Write32(DysymtabLoadCommandSize); + Write32(macho::LCT_Dysymtab); + Write32(macho::DysymtabLoadCommandSize); Write32(FirstLocalSymbol); Write32(NumLocalSymbols); Write32(FirstExternalSymbol); @@ -390,7 +330,7 @@ public: Write32(0); // locreloff Write32(0); // nlocrel - assert(OS.tell() - Start == DysymtabLoadCommandSize); + assert(OS.tell() - Start == macho::DysymtabLoadCommandSize); } void WriteNlist(MachSymbolData &MSD, const MCAsmLayout &Layout) { @@ -404,27 +344,27 @@ public: // // FIXME: Are the prebound or indirect fields possible here? if (Symbol.isUndefined()) - Type = STT_Undefined; + Type = macho::STT_Undefined; else if (Symbol.isAbsolute()) - Type = STT_Absolute; + Type = macho::STT_Absolute; else - Type = STT_Section; + Type = macho::STT_Section; // FIXME: Set STAB bits. if (Data.isPrivateExtern()) - Type |= STF_PrivateExtern; + Type |= macho::STF_PrivateExtern; // Set external bit. if (Data.isExternal() || Symbol.isUndefined()) - Type |= STF_External; + Type |= macho::STF_External; // Compute the symbol address. if (Symbol.isDefined()) { if (Symbol.isAbsolute()) { Address = cast<MCConstantExpr>(Symbol.getVariableValue())->getValue(); } else { - Address = Layout.getSymbolAddress(&Data); + Address = getSymbolAddress(&Data, Layout); } } else if (Data.isCommon()) { // Common symbols are encoded with the size in the address @@ -452,7 +392,7 @@ public: // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' // value. Write16(Flags); - if (Is64Bit) + if (is64Bit()) Write64(Address); else Write32(Address); @@ -472,11 +412,15 @@ public: // - Input errors, where something cannot be correctly encoded. 'as' allows // these through in many cases. + static bool isFixupKindRIPRel(unsigned Kind) { + return Kind == X86::reloc_riprel_4byte || + Kind == X86::reloc_riprel_4byte_movq_load; + } void RecordX86_64Relocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); unsigned IsRIPRel = isFixupKindRIPRel(Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); @@ -484,7 +428,7 @@ public: uint32_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); uint32_t FixupAddress = - Layout.getFragmentAddress(Fragment) + Fixup.getOffset(); + getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); int64_t Value = 0; unsigned Index = 0; unsigned IsExtern = 0; @@ -503,7 +447,7 @@ public: if (Target.isAbsolute()) { // constant // SymbolNum of 0 indicates the absolute section. - Type = RIT_X86_64_Unsigned; + Type = macho::RIT_X86_64_Unsigned; Index = 0; // FIXME: I believe this is broken, I don't think the linker can @@ -513,16 +457,16 @@ public: // yet). if (IsPCRel) { IsExtern = 1; - Type = RIT_X86_64_Branch; + Type = macho::RIT_X86_64_Branch; } } else if (Target.getSymB()) { // A - B + constant const MCSymbol *A = &Target.getSymA()->getSymbol(); MCSymbolData &A_SD = Asm.getSymbolData(*A); - const MCSymbolData *A_Base = Asm.getAtom(Layout, &A_SD); + const MCSymbolData *A_Base = Asm.getAtom(&A_SD); const MCSymbol *B = &Target.getSymB()->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); - const MCSymbolData *B_Base = Asm.getAtom(Layout, &B_SD); + const MCSymbolData *B_Base = Asm.getAtom(&B_SD); // Neither symbol can be modified. if (Target.getSymA()->getKind() != MCSymbolRefExpr::VK_None || @@ -534,25 +478,35 @@ public: if (IsPCRel) report_fatal_error("unsupported pc-relative relocation of difference"); - // We don't currently support any situation where one or both of the - // symbols would require a local relocation. This is almost certainly - // unused and may not be possible to encode correctly. - if (!A_Base || !B_Base) - report_fatal_error("unsupported local relocations in difference"); + // The support for the situation where one or both of the symbols would + // require a local relocation is handled just like if the symbols were + // external. This is certainly used in the case of debug sections where + // the section has only temporary symbols and thus the symbols don't have + // base symbols. This is encoded using the section ordinal and + // non-extern relocation entries. // Darwin 'as' doesn't emit correct relocations for this (it ends up with - // a single SIGNED relocation); reject it for now. - if (A_Base == B_Base) + // a single SIGNED relocation); reject it for now. Except the case where + // both symbols don't have a base, equal but both NULL. + if (A_Base == B_Base && A_Base) report_fatal_error("unsupported relocation with identical base"); - Value += Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(A_Base); - Value -= Layout.getSymbolAddress(&B_SD) - Layout.getSymbolAddress(B_Base); + Value += getSymbolAddress(&A_SD, Layout) - + (A_Base == NULL ? 0 : getSymbolAddress(A_Base, Layout)); + Value -= getSymbolAddress(&B_SD, Layout) - + (B_Base == NULL ? 0 : getSymbolAddress(B_Base, Layout)); - Index = A_Base->getIndex(); - IsExtern = 1; - Type = RIT_X86_64_Unsigned; + if (A_Base) { + Index = A_Base->getIndex(); + IsExtern = 1; + } + else { + Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } + Type = macho::RIT_X86_64_Unsigned; - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | @@ -561,13 +515,19 @@ public: (Type << 28)); Relocations[Fragment->getParent()].push_back(MRE); - Index = B_Base->getIndex(); - IsExtern = 1; - Type = RIT_X86_64_Subtractor; + if (B_Base) { + Index = B_Base->getIndex(); + IsExtern = 1; + } + else { + Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } + Type = macho::RIT_X86_64_Subtractor; } else { const MCSymbol *Symbol = &Target.getSymA()->getSymbol(); MCSymbolData &SD = Asm.getSymbolData(*Symbol); - const MCSymbolData *Base = Asm.getAtom(Layout, &SD); + const MCSymbolData *Base = Asm.getAtom(&SD); // Relocations inside debug sections always use local relocations when // possible. This seems to be done because the debugger doesn't fully @@ -589,15 +549,26 @@ public: // Add the local offset, if needed. if (Base != &SD) - Value += Layout.getSymbolAddress(&SD) - Layout.getSymbolAddress(Base); + Value += Layout.getSymbolOffset(&SD) - Layout.getSymbolOffset(Base); } else if (Symbol->isInSection()) { // The index is the section ordinal (1-based). Index = SD.getFragment()->getParent()->getOrdinal() + 1; IsExtern = 0; - Value += Layout.getSymbolAddress(&SD); + Value += getSymbolAddress(&SD, Layout); if (IsPCRel) Value -= FixupAddress + (1 << Log2Size); + } else if (Symbol->isVariable()) { + const MCExpr *Value = Symbol->getVariableValue(); + int64_t Res; + bool isAbs = Value->EvaluateAsAbsolute(Res, Layout, SectionAddress); + if (isAbs) { + FixedValue = Res; + return; + } else { + report_fatal_error("unsupported relocation of variable '" + + Symbol->getName() + "'"); + } } else { report_fatal_error("unsupported relocation of undefined symbol '" + Symbol->getName() + "'"); @@ -611,15 +582,15 @@ public: // rewrite the movq to an leaq at link time if the symbol ends up in // the same linkage unit. if (unsigned(Fixup.getKind()) == X86::reloc_riprel_4byte_movq_load) - Type = RIT_X86_64_GOTLoad; + Type = macho::RIT_X86_64_GOTLoad; else - Type = RIT_X86_64_GOT; + Type = macho::RIT_X86_64_GOT; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { - Type = RIT_X86_64_TLV; + Type = macho::RIT_X86_64_TLV; } else if (Modifier != MCSymbolRefExpr::VK_None) { report_fatal_error("unsupported symbol modifier in relocation"); } else { - Type = RIT_X86_64_Signed; + Type = macho::RIT_X86_64_Signed; // The Darwin x86_64 relocation format has a problem where it cannot // encode an address (L<foo> + <constant>) which is outside the atom @@ -636,9 +607,9 @@ public: // (the additional bias), but instead appear to just look at the // final offset. switch (-(Target.getConstant() + (1LL << Log2Size))) { - case 1: Type = RIT_X86_64_Signed1; break; - case 2: Type = RIT_X86_64_Signed2; break; - case 4: Type = RIT_X86_64_Signed4; break; + case 1: Type = macho::RIT_X86_64_Signed1; break; + case 2: Type = macho::RIT_X86_64_Signed2; break; + case 4: Type = macho::RIT_X86_64_Signed4; break; } } } else { @@ -646,24 +617,24 @@ public: report_fatal_error("unsupported symbol modifier in branch " "relocation"); - Type = RIT_X86_64_Branch; + Type = macho::RIT_X86_64_Branch; } } else { if (Modifier == MCSymbolRefExpr::VK_GOT) { - Type = RIT_X86_64_GOT; + Type = macho::RIT_X86_64_GOT; } else if (Modifier == MCSymbolRefExpr::VK_GOTPCREL) { // GOTPCREL is allowed as a modifier on non-PCrel instructions, in // which case all we do is set the PCrel bit in the relocation entry; // this is used with exception handling, for example. The source is // required to include any necessary offset directly. - Type = RIT_X86_64_GOT; + Type = macho::RIT_X86_64_GOT; IsPCRel = 1; } else if (Modifier == MCSymbolRefExpr::VK_TLVP) { report_fatal_error("TLVP symbol modifier should have been rip-rel"); } else if (Modifier != MCSymbolRefExpr::VK_None) report_fatal_error("unsupported symbol modifier in relocation"); else - Type = RIT_X86_64_Unsigned; + Type = macho::RIT_X86_64_Unsigned; } } @@ -671,7 +642,7 @@ public: FixedValue = Value; // struct relocation_info (8 bytes) - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | @@ -685,11 +656,11 @@ public: const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, + unsigned Log2Size, uint64_t &FixedValue) { uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); - unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); - unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); - unsigned Type = RIT_Vanilla; + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Type = macho::RIT_Vanilla; // See <reloc.h>. const MCSymbol *A = &Target.getSymA()->getSymbol(); @@ -699,7 +670,9 @@ public: report_fatal_error("symbol '" + A->getName() + "' can not be undefined in a subtraction expression"); - uint32_t Value = Layout.getSymbolAddress(A_SD); + uint32_t Value = getSymbolAddress(A_SD, Layout); + uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); + FixedValue += SecAddr; uint32_t Value2 = 0; if (const MCSymbolRefExpr *B = Target.getSymB()) { @@ -714,28 +687,184 @@ public: // Note that there is no longer any semantic difference between these two // relocation types from the linkers point of view, this is done solely // for pedantic compatibility with 'as'. - Type = A_SD->isExternal() ? RIT_Difference : RIT_LocalDifference; - Value2 = Layout.getSymbolAddress(B_SD); + Type = A_SD->isExternal() ? (unsigned)macho::RIT_Difference : + (unsigned)macho::RIT_Generic_LocalDifference; + Value2 = getSymbolAddress(B_SD, Layout); + FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); + } + + // Relocations are written out in reverse order, so the PAIR comes first. + if (Type == macho::RIT_Difference || + Type == macho::RIT_Generic_LocalDifference) { + macho::RelocationEntry MRE; + MRE.Word0 = ((0 << 0) | + (macho::RIT_Pair << 24) | + (Log2Size << 28) | + (IsPCRel << 30) | + macho::RF_Scattered); + MRE.Word1 = Value2; + Relocations[Fragment->getParent()].push_back(MRE); + } + + macho::RelocationEntry MRE; + MRE.Word0 = ((FixupOffset << 0) | + (Type << 24) | + (Log2Size << 28) | + (IsPCRel << 30) | + macho::RF_Scattered); + MRE.Word1 = Value; + Relocations[Fragment->getParent()].push_back(MRE); + } + + void RecordARMScatteredRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + unsigned Log2Size, + uint64_t &FixedValue) { + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Type = macho::RIT_Vanilla; + + // See <reloc.h>. + const MCSymbol *A = &Target.getSymA()->getSymbol(); + MCSymbolData *A_SD = &Asm.getSymbolData(*A); + + if (!A_SD->getFragment()) + report_fatal_error("symbol '" + A->getName() + + "' can not be undefined in a subtraction expression"); + + uint32_t Value = getSymbolAddress(A_SD, Layout); + uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); + FixedValue += SecAddr; + uint32_t Value2 = 0; + + if (const MCSymbolRefExpr *B = Target.getSymB()) { + MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); + + if (!B_SD->getFragment()) + report_fatal_error("symbol '" + B->getSymbol().getName() + + "' can not be undefined in a subtraction expression"); + + // Select the appropriate difference relocation type. + Type = macho::RIT_Difference; + Value2 = getSymbolAddress(B_SD, Layout); + FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); } // Relocations are written out in reverse order, so the PAIR comes first. - if (Type == RIT_Difference || Type == RIT_LocalDifference) { - MachRelocationEntry MRE; + if (Type == macho::RIT_Difference || + Type == macho::RIT_Generic_LocalDifference) { + macho::RelocationEntry MRE; MRE.Word0 = ((0 << 0) | - (RIT_Pair << 24) | + (macho::RIT_Pair << 24) | (Log2Size << 28) | (IsPCRel << 30) | - RF_Scattered); + macho::RF_Scattered); MRE.Word1 = Value2; Relocations[Fragment->getParent()].push_back(MRE); } - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = ((FixupOffset << 0) | (Type << 24) | (Log2Size << 28) | (IsPCRel << 30) | - RF_Scattered); + macho::RF_Scattered); + MRE.Word1 = Value; + Relocations[Fragment->getParent()].push_back(MRE); + } + + void RecordARMMovwMovtRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue) { + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Type = macho::RIT_ARM_Half; + + // See <reloc.h>. + const MCSymbol *A = &Target.getSymA()->getSymbol(); + MCSymbolData *A_SD = &Asm.getSymbolData(*A); + + if (!A_SD->getFragment()) + report_fatal_error("symbol '" + A->getName() + + "' can not be undefined in a subtraction expression"); + + uint32_t Value = getSymbolAddress(A_SD, Layout); + uint32_t Value2 = 0; + uint64_t SecAddr = getSectionAddress(A_SD->getFragment()->getParent()); + FixedValue += SecAddr; + + if (const MCSymbolRefExpr *B = Target.getSymB()) { + MCSymbolData *B_SD = &Asm.getSymbolData(B->getSymbol()); + + if (!B_SD->getFragment()) + report_fatal_error("symbol '" + B->getSymbol().getName() + + "' can not be undefined in a subtraction expression"); + + // Select the appropriate difference relocation type. + Type = macho::RIT_ARM_HalfDifference; + Value2 = getSymbolAddress(B_SD, Layout); + FixedValue -= getSectionAddress(B_SD->getFragment()->getParent()); + } + + // Relocations are written out in reverse order, so the PAIR comes first. + // ARM_RELOC_HALF and ARM_RELOC_HALF_SECTDIFF abuse the r_length field: + // + // For these two r_type relocations they always have a pair following them + // and the r_length bits are used differently. The encoding of the + // r_length is as follows: + // low bit of r_length: + // 0 - :lower16: for movw instructions + // 1 - :upper16: for movt instructions + // high bit of r_length: + // 0 - arm instructions + // 1 - thumb instructions + // the other half of the relocated expression is in the following pair + // relocation entry in the the low 16 bits of r_address field. + unsigned ThumbBit = 0; + unsigned MovtBit = 0; + switch (Fixup.getKind()) { + default: break; + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + MovtBit = 1; + break; + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + MovtBit = 1; + // Fallthrough + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: + ThumbBit = 1; + break; + } + + + if (Type == macho::RIT_ARM_HalfDifference) { + uint32_t OtherHalf = MovtBit + ? (FixedValue & 0xffff) : ((FixedValue & 0xffff0000) >> 16); + + macho::RelocationEntry MRE; + MRE.Word0 = ((OtherHalf << 0) | + (macho::RIT_Pair << 24) | + (MovtBit << 28) | + (ThumbBit << 29) | + (IsPCRel << 30) | + macho::RF_Scattered); + MRE.Word1 = Value2; + Relocations[Fragment->getParent()].push_back(MRE); + } + + macho::RelocationEntry MRE; + MRE.Word0 = ((FixupOffset << 0) | + (Type << 24) | + (MovtBit << 28) | + (ThumbBit << 29) | + (IsPCRel << 30) | + macho::RF_Scattered); MRE.Word1 = Value; Relocations[Fragment->getParent()].push_back(MRE); } @@ -746,7 +875,7 @@ public: const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { assert(Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP && - !Is64Bit && + !is64Bit() && "Should only be called with a 32-bit TLVP relocation!"); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); @@ -764,50 +893,218 @@ public: if (Target.getSymB()) { // If this is a subtraction then we're pcrel. uint32_t FixupAddress = - Layout.getFragmentAddress(Fragment) + Fixup.getOffset(); + getFragmentAddress(Fragment, Layout) + Fixup.getOffset(); MCSymbolData *SD_B = &Asm.getSymbolData(Target.getSymB()->getSymbol()); IsPCRel = 1; - FixedValue = (FixupAddress - Layout.getSymbolAddress(SD_B) + + FixedValue = (FixupAddress - getSymbolAddress(SD_B, Layout) + Target.getConstant()); FixedValue += 1ULL << Log2Size; } else { FixedValue = 0; } - + // struct relocation_info (8 bytes) - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = Value; + MRE.Word1 = ((Index << 0) | + (IsPCRel << 24) | + (Log2Size << 25) | + (1 << 27) | // Extern + (macho::RIT_Generic_TLV << 28)); // Type + Relocations[Fragment->getParent()].push_back(MRE); + } + + static bool getARMFixupKindMachOInfo(unsigned Kind, unsigned &RelocType, + unsigned &Log2Size) { + RelocType = unsigned(macho::RIT_Vanilla); + Log2Size = ~0U; + + switch (Kind) { + default: + return false; + + case FK_Data_1: + Log2Size = llvm::Log2_32(1); + return true; + case FK_Data_2: + Log2Size = llvm::Log2_32(2); + return true; + case FK_Data_4: + Log2Size = llvm::Log2_32(4); + return true; + case FK_Data_8: + Log2Size = llvm::Log2_32(8); + return true; + + // Handle 24-bit branch kinds. + case ARM::fixup_arm_ldst_pcrel_12: + case ARM::fixup_arm_pcrel_10: + case ARM::fixup_arm_adr_pcrel_12: + case ARM::fixup_arm_condbranch: + case ARM::fixup_arm_uncondbranch: + RelocType = unsigned(macho::RIT_ARM_Branch24Bit); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + + // Handle Thumb branches. + case ARM::fixup_arm_thumb_br: + RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); + Log2Size = llvm::Log2_32(2); + return true; + + case ARM::fixup_arm_thumb_bl: + RelocType = unsigned(macho::RIT_ARM_ThumbBranch32Bit); + Log2Size = llvm::Log2_32(4); + return true; + + case ARM::fixup_arm_thumb_blx: + RelocType = unsigned(macho::RIT_ARM_ThumbBranch22Bit); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + + case ARM::fixup_arm_movt_hi16: + case ARM::fixup_arm_movt_hi16_pcrel: + case ARM::fixup_t2_movt_hi16: + case ARM::fixup_t2_movt_hi16_pcrel: + RelocType = unsigned(macho::RIT_ARM_HalfDifference); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + + case ARM::fixup_arm_movw_lo16: + case ARM::fixup_arm_movw_lo16_pcrel: + case ARM::fixup_t2_movw_lo16: + case ARM::fixup_t2_movw_lo16_pcrel: + RelocType = unsigned(macho::RIT_ARM_Half); + // Report as 'long', even though that is not quite accurate. + Log2Size = llvm::Log2_32(4); + return true; + } + } + void RecordARMRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, + const MCFragment *Fragment, const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) { + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); + unsigned Log2Size; + unsigned RelocType = macho::RIT_Vanilla; + if (!getARMFixupKindMachOInfo(Fixup.getKind(), RelocType, Log2Size)) { + report_fatal_error("unknown ARM fixup kind!"); + return; + } + + // If this is a difference or a defined symbol plus an offset, then we need + // a scattered relocation entry. Differences always require scattered + // relocations. + if (Target.getSymB()) { + if (RelocType == macho::RIT_ARM_Half || + RelocType == macho::RIT_ARM_HalfDifference) + return RecordARMMovwMovtRelocation(Asm, Layout, Fragment, Fixup, + Target, FixedValue); + return RecordARMScatteredRelocation(Asm, Layout, Fragment, Fixup, + Target, Log2Size, FixedValue); + } + + // Get the symbol data, if any. + MCSymbolData *SD = 0; + if (Target.getSymA()) + SD = &Asm.getSymbolData(Target.getSymA()->getSymbol()); + + // FIXME: For other platforms, we need to use scattered relocations for + // internal relocations with offsets. If this is an internal relocation + // with an offset, it also needs a scattered relocation entry. + // + // Is this right for ARM? + uint32_t Offset = Target.getConstant(); + if (IsPCRel && RelocType == macho::RIT_Vanilla) + Offset += 1 << Log2Size; + if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) + return RecordARMScatteredRelocation(Asm, Layout, Fragment, Fixup, Target, + Log2Size, FixedValue); + + // See <reloc.h>. + uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); + unsigned Index = 0; + unsigned IsExtern = 0; + unsigned Type = 0; + + if (Target.isAbsolute()) { // constant + // FIXME! + report_fatal_error("FIXME: relocations to absolute targets " + "not yet implemented"); + } else if (SD->getSymbol().isVariable()) { + int64_t Res; + if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( + Res, Layout, SectionAddress)) { + FixedValue = Res; + return; + } + + report_fatal_error("unsupported relocation of variable '" + + SD->getSymbol().getName() + "'"); + } else { + // Check whether we need an external or internal relocation. + if (doesSymbolRequireExternRelocation(SD)) { + IsExtern = 1; + Index = SD->getIndex(); + // For external relocations, make sure to offset the fixup value to + // compensate for the addend of the symbol address, if it was + // undefined. This occurs with weak definitions, for example. + if (!SD->Symbol->isUndefined()) + FixedValue -= Layout.getSymbolOffset(SD); + } else { + // The index is the section ordinal (1-based). + Index = SD->getFragment()->getParent()->getOrdinal() + 1; + FixedValue += getSectionAddress(SD->getFragment()->getParent()); + } + if (IsPCRel) + FixedValue -= getSectionAddress(Fragment->getParent()); + + // The type is determined by the fixup kind. + Type = RelocType; + } + + // struct relocation_info (8 bytes) + macho::RelocationEntry MRE; + MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | (Log2Size << 25) | - (1 << 27) | // Extern - (RIT_TLV << 28)); // Type + (IsExtern << 27) | + (Type << 28)); Relocations[Fragment->getParent()].push_back(MRE); } - + void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) { - if (Is64Bit) { + // FIXME: These needs to be factored into the target Mach-O writer. + if (isARM()) { + RecordARMRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); + return; + } + if (is64Bit()) { RecordX86_64Relocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); return; } - unsigned IsPCRel = isFixupKindPCRel(Fixup.getKind()); + unsigned IsPCRel = isFixupKindPCRel(Asm, Fixup.getKind()); unsigned Log2Size = getFixupKindLog2Size(Fixup.getKind()); // If this is a 32-bit TLVP reloc it's handled a bit differently. - if (Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { + if (Target.getSymA() && + Target.getSymA()->getKind() == MCSymbolRefExpr::VK_TLVP) { RecordTLVPRelocation(Asm, Layout, Fragment, Fixup, Target, FixedValue); return; } - + // If this is a difference or a defined symbol plus an offset, then we need // a scattered relocation entry. // Differences always require scattered relocations. if (Target.getSymB()) return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); + Target, Log2Size, FixedValue); // Get the symbol data, if any. MCSymbolData *SD = 0; @@ -821,7 +1118,7 @@ public: Offset += 1 << Log2Size; if (Offset && SD && !doesSymbolRequireExternRelocation(SD)) return RecordScatteredRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); + Target, Log2Size, FixedValue); // See <reloc.h>. uint32_t FixupOffset = Layout.getFragmentOffset(Fragment)+Fixup.getOffset(); @@ -834,7 +1131,17 @@ public: // // FIXME: Currently, these are never generated (see code below). I cannot // find a case where they are actually emitted. - Type = RIT_Vanilla; + Type = macho::RIT_Vanilla; + } else if (SD->getSymbol().isVariable()) { + int64_t Res; + if (SD->getSymbol().getVariableValue()->EvaluateAsAbsolute( + Res, Layout, SectionAddress)) { + FixedValue = Res; + return; + } + + report_fatal_error("unsupported relocation of variable '" + + SD->getSymbol().getName() + "'"); } else { // Check whether we need an external or internal relocation. if (doesSymbolRequireExternRelocation(SD)) { @@ -844,17 +1151,20 @@ public: // compensate for the addend of the symbol address, if it was // undefined. This occurs with weak definitions, for example. if (!SD->Symbol->isUndefined()) - FixedValue -= Layout.getSymbolAddress(SD); + FixedValue -= Layout.getSymbolOffset(SD); } else { // The index is the section ordinal (1-based). Index = SD->getFragment()->getParent()->getOrdinal() + 1; + FixedValue += getSectionAddress(SD->getFragment()->getParent()); } + if (IsPCRel) + FixedValue -= getSectionAddress(Fragment->getParent()); - Type = RIT_Vanilla; + Type = macho::RIT_Vanilla; } // struct relocation_info (8 bytes) - MachRelocationEntry MRE; + macho::RelocationEntry MRE; MRE.Word0 = FixupOffset; MRE.Word1 = ((Index << 0) | (IsPCRel << 24) | @@ -885,7 +1195,7 @@ public: // Initialize the section indirect symbol base, if necessary. if (!IndirectSymBase.count(it->SectionData)) IndirectSymBase[it->SectionData] = IndirectIndex; - + Asm.getOrCreateSymbolData(*it->Symbol); } @@ -1028,7 +1338,25 @@ public: StringTable += '\x00'; } - void ExecutePostLayoutBinding(MCAssembler &Asm) { + void computeSectionAddresses(const MCAssembler &Asm, + const MCAsmLayout &Layout) { + uint64_t StartAddress = 0; + const SmallVectorImpl<MCSectionData*> &Order = Layout.getSectionOrder(); + for (int i = 0, n = Order.size(); i != n ; ++i) { + const MCSectionData *SD = Order[i]; + StartAddress = RoundUpToAlignment(StartAddress, SD->getAlignment()); + SectionAddress[SD] = StartAddress; + StartAddress += Layout.getSectionAddressSize(SD); + // Explicitly pad the section to match the alignment requirements of the + // following one. This is for 'gas' compatibility, it shouldn't + /// strictly be necessary. + StartAddress += getPaddingSize(SD, Layout); + } + } + + void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout) { + computeSectionAddresses(Asm, Layout); + // Create symbol data for any indirect symbols. BindIndirectSymbols(Asm); @@ -1037,41 +1365,101 @@ public: UndefinedSymbolData); } - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { + virtual bool IsSymbolRefDifferenceFullyResolvedImpl(const MCAssembler &Asm, + const MCSymbolData &DataA, + const MCFragment &FB, + bool InSet, + bool IsPCRel) const { + if (InSet) + return true; + + // The effective address is + // addr(atom(A)) + offset(A) + // - addr(atom(B)) - offset(B) + // and the offsets are not relocatable, so the fixup is fully resolved when + // addr(atom(A)) - addr(atom(B)) == 0. + const MCSymbolData *A_Base = 0, *B_Base = 0; + + const MCSymbol &SA = DataA.getSymbol().AliasedSymbol(); + const MCSection &SecA = SA.getSection(); + const MCSection &SecB = FB.getParent()->getSection(); + + if (IsPCRel) { + // The simple (Darwin, except on x86_64) way of dealing with this was to + // assume that any reference to a temporary symbol *must* be a temporary + // symbol in the same atom, unless the sections differ. Therefore, any + // PCrel relocation to a temporary symbol (in the same section) is fully + // resolved. This also works in conjunction with absolutized .set, which + // requires the compiler to use .set to absolutize the differences between + // symbols which the compiler knows to be assembly time constants, so we + // don't need to worry about considering symbol differences fully + // resolved. + + if (!Asm.getBackend().hasReliableSymbolDifference()) { + if (!SA.isTemporary() || !SA.isInSection() || &SecA != &SecB) + return false; + return true; + } + } else { + if (!TargetObjectWriter->useAggressiveSymbolFolding()) + return false; + } + + const MCFragment &FA = *Asm.getSymbolData(SA).getFragment(); + + A_Base = FA.getAtom(); + if (!A_Base) + return false; + + B_Base = FB.getAtom(); + if (!B_Base) + return false; + + // If the atoms are the same, they are guaranteed to have the same address. + if (A_Base == B_Base) + return true; + + // Otherwise, we can't prove this is fully resolved. + return false; + } + + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. unsigned NumLoadCommands = 1; - uint64_t LoadCommandsSize = Is64Bit ? - SegmentLoadCommand64Size + NumSections * Section64Size : - SegmentLoadCommand32Size + NumSections * Section32Size; + uint64_t LoadCommandsSize = is64Bit() ? + macho::SegmentLoadCommand64Size + NumSections * macho::Section64Size : + macho::SegmentLoadCommand32Size + NumSections * macho::Section32Size; // Add the symbol table load command sizes, if used. unsigned NumSymbols = LocalSymbolData.size() + ExternalSymbolData.size() + UndefinedSymbolData.size(); if (NumSymbols) { NumLoadCommands += 2; - LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize; + LoadCommandsSize += (macho::SymtabLoadCommandSize + + macho::DysymtabLoadCommandSize); } // Compute the total size of the section data, as well as its file size and // vm size. - uint64_t SectionDataStart = (Is64Bit ? Header64Size : Header32Size) - + LoadCommandsSize; + uint64_t SectionDataStart = (is64Bit() ? macho::Header64Size : + macho::Header32Size) + LoadCommandsSize; uint64_t SectionDataSize = 0; uint64_t SectionDataFileSize = 0; uint64_t VMSize = 0; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { const MCSectionData &SD = *it; - uint64_t Address = Layout.getSectionAddress(&SD); - uint64_t Size = Layout.getSectionSize(&SD); + uint64_t Address = getSectionAddress(&SD); + uint64_t Size = Layout.getSectionAddressSize(&SD); uint64_t FileSize = Layout.getSectionFileSize(&SD); + FileSize += getPaddingSize(&SD, Layout); VMSize = std::max(VMSize, Address + Size); - if (Asm.getBackend().isVirtualSection(SD.getSection())) + if (SD.getSection().isVirtualSection()) continue; SectionDataSize = std::max(SectionDataSize, Address + Size); @@ -1094,11 +1482,11 @@ public: uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) { - std::vector<MachRelocationEntry> &Relocs = Relocations[it]; + std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; unsigned NumRelocs = Relocs.size(); - uint64_t SectionStart = SectionDataStart + Layout.getSectionAddress(it); + uint64_t SectionStart = SectionDataStart + getSectionAddress(it); WriteSection(Asm, Layout, *it, SectionStart, RelocTableEnd, NumRelocs); - RelocTableEnd += NumRelocs * RelocationInfoSize; + RelocTableEnd += NumRelocs * macho::RelocationInfoSize; } // Write the symbol table load command, if used. @@ -1124,8 +1512,8 @@ public: // The string table is written after symbol table. uint64_t StringTableOffset = - SymbolTableOffset + NumSymTabSymbols * (Is64Bit ? Nlist64Size : - Nlist32Size); + SymbolTableOffset + NumSymTabSymbols * (is64Bit() ? macho::Nlist64Size : + macho::Nlist32Size); WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, StringTableOffset, StringTable.size()); @@ -1137,8 +1525,13 @@ public: // Write the actual section data. for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) - Asm.WriteSectionData(it, Layout, Writer); + ie = Asm.end(); it != ie; ++it) { + Asm.WriteSectionData(it, Layout); + + uint64_t Pad = getPaddingSize(it, Layout); + for (unsigned int i = 0; i < Pad; ++i) + Write8(0); + } // Write the extra padding. WriteZeros(SectionDataPadding); @@ -1148,7 +1541,7 @@ public: ie = Asm.end(); it != ie; ++it) { // Write the section relocation entries, in reverse order to match 'as' // (approximately, the exact algorithm is more complicated than this). - std::vector<MachRelocationEntry> &Relocs = Relocations[it]; + std::vector<macho::RelocationEntry> &Relocs = Relocations[it]; for (unsigned i = 0, e = Relocs.size(); i != e; ++i) { Write32(Relocs[e - i - 1].Word0); Write32(Relocs[e - i - 1].Word1); @@ -1169,9 +1562,9 @@ public: // If this symbol is defined and internal, mark it as such. if (it->Symbol->isDefined() && !Asm.getSymbolData(*it->Symbol).isExternal()) { - uint32_t Flags = ISF_Local; + uint32_t Flags = macho::ISF_Local; if (it->Symbol->isAbsolute()) - Flags |= ISF_Absolute; + Flags |= macho::ISF_Absolute; Write32(Flags); continue; } @@ -1198,32 +1591,8 @@ public: } -MachObjectWriter::MachObjectWriter(raw_ostream &OS, - bool Is64Bit, - bool IsLittleEndian) - : MCObjectWriter(OS, IsLittleEndian) -{ - Impl = new MachObjectWriterImpl(this, Is64Bit); -} - -MachObjectWriter::~MachObjectWriter() { - delete (MachObjectWriterImpl*) Impl; -} - -void MachObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { - ((MachObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); -} - -void MachObjectWriter::RecordRelocation(const MCAssembler &Asm, - const MCAsmLayout &Layout, - const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, - uint64_t &FixedValue) { - ((MachObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); -} - -void MachObjectWriter::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - ((MachObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); +MCObjectWriter *llvm::createMachObjectWriter(MCMachObjectTargetWriter *MOTW, + raw_ostream &OS, + bool IsLittleEndian) { + return new MachObjectWriter(MOTW, OS, IsLittleEndian); } diff --git a/lib/MC/TargetAsmBackend.cpp b/lib/MC/TargetAsmBackend.cpp index bbfddbe..1927557 100644 --- a/lib/MC/TargetAsmBackend.cpp +++ b/lib/MC/TargetAsmBackend.cpp @@ -10,13 +10,28 @@ #include "llvm/Target/TargetAsmBackend.h" using namespace llvm; -TargetAsmBackend::TargetAsmBackend(const Target &T) - : TheTarget(T), - HasAbsolutizedSet(false), - HasReliableSymbolDifference(false), - HasScatteredSymbols(false) +TargetAsmBackend::TargetAsmBackend() + : HasReliableSymbolDifference(false) { } TargetAsmBackend::~TargetAsmBackend() { } + +const MCFixupKindInfo & +TargetAsmBackend::getFixupKindInfo(MCFixupKind Kind) const { + static const MCFixupKindInfo Builtins[] = { + { "FK_Data_1", 0, 8, 0 }, + { "FK_Data_2", 0, 16, 0 }, + { "FK_Data_4", 0, 32, 0 }, + { "FK_Data_8", 0, 64, 0 }, + { "FK_PCRel_1", 0, 8, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_PCRel_2", 0, 16, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_PCRel_4", 0, 32, MCFixupKindInfo::FKF_IsPCRel }, + { "FK_PCRel_8", 0, 64, MCFixupKindInfo::FKF_IsPCRel } + }; + + assert((size_t)Kind <= sizeof(Builtins) / sizeof(Builtins[0]) && + "Unknown fixup kind"); + return Builtins[Kind]; +} diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index eeb2b96..6ca5d37 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -31,7 +31,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/System/TimeValue.h" +#include "llvm/Support/TimeValue.h" #include "../Target/X86/X86FixupKinds.h" @@ -55,6 +55,9 @@ struct AuxSymbol { COFF::Auxiliary Aux; }; +class COFFSymbol; +class COFFSection; + class COFFSymbol { public: COFF::symbol Data; @@ -62,15 +65,19 @@ public: typedef llvm::SmallVector<AuxSymbol, 1> AuxiliarySymbols; name Name; - size_t Index; + int Index; AuxiliarySymbols Aux; COFFSymbol *Other; + COFFSection *Section; + int Relocations; MCSymbolData const *MCData; - COFFSymbol(llvm::StringRef name, size_t index); + COFFSymbol(llvm::StringRef name); size_t size() const; void set_name_offset(uint32_t Offset); + + bool should_keep() const; }; // This class contains staging data for a COFF relocation entry. @@ -89,12 +96,12 @@ public: COFF::section Header; std::string Name; - size_t Number; + int Number; MCSectionData const *MCData; - COFFSymbol *Symb; + COFFSymbol *Symbol; relocations Relocations; - COFFSection(llvm::StringRef name, size_t Index); + COFFSection(llvm::StringRef name); static size_t size(); }; @@ -118,11 +125,8 @@ 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; + typedef DenseMap<MCSymbol const *, COFFSymbol *> symbol_map; + typedef DenseMap<MCSection const *, COFFSection *> section_map; // Root level file contents. bool Is64Bit; @@ -138,11 +142,9 @@ public: 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); + COFFSymbol *createSymbol(StringRef Name); + COFFSymbol *GetOrCreateCOFFSymbol(const MCSymbol * Symbol); + COFFSection *createSection(StringRef Name); template <typename object_t, typename list_t> object_t *createCOFFEntity(llvm::StringRef Name, list_t &List); @@ -150,9 +152,14 @@ public: void DefineSection(MCSectionData const &SectionData); void DefineSymbol(MCSymbolData const &SymbolData, MCAssembler &Assembler); - bool ExportSection(COFFSection *S); + void MakeSymbolReal(COFFSymbol &S, size_t Index); + void MakeSectionReal(COFFSection &S, size_t Number); + + bool ExportSection(COFFSection const *S); bool ExportSymbol(MCSymbolData const &SymbolData, MCAssembler &Asm); + bool IsPhysicalSection(COFFSection *S); + // Entity writing methods. void WriteFileHeader(const COFF::header &Header); @@ -163,7 +170,7 @@ public: // MCObjectWriter interface implementation. - void ExecutePostLayoutBinding(MCAssembler &Asm); + void ExecutePostLayoutBinding(MCAssembler &Asm, const MCAsmLayout &Layout); void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, @@ -172,7 +179,7 @@ public: MCValue Target, uint64_t &FixedValue); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); }; } @@ -198,9 +205,12 @@ static inline void write_uint8_le(void *Data, uint8_t const &Value) { //------------------------------------------------------------------------------ // Symbol class implementation -COFFSymbol::COFFSymbol(llvm::StringRef name, size_t index) - : Name(name.begin(), name.end()), Index(-1) - , Other(NULL), MCData(NULL) { +COFFSymbol::COFFSymbol(llvm::StringRef name) + : Name(name.begin(), name.end()) + , Other(NULL) + , Section(NULL) + , Relocations(0) + , MCData(NULL) { memset(&Data, 0, sizeof(Data)); } @@ -216,12 +226,41 @@ void COFFSymbol::set_name_offset(uint32_t Offset) { write_uint32_le(Data.Name + 4, Offset); } +/// logic to decide if the symbol should be reported in the symbol table +bool COFFSymbol::should_keep() const { + // no section means its external, keep it + if (Section == NULL) + return true; + + // if it has relocations pointing at it, keep it + if (Relocations > 0) { + assert(Section->Number != -1 && "Sections with relocations must be real!"); + return true; + } + + // if the section its in is being droped, drop it + if (Section->Number == -1) + return false; + + // if it is the section symbol, keep it + if (Section->Symbol == this) + return true; + + // if its temporary, drop it + if (MCData && MCData->getSymbol().isTemporary()) + return false; + + // otherwise, keep it + return true; +} + //------------------------------------------------------------------------------ // Section class implementation -COFFSection::COFFSection(llvm::StringRef name, size_t Index) - : Name(name), Number(Index + 1) - , MCData(NULL), Symb(NULL) { +COFFSection::COFFSection(llvm::StringRef name) + : Name(name) + , MCData(NULL) + , Symbol(NULL) { memset(&Header, 0, sizeof(Header)); } @@ -290,43 +329,22 @@ WinCOFFObjectWriter::~WinCOFFObjectWriter() { delete *I; } -COFFSymbol *WinCOFFObjectWriter::createSymbol(llvm::StringRef Name) { +COFFSymbol *WinCOFFObjectWriter::createSymbol(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()); +COFFSymbol *WinCOFFObjectWriter::GetOrCreateCOFFSymbol(const MCSymbol * Symbol){ + symbol_map::iterator i = SymbolMap.find(Symbol); + if (i != SymbolMap.end()) + return i->second; + COFFSymbol *RetSymbol + = createCOFFEntity<COFFSymbol>(Symbol->getName(), Symbols); + SymbolMap[Symbol] = RetSymbol; + return RetSymbol; } -/// 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()); +COFFSection *WinCOFFObjectWriter::createSection(llvm::StringRef Name) { + return createCOFFEntity<COFFSection>(Name, Sections); } /// A template used to lookup or create a symbol/section, and initialize it if @@ -334,9 +352,7 @@ void WinCOFFObjectWriter::InitCOFFEntity(COFFSection &S) { 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); + object_t *Object = new object_t(Name); List.push_back(Object); @@ -346,6 +362,8 @@ object_t *WinCOFFObjectWriter::createCOFFEntity(llvm::StringRef Name, /// This function takes a section data object from the assembler /// and creates the associated COFF section staging object. void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { + assert(SectionData.getSection().getVariant() == MCSection::SV_COFF + && "Got non COFF section in the COFF backend!"); // FIXME: Not sure how to verify this (at least in a debug build). MCSectionCOFF const &Sec = static_cast<MCSectionCOFF const &>(SectionData.getSection()); @@ -353,15 +371,14 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { COFFSection *coff_section = createSection(Sec.getSectionName()); COFFSymbol *coff_symbol = createSymbol(Sec.getSectionName()); - coff_section->Symb = coff_symbol; + coff_section->Symbol = coff_symbol; + coff_symbol->Section = coff_section; 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(); @@ -388,18 +405,53 @@ void WinCOFFObjectWriter::DefineSection(MCSectionData const &SectionData) { // Bind internal COFF section to MC section. coff_section->MCData = &SectionData; - SectionMap[&SectionData] = coff_section; + SectionMap[&SectionData.getSection()] = coff_section; } /// This function takes a section data object from the assembler /// and creates the associated COFF symbol staging object. void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, - MCAssembler &Assembler) { - COFFSymbol *coff_symbol = createSymbol(SymbolData.getSymbol().getName()); + MCAssembler &Assembler) { + COFFSymbol *coff_symbol = GetOrCreateCOFFSymbol(&SymbolData.getSymbol()); coff_symbol->Data.Type = (SymbolData.getFlags() & 0x0000FFFF) >> 0; coff_symbol->Data.StorageClass = (SymbolData.getFlags() & 0x00FF0000) >> 16; + if (SymbolData.getFlags() & COFF::SF_WeakExternal) { + coff_symbol->Data.StorageClass = COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + + if (SymbolData.getSymbol().isVariable()) { + 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); + coff_symbol->Other = GetOrCreateCOFFSymbol(&SymbolRef->getSymbol()); + } else { + std::string WeakName = std::string(".weak.") + + SymbolData.getSymbol().getName().str() + + ".default"; + COFFSymbol *WeakDefault = createSymbol(WeakName); + WeakDefault->Data.SectionNumber = COFF::IMAGE_SYM_ABSOLUTE; + WeakDefault->Data.StorageClass = COFF::IMAGE_SYM_CLASS_EXTERNAL; + WeakDefault->Data.Type = 0; + WeakDefault->Data.Value = 0; + coff_symbol->Other = WeakDefault; + } + + // Setup the Weak External auxiliary symbol. + coff_symbol->Aux.resize(1); + memset(&coff_symbol->Aux[0], 0, sizeof(coff_symbol->Aux[0])); + coff_symbol->Aux[0].AuxType = ATWeakExternal; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = 0; + coff_symbol->Aux[0].Aux.WeakExternal.Characteristics = + COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY; + } + // 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); @@ -408,44 +460,51 @@ void WinCOFFObjectWriter::DefineSymbol(MCSymbolData const &SymbolData, 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(); + if (SymbolData.Fragment != NULL) + coff_symbol->Section = + SectionMap[&SymbolData.Fragment->getParent()->getSection()]; - // FIXME: This assert message isn't very good. - assert(Value->getKind() == MCExpr::SymbolRef && - "Value must be a SymbolRef!"); + // Bind internal COFF symbol to MC symbol. + coff_symbol->MCData = &SymbolData; + SymbolMap[&SymbolData.getSymbol()] = coff_symbol; +} - const MCSymbolRefExpr *SymbolRef = - static_cast<const MCSymbolRefExpr *>(Value); +/// making a section real involves assigned it a number and putting +/// name into the string table if needed +void WinCOFFObjectWriter::MakeSectionReal(COFFSection &S, size_t Number) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); - const MCSymbolData &OtherSymbolData = - Assembler.getSymbolData(SymbolRef->getSymbol()); + // 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."); - // FIXME: This assert message isn't very good. - assert(SymbolMap.find(&OtherSymbolData) != SymbolMap.end() && - "OtherSymbolData must be in the symbol map!"); + std::sprintf(S.Header.Name, "/%d", unsigned(StringTableEntry)); + } else + std::memcpy(S.Header.Name, S.Name.c_str(), S.Name.size()); - coff_symbol->Other = SymbolMap[&OtherSymbolData]; + S.Number = Number; + S.Symbol->Data.SectionNumber = S.Number; + S.Symbol->Aux[0].Aux.SectionDefinition.Number = S.Number; +} - // 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; - } +void WinCOFFObjectWriter::MakeSymbolReal(COFFSymbol &S, size_t Index) { + if (S.Name.size() > COFF::NameSize) { + size_t StringTableEntry = Strings.insert(S.Name.c_str()); - // Bind internal COFF symbol to MC symbol. - coff_symbol->MCData = &SymbolData; - SymbolMap[&SymbolData] = coff_symbol; + S.set_name_offset(StringTableEntry); + } else + std::memcpy(S.Data.Name, S.Name.c_str(), S.Name.size()); + S.Index = Index; } -bool WinCOFFObjectWriter::ExportSection(COFFSection *S) { - return (S->Header.Characteristics - & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; +bool WinCOFFObjectWriter::ExportSection(COFFSection const *S) { + return !S->MCData->getFragmentList().empty(); } bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, @@ -455,8 +514,14 @@ bool WinCOFFObjectWriter::ExportSymbol(MCSymbolData const &SymbolData, // return Asm.isSymbolLinkerVisible (&SymbolData); - // For now, all symbols are exported, the linker will sort it out for us. - return true; + // For now, all non-variable symbols are exported, + // the linker will sort the rest out for us. + return SymbolData.isExternal() || !SymbolData.getSymbol().isVariable(); +} + +bool WinCOFFObjectWriter::IsPhysicalSection(COFFSection *S) { + return (S->Header.Characteristics + & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0; } //------------------------------------------------------------------------------ @@ -546,9 +611,10 @@ void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { //////////////////////////////////////////////////////////////////////////////// // MCObjectWriter interface implementations -void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { +void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm, + const MCAsmLayout &Layout) { // "Define" each section & symbol. This creates section & symbol - // entries in the staging area and gives them their final indexes. + // entries in the staging area. for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) DefineSection(*i); @@ -574,19 +640,24 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, MCSectionData const *SectionData = Fragment->getParent(); // Mark this symbol as requiring an entry in the symbol table. - assert(SectionMap.find(SectionData) != SectionMap.end() && + assert(SectionMap.find(&SectionData->getSection()) != SectionMap.end() && "Section must already have been defined in ExecutePostLayoutBinding!"); - assert(SymbolMap.find(&A_SD) != SymbolMap.end() && + assert(SymbolMap.find(&A_SD.getSymbol()) != SymbolMap.end() && "Symbol must already have been defined in ExecutePostLayoutBinding!"); - COFFSection *coff_section = SectionMap[SectionData]; - COFFSymbol *coff_symbol = SymbolMap[&A_SD]; + COFFSection *coff_section = SectionMap[&SectionData->getSection()]; + COFFSymbol *coff_symbol = SymbolMap[&A_SD.getSymbol()]; if (Target.getSymB()) { + if (&Target.getSymA()->getSymbol().getSection() + != &Target.getSymB()->getSymbol().getSection()) { + llvm_unreachable("Symbol relative relocations are only allowed between " + "symbols in the same section"); + } const MCSymbol *B = &Target.getSymB()->getSymbol(); MCSymbolData &B_SD = Asm.getSymbolData(*B); - FixedValue = Layout.getSymbolAddress(&A_SD) - Layout.getSymbolAddress(&B_SD); + FixedValue = Layout.getSymbolOffset(&A_SD) - Layout.getSymbolOffset(&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 @@ -600,12 +671,21 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, Reloc.Data.SymbolTableIndex = 0; Reloc.Data.VirtualAddress = Layout.getFragmentOffset(Fragment); - Reloc.Symb = coff_symbol; + + // Turn relocations for temporary symbols into section relocations. + if (coff_symbol->MCData->getSymbol().isTemporary()) { + Reloc.Symb = coff_symbol->Section->Symbol; + FixedValue += Layout.getFragmentOffset(coff_symbol->MCData->Fragment) + + coff_symbol->MCData->getOffset(); + } else + Reloc.Symb = coff_symbol; + + ++Reloc.Symb->Relocations; Reloc.Data.VirtualAddress += Fixup.getOffset(); - switch (Fixup.getKind()) { - case X86::reloc_pcrel_4byte: + switch ((unsigned)Fixup.getKind()) { + case FK_PCRel_4: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_REL32 @@ -615,6 +695,7 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, FixedValue += 4; break; case FK_Data_4: + case X86::reloc_signed_4byte: Reloc.Data.Type = Is64Bit ? COFF::IMAGE_REL_AMD64_ADDR32 : COFF::IMAGE_REL_I386_DIR32; break; @@ -631,9 +712,19 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, coff_section->Relocations.push_back(Reloc); } -void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, +void WinCOFFObjectWriter::WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { // Assign symbol and section indexes and offsets. + Header.NumberOfSections = 0; + + for (sections::iterator i = Sections.begin(), + e = Sections.end(); i != e; i++) { + if (Layout.getSectionAddressSize((*i)->MCData) > 0) { + MakeSectionReal(**i, ++Header.NumberOfSections); + } else { + (*i)->Number = -1; + } + } Header.NumberOfSymbols = 0; @@ -641,32 +732,35 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, 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()]; + assert(coff_symbol->Section != NULL); - coff_symbol->Data.SectionNumber = coff_section->Number; + coff_symbol->Data.SectionNumber = coff_symbol->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; + if (coff_symbol->should_keep()) { + MakeSymbolReal(*coff_symbol, Header.NumberOfSymbols++); + + // Update auxiliary symbol info. + coff_symbol->Data.NumberOfAuxSymbols = coff_symbol->Aux.size(); + Header.NumberOfSymbols += coff_symbol->Data.NumberOfAuxSymbols; + } else + coff_symbol->Index = -1; } // Fixup weak external references. for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) { - COFFSymbol *symb = *i; - - if (symb->Other != NULL) { - assert(symb->Aux.size() == 1 && + COFFSymbol *coff_symbol = *i; + if (coff_symbol->Other != NULL) { + assert(coff_symbol->Index != -1); + assert(coff_symbol->Aux.size() == 1 && "Symbol must contain one aux symbol!"); - assert(symb->Aux[0].AuxType == ATWeakExternal && + assert(coff_symbol->Aux[0].AuxType == ATWeakExternal && "Symbol's aux symbol must be a Weak External!"); - symb->Aux[0].Aux.WeakExternal.TagIndex = symb->Other->Index; + coff_symbol->Aux[0].Aux.WeakExternal.TagIndex = coff_symbol->Other->Index; } } @@ -675,18 +769,19 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, unsigned offset = 0; offset += COFF::HeaderSize; - offset += COFF::SectionSize * Asm.size(); - - Header.NumberOfSections = Sections.size(); + offset += COFF::SectionSize * Header.NumberOfSections; for (MCAssembler::const_iterator i = Asm.begin(), e = Asm.end(); i != e; i++) { - COFFSection *Sec = SectionMap[i]; + COFFSection *Sec = SectionMap[&i->getSection()]; - Sec->Header.SizeOfRawData = Layout.getSectionFileSize(i); + if (Sec->Number == -1) + continue; - if (ExportSection(Sec)) { + Sec->Header.SizeOfRawData = Layout.getSectionAddressSize(i); + + if (IsPhysicalSection(Sec)) { Sec->Header.PointerToRawData = offset; offset += Sec->Header.SizeOfRawData; @@ -700,13 +795,15 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, for (relocations::iterator cr = Sec->Relocations.begin(), er = Sec->Relocations.end(); - cr != er; cr++) { + cr != er; ++cr) { + assert((*cr).Symb->Index != -1); (*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(Sec->Symbol->Aux.size() == 1 + && "Section's symbol must have one aux!"); + AuxSymbol &Aux = Sec->Symbol->Aux[0]; assert(Aux.AuxType == ATSectionDefinition && "Section's symbol's aux symbol must be a Section Definition!"); Aux.Aux.SectionDefinition.Length = Sec->Header.SizeOfRawData; @@ -728,16 +825,21 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, MCAssembler::const_iterator j, je; for (i = Sections.begin(), ie = Sections.end(); i != ie; i++) - WriteSectionHeader((*i)->Header); + if ((*i)->Number != -1) + WriteSectionHeader((*i)->Header); for (i = Sections.begin(), ie = Sections.end(), j = Asm.begin(), je = Asm.end(); - (i != ie) && (j != je); i++, j++) { + (i != ie) && (j != je); ++i, ++j) { + + if ((*i)->Number == -1) + continue; + if ((*i)->Header.PointerToRawData != 0) { assert(OS.tell() == (*i)->Header.PointerToRawData && "Section::PointerToRawData is insane!"); - Asm.WriteSectionData(j, Layout, this); + Asm.WriteSectionData(j, Layout); } if ((*i)->Relocations.size() > 0) { @@ -759,7 +861,8 @@ void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, "Header::PointerToSymbolTable is insane!"); for (symbols::iterator i = Symbols.begin(), e = Symbols.end(); i != e; i++) - WriteSymbol(*i); + if ((*i)->Index != -1) + WriteSymbol(*i); OS.write((char const *)&Strings.Data.front(), Strings.Data.size()); } diff --git a/lib/MC/WinCOFFStreamer.cpp b/lib/MC/WinCOFFStreamer.cpp index 8a194bf..46968e6 100644 --- a/lib/MC/WinCOFFStreamer.cpp +++ b/lib/MC/WinCOFFStreamer.cpp @@ -48,8 +48,10 @@ public: // MCStreamer interface + virtual void InitSections(); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); @@ -66,18 +68,55 @@ public: virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - 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); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit); - virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value); virtual void EmitFileDirective(StringRef Filename); - virtual void EmitDwarfFileDirective(unsigned FileNo,StringRef Filename); virtual void EmitInstruction(const MCInst &Instruction); virtual void Finish(); + +private: + virtual void EmitInstToFragment(const MCInst &Inst) { + llvm_unreachable("Not used by WinCOFF."); + } + virtual void EmitInstToData(const MCInst &Inst) { + llvm_unreachable("Not used by WinCOFF."); + } + + void SetSection(StringRef Section, + unsigned Characteristics, + SectionKind Kind) { + SwitchSection(getContext().getCOFFSection(Section, Characteristics, Kind)); + } + + void SetSectionText() { + SetSection(".text", + COFF::IMAGE_SCN_CNT_CODE + | COFF::IMAGE_SCN_MEM_EXECUTE + | COFF::IMAGE_SCN_MEM_READ, + SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + + void SetSectionData() { + SetSection(".data", + COFF::IMAGE_SCN_CNT_INITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + + void SetSectionBSS() { + SetSection(".bss", + COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA + | COFF::IMAGE_SCN_MEM_READ + | COFF::IMAGE_SCN_MEM_WRITE, + SectionKind::getBSS()); + EmitCodeAlignment(4, 0); + } + }; } // end anonymous namespace. @@ -126,47 +165,81 @@ void WinCOFFStreamer::AddCommonSymbol(MCSymbol *Symbol, uint64_t Size, // MCStreamer interface +void WinCOFFStreamer::InitSections() { + SetSectionText(); + SetSectionData(); + SetSectionBSS(); + SetSectionText(); +} + 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()); + MCObjectStreamer::EmitLabel(Symbol); } void WinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { llvm_unreachable("not implemented"); } +void WinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) { + 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); + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); + // FIXME: This is all very ugly and depressing. What needs to happen here + // depends on quite a few things that are all part of relaxation, which we + // don't really even do. + + if (Value->getKind() != MCExpr::SymbolRef) { + // TODO: This is exactly the same as MachOStreamer. Consider merging into + // MCObjectStreamer. + getAssembler().getOrCreateSymbolData(*Symbol); + AddValueSymbols(Value); + Symbol->setVariableValue(Value); + } else { + // FIXME: This is a horrible way to do this :(. This should really be + // handled after we are done with the MC* objects and immediately before + // writing out the object file when we know exactly what the symbol should + // look like in the coff symbol table. I'm not doing that now because the + // COFF object writer doesn't have a clearly defined separation between MC + // data structures, the object writers data structures, and the raw, POD, + // data structures that get written to disk. + + // Copy over the aliased data. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + const MCSymbolData &RealSD = getAssembler().getOrCreateSymbolData( + dyn_cast<const MCSymbolRefExpr>(Value)->getSymbol()); + + // FIXME: This is particularly nasty because it breaks as soon as any data + // members of MCSymbolData change. + SD.CommonAlign = RealSD.CommonAlign; + SD.CommonSize = RealSD.CommonSize; + SD.Flags = RealSD.Flags; + SD.Fragment = RealSD.Fragment; + SD.Index = RealSD.Index; + SD.IsExternal = RealSD.IsExternal; + SD.IsPrivateExtern = RealSD.IsPrivateExtern; + SD.Offset = RealSD.Offset; + SD.SymbolSize = RealSD.SymbolSize; + } } void WinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { + assert(Symbol && "Symbol must be non-null!"); + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); switch (Attribute) { case MCSA_WeakReference: - getAssembler().getOrCreateSymbolData(*Symbol).modifyFlags( - COFF::SF_WeakReference, - COFF::SF_WeakReference); + case MCSA_Weak: { + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.modifyFlags(COFF::SF_WeakExternal, COFF::SF_WeakExternal); + SD.setExternal(true); + } break; case MCSA_Global: @@ -184,6 +257,9 @@ void WinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { } void WinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); assert(CurSymbol == NULL && "EndCOFFSymbolDef must be called between calls " "to BeginCOFFSymbolDef!"); CurSymbol = Symbol; @@ -220,10 +296,16 @@ void WinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) { void WinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); AddCommonSymbol(Symbol, Size, ByteAlignment, true); } void WinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size) { + assert((Symbol->isInSection() + ? Symbol->getSection().getVariant() == MCSection::SV_COFF + : true) && "Got non COFF section in the COFF backend!"); AddCommonSymbol(Symbol, Size, 1, false); } @@ -243,32 +325,6 @@ void WinCOFFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } -void WinCOFFStreamer::EmitValue(const MCExpr *Value, unsigned Size, - 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) { - llvm_unreachable("not implemented"); -} - void WinCOFFStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, @@ -300,21 +356,11 @@ void WinCOFFStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void WinCOFFStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - llvm_unreachable("not implemented"); -} - void WinCOFFStreamer::EmitFileDirective(StringRef Filename) { // Ignore for now, linkers don't care, and proper debug // info will be a much large effort. } -void WinCOFFStreamer::EmitDwarfFileDirective(unsigned FileNo, - 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()) |