reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
//===-- llvm/MC/MCFixup.h - Instruction Relocation and Patching -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_MC_MCFIXUP_H
#define LLVM_MC_MCFIXUP_H

#include "llvm/MC/MCExpr.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SMLoc.h"
#include <cassert>

namespace llvm {
class MCExpr;

/// Extensible enumeration to represent the type of a fixup.
enum MCFixupKind {
  FK_NONE = 0,    ///< A no-op fixup.
  FK_Data_1,      ///< 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.
  FK_Data_6b,     ///< A six-bits fixup.
  FK_PCRel_1,     ///< A one-byte pc relative fixup.
  FK_PCRel_2,     ///< A two-byte pc relative fixup.
  FK_PCRel_4,     ///< A four-byte pc relative fixup.
  FK_PCRel_8,     ///< A eight-byte pc relative fixup.
  FK_GPRel_1,     ///< A one-byte gp relative fixup.
  FK_GPRel_2,     ///< A two-byte gp relative fixup.
  FK_GPRel_4,     ///< A four-byte gp relative fixup.
  FK_GPRel_8,     ///< A eight-byte gp relative fixup.
  FK_DTPRel_4,    ///< A four-byte dtp relative fixup.
  FK_DTPRel_8,    ///< A eight-byte dtp relative fixup.
  FK_TPRel_4,     ///< A four-byte tp relative fixup.
  FK_TPRel_8,     ///< A eight-byte tp relative fixup.
  FK_SecRel_1,    ///< A one-byte section relative fixup.
  FK_SecRel_2,    ///< A two-byte section relative fixup.
  FK_SecRel_4,    ///< A four-byte section relative fixup.
  FK_SecRel_8,    ///< A eight-byte section relative fixup.
  FK_Data_Add_1,  ///< A one-byte add fixup.
  FK_Data_Add_2,  ///< A two-byte add fixup.
  FK_Data_Add_4,  ///< A four-byte add fixup.
  FK_Data_Add_8,  ///< A eight-byte add fixup.
  FK_Data_Add_6b, ///< A six-bits add fixup.
  FK_Data_Sub_1,  ///< A one-byte sub fixup.
  FK_Data_Sub_2,  ///< A two-byte sub fixup.
  FK_Data_Sub_4,  ///< A four-byte sub fixup.
  FK_Data_Sub_8,  ///< A eight-byte sub fixup.
  FK_Data_Sub_6b, ///< A six-bits sub fixup.

  FirstTargetFixupKind = 128,

  // Limit range of target fixups, in case we want to pack more efficiently
  // later.
  MaxTargetFixupKind = (1 << 8)
};

/// Encode information on a single operation to perform on a 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 {
  /// The value to put into the fixup location. The exact interpretation of the
  /// expression is target dependent, usually it will be one of the operands to
  /// an instruction or an assembler directive.
  const MCExpr *Value = nullptr;

  /// The byte index of start of the relocation inside the MCFragment.
  uint32_t Offset = 0;

  /// 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.
  MCFixupKind Kind = FK_NONE;

  /// The source location which gave rise to the fixup, if any.
  SMLoc Loc;
public:
  static MCFixup create(uint32_t Offset, const MCExpr *Value,
                        MCFixupKind Kind, SMLoc Loc = SMLoc()) {
    assert(Kind < MaxTargetFixupKind && "Kind out of range!");
    MCFixup FI;
    FI.Value = Value;
    FI.Offset = Offset;
    FI.Kind = Kind;
    FI.Loc = Loc;
    return FI;
  }

  /// Return a fixup corresponding to the add half of a add/sub fixup pair for
  /// the given Fixup.
  static MCFixup createAddFor(const MCFixup &Fixup) {
    MCFixup FI;
    FI.Value = Fixup.getValue();
    FI.Offset = Fixup.getOffset();
    FI.Kind = getAddKindForKind(Fixup.getKind());
    FI.Loc = Fixup.getLoc();
    return FI;
  }

  /// Return a fixup corresponding to the sub half of a add/sub fixup pair for
  /// the given Fixup.
  static MCFixup createSubFor(const MCFixup &Fixup) {
    MCFixup FI;
    FI.Value = Fixup.getValue();
    FI.Offset = Fixup.getOffset();
    FI.Kind = getSubKindForKind(Fixup.getKind());
    FI.Loc = Fixup.getLoc();
    return FI;
  }

  MCFixupKind getKind() const { return Kind; }

  unsigned getTargetKind() const { return Kind; }

  uint32_t getOffset() const { return Offset; }
  void setOffset(uint32_t Value) { Offset = Value; }

  const MCExpr *getValue() const { return Value; }

  /// Return the generic fixup kind for a value with the given size. It
  /// is an error to pass an unsupported size.
  static MCFixupKind getKindForSize(unsigned Size, bool IsPCRel) {
    switch (Size) {
    default: llvm_unreachable("Invalid generic fixup size!");
    case 1:
      return IsPCRel ? FK_PCRel_1 : FK_Data_1;
    case 2:
      return IsPCRel ? FK_PCRel_2 : FK_Data_2;
    case 4:
      return IsPCRel ? FK_PCRel_4 : FK_Data_4;
    case 8:
      return IsPCRel ? FK_PCRel_8 : FK_Data_8;
    }
  }

  /// Return the generic fixup kind for a value with the given size in bits.
  /// It is an error to pass an unsupported size.
  static MCFixupKind getKindForSizeInBits(unsigned Size, bool IsPCRel) {
    switch (Size) {
    default:
      llvm_unreachable("Invalid generic fixup size!");
    case 6:
      assert(!IsPCRel && "Invalid pc-relative fixup size!");
      return FK_Data_6b;
    case 8:
      return IsPCRel ? FK_PCRel_1 : FK_Data_1;
    case 16:
      return IsPCRel ? FK_PCRel_2 : FK_Data_2;
    case 32:
      return IsPCRel ? FK_PCRel_4 : FK_Data_4;
    case 64:
      return IsPCRel ? FK_PCRel_8 : FK_Data_8;
    }
  }

  /// Return the generic fixup kind for an addition with a given size. It
  /// is an error to pass an unsupported size.
  static MCFixupKind getAddKindForKind(MCFixupKind Kind) {
    switch (Kind) {
    default: llvm_unreachable("Unknown type to convert!");
    case FK_Data_1: return FK_Data_Add_1;
    case FK_Data_2: return FK_Data_Add_2;
    case FK_Data_4: return FK_Data_Add_4;
    case FK_Data_8: return FK_Data_Add_8;
    case FK_Data_6b: return FK_Data_Add_6b;
    }
  }

  /// Return the generic fixup kind for an subtraction with a given size. It
  /// is an error to pass an unsupported size.
  static MCFixupKind getSubKindForKind(MCFixupKind Kind) {
    switch (Kind) {
    default: llvm_unreachable("Unknown type to convert!");
    case FK_Data_1: return FK_Data_Sub_1;
    case FK_Data_2: return FK_Data_Sub_2;
    case FK_Data_4: return FK_Data_Sub_4;
    case FK_Data_8: return FK_Data_Sub_8;
    case FK_Data_6b: return FK_Data_Sub_6b;
    }
  }

  SMLoc getLoc() const { return Loc; }
};

} // End llvm namespace

#endif