OpenCores
URL https://opencores.org/ocsvn/open8_urisc/open8_urisc/trunk

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [gold/] [arm.cc] - Diff between revs 163 and 166

Go to most recent revision | Show entire file | Details | Blame | View Log

Rev 163 Rev 166
Line 1... Line 1...
// arm.cc -- arm target support for gold.
// arm.cc -- arm target support for gold.
 
 
// Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
// Written by Doug Kwan <dougkwan@google.com> based on the i386 code
// Written by Doug Kwan <dougkwan@google.com> based on the i386 code
// by Ian Lance Taylor <iant@google.com>.
// by Ian Lance Taylor <iant@google.com>.
// This file also contains borrowed and adapted code from
// This file also contains borrowed and adapted code from
// bfd/elf32-arm.c.
// bfd/elf32-arm.c.
 
 
Line 2101... Line 2101...
          }
          }
      }
      }
  }
  }
};
};
 
 
// Utilities for manipulating integers of up to 32-bits
 
 
 
namespace utils
 
{
 
  // Sign extend an n-bit unsigned integer stored in an uint32_t into
 
  // an int32_t.  NO_BITS must be between 1 to 32.
 
  template<int no_bits>
 
  static inline int32_t
 
  sign_extend(uint32_t bits)
 
  {
 
    gold_assert(no_bits >= 0 && no_bits <= 32);
 
    if (no_bits == 32)
 
      return static_cast<int32_t>(bits);
 
    uint32_t mask = (~((uint32_t) 0)) >> (32 - no_bits);
 
    bits &= mask;
 
    uint32_t top_bit = 1U << (no_bits - 1);
 
    int32_t as_signed = static_cast<int32_t>(bits);
 
    return (bits & top_bit) ? as_signed + (-top_bit * 2) : as_signed;
 
  }
 
 
 
  // Detects overflow of an NO_BITS integer stored in a uint32_t.
 
  template<int no_bits>
 
  static inline bool
 
  has_overflow(uint32_t bits)
 
  {
 
    gold_assert(no_bits >= 0 && no_bits <= 32);
 
    if (no_bits == 32)
 
      return false;
 
    int32_t max = (1 << (no_bits - 1)) - 1;
 
    int32_t min = -(1 << (no_bits - 1));
 
    int32_t as_signed = static_cast<int32_t>(bits);
 
    return as_signed > max || as_signed < min;
 
  }
 
 
 
  // Detects overflow of an NO_BITS integer stored in a uint32_t when it
 
  // fits in the given number of bits as either a signed or unsigned value.
 
  // For example, has_signed_unsigned_overflow<8> would check
 
  // -128 <= bits <= 255
 
  template<int no_bits>
 
  static inline bool
 
  has_signed_unsigned_overflow(uint32_t bits)
 
  {
 
    gold_assert(no_bits >= 2 && no_bits <= 32);
 
    if (no_bits == 32)
 
      return false;
 
    int32_t max = static_cast<int32_t>((1U << no_bits) - 1);
 
    int32_t min = -(1 << (no_bits - 1));
 
    int32_t as_signed = static_cast<int32_t>(bits);
 
    return as_signed > max || as_signed < min;
 
  }
 
 
 
  // Select bits from A and B using bits in MASK.  For each n in [0..31],
 
  // the n-th bit in the result is chosen from the n-th bits of A and B.
 
  // A zero selects A and a one selects B.
 
  static inline uint32_t
 
  bit_select(uint32_t a, uint32_t b, uint32_t mask)
 
  { return (a & ~mask) | (b & mask); }
 
};
 
 
 
template<bool big_endian>
template<bool big_endian>
class Target_arm : public Sized_target<32, big_endian>
class Target_arm : public Sized_target<32, big_endian>
{
{
 public:
 public:
  typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
  typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
Line 3013... Line 2954...
  extract_arm_movw_movt_addend(
  extract_arm_movw_movt_addend(
      typename elfcpp::Swap<32, big_endian>::Valtype val)
      typename elfcpp::Swap<32, big_endian>::Valtype val)
  {
  {
    // According to the Elf ABI for ARM Architecture the immediate
    // According to the Elf ABI for ARM Architecture the immediate
    // field is sign-extended to form the addend.
    // field is sign-extended to form the addend.
    return utils::sign_extend<16>(((val >> 4) & 0xf000) | (val & 0xfff));
    return Bits<16>::sign_extend32(((val >> 4) & 0xf000) | (val & 0xfff));
  }
  }
 
 
  // Insert X into VAL based on the ARM instruction encoding described
  // Insert X into VAL based on the ARM instruction encoding described
  // above.
  // above.
  static inline typename elfcpp::Swap<32, big_endian>::Valtype
  static inline typename elfcpp::Swap<32, big_endian>::Valtype
Line 3047... Line 2988...
  extract_thumb_movw_movt_addend(
  extract_thumb_movw_movt_addend(
      typename elfcpp::Swap<32, big_endian>::Valtype val)
      typename elfcpp::Swap<32, big_endian>::Valtype val)
  {
  {
    // According to the Elf ABI for ARM Architecture the immediate
    // According to the Elf ABI for ARM Architecture the immediate
    // field is sign-extended to form the addend.
    // field is sign-extended to form the addend.
    return utils::sign_extend<16>(((val >> 4) & 0xf000)
    return Bits<16>::sign_extend32(((val >> 4) & 0xf000)
                                  | ((val >> 15) & 0x0800)
                                  | ((val >> 15) & 0x0800)
                                  | ((val >> 4) & 0x0700)
                                  | ((val >> 4) & 0x0700)
                                  | (val & 0x00ff));
                                  | (val & 0x00ff));
  }
  }
 
 
Line 3158... Line 3099...
    uint32_t j1 = (lower_insn & (1U << 13)) >> 13;
    uint32_t j1 = (lower_insn & (1U << 13)) >> 13;
    uint32_t j2 = (lower_insn & (1U << 11)) >> 11;
    uint32_t j2 = (lower_insn & (1U << 11)) >> 11;
    uint32_t i1 = j1 ^ s ? 0 : 1;
    uint32_t i1 = j1 ^ s ? 0 : 1;
    uint32_t i2 = j2 ^ s ? 0 : 1;
    uint32_t i2 = j2 ^ s ? 0 : 1;
 
 
    return utils::sign_extend<25>((s << 24) | (i1 << 23) | (i2 << 22)
    return Bits<25>::sign_extend32((s << 24) | (i1 << 23) | (i2 << 22)
                                  | (upper << 12) | (lower << 1));
                                  | (upper << 12) | (lower << 1));
  }
  }
 
 
  // Insert OFFSET to a 32-bit THUMB branch and return the upper instruction.
  // Insert OFFSET to a 32-bit THUMB branch and return the upper instruction.
  // UPPER_INSN is the original upper instruction of the branch.  Caller is
  // UPPER_INSN is the original upper instruction of the branch.  Caller is
Line 3197... Line 3138...
    uint32_t j1 = (lower_insn & 0x2000U) >> 13;
    uint32_t j1 = (lower_insn & 0x2000U) >> 13;
    uint32_t j2 = (lower_insn & 0x0800U) >> 11;
    uint32_t j2 = (lower_insn & 0x0800U) >> 11;
    uint32_t lower = (lower_insn & 0x07ffU);
    uint32_t lower = (lower_insn & 0x07ffU);
    uint32_t upper = (s << 8) | (j2 << 7) | (j1 << 6) | (upper_insn & 0x003fU);
    uint32_t upper = (s << 8) | (j2 << 7) | (j1 << 6) | (upper_insn & 0x003fU);
 
 
    return utils::sign_extend<21>((upper << 12) | (lower << 1));
    return Bits<21>::sign_extend32((upper << 12) | (lower << 1));
  }
  }
 
 
  // Insert OFFSET to a 32-bit THUMB conditional branch and return the upper
  // Insert OFFSET to a 32-bit THUMB conditional branch and return the upper
  // instruction.  UPPER_INSN is the original upper instruction of the branch.
  // instruction.  UPPER_INSN is the original upper instruction of the branch.
  // Caller is responsible for overflow checking.
  // Caller is responsible for overflow checking.
Line 3234... Line 3175...
       const Symbol_value<32>* psymval)
       const Symbol_value<32>* psymval)
  {
  {
    typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype;
    typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype;
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype val = elfcpp::Swap<8, big_endian>::readval(wv);
    Valtype val = elfcpp::Swap<8, big_endian>::readval(wv);
    int32_t addend = utils::sign_extend<8>(val);
    int32_t addend = Bits<8>::sign_extend32(val);
    Arm_address x = psymval->value(object, addend);
    Arm_address x = psymval->value(object, addend);
    val = utils::bit_select(val, x, 0xffU);
    val = Bits<32>::bit_select32(val, x, 0xffU);
    elfcpp::Swap<8, big_endian>::writeval(wv, val);
    elfcpp::Swap<8, big_endian>::writeval(wv, val);
 
 
    // R_ARM_ABS8 permits signed or unsigned results.
    // R_ARM_ABS8 permits signed or unsigned results.
    int signed_x = static_cast<int32_t>(x);
    return (Bits<8>::has_signed_unsigned_overflow32(x)
    return ((signed_x < -128 || signed_x > 255)
 
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_THM_ABS5: S + A
  // R_ARM_THM_ABS5: S + A
Line 3258... Line 3198...
    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
    Reltype addend = (val & 0x7e0U) >> 6;
    Reltype addend = (val & 0x7e0U) >> 6;
    Reltype x = psymval->value(object, addend);
    Reltype x = psymval->value(object, addend);
    val = utils::bit_select(val, x << 6, 0x7e0U);
    val = Bits<32>::bit_select32(val, x << 6, 0x7e0U);
    elfcpp::Swap<16, big_endian>::writeval(wv, val);
    elfcpp::Swap<16, big_endian>::writeval(wv, val);
 
    return (Bits<5>::has_overflow32(x)
    // R_ARM_ABS16 permits signed or unsigned results.
 
    int signed_x = static_cast<int32_t>(x);
 
    return ((signed_x < -32768 || signed_x > 65535)
 
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_ABS12: S + A
  // R_ARM_ABS12: S + A
Line 3280... Line 3217...
    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
    Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
    Reltype addend = val & 0x0fffU;
    Reltype addend = val & 0x0fffU;
    Reltype x = psymval->value(object, addend);
    Reltype x = psymval->value(object, addend);
    val = utils::bit_select(val, x, 0x0fffU);
    val = Bits<32>::bit_select32(val, x, 0x0fffU);
    elfcpp::Swap<32, big_endian>::writeval(wv, val);
    elfcpp::Swap<32, big_endian>::writeval(wv, val);
    return (utils::has_overflow<12>(x)
    return (Bits<12>::has_overflow32(x)
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_ABS16: S + A
  // R_ARM_ABS16: S + A
Line 3296... Line 3233...
        const Symbol_value<32>* psymval)
        const Symbol_value<32>* psymval)
  {
  {
    typedef typename elfcpp::Swap_unaligned<16, big_endian>::Valtype Valtype;
    typedef typename elfcpp::Swap_unaligned<16, big_endian>::Valtype Valtype;
    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
    typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype;
    Valtype val = elfcpp::Swap_unaligned<16, big_endian>::readval(view);
    Valtype val = elfcpp::Swap_unaligned<16, big_endian>::readval(view);
    int32_t addend = utils::sign_extend<16>(val);
    int32_t addend = Bits<16>::sign_extend32(val);
    Arm_address x = psymval->value(object, addend);
    Arm_address x = psymval->value(object, addend);
    val = utils::bit_select(val, x, 0xffffU);
    val = Bits<32>::bit_select32(val, x, 0xffffU);
    elfcpp::Swap_unaligned<16, big_endian>::writeval(view, val);
    elfcpp::Swap_unaligned<16, big_endian>::writeval(view, val);
 
 
    // R_ARM_ABS16 permits signed or unsigned results.
    // R_ARM_ABS16 permits signed or unsigned results.
    int signed_x = static_cast<int32_t>(x);
    return (Bits<16>::has_signed_unsigned_overflow32(x)
    return ((signed_x < -32768 || signed_x > 65536)
 
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_ABS32: (S + A) | T
  // R_ARM_ABS32: (S + A) | T
Line 3375... Line 3311...
            Arm_address address)
            Arm_address address)
  {
  {
    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
    int32_t addend = utils::sign_extend<8>((val & 0x00ff) << 1);
    int32_t addend = Bits<8>::sign_extend32((val & 0x00ff) << 1);
    int32_t x = (psymval->value(object, addend) - address);
    int32_t x = (psymval->value(object, addend) - address);
    elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xff00)
    elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xff00)
                                                | ((x & 0x01fe) >> 1)));
                                                | ((x & 0x01fe) >> 1)));
    // We do a 9-bit overflow check because x is right-shifted by 1 bit.
    // We do a 9-bit overflow check because x is right-shifted by 1 bit.
    return (utils::has_overflow<9>(x)
    return (Bits<9>::has_overflow32(x)
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_THM_JUMP11: S + A – P
  // R_ARM_THM_JUMP11: S + A – P
Line 3395... Line 3331...
            Arm_address address)
            Arm_address address)
  {
  {
    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
    typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype;
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype* wv = reinterpret_cast<Valtype*>(view);
    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
    Valtype val = elfcpp::Swap<16, big_endian>::readval(wv);
    int32_t addend = utils::sign_extend<11>((val & 0x07ff) << 1);
    int32_t addend = Bits<11>::sign_extend32((val & 0x07ff) << 1);
    int32_t x = (psymval->value(object, addend) - address);
    int32_t x = (psymval->value(object, addend) - address);
    elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xf800)
    elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xf800)
                                                | ((x & 0x0ffe) >> 1)));
                                                | ((x & 0x0ffe) >> 1)));
    // We do a 12-bit overflow check because x is right-shifted by 1 bit.
    // We do a 12-bit overflow check because x is right-shifted by 1 bit.
    return (utils::has_overflow<12>(x)
    return (Bits<12>::has_overflow32(x)
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_BASE_PREL: B(S) + A - P
  // R_ARM_BASE_PREL: B(S) + A - P
Line 3453... Line 3389...
         Arm_address address,
         Arm_address address,
         Arm_address thumb_bit)
         Arm_address thumb_bit)
  {
  {
    typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
    typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
    Valtype val = elfcpp::Swap_unaligned<32, big_endian>::readval(view);
    Valtype val = elfcpp::Swap_unaligned<32, big_endian>::readval(view);
    Valtype addend = utils::sign_extend<31>(val);
    Valtype addend = Bits<31>::sign_extend32(val);
    Valtype x = (psymval->value(object, addend) | thumb_bit) - address;
    Valtype x = (psymval->value(object, addend) | thumb_bit) - address;
    val = utils::bit_select(val, x, 0x7fffffffU);
    val = Bits<32>::bit_select32(val, x, 0x7fffffffU);
    elfcpp::Swap_unaligned<32, big_endian>::writeval(view, val);
    elfcpp::Swap_unaligned<32, big_endian>::writeval(view, val);
    return (utils::has_overflow<31>(x) ?
    return (Bits<31>::has_overflow32(x)
            This::STATUS_OVERFLOW : This::STATUS_OKAY);
            ? This::STATUS_OVERFLOW
 
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_MOVW_ABS_NC: (S + A) | T     (relative address base is )
  // R_ARM_MOVW_ABS_NC: (S + A) | T     (relative address base is )
  // R_ARM_MOVW_PREL_NC: (S + A) | T - P
  // R_ARM_MOVW_PREL_NC: (S + A) | T - P
  // R_ARM_MOVW_BREL_NC: ((S + A) | T) - B(S)
  // R_ARM_MOVW_BREL_NC: ((S + A) | T) - B(S)
Line 3481... Line 3418...
    Valtype addend = This::extract_arm_movw_movt_addend(val);
    Valtype addend = This::extract_arm_movw_movt_addend(val);
    Valtype x = ((psymval->value(object, addend) | thumb_bit)
    Valtype x = ((psymval->value(object, addend) | thumb_bit)
                 - relative_address_base);
                 - relative_address_base);
    val = This::insert_val_arm_movw_movt(val, x);
    val = This::insert_val_arm_movw_movt(val, x);
    elfcpp::Swap<32, big_endian>::writeval(wv, val);
    elfcpp::Swap<32, big_endian>::writeval(wv, val);
    return ((check_overflow && utils::has_overflow<16>(x))
    return ((check_overflow && Bits<16>::has_overflow32(x))
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_MOVT_ABS: S + A      (relative address base is 0)
  // R_ARM_MOVT_ABS: S + A      (relative address base is 0)
Line 3529... Line 3466...
    Reltype x =
    Reltype x =
      (psymval->value(object, addend) | thumb_bit) - relative_address_base;
      (psymval->value(object, addend) | thumb_bit) - relative_address_base;
    val = This::insert_val_thumb_movw_movt(val, x);
    val = This::insert_val_thumb_movw_movt(val, x);
    elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
    elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
    elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
    elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
    return ((check_overflow && utils::has_overflow<16>(x))
    return ((check_overflow && Bits<16>::has_overflow32(x))
            ? This::STATUS_OVERFLOW
            ? This::STATUS_OVERFLOW
            : This::STATUS_OKAY);
            : This::STATUS_OKAY);
  }
  }
 
 
  // R_ARM_THM_MOVT_ABS: S + A          (relative address base is 0)
  // R_ARM_THM_MOVT_ABS: S + A          (relative address base is 0)
Line 3961... Line 3898...
        val = cond | 0x01a00000;        // Using pre-UAL nop: mov r0, r0.
        val = cond | 0x01a00000;        // Using pre-UAL nop: mov r0, r0.
      elfcpp::Swap<32, big_endian>::writeval(wv, val);
      elfcpp::Swap<32, big_endian>::writeval(wv, val);
      return This::STATUS_OKAY;
      return This::STATUS_OKAY;
    }
    }
 
 
  Valtype addend = utils::sign_extend<26>(val << 2);
  Valtype addend = Bits<26>::sign_extend32(val << 2);
  Valtype branch_target = psymval->value(object, addend);
  Valtype branch_target = psymval->value(object, addend);
  int32_t branch_offset = branch_target - address;
  int32_t branch_offset = branch_target - address;
 
 
  // We need a stub if the branch offset is too large or if we need
  // We need a stub if the branch offset is too large or if we need
  // to switch mode.
  // to switch mode.
  bool may_use_blx = arm_target->may_use_v5t_interworking();
  bool may_use_blx = arm_target->may_use_v5t_interworking();
  Reloc_stub* stub = NULL;
  Reloc_stub* stub = NULL;
 
 
  if (!parameters->options().relocatable()
  if (!parameters->options().relocatable()
      && (utils::has_overflow<26>(branch_offset)
      && (Bits<26>::has_overflow32(branch_offset)
          || ((thumb_bit != 0)
          || ((thumb_bit != 0)
              && !(may_use_blx && r_type == elfcpp::R_ARM_CALL))))
              && !(may_use_blx && r_type == elfcpp::R_ARM_CALL))))
    {
    {
      Valtype unadjusted_branch_target = psymval->value(object, 0);
      Valtype unadjusted_branch_target = psymval->value(object, 0);
 
 
Line 3993... Line 3930...
          stub = stub_table->find_reloc_stub(stub_key);
          stub = stub_table->find_reloc_stub(stub_key);
          gold_assert(stub != NULL);
          gold_assert(stub != NULL);
          thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0;
          thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0;
          branch_target = stub_table->address() + stub->offset() + addend;
          branch_target = stub_table->address() + stub->offset() + addend;
          branch_offset = branch_target - address;
          branch_offset = branch_target - address;
          gold_assert(!utils::has_overflow<26>(branch_offset));
          gold_assert(!Bits<26>::has_overflow32(branch_offset));
        }
        }
    }
    }
 
 
  // At this point, if we still need to switch mode, the instruction
  // At this point, if we still need to switch mode, the instruction
  // must either be a BLX or a BL that can be converted to a BLX.
  // must either be a BLX or a BL that can be converted to a BLX.
Line 4006... Line 3943...
      // Turn BL to BLX.
      // Turn BL to BLX.
      gold_assert(may_use_blx && r_type == elfcpp::R_ARM_CALL);
      gold_assert(may_use_blx && r_type == elfcpp::R_ARM_CALL);
      val = (val & 0xffffff) | 0xfa000000 | ((branch_offset & 2) << 23);
      val = (val & 0xffffff) | 0xfa000000 | ((branch_offset & 2) << 23);
    }
    }
 
 
  val = utils::bit_select(val, (branch_offset >> 2), 0xffffffUL);
  val = Bits<32>::bit_select32(val, (branch_offset >> 2), 0xffffffUL);
  elfcpp::Swap<32, big_endian>::writeval(wv, val);
  elfcpp::Swap<32, big_endian>::writeval(wv, val);
  return (utils::has_overflow<26>(branch_offset)
  return (Bits<26>::has_overflow32(branch_offset)
          ? This::STATUS_OVERFLOW : This::STATUS_OKAY);
          ? This::STATUS_OVERFLOW
 
          : This::STATUS_OKAY);
}
}
 
 
// Relocate THUMB long branches.  This handles relocation types
// Relocate THUMB long branches.  This handles relocation types
// R_ARM_THM_CALL, R_ARM_THM_JUMP24 and R_ARM_THM_XPC22.
// R_ARM_THM_CALL, R_ARM_THM_JUMP24 and R_ARM_THM_XPC22.
// If IS_WEAK_UNDEFINED_WITH_PLT is true.  The target symbol is weakly
// If IS_WEAK_UNDEFINED_WITH_PLT is true.  The target symbol is weakly
Line 4100... Line 4038...
  Arm_address branch_target = psymval->value(object, addend);
  Arm_address branch_target = psymval->value(object, addend);
 
 
  // For BLX, bit 1 of target address comes from bit 1 of base address.
  // For BLX, bit 1 of target address comes from bit 1 of base address.
  bool may_use_blx = arm_target->may_use_v5t_interworking();
  bool may_use_blx = arm_target->may_use_v5t_interworking();
  if (thumb_bit == 0 && may_use_blx)
  if (thumb_bit == 0 && may_use_blx)
    branch_target = utils::bit_select(branch_target, address, 0x2);
    branch_target = Bits<32>::bit_select32(branch_target, address, 0x2);
 
 
  int32_t branch_offset = branch_target - address;
  int32_t branch_offset = branch_target - address;
 
 
  // We need a stub if the branch offset is too large or if we need
  // We need a stub if the branch offset is too large or if we need
  // to switch mode.
  // to switch mode.
  bool thumb2 = arm_target->using_thumb2();
  bool thumb2 = arm_target->using_thumb2();
  if (!parameters->options().relocatable()
  if (!parameters->options().relocatable()
      && ((!thumb2 && utils::has_overflow<23>(branch_offset))
      && ((!thumb2 && Bits<23>::has_overflow32(branch_offset))
          || (thumb2 && utils::has_overflow<25>(branch_offset))
          || (thumb2 && Bits<25>::has_overflow32(branch_offset))
          || ((thumb_bit == 0)
          || ((thumb_bit == 0)
              && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx)
              && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx)
                  || r_type == elfcpp::R_ARM_THM_JUMP24))))
                  || r_type == elfcpp::R_ARM_THM_JUMP24))))
    {
    {
      Arm_address unadjusted_branch_target = psymval->value(object, 0);
      Arm_address unadjusted_branch_target = psymval->value(object, 0);
Line 4133... Line 4071...
          Reloc_stub* stub = stub_table->find_reloc_stub(stub_key);
          Reloc_stub* stub = stub_table->find_reloc_stub(stub_key);
          gold_assert(stub != NULL);
          gold_assert(stub != NULL);
          thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0;
          thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0;
          branch_target = stub_table->address() + stub->offset() + addend;
          branch_target = stub_table->address() + stub->offset() + addend;
          if (thumb_bit == 0 && may_use_blx)
          if (thumb_bit == 0 && may_use_blx)
            branch_target = utils::bit_select(branch_target, address, 0x2);
            branch_target = Bits<32>::bit_select32(branch_target, address, 0x2);
          branch_offset = branch_target - address;
          branch_offset = branch_target - address;
        }
        }
    }
    }
 
 
  // At this point, if we still need to switch mode, the instruction
  // At this point, if we still need to switch mode, the instruction
Line 4170... Line 4108...
  lower_insn = This::thumb32_branch_lower(lower_insn, branch_offset);
  lower_insn = This::thumb32_branch_lower(lower_insn, branch_offset);
 
 
  elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn);
  elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn);
  elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
  elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
 
 
  gold_assert(!utils::has_overflow<25>(branch_offset));
  gold_assert(!Bits<25>::has_overflow32(branch_offset));
 
 
  return ((thumb2
  return ((thumb2
           ? utils::has_overflow<25>(branch_offset)
           ? Bits<25>::has_overflow32(branch_offset)
           : utils::has_overflow<23>(branch_offset))
           : Bits<23>::has_overflow32(branch_offset))
          ? This::STATUS_OVERFLOW
          ? This::STATUS_OVERFLOW
          : This::STATUS_OKAY);
          : This::STATUS_OKAY);
}
}
 
 
// Relocate THUMB-2 long conditional branches.
// Relocate THUMB-2 long conditional branches.
Line 4219... Line 4157...
 
 
  // Put the relocated value back in the object file:
  // Put the relocated value back in the object file:
  elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn);
  elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn);
  elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
  elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
 
 
  return (utils::has_overflow<21>(branch_offset)
  return (Bits<21>::has_overflow32(branch_offset)
          ? This::STATUS_OVERFLOW
          ? This::STATUS_OVERFLOW
          : This::STATUS_OKAY);
          : This::STATUS_OKAY);
}
}
 
 
// Get the GOT section, creating it if necessary.
// Get the GOT section, creating it if necessary.
Line 4497... Line 4435...
      thumb2 = little_endian_target->using_thumb2();
      thumb2 = little_endian_target->using_thumb2();
      thumb_only = little_endian_target->using_thumb_only();
      thumb_only = little_endian_target->using_thumb_only();
    }
    }
 
 
  int64_t branch_offset;
  int64_t branch_offset;
 
  bool output_is_position_independent =
 
      parameters->options().output_is_position_independent();
  if (r_type == elfcpp::R_ARM_THM_CALL || r_type == elfcpp::R_ARM_THM_JUMP24)
  if (r_type == elfcpp::R_ARM_THM_CALL || r_type == elfcpp::R_ARM_THM_JUMP24)
    {
    {
      // For THUMB BLX instruction, bit 1 of target comes from bit 1 of the
      // For THUMB BLX instruction, bit 1 of target comes from bit 1 of the
      // base address (instruction address + 4).
      // base address (instruction address + 4).
      if ((r_type == elfcpp::R_ARM_THM_CALL) && may_use_blx && !target_is_thumb)
      if ((r_type == elfcpp::R_ARM_THM_CALL) && may_use_blx && !target_is_thumb)
        destination = utils::bit_select(destination, location, 0x2);
        destination = Bits<32>::bit_select32(destination, location, 0x2);
      branch_offset = static_cast<int64_t>(destination) - location;
      branch_offset = static_cast<int64_t>(destination) - location;
 
 
      // Handle cases where:
      // Handle cases where:
      // - this call goes too far (different Thumb/Thumb2 max
      // - this call goes too far (different Thumb/Thumb2 max
      //   distance)
      //   distance)
Line 4525... Line 4465...
          if (target_is_thumb)
          if (target_is_thumb)
            {
            {
              // Thumb to thumb.
              // Thumb to thumb.
              if (!thumb_only)
              if (!thumb_only)
                {
                {
                  stub_type = (parameters->options().shared()
                  stub_type = (output_is_position_independent
                               || should_force_pic_veneer)
                               || should_force_pic_veneer)
                    // PIC stubs.
                    // PIC stubs.
                    ? ((may_use_blx
                    ? ((may_use_blx
                        && (r_type == elfcpp::R_ARM_THM_CALL))
                        && (r_type == elfcpp::R_ARM_THM_CALL))
                       // V5T and above. Stub starts with ARM code, so
                       // V5T and above. Stub starts with ARM code, so
Line 4546... Line 4486...
                       ? arm_stub_long_branch_any_any // V5T and above.
                       ? arm_stub_long_branch_any_any // V5T and above.
                       : arm_stub_long_branch_v4t_thumb_thumb); // V4T.
                       : arm_stub_long_branch_v4t_thumb_thumb); // V4T.
                }
                }
              else
              else
                {
                {
                  stub_type = (parameters->options().shared()
                  stub_type = (output_is_position_independent
                               || should_force_pic_veneer)
                               || should_force_pic_veneer)
                    ? arm_stub_long_branch_thumb_only_pic       // PIC stub.
                    ? arm_stub_long_branch_thumb_only_pic       // PIC stub.
                    : arm_stub_long_branch_thumb_only;  // non-PIC stub.
                    : arm_stub_long_branch_thumb_only;  // non-PIC stub.
                }
                }
            }
            }
Line 4559... Line 4499...
              // Thumb to arm.
              // Thumb to arm.
 
 
              // FIXME: We should check that the input section is from an
              // FIXME: We should check that the input section is from an
              // object that has interwork enabled.
              // object that has interwork enabled.
 
 
              stub_type = (parameters->options().shared()
              stub_type = (output_is_position_independent
                           || should_force_pic_veneer)
                           || should_force_pic_veneer)
                // PIC stubs.
                // PIC stubs.
                ? ((may_use_blx
                ? ((may_use_blx
                    && (r_type == elfcpp::R_ARM_THM_CALL))
                    && (r_type == elfcpp::R_ARM_THM_CALL))
                   ? arm_stub_long_branch_any_arm_pic   // V5T and above.
                   ? arm_stub_long_branch_any_arm_pic   // V5T and above.
Line 4601... Line 4541...
              || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
              || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)
              || ((r_type == elfcpp::R_ARM_CALL) && !may_use_blx)
              || ((r_type == elfcpp::R_ARM_CALL) && !may_use_blx)
              || (r_type == elfcpp::R_ARM_JUMP24)
              || (r_type == elfcpp::R_ARM_JUMP24)
              || (r_type == elfcpp::R_ARM_PLT32))
              || (r_type == elfcpp::R_ARM_PLT32))
            {
            {
              stub_type = (parameters->options().shared()
              stub_type = (output_is_position_independent
                           || should_force_pic_veneer)
                           || should_force_pic_veneer)
                // PIC stubs.
                // PIC stubs.
                ? (may_use_blx
                ? (may_use_blx
                   ? arm_stub_long_branch_any_thumb_pic// V5T and above.
                   ? arm_stub_long_branch_any_thumb_pic// V5T and above.
                   : arm_stub_long_branch_v4t_arm_thumb_pic)    // V4T stub.
                   : arm_stub_long_branch_v4t_arm_thumb_pic)    // V4T stub.
Line 4620... Line 4560...
        {
        {
          // Arm to arm.
          // Arm to arm.
          if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
          if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET
              || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET))
              || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET))
            {
            {
              stub_type = (parameters->options().shared()
              stub_type = (output_is_position_independent
                           || should_force_pic_veneer)
                           || should_force_pic_veneer)
                ? arm_stub_long_branch_any_arm_pic      // PIC stubs.
                ? arm_stub_long_branch_any_arm_pic      // PIC stubs.
                : arm_stub_long_branch_any_any;         /// non-PIC.
                : arm_stub_long_branch_any_any;         /// non-PIC.
            }
            }
        }
        }
Line 5275... Line 5215...
 
 
  // Write out the entry.  The first word either points to the beginning
  // Write out the entry.  The first word either points to the beginning
  // or after the end of a text section.  The second word is the special
  // or after the end of a text section.  The second word is the special
  // EXIDX_CANTUNWIND value.
  // EXIDX_CANTUNWIND value.
  uint32_t prel31_offset = output_address - this->address();
  uint32_t prel31_offset = output_address - this->address();
  if (utils::has_overflow<31>(offset))
  if (Bits<31>::has_overflow32(offset))
    gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry"));
    gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry"));
  elfcpp::Swap_unaligned<32, big_endian>::writeval(oview,
  elfcpp::Swap_unaligned<32, big_endian>::writeval(oview,
                                                   prel31_offset & 0x7fffffffU);
                                                   prel31_offset & 0x7fffffffU);
  elfcpp::Swap_unaligned<32, big_endian>::writeval(oview + 4,
  elfcpp::Swap_unaligned<32, big_endian>::writeval(oview + 4,
                                                   elfcpp::EXIDX_CANTUNWIND);
                                                   elfcpp::EXIDX_CANTUNWIND);
Line 7048... Line 6988...
    case elfcpp::R_ARM_PLT32:
    case elfcpp::R_ARM_PLT32:
      {
      {
        typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
        typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
        const Valtype* wv = reinterpret_cast<const Valtype*>(view);
        const Valtype* wv = reinterpret_cast<const Valtype*>(view);
        Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
        Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
        return utils::sign_extend<26>(val << 2);
        return Bits<26>::sign_extend32(val << 2);
      }
      }
 
 
    case elfcpp::R_ARM_THM_CALL:
    case elfcpp::R_ARM_THM_CALL:
    case elfcpp::R_ARM_THM_JUMP24:
    case elfcpp::R_ARM_THM_JUMP24:
    case elfcpp::R_ARM_THM_XPC22:
    case elfcpp::R_ARM_THM_XPC22:
Line 11899... Line 11839...
        // the instruction which specifies that bit 1 of the target
        // the instruction which specifies that bit 1 of the target
        // address will come from bit 1 of the base address.
        // address will come from bit 1 of the base address.
        branch_offset = (branch_offset + 2) & ~3;
        branch_offset = (branch_offset + 2) & ~3;
 
 
      // Put BRANCH_OFFSET back into the insn.
      // Put BRANCH_OFFSET back into the insn.
      gold_assert(!utils::has_overflow<25>(branch_offset));
      gold_assert(!Bits<25>::has_overflow32(branch_offset));
      upper_insn = RelocFuncs::thumb32_branch_upper(upper_insn, branch_offset);
      upper_insn = RelocFuncs::thumb32_branch_upper(upper_insn, branch_offset);
      lower_insn = RelocFuncs::thumb32_branch_lower(lower_insn, branch_offset);
      lower_insn = RelocFuncs::thumb32_branch_lower(lower_insn, branch_offset);
      break;
      break;
 
 
    default:
    default:

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.