diff options
Diffstat (limited to 'lib/MC')
-rw-r--r-- | lib/MC/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/MC/MCAsmStreamer.cpp | 10 | ||||
-rw-r--r-- | lib/MC/MCAssembler.cpp | 82 | ||||
-rw-r--r-- | lib/MC/MCMachOStreamer.cpp | 21 | ||||
-rw-r--r-- | lib/MC/MCNullStreamer.cpp | 3 | ||||
-rw-r--r-- | lib/MC/MCParser/AsmParser.cpp | 26 | ||||
-rw-r--r-- | lib/MC/TargetAsmBackend.cpp | 19 |
7 files changed, 142 insertions, 20 deletions
diff --git a/lib/MC/CMakeLists.txt b/lib/MC/CMakeLists.txt index 9ead33b..4cf71dc 100644 --- a/lib/MC/CMakeLists.txt +++ b/lib/MC/CMakeLists.txt @@ -18,4 +18,5 @@ add_llvm_library(LLVMMC MCStreamer.cpp MCSymbol.cpp MCValue.cpp + TargetAsmBackend.cpp ) diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index 6add1b4..66a0a24 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -134,6 +134,9 @@ public: unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0); + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0); + virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0); @@ -513,6 +516,13 @@ void MCAsmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, EmitEOL(); } +void MCAsmStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + // Emit with a text fill value. + EmitValueToAlignment(ByteAlignment, MAI.getTextAlignFillValue(), + 1, MaxBytesToEmit); +} + void MCAsmStreamer::EmitValueToOffset(const MCExpr *Offset, unsigned char Value) { // FIXME: Verify that Offset is associated with the current section. diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 653fbf2..96227db 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -42,6 +42,8 @@ STATISTIC(EmittedFragments, "Number of emitted assembler fragments"); static void WriteFileData(raw_ostream &OS, const MCSectionData &SD, MachObjectWriter &MOW); +static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW); + /// isVirtualSection - Check if this is a section which does not actually exist /// in the object file. static bool isVirtualSection(const MCSection &Section) { @@ -51,7 +53,7 @@ static bool isVirtualSection(const MCSection &Section) { return (Type == MCSectionMachO::S_ZEROFILL); } -static unsigned getFixupKindLog2Size(MCFixupKind Kind) { +static unsigned getFixupKindLog2Size(unsigned Kind) { switch (Kind) { default: llvm_unreachable("invalid fixup kind!"); case X86::reloc_pcrel_1byte: @@ -64,7 +66,7 @@ static unsigned getFixupKindLog2Size(MCFixupKind Kind) { } } -static bool isFixupKindPCRel(MCFixupKind Kind) { +static bool isFixupKindPCRel(unsigned Kind) { switch (Kind) { default: return false; @@ -439,6 +441,7 @@ public: std::vector<MachRelocationEntry> &Relocs) { uint32_t Address = Fragment.getOffset() + Fixup.Offset; unsigned IsPCRel = 0; + unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); unsigned Type = RIT_Vanilla; // See <reloc.h>. @@ -454,12 +457,10 @@ public: Value2 = SD->getFragment()->getAddress() + SD->getOffset(); } - unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); - // The value which goes in the fixup is current value of the expression. Fixup.FixedValue = Value - Value2 + Target.getConstant(); if (isFixupKindPCRel(Fixup.Kind)) { - Fixup.FixedValue -= Address + (1 << Log2Size); + Fixup.FixedValue -= Address; IsPCRel = 1; } @@ -507,6 +508,7 @@ public: uint32_t Value = 0; unsigned Index = 0; unsigned IsPCRel = 0; + unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); unsigned IsExtern = 0; unsigned Type = 0; @@ -544,10 +546,8 @@ public: // The value which goes in the fixup is current value of the expression. Fixup.FixedValue = Value + Target.getConstant(); - unsigned Log2Size = getFixupKindLog2Size(Fixup.Kind); - if (isFixupKindPCRel(Fixup.Kind)) { - Fixup.FixedValue -= Address + (1<<Log2Size); + Fixup.FixedValue -= Address; IsPCRel = 1; } @@ -1060,6 +1060,64 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { SD.setFileSize(Address - SD.getAddress()); } +/// WriteNopData - Write optimal nops to the output file for the \arg Count +/// bytes. This returns the number of bytes written. It may return 0 if +/// the \arg Count is more than the maximum optimal nops. +/// +/// FIXME this is X86 32-bit specific and should move to a better place. +static uint64_t WriteNopData(uint64_t Count, MachObjectWriter &MOW) { + static const uint8_t Nops[16][16] = { + // nop + {0x90}, + // xchg %ax,%ax + {0x66, 0x90}, + // nopl (%[re]ax) + {0x0f, 0x1f, 0x00}, + // nopl 0(%[re]ax) + {0x0f, 0x1f, 0x40, 0x00}, + // nopl 0(%[re]ax,%[re]ax,1) + {0x0f, 0x1f, 0x44, 0x00, 0x00}, + // nopw 0(%[re]ax,%[re]ax,1) + {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, + // nopl 0L(%[re]ax) + {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, + // nopl 0L(%[re]ax,%[re]ax,1) + {0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + // nopw 0L(%[re]ax,%[re]ax,1) + {0x66, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + // nopw %cs:0L(%[re]ax,%[re]ax,1) + {0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00}, + // nopl 0(%[re]ax,%[re]ax,1) + // nopw 0(%[re]ax,%[re]ax,1) + {0x0f, 0x1f, 0x44, 0x00, 0x00, + 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, + // nopw 0(%[re]ax,%[re]ax,1) + // nopw 0(%[re]ax,%[re]ax,1) + {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, + 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00}, + // nopw 0(%[re]ax,%[re]ax,1) + // nopl 0L(%[re]ax) */ + {0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00, + 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, + // nopl 0L(%[re]ax) + // nopl 0L(%[re]ax) + {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00}, + // nopl 0L(%[re]ax) + // nopl 0L(%[re]ax,%[re]ax,1) + {0x0f, 0x1f, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00} + }; + + if (Count > 15) + return 0; + + for (uint64_t i = 0; i < Count; i++) + MOW.Write8 (uint8_t(Nops[Count - 1][i])); + + return Count; +} + /// WriteFileData - Write the \arg F data to the output file. static void WriteFileData(raw_ostream &OS, const MCFragment &F, MachObjectWriter &MOW) { @@ -1083,6 +1141,14 @@ static void WriteFileData(raw_ostream &OS, const MCFragment &F, "' is not a divisor of padding size '" + Twine(AF.getFileSize()) + "'"); + // See if we are aligning with nops, and if so do that first to try to fill + // the Count bytes. Then if that did not fill any bytes or there are any + // bytes left to fill use the the Value and ValueSize to fill the rest. + if (AF.getEmitNops()) { + uint64_t NopByteCount = WriteNopData(Count, MOW); + Count -= NopByteCount; + } + for (uint64_t i = 0; i != Count; ++i) { switch (AF.getValueSize()) { default: diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 0c9627d..a7a8a5d 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -137,6 +137,8 @@ public: 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); @@ -333,15 +335,13 @@ void MCMachOStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) { void MCMachOStreamer::EmitValue(const MCExpr *Value, unsigned Size, unsigned AddrSpace) { - // Assume the front-end will have evaluate things absolute expressions, so - // just create data + fixup. MCDataFragment *DF = dyn_cast_or_null<MCDataFragment>(getCurrentFragment()); if (!DF) DF = new MCDataFragment(CurSectionData); // Avoid fixups when possible. int64_t AbsValue; - if (Value->EvaluateAsAbsolute(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))); @@ -359,7 +359,20 @@ void MCMachOStreamer::EmitValueToAlignment(unsigned ByteAlignment, if (MaxBytesToEmit == 0) MaxBytesToEmit = ByteAlignment; new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit, - CurSectionData); + false /* EmitNops */, CurSectionData); + + // Update the maximum alignment on the current section if necessary. + if (ByteAlignment > CurSectionData->getAlignment()) + CurSectionData->setAlignment(ByteAlignment); +} + +void MCMachOStreamer::EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit) { + if (MaxBytesToEmit == 0) + MaxBytesToEmit = ByteAlignment; + // FIXME the 0x90 is the default x86 1 byte nop opcode. + new MCAlignFragment(ByteAlignment, 0x90, 1, MaxBytesToEmit, + true /* EmitNops */, CurSectionData); // Update the maximum alignment on the current section if necessary. if (ByteAlignment > CurSectionData->getAlignment()) diff --git a/lib/MC/MCNullStreamer.cpp b/lib/MC/MCNullStreamer.cpp index 46e9ebf..ab61799 100644 --- a/lib/MC/MCNullStreamer.cpp +++ b/lib/MC/MCNullStreamer.cpp @@ -55,6 +55,9 @@ namespace { unsigned ValueSize = 1, unsigned MaxBytesToEmit = 0) {} + virtual void EmitCodeAlignment(unsigned ByteAlignment, + unsigned MaxBytesToEmit = 0) {} + virtual void EmitValueToOffset(const MCExpr *Offset, unsigned char Value = 0) {} diff --git a/lib/MC/MCParser/AsmParser.cpp b/lib/MC/MCParser/AsmParser.cpp index 51ad5d1..6185c30 100644 --- a/lib/MC/MCParser/AsmParser.cpp +++ b/lib/MC/MCParser/AsmParser.cpp @@ -146,7 +146,7 @@ bool AsmParser::Run() { // FIXME: Target hook & command line option for initial section. Out.SwitchSection(getMachOSection("__TEXT", "__text", MCSectionMachO::S_ATTR_PURE_INSTRUCTIONS, - 0, SectionKind())); + 0, SectionKind::getText())); // Prime the lexer. @@ -914,8 +914,10 @@ bool AsmParser::ParseDirectiveDarwinSection() { return Error(Loc, ErrorStr.c_str()); // FIXME: Arch specific. + bool isText = Segment == "__TEXT"; // FIXME: Hack. Out.SwitchSection(getMachOSection(Segment, Section, TAA, StubSize, - SectionKind())); + isText ? SectionKind::getText() + : SectionKind::getDataRel())); return false; } @@ -929,8 +931,10 @@ bool AsmParser::ParseDirectiveSectionSwitch(const char *Segment, Lex(); // FIXME: Arch specific. + bool isText = StringRef(Segment) == "__TEXT"; // FIXME: Hack. Out.SwitchSection(getMachOSection(Segment, Section, TAA, StubSize, - SectionKind())); + isText ? SectionKind::getText() + : SectionKind::getDataRel())); // Set the implicit alignment, if any. // @@ -1237,8 +1241,14 @@ bool AsmParser::ParseDirectiveAlign(bool IsPow2, unsigned ValueSize) { } } - // FIXME: Target specific behavior about how the "extra" bytes are filled. - Out.EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill); + // FIXME: hard code the parser to use EmitCodeAlignment for text when using + // the TextAlignFillValue. + if(Out.getCurrentSection()->getKind().isText() && + Lexer.getMAI().getTextAlignFillValue() == FillExpr) + Out.EmitCodeAlignment(Alignment, MaxBytesToFill); + else + // FIXME: Target specific behavior about how the "extra" bytes are filled. + Out.EmitValueToAlignment(Alignment, FillExpr, ValueSize, MaxBytesToFill); return false; } @@ -1362,7 +1372,7 @@ bool AsmParser::ParseDirectiveComm(bool IsLocal) { if (IsLocal) { Out.EmitZerofill(getMachOSection("__DATA", "__bss", MCSectionMachO::S_ZEROFILL, 0, - SectionKind()), + SectionKind::getBSS()), Sym, Size, 1 << Pow2Alignment); return false; } @@ -1398,7 +1408,7 @@ bool AsmParser::ParseDirectiveDarwinZerofill() { // Create the zerofill section but no symbol Out.EmitZerofill(getMachOSection(Segment, Section, MCSectionMachO::S_ZEROFILL, 0, - SectionKind())); + SectionKind::getBSS())); return false; } @@ -1456,7 +1466,7 @@ bool AsmParser::ParseDirectiveDarwinZerofill() { // FIXME: Arch specific. Out.EmitZerofill(getMachOSection(Segment, Section, MCSectionMachO::S_ZEROFILL, 0, - SectionKind()), + SectionKind::getBSS()), Sym, Size, 1 << Pow2Alignment); return false; diff --git a/lib/MC/TargetAsmBackend.cpp b/lib/MC/TargetAsmBackend.cpp new file mode 100644 index 0000000..918d272 --- /dev/null +++ b/lib/MC/TargetAsmBackend.cpp @@ -0,0 +1,19 @@ +//===-- TargetAsmBackend.cpp - Target Assembly Backend ---------------------==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Target/TargetAsmBackend.h" +using namespace llvm; + +TargetAsmBackend::TargetAsmBackend(const Target &T) + : TheTarget(T) +{ +} + +TargetAsmBackend::~TargetAsmBackend() { +} |