| //===- subzero/src/IceFixups.h - Assembler fixup kinds ----------*- C++ -*-===// |
| // |
| // The Subzero Code Generator |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// \brief Declares generic fixup types. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef SUBZERO_SRC_ICEFIXUPS_H |
| #define SUBZERO_SRC_ICEFIXUPS_H |
| |
| #include "IceClFlags.h" |
| #include "IceDefs.h" |
| #include "IceStringPool.h" |
| |
| namespace Ice { |
| |
| /// Each target and container format has a different namespace of relocations. |
| /// This holds the specific target+container format's relocation number. |
| using FixupKind = uint32_t; |
| |
| struct ELFSym; |
| |
| /// Assembler fixups are positions in generated code/data that hold relocation |
| /// information that needs to be processed before finalizing the code/data. |
| class AssemblerFixup { |
| AssemblerFixup &operator=(const AssemblerFixup &) = delete; |
| |
| public: |
| AssemblerFixup() = default; |
| AssemblerFixup(const AssemblerFixup &) = default; |
| virtual ~AssemblerFixup() = default; |
| intptr_t position() const { return position_; } |
| void set_position(intptr_t Position) { position_ = Position; } |
| |
| FixupKind kind() const { return kind_; } |
| void set_kind(FixupKind Kind) { kind_ = Kind; } |
| |
| RelocOffsetT offset() const; |
| GlobalString symbol() const; |
| |
| static const Constant *NullSymbol; |
| bool isNullSymbol() const { return ConstValue == NullSymbol; } |
| |
| static constexpr AssemblerFixup *NoFixup = nullptr; |
| |
| bool valueIsSymbol() const { return ValueIsSymbol; } |
| void set_value(const Constant *Value) { |
| ValueIsSymbol = false; |
| ConstValue = Value; |
| } |
| void set_value(const ELFSym *Value) { |
| ValueIsSymbol = true; |
| SymbolValue = Value; |
| } |
| const ELFSym *getSymbolValue() const { |
| assert(ValueIsSymbol); |
| return SymbolValue; |
| } |
| |
| void set_addend(RelocOffsetT Addend) { addend_ = Addend; } |
| RelocOffsetT get_addend() const { return addend_; } |
| |
| /// Emits fixup, then returns the number of bytes to skip. |
| virtual size_t emit(GlobalContext *Ctx, const Assembler &Asm) const; |
| |
| /// Emits offset() (little endian) in position_. If your fixup requires |
| /// something smarter, you must create your own fixup type. |
| virtual void emitOffset(Assembler *Asm) const; |
| |
| private: |
| intptr_t position_ = 0; |
| FixupKind kind_ = 0; |
| // An offset addend to the fixup offset (as returned by offset()), in case the |
| // assembler needs to adjust it. |
| RelocOffsetT addend_ = 0; |
| |
| // Tagged union that holds either a Constant or ELFSym pointer, depending on |
| // the ValueIsSymbol tag. |
| bool ValueIsSymbol = false; |
| union { |
| const Constant *ConstValue; |
| const ELFSym *SymbolValue; |
| }; |
| }; |
| |
| /// Extends a fixup to be textual. That is, it emits text instead of a sequence |
| /// of bytes. This class is used as a fallback for unimplemented emitIAS |
| /// methods, allowing them to generate compilable assembly code. |
| class AssemblerTextFixup : public AssemblerFixup { |
| AssemblerTextFixup() = delete; |
| AssemblerTextFixup(const AssemblerTextFixup &) = delete; |
| AssemblerTextFixup &operator=(const AssemblerTextFixup &) = delete; |
| |
| public: |
| AssemblerTextFixup(const std::string &Message, size_t NumBytes) |
| : AssemblerFixup(), Message(Message), NumBytes(NumBytes) {} |
| ~AssemblerTextFixup() = default; |
| size_t emit(GlobalContext *Ctx, const Assembler &Asm) const override; |
| |
| private: |
| const std::string Message; |
| const size_t NumBytes; |
| }; |
| |
| using FixupList = std::vector<AssemblerFixup>; |
| using FixupRefList = std::vector<AssemblerFixup *>; |
| |
| } // end of namespace Ice |
| |
| #endif // SUBZERO_SRC_ICEFIXUPS_H |