diff options
Diffstat (limited to 'contrib/llvm/lib/MC/MCMachOStreamer.cpp')
-rw-r--r-- | contrib/llvm/lib/MC/MCMachOStreamer.cpp | 355 |
1 files changed, 41 insertions, 314 deletions
diff --git a/contrib/llvm/lib/MC/MCMachOStreamer.cpp b/contrib/llvm/lib/MC/MCMachOStreamer.cpp index 671874d..d1f9f5c 100644 --- a/contrib/llvm/lib/MC/MCMachOStreamer.cpp +++ b/contrib/llvm/lib/MC/MCMachOStreamer.cpp @@ -20,9 +20,11 @@ #include "llvm/MC/MCMachOSymbolFlags.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/MC/MCDwarf.h" +#include "llvm/Support/Dwarf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetAsmBackend.h" +#include "llvm/Target/TargetAsmInfo.h" using namespace llvm; @@ -30,13 +32,7 @@ namespace { class MCMachOStreamer : public MCObjectStreamer { private: - void EmitInstToFragment(const MCInst &Inst); - void EmitInstToData(const MCInst &Inst); - // FIXME: These will likely moved to a better place. - void MakeLineEntryForSection(const MCSection *Section); - const MCExpr * MakeStartMinusEndExpr(MCSymbol *Start, MCSymbol *End, - int IntVal); - void EmitDwarfFileTable(void); + virtual void EmitInstToData(const MCInst &Inst); public: MCMachOStreamer(MCContext &Context, TargetAsmBackend &TAB, @@ -46,8 +42,10 @@ public: /// @name MCStreamer Interface /// @{ + virtual void InitSections(); virtual void EmitLabel(MCSymbol *Symbol); virtual void EmitAssemblerFlag(MCAssemblerFlag Flag); + virtual void EmitThumbFunc(MCSymbol *Func); virtual void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value); virtual void EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute); virtual void EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue); @@ -76,17 +74,11 @@ public: virtual void EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment = 0); virtual void EmitBytes(StringRef Data, unsigned AddrSpace); - virtual void EmitValue(const MCExpr *Value, unsigned Size,unsigned AddrSpace); - virtual void EmitGPRel32Value(const MCExpr *Value) { - assert(0 && "macho doesn't support this directive"); - } virtual void EmitValueToAlignment(unsigned ByteAlignment, int64_t Value = 0, unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); virtual void EmitCodeAlignment(unsigned ByteAlignment, unsigned MaxBytesToEmit = 0); - virtual void EmitValueToOffset(const MCExpr *Offset, - unsigned char Value = 0); virtual void EmitFileDirective(StringRef Filename) { // FIXME: Just ignore the .file; it isn't important enough to fail the @@ -94,14 +86,6 @@ public: //report_fatal_error("unsupported directive: '.file'"); } - virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) { - // FIXME: Just ignore the .file; it isn't important enough to fail the - // entire assembly. - - //report_fatal_error("unsupported directive: '.file'"); - } - - virtual void EmitInstruction(const MCInst &Inst); virtual void Finish(); @@ -110,31 +94,26 @@ public: } // end anonymous namespace. -void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { - // TODO: This is almost exactly the same as WinCOFFStreamer. Consider merging - // into MCObjectStreamer. - assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); - assert(!Symbol->isVariable() && "Cannot emit a variable symbol!"); - assert(CurSection && "Cannot emit before setting section!"); +void MCMachOStreamer::InitSections() { + SwitchSection(getContext().getMachOSection("__TEXT", "__text", + MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, + 0, SectionKind::getText())); - Symbol->setSection(*CurSection); +} - MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); +void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { + assert(Symbol->isUndefined() && "Cannot define a symbol twice!"); + // isSymbolLinkerVisible uses the section. + Symbol->setSection(*getCurrentSection()); // We have to create a new fragment if this is an atom defining symbol, // fragments cannot span atoms. - if (getAssembler().isSymbolLinkerVisible(SD.getSymbol())) + if (getAssembler().isSymbolLinkerVisible(*Symbol)) new MCDataFragment(getCurrentSectionData()); - // FIXME: This is wasteful, we don't necessarily need to create a data - // fragment. Instead, we should mark the symbol as pointing into the data - // fragment if it exists, otherwise we should just queue the label and set its - // fragment pointer when we emit the next fragment. - MCDataFragment *F = getOrCreateDataFragment(); - assert(!SD.getFragment() && "Unexpected fragment on symbol data!"); - SD.setFragment(F); - SD.setOffset(F->getContents().size()); + MCObjectStreamer::EmitLabel(Symbol); + MCSymbolData &SD = getAssembler().getSymbolData(*Symbol); // This causes the reference type flag to be cleared. Darwin 'as' was "trying" // to clear the weak reference and weak definition bits too, but the // implementation was buggy. For now we just try to match 'as', for @@ -146,13 +125,31 @@ void MCMachOStreamer::EmitLabel(MCSymbol *Symbol) { } void MCMachOStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + // Let the target do whatever target specific stuff it needs to do. + getAssembler().getBackend().HandleAssemblerFlag(Flag); + // Do any generic stuff we need to do. switch (Flag) { + case MCAF_SyntaxUnified: return; // no-op here. + case MCAF_Code16: return; // no-op here. + case MCAF_Code32: return; // no-op here. case MCAF_SubsectionsViaSymbols: getAssembler().setSubsectionsViaSymbols(true); return; + default: + llvm_unreachable("invalid assembler flag!"); } +} + +void MCMachOStreamer::EmitThumbFunc(MCSymbol *Symbol) { + // FIXME: Flag the function ISA as thumb with DW_AT_APPLE_isa. - assert(0 && "invalid assembler flag!"); + // Remember that the function is a thumb function. Fixup and relocation + // values will need adjusted. + getAssembler().setIsThumbFunc(Symbol); + + // Mark the thumb bit on the symbol. + MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol); + SD.setFlags(SD.getFlags() | SF_ThumbFunc); } void MCMachOStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) { @@ -196,6 +193,7 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, case MCSA_ELF_TypeTLS: case MCSA_ELF_TypeCommon: case MCSA_ELF_TypeNoType: + case MCSA_ELF_TypeGnuUniqueObject: case MCSA_IndirectSymbol: case MCSA_Hidden: case MCSA_Internal: @@ -230,6 +228,10 @@ void MCMachOStreamer::EmitSymbolAttribute(MCSymbol *Symbol, SD.setFlags(SD.getFlags() | SF_NoDeadStrip); break; + case MCSA_SymbolResolver: + SD.setFlags(SD.getFlags() | SF_SymbolResolver); + break; + case MCSA_PrivateExtern: SD.setExternal(true); SD.setPrivateExtern(true); @@ -313,26 +315,6 @@ void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end()); } -void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, - unsigned AddrSpace) { - // TODO: This is exactly the same as WinCOFFStreamer. Consider merging into - // MCObjectStreamer. - MCDataFragment *DF = getOrCreateDataFragment(); - - // Avoid fixups when possible. - int64_t AbsValue; - if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) { - // FIXME: Endianness assumption. - for (unsigned i = 0; i != Size; ++i) - DF->getContents().push_back(uint8_t(AbsValue >> (i * 8))); - } else { - DF->addFixup(MCFixup::Create(DF->getContents().size(), - AddValueSymbols(Value), - MCFixup::getKindForSize(Size))); - DF->getContents().resize(DF->getContents().size() + Size, 0); - } -} - void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, unsigned ValueSize, unsigned MaxBytesToEmit) { @@ -363,28 +345,6 @@ void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, getCurrentSectionData()->setAlignment(ByteAlignment); } -void MCMachOStreamer::EmitValueToOffset(const MCExpr *Offset, - unsigned char Value) { - new MCOrgFragment(*Offset, Value, getCurrentSectionData()); -} - -void MCMachOStreamer::EmitInstToFragment(const MCInst &Inst) { - MCInstFragment *IF = new MCInstFragment(Inst, getCurrentSectionData()); - - // Add the fixups and data. - // - // FIXME: Revisit this design decision when relaxation is done, we may be - // able to get away with not storing any extra data in the MCInst. - SmallVector<MCFixup, 4> Fixups; - SmallString<256> Code; - raw_svector_ostream VecOS(Code); - getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups); - VecOS.flush(); - - IF->getCode() = Code; - IF->getFixups() = Fixups; -} - void MCMachOStreamer::EmitInstToData(const MCInst &Inst) { MCDataFragment *DF = getOrCreateDataFragment(); @@ -402,240 +362,7 @@ void MCMachOStreamer::EmitInstToData(const MCInst &Inst) { DF->getContents().append(Code.begin(), Code.end()); } -void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { - // Scan for values. - for (unsigned i = Inst.getNumOperands(); i--; ) - if (Inst.getOperand(i).isExpr()) - AddValueSymbols(Inst.getOperand(i).getExpr()); - - getCurrentSectionData()->setHasInstructions(true); - - // Now that a machine instruction has been assembled into this section, make - // a line entry for any .loc directive that has been seen. - MakeLineEntryForSection(getCurrentSection()); - - // If this instruction doesn't need relaxation, just emit it as data. - if (!getAssembler().getBackend().MayNeedRelaxation(Inst)) { - EmitInstToData(Inst); - return; - } - - // Otherwise, if we are relaxing everything, relax the instruction as much as - // possible and emit it as data. - if (getAssembler().getRelaxAll()) { - MCInst Relaxed; - getAssembler().getBackend().RelaxInstruction(Inst, Relaxed); - while (getAssembler().getBackend().MayNeedRelaxation(Relaxed)) - getAssembler().getBackend().RelaxInstruction(Relaxed, Relaxed); - EmitInstToData(Relaxed); - return; - } - - // Otherwise emit to a separate fragment. - EmitInstToFragment(Inst); -} - -// -// This is called when an instruction is assembled into the specified section -// and if there is information from the last .loc directive that has yet to have -// a line entry made for it is made. -// -void MCMachOStreamer::MakeLineEntryForSection(const MCSection *Section) { - if (!getContext().getDwarfLocSeen()) - return; - - // Create a symbol at in the current section for use in the line entry. - MCSymbol *LineSym = getContext().CreateTempSymbol(); - // Set the value of the symbol to use for the MCLineEntry. - EmitLabel(LineSym); - - // Get the current .loc info saved in the context. - const MCDwarfLoc &DwarfLoc = getContext().getCurrentDwarfLoc(); - - // Create a (local) line entry with the symbol and the current .loc info. - MCLineEntry LineEntry(LineSym, DwarfLoc); - - // clear DwarfLocSeen saying the current .loc info is now used. - getContext().clearDwarfLocSeen(); - - // Get the MCLineSection for this section, if one does not exist for this - // section create it. - DenseMap<const MCSection *, MCLineSection *> &MCLineSections = - getContext().getMCLineSections(); - MCLineSection *LineSection = MCLineSections[Section]; - if (!LineSection) { - // Create a new MCLineSection. This will be deleted after the dwarf line - // table is created using it by iterating through the MCLineSections - // DenseMap. - LineSection = new MCLineSection; - // Save a pointer to the new LineSection into the MCLineSections DenseMap. - MCLineSections[Section] = LineSection; - } - - // Add the line entry to this section's entries. - LineSection->addLineEntry(LineEntry); -} - -// -// This helper routine returns an expression of End - Start + IntVal for use -// by EmitDwarfFileTable() below. -// -const MCExpr * MCMachOStreamer::MakeStartMinusEndExpr(MCSymbol *Start, - MCSymbol *End, - int IntVal) { - MCSymbolRefExpr::VariantKind Variant = MCSymbolRefExpr::VK_None; - const MCExpr *Res = - MCSymbolRefExpr::Create(End, Variant, getContext()); - const MCExpr *RHS = - MCSymbolRefExpr::Create(Start, Variant, getContext()); - const MCExpr *Res1 = - MCBinaryExpr::Create(MCBinaryExpr::Sub, Res, RHS,getContext()); - const MCExpr *Res2 = - MCConstantExpr::Create(IntVal, getContext()); - const MCExpr *Res3 = - MCBinaryExpr::Create(MCBinaryExpr::Sub, Res1, Res2, getContext()); - return Res3; -} - -// -// This emits the Dwarf file (and eventually the line) table. -// -void MCMachOStreamer::EmitDwarfFileTable(void) { - // For now make sure we don't put out the Dwarf file table if no .file - // directives were seen. - const std::vector<MCDwarfFile *> &MCDwarfFiles = - getContext().getMCDwarfFiles(); - if (MCDwarfFiles.size() == 0) - return; - - // This is the Mach-O section, for ELF it is the .debug_line section. - SwitchSection(getContext().getMachOSection("__DWARF", "__debug_line", - MCSectionMachO::S_ATTR_DEBUG, - 0, SectionKind::getDataRelLocal())); - - // Create a symbol at the beginning of this section. - MCSymbol *LineStartSym = getContext().CreateTempSymbol(); - // Set the value of the symbol, as we are at the start of the section. - EmitLabel(LineStartSym); - - // Create a symbol for the end of the section (to be set when we get there). - MCSymbol *LineEndSym = getContext().CreateTempSymbol(); - - // The first 4 bytes is the total length of the information for this - // compilation unit (not including these 4 bytes for the length). - EmitValue(MakeStartMinusEndExpr(LineStartSym, LineEndSym, 4), 4, 0); - - // Next 2 bytes is the Version, which is Dwarf 2. - EmitIntValue(2, 2); - - // Create a symbol for the end of the prologue (to be set when we get there). - MCSymbol *ProEndSym = getContext().CreateTempSymbol(); // Lprologue_end - - // Length of the prologue, is the next 4 bytes. Which is the start of the - // section to the end of the prologue. Not including the 4 bytes for the - // total length, the 2 bytes for the version, and these 4 bytes for the - // length of the prologue. - EmitValue(MakeStartMinusEndExpr(LineStartSym, ProEndSym, (4 + 2 + 4)), 4, 0); - - // Parameters of the state machine, are next. - // Define the architecture-dependent minimum instruction length (in - // bytes). This value should be rather too small than too big. */ - // DWARF2_LINE_MIN_INSN_LENGTH - EmitIntValue(1, 1); - // Flag that indicates the initial value of the is_stmt_start flag. - // DWARF2_LINE_DEFAULT_IS_STMT - EmitIntValue(1, 1); - // Minimum line offset in a special line info. opcode. This value - // was chosen to give a reasonable range of values. */ - // DWARF2_LINE_BASE - EmitIntValue(uint64_t(-5), 1); - // Range of line offsets in a special line info. opcode. - // DWARF2_LINE_RANGE - EmitIntValue(14, 1); - // First special line opcode - leave room for the standard opcodes. - // DWARF2_LINE_OPCODE_BASE - EmitIntValue(13, 1); - - // Standard opcode lengths - EmitIntValue(0, 1); // length of DW_LNS_copy - EmitIntValue(1, 1); // length of DW_LNS_advance_pc - EmitIntValue(1, 1); // length of DW_LNS_advance_line - EmitIntValue(1, 1); // length of DW_LNS_set_file - EmitIntValue(1, 1); // length of DW_LNS_set_column - EmitIntValue(0, 1); // length of DW_LNS_negate_stmt - EmitIntValue(0, 1); // length of DW_LNS_set_basic_block - EmitIntValue(0, 1); // length of DW_LNS_const_add_pc - EmitIntValue(1, 1); // length of DW_LNS_fixed_advance_pc - EmitIntValue(0, 1); // length of DW_LNS_set_prologue_end - EmitIntValue(0, 1); // length of DW_LNS_set_epilogue_begin - EmitIntValue(1, 1); // DW_LNS_set_isa - - // Put out the directory and file tables. - - // First the directory table. - const std::vector<StringRef> &MCDwarfDirs = - getContext().getMCDwarfDirs(); - for (unsigned i = 0; i < MCDwarfDirs.size(); i++) { - EmitBytes(MCDwarfDirs[i], 0); // the DirectoryName - EmitBytes(StringRef("\0", 1), 0); // the null termination of the string - } - EmitIntValue(0, 1); // Terminate the directory list - - // Second the file table. - for (unsigned i = 1; i < MCDwarfFiles.size(); i++) { - EmitBytes(MCDwarfFiles[i]->getName(), 0); // FileName - EmitBytes(StringRef("\0", 1), 0); // the null termination of the string - // FIXME the Directory number should be a .uleb128 not a .byte - EmitIntValue(MCDwarfFiles[i]->getDirIndex(), 1); - EmitIntValue(0, 1); // last modification timestamp (always 0) - EmitIntValue(0, 1); // filesize (always 0) - } - EmitIntValue(0, 1); // Terminate the file list - - // This is the end of the prologue, so set the value of the symbol at the - // end of the prologue (that was used in a previous expression). - EmitLabel(ProEndSym); - - // TODO: This is the point where the line tables would be emitted. - - // Delete the MCLineSections that were created in - // MCMachOStreamer::MakeLineEntryForSection() and used to emit the line - // tables. - DenseMap<const MCSection *, MCLineSection *> &MCLineSections = - getContext().getMCLineSections(); - for (DenseMap<const MCSection *, MCLineSection *>::iterator it = - MCLineSections.begin(), ie = MCLineSections.end(); it != ie; ++it) { - delete it->second; - } - - // If there are no line tables emited then we emit: - // The following DW_LNE_set_address sequence to set the address to zero - // TODO test for 32-bit or 64-bit output - // This is the sequence for 32-bit code - EmitIntValue(0, 1); - EmitIntValue(5, 1); - EmitIntValue(2, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - EmitIntValue(0, 1); - - // Lastly emit the DW_LNE_end_sequence which consists of 3 bytes '00 01 01' - // (00 is the code for extended opcodes, followed by a ULEB128 length of the - // extended opcode (01), and the DW_LNE_end_sequence (01). - EmitIntValue(0, 1); // DW_LNS_extended_op - EmitIntValue(1, 1); // ULEB128 length of the extended opcode - EmitIntValue(1, 1); // DW_LNE_end_sequence - - // This is the end of the section, so set the value of the symbol at the end - // of this section (that was used in a previous expression). - EmitLabel(LineEndSym); -} - void MCMachOStreamer::Finish() { - // Dump out the dwarf file and directory tables (soon to include line table) - EmitDwarfFileTable(); - // We have to set the fragment atom associations so we can relax properly for // Mach-O. |