diff options
Diffstat (limited to 'lib/MC')
33 files changed, 3788 insertions, 1548 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 60a3a3e..5856e07 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -18,6 +18,7 @@ add_llvm_library(LLVMMC MCMachOStreamer.cpp MCNullStreamer.cpp MCObjectStreamer.cpp + MCObjectFormat.cpp MCObjectWriter.cpp MCSection.cpp MCSectionCOFF.cpp diff --git a/lib/MC/ELFObjectWriter.cpp b/lib/MC/ELFObjectWriter.cpp index 1704fb0..b15c2d4 100644 --- a/lib/MC/ELFObjectWriter.cpp +++ b/lib/MC/ELFObjectWriter.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/ELFObjectWriter.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" @@ -34,21 +34,72 @@ #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 isFixupKindX86PCRel(unsigned Kind) { + switch (Kind) { + default: + return false; + case X86::reloc_pcrel_1byte: + case X86::reloc_pcrel_4byte: + case X86::reloc_riprel_4byte: + case X86::reloc_riprel_4byte_movq_load: + return true; + } +} + +static bool 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; + } +} + +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,7 +130,9 @@ 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; // Support lexicographic sorting. @@ -84,6 +141,10 @@ namespace { } }; + 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 +160,49 @@ namespace { /// @} - ELFObjectWriter *Writer; - - raw_ostream &OS; + bool NeedsGOT; - // This holds the current offset into the object file. - size_t FileOff; + bool NeedsSymtabShndx; unsigned Is64Bit : 1; bool HasRelocationAddend; + Triple::OSType OSType; + + uint16_t EMachine; + // 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; + public: - ELFObjectWriterImpl(ELFObjectWriter *_Writer, bool _Is64Bit, - bool _HasRelAddend) - : Writer(_Writer), OS(Writer->getStream()), FileOff(0), - Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend) { + ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, + uint16_t _EMachine, bool _HasRelAddend, + Triple::OSType _OSType) + : MCObjectWriter(_OS, IsLittleEndian), + NeedsGOT(false), NeedsSymtabShndx(false), + Is64Bit(_Is64Bit), HasRelocationAddend(_HasRelAddend), + OSType(_OSType), EMachine(_EMachine) { } - 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); + 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 +235,162 @@ 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); - 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, + virtual void RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, - MCValue Target, uint64_t &FixedValue); + MCValue Target, uint64_t &FixedValue) { + assert(0 && "RecordRelocation is not specific enough"); + } - 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); - } + virtual void CreateGroupSections(MCAssembler &Asm, MCAsmLayout &Layout, + GroupMapTy &GroupMap, RevGroupMapTy &RevGroupMap); + + virtual void ExecutePostLayoutBinding(MCAssembler &Asm); - void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags, + 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, + virtual void WriteRelocationsFragment(const MCAssembler &Asm, MCDataFragment *F, const MCSectionData *SD); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + virtual bool IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const; + + 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); }; + //===- X86ELFObjectWriter -------------------------------------------===// + + class X86ELFObjectWriter : public ELFObjectWriter { + public: + X86ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, + uint16_t _EMachine, bool _HasRelAddend, + Triple::OSType _OSType); + + virtual ~X86ELFObjectWriter(); + virtual void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue); + }; + + + //===- ARMELFObjectWriter -------------------------------------------===// + + class ARMELFObjectWriter : public ELFObjectWriter { + public: + ARMELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, bool IsLittleEndian, + uint16_t _EMachine, bool _HasRelAddend, + Triple::OSType _OSType); + + virtual ~ARMELFObjectWriter(); + virtual void RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, MCValue Target, + uint64_t &FixedValue); + }; } +ELFObjectWriter::~ELFObjectWriter() +{} + // Emit the ELF header. -void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, - unsigned NumberOfSections) { +void ELFObjectWriter::WriteHeader(uint64_t SectionDataSize, + unsigned NumberOfSections) { // ELF Header // ---------- // @@ -270,18 +407,22 @@ void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, 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 (OSType) { + 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(EMachine); // e_machine = target Write32(ELF::EV_CURRENT); // e_version WriteWord(0); // e_entry, no entry point in .o file @@ -302,70 +443,127 @@ void ELFObjectWriterImpl::WriteHeader(uint64_t SectionDataSize, 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) { +void ELFObjectWriter::WriteSymbolEntry(MCDataFragment *SymtabF, + MCDataFragment *ShndxF, + uint64_t name, + uint8_t info, uint64_t value, + uint64_t size, uint8_t other, + uint32_t shndx, + bool Reserved) { + if (ShndxF) { + if (shndx >= ELF::SHN_LORESERVE && !Reserved) + String32(*ShndxF, shndx); + else + String32(*ShndxF, 0); + } + + uint16_t Index = (shndx >= ELF::SHN_LORESERVE && !Reserved) ? + uint16_t(ELF::SHN_XINDEX) : shndx; + if (Is64Bit) { - char buf[8]; + 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 + } +} - String32(buf, name); - F->getContents() += StringRef(buf, 4); // st_name +static uint64_t SymbolValue(MCSymbolData &Data, const MCAsmLayout &Layout) { + if (Data.isCommon() && Data.isExternal()) + return Data.getCommonAlignment(); - String8(buf, info); - F->getContents() += StringRef(buf, 1); // st_info + const MCSymbol &Symbol = Data.getSymbol(); + if (!Symbol.isInSection()) + return 0; - String8(buf, other); - F->getContents() += StringRef(buf, 1); // st_other + if (MCFragment *FF = Data.getFragment()) + return Layout.getSymbolAddress(&Data) - + Layout.getSectionAddress(FF->getParent()); - String16(buf, shndx); - F->getContents() += StringRef(buf, 2); // st_shndx + return 0; +} - String64(buf, value); - F->getContents() += StringRef(buf, 8); // st_value +void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { + // The presence of symbol versions causes undefined symbols and + // versions declared with @@@ to be renamed. - String64(buf, size); - F->getContents() += StringRef(buf, 8); // st_size - } else { - char buf[4]; + 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); - String32(buf, name); - F->getContents() += StringRef(buf, 4); // st_name + // Not an alias. + if (&Symbol == &Alias) + continue; - String32(buf, value); - F->getContents() += StringRef(buf, 4); // st_value + 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(); + assert(!(Data.isCommon() && !Data.isExternal())); ESize = Data.getSize(); if (Data.getSize()) { @@ -374,13 +572,9 @@ void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, 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); - Value = Layout.getSymbolAddress(&Data); + assert(!Res.getSymA() || !Res.getSymA()->getSymbol().isDefined()); + assert(!Res.getSymB() || !Res.getSymB()->getSymbol().isDefined()); + Size = Res.getConstant(); } } else if (ESize->getKind() == MCExpr::Constant) { Size = static_cast<const MCConstantExpr *>(ESize)->getValue(); @@ -390,13 +584,15 @@ void ELFObjectWriterImpl::WriteSymbol(MCDataFragment *F, ELFSymbolData &MSD, } // 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"); @@ -404,258 +600,271 @@ 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) { - int64_t Addend = 0; - unsigned Index = 0; - int64_t Value = Target.getConstant(); +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 (!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())) { - 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; - } - } + if (SD.isExternal()) { + if (Renamed) + return Renamed; + return &Symbol; } - FixedValue = Value; + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(ASymbol.getSection()); - // determine the type of the relocation - bool IsPCRel = isFixupKindX86PCRel(Fixup.getKind()); - unsigned Type; - if (Is64Bit) { - if (IsPCRel) { - Type = ELF::R_X86_64_PC32; - } else { - switch ((unsigned)Fixup.getKind()) { - default: llvm_unreachable("invalid fixup kind!"); - case FK_Data_8: Type = ELF::R_X86_64_64; break; - case X86::reloc_pcrel_4byte: - case FK_Data_4: - // check that the offset fits within a signed long - if (isInt<32>(Target.getConstant())) - Type = ELF::R_X86_64_32S; - else - Type = ELF::R_X86_64_32; - break; - case FK_Data_2: Type = ELF::R_X86_64_16; break; - case X86::reloc_pcrel_1byte: - case FK_Data_1: Type = ELF::R_X86_64_8; break; - } - } - } else { - if (IsPCRel) { - Type = ELF::R_386_PC32; - } else { - switch ((unsigned)Fixup.getKind()) { - default: llvm_unreachable("invalid fixup kind!"); - case X86::reloc_pcrel_4byte: - case FK_Data_4: Type = ELF::R_386_32; break; - case FK_Data_2: Type = ELF::R_386_16; break; - case X86::reloc_pcrel_1byte: - case FK_Data_1: Type = ELF::R_386_8; break; - } - } - } + if (Section.getKind().isBSS()) + return NULL; - ELFRelocationEntry ERE; + MCSymbolRefExpr::VariantKind Kind = Target.getSymA()->getKind(); + const MCSectionELF &Sec2 = + static_cast<const MCSectionELF&>(F.getParent()->getSection()); - 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; + if (&Sec2 != &Section && + (Kind == MCSymbolRefExpr::VK_PLT || + Kind == MCSymbolRefExpr::VK_GOTPCREL || + Kind == MCSymbolRefExpr::VK_GOTOFF)) { + if (Renamed) + return Renamed; + return &Symbol; } - ERE.r_offset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); - - if (HasRelocationAddend) - ERE.r_addend = Addend; - else - ERE.r_addend = 0; // Silence compiler warning. + if (Section.getFlags() & MCSectionELF::SHF_MERGE) { + if (Target.getConstant() == 0) + return NULL; + if (Renamed) + return Renamed; + return &Symbol; + } - Relocations[Fragment->getParent()].push_back(ERE); + return NULL; } + uint64_t -ELFObjectWriterImpl::getSymbolIndexInSymbolTable(const MCAssembler &Asm, - const MCSymbol *S) { +ELFObjectWriter::getSymbolIndexInSymbolTable(const MCAssembler &Asm, + const MCSymbol *S) { MCSymbolData &SD = Asm.getSymbolData(*S); + return SD.getIndex(); +} + +static bool isInSymtab(const MCAssembler &Asm, const MCSymbolData &Data, + bool Used, bool Renamed) { + if (Data.getFlags() & ELF_Other_Weakref) + return false; + + if (Used) + return true; + + if (Renamed) + return false; - // Local symbol. - if (!SD.isExternal() && !S->isUndefined()) - return SD.getIndex() + /* empty symbol */ 1; + const MCSymbol &Symbol = Data.getSymbol(); - // External or undefined symbol. - return SD.getIndex() + Asm.size() + /* empty symbol */ 1; + 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; } -void ELFObjectWriterImpl::ComputeSymbolTable(MCAssembler &Asm) { - // Build section lookup table. - DenseMap<const MCSection*, uint8_t> SectionIndexMap; +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(); + + if (RefSymbol.isUndefined() && !RefSymbol.isVariable()) { + if (isSignature && !isUsedInReloc) + return true; + + return false; + } + + return true; +} + +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. @@ -665,20 +874,23 @@ 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()); @@ -695,25 +907,25 @@ void ELFObjectWriterImpl::WriteRelocation(MCAssembler &Asm, MCAsmLayout &Layout, 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); + Asm.AddSectionToTheEnd(*this, 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 @@ -726,9 +938,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()); @@ -736,67 +948,91 @@ 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 < 0) + entry.Index = getSymbolIndexInSymbolTable(Asm, entry.Symbol); + else + entry.Index += LocalSymbolData.size() + 1; + 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; - 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(); - F = new MCDataFragment(&SymtabSD); + MCSectionData *SymtabShndxSD = NULL; - // 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); + Asm.AddSectionToTheEnd(*this, *SymtabShndxSD, Layout); + } + WriteSymbolTable(F, ShndxF, Asm, Layout, SectionIndexMap); + Asm.AddSectionToTheEnd(*this, SymtabSD, Layout); - MCSectionData &ShstrtabSD = Asm.getOrCreateSectionData(*ShstrtabSection); - ShstrtabSD.setAlignment(1); + F = new MCDataFragment(&StrtabSD); + F->getContents().append(StringTable.begin(), StringTable.end()); + Asm.AddSectionToTheEnd(*this, StrtabSD, Layout); 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 @@ -804,165 +1040,543 @@ 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'; } - Asm.AddSectionToTheEnd(ShstrtabSD, Layout); + Asm.AddSectionToTheEnd(*this, ShstrtabSD, Layout); +} + +bool ELFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const { + // If this is a PCrel relocation, find the section this fixup value is + // relative to. + const MCSection *BaseSection = 0; + if (IsPCRel) { + BaseSection = &DF->getParent()->getSection(); + assert(BaseSection); + } + + const MCSection *SectionA = 0; + const MCSymbol *SymbolA = 0; + if (const MCSymbolRefExpr *A = Target.getSymA()) { + SymbolA = &A->getSymbol().AliasedSymbol(); + SectionA = &SymbolA->getSection(); + } + + const MCSection *SectionB = 0; + if (const MCSymbolRefExpr *B = Target.getSymB()) { + SectionB = &B->getSymbol().AliasedSymbol().getSection(); + } + + if (!BaseSection) + return SectionA == SectionB; + + const MCSymbolData &DataA = Asm.getSymbolData(*SymbolA); + if (DataA.isExternal()) + return false; + + return !SectionB && BaseSection == SectionA; +} + +void ELFObjectWriter::CreateGroupSections(MCAssembler &Asm, + MCAsmLayout &Layout, + GroupMapTy &GroupMap, + RevGroupMapTy &RevGroupMap) { + // 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() & MCSectionELF::SHF_GROUP)) + continue; + + const MCSymbol *SignatureSymbol = Section.getGroup(); + Asm.getOrCreateSymbolData(*SignatureSymbol); + const MCSectionELF *&Group = RevGroupMap[SignatureSymbol]; + if (!Group) { + Group = Asm.getContext().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() & MCSectionELF::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); + } + + for (RevGroupMapTy::const_iterator i = RevGroupMap.begin(), + e = RevGroupMap.end(); i != e; ++i) { + const MCSectionELF *Group = i->second; + MCSectionData &Data = Asm.getOrCreateSectionData(*Group); + Asm.AddSectionToTheEnd(*this, Data, Layout); + } +} + +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_NULL: + case ELF::SHT_ARM_ATTRIBUTES: + // 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; + } + + 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) { +void ELFObjectWriter::WriteObject(MCAssembler &Asm, + const MCAsmLayout &Layout) { + GroupMapTy GroupMap; + RevGroupMapTy RevGroupMap; + CreateGroupSections(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; - uint64_t SectionDataSize = 0; + std::vector<const MCSectionELF*> Sections; + Sections.resize(NumSections); - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; + 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; + } + + for (unsigned i = 1; i < NumSections; ++i) { + const MCSectionELF &Section = *Sections[i]; + const MCSectionData &SD = Asm.getOrCreateSectionData(Section); + + 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 += Size; } + 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); - Asm.WriteSectionData(it, Layout, Writer); + Asm.WriteSectionData(&SD, Layout, this); } + 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); - - for (MCAssembler::const_iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it) { - const MCSectionData &SD = *it; - const MCSectionELF &Section = - static_cast<const MCSectionELF&>(SD.getSection()); - - uint64_t sh_link = 0; - uint64_t sh_info = 0; - - switch(Section.getType()) { - case ELF::SHT_DYNAMIC: - sh_link = SectionStringTableIndex[&it->getSection()]; - sh_info = 0; - break; - - case ELF::SHT_REL: - case ELF::SHT_RELA: { - const MCSection *SymtabSection; - const MCSection *InfoSection; - - SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, 0, - SectionKind::getReadOnly(), - false); - sh_link = SectionIndexMap[SymtabSection]; - - // Remove ".rel" and ".rela" prefixes. - unsigned SecNameLen = (Section.getType() == ELF::SHT_REL) ? 4 : 5; - StringRef SectionName = Section.getSectionName().substr(SecNameLen); - - InfoSection = Asm.getContext().getELFSection(SectionName, - ELF::SHT_PROGBITS, 0, - SectionKind::getReadOnly(), - false); - sh_info = SectionIndexMap[InfoSection]; - break; - } - - case ELF::SHT_SYMTAB: - case ELF::SHT_DYNSYM: - sh_link = StringTableIndex; - sh_info = LastLocalSymbolIndex; - break; - - case ELF::SHT_PROGBITS: - case ELF::SHT_STRTAB: - case ELF::SHT_NOBITS: - // Nothing to do. - break; - - case ELF::SHT_HASH: - case ELF::SHT_GROUP: - case ELF::SHT_SYMTAB_SHNDX: - default: - assert(0 && "FIXME: sh_type value not supported!"); - break; - } + 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]); - 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()); + WriteSection(Asm, SectionIndexMap, GroupSymbolIndex, + SectionOffsetMap[&Section], Layout.getSectionSize(&SD), + SD.getAlignment(), Section); } } -ELFObjectWriter::ELFObjectWriter(raw_ostream &OS, - bool Is64Bit, - bool IsLittleEndian, - bool HasRelocationAddend) - : MCObjectWriter(OS, IsLittleEndian) -{ - Impl = new ELFObjectWriterImpl(this, Is64Bit, HasRelocationAddend); +MCObjectWriter *llvm::createELFObjectWriter(raw_ostream &OS, + bool Is64Bit, + Triple::OSType OSType, + uint16_t EMachine, + bool IsLittleEndian, + bool HasRelocationAddend) { + switch (EMachine) { + case ELF::EM_386: + case ELF::EM_X86_64: + return new X86ELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine, + HasRelocationAddend, OSType); break; + case ELF::EM_ARM: + return new ARMELFObjectWriter(OS, Is64Bit, IsLittleEndian, EMachine, + HasRelocationAddend, OSType); break; + default: llvm_unreachable("Unsupported architecture"); break; + } } -ELFObjectWriter::~ELFObjectWriter() { - delete (ELFObjectWriterImpl*) Impl; -} -void ELFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { - ((ELFObjectWriterImpl*) Impl)->ExecutePostLayoutBinding(Asm); +/// START OF SUBCLASSES for ELFObjectWriter +//===- ARMELFObjectWriter -------------------------------------------===// + +ARMELFObjectWriter::ARMELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, + bool _IsLittleEndian, + uint16_t _EMachine, bool _HasRelocationAddend, + Triple::OSType _OSType) + : ELFObjectWriter(_OS, _Is64Bit, _IsLittleEndian, _EMachine, + _HasRelocationAddend, _OSType) +{} + +ARMELFObjectWriter::~ARMELFObjectWriter() +{} + +void ARMELFObjectWriter::RecordRelocation(const MCAssembler &Asm, + const MCAsmLayout &Layout, + const MCFragment *Fragment, + const MCFixup &Fixup, + MCValue Target, + uint64_t &FixedValue) { + assert(0 && "ARMELFObjectWriter::RecordRelocation() unimplemented"); } -void ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, + + +//===- X86ELFObjectWriter -------------------------------------------===// + + +X86ELFObjectWriter::X86ELFObjectWriter(raw_ostream &_OS, bool _Is64Bit, + bool _IsLittleEndian, + uint16_t _EMachine, bool _HasRelocationAddend, + Triple::OSType _OSType) + : ELFObjectWriter(_OS, _Is64Bit, _IsLittleEndian, _EMachine, + _HasRelocationAddend, _OSType) +{} + +X86ELFObjectWriter::~X86ELFObjectWriter() +{} + +void X86ELFObjectWriter::RecordRelocation(const MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, - const MCFixup &Fixup, MCValue Target, + const MCFixup &Fixup, + MCValue Target, uint64_t &FixedValue) { - ((ELFObjectWriterImpl*) Impl)->RecordRelocation(Asm, Layout, Fragment, Fixup, - Target, FixedValue); -} + int64_t Addend = 0; + int Index = 0; + int64_t Value = Target.getConstant(); + const MCSymbol &Symbol = Target.getSymA()->getSymbol(); + const MCSymbol &ASymbol = Symbol.AliasedSymbol(); + const MCSymbol *RelocSymbol = SymbolToReloc(Asm, Target, *Fragment); -void ELFObjectWriter::WriteObject(const MCAssembler &Asm, - const MCAsmLayout &Layout) { - ((ELFObjectWriterImpl*) Impl)->WriteObject(Asm, Layout); + bool IsPCRel = isFixupKindX86PCRel(Fixup.getKind()); + if (!Target.isAbsolute()) { + if (const MCSymbolRefExpr *RefB = Target.getSymB()) { + const MCSymbol &SymbolB = RefB->getSymbol(); + MCSymbolData &SDB = Asm.getSymbolData(SymbolB); + IsPCRel = true; + MCSectionData *Sec = Fragment->getParent(); + + // Offset of the symbol in the section + int64_t a = Layout.getSymbolAddress(&SDB) - Layout.getSectionAddress(Sec); + + // Ofeset of the relocation in the section + int64_t b = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + Value += b - a; + } + + if (!RelocSymbol) { + MCSymbolData &SD = Asm.getSymbolData(ASymbol); + MCFragment *F = SD.getFragment(); + + Index = F->getParent()->getOrdinal(); + + MCSectionData *FSD = F->getParent(); + // Offset of the symbol in the section + Value += Layout.getSymbolAddress(&SD) - Layout.getSectionAddress(FSD); + } else { + 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; + } + + FixedValue = Value; + + // determine the type of the relocation + + MCSymbolRefExpr::VariantKind Modifier = Target.getSymA()->getKind(); + unsigned Type; + if (Is64Bit) { + if (IsPCRel) { + 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; + } + } 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: + case X86::reloc_pcrel_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 X86::reloc_pcrel_1byte: + 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 X86::reloc_pcrel_4byte: + 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 X86::reloc_pcrel_1byte: + case FK_Data_1: Type = ELF::R_386_8; break; + } + } + } + + if (RelocNeedsGOT(Modifier)) + NeedsGOT = true; + + ELFRelocationEntry ERE; + + ERE.Index = Index; + ERE.Type = Type; + ERE.Symbol = RelocSymbol; + + ERE.r_offset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset(); + + if (HasRelocationAddend) + ERE.r_addend = Addend; + else + ERE.r_addend = 0; // Silence compiler warning. + + Relocations[Fragment->getParent()].push_back(ERE); } diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp index a275be2..e8902e7 100644 --- a/lib/MC/MCAsmInfo.cpp +++ b/lib/MC/MCAsmInfo.cpp @@ -28,6 +28,7 @@ MCAsmInfo::MCAsmInfo() { SeparatorChar = ';'; CommentColumn = 40; CommentString = "#"; + LabelSuffix = ":"; GlobalPrefix = ""; PrivateGlobalPrefix = "."; LinkerPrivateGlobalPrefix = ""; @@ -68,7 +69,9 @@ MCAsmInfo::MCAsmInfo() { ExceptionsType = ExceptionHandling::None; DwarfRequiresFrameSection = true; DwarfUsesInlineInfoSection = false; + DwarfUsesAbsoluteLabelForStmtList = true; DwarfSectionOffsetDirective = 0; + DwarfUsesLabelOffsetForRanges = true; HasMicrosoftFastStdCallMangling = false; AsmTransCBE = 0; diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp index 0bd3b2d..e0e261a 100644 --- a/lib/MC/MCAsmInfoDarwin.cpp +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -44,5 +44,8 @@ MCAsmInfoDarwin::MCAsmInfoDarwin() { HasDotTypeDotSizeDirective = false; HasNoDeadStrip = true; + + DwarfUsesAbsoluteLabelForStmtList = false; + DwarfUsesLabelOffsetForRanges = false; } diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 5c14ad3..692f178 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -33,7 +33,7 @@ class MCAsmStreamer : public MCStreamer { const MCAsmInfo &MAI; OwningPtr<MCInstPrinter> InstPrinter; OwningPtr<MCCodeEmitter> Emitter; - + SmallString<128> CommentToEmit; raw_svector_ostream CommentStream; @@ -69,7 +69,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; } @@ -101,11 +101,21 @@ public: virtual void SwitchSection(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 EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); @@ -123,19 +133,25 @@ 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 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); @@ -154,14 +170,14 @@ public: virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename); 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(); - + /// @} }; @@ -173,14 +189,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(); } @@ -190,10 +206,10 @@ void MCAsmStreamer::EmitCommentsAndEOL() { OS << '\n'; return; } - + CommentStream.flush(); StringRef Comments = CommentToEmit.str(); - + assert(Comments.back() == '\n' && "Comment array not newline terminated"); do { @@ -201,10 +217,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(); @@ -218,6 +234,7 @@ static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { void MCAsmStreamer::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); if (Section != CurSection) { + PrevSection = CurSection; CurSection = Section; Section->PrintSwitchToSection(MAI, OS); } @@ -228,7 +245,7 @@ void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); assert(CurSection && "Cannot emit before setting section!"); - OS << *Symbol << ":"; + OS << *Symbol << MAI.getLabelSuffix(); EmitEOL(); Symbol->setSection(*CurSection); } @@ -236,11 +253,23 @@ void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { 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 +278,11 @@ 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::EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { switch (Attribute) { @@ -259,6 +293,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 +305,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; @@ -352,11 +388,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 +410,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 +422,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,7 +449,7 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) { break; } } - + OS << '"'; } @@ -421,7 +457,7 @@ static void PrintQuotedString(StringRef Data, raw_ostream &OS) { void MCAsmStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { assert(CurSection && "Cannot emit contents before setting section!"); if (Data.empty()) return; - + if (Data.size() == 1) { OS << MAI.getData8bitsDirective(AddrSpace); OS << (unsigned)(unsigned char)Data[0]; @@ -467,7 +503,7 @@ void MCAsmStreamer::EmitIntValue(uint64_t Value, unsigned Size, } return; } - + assert(Directive && "Invalid size for machine code value!"); OS << Directive << truncateToSize(Value, Size); EmitEOL(); @@ -484,12 +520,24 @@ void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size, case 4: Directive = MAI.getData32bitsDirective(AddrSpace); break; case 8: Directive = MAI.getData64bitsDirective(AddrSpace); break; } - + assert(Directive && "Invalid size for machine code value!"); OS << Directive << *Value; EmitEOL(); } +void MCAsmStreamer::EmitULEB128Value(const MCExpr *Value, unsigned AddrSpace) { + assert(MAI.hasLEB128() && "Cannot print a .uleb"); + OS << ".uleb128 " << *Value; + EmitEOL(); +} + +void MCAsmStreamer::EmitSLEB128Value(const MCExpr *Value, unsigned AddrSpace) { + assert(MAI.hasLEB128() && "Cannot print a .sleb"); + OS << ".sleb128 " << *Value; + EmitEOL(); +} + void MCAsmStreamer::EmitGPRel32Value(const MCExpr *Value) { assert(MAI.getGPRel32Directive() != 0); OS << MAI.getGPRel32Directive() << *Value; @@ -502,7 +550,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 +578,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 +588,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 +607,7 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, OS << ' ' << ByteAlignment; OS << ", " << truncateToSize(Value, ValueSize); - if (MaxBytesToEmit) + if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; EmitEOL(); } @@ -645,7 +693,14 @@ void MCAsmStreamer::AddEncodingComment(const MCInst &Inst) { OS << "0b"; for (unsigned j = 8; j--;) { unsigned Bit = (Code[i] >> j) & 1; - if (uint8_t MapEntry = FixupMap[i * 8 + j]) { + + unsigned FixupBit; + if (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 @@ -684,7 +739,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) { diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index f0e1d7f..c80dc3c 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -13,8 +13,10 @@ #include "llvm/MC/MCCodeEmitter.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" @@ -221,98 +223,17 @@ MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, /* *** */ MCAssembler::MCAssembler(MCContext &_Context, TargetAsmBackend &_Backend, - MCCodeEmitter &_Emitter, raw_ostream &_OS) + MCCodeEmitter &_Emitter, bool _PadSectionToAlignment, + raw_ostream &_OS) : Context(_Context), Backend(_Backend), Emitter(_Emitter), - OS(_OS), RelaxAll(false), SubsectionsViaSymbols(false) + OS(_OS), RelaxAll(false), SubsectionsViaSymbols(false), + PadSectionToAlignment(_PadSectionToAlignment) { } 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 +247,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; @@ -346,7 +266,8 @@ const MCSymbolData *MCAssembler::getAtom(const MCAsmLayout &Layout, return SD->getFragment()->getAtom(); } -bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, +bool MCAssembler::EvaluateFixup(const MCObjectWriter &Writer, + const MCAsmLayout &Layout, const MCFixup &Fixup, const MCFragment *DF, MCValue &Target, uint64_t &Value) const { ++stats::EvaluateFixup; @@ -364,43 +285,22 @@ bool MCAssembler::EvaluateFixup(const MCAsmLayout &Layout, Fixup.getKind()).Flags & MCFixupKindInfo::FKF_IsPCRel; bool IsResolved = true; if (const MCSymbolRefExpr *A = Target.getSymA()) { - if (A->getSymbol().isDefined()) - Value += Layout.getSymbolAddress(&getSymbolData(A->getSymbol())); + const MCSymbol &Sym = A->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value += Layout.getSymbolAddress(&getSymbolData(Sym)); else IsResolved = false; } if (const MCSymbolRefExpr *B = Target.getSymB()) { - if (B->getSymbol().isDefined()) - Value -= Layout.getSymbolAddress(&getSymbolData(B->getSymbol())); + const MCSymbol &Sym = B->getSymbol().AliasedSymbol(); + if (Sym.isDefined()) + Value -= Layout.getSymbolAddress(&getSymbolData(Sym)); else IsResolved = false; } - // 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(); - - IsResolved = isScatteredFixupFullyResolvedSimple(*this, Fixup, Target, - BaseSection); - } - } + if (IsResolved) + IsResolved = Writer.IsFixupFullyResolved(*this, Target, IsPCRel, DF); if (IsPCRel) Value -= Layout.getFragmentAddress(DF) + Fixup.getOffset(); @@ -420,6 +320,9 @@ uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, case MCFragment::FT_Inst: return cast<MCInstFragment>(F).getInstSize(); + case MCFragment::FT_LEB: + return cast<MCLEBFragment>(F).getSize(); + case MCFragment::FT_Align: { const MCAlignFragment &AF = cast<MCAlignFragment>(F); @@ -436,23 +339,11 @@ uint64_t MCAssembler::ComputeFragmentSize(MCAsmLayout &Layout, 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. - int64_t TargetLocation; - if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout)) - report_fatal_error("expected assembly-time absolute expression"); - - // FIXME: We need a way to communicate this error. - int64_t Offset = TargetLocation - FragmentOffset; - if (Offset < 0) - report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + - "' (at offset '" + Twine(FragmentOffset) + "'"); + case MCFragment::FT_Org: + return cast<MCOrgFragment>(F).getSize(); - return Offset; - } + case MCFragment::FT_Dwarf: + return cast<MCDwarfLineAddrFragment>(F).getSize(); } assert(0 && "invalid fragment kind"); @@ -602,6 +493,23 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, llvm_unreachable("unexpected inst fragment after lowering"); break; + case MCFragment::FT_LEB: { + MCLEBFragment &LF = cast<MCLEBFragment>(F); + + // FIXME: It is probably better if we don't call EvaluateAsAbsolute in + // here. + int64_t Value; + LF.getValue().EvaluateAsAbsolute(Value, &Layout); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + if (LF.isSigned()) + MCObjectWriter::EncodeSLEB128(Value, OSE); + else + MCObjectWriter::EncodeULEB128(Value, OSE); + OW->WriteBytes(OSE.str()); + break; + } + case MCFragment::FT_Org: { MCOrgFragment &OF = cast<MCOrgFragment>(F); @@ -610,6 +518,20 @@ static void WriteFragmentData(const MCAssembler &Asm, const MCAsmLayout &Layout, break; } + + case MCFragment::FT_Dwarf: { + const MCDwarfLineAddrFragment &OF = cast<MCDwarfLineAddrFragment>(F); + + // The AddrDelta is really unsigned and it can only increase. + int64_t AddrDelta; + OF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, &Layout); + + int64_t LineDelta; + LineDelta = OF.getLineDelta(); + + MCDwarfLineAddr::Write(OW, LineDelta, (uint64_t)AddrDelta); + break; + } } assert(OW->getStream().tell() - Start == FragmentSize); @@ -667,26 +589,17 @@ void MCAssembler::WriteSectionData(const MCSectionData *SD, assert(OW->getStream().tell() - Start == Layout.getSectionFileSize(SD)); } -void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) { +void MCAssembler::AddSectionToTheEnd(const MCObjectWriter &Writer, + 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++; - + unsigned SectionIndex = size(); 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++; - } + const MCFragment &Last = *Layout.getSectionOrder().back()->rbegin(); + unsigned FragmentIndex = Last.getLayoutOrder() + 1; - SD.setLayoutOrder(i); + SD.setLayoutOrder(Layout.getSectionOrder().size()); for (MCSectionData::iterator it2 = SD.begin(), ie2 = SD.end(); it2 != ie2; ++it2) { it2->setLayoutOrder(FragmentIndex++); @@ -694,11 +607,6 @@ void MCAssembler::AddSectionToTheEnd(MCSectionData &SD, MCAsmLayout &Layout) { Layout.getSectionOrder().push_back(&SD); Layout.LayoutSection(&SD); - - // Layout until everything fits. - while (LayoutOnce(Layout)) - continue; - } void MCAssembler::Finish(MCObjectWriter *Writer) { @@ -712,25 +620,25 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { // 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]; + if (PadSectionToAlignment) { + 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 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; + // 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); + // 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. @@ -739,7 +647,7 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { // 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++); } @@ -755,8 +663,17 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { it2->setLayoutOrder(FragmentIndex++); } + 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!"); + } + // Layout until everything fits. - while (LayoutOnce(Layout)) + while (LayoutOnce(*Writer, Layout)) continue; DEBUG_WITH_TYPE("mc-dump", { @@ -772,15 +689,6 @@ 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); @@ -800,7 +708,7 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { // Evaluate the fixup. MCValue Target; uint64_t FixedValue; - if (!EvaluateFixup(Layout, Fixup, DF, Target, FixedValue)) { + if (!EvaluateFixup(*Writer, 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. @@ -818,7 +726,8 @@ void MCAssembler::Finish(MCObjectWriter *Writer) { stats::ObjectBytes += OS.tell() - StartOffset; } -bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup, +bool MCAssembler::FixupNeedsRelaxation(const MCObjectWriter &Writer, + const MCFixup &Fixup, const MCFragment *DF, const MCAsmLayout &Layout) const { if (getRelaxAll()) @@ -827,7 +736,7 @@ bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup, // If we cannot resolve the fixup value, it requires relaxation. MCValue Target; uint64_t Value; - if (!EvaluateFixup(Layout, Fixup, DF, Target, Value)) + if (!EvaluateFixup(Writer, Layout, Fixup, DF, Target, Value)) return true; // Otherwise, relax if the value is too big for a (signed) i8. @@ -836,7 +745,8 @@ bool MCAssembler::FixupNeedsRelaxation(const MCFixup &Fixup, return int64_t(Value) != int64_t(int8_t(Value)); } -bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF, +bool MCAssembler::FragmentNeedsRelaxation(const MCObjectWriter &Writer, + const MCInstFragment *IF, const MCAsmLayout &Layout) const { // If this inst doesn't ever need relaxation, ignore it. This occurs when we // are intentionally pushing out inst fragments, or because we relaxed a @@ -846,13 +756,101 @@ bool MCAssembler::FragmentNeedsRelaxation(const MCInstFragment *IF, for (MCInstFragment::const_fixup_iterator it = IF->fixup_begin(), ie = IF->fixup_end(); it != ie; ++it) - if (FixupNeedsRelaxation(*it, IF, Layout)) + if (FixupNeedsRelaxation(Writer, *it, IF, Layout)) return true; return false; } -bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { +bool MCAssembler::RelaxInstruction(const MCObjectWriter &Writer, + MCAsmLayout &Layout, + MCInstFragment &IF) { + if (!FragmentNeedsRelaxation(Writer, &IF, Layout)) + return false; + + ++stats::RelaxedInstructions; + + // FIXME-PERF: We could immediately lower out instructions if we can tell + // they are fully resolved, to avoid retesting on later passes. + + // Relax the fragment. + + MCInst Relaxed; + getBackend().RelaxInstruction(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); + return true; +} + +bool MCAssembler::RelaxOrg(const MCObjectWriter &Writer, + MCAsmLayout &Layout, + MCOrgFragment &OF) { + int64_t TargetLocation; + if (!OF.getOffset().EvaluateAsAbsolute(TargetLocation, &Layout)) + report_fatal_error("expected assembly-time absolute expression"); + + // FIXME: We need a way to communicate this error. + uint64_t FragmentOffset = Layout.getFragmentOffset(&OF); + int64_t Offset = TargetLocation - FragmentOffset; + if (Offset < 0 || Offset >= 0x40000000) + report_fatal_error("invalid .org offset '" + Twine(TargetLocation) + + "' (at offset '" + Twine(FragmentOffset) + "')"); + + unsigned OldSize = OF.getSize(); + OF.setSize(Offset); + return OldSize != OF.getSize(); +} + +bool MCAssembler::RelaxLEB(const MCObjectWriter &Writer, + MCAsmLayout &Layout, + MCLEBFragment &LF) { + int64_t Value; + LF.getValue().EvaluateAsAbsolute(Value, &Layout); + SmallString<32> Tmp; + raw_svector_ostream OSE(Tmp); + if (LF.isSigned()) + MCObjectWriter::EncodeSLEB128(Value, OSE); + else + MCObjectWriter::EncodeULEB128(Value, OSE); + uint64_t OldSize = LF.getSize(); + LF.setSize(OSE.GetNumBytesInBuffer()); + return OldSize != LF.getSize(); +} + +bool MCAssembler::RelaxDwarfLineAddr(const MCObjectWriter &Writer, + MCAsmLayout &Layout, + MCDwarfLineAddrFragment &DF) { + int64_t AddrDelta; + DF.getAddrDelta().EvaluateAsAbsolute(AddrDelta, &Layout); + int64_t LineDelta; + LineDelta = DF.getLineDelta(); + uint64_t OldSize = DF.getSize(); + DF.setSize(MCDwarfLineAddr::ComputeSize(LineDelta, AddrDelta)); + return OldSize != DF.getSize(); +} + +bool MCAssembler::LayoutOnce(const MCObjectWriter &Writer, + MCAsmLayout &Layout) { ++stats::RelaxationSteps; // Layout the sections in order. @@ -865,43 +863,25 @@ bool MCAssembler::LayoutOnce(MCAsmLayout &Layout) { 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); - WasRelaxed = true; + // Check if this is an fragment that needs relaxation. + switch(it2->getKind()) { + default: + break; + case MCFragment::FT_Inst: + WasRelaxed |= RelaxInstruction(Writer, Layout, + *cast<MCInstFragment>(it2)); + break; + case MCFragment::FT_Org: + WasRelaxed |= RelaxOrg(Writer, Layout, *cast<MCOrgFragment>(it2)); + break; + case MCFragment::FT_Dwarf: + WasRelaxed |= RelaxDwarfLineAddr(Writer, Layout, + *cast<MCDwarfLineAddrFragment>(it2)); + break; + case MCFragment::FT_LEB: + WasRelaxed |= RelaxLEB(Writer, Layout, *cast<MCLEBFragment>(it2)); + break; + } } } @@ -972,6 +952,8 @@ 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_LEB: OS << "MCLEBFragment"; break; } OS << "<MCFragment " << (void*) this << " LayoutOrder:" << LayoutOrder @@ -1032,6 +1014,19 @@ 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_LEB: { + const MCLEBFragment *LF = cast<MCLEBFragment>(this); + OS << "\n "; + OS << " Value:" << LF->getValue() << " Signed:" << LF->isSigned(); + break; + } } OS << ">"; } diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 13cf9a8..87619d5 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -25,7 +25,7 @@ typedef StringMap<const MCSectionCOFF*> COFFUniqueMapTy; MCContext::MCContext(const MCAsmInfo &mai) : MAI(mai), NextUniqueID(0), - CurrentDwarfLoc(0,0,0,0,0) { + CurrentDwarfLoc(0,0,0,0,0,0) { MachOUniquingMap = 0; ELFUniquingMap = 0; COFFUniquingMap = 0; @@ -148,10 +148,15 @@ getMachOSection(StringRef Segment, StringRef Section, 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; @@ -160,12 +165,28 @@ getELFSection(StringRef Section, unsigned Type, unsigned Flags, 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", MCSectionELF::SHT_GROUP, 0, + SectionKind::getReadOnly(), 4, NULL); + return Result; +} + const MCSection *MCContext::getCOFFSection(StringRef Section, unsigned Characteristics, int Selection, @@ -227,7 +248,7 @@ unsigned MCContext::GetDwarfFile(StringRef FileName, unsigned FileNumber) { Name = Slash.second; for (DirIndex = 0; DirIndex < MCDwarfDirs.size(); DirIndex++) { if (Directory == MCDwarfDirs[DirIndex]) - break; + break; } if (DirIndex >= MCDwarfDirs.size()) { char *Buf = static_cast<char *>(Allocate(Directory.size())); @@ -251,15 +272,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/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/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/MCDwarf.cpp b/lib/MC/MCDwarf.cpp index 2da71f9..679f4ee 100644 --- a/lib/MC/MCDwarf.cpp +++ b/lib/MC/MCDwarf.cpp @@ -8,10 +8,436 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCDwarf.h" +#include "llvm/MC/MCAssembler.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/raw_ostream.h" +#include "llvm/Target/TargetAsmBackend.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(MCObjectStreamer *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. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->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 . +// +static inline const MCExpr *MakeStartMinusEndExpr(MCObjectStreamer *MCOS, + MCSymbol *Start, + 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 an "absolute" address used in the start of a dwarf line number +// table. This will result in a relocatation entry for the address. +// +static inline void EmitDwarfSetAddress(MCObjectStreamer *MCOS, + MCSymbol *Symbol) { + MCOS->EmitIntValue(dwarf::DW_LNS_extended_op, 1); + + int sizeof_address = MCOS->getAssembler().getBackend().getPointerSize(); + MCOS->EmitULEB128IntValue(sizeof_address + 1); + + MCOS->EmitIntValue(dwarf::DW_LNE_set_address, 1); + MCOS->EmitSymbolValue(Symbol, sizeof_address); +} + +// +// This emits the Dwarf line table for the specified section from the entries +// in the LineSection. +// +static inline void EmitDwarfLineTable(MCObjectStreamer *MCOS, + const MCSection *Section, + MCLineSection *LineSection, + const MCSection *DwarfLineSection) { + 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; + MCSectionData &DLS = + MCOS->getAssembler().getOrCreateSectionData(*DwarfLineSection); + + // Loop through each MCLineEntry and encode the dwarf line number table. + for (MCLineSection::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. + if (LastLabel == NULL) { + // emit the sequence to set the address + EmitDwarfSetAddress(MCOS, Label); + // emit the sequence for the LineDelta (from 1) and a zero address delta. + MCDwarfLineAddr::Emit(MCOS, LineDelta, 0); + } + else { + // Create an expression for the address delta from the LastLabel and + // this Label (plus 0). + const MCExpr *AddrDelta = MakeStartMinusEndExpr(MCOS, LastLabel, Label,0); + // Create a Dwarf Line fragment for the LineDelta and AddrDelta. + new MCDwarfLineAddrFragment(LineDelta, *AddrDelta, &DLS); + } + + 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); + // Create a symbol at the end of the section. + MCSymbol *SectionEnd = MCOS->getContext().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(DwarfLineSection); + // Create an expression for the address delta from the LastLabel and this + // SectionEnd label. + const MCExpr *AddrDelta = MakeStartMinusEndExpr(MCOS, LastLabel, SectionEnd, + 0); + // Create a Dwarf Line fragment for the LineDelta and AddrDelta. + new MCDwarfLineAddrFragment(INT64_MAX, *AddrDelta, &DLS); +} + +// +// This emits the Dwarf file and the line tables. +// +void MCDwarfFileTable::Emit(MCObjectStreamer *MCOS, + const MCSection *DwarfLineSection) { + // Switch to the section where the table will be emitted into. + MCOS->SwitchSection(DwarfLineSection); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = MCOS->getContext().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 = MCOS->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). + MCOS->EmitValue(MakeStartMinusEndExpr(MCOS, LineStartSym, LineEndSym, 4), + 4, 0); + + // 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 = MCOS->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. + MCOS->EmitValue(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 = + MCOS->getContext().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. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + MCOS->getContext().getMCLineSections(); + for (DenseMap<const MCSection *, MCLineSection *>::iterator it = + MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { + EmitDwarfLineTable(MCOS, it->first, it->second, DwarfLineSection); + + // Now delete the MCLineSections that were created in MCLineEntry::Make() + // and used to emit the line table. + delete it->second; + } + + // This is the end of the section, so set the value of the symbol at the end + // of this section (that was used in a previous expression). + MCOS->EmitLabel(LineEndSym); +} + +/// Utility function to compute the size of the encoding. +uint64_t MCDwarfLineAddr::ComputeSize(int64_t LineDelta, uint64_t AddrDelta) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + MCDwarfLineAddr::Encode(LineDelta, AddrDelta, OS); + return OS.GetNumBytesInBuffer(); +} + +/// 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(MCObjectStreamer *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 +445,4 @@ void MCDwarfFile::print(raw_ostream &OS) const { void MCDwarfFile::dump() const { print(dbgs()); } + diff --git a/lib/MC/MCELFStreamer.cpp b/lib/MC/MCELFStreamer.cpp index fcc6262..157c0c0 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,6 +24,7 @@ #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" @@ -33,22 +35,56 @@ 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) - : MCObjectStreamer(Context, TAB, OS, Emitter) {} + : MCObjectStreamer(Context, TAB, OS, Emitter, false) {} ~MCELFStreamer() {} /// @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 EmitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol); + virtual void SwitchSection(const MCSection *Section); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { assert(0 && "ELF doesn't support this directive"); @@ -105,32 +141,85 @@ public: 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); + + 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", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_WRITE |MCSectionELF::SHF_ALLOC, + SectionKind::getDataRel()); + EmitCodeAlignment(4, 0); + } + void SetSectionText() { + SetSection(".text", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_EXECINSTR | + MCSectionELF::SHF_ALLOC, SectionKind::getText()); + EmitCodeAlignment(4, 0); + } + void SetSectionBss() { + SetSection(".bss", MCSectionELF::SHT_NOBITS, + MCSectionELF::SHF_WRITE | + MCSectionELF::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!"); + Symbol->setSection(*CurSection); + + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + + const MCSectionELF &Section = + static_cast<const MCSectionELF&>(Symbol->getSection()); + if (Section.getFlags() & MCSectionELF::SHF_TLS) + SetType(SD, ELF::STT_TLS); + // FIXME: This is wasteful, we don't necessarily need to create a data // fragment. Instead, we should mark the symbol as pointing into the data // fragment if it exists, otherwise we should just queue the label and set its // fragment pointer when we emit the next fragment. MCDataFragment *F = getOrCreateDataFragment(); - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); SD.setFragment(F); SD.setOffset(F->getContents().size()); - - Symbol->setSection(*CurSection); } void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { switch (Flag) { + case MCAF_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 +228,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 +240,21 @@ void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { Symbol->setVariableValue(AddValueSymbols(Value)); } +void MCELFStreamer::SwitchSection(const MCSection *Section) { + const MCSymbol *Grp = static_cast<const MCSectionELF *>(Section)->getGroup(); + if (Grp) + getAssembler().getOrCreateSymbolData(*Grp); + this->MCObjectStreamer::SwitchSection(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 @@ -177,7 +285,6 @@ void MCELFStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_Reference: case MCSA_NoDeadStrip: case MCSA_PrivateExtern: - case MCSA_WeakReference: case MCSA_WeakDefinition: case MCSA_WeakDefAutoPrivate: case MCSA_Invalid: @@ -186,49 +293,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,23 +354,28 @@ 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, 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.setExternal(true); + SD.setCommon(Size, ByteAlignment); } - SD.setCommon(Size, ByteAlignment); + SD.setSize(MCConstantExpr::Create(Size, getContext())); } void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { @@ -364,37 +486,37 @@ 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() { + // FIXME: duplicated code with the MachO streamer. + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles()) { + const MCSection *DwarfLineSection = + getContext().getELFSection(".debug_line", 0, 0, + SectionKind::getDataRelLocal()); + MCDwarfFileTable::Emit(this, DwarfLineSection); + } - 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, diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp index 343f334..eea736e 100644 --- a/lib/MC/MCExpr.cpp +++ b/lib/MC/MCExpr.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFormat.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCValue.h" #include "llvm/Support/Debug.h" @@ -38,21 +39,37 @@ 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) OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); - // Parenthesize names that start with $ so that they don't look like - // absolute names. - if (Sym.getName()[0] == '$') + if (SRE.getKind() == MCSymbolRefExpr::VK_PPC_HA16 || + SRE.getKind() == MCSymbolRefExpr::VK_PPC_LO16) { + OS << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); + UseParens = true; + } + + 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_ARM_HI16 && + SRE.getKind() != MCSymbolRefExpr::VK_ARM_LO16 && + SRE.getKind() != MCSymbolRefExpr::VK_PPC_HA16 && + SRE.getKind() != MCSymbolRefExpr::VK_PPC_LO16) OS << '@' << MCSymbolRefExpr::getVariantKindName(SRE.getKind()); return; @@ -172,12 +189,25 @@ 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_DTPOFF: return "DTPOFF"; + case VK_TLVP: return "TLVP"; case VK_ARM_HI16: return ":upper16:"; case VK_ARM_LO16: return ":lower16:"; - 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 "(tldgd)"; + case VK_PPC_TOC: return "toc"; + case VK_PPC_HA16: return "ha16"; + case VK_PPC_LO16: return "lo16"; } } @@ -190,9 +220,13 @@ MCSymbolRefExpr::getVariantKindForName(StringRef Name) { .Case("GOTTPOFF", VK_GOTTPOFF) .Case("INDNTPOFF", VK_INDNTPOFF) .Case("NTPOFF", VK_NTPOFF) + .Case("GOTNTPOFF", VK_GOTNTPOFF) .Case("PLT", VK_PLT) .Case("TLSGD", VK_TLSGD) + .Case("TLSLD", VK_TLSLD) + .Case("TLSLDM", VK_TLSLDM) .Case("TPOFF", VK_TPOFF) + .Case("DTPOFF", VK_DTPOFF) .Case("TLVP", VK_TLVP) .Default(VK_Invalid); } @@ -212,14 +246,30 @@ bool MCExpr::EvaluateAsAbsolute(int64_t &Res, const MCAsmLayout *Layout) const { return true; } - if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) + if (!EvaluateAsRelocatable(Value, Layout) || !Value.isAbsolute()) { + // EvaluateAsAbsolute is defined to return the "current value" of + // the expression if we are given a Layout object, even in cases + // when the value is not fixed. + if (Layout) { + Res = Value.getConstant(); + if (Value.getSymA()) { + Res += Layout->getSymbolAddress( + &Layout->getAssembler().getSymbolData(Value.getSymA()->getSymbol())); + } + if (Value.getSymB()) { + Res -= Layout->getSymbolAddress( + &Layout->getAssembler().getSymbolData(Value.getSymB()->getSymbol())); + } + } return false; + } Res = Value.getConstant(); return true; } -static bool EvaluateSymbolicAdd(const MCValue &LHS,const MCSymbolRefExpr *RHS_A, +static bool EvaluateSymbolicAdd(const MCAsmLayout *Layout, 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. @@ -237,12 +287,40 @@ static bool EvaluateSymbolicAdd(const MCValue &LHS,const MCSymbolRefExpr *RHS_A, if (!A) return false; } + + // Absolutize symbol differences between defined symbols when we have a + // layout object and the target requests it. + + if (Layout && A && B) { + const MCSymbol &SA = A->getSymbol(); + const MCSymbol &SB = B->getSymbol(); + const MCObjectFormat &F = + Layout->getAssembler().getBackend().getObjectFormat(); + if (SA.isDefined() && SB.isDefined() && F.isAbsolute(InSet, SA, SB)) { + const MCAssembler &Asm = Layout->getAssembler(); + MCSymbolData &AD = Asm.getSymbolData(A->getSymbol()); + MCSymbolData &BD = Asm.getSymbolData(B->getSymbol()); + Res = MCValue::get(+ Layout->getSymbolAddress(&AD) + - Layout->getSymbolAddress(&BD) + + LHS.getConstant() + + RHS_Cst); + return true; + } + } + + Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst); return true; } bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCAsmLayout *Layout) const { + return EvaluateAsRelocatableImpl(Res, Layout, false); +} + +bool MCExpr::EvaluateAsRelocatableImpl(MCValue &Res, + const MCAsmLayout *Layout, + bool InSet) const { ++stats::MCExprEvaluate; switch (getKind()) { @@ -258,26 +336,13 @@ 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, Layout, + 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 +353,7 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this); MCValue Value; - if (!AUE->getSubExpr()->EvaluateAsRelocatable(Value, Layout)) + if (!AUE->getSubExpr()->EvaluateAsRelocatableImpl(Value, Layout, InSet)) return false; switch (AUE->getOpcode()) { @@ -321,8 +386,8 @@ 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, Layout, InSet) || + !ABE->getRHS()->EvaluateAsRelocatableImpl(RHSValue, Layout, InSet)) return false; // We only support a few operations on non-constant expressions, handle @@ -333,13 +398,13 @@ bool MCExpr::EvaluateAsRelocatable(MCValue &Res, return false; case MCBinaryExpr::Sub: // Negate RHS and add. - return EvaluateSymbolicAdd(LHSValue, + return EvaluateSymbolicAdd(Layout, InSet, LHSValue, RHSValue.getSymB(), RHSValue.getSymA(), -RHSValue.getConstant(), Res); case MCBinaryExpr::Add: - return EvaluateSymbolicAdd(LHSValue, + return EvaluateSymbolicAdd(Layout, InSet, LHSValue, RHSValue.getSymA(), RHSValue.getSymB(), RHSValue.getConstant(), Res); diff --git a/lib/MC/MCLoggingStreamer.cpp b/lib/MC/MCLoggingStreamer.cpp index b96040a..9681c06 100644 --- a/lib/MC/MCLoggingStreamer.cpp +++ b/lib/MC/MCLoggingStreamer.cpp @@ -54,6 +54,11 @@ public: return Child->SwitchSection(Section); } + virtual void InitSections() { + LogCall("InitSections"); + return Child->InitSections(); + } + virtual void EmitLabel(MCSymbol *Symbol) { LogCall("EmitLabel"); return Child->EmitLabel(Symbol); @@ -64,11 +69,21 @@ 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 EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) { LogCall("EmitSymbolAttribute"); return Child->EmitSymbolAttribute(Symbol, Attribute); @@ -142,6 +157,18 @@ public: return Child->EmitIntValue(Value, Size, AddrSpace); } + virtual void EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) { + LogCall("EmitULEB128Value"); + return Child->EmitULEB128Value(Value, AddrSpace); + } + + virtual void EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace = 0) { + LogCall("EmitSLEB128Value"); + return Child->EmitSLEB128Value(Value, AddrSpace); + } + virtual void EmitGPRel32Value(const MCExpr *Value) { LogCall("EmitGPRel32Value"); return Child->EmitGPRel32Value(Value); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 88d9982..b8640d3 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -20,6 +20,7 @@ #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" @@ -30,23 +31,21 @@ 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. - const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, - int IntVal); - void EmitDwarfFileTable(void); + virtual void EmitInstToFragment(const MCInst &Inst); + virtual void EmitInstToData(const MCInst &Inst); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) - : MCObjectStreamer(Context, TAB, OS, Emitter) {} + : MCObjectStreamer(Context, TAB, OS, Emitter, true) {} /// @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); @@ -100,8 +99,6 @@ public: //report_fatal_error("unsupported directive: '.file'"); } - virtual void EmitInstruction(const MCInst &Inst); - virtual void Finish(); /// @} @@ -109,6 +106,13 @@ public: } // end anonymous namespace. +void MCMachOStreamer::InitSections() { + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); + +} + void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { // TODO: This is almost exactly the same as WinCOFFStreamer. Consider merging // into MCObjectStreamer. @@ -146,12 +150,19 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { void MCMachOStreamer::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; + default: + llvm_unreachable("invalid assembler flag!"); } +} - assert(0 && "invalid assembler flag!"); +void MCMachOStreamer::EmitThumbFunc(MCSymbol *Func) { + // FIXME: Flag the function ISA as thumb with DW_AT_APPLE_isa. } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { @@ -195,6 +206,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: @@ -401,184 +413,15 @@ 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); - - // 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 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", +void MCMachOStreamer::Finish() { + // Dump out the dwarf file & directory tables and line tables. + if (getContext().hasDwarfFiles()) { + const MCSection *DwarfLineSection = 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(-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) + 0, SectionKind::getDataRelLocal()); + MCDwarfFileTable::Emit(this, DwarfLineSection); } - 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. - - // 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/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index 5332ade..b95a4f6 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -25,7 +25,11 @@ namespace { /// @name MCStreamer Interface /// @{ + virtual void InitSections() { + } + virtual void SwitchSection(const MCSection *Section) { + PrevSection = CurSection; CurSection = Section; } @@ -36,8 +40,10 @@ namespace { } 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){} @@ -61,6 +67,10 @@ namespace { virtual void EmitValue(const MCExpr *Value, unsigned Size, 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, diff --git a/lib/MC/MCObjectFormat.cpp b/lib/MC/MCObjectFormat.cpp new file mode 100644 index 0000000..aeff334 --- /dev/null +++ b/lib/MC/MCObjectFormat.cpp @@ -0,0 +1,34 @@ +//===- lib/MC/MCObjectFormat.cpp - MCObjectFormat implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCObjectFormat.h" +#include "llvm/MC/MCSymbol.h" + +using namespace llvm; + +MCObjectFormat::~MCObjectFormat() { +} + +bool MCELFObjectFormat::isAbsolute(bool IsSet, const MCSymbol &A, + const MCSymbol &B) const { + // On ELF A - B is absolute if A and B are in the same section. + return &A.getSection() == &B.getSection(); +} + +bool MCMachOObjectFormat::isAbsolute(bool IsSet, const MCSymbol &A, + const MCSymbol &B) const { + // On MachO A - B is absolute only if in a set. + return IsSet; +} + +bool MCCOFFObjectFormat::isAbsolute(bool IsSet, const MCSymbol &A, + const MCSymbol &B) const { + // On COFF A - B is absolute if A and B are in the same section. + return &A.getSection() == &B.getSection(); +} diff --git a/lib/MC/MCObjectStreamer.cpp b/lib/MC/MCObjectStreamer.cpp index eed4e7b..a40c754 100644 --- a/lib/MC/MCObjectStreamer.cpp +++ b/lib/MC/MCObjectStreamer.cpp @@ -12,14 +12,18 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/MC/MCExpr.h" #include "llvm/Target/TargetAsmBackend.h" using namespace llvm; MCObjectStreamer::MCObjectStreamer(MCContext &Context, TargetAsmBackend &TAB, - raw_ostream &_OS, MCCodeEmitter *_Emitter) + raw_ostream &_OS, MCCodeEmitter *_Emitter, + bool _PadSectionToAlignment) : MCStreamer(Context), Assembler(new MCAssembler(Context, TAB, - *_Emitter, _OS)), + *_Emitter, + _PadSectionToAlignment, + _OS)), CurSectionData(0) { } @@ -71,16 +75,65 @@ const MCExpr *MCObjectStreamer::AddValueSymbols(const MCExpr *Value) { return Value; } +void MCObjectStreamer::EmitULEB128Value(const MCExpr *Value, + unsigned AddrSpace) { + new MCLEBFragment(*Value, false, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitSLEB128Value(const MCExpr *Value, + unsigned AddrSpace) { + new MCLEBFragment(*Value, true, getCurrentSectionData()); +} + +void MCObjectStreamer::EmitWeakReference(MCSymbol *Alias, + const MCSymbol *Symbol) { + report_fatal_error("This file format doesn't support weak aliases."); +} + void MCObjectStreamer::SwitchSection(const MCSection *Section) { assert(Section && "Cannot switch to a null section!"); // If already in this section, then this is a noop. if (Section == CurSection) return; + PrevSection = CurSection; CurSection = Section; CurSectionData = &getAssembler().getOrCreateSectionData(*Section); } +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::Finish() { getAssembler().Finish(); } diff --git a/lib/MC/MCObjectWriter.cpp b/lib/MC/MCObjectWriter.cpp index d117e82..6cee76d 100644 --- a/lib/MC/MCObjectWriter.cpp +++ b/lib/MC/MCObjectWriter.cpp @@ -13,3 +13,29 @@ 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); +} diff --git a/lib/MC/MCParser/AsmLexer.cpp b/lib/MC/MCParser/AsmLexer.cpp index 549bd47..5c1ae2f 100644 --- a/lib/MC/MCParser/AsmLexer.cpp +++ b/lib/MC/MCParser/AsmLexer.cpp @@ -65,10 +65,46 @@ int AsmLexer::getNextChar() { } } +/// 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. @@ -84,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. @@ -125,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] @@ -133,13 +168,18 @@ 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; diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 9b2dbc3..fa7a785 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,7 +27,6 @@ #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" @@ -103,6 +102,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); @@ -138,14 +140,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); @@ -170,13 +176,17 @@ private: /// 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); // ".set" or ".equ" bool ParseDirectiveOrg(); // ".org" // ".align{,32}", ".p2align{,w,l}" bool ParseDirectiveAlign(bool IsPow2, unsigned ValueSize); @@ -184,7 +194,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" @@ -199,6 +208,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 @@ -225,6 +237,7 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveFile>(".file"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLine>(".line"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLoc>(".loc"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveStabs>(".stabs"); // Macro directives. AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacrosOnOff>( @@ -234,15 +247,21 @@ public: AddDirectiveHandler<&GenericAsmParser::ParseDirectiveMacro>(".macro"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endm"); AddDirectiveHandler<&GenericAsmParser::ParseDirectiveEndMacro>(".endmacro"); + + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".sleb128"); + AddDirectiveHandler<&GenericAsmParser::ParseDirectiveLEB128>(".uleb128"); } bool ParseDirectiveFile(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLine(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc); + bool ParseDirectiveStabs(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacrosOnOff(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveMacro(StringRef, SMLoc DirectiveLoc); bool ParseDirectiveEndMacro(StringRef, SMLoc DirectiveLoc); + + bool ParseDirectiveLEB128(StringRef, SMLoc); }; } @@ -251,6 +270,7 @@ namespace llvm { extern MCAsmParserExtension *createDarwinAsmParser(); extern MCAsmParserExtension *createELFAsmParser(); +extern MCAsmParserExtension *createCOFFAsmParser(); } @@ -270,7 +290,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 { @@ -300,30 +323,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; } @@ -334,7 +353,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. @@ -344,35 +363,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(); } @@ -384,26 +399,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(); @@ -463,19 +486,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; + 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; @@ -517,7 +542,7 @@ bool AsmParser::ParsePrimaryExpr(const MCExpr *&Res, SMLoc &EndLoc) { Lex(); // Eat identifier. return false; } - + case AsmToken::LParen: Lex(); // Eat the '('. return ParseParenExpr(Res, EndLoc); @@ -547,8 +572,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. @@ -560,6 +634,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)) @@ -576,7 +675,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; @@ -587,13 +686,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; @@ -601,62 +700,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; } } @@ -668,18 +770,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; @@ -693,9 +795,9 @@ bool AsmParser::ParseBinOpRHS(unsigned Precedence, const MCExpr *&Res, } } - - - + + + /// ParseStatement: /// ::= EndOfStatement /// ::= Label* Directive ...Operands... EndOfStatement @@ -746,18 +848,20 @@ bool AsmParser::ParseStatement() { 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(); @@ -773,10 +877,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)) { @@ -803,27 +907,33 @@ 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); // 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 == ".long") return ParseDirectiveValue(4); if (IDVal == ".quad") return ParseDirectiveValue(8); + if (IDVal == ".single") + return ParseDirectiveRealValue(APFloat::IEEEsingle); + if (IDVal == ".double") + return ParseDirectiveRealValue(APFloat::IEEEdouble); if (IDVal == ".align") { bool IsPow2 = !getContext().getAsmInfo().getAlignmentIsInBytes(); @@ -853,11 +963,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") @@ -874,8 +989,6 @@ bool AsmParser::ParseStatement() { 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") @@ -910,16 +1023,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()) { @@ -937,25 +1050,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, @@ -1084,6 +1189,25 @@ void AsmParser::HandleMacroExit() { ActiveMacros.pop_back(); } +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) { // FIXME: Use better location, we should use proper tokens. SMLoc EqualLoc = Lexer.getLoc(); @@ -1091,7 +1215,9 @@ bool AsmParser::ParseAssignment(StringRef Name) { const MCExpr *Value; if (ParseExpression(Value)) return true; - + + MarkUsed(Value); + if (Lexer.isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in assignment"); @@ -1106,7 +1232,7 @@ 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()) return Error(EqualLoc, "redefinition of '" + Name + "'"); @@ -1115,13 +1241,14 @@ bool AsmParser::ParseAssignment(StringRef 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); @@ -1169,14 +1296,14 @@ bool AsmParser::ParseIdentifier(StringRef &Res) { /// ParseDirectiveSet: /// ::= .set identifier ',' expression -bool AsmParser::ParseDirectiveSet() { +bool AsmParser::ParseDirectiveSet(StringRef IDVal) { 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); @@ -1241,12 +1368,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)) @@ -1262,7 +1391,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(); } } @@ -1275,9 +1404,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; @@ -1289,7 +1419,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"); @@ -1301,9 +1431,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; @@ -1313,7 +1495,7 @@ bool AsmParser::ParseDirectiveSpace() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.space' directive"); Lex(); - + if (ParseAbsoluteExpression(FillExpr)) return true; @@ -1332,9 +1514,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; @@ -1342,7 +1552,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; @@ -1350,14 +1560,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) @@ -1372,6 +1582,8 @@ bool AsmParser::ParseDirectiveFill() { /// ParseDirectiveOrg /// ::= .org expression [ , expression ] bool AsmParser::ParseDirectiveOrg() { + CheckForValidSection(); + const MCExpr *Offset; if (ParseExpression(Offset)) return true; @@ -1382,7 +1594,7 @@ bool AsmParser::ParseDirectiveOrg() { if (getLexer().isNot(AsmToken::Comma)) return TokError("unexpected token in '.org' directive"); Lex(); - + if (ParseAbsoluteExpression(FillExpr)) return true; @@ -1402,6 +1614,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)) @@ -1433,7 +1647,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"); } @@ -1472,12 +1686,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); @@ -1499,7 +1708,7 @@ bool AsmParser::ParseDirectiveSymbolAttribute(MCSymbolAttr Attr) { if (ParseIdentifier(Name)) return TokError("expected identifier in directive"); - + MCSymbol *Sym = getContext().GetOrCreateSymbol(Name); getStreamer().EmitSymbolAttribute(Sym, Attr); @@ -1514,63 +1723,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); @@ -1590,7 +1755,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)) @@ -1598,10 +1763,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 @@ -1660,17 +1825,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)) { @@ -1696,7 +1861,7 @@ bool AsmParser::ParseDirectiveIf(SMLoc DirectiveLoc) { if (getLexer().isNot(AsmToken::EndOfStatement)) return TokError("unexpected token in '.if' directive"); - + Lex(); TheCondState.CondMet = ExprValue; @@ -1729,7 +1894,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; @@ -1743,7 +1908,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 && @@ -1767,7 +1932,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) || @@ -1809,8 +1974,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"); + if (getContext().GetDwarfFile(Filename, FileNumber) == 0) + Error(FileNumberLoc, "file number already allocated"); getStreamer().EmitDwarfFileDirective(FileNumber, Filename); } @@ -1852,7 +2017,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(); @@ -1872,8 +2037,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)) @@ -1904,7 +2070,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"); } @@ -1920,11 +2086,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"); } @@ -1934,11 +2104,19 @@ bool GenericAsmParser::ParseDirectiveLoc(StringRef, SMLoc DirectiveLoc) { } } - getContext().setCurrentDwarfLoc(FileNumber, LineNumber, ColumnPos, Flags,Isa); + getContext().setCurrentDwarfLoc(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 + "'"); +} + /// ParseDirectiveMacrosOnOff /// ::= .macros_on /// ::= .macros_off @@ -2023,6 +2201,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 b0bc5c6..d074ea9 100644 --- a/lib/MC/MCParser/ELFAsmParser.cpp +++ b/lib/MC/MCParser/ELFAsmParser.cpp @@ -8,13 +8,14 @@ //===----------------------------------------------------------------------===// #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" using namespace llvm; namespace { @@ -48,10 +49,15 @@ public: AddDirectiveHandler<&ELFAsmParser::ParseSectionDirectiveEhFrame>(".eh_frame"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSection>(".section"); AddDirectiveHandler<&ELFAsmParser::ParseDirectiveSize>(".size"); - AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".sleb128"); - AddDirectiveHandler<&ELFAsmParser::ParseDirectiveLEB128>(".uleb128"); + AddDirectiveHandler<&ELFAsmParser::ParseDirectivePrevious>(".previous"); + 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, @@ -108,9 +114,16 @@ public: MCSectionELF::SHF_WRITE, SectionKind::getDataRel()); } - bool ParseDirectiveLEB128(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); }; } @@ -148,16 +161,49 @@ bool ELFAsmParser::ParseDirectiveSize(StringRef, SMLoc) { return false; } +bool ELFAsmParser::ParseSectionName(StringRef &SectionName) { + // A section name can contain -, so we cannot just use + // ParseIdentifier. + SMLoc FirstLoc = getLexer().getLoc(); + unsigned Size = 0; + + for (;;) { + StringRef Tmp; + unsigned CurSize; + + SMLoc PrevLoc = getLexer().getLoc(); + if (getLexer().is(AsmToken::Minus)) { + CurSize = 1; + Lex(); // Consume the "-". + } else if (!getParser().ParseIdentifier(Tmp)) + CurSize = Tmp.size(); + else + break; + + Size += CurSize; + SectionName = StringRef(FirstLoc.getPointer(), Size); + + // Make sure the following token is adjacent. + if (PrevLoc.getPointer() + CurSize != getTok().getLoc().getPointer()) + break; + } + if (Size == 0) + return true; + + return false; +} + // 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)) + + if (ParseSectionName(SectionName)) return TokError("expected identifier in directive"); - std::string FlagsStr; + StringRef FlagsStr; StringRef TypeName; int64_t Size = 0; + StringRef GroupName; if (getLexer().is(AsmToken::Comma)) { Lex(); @@ -167,27 +213,46 @@ bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { FlagsStr = getTok().getStringContents(); Lex(); - AsmToken::TokenKind TypeStartToken; - if (getContext().getAsmInfo().getCommentString()[0] == '@') - TypeStartToken = AsmToken::Percent; - else - TypeStartToken = AsmToken::At; + bool Mergeable = FlagsStr.find('M') != StringRef::npos; + bool Group = FlagsStr.find('G') != StringRef::npos; + + 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"); - if (getLexer().is(AsmToken::Comma)) { Lex(); - if (getLexer().is(TypeStartToken)) { + 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().ParseIdentifier(TypeName)) - return TokError("expected identifier in directive"); + 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(); - - if (getParser().ParseAbsoluteExpression(Size)) + StringRef Linkage; + if (getParser().ParseIdentifier(Linkage)) return true; - - if (Size <= 0) - return TokError("section size must be positive"); + if (Linkage != "comdat") + return TokError("Linkage must be 'comdat'"); } } } @@ -197,6 +262,17 @@ bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { return TokError("unexpected token in directive"); unsigned Flags = 0; + unsigned Type = MCSectionELF::SHT_NULL; + + // Set the defaults first. + if (SectionName == ".fini" || SectionName == ".init" || SectionName == ".rodata") { + Type = MCSectionELF::SHT_PROGBITS; + Flags |= MCSectionELF::SHF_ALLOC; + } + if (SectionName == ".fini" || SectionName == ".init") { + Flags |= MCSectionELF::SHF_EXECINSTR; + } + for (unsigned i = 0; i < FlagsStr.size(); i++) { switch (FlagsStr[i]) { case 'a': @@ -223,12 +299,14 @@ bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { case 'd': Flags |= MCSectionELF::XCORE_SHF_DP_SECTION; break; + case 'G': + Flags |= MCSectionELF::SHF_GROUP; + break; default: return TokError("unknown flag"); } } - unsigned Type = MCSectionELF::SHT_NULL; if (!TypeName.empty()) { if (TypeName == "init_array") Type = MCSectionELF::SHT_INIT_ARRAY; @@ -248,28 +326,147 @@ bool ELFAsmParser::ParseDirectiveSection(StringRef, SMLoc) { ? SectionKind::getText() : SectionKind::getDataRel(); 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) + 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; +} + +/// 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 *OldSection = getStreamer().getCurrentSection(); + const MCSection *Comment = + getContext().getELFSection(".comment", MCSectionELF::SHT_PROGBITS, + MCSectionELF::SHF_MERGE | + MCSectionELF::SHF_STRINGS, + SectionKind::getReadOnly(), + 1, ""); + + static bool First = true; + + getStreamer().SwitchSection(Comment); + if (First) + getStreamer().EmitIntValue(0, 1); + First = false; + getStreamer().EmitBytes(Data, 0); + getStreamer().EmitIntValue(0, 1); + getStreamer().SwitchSection(OldSection); + 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; } namespace llvm { diff --git a/lib/MC/MCSectionCOFF.cpp b/lib/MC/MCSectionCOFF.cpp index eb53160..0909df4 100644 --- a/lib/MC/MCSectionCOFF.cpp +++ b/lib/MC/MCSectionCOFF.cpp @@ -74,3 +74,7 @@ void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, } } } + +bool MCSectionCOFF::UseCodeAlign() const { + return getKind().isText(); +} diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp index a7599de..ab72a0e 100644 --- a/lib/MC/MCSectionELF.cpp +++ b/lib/MC/MCSectionELF.cpp @@ -29,14 +29,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 { @@ -84,43 +76,37 @@ void MCSectionELF::PrintSwitchToSection(const MCAsmInfo &MAI, 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 == 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 (EntrySize) { + assert(Flags & MCSectionELF::SHF_MERGE); + OS << "," << EntrySize; } - + OS << '\n'; } +bool MCSectionELF::UseCodeAlign() const { + return getFlags() & MCSectionELF::SHF_EXECINSTR; +} + // 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. @@ -132,4 +118,12 @@ bool MCSectionELF::HasCommonSymbols() const { return false; } - +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 9bf2e66..853d990 100644 --- a/lib/MC/MCSectionMachO.cpp +++ b/lib/MC/MCSectionMachO.cpp @@ -82,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) { @@ -102,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!"); @@ -111,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) { @@ -129,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; @@ -140,15 +140,19 @@ 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); +} + /// StripSpaces - This removes leading and trailing spaces from the StringRef. static void StripSpaces(StringRef &Str) { while (!Str.empty() && isspace(Str[0])) @@ -169,12 +173,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); @@ -183,14 +187,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 " @@ -201,25 +205,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; @@ -236,10 +240,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); @@ -248,14 +252,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('+'); }; @@ -273,15 +277,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 f682721..98667f4 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -9,13 +9,16 @@ #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) { +MCStreamer::MCStreamer(MCContext &Ctx) : Context(Ctx), CurSection(0), + PrevSection(0) { } MCStreamer::~MCStreamer() { @@ -34,6 +37,18 @@ void MCStreamer::EmitIntValue(uint64_t Value, unsigned Size, EmitValue(MCConstantExpr::Create(Value, getContext()), 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) { + EmitULEB128Value(MCConstantExpr::Create(Value, getContext()), 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) { + EmitSLEB128Value(MCConstantExpr::Create(Value, getContext()), AddrSpace); +} + void MCStreamer::EmitSymbolValue(const MCSymbol *Sym, unsigned Size, unsigned AddrSpace) { EmitValue(MCSymbolRefExpr::Create(Sym, getContext()), Size, AddrSpace); 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..41c11fb 100644 --- a/lib/MC/MachObjectWriter.cpp +++ b/lib/MC/MachObjectWriter.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -#include "llvm/MC/MachObjectWriter.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCAssembler.h" @@ -28,6 +27,7 @@ #include <vector> using namespace llvm; +// FIXME: this has been copied from (or to) X86AsmBackend.cpp static unsigned getFixupKindLog2Size(unsigned Kind) { switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); @@ -38,6 +38,7 @@ static unsigned getFixupKindLog2Size(unsigned Kind) { case X86::reloc_pcrel_4byte: 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; } @@ -75,9 +76,89 @@ static bool doesSymbolRequireExternRelocation(MCSymbolData *SD) { return false; } +static bool isScatteredFixupFullyResolved(const MCAssembler &Asm, + 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(&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(&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; +} + +static bool isScatteredFixupFullyResolvedSimple(const MCAssembler &Asm, + 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; +} + namespace { -class MachObjectWriterImpl { +class MachObjectWriter : public MCObjectWriter { // See <mach-o/loader.h>. enum { Header_Magic32 = 0xFEEDFACE, @@ -202,24 +283,17 @@ class MachObjectWriterImpl { /// @} - MachObjectWriter *Writer; - - raw_ostream &OS; - unsigned Is64Bit : 1; -public: - MachObjectWriterImpl(MachObjectWriter *_Writer, bool _Is64Bit) - : Writer(_Writer), OS(Writer->getStream()), Is64Bit(_Is64Bit) { - } + uint32_t CPUType; + uint32_t CPUSubtype; - 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); +public: + MachObjectWriter(raw_ostream &_OS, + bool _Is64Bit, uint32_t _CPUType, uint32_t _CPUSubtype, + bool _IsLittleEndian) + : MCObjectWriter(_OS, _IsLittleEndian), + Is64Bit(_Is64Bit), CPUType(_CPUType), CPUSubtype(_CPUSubtype) { } void WriteHeader(unsigned NumLoadCommands, unsigned LoadCommandsSize, @@ -237,10 +311,9 @@ public: Write32(Is64Bit ? Header_Magic64 : Header_Magic32); - // FIXME: Support cputype. - Write32(Is64Bit ? MachO::CPUTypeX86_64 : MachO::CPUTypeI386); - // FIXME: Support cpusubtype. - Write32(MachO::CPUSubType_I386_ALL); + Write32(CPUType); + Write32(CPUSubtype); + Write32(HFT_Object); Write32(NumLoadCommands); // Object files have a single load command, the // segment. @@ -518,11 +591,11 @@ public: } 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,22 +607,32 @@ 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 += Layout.getSymbolAddress(&A_SD) - + (A_Base == NULL ? 0 : Layout.getSymbolAddress(A_Base)); + Value -= Layout.getSymbolAddress(&B_SD) - + (B_Base == NULL ? 0 : Layout.getSymbolAddress(B_Base)); - Index = A_Base->getIndex(); - IsExtern = 1; + if (A_Base) { + Index = A_Base->getIndex(); + IsExtern = 1; + } + else { + Index = A_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } Type = RIT_X86_64_Unsigned; MachRelocationEntry MRE; @@ -561,13 +644,19 @@ public: (Type << 28)); Relocations[Fragment->getParent()].push_back(MRE); - Index = B_Base->getIndex(); - IsExtern = 1; + if (B_Base) { + Index = B_Base->getIndex(); + IsExtern = 1; + } + else { + Index = B_SD.getFragment()->getParent()->getOrdinal() + 1; + IsExtern = 0; + } Type = 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 @@ -773,7 +862,7 @@ public: } else { FixedValue = 0; } - + // struct relocation_info (8 bytes) MachRelocationEntry MRE; MRE.Word0 = Value; @@ -784,7 +873,7 @@ public: (RIT_TLV << 28)); // Type 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) { @@ -797,11 +886,12 @@ public: 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. @@ -885,7 +975,7 @@ public: // Initialize the section indirect symbol base, if necessary. if (!IndirectSymBase.count(it->SectionData)) IndirectSymBase[it->SectionData] = IndirectIndex; - + Asm.getOrCreateSymbolData(*it->Symbol); } @@ -1037,7 +1127,37 @@ public: UndefinedSymbolData); } - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout) { + + bool IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const { + // If we are using scattered symbols, determine whether this value is + // actually resolved; scattering may cause atoms to move. + if (Asm.getBackend().hasScatteredSymbols()) { + if (Asm.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) + return false; + } + + return isScatteredFixupFullyResolved(Asm, Target, BaseSymbol); + } else { + const MCSection *BaseSection = 0; + if (IsPCRel) + BaseSection = &DF->getParent()->getSection(); + + return isScatteredFixupFullyResolvedSimple(Asm, Target, BaseSection); + } + } + return true; + } + + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout) { unsigned NumSections = Asm.size(); // The section data starts after the header, the segment load command (and @@ -1138,7 +1258,7 @@ public: // Write the actual section data. for (MCAssembler::const_iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) - Asm.WriteSectionData(it, Layout, Writer); + Asm.WriteSectionData(it, Layout, this); // Write the extra padding. WriteZeros(SectionDataPadding); @@ -1198,32 +1318,9 @@ 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(raw_ostream &OS, bool is64Bit, + uint32_t CPUType, + uint32_t CPUSubtype, + bool IsLittleEndian) { + return new MachObjectWriter(OS, is64Bit, CPUType, CPUSubtype, IsLittleEndian); } diff --git a/lib/MC/TargetAsmBackend.cpp b/lib/MC/TargetAsmBackend.cpp index bbfddbe..1f10410 100644 --- a/lib/MC/TargetAsmBackend.cpp +++ b/lib/MC/TargetAsmBackend.cpp @@ -12,7 +12,6 @@ using namespace llvm; TargetAsmBackend::TargetAsmBackend(const Target &T) : TheTarget(T), - HasAbsolutizedSet(false), HasReliableSymbolDifference(false), HasScatteredSymbols(false) { diff --git a/lib/MC/WinCOFFObjectWriter.cpp b/lib/MC/WinCOFFObjectWriter.cpp index eeb2b96..fd79203 100644 --- a/lib/MC/WinCOFFObjectWriter.cpp +++ b/lib/MC/WinCOFFObjectWriter.cpp @@ -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); @@ -172,7 +179,12 @@ public: MCValue Target, uint64_t &FixedValue); - void WriteObject(const MCAssembler &Asm, const MCAsmLayout &Layout); + virtual bool IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const; + + void WriteObject(MCAssembler &Asm, const MCAsmLayout &Layout); }; } @@ -198,9 +210,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 +231,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 +334,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 +357,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 +367,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 +376,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 +410,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 +465,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 +519,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; } //------------------------------------------------------------------------------ @@ -548,7 +618,7 @@ void WinCOFFObjectWriter::WriteRelocation(const COFF::relocation &R) { void WinCOFFObjectWriter::ExecutePostLayoutBinding(MCAssembler &Asm) { // "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,15 +644,20 @@ 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); @@ -600,11 +675,20 @@ 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()) { + switch ((unsigned)Fixup.getKind()) { case X86::reloc_pcrel_4byte: case X86::reloc_riprel_4byte: case X86::reloc_riprel_4byte_movq_load: @@ -615,6 +699,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 +716,49 @@ void WinCOFFObjectWriter::RecordRelocation(const MCAssembler &Asm, coff_section->Relocations.push_back(Reloc); } -void WinCOFFObjectWriter::WriteObject(const MCAssembler &Asm, +bool WinCOFFObjectWriter::IsFixupFullyResolved(const MCAssembler &Asm, + const MCValue Target, + bool IsPCRel, + const MCFragment *DF) const { + // If this is a PCrel relocation, find the section this fixup value is + // relative to. + const MCSection *BaseSection = 0; + if (IsPCRel) { + BaseSection = &DF->getParent()->getSection(); + assert(BaseSection); + } + + const MCSection *SectionA = 0; + const MCSymbol *SymbolA = 0; + if (const MCSymbolRefExpr *A = Target.getSymA()) { + SymbolA = &A->getSymbol(); + SectionA = &SymbolA->getSection(); + } + + const MCSection *SectionB = 0; + if (const MCSymbolRefExpr *B = Target.getSymB()) { + SectionB = &B->getSymbol().getSection(); + } + + if (!BaseSection) + return SectionA == SectionB; + + return !SectionB && BaseSection == SectionA; +} + +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.getSectionSize((*i)->MCData) > 0) { + MakeSectionReal(**i, ++Header.NumberOfSections); + } else { + (*i)->Number = -1; + } + } Header.NumberOfSymbols = 0; @@ -641,32 +766,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 +803,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 +829,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,11 +859,16 @@ 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!"); @@ -759,7 +895,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..3c5a3be 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); @@ -78,6 +80,48 @@ public: 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. @@ -85,7 +129,7 @@ WinCOFFStreamer::WinCOFFStreamer(MCContext &Context, TargetAsmBackend &TAB, MCCodeEmitter &CE, raw_ostream &OS) - : MCObjectStreamer(Context, TAB, OS, &CE) + : MCObjectStreamer(Context, TAB, OS, &CE, true) , CurSymbol(NULL) { } @@ -126,6 +170,13 @@ 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? @@ -152,21 +203,65 @@ 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 +279,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 +318,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); } |