diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 17:57:32 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-10-14 17:57:32 +0000 |
commit | cd749a9c07f1de2fb8affde90537efa4bc3e7c54 (patch) | |
tree | b21f6de4e08b89bb7931806bab798fc2a5e3a686 /lib/MC | |
parent | 72621d11de5b873f1695f391eb95f0b336c3d2d4 (diff) | |
download | FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.zip FreeBSD-src-cd749a9c07f1de2fb8affde90537efa4bc3e7c54.tar.gz |
Update llvm to r84119.
Diffstat (limited to 'lib/MC')
-rw-r--r-- | lib/MC/CMakeLists.txt | 19 | ||||
-rw-r--r-- | lib/MC/MCAsmInfo.cpp | 107 | ||||
-rw-r--r-- | lib/MC/MCAsmInfoCOFF.cpp | 37 | ||||
-rw-r--r-- | lib/MC/MCAsmInfoDarwin.cpp | 52 | ||||
-rw-r--r-- | lib/MC/MCAsmLexer.cpp | 23 | ||||
-rw-r--r-- | lib/MC/MCAsmParser.cpp | 18 | ||||
-rw-r--r-- | lib/MC/MCAsmStreamer.cpp | 311 | ||||
-rw-r--r-- | lib/MC/MCAssembler.cpp | 1190 | ||||
-rw-r--r-- | lib/MC/MCCodeEmitter.cpp | 18 | ||||
-rw-r--r-- | lib/MC/MCContext.cpp | 33 | ||||
-rw-r--r-- | lib/MC/MCDisassembler.cpp | 14 | ||||
-rw-r--r-- | lib/MC/MCExpr.cpp | 286 | ||||
-rw-r--r-- | lib/MC/MCInst.cpp | 50 | ||||
-rw-r--r-- | lib/MC/MCInstPrinter.cpp | 14 | ||||
-rw-r--r-- | lib/MC/MCMachOStreamer.cpp | 379 | ||||
-rw-r--r-- | lib/MC/MCNullStreamer.cpp | 70 | ||||
-rw-r--r-- | lib/MC/MCSection.cpp | 45 | ||||
-rw-r--r-- | lib/MC/MCSectionELF.cpp | 138 | ||||
-rw-r--r-- | lib/MC/MCSectionMachO.cpp | 271 | ||||
-rw-r--r-- | lib/MC/MCStreamer.cpp | 2 | ||||
-rw-r--r-- | lib/MC/MCSymbol.cpp | 110 | ||||
-rw-r--r-- | lib/MC/MCValue.cpp | 34 | ||||
-rw-r--r-- | lib/MC/TargetAsmParser.cpp | 19 |
23 files changed, 3100 insertions, 140 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 6307ffe..8a1a058 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -1,5 +1,24 @@ add_llvm_library(LLVMMC + MCAsmInfo.cpp + MCAsmInfoCOFF.cpp + MCAsmInfoDarwin.cpp + MCAsmLexer.cpp + MCAsmParser.cpp MCAsmStreamer.cpp + MCAssembler.cpp + MCCodeEmitter.cpp MCContext.cpp + MCDisassembler.cpp + MCExpr.cpp + MCInst.cpp + MCInstPrinter.cpp + MCMachOStreamer.cpp + MCNullStreamer.cpp + MCSection.cpp + MCSectionELF.cpp + MCSectionMachO.cpp MCStreamer.cpp + MCSymbol.cpp + MCValue.cpp + TargetAsmParser.cpp ) diff --git a/lib/MC/MCAsmInfo.cpp b/lib/MC/MCAsmInfo.cpp new file mode 100644 index 0000000..74fb930 --- /dev/null +++ b/lib/MC/MCAsmInfo.cpp @@ -0,0 +1,107 @@ +//===-- MCAsmInfo.cpp - Asm Info -------------------------------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines target asm properties related what form asm statements +// should take. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/DataTypes.h" +#include <cctype> +#include <cstring> +using namespace llvm; + +MCAsmInfo::MCAsmInfo() { + ZeroFillDirective = 0; + NonexecutableStackDirective = 0; + NeedsSet = false; + MaxInstLength = 4; + PCSymbol = "$"; + SeparatorChar = ';'; + CommentColumn = 60; + CommentString = "#"; + GlobalPrefix = ""; + PrivateGlobalPrefix = "."; + LinkerPrivateGlobalPrefix = ""; + InlineAsmStart = "APP"; + InlineAsmEnd = "NO_APP"; + AssemblerDialect = 0; + AllowQuotesInName = false; + AllowNameToStartWithDigit = false; + ZeroDirective = "\t.zero\t"; + ZeroDirectiveSuffix = 0; + AsciiDirective = "\t.ascii\t"; + AscizDirective = "\t.asciz\t"; + Data8bitsDirective = "\t.byte\t"; + Data16bitsDirective = "\t.short\t"; + Data32bitsDirective = "\t.long\t"; + Data64bitsDirective = "\t.quad\t"; + SunStyleELFSectionSwitchSyntax = false; + UsesELFSectionDirectiveForBSS = false; + AlignDirective = "\t.align\t"; + AlignmentIsInBytes = true; + TextAlignFillValue = 0; + JumpTableDirective = 0; + PICJumpTableDirective = 0; + GlobalDirective = "\t.globl\t"; + SetDirective = 0; + LCOMMDirective = 0; + COMMDirective = "\t.comm\t"; + COMMDirectiveTakesAlignment = true; + HasDotTypeDotSizeDirective = true; + HasSingleParameterDotFile = true; + UsedDirective = 0; + WeakRefDirective = 0; + WeakDefDirective = 0; + // FIXME: These are ELFish - move to ELFMAI. + HiddenDirective = "\t.hidden\t"; + ProtectedDirective = "\t.protected\t"; + AbsoluteDebugSectionOffsets = false; + AbsoluteEHSectionOffsets = false; + HasLEB128 = false; + HasDotLocAndDotFile = false; + SupportsDebugInformation = false; + ExceptionsType = ExceptionHandling::None; + DwarfRequiresFrameSection = true; + DwarfUsesInlineInfoSection = false; + Is_EHSymbolPrivate = true; + GlobalEHDirective = 0; + SupportsWeakOmittedEHFrame = true; + DwarfSectionOffsetDirective = 0; + + AsmTransCBE = 0; +} + +MCAsmInfo::~MCAsmInfo() { +} + + +unsigned MCAsmInfo::getULEB128Size(unsigned Value) { + unsigned Size = 0; + do { + Value >>= 7; + Size += sizeof(int8_t); + } while (Value); + return Size; +} + +unsigned MCAsmInfo::getSLEB128Size(int Value) { + unsigned Size = 0; + int Sign = Value >> (8 * sizeof(Value) - 1); + bool IsMore; + + do { + unsigned Byte = Value & 0x7f; + Value >>= 7; + IsMore = Value != Sign || ((Byte ^ Sign) & 0x40) != 0; + Size += sizeof(int8_t); + } while (IsMore); + return Size; +} diff --git a/lib/MC/MCAsmInfoCOFF.cpp b/lib/MC/MCAsmInfoCOFF.cpp new file mode 100644 index 0000000..23b0dd7 --- /dev/null +++ b/lib/MC/MCAsmInfoCOFF.cpp @@ -0,0 +1,37 @@ +//===-- MCAsmInfoCOFF.cpp - COFF asm properties -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines target asm properties related what form asm statements +// should take in general on COFF-based targets +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoCOFF.h" +#include "llvm/ADT/SmallVector.h" +using namespace llvm; + +MCAsmInfoCOFF::MCAsmInfoCOFF() { + GlobalPrefix = "_"; + LCOMMDirective = "\t.lcomm\t"; + COMMDirectiveTakesAlignment = false; + HasDotTypeDotSizeDirective = false; + HasSingleParameterDotFile = false; + HiddenDirective = NULL; + PrivateGlobalPrefix = "L"; // Prefix for private global symbols + WeakRefDirective = "\t.weak\t"; + SetDirective = "\t.set\t"; + + // Set up DWARF directives + HasLEB128 = true; // Target asm supports leb128 directives (little-endian) + AbsoluteDebugSectionOffsets = true; + AbsoluteEHSectionOffsets = false; + SupportsDebugInformation = true; + DwarfSectionOffsetDirective = "\t.secrel32\t"; +} + diff --git a/lib/MC/MCAsmInfoDarwin.cpp b/lib/MC/MCAsmInfoDarwin.cpp new file mode 100644 index 0000000..d99120d --- /dev/null +++ b/lib/MC/MCAsmInfoDarwin.cpp @@ -0,0 +1,52 @@ +//===-- MCAsmInfoDarwin.cpp - Darwin asm properties -------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines target asm properties related what form asm statements +// should take in general on Darwin-based targets +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmInfoDarwin.h" +using namespace llvm; + +MCAsmInfoDarwin::MCAsmInfoDarwin() { + // Common settings for all Darwin targets. + // Syntax: + GlobalPrefix = "_"; + PrivateGlobalPrefix = "L"; + LinkerPrivateGlobalPrefix = "l"; + NeedsSet = true; + AllowQuotesInName = true; + HasSingleParameterDotFile = false; + + AlignmentIsInBytes = false; + InlineAsmStart = " InlineAsm Start"; + InlineAsmEnd = " InlineAsm End"; + + // Directives: + WeakDefDirective = "\t.weak_definition "; + WeakRefDirective = "\t.weak_reference "; + HiddenDirective = "\t.private_extern "; + LCOMMDirective = "\t.lcomm\t"; + ZeroDirective = "\t.space\t"; // ".space N" emits N zeros. + ZeroFillDirective = "\t.zerofill\t"; // Uses .zerofill + SetDirective = "\t.set"; + ProtectedDirective = "\t.globl\t"; + HasDotTypeDotSizeDirective = false; + UsedDirective = "\t.no_dead_strip\t"; + + // _foo.eh symbols are currently always exported so that the linker knows + // about them. This is not necessary on 10.6 and later, but it + // doesn't hurt anything. + // FIXME: I need to get this from Triple. + Is_EHSymbolPrivate = false; + GlobalEHDirective = "\t.globl\t"; + SupportsWeakOmittedEHFrame = false; +} + diff --git a/lib/MC/MCAsmLexer.cpp b/lib/MC/MCAsmLexer.cpp new file mode 100644 index 0000000..1e34ed6 --- /dev/null +++ b/lib/MC/MCAsmLexer.cpp @@ -0,0 +1,23 @@ +//===-- MCAsmLexer.cpp - Abstract Asm Lexer Interface ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmLexer.h" +#include "llvm/Support/SourceMgr.h" + +using namespace llvm; + +MCAsmLexer::MCAsmLexer() : CurTok(AsmToken::Error, StringRef()) { +} + +MCAsmLexer::~MCAsmLexer() { +} + +SMLoc AsmToken::getLoc() const { + return SMLoc::getFromPointer(Str.data()); +} diff --git a/lib/MC/MCAsmParser.cpp b/lib/MC/MCAsmParser.cpp new file mode 100644 index 0000000..2287e89 --- /dev/null +++ b/lib/MC/MCAsmParser.cpp @@ -0,0 +1,18 @@ +//===-- MCAsmParser.cpp - Abstract Asm Parser Interface -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCAsmParser.h" + +using namespace llvm; + +MCAsmParser::MCAsmParser() { +} + +MCAsmParser::~MCAsmParser() { +} diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 7d94464..e56e968 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -8,118 +8,121 @@ //===----------------------------------------------------------------------===// #include "llvm/MC/MCStreamer.h" - +#include "llvm/ADT/SmallString.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; namespace { - class MCAsmStreamer : public MCStreamer { - raw_ostream &OS; +class MCAsmStreamer : public MCStreamer { + raw_ostream &OS; + const MCAsmInfo &MAI; + MCInstPrinter *InstPrinter; + MCCodeEmitter *Emitter; +public: + MCAsmStreamer(MCContext &Context, raw_ostream &_OS, const MCAsmInfo &tai, + MCInstPrinter *_Printer, MCCodeEmitter *_Emitter) + : MCStreamer(Context), OS(_OS), MAI(tai), InstPrinter(_Printer), + Emitter(_Emitter) {} + ~MCAsmStreamer() {} - MCSection *CurSection; + /// @name MCStreamer Interface + /// @{ - public: - MCAsmStreamer(MCContext &Context, raw_ostream &_OS) - : MCStreamer(Context), OS(_OS), CurSection(0) {} - ~MCAsmStreamer() {} + virtual void SwitchSection(const MCSection *Section); - /// @name MCStreamer Interface - /// @{ + virtual void EmitLabel(MCSymbol *Symbol); - virtual void SwitchSection(MCSection *Section); + virtual void EmitAssemblerFlag(AssemblerFlag Flag); - virtual void EmitLabel(MCSymbol *Symbol); + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); - virtual void EmitAssignment(MCSymbol *Symbol, const MCValue &Value, - bool MakeAbsolute = false); + virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); - virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); - virtual void EmitBytes(const char *Data, unsigned Length); + virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned ByteAlignment); - virtual void EmitValue(const MCValue &Value, unsigned Size); + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0); - virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, - unsigned ValueSize = 1, - unsigned MaxBytesToEmit = 0); + virtual void EmitBytes(const StringRef &Data); - virtual void EmitValueToOffset(const MCValue &Offset, - unsigned char Value = 0); - - virtual void EmitInstruction(const MCInst &Inst); + virtual void EmitValue(const MCExpr *Value, unsigned Size); - virtual void Finish(); - - /// @} - }; - -} - -/// Allow printing values directly to a raw_ostream. -static inline raw_ostream &operator<<(raw_ostream &os, const MCValue &Value) { - if (Value.getSymA()) { - os << Value.getSymA()->getName(); - if (Value.getSymB()) - os << " - " << Value.getSymB()->getName(); - if (Value.getConstant()) - os << " + " << Value.getConstant(); - } else { - assert(!Value.getSymB() && "Invalid machine code value!"); - os << Value.getConstant(); - } + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); - return os; -} + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + + virtual void EmitInstruction(const MCInst &Inst); + + virtual void Finish(); + + /// @} +}; + +} // end anonymous namespace. static inline int64_t truncateToSize(int64_t Value, unsigned Bytes) { assert(Bytes && "Invalid size!"); return Value & ((uint64_t) (int64_t) -1 >> (64 - Bytes * 8)); } -static inline MCValue truncateToSize(const MCValue &Value, unsigned Bytes) { - return MCValue::get(Value.getSymA(), Value.getSymB(), - truncateToSize(Value.getConstant(), Bytes)); +static inline const MCExpr *truncateToSize(const MCExpr *Value, + unsigned Bytes) { + // FIXME: Do we really need this routine? + return Value; } -void MCAsmStreamer::SwitchSection(MCSection *Section) { +void MCAsmStreamer::SwitchSection(const MCSection *Section) { + assert(Section && "Cannot switch to a null section!"); if (Section != CurSection) { CurSection = Section; - - // FIXME: Really we would like the segment, flags, etc. to be separate - // values instead of embedded in the name. Not all assemblers understand all - // this stuff though. - OS << ".section " << Section->getName() << "\n"; + Section->PrintSwitchToSection(MAI, OS); } } void MCAsmStreamer::EmitLabel(MCSymbol *Symbol) { - assert(Symbol->getSection() == 0 && "Cannot emit a symbol twice!"); + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(CurSection && "Cannot emit before setting section!"); - assert(!getContext().GetSymbolValue(Symbol) && - "Cannot emit symbol which was directly assigned to!"); - OS << Symbol->getName() << ":\n"; - Symbol->setSection(CurSection); - Symbol->setExternal(false); + Symbol->print(OS, &MAI); + OS << ":\n"; + Symbol->setSection(*CurSection); } -void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCValue &Value, - bool MakeAbsolute) { - assert(!Symbol->getSection() && "Cannot assign to a label!"); - - if (MakeAbsolute) { - OS << ".set " << Symbol->getName() << ", " << Value << '\n'; - } else { - OS << Symbol->getName() << " = " << Value << '\n'; +void MCAsmStreamer::EmitAssemblerFlag(AssemblerFlag Flag) { + switch (Flag) { + default: assert(0 && "Invalid flag!"); + case SubsectionsViaSymbols: OS << ".subsections_via_symbols"; break; } + OS << '\n'; +} - getContext().SetSymbolValue(Symbol, Value); +void MCAsmStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // Only absolute symbols can be redefined. + assert((Symbol->isUndefined() || Symbol->isAbsolute()) && + "Cannot define a symbol twice!"); + + Symbol->print(OS, &MAI); + OS << " = "; + Value->print(OS, &MAI); + OS << '\n'; } void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, @@ -139,93 +142,165 @@ void MCAsmStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case WeakReference: OS << ".weak_reference"; break; } - OS << ' ' << Symbol->getName() << '\n'; + OS << ' '; + Symbol->print(OS, &MAI); + OS << '\n'; +} + +void MCAsmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + OS << ".desc" << ' '; + Symbol->print(OS, &MAI); + OS << ',' << DescValue << '\n'; +} + +void MCAsmStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned ByteAlignment) { + OS << ".comm "; + Symbol->print(OS, &MAI); + OS << ',' << Size; + if (ByteAlignment != 0) + OS << ',' << Log2_32(ByteAlignment); + OS << '\n'; } -void MCAsmStreamer::EmitBytes(const char *Data, unsigned Length) { +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->print(OS, &MAI); + OS << ',' << Size; + if (ByteAlignment != 0) + OS << ',' << Log2_32(ByteAlignment); + } + OS << '\n'; +} + +void MCAsmStreamer::EmitBytes(const StringRef &Data) { assert(CurSection && "Cannot emit contents before setting section!"); - for (unsigned i = 0; i != Length; ++i) - OS << ".byte " << (unsigned) Data[i] << '\n'; + for (unsigned i = 0, e = Data.size(); i != e; ++i) + OS << ".byte " << (unsigned) (unsigned char) Data[i] << '\n'; } -void MCAsmStreamer::EmitValue(const MCValue &Value, unsigned Size) { +void MCAsmStreamer::EmitValue(const MCExpr *Value, unsigned Size) { assert(CurSection && "Cannot emit contents before setting section!"); // Need target hooks to know how to print this. switch (Size) { default: - assert(0 && "Invalid size for machine code value!"); + llvm_unreachable("Invalid size for machine code value!"); case 1: OS << ".byte"; break; case 2: OS << ".short"; break; case 4: OS << ".long"; break; case 8: OS << ".quad"; break; } - OS << ' ' << truncateToSize(Value, Size) << '\n'; + OS << ' '; + truncateToSize(Value, Size)->print(OS, &MAI); + OS << '\n'; } void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { - // Some assemblers don't support .balign, so we always emit as .p2align if - // this is a power of two. Otherwise we assume the client knows the target - // supports .balign and use that. - unsigned Pow2 = Log2_32(ByteAlignment); - bool IsPow2 = (1U << Pow2) == ByteAlignment; - + // Some assemblers don't support non-power of two alignments, so we always + // emit alignments as a power of two if possible. + if (isPowerOf2_32(ByteAlignment)) { + switch (ValueSize) { + default: llvm_unreachable("Invalid size for machine code value!"); + case 1: OS << MAI.getAlignDirective(); break; + // FIXME: use MAI for this! + case 2: OS << ".p2alignw "; break; + case 4: OS << ".p2alignl "; break; + case 8: llvm_unreachable("Unsupported alignment size!"); + } + + if (MAI.getAlignmentIsInBytes()) + OS << ByteAlignment; + else + OS << Log2_32(ByteAlignment); + + if (Value || MaxBytesToEmit) { + OS << ", 0x"; + OS.write_hex(truncateToSize(Value, ValueSize)); + + if (MaxBytesToEmit) + OS << ", " << MaxBytesToEmit; + } + OS << '\n'; + return; + } + + // Non-power of two alignment. This is not widely supported by assemblers. + // FIXME: Parameterize this based on MAI. switch (ValueSize) { - default: - assert(0 && "Invalid size for machine code value!"); - case 8: - assert(0 && "Unsupported alignment size!"); - case 1: OS << (IsPow2 ? ".p2align" : ".balign"); break; - case 2: OS << (IsPow2 ? ".p2alignw" : ".balignw"); break; - case 4: OS << (IsPow2 ? ".p2alignl" : ".balignl"); break; + default: llvm_unreachable("Invalid size for machine code value!"); + case 1: OS << ".balign"; break; + case 2: OS << ".balignw"; break; + case 4: OS << ".balignl"; break; + case 8: llvm_unreachable("Unsupported alignment size!"); } - OS << ' ' << (IsPow2 ? Pow2 : ByteAlignment); - + OS << ' ' << ByteAlignment; OS << ", " << truncateToSize(Value, ValueSize); if (MaxBytesToEmit) OS << ", " << MaxBytesToEmit; OS << '\n'; } -void MCAsmStreamer::EmitValueToOffset(const MCValue &Offset, +void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, unsigned char Value) { // FIXME: Verify that Offset is associated with the current section. - OS << ".org " << Offset << ", " << (unsigned) Value << '\n'; -} - -static raw_ostream &operator<<(raw_ostream &OS, const MCOperand &Op) { - if (Op.isReg()) - return OS << "reg:" << Op.getReg(); - if (Op.isImm()) - return OS << "imm:" << Op.getImm(); - if (Op.isMBBLabel()) - return OS << "mbblabel:(" - << Op.getMBBLabelFunction() << ", " << Op.getMBBLabelBlock(); - assert(Op.isMCValue() && "Invalid operand!"); - return OS << "val:" << Op.getMCValue(); + OS << ".org "; + Offset->print(OS, &MAI); + OS << ", " << (unsigned) Value << '\n'; } void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { assert(CurSection && "Cannot emit contents before setting section!"); - // FIXME: Implement proper printing. - OS << "MCInst(" - << "opcode=" << Inst.getOpcode() << ", " - << "operands=["; - for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) { - if (i) - OS << ", "; - OS << Inst.getOperand(i); + + // If we have an AsmPrinter, use that to print. + if (InstPrinter) { + InstPrinter->printInst(&Inst); + OS << '\n'; + + // Show the encoding if we have a code emitter. + if (Emitter) { + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + Emitter->EncodeInstruction(Inst, VecOS); + VecOS.flush(); + + OS.indent(20); + OS << " # encoding: ["; + for (unsigned i = 0, e = Code.size(); i != e; ++i) { + if (i) + OS << ','; + OS << format("%#04x", uint8_t(Code[i])); + } + OS << "]\n"; + } + + return; } - OS << "])\n"; + + // Otherwise fall back to a structural printing for now. Eventually we should + // always have access to the target specific printer. + Inst.print(OS, &MAI); + OS << '\n'; } void MCAsmStreamer::Finish() { OS.flush(); } -MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS) { - return new MCAsmStreamer(Context, OS); +MCStreamer *llvm::createAsmStreamer(MCContext &Context, raw_ostream &OS, + const MCAsmInfo &MAI, MCInstPrinter *IP, + MCCodeEmitter *CE) { + return new MCAsmStreamer(Context, OS, MAI, IP, CE); } diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp new file mode 100644 index 0000000..0afdf98 --- /dev/null +++ b/lib/MC/MCAssembler.cpp @@ -0,0 +1,1190 @@ +//===- lib/MC/MCAssembler.cpp - Assembler Backend Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#define DEBUG_TYPE "assembler" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/Target/TargetMachOWriterInfo.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <vector> +using namespace llvm; + +class MachObjectWriter; + +STATISTIC(EmittedFragments, "Number of emitted assembler fragments"); + +// FIXME FIXME FIXME: There are number of places in this file where we convert +// what is a 64-bit assembler value used for computation into a value in the +// object file, which may truncate it. We should detect that truncation where +// invalid and report errors back. + +static void WriteFileData(raw_ostream &OS, const MCSectionData &SD, + MachObjectWriter &MOW); + +/// isVirtualSection - Check if this is a section which does not actually exist +/// in the object file. +static bool isVirtualSection(const MCSection &Section) { + // FIXME: Lame. + const MCSectionMachO &SMO = static_cast<const MCSectionMachO&>(Section); + unsigned Type = SMO.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; + return (Type == MCSectionMachO::S_ZEROFILL); +} + +class MachObjectWriter { + // See <mach-o/loader.h>. + enum { + Header_Magic32 = 0xFEEDFACE, + Header_Magic64 = 0xFEEDFACF + }; + + static const unsigned Header32Size = 28; + static const unsigned Header64Size = 32; + static const unsigned SegmentLoadCommand32Size = 56; + static const unsigned Section32Size = 68; + static const unsigned SymtabLoadCommandSize = 24; + static const unsigned DysymtabLoadCommandSize = 80; + static const unsigned Nlist32Size = 12; + static const unsigned RelocationInfoSize = 8; + + enum HeaderFileType { + HFT_Object = 0x1 + }; + + enum HeaderFlags { + HF_SubsectionsViaSymbols = 0x2000 + }; + + enum LoadCommandType { + LCT_Segment = 0x1, + LCT_Symtab = 0x2, + LCT_Dysymtab = 0xb + }; + + // See <mach-o/nlist.h>. + enum SymbolTypeType { + STT_Undefined = 0x00, + STT_Absolute = 0x02, + STT_Section = 0x0e + }; + + enum SymbolTypeFlags { + // If any of these bits are set, then the entry is a stab entry number (see + // <mach-o/stab.h>. Otherwise the other masks apply. + STF_StabsEntryMask = 0xe0, + + STF_TypeMask = 0x0e, + STF_External = 0x01, + STF_PrivateExtern = 0x10 + }; + + /// IndirectSymbolFlags - Flags for encoding special values in the indirect + /// symbol entry. + enum IndirectSymbolFlags { + ISF_Local = 0x80000000, + ISF_Absolute = 0x40000000 + }; + + /// RelocationFlags - Special flags for addresses. + enum RelocationFlags { + RF_Scattered = 0x80000000 + }; + + enum RelocationInfoType { + RIT_Vanilla = 0, + RIT_Pair = 1, + RIT_Difference = 2, + RIT_PreboundLazyPointer = 3, + RIT_LocalDifference = 4 + }; + + /// MachSymbolData - Helper struct for containing some precomputed information + /// on symbols. + struct MachSymbolData { + MCSymbolData *SymbolData; + uint64_t StringIndex; + uint8_t SectionIndex; + + // Support lexicographic sorting. + bool operator<(const MachSymbolData &RHS) const { + const std::string &Name = SymbolData->getSymbol().getName(); + return Name < RHS.SymbolData->getSymbol().getName(); + } + }; + + raw_ostream &OS; + bool IsLSB; + +public: + MachObjectWriter(raw_ostream &_OS, bool _IsLSB = true) + : OS(_OS), IsLSB(_IsLSB) { + } + + /// @name Helper Methods + /// @{ + + void Write8(uint8_t Value) { + OS << char(Value); + } + + void Write16(uint16_t Value) { + if (IsLSB) { + Write8(uint8_t(Value >> 0)); + Write8(uint8_t(Value >> 8)); + } else { + Write8(uint8_t(Value >> 8)); + Write8(uint8_t(Value >> 0)); + } + } + + void Write32(uint32_t Value) { + if (IsLSB) { + Write16(uint16_t(Value >> 0)); + Write16(uint16_t(Value >> 16)); + } else { + Write16(uint16_t(Value >> 16)); + Write16(uint16_t(Value >> 0)); + } + } + + void Write64(uint64_t Value) { + if (IsLSB) { + Write32(uint32_t(Value >> 0)); + Write32(uint32_t(Value >> 32)); + } else { + Write32(uint32_t(Value >> 32)); + Write32(uint32_t(Value >> 0)); + } + } + + void WriteZeros(unsigned N) { + const char Zeros[16] = { 0 }; + + for (unsigned i = 0, e = N / 16; i != e; ++i) + OS << StringRef(Zeros, 16); + + OS << StringRef(Zeros, N % 16); + } + + void WriteString(const StringRef &Str, unsigned ZeroFillSize = 0) { + OS << Str; + if (ZeroFillSize) + WriteZeros(ZeroFillSize - Str.size()); + } + + /// @} + + void WriteHeader32(unsigned NumLoadCommands, unsigned LoadCommandsSize, + bool SubsectionsViaSymbols) { + uint32_t Flags = 0; + + if (SubsectionsViaSymbols) + Flags |= HF_SubsectionsViaSymbols; + + // struct mach_header (28 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + Write32(Header_Magic32); + + // FIXME: Support cputype. + Write32(TargetMachOWriterInfo::HDR_CPU_TYPE_I386); + // FIXME: Support cpusubtype. + Write32(TargetMachOWriterInfo::HDR_CPU_SUBTYPE_I386_ALL); + Write32(HFT_Object); + Write32(NumLoadCommands); // Object files have a single load command, the + // segment. + Write32(LoadCommandsSize); + Write32(Flags); + + assert(OS.tell() - Start == Header32Size); + } + + /// WriteSegmentLoadCommand32 - Write a 32-bit segment load command. + /// + /// \arg NumSections - The number of sections in this segment. + /// \arg SectionDataSize - The total size of the sections. + void WriteSegmentLoadCommand32(unsigned NumSections, + uint64_t VMSize, + uint64_t SectionDataStartOffset, + uint64_t SectionDataSize) { + // struct segment_command (56 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + Write32(LCT_Segment); + Write32(SegmentLoadCommand32Size + NumSections * Section32Size); + + WriteString("", 16); + Write32(0); // vmaddr + Write32(VMSize); // vmsize + Write32(SectionDataStartOffset); // file offset + Write32(SectionDataSize); // file size + Write32(0x7); // maxprot + Write32(0x7); // initprot + Write32(NumSections); + Write32(0); // flags + + assert(OS.tell() - Start == SegmentLoadCommand32Size); + } + + void WriteSection32(const MCSectionData &SD, uint64_t FileOffset, + uint64_t RelocationsStart, unsigned NumRelocations) { + // The offset is unused for virtual sections. + if (isVirtualSection(SD.getSection())) { + assert(SD.getFileSize() == 0 && "Invalid file size!"); + FileOffset = 0; + } + + // struct section (68 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + // FIXME: cast<> support! + const MCSectionMachO &Section = + static_cast<const MCSectionMachO&>(SD.getSection()); + WriteString(Section.getSectionName(), 16); + WriteString(Section.getSegmentName(), 16); + Write32(SD.getAddress()); // address + Write32(SD.getSize()); // size + Write32(FileOffset); + + assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); + Write32(Log2_32(SD.getAlignment())); + Write32(NumRelocations ? RelocationsStart : 0); + Write32(NumRelocations); + Write32(Section.getTypeAndAttributes()); + Write32(0); // reserved1 + Write32(Section.getStubSize()); // reserved2 + + assert(OS.tell() - Start == Section32Size); + } + + void WriteSymtabLoadCommand(uint32_t SymbolOffset, uint32_t NumSymbols, + uint32_t StringTableOffset, + uint32_t StringTableSize) { + // struct symtab_command (24 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + Write32(LCT_Symtab); + Write32(SymtabLoadCommandSize); + Write32(SymbolOffset); + Write32(NumSymbols); + Write32(StringTableOffset); + Write32(StringTableSize); + + assert(OS.tell() - Start == SymtabLoadCommandSize); + } + + void WriteDysymtabLoadCommand(uint32_t FirstLocalSymbol, + uint32_t NumLocalSymbols, + uint32_t FirstExternalSymbol, + uint32_t NumExternalSymbols, + uint32_t FirstUndefinedSymbol, + uint32_t NumUndefinedSymbols, + uint32_t IndirectSymbolOffset, + uint32_t NumIndirectSymbols) { + // struct dysymtab_command (80 bytes) + + uint64_t Start = OS.tell(); + (void) Start; + + Write32(LCT_Dysymtab); + Write32(DysymtabLoadCommandSize); + Write32(FirstLocalSymbol); + Write32(NumLocalSymbols); + Write32(FirstExternalSymbol); + Write32(NumExternalSymbols); + Write32(FirstUndefinedSymbol); + Write32(NumUndefinedSymbols); + Write32(0); // tocoff + Write32(0); // ntoc + Write32(0); // modtaboff + Write32(0); // nmodtab + Write32(0); // extrefsymoff + Write32(0); // nextrefsyms + Write32(IndirectSymbolOffset); + Write32(NumIndirectSymbols); + Write32(0); // extreloff + Write32(0); // nextrel + Write32(0); // locreloff + Write32(0); // nlocrel + + assert(OS.tell() - Start == DysymtabLoadCommandSize); + } + + void WriteNlist32(MachSymbolData &MSD) { + MCSymbolData &Data = *MSD.SymbolData; + const MCSymbol &Symbol = Data.getSymbol(); + uint8_t Type = 0; + uint16_t Flags = Data.getFlags(); + uint32_t Address = 0; + + // Set the N_TYPE bits. See <mach-o/nlist.h>. + // + // FIXME: Are the prebound or indirect fields possible here? + if (Symbol.isUndefined()) + Type = STT_Undefined; + else if (Symbol.isAbsolute()) + Type = STT_Absolute; + else + Type = STT_Section; + + // FIXME: Set STAB bits. + + if (Data.isPrivateExtern()) + Type |= STF_PrivateExtern; + + // Set external bit. + if (Data.isExternal() || Symbol.isUndefined()) + Type |= STF_External; + + // Compute the symbol address. + if (Symbol.isDefined()) { + if (Symbol.isAbsolute()) { + llvm_unreachable("FIXME: Not yet implemented!"); + } else { + Address = Data.getFragment()->getAddress() + Data.getOffset(); + } + } else if (Data.isCommon()) { + // Common symbols are encoded with the size in the address + // field, and their alignment in the flags. + Address = Data.getCommonSize(); + + // Common alignment is packed into the 'desc' bits. + if (unsigned Align = Data.getCommonAlignment()) { + unsigned Log2Size = Log2_32(Align); + assert((1U << Log2Size) == Align && "Invalid 'common' alignment!"); + if (Log2Size > 15) + llvm_report_error("invalid 'common' alignment '" + + Twine(Align) + "'"); + // FIXME: Keep this mask with the SymbolFlags enumeration. + Flags = (Flags & 0xF0FF) | (Log2Size << 8); + } + } + + // struct nlist (12 bytes) + + Write32(MSD.StringIndex); + Write8(Type); + Write8(MSD.SectionIndex); + + // The Mach-O streamer uses the lowest 16-bits of the flags for the 'desc' + // value. + Write16(Flags); + Write32(Address); + } + + struct MachRelocationEntry { + uint32_t Word0; + uint32_t Word1; + }; + void ComputeScatteredRelocationInfo(MCAssembler &Asm, + MCSectionData::Fixup &Fixup, + DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap, + std::vector<MachRelocationEntry> &Relocs) { + uint32_t Address = Fixup.Fragment->getOffset() + Fixup.Offset; + unsigned IsPCRel = 0; + unsigned Type = RIT_Vanilla; + + // See <reloc.h>. + + const MCSymbol *A = Fixup.Value.getSymA(); + MCSymbolData *SD = SymbolMap.lookup(A); + uint32_t Value = SD->getFragment()->getAddress() + SD->getOffset(); + uint32_t Value2 = 0; + + if (const MCSymbol *B = Fixup.Value.getSymB()) { + Type = RIT_LocalDifference; + + MCSymbolData *SD = SymbolMap.lookup(B); + Value2 = SD->getFragment()->getAddress() + SD->getOffset(); + } + + unsigned Log2Size = Log2_32(Fixup.Size); + assert((1U << Log2Size) == Fixup.Size && "Invalid fixup size!"); + + // The value which goes in the fixup is current value of the expression. + Fixup.FixedValue = Value - Value2 + Fixup.Value.getConstant(); + + MachRelocationEntry MRE; + MRE.Word0 = ((Address << 0) | + (Type << 24) | + (Log2Size << 28) | + (IsPCRel << 30) | + RF_Scattered); + MRE.Word1 = Value; + Relocs.push_back(MRE); + + if (Type == RIT_LocalDifference) { + Type = RIT_Pair; + + MachRelocationEntry MRE; + MRE.Word0 = ((0 << 0) | + (Type << 24) | + (Log2Size << 28) | + (0 << 30) | + RF_Scattered); + MRE.Word1 = Value2; + Relocs.push_back(MRE); + } + } + + void ComputeRelocationInfo(MCAssembler &Asm, + MCSectionData::Fixup &Fixup, + DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap, + std::vector<MachRelocationEntry> &Relocs) { + // If this is a local symbol plus an offset or a difference, then we need a + // scattered relocation entry. + if (Fixup.Value.getSymB()) // a - b + return ComputeScatteredRelocationInfo(Asm, Fixup, SymbolMap, Relocs); + if (Fixup.Value.getSymA() && Fixup.Value.getConstant()) + if (!Fixup.Value.getSymA()->isUndefined()) + return ComputeScatteredRelocationInfo(Asm, Fixup, SymbolMap, Relocs); + + // See <reloc.h>. + uint32_t Address = Fixup.Fragment->getOffset() + Fixup.Offset; + uint32_t Value = 0; + unsigned Index = 0; + unsigned IsPCRel = 0; + unsigned IsExtern = 0; + unsigned Type = 0; + + if (Fixup.Value.isAbsolute()) { // constant + // SymbolNum of 0 indicates the absolute section. + Type = RIT_Vanilla; + Value = 0; + llvm_unreachable("FIXME: Not yet implemented!"); + } else { + const MCSymbol *Symbol = Fixup.Value.getSymA(); + MCSymbolData *SD = SymbolMap.lookup(Symbol); + + if (Symbol->isUndefined()) { + IsExtern = 1; + Index = SD->getIndex(); + Value = 0; + } else { + // The index is the section ordinal. + // + // FIXME: O(N) + Index = 1; + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it, ++Index) + if (&*it == SD->getFragment()->getParent()) + break; + Value = SD->getFragment()->getAddress() + SD->getOffset(); + } + + Type = RIT_Vanilla; + } + + // The value which goes in the fixup is current value of the expression. + Fixup.FixedValue = Value + Fixup.Value.getConstant(); + + unsigned Log2Size = Log2_32(Fixup.Size); + assert((1U << Log2Size) == Fixup.Size && "Invalid fixup size!"); + + // struct relocation_info (8 bytes) + MachRelocationEntry MRE; + MRE.Word0 = Address; + MRE.Word1 = ((Index << 0) | + (IsPCRel << 24) | + (Log2Size << 25) | + (IsExtern << 27) | + (Type << 28)); + Relocs.push_back(MRE); + } + + void BindIndirectSymbols(MCAssembler &Asm, + DenseMap<const MCSymbol*,MCSymbolData*> &SymbolMap) { + // This is the point where 'as' creates actual symbols for indirect symbols + // (in the following two passes). It would be easier for us to do this + // sooner when we see the attribute, but that makes getting the order in the + // symbol table much more complicated than it is worth. + // + // FIXME: Revisit this when the dust settles. + + // Bind non lazy symbol pointers first. + for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), + ie = Asm.indirect_symbol_end(); it != ie; ++it) { + // FIXME: cast<> support! + const MCSectionMachO &Section = + static_cast<const MCSectionMachO&>(it->SectionData->getSection()); + + unsigned Type = + Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; + if (Type != MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) + continue; + + MCSymbolData *&Entry = SymbolMap[it->Symbol]; + if (!Entry) + Entry = new MCSymbolData(*it->Symbol, 0, 0, &Asm); + } + + // Then lazy symbol pointers and symbol stubs. + for (MCAssembler::indirect_symbol_iterator it = Asm.indirect_symbol_begin(), + ie = Asm.indirect_symbol_end(); it != ie; ++it) { + // FIXME: cast<> support! + const MCSectionMachO &Section = + static_cast<const MCSectionMachO&>(it->SectionData->getSection()); + + unsigned Type = + Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; + if (Type != MCSectionMachO::S_LAZY_SYMBOL_POINTERS && + Type != MCSectionMachO::S_SYMBOL_STUBS) + continue; + + MCSymbolData *&Entry = SymbolMap[it->Symbol]; + if (!Entry) { + Entry = new MCSymbolData(*it->Symbol, 0, 0, &Asm); + + // Set the symbol type to undefined lazy, but only on construction. + // + // FIXME: Do not hardcode. + Entry->setFlags(Entry->getFlags() | 0x0001); + } + } + } + + /// ComputeSymbolTable - Compute the symbol table data + /// + /// \param StringTable [out] - The string table data. + /// \param StringIndexMap [out] - Map from symbol names to offsets in the + /// string table. + void ComputeSymbolTable(MCAssembler &Asm, SmallString<256> &StringTable, + std::vector<MachSymbolData> &LocalSymbolData, + std::vector<MachSymbolData> &ExternalSymbolData, + std::vector<MachSymbolData> &UndefinedSymbolData) { + // Build section lookup table. + DenseMap<const MCSection*, uint8_t> SectionIndexMap; + unsigned Index = 1; + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it, ++Index) + SectionIndexMap[&it->getSection()] = Index; + assert(Index <= 256 && "Too many sections!"); + + // Index 0 is always the empty string. + StringMap<uint64_t> StringIndexMap; + StringTable += '\x00'; + + // Build the symbol arrays and the string table, but only for non-local + // symbols. + // + // The particular order that we collect the symbols and create the string + // table, then sort the symbols is chosen to match 'as'. Even though it + // doesn't matter for correctness, this is important for letting us diff .o + // files. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore assembler temporaries. + if (it->getSymbol().isTemporary()) + continue; + + if (!it->isExternal() && !Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + MachSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + if (Symbol.isUndefined()) { + MSD.SectionIndex = 0; + UndefinedSymbolData.push_back(MSD); + } else if (Symbol.isAbsolute()) { + MSD.SectionIndex = 0; + ExternalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + ExternalSymbolData.push_back(MSD); + } + } + + // Now add the data for local symbols. + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) { + const MCSymbol &Symbol = it->getSymbol(); + + // Ignore assembler temporaries. + if (it->getSymbol().isTemporary()) + continue; + + if (it->isExternal() || Symbol.isUndefined()) + continue; + + uint64_t &Entry = StringIndexMap[Symbol.getName()]; + if (!Entry) { + Entry = StringTable.size(); + StringTable += Symbol.getName(); + StringTable += '\x00'; + } + + MachSymbolData MSD; + MSD.SymbolData = it; + MSD.StringIndex = Entry; + + if (Symbol.isAbsolute()) { + MSD.SectionIndex = 0; + LocalSymbolData.push_back(MSD); + } else { + MSD.SectionIndex = SectionIndexMap.lookup(&Symbol.getSection()); + assert(MSD.SectionIndex && "Invalid section index!"); + LocalSymbolData.push_back(MSD); + } + } + + // External and undefined symbols are required to be in lexicographic order. + std::sort(ExternalSymbolData.begin(), ExternalSymbolData.end()); + std::sort(UndefinedSymbolData.begin(), UndefinedSymbolData.end()); + + // Set the symbol indices. + Index = 0; + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + LocalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + ExternalSymbolData[i].SymbolData->setIndex(Index++); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + UndefinedSymbolData[i].SymbolData->setIndex(Index++); + + // The string table is padded to a multiple of 4. + // + // FIXME: Check to see if this varies per arch. + while (StringTable.size() % 4) + StringTable += '\x00'; + } + + void WriteObject(MCAssembler &Asm) { + unsigned NumSections = Asm.size(); + + // Compute the symbol -> symbol data map. + // + // FIXME: This should not be here. + DenseMap<const MCSymbol*, MCSymbolData *> SymbolMap; + for (MCAssembler::symbol_iterator it = Asm.symbol_begin(), + ie = Asm.symbol_end(); it != ie; ++it) + SymbolMap[&it->getSymbol()] = it; + + // Create symbol data for any indirect symbols. + BindIndirectSymbols(Asm, SymbolMap); + + // Compute symbol table information. + SmallString<256> StringTable; + std::vector<MachSymbolData> LocalSymbolData; + std::vector<MachSymbolData> ExternalSymbolData; + std::vector<MachSymbolData> UndefinedSymbolData; + unsigned NumSymbols = Asm.symbol_size(); + + // No symbol table command is written if there are no symbols. + if (NumSymbols) + ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, + UndefinedSymbolData); + + // The section data starts after the header, the segment load command (and + // section headers) and the symbol table. + unsigned NumLoadCommands = 1; + uint64_t LoadCommandsSize = + SegmentLoadCommand32Size + NumSections * Section32Size; + + // Add the symbol table load command sizes, if used. + if (NumSymbols) { + NumLoadCommands += 2; + LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize; + } + + // Compute the total size of the section data, as well as its file size and + // vm size. + uint64_t SectionDataStart = Header32Size + LoadCommandsSize; + uint64_t SectionDataSize = 0; + uint64_t SectionDataFileSize = 0; + uint64_t VMSize = 0; + for (MCAssembler::iterator it = Asm.begin(), + ie = Asm.end(); it != ie; ++it) { + MCSectionData &SD = *it; + + VMSize = std::max(VMSize, SD.getAddress() + SD.getSize()); + + if (isVirtualSection(SD.getSection())) + continue; + + SectionDataSize = std::max(SectionDataSize, + SD.getAddress() + SD.getSize()); + SectionDataFileSize = std::max(SectionDataFileSize, + SD.getAddress() + SD.getFileSize()); + } + + // The section data is passed to 4 bytes. + // + // FIXME: Is this machine dependent? + unsigned SectionDataPadding = OffsetToAlignment(SectionDataFileSize, 4); + SectionDataFileSize += SectionDataPadding; + + // Write the prolog, starting with the header and load command... + WriteHeader32(NumLoadCommands, LoadCommandsSize, + Asm.getSubsectionsViaSymbols()); + WriteSegmentLoadCommand32(NumSections, VMSize, + SectionDataStart, SectionDataSize); + + // ... and then the section headers. + // + // We also compute the section relocations while we do this. Note that + // compute relocation info will also update the fixup to have the correct + // value; this will be overwrite the appropriate data in the fragment when + // it is written. + std::vector<MachRelocationEntry> RelocInfos; + uint64_t RelocTableEnd = SectionDataStart + SectionDataFileSize; + for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; + ++it) { + MCSectionData &SD = *it; + + // The assembler writes relocations in the reverse order they were seen. + // + // FIXME: It is probably more complicated than this. + unsigned NumRelocsStart = RelocInfos.size(); + for (unsigned i = 0, e = SD.fixup_size(); i != e; ++i) + ComputeRelocationInfo(Asm, SD.getFixups()[e - i - 1], SymbolMap, + RelocInfos); + + unsigned NumRelocs = RelocInfos.size() - NumRelocsStart; + uint64_t SectionStart = SectionDataStart + SD.getAddress(); + WriteSection32(SD, SectionStart, RelocTableEnd, NumRelocs); + RelocTableEnd += NumRelocs * RelocationInfoSize; + } + + // Write the symbol table load command, if used. + if (NumSymbols) { + unsigned FirstLocalSymbol = 0; + unsigned NumLocalSymbols = LocalSymbolData.size(); + unsigned FirstExternalSymbol = FirstLocalSymbol + NumLocalSymbols; + unsigned NumExternalSymbols = ExternalSymbolData.size(); + unsigned FirstUndefinedSymbol = FirstExternalSymbol + NumExternalSymbols; + unsigned NumUndefinedSymbols = UndefinedSymbolData.size(); + unsigned NumIndirectSymbols = Asm.indirect_symbol_size(); + unsigned NumSymTabSymbols = + NumLocalSymbols + NumExternalSymbols + NumUndefinedSymbols; + uint64_t IndirectSymbolSize = NumIndirectSymbols * 4; + uint64_t IndirectSymbolOffset = 0; + + // If used, the indirect symbols are written after the section data. + if (NumIndirectSymbols) + IndirectSymbolOffset = RelocTableEnd; + + // The symbol table is written after the indirect symbol data. + uint64_t SymbolTableOffset = RelocTableEnd + IndirectSymbolSize; + + // The string table is written after symbol table. + uint64_t StringTableOffset = + SymbolTableOffset + NumSymTabSymbols * Nlist32Size; + WriteSymtabLoadCommand(SymbolTableOffset, NumSymTabSymbols, + StringTableOffset, StringTable.size()); + + WriteDysymtabLoadCommand(FirstLocalSymbol, NumLocalSymbols, + FirstExternalSymbol, NumExternalSymbols, + FirstUndefinedSymbol, NumUndefinedSymbols, + IndirectSymbolOffset, NumIndirectSymbols); + } + + // Write the actual section data. + for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) + WriteFileData(OS, *it, *this); + + // Write the extra padding. + WriteZeros(SectionDataPadding); + + // Write the relocation entries. + for (unsigned i = 0, e = RelocInfos.size(); i != e; ++i) { + Write32(RelocInfos[i].Word0); + Write32(RelocInfos[i].Word1); + } + + // Write the symbol table data, if used. + if (NumSymbols) { + // Write the indirect symbol entries. + for (MCAssembler::indirect_symbol_iterator + it = Asm.indirect_symbol_begin(), + ie = Asm.indirect_symbol_end(); it != ie; ++it) { + // Indirect symbols in the non lazy symbol pointer section have some + // special handling. + const MCSectionMachO &Section = + static_cast<const MCSectionMachO&>(it->SectionData->getSection()); + unsigned Type = + Section.getTypeAndAttributes() & MCSectionMachO::SECTION_TYPE; + if (Type == MCSectionMachO::S_NON_LAZY_SYMBOL_POINTERS) { + // If this symbol is defined and internal, mark it as such. + if (it->Symbol->isDefined() && + !SymbolMap.lookup(it->Symbol)->isExternal()) { + uint32_t Flags = ISF_Local; + if (it->Symbol->isAbsolute()) + Flags |= ISF_Absolute; + Write32(Flags); + continue; + } + } + + Write32(SymbolMap[it->Symbol]->getIndex()); + } + + // FIXME: Check that offsets match computed ones. + + // Write the symbol table entries. + for (unsigned i = 0, e = LocalSymbolData.size(); i != e; ++i) + WriteNlist32(LocalSymbolData[i]); + for (unsigned i = 0, e = ExternalSymbolData.size(); i != e; ++i) + WriteNlist32(ExternalSymbolData[i]); + for (unsigned i = 0, e = UndefinedSymbolData.size(); i != e; ++i) + WriteNlist32(UndefinedSymbolData[i]); + + // Write the string table. + OS << StringTable.str(); + } + } +}; + +/* *** */ + +MCFragment::MCFragment() : Kind(FragmentType(~0)) { +} + +MCFragment::MCFragment(FragmentType _Kind, MCSectionData *_Parent) + : Kind(_Kind), + Parent(_Parent), + FileSize(~UINT64_C(0)) +{ + if (Parent) + Parent->getFragmentList().push_back(this); +} + +MCFragment::~MCFragment() { +} + +uint64_t MCFragment::getAddress() const { + assert(getParent() && "Missing Section!"); + return getParent()->getAddress() + Offset; +} + +/* *** */ + +MCSectionData::MCSectionData() : Section(0) {} + +MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) + : Section(&_Section), + Alignment(1), + Address(~UINT64_C(0)), + Size(~UINT64_C(0)), + FileSize(~UINT64_C(0)), + LastFixupLookup(~0) +{ + if (A) + A->getSectionList().push_back(this); +} + +const MCSectionData::Fixup * +MCSectionData::LookupFixup(const MCFragment *Fragment, uint64_t Offset) const { + // Use a one level cache to turn the common case of accessing the fixups in + // order into O(1) instead of O(N). + unsigned i = LastFixupLookup, Count = Fixups.size(), End = Fixups.size(); + if (i >= End) + i = 0; + while (Count--) { + const Fixup &F = Fixups[i]; + if (F.Fragment == Fragment && F.Offset == Offset) { + LastFixupLookup = i; + return &F; + } + + ++i; + if (i == End) + i = 0; + } + + return 0; +} + +/* *** */ + +MCSymbolData::MCSymbolData() : Symbol(0) {} + +MCSymbolData::MCSymbolData(const MCSymbol &_Symbol, MCFragment *_Fragment, + uint64_t _Offset, MCAssembler *A) + : Symbol(&_Symbol), Fragment(_Fragment), Offset(_Offset), + IsExternal(false), IsPrivateExtern(false), + CommonSize(0), CommonAlign(0), Flags(0), Index(0) +{ + if (A) + A->getSymbolList().push_back(this); +} + +/* *** */ + +MCAssembler::MCAssembler(MCContext &_Context, raw_ostream &_OS) + : Context(_Context), OS(_OS), SubsectionsViaSymbols(false) +{ +} + +MCAssembler::~MCAssembler() { +} + +void MCAssembler::LayoutSection(MCSectionData &SD) { + uint64_t Address = SD.getAddress(); + + for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) { + MCFragment &F = *it; + + F.setOffset(Address - SD.getAddress()); + + // Evaluate fragment size. + switch (F.getKind()) { + case MCFragment::FT_Align: { + MCAlignFragment &AF = cast<MCAlignFragment>(F); + + uint64_t Size = OffsetToAlignment(Address, AF.getAlignment()); + if (Size > AF.getMaxBytesToEmit()) + AF.setFileSize(0); + else + AF.setFileSize(Size); + break; + } + + case MCFragment::FT_Data: + F.setFileSize(F.getMaxFileSize()); + break; + + case MCFragment::FT_Fill: { + MCFillFragment &FF = cast<MCFillFragment>(F); + + F.setFileSize(F.getMaxFileSize()); + + // If the fill value is constant, thats it. + if (FF.getValue().isAbsolute()) + break; + + // Otherwise, add fixups for the values. + for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) { + MCSectionData::Fixup Fix(F, i * FF.getValueSize(), + FF.getValue(),FF.getValueSize()); + SD.getFixups().push_back(Fix); + } + break; + } + + case MCFragment::FT_Org: { + MCOrgFragment &OF = cast<MCOrgFragment>(F); + + if (!OF.getOffset().isAbsolute()) + llvm_unreachable("FIXME: Not yet implemented!"); + uint64_t OrgOffset = OF.getOffset().getConstant(); + uint64_t Offset = Address - SD.getAddress(); + + // FIXME: We need a way to communicate this error. + if (OrgOffset < Offset) + llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + + "' (at offset '" + Twine(Offset) + "'"); + + F.setFileSize(OrgOffset - Offset); + break; + } + + case MCFragment::FT_ZeroFill: { + MCZeroFillFragment &ZFF = cast<MCZeroFillFragment>(F); + + // Align the fragment offset; it is safe to adjust the offset freely since + // this is only in virtual sections. + uint64_t Aligned = RoundUpToAlignment(Address, ZFF.getAlignment()); + F.setOffset(Aligned - SD.getAddress()); + + // FIXME: This is misnamed. + F.setFileSize(ZFF.getSize()); + break; + } + } + + Address += F.getFileSize(); + } + + // Set the section sizes. + SD.setSize(Address - SD.getAddress()); + if (isVirtualSection(SD.getSection())) + SD.setFileSize(0); + else + SD.setFileSize(Address - SD.getAddress()); +} + +/// WriteFileData - Write the \arg F data to the output file. +static void WriteFileData(raw_ostream &OS, const MCFragment &F, + MachObjectWriter &MOW) { + uint64_t Start = OS.tell(); + (void) Start; + + ++EmittedFragments; + + // FIXME: Embed in fragments instead? + switch (F.getKind()) { + case MCFragment::FT_Align: { + MCAlignFragment &AF = cast<MCAlignFragment>(F); + uint64_t Count = AF.getFileSize() / AF.getValueSize(); + + // FIXME: This error shouldn't actually occur (the front end should emit + // multiple .align directives to enforce the semantics it wants), but is + // severe enough that we want to report it. How to handle this? + if (Count * AF.getValueSize() != AF.getFileSize()) + llvm_report_error("undefined .align directive, value size '" + + Twine(AF.getValueSize()) + + "' is not a divisor of padding size '" + + Twine(AF.getFileSize()) + "'"); + + for (uint64_t i = 0; i != Count; ++i) { + switch (AF.getValueSize()) { + default: + assert(0 && "Invalid size!"); + case 1: MOW.Write8 (uint8_t (AF.getValue())); break; + case 2: MOW.Write16(uint16_t(AF.getValue())); break; + case 4: MOW.Write32(uint32_t(AF.getValue())); break; + case 8: MOW.Write64(uint64_t(AF.getValue())); break; + } + } + break; + } + + case MCFragment::FT_Data: + OS << cast<MCDataFragment>(F).getContents().str(); + break; + + case MCFragment::FT_Fill: { + MCFillFragment &FF = cast<MCFillFragment>(F); + + int64_t Value = 0; + if (FF.getValue().isAbsolute()) + Value = FF.getValue().getConstant(); + for (uint64_t i = 0, e = FF.getCount(); i != e; ++i) { + if (!FF.getValue().isAbsolute()) { + // Find the fixup. + // + // FIXME: Find a better way to write in the fixes. + const MCSectionData::Fixup *Fixup = + F.getParent()->LookupFixup(&F, i * FF.getValueSize()); + assert(Fixup && "Missing fixup for fill value!"); + Value = Fixup->FixedValue; + } + + switch (FF.getValueSize()) { + default: + assert(0 && "Invalid size!"); + case 1: MOW.Write8 (uint8_t (Value)); break; + case 2: MOW.Write16(uint16_t(Value)); break; + case 4: MOW.Write32(uint32_t(Value)); break; + case 8: MOW.Write64(uint64_t(Value)); break; + } + } + break; + } + + case MCFragment::FT_Org: { + MCOrgFragment &OF = cast<MCOrgFragment>(F); + + for (uint64_t i = 0, e = OF.getFileSize(); i != e; ++i) + MOW.Write8(uint8_t(OF.getValue())); + + break; + } + + case MCFragment::FT_ZeroFill: { + assert(0 && "Invalid zero fill fragment in concrete section!"); + break; + } + } + + assert(OS.tell() - Start == F.getFileSize()); +} + +/// WriteFileData - Write the \arg SD data to the output file. +static void WriteFileData(raw_ostream &OS, const MCSectionData &SD, + MachObjectWriter &MOW) { + // Ignore virtual sections. + if (isVirtualSection(SD.getSection())) { + assert(SD.getFileSize() == 0); + return; + } + + uint64_t Start = OS.tell(); + (void) Start; + + for (MCSectionData::const_iterator it = SD.begin(), + ie = SD.end(); it != ie; ++it) + WriteFileData(OS, *it, MOW); + + // Add section padding. + assert(SD.getFileSize() >= SD.getSize() && "Invalid section sizes!"); + MOW.WriteZeros(SD.getFileSize() - SD.getSize()); + + assert(OS.tell() - Start == SD.getFileSize()); +} + +void MCAssembler::Finish() { + // Layout the concrete sections and fragments. + uint64_t Address = 0; + MCSectionData *Prev = 0; + for (iterator it = begin(), ie = end(); it != ie; ++it) { + MCSectionData &SD = *it; + + // Skip virtual sections. + if (isVirtualSection(SD.getSection())) + continue; + + // Align this section if necessary by adding padding bytes to the previous + // section. + if (uint64_t Pad = OffsetToAlignment(Address, it->getAlignment())) { + assert(Prev && "Missing prev section!"); + Prev->setFileSize(Prev->getFileSize() + Pad); + Address += Pad; + } + + // Layout the section fragments and its size. + SD.setAddress(Address); + LayoutSection(SD); + Address += SD.getFileSize(); + + Prev = &SD; + } + + // Layout the virtual sections. + for (iterator it = begin(), ie = end(); it != ie; ++it) { + MCSectionData &SD = *it; + + if (!isVirtualSection(SD.getSection())) + continue; + + SD.setAddress(Address); + LayoutSection(SD); + Address += SD.getSize(); + } + + // Write the object file. + MachObjectWriter MOW(OS); + MOW.WriteObject(*this); + + OS.flush(); +} diff --git a/lib/MC/MCCodeEmitter.cpp b/lib/MC/MCCodeEmitter.cpp new file mode 100644 index 0000000..c122763 --- /dev/null +++ b/lib/MC/MCCodeEmitter.cpp @@ -0,0 +1,18 @@ +//===-- MCCodeEmitter.cpp - Instruction Encoding --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCCodeEmitter.h" + +using namespace llvm; + +MCCodeEmitter::MCCodeEmitter() { +} + +MCCodeEmitter::~MCCodeEmitter() { +} diff --git a/lib/MC/MCContext.cpp b/lib/MC/MCContext.cpp index 6c6019c..f36564a 100644 --- a/lib/MC/MCContext.cpp +++ b/lib/MC/MCContext.cpp @@ -14,23 +14,15 @@ #include "llvm/MC/MCValue.h" using namespace llvm; -MCContext::MCContext() -{ +MCContext::MCContext() { } MCContext::~MCContext() { + // NOTE: The sections are all allocated out of a bump pointer allocator, + // we don't need to free them here. } -MCSection *MCContext::GetSection(const char *Name) { - MCSection *&Entry = Sections[Name]; - - if (!Entry) - Entry = new (*this) MCSection(Name); - - return Entry; -} - -MCSymbol *MCContext::CreateSymbol(const char *Name) { +MCSymbol *MCContext::CreateSymbol(const StringRef &Name) { assert(Name[0] != '\0' && "Normal symbols cannot be unnamed!"); // Create and bind the symbol, and ensure that names are unique. @@ -39,17 +31,16 @@ MCSymbol *MCContext::CreateSymbol(const char *Name) { return Entry = new (*this) MCSymbol(Name, false); } -MCSymbol *MCContext::GetOrCreateSymbol(const char *Name) { +MCSymbol *MCContext::GetOrCreateSymbol(const StringRef &Name) { MCSymbol *&Entry = Symbols[Name]; if (Entry) return Entry; return Entry = new (*this) MCSymbol(Name, false); } - -MCSymbol *MCContext::CreateTemporarySymbol(const char *Name) { +MCSymbol *MCContext::CreateTemporarySymbol(const StringRef &Name) { // If unnamed, just create a symbol. - if (Name[0] == '\0') + if (Name.empty()) new (*this) MCSymbol("", true); // Otherwise create as usual. @@ -58,20 +49,20 @@ MCSymbol *MCContext::CreateTemporarySymbol(const char *Name) { return Entry = new (*this) MCSymbol(Name, true); } -MCSymbol *MCContext::LookupSymbol(const char *Name) const { +MCSymbol *MCContext::LookupSymbol(const StringRef &Name) const { return Symbols.lookup(Name); } -void MCContext::ClearSymbolValue(MCSymbol *Sym) { +void MCContext::ClearSymbolValue(const MCSymbol *Sym) { SymbolValues.erase(Sym); } -void MCContext::SetSymbolValue(MCSymbol *Sym, const MCValue &Value) { +void MCContext::SetSymbolValue(const MCSymbol *Sym, const MCValue &Value) { SymbolValues[Sym] = Value; } -const MCValue *MCContext::GetSymbolValue(MCSymbol *Sym) const { - DenseMap<MCSymbol*, MCValue>::iterator it = SymbolValues.find(Sym); +const MCValue *MCContext::GetSymbolValue(const MCSymbol *Sym) const { + DenseMap<const MCSymbol*, MCValue>::iterator it = SymbolValues.find(Sym); if (it == SymbolValues.end()) return 0; diff --git a/lib/MC/MCDisassembler.cpp b/lib/MC/MCDisassembler.cpp new file mode 100644 index 0000000..0809690 --- /dev/null +++ b/lib/MC/MCDisassembler.cpp @@ -0,0 +1,14 @@ +//===-- lib/MC/MCDisassembler.cpp - Disassembler interface ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCDisassembler.h" +using namespace llvm; + +MCDisassembler::~MCDisassembler() { +} diff --git a/lib/MC/MCExpr.cpp b/lib/MC/MCExpr.cpp new file mode 100644 index 0000000..0f3e053 --- /dev/null +++ b/lib/MC/MCExpr.cpp @@ -0,0 +1,286 @@ +//===- MCExpr.cpp - Assembly Level Expression Implementation --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +void MCExpr::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + switch (getKind()) { + case MCExpr::Constant: + OS << cast<MCConstantExpr>(*this).getValue(); + return; + + case MCExpr::SymbolRef: { + const MCSymbol &Sym = cast<MCSymbolRefExpr>(*this).getSymbol(); + + // Parenthesize names that start with $ so that they don't look like + // absolute names. + if (Sym.getName()[0] == '$') { + OS << '('; + Sym.print(OS, MAI); + OS << ')'; + } else { + Sym.print(OS, MAI); + } + return; + } + + case MCExpr::Unary: { + const MCUnaryExpr &UE = cast<MCUnaryExpr>(*this); + switch (UE.getOpcode()) { + default: assert(0 && "Invalid opcode!"); + case MCUnaryExpr::LNot: OS << '!'; break; + case MCUnaryExpr::Minus: OS << '-'; break; + case MCUnaryExpr::Not: OS << '~'; break; + case MCUnaryExpr::Plus: OS << '+'; break; + } + UE.getSubExpr()->print(OS, MAI); + return; + } + + case MCExpr::Binary: { + const MCBinaryExpr &BE = cast<MCBinaryExpr>(*this); + + // Only print parens around the LHS if it is non-trivial. + if (isa<MCConstantExpr>(BE.getLHS()) || isa<MCSymbolRefExpr>(BE.getLHS())) { + BE.getLHS()->print(OS, MAI); + } else { + OS << '('; + BE.getLHS()->print(OS, MAI); + OS << ')'; + } + + switch (BE.getOpcode()) { + default: assert(0 && "Invalid opcode!"); + case MCBinaryExpr::Add: + // Print "X-42" instead of "X+-42". + if (const MCConstantExpr *RHSC = dyn_cast<MCConstantExpr>(BE.getRHS())) { + if (RHSC->getValue() < 0) { + OS << RHSC->getValue(); + return; + } + } + + OS << '+'; + break; + case MCBinaryExpr::And: OS << '&'; break; + case MCBinaryExpr::Div: OS << '/'; break; + case MCBinaryExpr::EQ: OS << "=="; break; + case MCBinaryExpr::GT: OS << '>'; break; + case MCBinaryExpr::GTE: OS << ">="; break; + case MCBinaryExpr::LAnd: OS << "&&"; break; + case MCBinaryExpr::LOr: OS << "||"; break; + case MCBinaryExpr::LT: OS << '<'; break; + case MCBinaryExpr::LTE: OS << "<="; break; + case MCBinaryExpr::Mod: OS << '%'; break; + case MCBinaryExpr::Mul: OS << '*'; break; + case MCBinaryExpr::NE: OS << "!="; break; + case MCBinaryExpr::Or: OS << '|'; break; + case MCBinaryExpr::Shl: OS << "<<"; break; + case MCBinaryExpr::Shr: OS << ">>"; break; + case MCBinaryExpr::Sub: OS << '-'; break; + case MCBinaryExpr::Xor: OS << '^'; break; + } + + // Only print parens around the LHS if it is non-trivial. + if (isa<MCConstantExpr>(BE.getRHS()) || isa<MCSymbolRefExpr>(BE.getRHS())) { + BE.getRHS()->print(OS, MAI); + } else { + OS << '('; + BE.getRHS()->print(OS, MAI); + OS << ')'; + } + return; + } + } + + assert(0 && "Invalid expression kind!"); +} + +void MCExpr::dump() const { + print(errs(), 0); + errs() << '\n'; +} + +/* *** */ + +const MCBinaryExpr *MCBinaryExpr::Create(Opcode Opc, const MCExpr *LHS, + const MCExpr *RHS, MCContext &Ctx) { + return new (Ctx) MCBinaryExpr(Opc, LHS, RHS); +} + +const MCUnaryExpr *MCUnaryExpr::Create(Opcode Opc, const MCExpr *Expr, + MCContext &Ctx) { + return new (Ctx) MCUnaryExpr(Opc, Expr); +} + +const MCConstantExpr *MCConstantExpr::Create(int64_t Value, MCContext &Ctx) { + return new (Ctx) MCConstantExpr(Value); +} + +const MCSymbolRefExpr *MCSymbolRefExpr::Create(const MCSymbol *Sym, + MCContext &Ctx) { + return new (Ctx) MCSymbolRefExpr(Sym); +} + +const MCSymbolRefExpr *MCSymbolRefExpr::Create(const StringRef &Name, + MCContext &Ctx) { + return Create(Ctx.GetOrCreateSymbol(Name), Ctx); +} + + +/* *** */ + +bool MCExpr::EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const { + MCValue Value; + + if (!EvaluateAsRelocatable(Ctx, Value) || !Value.isAbsolute()) + return false; + + Res = Value.getConstant(); + return true; +} + +static bool EvaluateSymbolicAdd(const MCValue &LHS, const MCSymbol *RHS_A, + const MCSymbol *RHS_B, int64_t RHS_Cst, + MCValue &Res) { + // We can't add or subtract two symbols. + if ((LHS.getSymA() && RHS_A) || + (LHS.getSymB() && RHS_B)) + return false; + + const MCSymbol *A = LHS.getSymA() ? LHS.getSymA() : RHS_A; + const MCSymbol *B = LHS.getSymB() ? LHS.getSymB() : RHS_B; + if (B) { + // If we have a negated symbol, then we must have also have a non-negated + // symbol in order to encode the expression. We can do this check later to + // permit expressions which eventually fold to a representable form -- such + // as (a + (0 - b)) -- if necessary. + if (!A) + return false; + } + Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst); + return true; +} + +bool MCExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const { + switch (getKind()) { + case Constant: + Res = MCValue::get(cast<MCConstantExpr>(this)->getValue()); + return true; + + case SymbolRef: { + const MCSymbol &Sym = cast<MCSymbolRefExpr>(this)->getSymbol(); + if (const MCValue *Value = Ctx.GetSymbolValue(&Sym)) + Res = *Value; + else + Res = MCValue::get(&Sym, 0, 0); + return true; + } + + case Unary: { + const MCUnaryExpr *AUE = cast<MCUnaryExpr>(this); + MCValue Value; + + if (!AUE->getSubExpr()->EvaluateAsRelocatable(Ctx, Value)) + return false; + + switch (AUE->getOpcode()) { + case MCUnaryExpr::LNot: + if (!Value.isAbsolute()) + return false; + Res = MCValue::get(!Value.getConstant()); + break; + case MCUnaryExpr::Minus: + /// -(a - b + const) ==> (b - a - const) + if (Value.getSymA() && !Value.getSymB()) + return false; + Res = MCValue::get(Value.getSymB(), Value.getSymA(), + -Value.getConstant()); + break; + case MCUnaryExpr::Not: + if (!Value.isAbsolute()) + return false; + Res = MCValue::get(~Value.getConstant()); + break; + case MCUnaryExpr::Plus: + Res = Value; + break; + } + + return true; + } + + case Binary: { + const MCBinaryExpr *ABE = cast<MCBinaryExpr>(this); + MCValue LHSValue, RHSValue; + + if (!ABE->getLHS()->EvaluateAsRelocatable(Ctx, LHSValue) || + !ABE->getRHS()->EvaluateAsRelocatable(Ctx, RHSValue)) + return false; + + // We only support a few operations on non-constant expressions, handle + // those first. + if (!LHSValue.isAbsolute() || !RHSValue.isAbsolute()) { + switch (ABE->getOpcode()) { + default: + return false; + case MCBinaryExpr::Sub: + // Negate RHS and add. + return EvaluateSymbolicAdd(LHSValue, + RHSValue.getSymB(), RHSValue.getSymA(), + -RHSValue.getConstant(), + Res); + + case MCBinaryExpr::Add: + return EvaluateSymbolicAdd(LHSValue, + RHSValue.getSymA(), RHSValue.getSymB(), + RHSValue.getConstant(), + Res); + } + } + + // FIXME: We need target hooks for the evaluation. It may be limited in + // width, and gas defines the result of comparisons differently from Apple + // as (the result is sign extended). + int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant(); + int64_t Result = 0; + switch (ABE->getOpcode()) { + case MCBinaryExpr::Add: Result = LHS + RHS; break; + case MCBinaryExpr::And: Result = LHS & RHS; break; + case MCBinaryExpr::Div: Result = LHS / RHS; break; + case MCBinaryExpr::EQ: Result = LHS == RHS; break; + case MCBinaryExpr::GT: Result = LHS > RHS; break; + case MCBinaryExpr::GTE: Result = LHS >= RHS; break; + case MCBinaryExpr::LAnd: Result = LHS && RHS; break; + case MCBinaryExpr::LOr: Result = LHS || RHS; break; + case MCBinaryExpr::LT: Result = LHS < RHS; break; + case MCBinaryExpr::LTE: Result = LHS <= RHS; break; + case MCBinaryExpr::Mod: Result = LHS % RHS; break; + case MCBinaryExpr::Mul: Result = LHS * RHS; break; + case MCBinaryExpr::NE: Result = LHS != RHS; break; + case MCBinaryExpr::Or: Result = LHS | RHS; break; + case MCBinaryExpr::Shl: Result = LHS << RHS; break; + case MCBinaryExpr::Shr: Result = LHS >> RHS; break; + case MCBinaryExpr::Sub: Result = LHS - RHS; break; + case MCBinaryExpr::Xor: Result = LHS ^ RHS; break; + } + + Res = MCValue::get(Result); + return true; + } + } + + assert(0 && "Invalid assembly expression kind!"); + return false; +} diff --git a/lib/MC/MCInst.cpp b/lib/MC/MCInst.cpp new file mode 100644 index 0000000..d050318 --- /dev/null +++ b/lib/MC/MCInst.cpp @@ -0,0 +1,50 @@ +//===- lib/MC/MCInst.cpp - MCInst implementation --------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void MCOperand::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + OS << "<MCOperand "; + if (!isValid()) + OS << "INVALID"; + else if (isReg()) + OS << "Reg:" << getReg(); + else if (isImm()) + OS << "Imm:" << getImm(); + else if (isExpr()) { + OS << "Expr:("; + getExpr()->print(OS, MAI); + OS << ")"; + } else + OS << "UNDEFINED"; + OS << ">"; +} + +void MCOperand::dump() const { + print(errs(), 0); + errs() << "\n"; +} + +void MCInst::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + OS << "<MCInst " << getOpcode(); + for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { + OS << " "; + getOperand(i).print(OS, MAI); + } + OS << ">"; +} + +void MCInst::dump() const { + print(errs(), 0); + errs() << "\n"; +} diff --git a/lib/MC/MCInstPrinter.cpp b/lib/MC/MCInstPrinter.cpp new file mode 100644 index 0000000..e90c03c --- /dev/null +++ b/lib/MC/MCInstPrinter.cpp @@ -0,0 +1,14 @@ +//===-- MCInstPrinter.cpp - Convert an MCInst to target assembly syntax ---===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCInstPrinter.h" +using namespace llvm; + +MCInstPrinter::~MCInstPrinter() { +} diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp new file mode 100644 index 0000000..e04bd1f --- /dev/null +++ b/lib/MC/MCMachOStreamer.cpp @@ -0,0 +1,379 @@ +//===- lib/MC/MCMachOStreamer.cpp - Mach-O Object Output ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" + +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { + +class MCMachOStreamer : public MCStreamer { + /// SymbolFlags - We store the value for the 'desc' symbol field in the lowest + /// 16 bits of the implementation defined flags. + enum SymbolFlags { // See <mach-o/nlist.h>. + SF_DescFlagsMask = 0xFFFF, + + // Reference type flags. + SF_ReferenceTypeMask = 0x0007, + SF_ReferenceTypeUndefinedNonLazy = 0x0000, + SF_ReferenceTypeUndefinedLazy = 0x0001, + SF_ReferenceTypeDefined = 0x0002, + SF_ReferenceTypePrivateDefined = 0x0003, + SF_ReferenceTypePrivateUndefinedNonLazy = 0x0004, + SF_ReferenceTypePrivateUndefinedLazy = 0x0005, + + // Other 'desc' flags. + SF_NoDeadStrip = 0x0020, + SF_WeakReference = 0x0040, + SF_WeakDefinition = 0x0080 + }; + +private: + MCAssembler Assembler; + + MCCodeEmitter *Emitter; + + MCSectionData *CurSectionData; + + DenseMap<const MCSection*, MCSectionData*> SectionMap; + + DenseMap<const MCSymbol*, MCSymbolData*> SymbolMap; + +private: + MCFragment *getCurrentFragment() const { + assert(CurSectionData && "No current section!"); + + if (!CurSectionData->empty()) + return &CurSectionData->getFragmentList().back(); + + return 0; + } + + MCSectionData &getSectionData(const MCSection &Section) { + MCSectionData *&Entry = SectionMap[&Section]; + + if (!Entry) + Entry = new MCSectionData(Section, &Assembler); + + return *Entry; + } + + MCSymbolData &getSymbolData(const MCSymbol &Symbol) { + MCSymbolData *&Entry = SymbolMap[&Symbol]; + + if (!Entry) + Entry = new MCSymbolData(Symbol, 0, 0, &Assembler); + + return *Entry; + } + +public: + MCMachOStreamer(MCContext &Context, raw_ostream &_OS, MCCodeEmitter *_Emitter) + : MCStreamer(Context), Assembler(Context, _OS), Emitter(_Emitter), + CurSectionData(0) {} + ~MCMachOStreamer() {} + + const MCExpr *AddValueSymbols(const MCExpr *Value) { + switch (Value->getKind()) { + case MCExpr::Constant: + break; + + case MCExpr::Binary: { + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); + AddValueSymbols(BE->getLHS()); + AddValueSymbols(BE->getRHS()); + break; + } + + case MCExpr::SymbolRef: + getSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol()); + break; + + case MCExpr::Unary: + AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); + break; + } + + return Value; + } + + /// @name MCStreamer Interface + /// @{ + + virtual void SwitchSection(const MCSection *Section); + + virtual void EmitLabel(MCSymbol *Symbol); + + virtual void EmitAssemblerFlag(AssemblerFlag Flag); + + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); + + virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute); + + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); + + virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned ByteAlignment); + + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0); + + virtual void EmitBytes(const StringRef &Data); + + virtual void EmitValue(const MCExpr *Value, unsigned Size); + + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0); + + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0); + + virtual void EmitInstruction(const MCInst &Inst); + + virtual void Finish(); + + /// @} +}; + +} // end anonymous namespace. + +void MCMachOStreamer::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; + + CurSection = Section; + CurSectionData = &getSectionData(*Section); +} + +void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + // FIXME: We should also use offsets into Fill fragments. + MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); + if (!F) + F = new MCDataFragment(CurSectionData); + + MCSymbolData &SD = getSymbolData(*Symbol); + assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); + SD.setFragment(F); + SD.setOffset(F->getContents().size()); + + // This causes the reference type and weak reference flags to be cleared. + SD.setFlags(SD.getFlags() & ~(SF_WeakReference | SF_ReferenceTypeMask)); + + Symbol->setSection(*CurSection); +} + +void MCMachOStreamer::EmitAssemblerFlag(AssemblerFlag Flag) { + switch (Flag) { + case SubsectionsViaSymbols: + Assembler.setSubsectionsViaSymbols(true); + return; + } + + assert(0 && "invalid assembler flag!"); +} + +void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // Only absolute symbols can be redefined. + assert((Symbol->isUndefined() || Symbol->isAbsolute()) && + "Cannot define a symbol twice!"); + + llvm_unreachable("FIXME: Not yet implemented!"); +} + +void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, + SymbolAttr Attribute) { + // Indirect symbols are handled differently, to match how 'as' handles + // them. This makes writing matching .o files easier. + if (Attribute == MCStreamer::IndirectSymbol) { + // Note that we intentionally cannot use the symbol data here; this is + // important for matching the string table that 'as' generates. + IndirectSymbolData ISD; + ISD.Symbol = Symbol; + ISD.SectionData = CurSectionData; + Assembler.getIndirectSymbols().push_back(ISD); + return; + } + + // Adding a symbol attribute always introduces the symbol, note that an + // important side effect of calling getSymbolData here is to register the + // symbol with the assembler. + MCSymbolData &SD = getSymbolData(*Symbol); + + // The implementation of symbol attributes is designed to match 'as', but it + // leaves much to desired. It doesn't really make sense to arbitrarily add and + // remove flags, but 'as' allows this (in particular, see .desc). + // + // In the future it might be worth trying to make these operations more well + // defined. + switch (Attribute) { + case MCStreamer::IndirectSymbol: + case MCStreamer::Hidden: + case MCStreamer::Internal: + case MCStreamer::Protected: + case MCStreamer::Weak: + assert(0 && "Invalid symbol attribute for Mach-O!"); + break; + + case MCStreamer::Global: + SD.setExternal(true); + break; + + case MCStreamer::LazyReference: + // FIXME: This requires -dynamic. + SD.setFlags(SD.getFlags() | SF_NoDeadStrip); + if (Symbol->isUndefined()) + SD.setFlags(SD.getFlags() | SF_ReferenceTypeUndefinedLazy); + break; + + // Since .reference sets the no dead strip bit, it is equivalent to + // .no_dead_strip in practice. + case MCStreamer::Reference: + case MCStreamer::NoDeadStrip: + SD.setFlags(SD.getFlags() | SF_NoDeadStrip); + break; + + case MCStreamer::PrivateExtern: + SD.setExternal(true); + SD.setPrivateExtern(true); + break; + + case MCStreamer::WeakReference: + // FIXME: This requires -dynamic. + if (Symbol->isUndefined()) + SD.setFlags(SD.getFlags() | SF_WeakReference); + break; + + case MCStreamer::WeakDefinition: + // FIXME: 'as' enforces that this is defined and global. The manual claims + // it has to be in a coalesced section, but this isn't enforced. + SD.setFlags(SD.getFlags() | SF_WeakDefinition); + break; + } +} + +void MCMachOStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + // Encode the 'desc' value into the lowest implementation defined bits. + assert(DescValue == (DescValue & SF_DescFlagsMask) && + "Invalid .desc value!"); + getSymbolData(*Symbol).setFlags(DescValue & SF_DescFlagsMask); +} + +void MCMachOStreamer::EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned ByteAlignment) { + // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself. + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + MCSymbolData &SD = getSymbolData(*Symbol); + SD.setExternal(true); + SD.setCommon(Size, ByteAlignment); +} + +void MCMachOStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol, + unsigned Size, unsigned ByteAlignment) { + MCSectionData &SectData = getSectionData(*Section); + + // The symbol may not be present, which only creates the section. + if (!Symbol) + return; + + // FIXME: Assert that this section has the zerofill type. + + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + + MCSymbolData &SD = getSymbolData(*Symbol); + + MCFragment *F = new MCZeroFillFragment(Size, ByteAlignment, &SectData); + SD.setFragment(F); + + Symbol->setSection(*Section); + + // Update the maximum alignment on the zero fill section if necessary. + if (ByteAlignment > SectData.getAlignment()) + SectData.setAlignment(ByteAlignment); +} + +void MCMachOStreamer::EmitBytes(const StringRef &Data) { + MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); + if (!DF) + DF = new MCDataFragment(CurSectionData); + DF->getContents().append(Data.begin(), Data.end()); +} + +void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size) { + MCValue RelocValue; + + if (!AddValueSymbols(Value)->EvaluateAsRelocatable(getContext(), RelocValue)) + return llvm_report_error("expected relocatable expression"); + + new MCFillFragment(RelocValue, Size, 1, CurSectionData); +} + +void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, + int64_t Value, unsigned ValueSize, + unsigned MaxBytesToEmit) { + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, + CurSectionData); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > CurSectionData->getAlignment()) + CurSectionData->setAlignment(ByteAlignment); +} + +void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset, + unsigned char Value) { + MCValue RelocOffset; + + if (!AddValueSymbols(Offset)->EvaluateAsRelocatable(getContext(), + RelocOffset)) + return llvm_report_error("expected relocatable expression"); + + new MCOrgFragment(RelocOffset, Value, CurSectionData); +} + +void MCMachOStreamer::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()); + + if (!Emitter) + llvm_unreachable("no code emitter available!"); + + // FIXME: Relocations! + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + Emitter->EncodeInstruction(Inst, VecOS); + EmitBytes(VecOS.str()); +} + +void MCMachOStreamer::Finish() { + Assembler.Finish(); +} + +MCStreamer *llvm::createMachOStreamer(MCContext &Context, raw_ostream &OS, + MCCodeEmitter *CE) { + return new MCMachOStreamer(Context, OS, CE); +} diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp new file mode 100644 index 0000000..3cd22ca --- /dev/null +++ b/lib/MC/MCNullStreamer.cpp @@ -0,0 +1,70 @@ +//===- lib/MC/MCNullStreamer.cpp - Dummy Streamer Implementation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCStreamer.h" + +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSymbol.h" + +using namespace llvm; + +namespace { + + class MCNullStreamer : public MCStreamer { + public: + MCNullStreamer(MCContext &Context) : MCStreamer(Context) {} + + /// @name MCStreamer Interface + /// @{ + + virtual void SwitchSection(const MCSection *Section) { + CurSection = Section; + } + + virtual void EmitLabel(MCSymbol *Symbol) {} + + virtual void EmitAssemblerFlag(AssemblerFlag Flag) {} + + virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {} + + virtual void EmitSymbolAttribute(MCSymbol *Symbol, SymbolAttr Attribute) {} + + virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {} + + virtual void EmitCommonSymbol(MCSymbol *Symbol, unsigned Size, + unsigned ByteAlignment) {} + + virtual void EmitZerofill(const MCSection *Section, MCSymbol *Symbol = 0, + unsigned Size = 0, unsigned ByteAlignment = 0) {} + + virtual void EmitBytes(const StringRef &Data) {} + + virtual void EmitValue(const MCExpr *Value, unsigned Size) {} + + virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, + unsigned ValueSize = 1, + unsigned MaxBytesToEmit = 0) {} + + virtual void EmitValueToOffset(const MCExpr *Offset, + unsigned char Value = 0) {} + + virtual void EmitInstruction(const MCInst &Inst) {} + + virtual void Finish() {} + + /// @} + }; + +} + +MCStreamer *llvm::createNullStreamer(MCContext &Context) { + return new MCNullStreamer(Context); +} diff --git a/lib/MC/MCSection.cpp b/lib/MC/MCSection.cpp new file mode 100644 index 0000000..333a471 --- /dev/null +++ b/lib/MC/MCSection.cpp @@ -0,0 +1,45 @@ +//===- lib/MC/MCSection.cpp - Machine Code Section Representation ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +//===----------------------------------------------------------------------===// +// MCSection +//===----------------------------------------------------------------------===// + +MCSection::~MCSection() { +} + +//===----------------------------------------------------------------------===// +// MCSectionCOFF +//===----------------------------------------------------------------------===// + +MCSectionCOFF *MCSectionCOFF:: +Create(const StringRef &Name, bool IsDirective, SectionKind K, MCContext &Ctx) { + return new (Ctx) MCSectionCOFF(Name, IsDirective, K); +} + +void MCSectionCOFF::PrintSwitchToSection(const MCAsmInfo &MAI, + raw_ostream &OS) const { + + if (isDirective()) { + OS << getName() << '\n'; + return; + } + OS << "\t.section\t" << getName() << ",\""; + if (getKind().isText()) + OS << 'x'; + if (getKind().isWriteable()) + OS << 'w'; + OS << "\"\n"; +} diff --git a/lib/MC/MCSectionELF.cpp b/lib/MC/MCSectionELF.cpp new file mode 100644 index 0000000..660a8c9 --- /dev/null +++ b/lib/MC/MCSectionELF.cpp @@ -0,0 +1,138 @@ +//===- lib/MC/MCSectionELF.cpp - ELF Code Section Representation ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/MC/MCAsmInfo.h" + +using namespace llvm; + +MCSectionELF *MCSectionELF:: +Create(const StringRef &Section, unsigned Type, unsigned Flags, + SectionKind K, bool isExplicit, MCContext &Ctx) { + return new (Ctx) MCSectionELF(Section, Type, Flags, K, isExplicit); +} + +// ShouldOmitSectionDirective - Decides whether a '.section' directive +// should be printed before the section name +bool MCSectionELF::ShouldOmitSectionDirective(const char *Name, + const MCAsmInfo &MAI) const { + + // FIXME: Does .section .bss/.data/.text work everywhere?? + if (strcmp(Name, ".text") == 0 || + strcmp(Name, ".data") == 0 || + (strcmp(Name, ".bss") == 0 && + !MAI.usesELFSectionDirectiveForBSS())) + return true; + + 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 { + + if (ShouldOmitSectionDirective(SectionName.c_str(), MAI)) { + OS << '\t' << getSectionName() << '\n'; + return; + } + + OS << "\t.section\t" << getSectionName(); + + // Handle the weird solaris syntax if desired. + if (MAI.usesSunStyleELFSectionSwitchSyntax() && + !(Flags & MCSectionELF::SHF_MERGE)) { + if (Flags & MCSectionELF::SHF_ALLOC) + OS << ",#alloc"; + if (Flags & MCSectionELF::SHF_EXECINSTR) + OS << ",#execinstr"; + if (Flags & MCSectionELF::SHF_WRITE) + OS << ",#write"; + if (Flags & MCSectionELF::SHF_TLS) + OS << ",#tls"; + } else { + OS << ",\""; + if (Flags & MCSectionELF::SHF_ALLOC) + OS << 'a'; + if (Flags & MCSectionELF::SHF_EXECINSTR) + OS << 'x'; + if (Flags & MCSectionELF::SHF_WRITE) + OS << 'w'; + if (Flags & MCSectionELF::SHF_MERGE) + OS << 'M'; + if (Flags & MCSectionELF::SHF_STRINGS) + OS << 'S'; + if (Flags & MCSectionELF::SHF_TLS) + OS << 'T'; + + // If there are target-specific flags, print them. + if (Flags & ~MCSectionELF::TARGET_INDEP_SHF) + PrintTargetSpecificSectionFlags(MAI, OS); + + 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 << '\n'; +} + +// HasCommonSymbols - True if this section holds common symbols, this is +// indicated on the ELF object file by a symbol with SHN_COMMON section +// header index. +bool MCSectionELF::HasCommonSymbols() const { + + if (strncmp(SectionName.c_str(), ".gnu.linkonce.", 14) == 0) + return true; + + return false; +} + + diff --git a/lib/MC/MCSectionMachO.cpp b/lib/MC/MCSectionMachO.cpp new file mode 100644 index 0000000..b3aeb9c --- /dev/null +++ b/lib/MC/MCSectionMachO.cpp @@ -0,0 +1,271 @@ +//===- lib/MC/MCSectionMachO.cpp - MachO Code Section Representation ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +/// SectionTypeDescriptors - These are strings that describe the various section +/// types. This *must* be kept in order with and stay synchronized with the +/// section type list. +static const struct { + const char *AssemblerName, *EnumName; +} SectionTypeDescriptors[MCSectionMachO::LAST_KNOWN_SECTION_TYPE+1] = { + { "regular", "S_REGULAR" }, // 0x00 + { 0, "S_ZEROFILL" }, // 0x01 + { "cstring_literals", "S_CSTRING_LITERALS" }, // 0x02 + { "4byte_literals", "S_4BYTE_LITERALS" }, // 0x03 + { "8byte_literals", "S_8BYTE_LITERALS" }, // 0x04 + { "literal_pointers", "S_LITERAL_POINTERS" }, // 0x05 + { "non_lazy_symbol_pointers", "S_NON_LAZY_SYMBOL_POINTERS" }, // 0x06 + { "lazy_symbol_pointers", "S_LAZY_SYMBOL_POINTERS" }, // 0x07 + { "symbol_stubs", "S_SYMBOL_STUBS" }, // 0x08 + { "mod_init_funcs", "S_MOD_INIT_FUNC_POINTERS" }, // 0x09 + { "mod_term_funcs", "S_MOD_TERM_FUNC_POINTERS" }, // 0x0A + { "coalesced", "S_COALESCED" }, // 0x0B + { 0, /*FIXME??*/ "S_GB_ZEROFILL" }, // 0x0C + { "interposing", "S_INTERPOSING" }, // 0x0D + { "16byte_literals", "S_16BYTE_LITERALS" }, // 0x0E + { 0, /*FIXME??*/ "S_DTRACE_DOF" }, // 0x0F + { 0, /*FIXME??*/ "S_LAZY_DYLIB_SYMBOL_POINTERS" } // 0x10 +}; + + +/// SectionAttrDescriptors - This is an array of descriptors for section +/// attributes. Unlike the SectionTypeDescriptors, this is not directly indexed +/// by attribute, instead it is searched. The last entry has an AttrFlagEnd +/// AttrFlag value. +static const struct { + unsigned AttrFlag; + const char *AssemblerName, *EnumName; +} SectionAttrDescriptors[] = { +#define ENTRY(ASMNAME, ENUM) \ + { MCSectionMachO::ENUM, ASMNAME, #ENUM }, +ENTRY("pure_instructions", S_ATTR_PURE_INSTRUCTIONS) +ENTRY("no_toc", S_ATTR_NO_TOC) +ENTRY("strip_static_syms", S_ATTR_STRIP_STATIC_SYMS) +ENTRY("no_dead_strip", S_ATTR_NO_DEAD_STRIP) +ENTRY("live_support", S_ATTR_LIVE_SUPPORT) +ENTRY("self_modifying_code", S_ATTR_SELF_MODIFYING_CODE) +ENTRY("debug", S_ATTR_DEBUG) +ENTRY(0 /*FIXME*/, S_ATTR_SOME_INSTRUCTIONS) +ENTRY(0 /*FIXME*/, S_ATTR_EXT_RELOC) +ENTRY(0 /*FIXME*/, S_ATTR_LOC_RELOC) +#undef ENTRY + { 0, "none", 0 }, // used if section has no attributes but has a stub size +#define AttrFlagEnd 0xffffffff // non legal value, multiple attribute bits set + { AttrFlagEnd, 0, 0 } +}; + + +MCSectionMachO *MCSectionMachO:: +Create(const StringRef &Segment, const StringRef &Section, + unsigned TypeAndAttributes, unsigned Reserved2, + SectionKind K, MCContext &Ctx) { + // S_SYMBOL_STUBS must be set for Reserved2 to be non-zero. + return new (Ctx) MCSectionMachO(Segment, Section, TypeAndAttributes, + Reserved2, K); +} + +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) { + OS << '\n'; + return; + } + + OS << ','; + + unsigned SectionType = TAA & MCSectionMachO::SECTION_TYPE; + assert(SectionType <= MCSectionMachO::LAST_KNOWN_SECTION_TYPE && + "Invalid SectionType specified!"); + + if (SectionTypeDescriptors[SectionType].AssemblerName) + 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) { + // If we have a S_SYMBOL_STUBS size specified, print it along with 'none' as + // the attribute specifier. + if (Reserved2 != 0) + OS << ",none," << Reserved2; + OS << '\n'; + return; + } + + // Check each attribute to see if we have it. + char Separator = ','; + for (unsigned i = 0; SectionAttrDescriptors[i].AttrFlag; ++i) { + // Check to see if we have this attribute. + if ((SectionAttrDescriptors[i].AttrFlag & SectionAttrs) == 0) + continue; + + // Yep, clear it and print it. + SectionAttrs &= ~SectionAttrDescriptors[i].AttrFlag; + + OS << Separator; + if (SectionAttrDescriptors[i].AssemblerName) + OS << SectionAttrDescriptors[i].AssemblerName; + else + OS << "<<" << SectionAttrDescriptors[i].EnumName << ">>"; + Separator = '+'; + } + + assert(SectionAttrs == 0 && "Unknown section attributes!"); + + // If we have a S_SYMBOL_STUBS size specified, print it. + if (Reserved2 != 0) + OS << ',' << Reserved2; + OS << '\n'; +} + +/// StripSpaces - This removes leading and trailing spaces from the StringRef. +static void StripSpaces(StringRef &Str) { + while (!Str.empty() && isspace(Str[0])) + Str = Str.substr(1); + while (!Str.empty() && isspace(Str.back())) + Str = Str.substr(0, Str.size()-1); +} + +/// ParseSectionSpecifier - Parse the section specifier indicated by "Spec". +/// This is a string that can appear after a .section directive in a mach-o +/// flavored .s file. If successful, this fills in the specified Out +/// parameters and returns an empty string. When an invalid section +/// specifier is present, this returns a string indicating the problem. +std::string MCSectionMachO::ParseSectionSpecifier(StringRef Spec, // In. + StringRef &Segment, // Out. + StringRef &Section, // Out. + unsigned &TAA, // Out. + 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); + + // Verify that the segment is present and not too long. + if (Segment.empty() || Segment.size() > 16) + return "mach-o section specifier requires a segment whose length is " + "between 1 and 16 characters"; + + // Split the section name off from any attributes if present. + Comma = Comma.second.split(','); + + // Capture section, remove leading and trailing whitespace. + Section = Comma.first; + StripSpaces(Section); + + // Verify that the section is present and not too long. + if (Section.empty() || Section.size() > 16) + return "mach-o section specifier requires a section whose length is " + "between 1 and 16 characters"; + + // If there is no comma after the section, we're done. + TAA = 0; + StubSize = 0; + if (Comma.second.empty()) + return ""; + + // Otherwise, we need to parse the section type and attributes. + Comma = Comma.second.split(','); + + // Get the section type. + StringRef SectionType = Comma.first; + StripSpaces(SectionType); + + // Figure out which section type it is. + unsigned TypeID; + for (TypeID = 0; TypeID !=MCSectionMachO::LAST_KNOWN_SECTION_TYPE+1; ++TypeID) + if (SectionTypeDescriptors[TypeID].AssemblerName && + SectionType == SectionTypeDescriptors[TypeID].AssemblerName) + break; + + // If we didn't find the section type, reject it. + if (TypeID > MCSectionMachO::LAST_KNOWN_SECTION_TYPE) + return "mach-o section specifier uses an unknown section type"; + + // Remember the TypeID. + TAA = TypeID; + + // If we have no comma after the section type, there are no attributes. + if (Comma.second.empty()) { + // S_SYMBOL_STUBS always require a symbol stub size specifier. + if (TAA == MCSectionMachO::S_SYMBOL_STUBS) + return "mach-o section specifier of type 'symbol_stubs' requires a size " + "specifier"; + return ""; + } + + // Otherwise, we do have some attributes. Split off the size specifier if + // present. + Comma = Comma.second.split(','); + StringRef Attrs = Comma.first; + + // The attribute list is a '+' separated list of attributes. + std::pair<StringRef, StringRef> Plus = Attrs.split('+'); + + while (1) { + StringRef Attr = Plus.first; + StripSpaces(Attr); + + // Look up the attribute. + for (unsigned i = 0; ; ++i) { + if (SectionAttrDescriptors[i].AttrFlag == AttrFlagEnd) + return "mach-o section specifier has invalid attribute"; + + if (SectionAttrDescriptors[i].AssemblerName && + Attr == SectionAttrDescriptors[i].AssemblerName) { + TAA |= SectionAttrDescriptors[i].AttrFlag; + break; + } + } + + if (Plus.second.empty()) break; + Plus = Plus.second.split('+'); + }; + + // Okay, we've parsed the section attributes, see if we have a stub size spec. + if (Comma.second.empty()) { + // S_SYMBOL_STUBS always require a symbol stub size specifier. + if (TAA == MCSectionMachO::S_SYMBOL_STUBS) + return "mach-o section specifier of type 'symbol_stubs' requires a size " + "specifier"; + return ""; + } + + // If we have a stub size spec, we must have a sectiontype of S_SYMBOL_STUBS. + if ((TAA & MCSectionMachO::SECTION_TYPE) != MCSectionMachO::S_SYMBOL_STUBS) + return "mach-o section specifier cannot have a stub size specified because " + "it does not have type 'symbol_stubs'"; + + // Okay, if we do, it must be a number. + StringRef StubSizeStr = Comma.second; + StripSpaces(StubSizeStr); + + // Convert the stub size from a string to an integer. + if (StubSizeStr.getAsInteger(0, StubSize)) + return "mach-o section specifier has a malformed stub size"; + + return ""; +} + diff --git a/lib/MC/MCStreamer.cpp b/lib/MC/MCStreamer.cpp index a634f33..8a6dcda 100644 --- a/lib/MC/MCStreamer.cpp +++ b/lib/MC/MCStreamer.cpp @@ -11,7 +11,7 @@ using namespace llvm; -MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context) { +MCStreamer::MCStreamer(MCContext &_Context) : Context(_Context), CurSection(0) { } MCStreamer::~MCStreamer() { diff --git a/lib/MC/MCSymbol.cpp b/lib/MC/MCSymbol.cpp new file mode 100644 index 0000000..86ff3f3 --- /dev/null +++ b/lib/MC/MCSymbol.cpp @@ -0,0 +1,110 @@ +//===- lib/MC/MCSymbol.cpp - MCSymbol implementation ----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +// Sentinel value for the absolute pseudo section. +const MCSection *MCSymbol::AbsolutePseudoSection = + reinterpret_cast<const MCSection *>(1); + +static bool isAcceptableChar(char C) { + if ((C < 'a' || C > 'z') && + (C < 'A' || C > 'Z') && + (C < '0' || C > '9') && + C != '_' && C != '$' && C != '.' && C != '@') + return false; + return true; +} + +static char HexDigit(int V) { + return V < 10 ? V+'0' : V+'A'-10; +} + +static void MangleLetter(raw_ostream &OS, unsigned char C) { + OS << '_' << HexDigit(C >> 4) << HexDigit(C & 15) << '_'; +} + +/// NameNeedsEscaping - Return true if the identifier \arg Str needs quotes +/// for this assembler. +static bool NameNeedsEscaping(const StringRef &Str, const MCAsmInfo &MAI) { + assert(!Str.empty() && "Cannot create an empty MCSymbol"); + + // If the first character is a number and the target does not allow this, we + // need quotes. + if (!MAI.doesAllowNameToStartWithDigit() && Str[0] >= '0' && Str[0] <= '9') + return true; + + // If any of the characters in the string is an unacceptable character, force + // quotes. + for (unsigned i = 0, e = Str.size(); i != e; ++i) + if (!isAcceptableChar(Str[i])) + return true; + return false; +} + +static void PrintMangledName(raw_ostream &OS, StringRef Str, + const MCAsmInfo &MAI) { + // The first character is not allowed to be a number unless the target + // explicitly allows it. + if (!MAI.doesAllowNameToStartWithDigit() && Str[0] >= '0' && Str[0] <= '9') { + MangleLetter(OS, Str[0]); + Str = Str.substr(1); + } + + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + if (!isAcceptableChar(Str[i])) + MangleLetter(OS, Str[i]); + else + OS << Str[i]; + } +} + +/// PrintMangledQuotedName - On systems that support quoted symbols, we still +/// have to escape some (obscure) characters like " and \n which would break the +/// assembler's lexing. +static void PrintMangledQuotedName(raw_ostream &OS, StringRef Str) { + OS << '"'; + + for (unsigned i = 0, e = Str.size(); i != e; ++i) { + if (Str[i] == '"') + OS << "_QQ_"; + else if (Str[i] == '\n') + OS << "_NL_"; + else + OS << Str[i]; + } + OS << '"'; +} + + +void MCSymbol::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + if (MAI == 0 || !NameNeedsEscaping(getName(), *MAI)) { + OS << getName(); + return; + } + + // On systems that do not allow quoted names, print with mangling. + if (!MAI->doesAllowQuotesInName()) + return PrintMangledName(OS, getName(), *MAI); + + // If the string contains a double quote or newline, we still have to mangle + // it. + if (getName().find('"') != std::string::npos || + getName().find('\n') != std::string::npos) + return PrintMangledQuotedName(OS, getName()); + + OS << '"' << getName() << '"'; +} + +void MCSymbol::dump() const { + print(errs(), 0); +} diff --git a/lib/MC/MCValue.cpp b/lib/MC/MCValue.cpp new file mode 100644 index 0000000..69bd10c --- /dev/null +++ b/lib/MC/MCValue.cpp @@ -0,0 +1,34 @@ +//===- lib/MC/MCValue.cpp - MCValue implementation ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/MC/MCValue.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +void MCValue::print(raw_ostream &OS, const MCAsmInfo *MAI) const { + if (isAbsolute()) { + OS << getConstant(); + return; + } + + getSymA()->print(OS, MAI); + + if (getSymB()) { + OS << " - "; + getSymB()->print(OS, MAI); + } + + if (getConstant()) + OS << " + " << getConstant(); +} + +void MCValue::dump() const { + print(errs(), 0); +} diff --git a/lib/MC/TargetAsmParser.cpp b/lib/MC/TargetAsmParser.cpp new file mode 100644 index 0000000..05760c9 --- /dev/null +++ b/lib/MC/TargetAsmParser.cpp @@ -0,0 +1,19 @@ +//===-- TargetAsmParser.cpp - Target Assembly Parser -----------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Target/TargetAsmParser.h" +using namespace llvm; + +TargetAsmParser::TargetAsmParser(const Target &T) + : TheTarget(T) +{ +} + +TargetAsmParser::~TargetAsmParser() { +} |