From: Daniel Dunbar Date: Tue, 9 Feb 2010 22:59:55 +0000 (+0000) Subject: MC: First cut at MCFixup, for getting fixup/relocation information out of an MCCodeEm... X-Git-Tag: android-x86-6.0-r1~1003^2~10044 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=73c557458c0e28899f37c557bcaf36c2b6701260;p=android-x86%2Fexternal-llvm.git MC: First cut at MCFixup, for getting fixup/relocation information out of an MCCodeEmitter. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@95708 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/MC/MCCodeEmitter.h b/include/llvm/MC/MCCodeEmitter.h index ad42dc2e5b4..5565945f5ab 100644 --- a/include/llvm/MC/MCCodeEmitter.h +++ b/include/llvm/MC/MCCodeEmitter.h @@ -10,23 +10,60 @@ #ifndef LLVM_MC_MCCODEEMITTER_H #define LLVM_MC_MCCODEEMITTER_H +#include "llvm/MC/MCFixup.h" + +#include + namespace llvm { +class MCExpr; class MCInst; class raw_ostream; +template class SmallVectorImpl; + +/// MCFixupKindInfo - Target independent information on a fixup kind. +struct MCFixupKindInfo { + /// A target specific name for the fixup kind. The names will be unique for + /// distinct kinds on any given target. + const char *Name; + + /// The bit offset to write the relocation into. + // + // FIXME: These two fields are under-specified and not general enough, but it + // is covers many things, and is enough to let the AsmStreamer pretty-print + // the encoding. + unsigned TargetOffset; + + /// The number of bits written by this fixup. The bits are assumed to be + /// contiguous. + unsigned TargetSize; +}; /// MCCodeEmitter - Generic instruction encoding interface. class MCCodeEmitter { +private: MCCodeEmitter(const MCCodeEmitter &); // DO NOT IMPLEMENT void operator=(const MCCodeEmitter &); // DO NOT IMPLEMENT protected: // Can only create subclasses. MCCodeEmitter(); - + public: virtual ~MCCodeEmitter(); + /// @name Target Independent Fixup Information + /// @{ + + /// getNumFixupKinds - Get the number of target specific fixup kinds. + virtual unsigned getNumFixupKinds() const = 0; + + /// getFixupKindInfo - Get information on a fixup kind. + virtual MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const = 0; + + /// @} + /// EncodeInstruction - Encode the given \arg Inst to bytes on the output /// stream \arg OS. - virtual void EncodeInstruction(const MCInst &Inst, raw_ostream &OS) const = 0; + virtual void EncodeInstruction(const MCInst &Inst, raw_ostream &OS, + SmallVectorImpl &Fixups) const = 0; }; } // End llvm namespace diff --git a/include/llvm/MC/MCFixup.h b/include/llvm/MC/MCFixup.h new file mode 100644 index 00000000000..da8e92efe13 --- /dev/null +++ b/include/llvm/MC/MCFixup.h @@ -0,0 +1,95 @@ +//===-- llvm/MC/MCFixup.h - Instruction Relocation and Patching -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_MC_MCFIXUP_H +#define LLVM_MC_MCFIXUP_H + +#include + +namespace llvm { + +// Private constants, do not use. +// +// This is currently layed out so that the MCFixup fields can be efficiently +// accessed, while keeping the offset field large enought that the assembler +// backend can reasonably use the MCFixup representation for an entire fragment +// (splitting any overly large fragments). +// +// The division of bits between the kind and the opindex can be tweaked if we +// end up needing more bits for target dependent kinds. +enum { + MCFIXUP_NUM_GENERIC_KINDS = 128, + MCFIXUP_NUM_KIND_BITS = 8, + MCFIXUP_NUM_OPINDEX_BITS = 8, + MCFIXUP_NUM_OFFSET_BITS = (32 - MCFIXUP_NUM_OPINDEX_BITS - + MCFIXUP_NUM_OPINDEX_BITS) +}; + +/// MCFixupKind - Extensible enumeration to represent the type of a fixup. +enum MCFixupKind { + FK_Data_1 = 0, ///< A one-byte fixup. + FK_Data_2, ///< A two-byte fixup. + FK_Data_4, ///< A four-byte fixup. + FK_Data_8, ///< A eight-byte fixup. + + FirstTargetFixupKind = MCFIXUP_NUM_GENERIC_KINDS, + + MaxTargetFixupKind = (1 << MCFIXUP_NUM_KIND_BITS) +}; + +/// MCFixup - Encode information on a single operation to perform on an byte +/// sequence (e.g., an encoded instruction) which requires assemble- or run- +/// time patching. +/// +/// Fixups are used any time the target instruction encoder needs to represent +/// some value in an instruction which is not yet concrete. The encoder will +/// encode the instruction assuming the value is 0, and emit a fixup which +/// communicates to the assembler backend how it should rewrite the encoded +/// value. +/// +/// During the process of relaxation, the assembler will apply fixups as +/// symbolic values become concrete. When relaxation is complete, any remaining +/// fixups become relocations in the object file (or errors, if the fixup cannot +/// be encoded on the target). +class MCFixup { + static const unsigned MaxOffset = 1 << MCFIXUP_NUM_KIND_BITS; + + /// The byte index of start of the relocation inside the encoded instruction. + unsigned Offset : MCFIXUP_NUM_OFFSET_BITS; + + /// The index of the operand to encode into the instruction. + unsigned OpIndex : MCFIXUP_NUM_OPINDEX_BITS; + + /// The target dependent kind of fixup item this is. The kind is used to + /// determine how the operand value should be encoded into the instruction. + unsigned Kind : MCFIXUP_NUM_KIND_BITS; + +public: + static MCFixup Create(unsigned Offset, unsigned OpIndex, MCFixupKind Kind) { + MCFixup FI; + FI.Offset = Offset; + FI.OpIndex = OpIndex; + FI.Kind = unsigned(Kind); + + assert(Offset == FI.Offset && "Offset out of range!"); + assert(OpIndex == FI.OpIndex && "Operand index out of range!"); + assert(Kind == FI.Kind && "Kind out of range!"); + return FI; + } + + unsigned getOffset() const { return Offset; } + + unsigned getOpIndex() const { return OpIndex; } + + MCFixupKind getKind() const { return MCFixupKind(Kind); } +}; + +} // End llvm namespace + +#endif diff --git a/lib/MC/MCAsmStreamer.cpp b/lib/MC/MCAsmStreamer.cpp index d2e48583e02..f3c636c6a53 100644 --- a/lib/MC/MCAsmStreamer.cpp +++ b/lib/MC/MCAsmStreamer.cpp @@ -535,8 +535,9 @@ void MCAsmStreamer::EmitInstruction(const MCInst &Inst) { // Show the encoding in a comment if we have a code emitter. if (Emitter) { SmallString<256> Code; + SmallVector Fixups; raw_svector_ostream VecOS(Code); - Emitter->EncodeInstruction(Inst, VecOS); + Emitter->EncodeInstruction(Inst, VecOS, Fixups); VecOS.flush(); raw_ostream &OS = GetCommentOS(); diff --git a/lib/MC/MCMachOStreamer.cpp b/lib/MC/MCMachOStreamer.cpp index 40a21ad5dd2..99a819f7190 100644 --- a/lib/MC/MCMachOStreamer.cpp +++ b/lib/MC/MCMachOStreamer.cpp @@ -366,9 +366,10 @@ void MCMachOStreamer::EmitInstruction(const MCInst &Inst) { CurSectionData->setHasInstructions(true); // FIXME: Relocations! + SmallVector Fixups; SmallString<256> Code; raw_svector_ostream VecOS(Code); - Emitter->EncodeInstruction(Inst, VecOS); + Emitter->EncodeInstruction(Inst, VecOS, Fixups); EmitBytes(VecOS.str(), 0); } diff --git a/lib/Target/X86/X86CodeEmitter.cpp b/lib/Target/X86/X86CodeEmitter.cpp index 0cfb0cbb0b3..7ee22230b72 100644 --- a/lib/Target/X86/X86CodeEmitter.cpp +++ b/lib/Target/X86/X86CodeEmitter.cpp @@ -944,6 +944,24 @@ public: delete DummyF; } + unsigned getNumFixupKinds() const { + return 5; + } + + MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + static MCFixupKindInfo Infos[] = { + { "reloc_pcrel_word", 0, 4 * 8 }, + { "reloc_picrel_word", 0, 4 * 8 }, + { "reloc_absolute_word", 0, 4 * 8 }, + { "reloc_absolute_word_sext", 0, 4 * 8 }, + { "reloc_absolute_dword", 0, 8 * 8 } + }; + + assert(Kind >= FirstTargetFixupKind && Kind < MaxTargetFixupKind && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } + bool AddRegToInstr(const MCInst &MI, MachineInstr *Instr, unsigned Start) const { if (Start + 1 > MI.getNumOperands()) @@ -997,7 +1015,8 @@ public: AddRegToInstr(MI, Instr, Start + 4)); } - void EncodeInstruction(const MCInst &MI, raw_ostream &OS) const { + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups) const { // Don't look yet! // Convert the MCInst to a MachineInstr so we can (ab)use the regular diff --git a/lib/Target/X86/X86MCCodeEmitter.cpp b/lib/Target/X86/X86MCCodeEmitter.cpp index 7e9130b0a16..679abb388c4 100644 --- a/lib/Target/X86/X86MCCodeEmitter.cpp +++ b/lib/Target/X86/X86MCCodeEmitter.cpp @@ -33,6 +33,24 @@ public: } ~X86MCCodeEmitter() {} + + unsigned getNumFixupKinds() const { + return 5; + } + + MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { + static MCFixupKindInfo Infos[] = { + { "reloc_pcrel_word", 0, 4 * 8 }, + { "reloc_picrel_word", 0, 4 * 8 }, + { "reloc_absolute_word", 0, 4 * 8 }, + { "reloc_absolute_word_sext", 0, 4 * 8 }, + { "reloc_absolute_dword", 0, 8 * 8 } + }; + + assert(Kind >= FirstTargetFixupKind && Kind < MaxTargetFixupKind && + "Invalid kind!"); + return Infos[Kind - FirstTargetFixupKind]; + } static unsigned GetX86RegNum(const MCOperand &MO) { return X86RegisterInfo::getX86RegNum(MO.getReg()); @@ -75,7 +93,8 @@ public: unsigned RegOpcodeField, intptr_t PCAdj, raw_ostream &OS) const; - void EncodeInstruction(const MCInst &MI, raw_ostream &OS) const; + void EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups) const; }; @@ -379,7 +398,8 @@ static unsigned DetermineREXPrefix(const MCInst &MI, unsigned TSFlags, } void X86MCCodeEmitter:: -EncodeInstruction(const MCInst &MI, raw_ostream &OS) const { +EncodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups) const { unsigned Opcode = MI.getOpcode(); const TargetInstrDesc &Desc = TII.get(Opcode); unsigned TSFlags = Desc.TSFlags;