diff options
Diffstat (limited to 'contrib/llvm/lib/MC/MCMachOStreamer.cpp')
-rw-r--r-- | contrib/llvm/lib/MC/MCMachOStreamer.cpp | 277 |
1 files changed, 231 insertions, 46 deletions
diff --git a/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp index 44bc267..671874d 100644 --- a/contrib/llvm/lib/MC/MCMachOStreamer.cpp +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -18,6 +18,8 @@ #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCMachOSymbolFlags.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCDwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" @@ -28,58 +30,19 @@ namespace { class MCMachOStreamer : public MCObjectStreamer { private: - MCFragment *getCurrentFragment() const { - assert(getCurrentSectionData() && "No current section!"); - - if (!getCurrentSectionData()->empty()) - return &getCurrentSectionData()->getFragmentList().back(); - - return 0; - } - - /// Get a data fragment to write into, creating a new one if the current - /// fragment is not a data fragment. - MCDataFragment *getOrCreateDataFragment() const { - MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); - if (!F) - F = new MCDataFragment(getCurrentSectionData()); - return F; - } - void EmitInstToFragment(const MCInst &Inst); void EmitInstToData(const MCInst &Inst); + // FIXME: These will likely moved to a better place. + void MakeLineEntryForSection(const MCSection *Section); + const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, + int IntVal); + void EmitDwarfFileTable(void); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, raw_ostream &OS, MCCodeEmitter *Emitter) : MCObjectStreamer(Context, TAB, OS, Emitter) {} - const MCExpr *AddValueSymbols(const MCExpr *Value) { - switch (Value->getKind()) { - case MCExpr::Target: assert(0 && "Can't handle target exprs yet!"); - case MCExpr::Constant: - break; - - case MCExpr::Binary: { - const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value); - AddValueSymbols(BE->getLHS()); - AddValueSymbols(BE->getRHS()); - break; - } - - case MCExpr::SymbolRef: - getAssembler().getOrCreateSymbolData( - cast<MCSymbolRefExpr>(Value)->getSymbol()); - break; - - case MCExpr::Unary: - AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr()); - break; - } - - return Value; - } - /// @name MCStreamer Interface /// @{ @@ -126,10 +89,16 @@ public: unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename) { - report_fatal_error("unsupported directive: '.file'"); + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + //report_fatal_error("unsupported directive: '.file'"); } virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - report_fatal_error("unsupported directive: '.file'"); + // FIXME: Just ignore the .file; it isn't important enough to fail the + // entire assembly. + + //report_fatal_error("unsupported directive: '.file'"); } virtual void EmitInstruction(const MCInst &Inst); @@ -142,6 +111,8 @@ public: } // end anonymous namespace. void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + // TODO: This is almost exactly the same as WinCOFFStreamer. Consider merging + // into MCObjectStreamer. assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); assert(CurSection && "Cannot emit before setting section!"); @@ -185,6 +156,8 @@ void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. // FIXME: Lift context changes into super class. getAssembler().getOrCreateSymbolData(*Symbol); Symbol->setVariableValue(AddValueSymbols(Value)); @@ -335,11 +308,15 @@ void MCMachOStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, } void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. MCDataFragment *DF = getOrCreateDataFragment(); // Avoid fixups when possible. @@ -359,6 +336,8 @@ void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, @@ -371,6 +350,8 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit) { + // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into + // MCObjectStreamer. if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; MCAlignFragment *F = new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit, @@ -429,6 +410,10 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { getCurrentSectionData()->setHasInstructions(true); + // Now that a machine instruction has been assembled into this section, make + // a line entry for any .loc directive that has been seen. + MakeLineEntryForSection(getCurrentSection()); + // If this instruction doesn't need relaxation, just emit it as data. if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { EmitInstToData(Inst); @@ -450,7 +435,207 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { EmitInstToFragment(Inst); } +// +// This is called when an instruction is assembled into the specified section +// and if there is information from the last .loc directive that has yet to have +// a line entry made for it is made. +// +void MCMachOStreamer::MakeLineEntryForSection(const MCSection *Section) { + if (!getContext().getDwarfLocSeen()) + return; + + // Create a symbol at in the current section for use in the line entry. + MCSymbol *LineSym = getContext().CreateTempSymbol(); + // Set the value of the symbol to use for the MCLineEntry. + EmitLabel(LineSym); + + // Get the current .loc info saved in the context. + const MCDwarfLoc &DwarfLoc = getContext().getCurrentDwarfLoc(); + + // Create a (local) line entry with the symbol and the current .loc info. + MCLineEntry LineEntry(LineSym, DwarfLoc); + + // clear DwarfLocSeen saying the current .loc info is now used. + getContext().clearDwarfLocSeen(); + + // Get the MCLineSection for this section, if one does not exist for this + // section create it. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + getContext().getMCLineSections(); + MCLineSection *LineSection = MCLineSections[Section]; + if (!LineSection) { + // Create a new MCLineSection. This will be deleted after the dwarf line + // table is created using it by iterating through the MCLineSections + // DenseMap. + LineSection = new MCLineSection; + // Save a pointer to the new LineSection into the MCLineSections DenseMap. + MCLineSections[Section] = LineSection; + } + + // Add the line entry to this section's entries. + LineSection->addLineEntry(LineEntry); +} + +// +// This helper routine returns an expression of End - Start + IntVal for use +// by EmitDwarfFileTable() below. +// +const MCExpr * MCMachOStreamer::MakeStartMinusEndExpr(MCSymbol *Start, + MCSymbol *End, + int IntVal) { + MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; + const MCExpr *Res = + MCSymbolRefExpr::Create(End, Variant, getContext()); + const MCExpr *RHS = + MCSymbolRefExpr::Create(Start, Variant, getContext()); + const MCExpr *Res1 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS,getContext()); + const MCExpr *Res2 = + MCConstantExpr::Create(IntVal, getContext()); + const MCExpr *Res3 = + MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, getContext()); + return Res3; +} + +// +// This emits the Dwarf file (and eventually the line) table. +// +void MCMachOStreamer::EmitDwarfFileTable(void) { + // For now make sure we don't put out the Dwarf file table if no .file + // directives were seen. + const std::vector<MCDwarfFile *> &MCDwarfFiles = + getContext().getMCDwarfFiles(); + if (MCDwarfFiles.size() == 0) + return; + + // This is the Mach-O section, for ELF it is the .debug_line section. + SwitchSection(getContext().getMachOSection("__DWARF", "__debug_line", + MCSectionMachO::S_ATTR_DEBUG, + 0, SectionKind::getDataRelLocal())); + + // Create a symbol at the beginning of this section. + MCSymbol *LineStartSym = getContext().CreateTempSymbol(); + // Set the value of the symbol, as we are at the start of the section. + EmitLabel(LineStartSym); + + // Create a symbol for the end of the section (to be set when we get there). + MCSymbol *LineEndSym = getContext().CreateTempSymbol(); + + // The first 4 bytes is the total length of the information for this + // compilation unit (not including these 4 bytes for the length). + EmitValue(MakeStartMinusEndExpr(LineStartSym, LineEndSym, 4), 4, 0); + + // Next 2 bytes is the Version, which is Dwarf 2. + EmitIntValue(2, 2); + + // Create a symbol for the end of the prologue (to be set when we get there). + MCSymbol *ProEndSym = getContext().CreateTempSymbol(); // Lprologue_end + + // Length of the prologue, is the next 4 bytes. Which is the start of the + // section to the end of the prologue. Not including the 4 bytes for the + // total length, the 2 bytes for the version, and these 4 bytes for the + // length of the prologue. + EmitValue(MakeStartMinusEndExpr(LineStartSym, ProEndSym, (4 + 2 + 4)), 4, 0); + + // Parameters of the state machine, are next. + // Define the architecture-dependent minimum instruction length (in + // bytes). This value should be rather too small than too big. */ + // DWARF2_LINE_MIN_INSN_LENGTH + EmitIntValue(1, 1); + // Flag that indicates the initial value of the is_stmt_start flag. + // DWARF2_LINE_DEFAULT_IS_STMT + EmitIntValue(1, 1); + // Minimum line offset in a special line info. opcode. This value + // was chosen to give a reasonable range of values. */ + // DWARF2_LINE_BASE + EmitIntValue(uint64_t(-5), 1); + // Range of line offsets in a special line info. opcode. + // DWARF2_LINE_RANGE + EmitIntValue(14, 1); + // First special line opcode - leave room for the standard opcodes. + // DWARF2_LINE_OPCODE_BASE + EmitIntValue(13, 1); + + // Standard opcode lengths + EmitIntValue(0, 1); // length of DW_LNS_copy + EmitIntValue(1, 1); // length of DW_LNS_advance_pc + EmitIntValue(1, 1); // length of DW_LNS_advance_line + EmitIntValue(1, 1); // length of DW_LNS_set_file + EmitIntValue(1, 1); // length of DW_LNS_set_column + EmitIntValue(0, 1); // length of DW_LNS_negate_stmt + EmitIntValue(0, 1); // length of DW_LNS_set_basic_block + EmitIntValue(0, 1); // length of DW_LNS_const_add_pc + EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc + EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end + EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin + EmitIntValue(1, 1); // DW_LNS_set_isa + + // Put out the directory and file tables. + + // First the directory table. + const std::vector<StringRef> &MCDwarfDirs = + getContext().getMCDwarfDirs(); + for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { + EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName + EmitBytes(StringRef("\0", 1), 0); // the null termination of the string + } + EmitIntValue(0, 1); // Terminate the directory list + + // Second the file table. + for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { + EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName + EmitBytes(StringRef("\0", 1), 0); // the null termination of the string + // FIXME the Directory number should be a .uleb128 not a .byte + EmitIntValue(MCDwarfFiles[i]->getDirIndex(), 1); + EmitIntValue(0, 1); // last modification timestamp (always 0) + EmitIntValue(0, 1); // filesize (always 0) + } + EmitIntValue(0, 1); // Terminate the file list + + // This is the end of the prologue, so set the value of the symbol at the + // end of the prologue (that was used in a previous expression). + EmitLabel(ProEndSym); + + // TODO: This is the point where the line tables would be emitted. + + // Delete the MCLineSections that were created in + // MCMachOStreamer::MakeLineEntryForSection() and used to emit the line + // tables. + DenseMap<const MCSection *, MCLineSection *> &MCLineSections = + getContext().getMCLineSections(); + for (DenseMap<const MCSection *, MCLineSection *>::iterator it = + MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { + delete it->second; + } + + // If there are no line tables emited then we emit: + // The following DW_LNE_set_address sequence to set the address to zero + // TODO test for 32-bit or 64-bit output + // This is the sequence for 32-bit code + EmitIntValue(0, 1); + EmitIntValue(5, 1); + EmitIntValue(2, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + EmitIntValue(0, 1); + + // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' + // (00 is the code for extended opcodes, followed by a ULEB128 length of the + // extended opcode (01), and the DW_LNE_end_sequence (01). + EmitIntValue(0, 1); // DW_LNS_extended_op + EmitIntValue(1, 1); // ULEB128 length of the extended opcode + EmitIntValue(1, 1); // DW_LNE_end_sequence + + // This is the end of the section, so set the value of the symbol at the end + // of this section (that was used in a previous expression). + EmitLabel(LineEndSym); +} + void MCMachOStreamer::Finish() { + // Dump out the dwarf file and directory tables (soon to include line table) + EmitDwarfFileTable(); + // We have to set the fragment atom associations so we can relax properly for // Mach-O. |