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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [bfd/] [elfxx-mips.c] - Diff between revs 148 and 161

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

Rev 148 Rev 161
Line 304... Line 304...
/* Macros for populating a mips_elf_la25_stub.  */
/* Macros for populating a mips_elf_la25_stub.  */
 
 
#define LA25_LUI(VAL) (0x3c190000 | (VAL))      /* lui t9,VAL */
#define LA25_LUI(VAL) (0x3c190000 | (VAL))      /* lui t9,VAL */
#define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
#define LA25_J(VAL) (0x08000000 | (((VAL) >> 2) & 0x3ffffff)) /* j VAL */
#define LA25_ADDIU(VAL) (0x27390000 | (VAL))    /* addiu t9,t9,VAL */
#define LA25_ADDIU(VAL) (0x27390000 | (VAL))    /* addiu t9,t9,VAL */
 
#define LA25_LUI_MICROMIPS_1(VAL) (0x41b9)      /* lui t9,VAL */
 
#define LA25_LUI_MICROMIPS_2(VAL) (VAL)
 
#define LA25_J_MICROMIPS_1(VAL) (0xd400 | (((VAL) >> 17) & 0x3ff)) /* j VAL */
 
#define LA25_J_MICROMIPS_2(VAL) ((VAL) >> 1)
 
#define LA25_ADDIU_MICROMIPS_1(VAL) (0x3339)    /* addiu t9,t9,VAL */
 
#define LA25_ADDIU_MICROMIPS_2(VAL) (VAL)
 
 
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
/* This structure is passed to mips_elf_sort_hash_table_f when sorting
   the dynamic symbols.  */
   the dynamic symbols.  */
 
 
struct mips_elf_hash_sort_data
struct mips_elf_hash_sort_data
Line 520... Line 526...
   || r_type == R_MIPS_TLS_DTPREL_LO16          \
   || r_type == R_MIPS_TLS_DTPREL_LO16          \
   || r_type == R_MIPS_TLS_GOTTPREL             \
   || r_type == R_MIPS_TLS_GOTTPREL             \
   || r_type == R_MIPS_TLS_TPREL32              \
   || r_type == R_MIPS_TLS_TPREL32              \
   || r_type == R_MIPS_TLS_TPREL64              \
   || r_type == R_MIPS_TLS_TPREL64              \
   || r_type == R_MIPS_TLS_TPREL_HI16           \
   || r_type == R_MIPS_TLS_TPREL_HI16           \
   || r_type == R_MIPS_TLS_TPREL_LO16)
   || r_type == R_MIPS_TLS_TPREL_LO16           \
 
   || r_type == R_MICROMIPS_TLS_GD              \
 
   || r_type == R_MICROMIPS_TLS_LDM             \
 
   || r_type == R_MICROMIPS_TLS_DTPREL_HI16     \
 
   || r_type == R_MICROMIPS_TLS_DTPREL_LO16     \
 
   || r_type == R_MICROMIPS_TLS_GOTTPREL        \
 
   || r_type == R_MICROMIPS_TLS_TPREL_HI16      \
 
   || r_type == R_MICROMIPS_TLS_TPREL_LO16)
 
 
/* Structure used to pass information to mips_elf_output_extsym.  */
/* Structure used to pass information to mips_elf_output_extsym.  */
 
 
struct extsym_info
struct extsym_info
{
{
Line 1357... Line 1370...
{
{
  struct bfd_link_hash_entry *bh;
  struct bfd_link_hash_entry *bh;
  struct elf_link_hash_entry *elfh;
  struct elf_link_hash_entry *elfh;
  const char *name;
  const char *name;
 
 
 
  if (ELF_ST_IS_MICROMIPS (h->root.other))
 
    value |= 1;
 
 
  /* Create a new symbol.  */
  /* Create a new symbol.  */
  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
  name = ACONCAT ((prefix, h->root.root.root.string, NULL));
  bh = NULL;
  bh = NULL;
  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
  if (!_bfd_generic_link_add_one_symbol (info, s->owner, name,
                                         BSF_LOCAL, s, value, NULL,
                                         BSF_LOCAL, s, value, NULL,
Line 1849... Line 1865...
    default:
    default:
      return FALSE;
      return FALSE;
    }
    }
}
}
 
 
 
/* Check if a microMIPS reloc.  */
 
 
 
static inline bfd_boolean
 
micromips_reloc_p (unsigned int r_type)
 
{
 
  return r_type >= R_MICROMIPS_min && r_type < R_MICROMIPS_max;
 
}
 
 
 
/* Similar to MIPS16, the two 16-bit halves in microMIPS must be swapped
 
   on a little-endian system.  This does not apply to R_MICROMIPS_PC7_S1
 
   and R_MICROMIPS_PC10_S1 relocs that apply to 16-bit instructions.  */
 
 
 
static inline bfd_boolean
 
micromips_reloc_shuffle_p (unsigned int r_type)
 
{
 
  return (micromips_reloc_p (r_type)
 
          && r_type != R_MICROMIPS_PC7_S1
 
          && r_type != R_MICROMIPS_PC10_S1);
 
}
 
 
static inline bfd_boolean
static inline bfd_boolean
got16_reloc_p (int r_type)
got16_reloc_p (int r_type)
{
{
  return r_type == R_MIPS_GOT16 || r_type == R_MIPS16_GOT16;
  return (r_type == R_MIPS_GOT16
 
          || r_type == R_MIPS16_GOT16
 
          || r_type == R_MICROMIPS_GOT16);
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
call16_reloc_p (int r_type)
call16_reloc_p (int r_type)
{
{
  return r_type == R_MIPS_CALL16 || r_type == R_MIPS16_CALL16;
  return (r_type == R_MIPS_CALL16
 
          || r_type == R_MIPS16_CALL16
 
          || r_type == R_MICROMIPS_CALL16);
 
}
 
 
 
static inline bfd_boolean
 
got_disp_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_GOT_DISP || r_type == R_MICROMIPS_GOT_DISP;
 
}
 
 
 
static inline bfd_boolean
 
got_page_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_GOT_PAGE || r_type == R_MICROMIPS_GOT_PAGE;
 
}
 
 
 
static inline bfd_boolean
 
got_ofst_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_GOT_OFST || r_type == R_MICROMIPS_GOT_OFST;
 
}
 
 
 
static inline bfd_boolean
 
got_hi16_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_GOT_HI16 || r_type == R_MICROMIPS_GOT_HI16;
 
}
 
 
 
static inline bfd_boolean
 
got_lo16_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_GOT_LO16 || r_type == R_MICROMIPS_GOT_LO16;
 
}
 
 
 
static inline bfd_boolean
 
call_hi16_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_CALL_HI16 || r_type == R_MICROMIPS_CALL_HI16;
 
}
 
 
 
static inline bfd_boolean
 
call_lo16_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_CALL_LO16 || r_type == R_MICROMIPS_CALL_LO16;
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
hi16_reloc_p (int r_type)
hi16_reloc_p (int r_type)
{
{
  return r_type == R_MIPS_HI16 || r_type == R_MIPS16_HI16;
  return (r_type == R_MIPS_HI16
 
          || r_type == R_MIPS16_HI16
 
          || r_type == R_MICROMIPS_HI16);
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
lo16_reloc_p (int r_type)
lo16_reloc_p (int r_type)
{
{
  return r_type == R_MIPS_LO16 || r_type == R_MIPS16_LO16;
  return (r_type == R_MIPS_LO16
 
          || r_type == R_MIPS16_LO16
 
          || r_type == R_MICROMIPS_LO16);
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
mips16_call_reloc_p (int r_type)
mips16_call_reloc_p (int r_type)
{
{
Line 1882... Line 1968...
}
}
 
 
static inline bfd_boolean
static inline bfd_boolean
jal_reloc_p (int r_type)
jal_reloc_p (int r_type)
{
{
  return r_type == R_MIPS_26 || r_type == R_MIPS16_26;
  return (r_type == R_MIPS_26
 
          || r_type == R_MIPS16_26
 
          || r_type == R_MICROMIPS_26_S1);
 
}
 
 
 
static inline bfd_boolean
 
micromips_branch_reloc_p (int r_type)
 
{
 
  return (r_type == R_MICROMIPS_26_S1
 
          || r_type == R_MICROMIPS_PC16_S1
 
          || r_type == R_MICROMIPS_PC10_S1
 
          || r_type == R_MICROMIPS_PC7_S1);
 
}
 
 
 
static inline bfd_boolean
 
tls_gd_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_TLS_GD || r_type == R_MICROMIPS_TLS_GD;
 
}
 
 
 
static inline bfd_boolean
 
tls_ldm_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_TLS_LDM || r_type == R_MICROMIPS_TLS_LDM;
 
}
 
 
 
static inline bfd_boolean
 
tls_gottprel_reloc_p (unsigned int r_type)
 
{
 
  return r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MICROMIPS_TLS_GOTTPREL;
}
}
 
 
void
void
_bfd_mips16_elf_reloc_unshuffle (bfd *abfd, int r_type,
_bfd_mips_elf_reloc_unshuffle (bfd *abfd, int r_type,
                                 bfd_boolean jal_shuffle, bfd_byte *data)
                                 bfd_boolean jal_shuffle, bfd_byte *data)
{
{
  bfd_vma extend, insn, val;
  bfd_vma first, second, val;
 
 
  if (!mips16_reloc_p (r_type))
  if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
    return;
    return;
 
 
  /* Pick up the mips16 extend instruction and the real instruction.  */
  /* Pick up the first and second halfwords of the instruction.  */
  extend = bfd_get_16 (abfd, data);
  first = bfd_get_16 (abfd, data);
  insn = bfd_get_16 (abfd, data + 2);
  second = bfd_get_16 (abfd, data + 2);
  if (r_type == R_MIPS16_26)
  if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
    {
    val = first << 16 | second;
      if (jal_shuffle)
  else if (r_type != R_MIPS16_26)
        val = ((extend & 0xfc00) << 16) | ((extend & 0x3e0) << 11)
    val = (((first & 0xf800) << 16) | ((second & 0xffe0) << 11)
              | ((extend & 0x1f) << 21) | insn;
           | ((first & 0x1f) << 11) | (first & 0x7e0) | (second & 0x1f));
      else
      else
        val = extend << 16 | insn;
    val = (((first & 0xfc00) << 16) | ((first & 0x3e0) << 11)
    }
           | ((first & 0x1f) << 21) | second);
  else
 
    val = ((extend & 0xf800) << 16) | ((insn & 0xffe0) << 11)
 
          | ((extend & 0x1f) << 11) | (extend & 0x7e0) | (insn & 0x1f);
 
  bfd_put_32 (abfd, val, data);
  bfd_put_32 (abfd, val, data);
}
}
 
 
void
void
_bfd_mips16_elf_reloc_shuffle (bfd *abfd, int r_type,
_bfd_mips_elf_reloc_shuffle (bfd *abfd, int r_type,
                               bfd_boolean jal_shuffle, bfd_byte *data)
                               bfd_boolean jal_shuffle, bfd_byte *data)
{
{
  bfd_vma extend, insn, val;
  bfd_vma first, second, val;
 
 
  if (!mips16_reloc_p (r_type))
  if (!mips16_reloc_p (r_type) && !micromips_reloc_shuffle_p (r_type))
    return;
    return;
 
 
  val = bfd_get_32 (abfd, data);
  val = bfd_get_32 (abfd, data);
  if (r_type == R_MIPS16_26)
  if (micromips_reloc_p (r_type) || (r_type == R_MIPS16_26 && !jal_shuffle))
    {
    {
      if (jal_shuffle)
      second = val & 0xffff;
        {
      first = val >> 16;
          insn = val & 0xffff;
 
          extend = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
 
                   | ((val >> 21) & 0x1f);
 
        }
        }
      else
  else if (r_type != R_MIPS16_26)
        {
        {
          insn = val & 0xffff;
      second = ((val >> 11) & 0xffe0) | (val & 0x1f);
          extend = val >> 16;
      first = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
        }
 
    }
    }
  else
  else
    {
    {
      insn = ((val >> 11) & 0xffe0) | (val & 0x1f);
      second = val & 0xffff;
      extend = ((val >> 16) & 0xf800) | ((val >> 11) & 0x1f) | (val & 0x7e0);
      first = ((val >> 16) & 0xfc00) | ((val >> 11) & 0x3e0)
 
               | ((val >> 21) & 0x1f);
    }
    }
  bfd_put_16 (abfd, insn, data + 2);
  bfd_put_16 (abfd, second, data + 2);
  bfd_put_16 (abfd, extend, data);
  bfd_put_16 (abfd, first, data);
}
}
 
 
bfd_reloc_status_type
bfd_reloc_status_type
_bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
_bfd_mips_elf_gprel16_with_gp (bfd *abfd, asymbol *symbol,
                               arelent *reloc_entry, asection *input_section,
                               arelent *reloc_entry, asection *input_section,
Line 2082... Line 2191...
  bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
  bfd_byte *location = (bfd_byte *) data + reloc_entry->address;
 
 
  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
  if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
    return bfd_reloc_outofrange;
    return bfd_reloc_outofrange;
 
 
  _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
  _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
                                   location);
                                   location);
  vallo = bfd_get_32 (abfd, location);
  vallo = bfd_get_32 (abfd, location);
  _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
  _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
                                 location);
                                 location);
 
 
  while (mips_hi16_list != NULL)
  while (mips_hi16_list != NULL)
    {
    {
      bfd_reloc_status_type ret;
      bfd_reloc_status_type ret;
Line 2104... Line 2213...
         has a rightshift of 0.  */
         has a rightshift of 0.  */
      if (hi->rel.howto->type == R_MIPS_GOT16)
      if (hi->rel.howto->type == R_MIPS_GOT16)
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS_HI16, FALSE);
      else if (hi->rel.howto->type == R_MIPS16_GOT16)
      else if (hi->rel.howto->type == R_MIPS16_GOT16)
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, FALSE);
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MIPS16_HI16, FALSE);
 
      else if (hi->rel.howto->type == R_MICROMIPS_GOT16)
 
        hi->rel.howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, R_MICROMIPS_HI16, FALSE);
 
 
      /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any
      /* VALLO is a signed 16-bit number.  Bias it by 0x8000 so that any
         carry or borrow will induce a change of +1 or -1 in the high part.  */
         carry or borrow will induce a change of +1 or -1 in the high part.  */
      hi->rel.addend += (vallo + 0x8000) & 0xffff;
      hi->rel.addend += (vallo + 0x8000) & 0xffff;
 
 
Line 2181... Line 2292...
 
 
      /* Add in the separate addend, if any.  */
      /* Add in the separate addend, if any.  */
      val += reloc_entry->addend;
      val += reloc_entry->addend;
 
 
      /* Add VAL to the relocation field.  */
      /* Add VAL to the relocation field.  */
      _bfd_mips16_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
      _bfd_mips_elf_reloc_unshuffle (abfd, reloc_entry->howto->type, FALSE,
                                       location);
                                       location);
      status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
      status = _bfd_relocate_contents (reloc_entry->howto, abfd, val,
                                       location);
                                       location);
      _bfd_mips16_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
      _bfd_mips_elf_reloc_shuffle (abfd, reloc_entry->howto->type, FALSE,
                                     location);
                                     location);
 
 
      if (status != bfd_reloc_ok)
      if (status != bfd_reloc_ok)
        return status;
        return status;
    }
    }
Line 2975... Line 3086...
static bfd_vma
static bfd_vma
mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
mips_tls_got_index (bfd *abfd, bfd_vma got_index, unsigned char *tls_type,
                    int r_type, struct bfd_link_info *info,
                    int r_type, struct bfd_link_info *info,
                    struct mips_elf_link_hash_entry *h, bfd_vma symbol)
                    struct mips_elf_link_hash_entry *h, bfd_vma symbol)
{
{
  BFD_ASSERT (r_type == R_MIPS_TLS_GOTTPREL || r_type == R_MIPS_TLS_GD
  BFD_ASSERT (tls_gottprel_reloc_p (r_type)
              || r_type == R_MIPS_TLS_LDM);
              || tls_gd_reloc_p (r_type)
 
              || tls_ldm_reloc_p (r_type));
 
 
  mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
  mips_elf_initialize_tls_slots (abfd, got_index, tls_type, info, h, symbol);
 
 
  if (r_type == R_MIPS_TLS_GOTTPREL)
  if (tls_gottprel_reloc_p (r_type))
    {
    {
      BFD_ASSERT (*tls_type & GOT_TLS_IE);
      BFD_ASSERT (*tls_type & GOT_TLS_IE);
      if (*tls_type & GOT_TLS_GD)
      if (*tls_type & GOT_TLS_GD)
        return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd);
        return got_index + 2 * MIPS_ELF_GOT_SIZE (abfd);
      else
      else
        return got_index;
        return got_index;
    }
    }
 
 
  if (r_type == R_MIPS_TLS_GD)
  if (tls_gd_reloc_p (r_type))
    {
    {
      BFD_ASSERT (*tls_type & GOT_TLS_GD);
      BFD_ASSERT (*tls_type & GOT_TLS_GD);
      return got_index;
      return got_index;
    }
    }
 
 
  if (r_type == R_MIPS_TLS_LDM)
  if (tls_ldm_reloc_p (r_type))
    {
    {
      BFD_ASSERT (*tls_type & GOT_TLS_LDM);
      BFD_ASSERT (*tls_type & GOT_TLS_LDM);
      return got_index;
      return got_index;
    }
    }
 
 
Line 3277... Line 3389...
  if (TLS_RELOC_P (r_type))
  if (TLS_RELOC_P (r_type))
    {
    {
      struct mips_got_entry *p;
      struct mips_got_entry *p;
 
 
      entry.abfd = ibfd;
      entry.abfd = ibfd;
      if (r_type == R_MIPS_TLS_LDM)
      if (tls_ldm_reloc_p (r_type))
        {
        {
          entry.tls_type = GOT_TLS_LDM;
          entry.tls_type = GOT_TLS_LDM;
          entry.symndx = 0;
          entry.symndx = 0;
          entry.d.addend = 0;
          entry.d.addend = 0;
        }
        }
Line 4808... Line 4920...
  switch (r_type)
  switch (r_type)
    {
    {
    case R_MIPS_26:
    case R_MIPS_26:
    case R_MIPS_PC16:
    case R_MIPS_PC16:
    case R_MIPS16_26:
    case R_MIPS16_26:
 
    case R_MICROMIPS_26_S1:
 
    case R_MICROMIPS_PC7_S1:
 
    case R_MICROMIPS_PC10_S1:
 
    case R_MICROMIPS_PC16_S1:
 
    case R_MICROMIPS_PC23_S2:
      return TRUE;
      return TRUE;
 
 
    default:
    default:
      return FALSE;
      return FALSE;
    }
    }
Line 4821... Line 4938...
   the INPUT_BFD).  The ADDEND is the addend to use for this
   the INPUT_BFD).  The ADDEND is the addend to use for this
   RELOCATION; RELOCATION->R_ADDEND is ignored.
   RELOCATION; RELOCATION->R_ADDEND is ignored.
 
 
   The result of the relocation calculation is stored in VALUEP.
   The result of the relocation calculation is stored in VALUEP.
   On exit, set *CROSS_MODE_JUMP_P to true if the relocation field
   On exit, set *CROSS_MODE_JUMP_P to true if the relocation field
   is a MIPS16 jump to non-MIPS16 code, or vice versa.
   is a MIPS16 or microMIPS jump to standard MIPS code, or vice versa.
 
 
   This function returns bfd_reloc_continue if the caller need take no
   This function returns bfd_reloc_continue if the caller need take no
   further action regarding this relocation, bfd_reloc_notsupported if
   further action regarding this relocation, bfd_reloc_notsupported if
   something goes dramatically wrong, bfd_reloc_overflow if an
   something goes dramatically wrong, bfd_reloc_overflow if an
   overflow occurs, and bfd_reloc_ok to indicate success.  */
   overflow occurs, and bfd_reloc_ok to indicate success.  */
Line 4878... Line 4995...
  /* TRUE if overflow occurred during the calculation of the
  /* TRUE if overflow occurred during the calculation of the
     relocation value.  */
     relocation value.  */
  bfd_boolean overflowed_p;
  bfd_boolean overflowed_p;
  /* TRUE if this relocation refers to a MIPS16 function.  */
  /* TRUE if this relocation refers to a MIPS16 function.  */
  bfd_boolean target_is_16_bit_code_p = FALSE;
  bfd_boolean target_is_16_bit_code_p = FALSE;
 
  bfd_boolean target_is_micromips_code_p = FALSE;
  struct mips_elf_link_hash_table *htab;
  struct mips_elf_link_hash_table *htab;
  bfd *dynobj;
  bfd *dynobj;
 
 
  dynobj = elf_hash_table (info)->dynobj;
  dynobj = elf_hash_table (info)->dynobj;
  htab = mips_elf_hash_table (info);
  htab = mips_elf_hash_table (info);
Line 4930... Line 5048...
          addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
          addend = _bfd_elf_rel_local_sym (abfd, sym, &sec, addend);
          addend -= symbol;
          addend -= symbol;
          addend += sec->output_section->vma + sec->output_offset;
          addend += sec->output_section->vma + sec->output_offset;
        }
        }
 
 
      /* MIPS16 text labels should be treated as odd.  */
      /* MIPS16/microMIPS text labels should be treated as odd.  */
      if (ELF_ST_IS_MIPS16 (sym->st_other))
      if (ELF_ST_IS_COMPRESSED (sym->st_other))
        ++symbol;
        ++symbol;
 
 
      /* Record the name of this symbol, for our caller.  */
      /* Record the name of this symbol, for our caller.  */
      *namep = bfd_elf_string_from_elf_section (input_bfd,
      *namep = bfd_elf_string_from_elf_section (input_bfd,
                                                symtab_hdr->sh_link,
                                                symtab_hdr->sh_link,
                                                sym->st_name);
                                                sym->st_name);
      if (*namep == '\0')
      if (*namep == '\0')
        *namep = bfd_section_name (input_bfd, sec);
        *namep = bfd_section_name (input_bfd, sec);
 
 
      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (sym->st_other);
 
      target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (sym->st_other);
    }
    }
  else
  else
    {
    {
      /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ?  */
      /* ??? Could we use RELOC_FOR_GLOBAL_SYMBOL here ?  */
 
 
Line 5039... Line 5158...
        {
        {
          return bfd_reloc_notsupported;
          return bfd_reloc_notsupported;
        }
        }
 
 
      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
      target_is_16_bit_code_p = ELF_ST_IS_MIPS16 (h->root.other);
 
      /* If the output section is the PLT section,
 
         then the target is not microMIPS.  */
 
      target_is_micromips_code_p = (htab->splt != sec
 
                                    && ELF_ST_IS_MICROMIPS (h->root.other));
    }
    }
 
 
  /* If this is a reference to a 16-bit function with a stub, we need
  /* If this is a reference to a 16-bit function with a stub, we need
     to redirect the relocation to the stub unless:
     to redirect the relocation to the stub unless:
 
 
Line 5126... Line 5249...
           && mips_elf_relocation_needs_la25_stub (input_bfd, r_type))
           && mips_elf_relocation_needs_la25_stub (input_bfd, r_type))
    symbol = (h->la25_stub->stub_section->output_section->vma
    symbol = (h->la25_stub->stub_section->output_section->vma
              + h->la25_stub->stub_section->output_offset
              + h->la25_stub->stub_section->output_offset
              + h->la25_stub->offset);
              + h->la25_stub->offset);
 
 
 
  /* Make sure MIPS16 and microMIPS are not used together.  */
 
  if ((r_type == R_MIPS16_26 && target_is_micromips_code_p)
 
      || (micromips_branch_reloc_p (r_type) && target_is_16_bit_code_p))
 
   {
 
      (*_bfd_error_handler)
 
        (_("MIPS16 and microMIPS functions cannot call each other"));
 
      return bfd_reloc_notsupported;
 
   }
 
 
  /* Calls from 16-bit code to 32-bit code and vice versa require the
  /* Calls from 16-bit code to 32-bit code and vice versa require the
     mode change.  */
     mode change.  However, we can ignore calls to undefined weak symbols,
  *cross_mode_jump_p = !info->relocatable
     which should never be executed at runtime.  This exception is important
 
     because the assembly writer may have "known" that any definition of the
 
     symbol would be 16-bit code, and that direct jumps were therefore
 
     acceptable.  */
 
  *cross_mode_jump_p = (!info->relocatable
 
                        && !(h && h->root.root.type == bfd_link_hash_undefweak)
                       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
                       && ((r_type == R_MIPS16_26 && !target_is_16_bit_code_p)
 
                            || (r_type == R_MICROMIPS_26_S1
 
                                && !target_is_micromips_code_p)
                           || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
                           || ((r_type == R_MIPS_26 || r_type == R_MIPS_JALR)
                               && target_is_16_bit_code_p));
                                && (target_is_16_bit_code_p
 
                                    || target_is_micromips_code_p))));
 
 
  local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root);
  local_p = h == NULL || SYMBOL_REFERENCES_LOCAL (info, &h->root);
 
 
  gp0 = _bfd_get_gp_value (input_bfd);
  gp0 = _bfd_get_gp_value (input_bfd);
  gp = _bfd_get_gp_value (abfd);
  gp = _bfd_get_gp_value (abfd);
Line 5143... Line 5283...
    gp += mips_elf_adjust_gp (abfd, htab->got_info, input_bfd);
    gp += mips_elf_adjust_gp (abfd, htab->got_info, input_bfd);
 
 
  if (gnu_local_gp_p)
  if (gnu_local_gp_p)
    symbol = gp;
    symbol = gp;
 
 
  /* Global R_MIPS_GOT_PAGE relocations are equivalent to R_MIPS_GOT_DISP.
  /* Global R_MIPS_GOT_PAGE/R_MICROMIPS_GOT_PAGE relocations are equivalent
     The addend is applied by the corresponding R_MIPS_GOT_OFST.  */
     to R_MIPS_GOT_DISP/R_MICROMIPS_GOT_DISP.  The addend is applied by the
  if (r_type == R_MIPS_GOT_PAGE && !local_p)
     corresponding R_MIPS_GOT_OFST/R_MICROMIPS_GOT_OFST.  */
 
  if (got_page_reloc_p (r_type) && !local_p)
    {
    {
      r_type = R_MIPS_GOT_DISP;
      r_type = (micromips_reloc_p (r_type)
 
                ? R_MICROMIPS_GOT_DISP : R_MIPS_GOT_DISP);
      addend = 0;
      addend = 0;
    }
    }
 
 
  /* If we haven't already determined the GOT offset, and we're going
  /* If we haven't already determined the GOT offset, and we're going
     to need it, get it now.  */
     to need it, get it now.  */
Line 5164... Line 5306...
    case R_MIPS_GOT_DISP:
    case R_MIPS_GOT_DISP:
    case R_MIPS_GOT_HI16:
    case R_MIPS_GOT_HI16:
    case R_MIPS_CALL_HI16:
    case R_MIPS_CALL_HI16:
    case R_MIPS_GOT_LO16:
    case R_MIPS_GOT_LO16:
    case R_MIPS_CALL_LO16:
    case R_MIPS_CALL_LO16:
 
    case R_MICROMIPS_CALL16:
 
    case R_MICROMIPS_GOT16:
 
    case R_MICROMIPS_GOT_DISP:
 
    case R_MICROMIPS_GOT_HI16:
 
    case R_MICROMIPS_CALL_HI16:
 
    case R_MICROMIPS_GOT_LO16:
 
    case R_MICROMIPS_CALL_LO16:
    case R_MIPS_TLS_GD:
    case R_MIPS_TLS_GD:
    case R_MIPS_TLS_GOTTPREL:
    case R_MIPS_TLS_GOTTPREL:
    case R_MIPS_TLS_LDM:
    case R_MIPS_TLS_LDM:
 
    case R_MICROMIPS_TLS_GD:
 
    case R_MICROMIPS_TLS_GOTTPREL:
 
    case R_MICROMIPS_TLS_LDM:
      /* Find the index into the GOT where this value is located.  */
      /* Find the index into the GOT where this value is located.  */
      if (r_type == R_MIPS_TLS_LDM)
      if (tls_ldm_reloc_p (r_type))
        {
        {
          g = mips_elf_local_got_index (abfd, input_bfd, info,
          g = mips_elf_local_got_index (abfd, input_bfd, info,
                                        0, 0, NULL, r_type);
                                        0, 0, NULL, r_type);
          if (g == MINUS_ONE)
          if (g == MINUS_ONE)
            return bfd_reloc_outofrange;
            return bfd_reloc_outofrange;
Line 5180... Line 5332...
      else if (!local_p)
      else if (!local_p)
        {
        {
          /* On VxWorks, CALL relocations should refer to the .got.plt
          /* On VxWorks, CALL relocations should refer to the .got.plt
             entry, which is initialized to point at the PLT stub.  */
             entry, which is initialized to point at the PLT stub.  */
          if (htab->is_vxworks
          if (htab->is_vxworks
              && (r_type == R_MIPS_CALL_HI16
              && (call_hi16_reloc_p (r_type)
                  || r_type == R_MIPS_CALL_LO16
                  || call_lo16_reloc_p (r_type)
                  || call16_reloc_p (r_type)))
                  || call16_reloc_p (r_type)))
            {
            {
              BFD_ASSERT (addend == 0);
              BFD_ASSERT (addend == 0);
              BFD_ASSERT (h->root.needs_plt);
              BFD_ASSERT (h->root.needs_plt);
              g = mips_elf_gotplt_index (info, &h->root);
              g = mips_elf_gotplt_index (info, &h->root);
Line 5309... Line 5461...
         R_MIPS_26.  It's only the storage of the relocated field into
         R_MIPS_26.  It's only the storage of the relocated field into
         the output file that's different.  That's handled in
         the output file that's different.  That's handled in
         mips_elf_perform_relocation.  So, we just fall through to the
         mips_elf_perform_relocation.  So, we just fall through to the
         R_MIPS_26 case here.  */
         R_MIPS_26 case here.  */
    case R_MIPS_26:
    case R_MIPS_26:
 
    case R_MICROMIPS_26_S1:
 
      {
 
        unsigned int shift;
 
 
 
        /* Make sure the target of JALX is word-aligned.  Bit 0 must be
 
           the correct ISA mode selector and bit 1 must be 0.  */
 
        if (*cross_mode_jump_p && (symbol & 3) != (r_type == R_MIPS_26))
 
          return bfd_reloc_outofrange;
 
 
 
        /* Shift is 2, unusually, for microMIPS JALX.  */
 
        shift = (!*cross_mode_jump_p && r_type == R_MICROMIPS_26_S1) ? 1 : 2;
 
 
      if (was_local_p)
      if (was_local_p)
        value = ((addend | ((p + 4) & 0xf0000000)) + symbol) >> 2;
          value = addend | ((p + 4) & (0xfc000000 << shift));
      else
      else
        {
          value = _bfd_mips_elf_sign_extend (addend, 26 + shift);
          value = (_bfd_mips_elf_sign_extend (addend, 28) + symbol) >> 2;
        value = (value + symbol) >> shift;
          if (h->root.root.type != bfd_link_hash_undefweak)
        if (!was_local_p && h->root.root.type != bfd_link_hash_undefweak)
            overflowed_p = (value >> 26) != ((p + 4) >> 28);
          overflowed_p = (value >> 26) != ((p + 4) >> (26 + shift));
        }
 
      value &= howto->dst_mask;
      value &= howto->dst_mask;
 
      }
      break;
      break;
 
 
    case R_MIPS_TLS_DTPREL_HI16:
    case R_MIPS_TLS_DTPREL_HI16:
 
    case R_MICROMIPS_TLS_DTPREL_HI16:
      value = (mips_elf_high (addend + symbol - dtprel_base (info))
      value = (mips_elf_high (addend + symbol - dtprel_base (info))
               & howto->dst_mask);
               & howto->dst_mask);
      break;
      break;
 
 
    case R_MIPS_TLS_DTPREL_LO16:
    case R_MIPS_TLS_DTPREL_LO16:
    case R_MIPS_TLS_DTPREL32:
    case R_MIPS_TLS_DTPREL32:
    case R_MIPS_TLS_DTPREL64:
    case R_MIPS_TLS_DTPREL64:
 
    case R_MICROMIPS_TLS_DTPREL_LO16:
      value = (symbol + addend - dtprel_base (info)) & howto->dst_mask;
      value = (symbol + addend - dtprel_base (info)) & howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_TLS_TPREL_HI16:
    case R_MIPS_TLS_TPREL_HI16:
 
    case R_MICROMIPS_TLS_TPREL_HI16:
      value = (mips_elf_high (addend + symbol - tprel_base (info))
      value = (mips_elf_high (addend + symbol - tprel_base (info))
               & howto->dst_mask);
               & howto->dst_mask);
      break;
      break;
 
 
    case R_MIPS_TLS_TPREL_LO16:
    case R_MIPS_TLS_TPREL_LO16:
 
    case R_MICROMIPS_TLS_TPREL_LO16:
      value = (symbol + addend - tprel_base (info)) & howto->dst_mask;
      value = (symbol + addend - tprel_base (info)) & howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_HI16:
    case R_MIPS_HI16:
    case R_MIPS16_HI16:
    case R_MIPS16_HI16:
 
    case R_MICROMIPS_HI16:
      if (!gp_disp_p)
      if (!gp_disp_p)
        {
        {
          value = mips_elf_high (addend + symbol);
          value = mips_elf_high (addend + symbol);
          value &= howto->dst_mask;
          value &= howto->dst_mask;
        }
        }
Line 5360... Line 5529...
             So the offsets of hi and lo relocs are the same, but the
             So the offsets of hi and lo relocs are the same, but the
             $pc is four higher than $t9 would be, so reduce
             $pc is four higher than $t9 would be, so reduce
             both reloc addends by 4. */
             both reloc addends by 4. */
          if (r_type == R_MIPS16_HI16)
          if (r_type == R_MIPS16_HI16)
            value = mips_elf_high (addend + gp - p - 4);
            value = mips_elf_high (addend + gp - p - 4);
 
          /* The microMIPS .cpload sequence uses the same assembly
 
             instructions as the traditional psABI version, but the
 
             incoming $t9 has the low bit set.  */
 
          else if (r_type == R_MICROMIPS_HI16)
 
            value = mips_elf_high (addend + gp - p - 1);
          else
          else
            value = mips_elf_high (addend + gp - p);
            value = mips_elf_high (addend + gp - p);
          overflowed_p = mips_elf_overflow_p (value, 16);
          overflowed_p = mips_elf_overflow_p (value, 16);
        }
        }
      break;
      break;
 
 
    case R_MIPS_LO16:
    case R_MIPS_LO16:
    case R_MIPS16_LO16:
    case R_MIPS16_LO16:
 
    case R_MICROMIPS_LO16:
 
    case R_MICROMIPS_HI0_LO16:
      if (!gp_disp_p)
      if (!gp_disp_p)
        value = (symbol + addend) & howto->dst_mask;
        value = (symbol + addend) & howto->dst_mask;
      else
      else
        {
        {
          /* See the comment for R_MIPS16_HI16 above for the reason
          /* See the comment for R_MIPS16_HI16 above for the reason
             for this conditional.  */
             for this conditional.  */
          if (r_type == R_MIPS16_LO16)
          if (r_type == R_MIPS16_LO16)
            value = addend + gp - p;
            value = addend + gp - p;
 
          else if (r_type == R_MICROMIPS_LO16
 
                   || r_type == R_MICROMIPS_HI0_LO16)
 
            value = addend + gp - p + 3;
          else
          else
            value = addend + gp - p + 4;
            value = addend + gp - p + 4;
          /* The MIPS ABI requires checking the R_MIPS_LO16 relocation
          /* The MIPS ABI requires checking the R_MIPS_LO16 relocation
             for overflow.  But, on, say, IRIX5, relocations against
             for overflow.  But, on, say, IRIX5, relocations against
             _gp_disp are normally generated from the .cpload
             _gp_disp are normally generated from the .cpload
Line 5398... Line 5577...
             not check for overflow here.  */
             not check for overflow here.  */
        }
        }
      break;
      break;
 
 
    case R_MIPS_LITERAL:
    case R_MIPS_LITERAL:
 
    case R_MICROMIPS_LITERAL:
      /* Because we don't merge literal sections, we can handle this
      /* Because we don't merge literal sections, we can handle this
         just like R_MIPS_GPREL16.  In the long run, we should merge
         just like R_MIPS_GPREL16.  In the long run, we should merge
         shared literals, and then we will need to additional work
         shared literals, and then we will need to additional work
         here.  */
         here.  */
 
 
Line 5411... Line 5591...
      /* The R_MIPS16_GPREL performs the same calculation as
      /* The R_MIPS16_GPREL performs the same calculation as
         R_MIPS_GPREL16, but stores the relocated bits in a different
         R_MIPS_GPREL16, but stores the relocated bits in a different
         order.  We don't need to do anything special here; the
         order.  We don't need to do anything special here; the
         differences are handled in mips_elf_perform_relocation.  */
         differences are handled in mips_elf_perform_relocation.  */
    case R_MIPS_GPREL16:
    case R_MIPS_GPREL16:
 
    case R_MICROMIPS_GPREL7_S2:
 
    case R_MICROMIPS_GPREL16:
      /* Only sign-extend the addend if it was extracted from the
      /* Only sign-extend the addend if it was extracted from the
         instruction.  If the addend was separate, leave it alone,
         instruction.  If the addend was separate, leave it alone,
         otherwise we may lose significant bits.  */
         otherwise we may lose significant bits.  */
      if (howto->partial_inplace)
      if (howto->partial_inplace)
        addend = _bfd_mips_elf_sign_extend (addend, 16);
        addend = _bfd_mips_elf_sign_extend (addend, 16);
Line 5431... Line 5613...
 
 
    case R_MIPS16_GOT16:
    case R_MIPS16_GOT16:
    case R_MIPS16_CALL16:
    case R_MIPS16_CALL16:
    case R_MIPS_GOT16:
    case R_MIPS_GOT16:
    case R_MIPS_CALL16:
    case R_MIPS_CALL16:
 
    case R_MICROMIPS_GOT16:
 
    case R_MICROMIPS_CALL16:
      /* VxWorks does not have separate local and global semantics for
      /* VxWorks does not have separate local and global semantics for
         R_MIPS*_GOT16; every relocation evaluates to "G".  */
         R_MIPS*_GOT16; every relocation evaluates to "G".  */
      if (!htab->is_vxworks && local_p)
      if (!htab->is_vxworks && local_p)
        {
        {
          value = mips_elf_got16_entry (abfd, input_bfd, info,
          value = mips_elf_got16_entry (abfd, input_bfd, info,
Line 5451... Line 5635...
 
 
    case R_MIPS_TLS_GD:
    case R_MIPS_TLS_GD:
    case R_MIPS_TLS_GOTTPREL:
    case R_MIPS_TLS_GOTTPREL:
    case R_MIPS_TLS_LDM:
    case R_MIPS_TLS_LDM:
    case R_MIPS_GOT_DISP:
    case R_MIPS_GOT_DISP:
 
    case R_MICROMIPS_TLS_GD:
 
    case R_MICROMIPS_TLS_GOTTPREL:
 
    case R_MICROMIPS_TLS_LDM:
 
    case R_MICROMIPS_GOT_DISP:
      value = g;
      value = g;
      overflowed_p = mips_elf_overflow_p (value, 16);
      overflowed_p = mips_elf_overflow_p (value, 16);
      break;
      break;
 
 
    case R_MIPS_GPREL32:
    case R_MIPS_GPREL32:
Line 5469... Line 5657...
      overflowed_p = mips_elf_overflow_p (value, 18);
      overflowed_p = mips_elf_overflow_p (value, 18);
      value >>= howto->rightshift;
      value >>= howto->rightshift;
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      break;
      break;
 
 
 
    case R_MICROMIPS_PC7_S1:
 
      value = symbol + _bfd_mips_elf_sign_extend (addend, 8) - p;
 
      overflowed_p = mips_elf_overflow_p (value, 8);
 
      value >>= howto->rightshift;
 
      value &= howto->dst_mask;
 
      break;
 
 
 
    case R_MICROMIPS_PC10_S1:
 
      value = symbol + _bfd_mips_elf_sign_extend (addend, 11) - p;
 
      overflowed_p = mips_elf_overflow_p (value, 11);
 
      value >>= howto->rightshift;
 
      value &= howto->dst_mask;
 
      break;
 
 
 
    case R_MICROMIPS_PC16_S1:
 
      value = symbol + _bfd_mips_elf_sign_extend (addend, 17) - p;
 
      overflowed_p = mips_elf_overflow_p (value, 17);
 
      value >>= howto->rightshift;
 
      value &= howto->dst_mask;
 
      break;
 
 
 
    case R_MICROMIPS_PC23_S2:
 
      value = symbol + _bfd_mips_elf_sign_extend (addend, 25) - ((p | 3) ^ 3);
 
      overflowed_p = mips_elf_overflow_p (value, 25);
 
      value >>= howto->rightshift;
 
      value &= howto->dst_mask;
 
      break;
 
 
    case R_MIPS_GOT_HI16:
    case R_MIPS_GOT_HI16:
    case R_MIPS_CALL_HI16:
    case R_MIPS_CALL_HI16:
 
    case R_MICROMIPS_GOT_HI16:
 
    case R_MICROMIPS_CALL_HI16:
      /* We're allowed to handle these two relocations identically.
      /* We're allowed to handle these two relocations identically.
         The dynamic linker is allowed to handle the CALL relocations
         The dynamic linker is allowed to handle the CALL relocations
         differently by creating a lazy evaluation stub.  */
         differently by creating a lazy evaluation stub.  */
      value = g;
      value = g;
      value = mips_elf_high (value);
      value = mips_elf_high (value);
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_GOT_LO16:
    case R_MIPS_GOT_LO16:
    case R_MIPS_CALL_LO16:
    case R_MIPS_CALL_LO16:
 
    case R_MICROMIPS_GOT_LO16:
 
    case R_MICROMIPS_CALL_LO16:
      value = g & howto->dst_mask;
      value = g & howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_GOT_PAGE:
    case R_MIPS_GOT_PAGE:
 
    case R_MICROMIPS_GOT_PAGE:
      value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
      value = mips_elf_got_page (abfd, input_bfd, info, symbol + addend, NULL);
      if (value == MINUS_ONE)
      if (value == MINUS_ONE)
        return bfd_reloc_outofrange;
        return bfd_reloc_outofrange;
      value = mips_elf_got_offset_from_index (info, abfd, input_bfd, value);
      value = mips_elf_got_offset_from_index (info, abfd, input_bfd, value);
      overflowed_p = mips_elf_overflow_p (value, 16);
      overflowed_p = mips_elf_overflow_p (value, 16);
      break;
      break;
 
 
    case R_MIPS_GOT_OFST:
    case R_MIPS_GOT_OFST:
 
    case R_MICROMIPS_GOT_OFST:
      if (local_p)
      if (local_p)
        mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
        mips_elf_got_page (abfd, input_bfd, info, symbol + addend, &value);
      else
      else
        value = addend;
        value = addend;
      overflowed_p = mips_elf_overflow_p (value, 16);
      overflowed_p = mips_elf_overflow_p (value, 16);
      break;
      break;
 
 
    case R_MIPS_SUB:
    case R_MIPS_SUB:
 
    case R_MICROMIPS_SUB:
      value = symbol - addend;
      value = symbol - addend;
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_HIGHER:
    case R_MIPS_HIGHER:
 
    case R_MICROMIPS_HIGHER:
      value = mips_elf_higher (addend + symbol);
      value = mips_elf_higher (addend + symbol);
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_HIGHEST:
    case R_MIPS_HIGHEST:
 
    case R_MICROMIPS_HIGHEST:
      value = mips_elf_highest (addend + symbol);
      value = mips_elf_highest (addend + symbol);
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_SCN_DISP:
    case R_MIPS_SCN_DISP:
 
    case R_MICROMIPS_SCN_DISP:
      value = symbol + addend - sec->output_offset;
      value = symbol + addend - sec->output_offset;
      value &= howto->dst_mask;
      value &= howto->dst_mask;
      break;
      break;
 
 
    case R_MIPS_JALR:
    case R_MIPS_JALR:
 
    case R_MICROMIPS_JALR:
      /* This relocation is only a hint.  In some cases, we optimize
      /* This relocation is only a hint.  In some cases, we optimize
         it into a bal instruction.  But we don't try to optimize
         it into a bal instruction.  But we don't try to optimize
         when the symbol does not resolve locally.  */
         when the symbol does not resolve locally.  */
      if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
      if (h != NULL && !SYMBOL_CALLS_LOCAL (info, &h->root))
        return bfd_reloc_continue;
        return bfd_reloc_continue;
Line 5566... Line 5793...
/* It has been determined that the result of the RELOCATION is the
/* It has been determined that the result of the RELOCATION is the
   VALUE.  Use HOWTO to place VALUE into the output file at the
   VALUE.  Use HOWTO to place VALUE into the output file at the
   appropriate position.  The SECTION is the section to which the
   appropriate position.  The SECTION is the section to which the
   relocation applies.
   relocation applies.
   CROSS_MODE_JUMP_P is true if the relocation field
   CROSS_MODE_JUMP_P is true if the relocation field
   is a MIPS16 jump to non-MIPS16 code, or vice versa.
   is a MIPS16 or microMIPS jump to standard MIPS code, or vice versa.
 
 
   Returns FALSE if anything goes wrong.  */
   Returns FALSE if anything goes wrong.  */
 
 
static bfd_boolean
static bfd_boolean
mips_elf_perform_relocation (struct bfd_link_info *info,
mips_elf_perform_relocation (struct bfd_link_info *info,
Line 5585... Line 5812...
  int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
  int r_type = ELF_R_TYPE (input_bfd, relocation->r_info);
 
 
  /* Figure out where the relocation is occurring.  */
  /* Figure out where the relocation is occurring.  */
  location = contents + relocation->r_offset;
  location = contents + relocation->r_offset;
 
 
  _bfd_mips16_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
  _bfd_mips_elf_reloc_unshuffle (input_bfd, r_type, FALSE, location);
 
 
  /* Obtain the current value.  */
  /* Obtain the current value.  */
  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
  x = mips_elf_obtain_contents (howto, relocation, input_bfd, contents);
 
 
  /* Clear the field we are setting.  */
  /* Clear the field we are setting.  */
Line 5609... Line 5836...
      if (r_type == R_MIPS16_26)
      if (r_type == R_MIPS16_26)
        {
        {
          ok = ((opcode == 0x6) || (opcode == 0x7));
          ok = ((opcode == 0x6) || (opcode == 0x7));
          jalx_opcode = 0x7;
          jalx_opcode = 0x7;
        }
        }
 
      else if (r_type == R_MICROMIPS_26_S1)
 
        {
 
          ok = ((opcode == 0x3d) || (opcode == 0x3c));
 
          jalx_opcode = 0x3c;
 
        }
      else
      else
        {
        {
          ok = ((opcode == 0x3) || (opcode == 0x1d));
          ok = ((opcode == 0x3) || (opcode == 0x1d));
          jalx_opcode = 0x1d;
          jalx_opcode = 0x1d;
        }
        }
Line 5670... Line 5902...
    }
    }
 
 
  /* Put the value into the output.  */
  /* Put the value into the output.  */
  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
  bfd_put (8 * bfd_get_reloc_size (howto), input_bfd, x, location);
 
 
  _bfd_mips16_elf_reloc_shuffle(input_bfd, r_type, !info->relocatable,
  _bfd_mips_elf_reloc_shuffle (input_bfd, r_type, !info->relocatable,
                                location);
                                location);
 
 
  return TRUE;
  return TRUE;
}
}


Line 6132... Line 6364...
          }
          }
      }
      }
      break;
      break;
    }
    }
 
 
  /* If this is an odd-valued function symbol, assume it's a MIPS16 one.  */
  /* If this is an odd-valued function symbol, assume it's a MIPS16
 
     or microMIPS one.  */
  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_FUNC
      && (asym->value & 1) != 0)
      && (asym->value & 1) != 0)
    {
    {
      asym->value--;
      asym->value--;
 
      if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
 
        elfsym->internal_elf_sym.st_other
 
          = ELF_ST_SET_MICROMIPS (elfsym->internal_elf_sym.st_other);
 
      else
      elfsym->internal_elf_sym.st_other
      elfsym->internal_elf_sym.st_other
        = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
        = ELF_ST_SET_MIPS16 (elfsym->internal_elf_sym.st_other);
    }
    }
}
}


Line 6847... Line 7084...
    }
    }
 
 
  /* If this is a mips16 text symbol, add 1 to the value to make it
  /* If this is a mips16 text symbol, add 1 to the value to make it
     odd.  This will cause something like .word SYM to come up with
     odd.  This will cause something like .word SYM to come up with
     the right value when it is loaded into the PC.  */
     the right value when it is loaded into the PC.  */
  if (ELF_ST_IS_MIPS16 (sym->st_other))
  if (ELF_ST_IS_COMPRESSED (sym->st_other))
    ++*valp;
    ++*valp;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
Line 6870... Line 7107...
     common in the output file.  */
     common in the output file.  */
  if (sym->st_shndx == SHN_COMMON
  if (sym->st_shndx == SHN_COMMON
      && strcmp (input_sec->name, ".scommon") == 0)
      && strcmp (input_sec->name, ".scommon") == 0)
    sym->st_shndx = SHN_MIPS_SCOMMON;
    sym->st_shndx = SHN_MIPS_SCOMMON;
 
 
  if (ELF_ST_IS_MIPS16 (sym->st_other))
  if (ELF_ST_IS_COMPRESSED (sym->st_other))
    sym->st_value &= ~1;
    sym->st_value &= ~1;
 
 
  return 1;
  return 1;
}
}


Line 7121... Line 7358...
 
 
  r_type = ELF_R_TYPE (abfd, rel->r_info);
  r_type = ELF_R_TYPE (abfd, rel->r_info);
  location = contents + rel->r_offset;
  location = contents + rel->r_offset;
 
 
  /* Get the addend, which is stored in the input file.  */
  /* Get the addend, which is stored in the input file.  */
  _bfd_mips16_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
  _bfd_mips_elf_reloc_unshuffle (abfd, r_type, FALSE, location);
  addend = mips_elf_obtain_contents (howto, rel, abfd, contents);
  addend = mips_elf_obtain_contents (howto, rel, abfd, contents);
  _bfd_mips16_elf_reloc_shuffle (abfd, r_type, FALSE, location);
  _bfd_mips_elf_reloc_shuffle (abfd, r_type, FALSE, location);
 
 
  return addend & howto->src_mask;
  return addend & howto->src_mask;
}
}
 
 
/* REL is a relocation in ABFD that needs a partnering LO16 relocation
/* REL is a relocation in ABFD that needs a partnering LO16 relocation
Line 7148... Line 7385...
  bfd_vma l;
  bfd_vma l;
 
 
  r_type = ELF_R_TYPE (abfd, rel->r_info);
  r_type = ELF_R_TYPE (abfd, rel->r_info);
  if (mips16_reloc_p (r_type))
  if (mips16_reloc_p (r_type))
    lo16_type = R_MIPS16_LO16;
    lo16_type = R_MIPS16_LO16;
 
  else if (micromips_reloc_p (r_type))
 
    lo16_type = R_MICROMIPS_LO16;
  else
  else
    lo16_type = R_MIPS_LO16;
    lo16_type = R_MIPS_LO16;
 
 
  /* The combined value is the sum of the HI16 addend, left-shifted by
  /* The combined value is the sum of the HI16 addend, left-shifted by
     sixteen bits, and the LO16 addend, sign extended.  (Usually, the
     sixteen bits, and the LO16 addend, sign extended.  (Usually, the
Line 7540... Line 7779...
        case R_MIPS_GOT_OFST:
        case R_MIPS_GOT_OFST:
        case R_MIPS_GOT_DISP:
        case R_MIPS_GOT_DISP:
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS_TLS_GD:
        case R_MIPS_TLS_GD:
        case R_MIPS_TLS_LDM:
        case R_MIPS_TLS_LDM:
 
        case R_MICROMIPS_GOT16:
 
        case R_MICROMIPS_CALL16:
 
        case R_MICROMIPS_CALL_HI16:
 
        case R_MICROMIPS_CALL_LO16:
 
        case R_MICROMIPS_GOT_HI16:
 
        case R_MICROMIPS_GOT_LO16:
 
        case R_MICROMIPS_GOT_PAGE:
 
        case R_MICROMIPS_GOT_OFST:
 
        case R_MICROMIPS_GOT_DISP:
 
        case R_MICROMIPS_TLS_GOTTPREL:
 
        case R_MICROMIPS_TLS_GD:
 
        case R_MICROMIPS_TLS_LDM:
          if (dynobj == NULL)
          if (dynobj == NULL)
            elf_hash_table (info)->dynobj = dynobj = abfd;
            elf_hash_table (info)->dynobj = dynobj = abfd;
          if (!mips_elf_create_got_section (dynobj, info))
          if (!mips_elf_create_got_section (dynobj, info))
            return FALSE;
            return FALSE;
          if (htab->is_vxworks && !info->shared)
          if (htab->is_vxworks && !info->shared)
Line 7557... Line 7808...
          break;
          break;
 
 
          /* This is just a hint; it can safely be ignored.  Don't set
          /* This is just a hint; it can safely be ignored.  Don't set
             has_static_relocs for the corresponding symbol.  */
             has_static_relocs for the corresponding symbol.  */
        case R_MIPS_JALR:
        case R_MIPS_JALR:
 
        case R_MICROMIPS_JALR:
          break;
          break;
 
 
        case R_MIPS_32:
        case R_MIPS_32:
        case R_MIPS_REL32:
        case R_MIPS_REL32:
        case R_MIPS_64:
        case R_MIPS_64:
Line 7616... Line 7868...
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_MIPS_26:
        case R_MIPS_26:
        case R_MIPS_PC16:
        case R_MIPS_PC16:
        case R_MIPS16_26:
        case R_MIPS16_26:
 
        case R_MICROMIPS_26_S1:
 
        case R_MICROMIPS_PC7_S1:
 
        case R_MICROMIPS_PC10_S1:
 
        case R_MICROMIPS_PC16_S1:
 
        case R_MICROMIPS_PC23_S2:
          if (h)
          if (h)
            ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
            ((struct mips_elf_link_hash_entry *) h)->has_static_relocs = TRUE;
          break;
          break;
        }
        }
 
 
Line 7641... Line 7898...
                /* We tell the dynamic linker that there are
                /* We tell the dynamic linker that there are
                   relocations against the text segment.  */
                   relocations against the text segment.  */
                info->flags |= DF_TEXTREL;
                info->flags |= DF_TEXTREL;
            }
            }
        }
        }
      else if (r_type == R_MIPS_CALL_LO16
      else if (call_lo16_reloc_p (r_type)
               || r_type == R_MIPS_GOT_LO16
               || got_lo16_reloc_p (r_type)
               || r_type == R_MIPS_GOT_DISP
               || got_disp_reloc_p (r_type)
               || (got16_reloc_p (r_type) && htab->is_vxworks))
               || (got16_reloc_p (r_type) && htab->is_vxworks))
        {
        {
          /* We may need a local GOT entry for this relocation.  We
          /* We may need a local GOT entry for this relocation.  We
             don't count R_MIPS_GOT_PAGE because we can estimate the
             don't count R_MIPS_GOT_PAGE because we can estimate the
             maximum number of pages needed by looking at the size of
             maximum number of pages needed by looking at the size of
Line 7666... Line 7923...
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_MIPS_CALL16:
        case R_MIPS_CALL16:
        case R_MIPS16_CALL16:
        case R_MIPS16_CALL16:
 
        case R_MICROMIPS_CALL16:
          if (h == NULL)
          if (h == NULL)
            {
            {
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
                (_("%B: CALL16 reloc at 0x%lx not against global symbol"),
                 abfd, (unsigned long) rel->r_offset);
                 abfd, (unsigned long) rel->r_offset);
Line 7678... Line 7936...
            }
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_HI16:
        case R_MIPS_CALL_LO16:
        case R_MIPS_CALL_LO16:
 
        case R_MICROMIPS_CALL_HI16:
 
        case R_MICROMIPS_CALL_LO16:
          if (h != NULL)
          if (h != NULL)
            {
            {
              /* Make sure there is room in the regular GOT to hold the
              /* Make sure there is room in the regular GOT to hold the
                 function's address.  We may eliminate it in favour of
                 function's address.  We may eliminate it in favour of
                 a .got.plt entry later; see mips_elf_count_got_symbols.  */
                 a .got.plt entry later; see mips_elf_count_got_symbols.  */
Line 7695... Line 7955...
              h->type = STT_FUNC;
              h->type = STT_FUNC;
            }
            }
          break;
          break;
 
 
        case R_MIPS_GOT_PAGE:
        case R_MIPS_GOT_PAGE:
 
        case R_MICROMIPS_GOT_PAGE:
          /* If this is a global, overridable symbol, GOT_PAGE will
          /* If this is a global, overridable symbol, GOT_PAGE will
             decay to GOT_DISP, so we'll need a GOT entry for it.  */
             decay to GOT_DISP, so we'll need a GOT entry for it.  */
          if (h)
          if (h)
            {
            {
              struct mips_elf_link_hash_entry *hmips =
              struct mips_elf_link_hash_entry *hmips =
Line 7714... Line 7975...
 
 
        case R_MIPS16_GOT16:
        case R_MIPS16_GOT16:
        case R_MIPS_GOT16:
        case R_MIPS_GOT16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_HI16:
        case R_MIPS_GOT_LO16:
        case R_MIPS_GOT_LO16:
          if (!h || r_type == R_MIPS_GOT_PAGE)
        case R_MICROMIPS_GOT16:
 
        case R_MICROMIPS_GOT_HI16:
 
        case R_MICROMIPS_GOT_LO16:
 
          if (!h || got_page_reloc_p (r_type))
            {
            {
              /* This relocation needs (or may need, if h != NULL) a
              /* This relocation needs (or may need, if h != NULL) a
                 page entry in the GOT.  For R_MIPS_GOT_PAGE we do not
                 page entry in the GOT.  For R_MIPS_GOT_PAGE we do not
                 know for sure until we know whether the symbol is
                 know for sure until we know whether the symbol is
                 preemptible.  */
                 preemptible.  */
Line 7742... Line 8006...
                return FALSE;
                return FALSE;
            }
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_MIPS_GOT_DISP:
        case R_MIPS_GOT_DISP:
 
        case R_MICROMIPS_GOT_DISP:
          if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
          if (h && !mips_elf_record_global_got_symbol (h, abfd, info,
                                                       FALSE, 0))
                                                       FALSE, 0))
            return FALSE;
            return FALSE;
          break;
          break;
 
 
        case R_MIPS_TLS_GOTTPREL:
        case R_MIPS_TLS_GOTTPREL:
 
        case R_MICROMIPS_TLS_GOTTPREL:
          if (info->shared)
          if (info->shared)
            info->flags |= DF_STATIC_TLS;
            info->flags |= DF_STATIC_TLS;
          /* Fall through */
          /* Fall through */
 
 
        case R_MIPS_TLS_LDM:
        case R_MIPS_TLS_LDM:
          if (r_type == R_MIPS_TLS_LDM)
        case R_MICROMIPS_TLS_LDM:
 
          if (tls_ldm_reloc_p (r_type))
            {
            {
              r_symndx = STN_UNDEF;
              r_symndx = STN_UNDEF;
              h = NULL;
              h = NULL;
            }
            }
          /* Fall through */
          /* Fall through */
 
 
        case R_MIPS_TLS_GD:
        case R_MIPS_TLS_GD:
 
        case R_MICROMIPS_TLS_GD:
          /* This symbol requires a global offset table entry, or two
          /* This symbol requires a global offset table entry, or two
             for TLS GD relocations.  */
             for TLS GD relocations.  */
          {
          {
            unsigned char flag = (r_type == R_MIPS_TLS_GD
            unsigned char flag;
 
 
 
            flag = (tls_gd_reloc_p (r_type)
                                  ? GOT_TLS_GD
                                  ? GOT_TLS_GD
                                  : r_type == R_MIPS_TLS_LDM
                    : tls_ldm_reloc_p (r_type) ? GOT_TLS_LDM : GOT_TLS_IE);
                                  ? GOT_TLS_LDM
 
                                  : GOT_TLS_IE);
 
            if (h != NULL)
            if (h != NULL)
              {
              {
                struct mips_elf_link_hash_entry *hmips =
                struct mips_elf_link_hash_entry *hmips =
                  (struct mips_elf_link_hash_entry *) h;
                  (struct mips_elf_link_hash_entry *) h;
                hmips->tls_type |= flag;
                hmips->tls_type |= flag;
Line 7849... Line 8117...
 
 
        case R_MIPS_26:
        case R_MIPS_26:
        case R_MIPS_GPREL16:
        case R_MIPS_GPREL16:
        case R_MIPS_LITERAL:
        case R_MIPS_LITERAL:
        case R_MIPS_GPREL32:
        case R_MIPS_GPREL32:
 
        case R_MICROMIPS_26_S1:
 
        case R_MICROMIPS_GPREL16:
 
        case R_MICROMIPS_LITERAL:
 
        case R_MICROMIPS_GPREL7_S2:
          if (SGI_COMPAT (abfd))
          if (SGI_COMPAT (abfd))
            mips_elf_hash_table (info)->compact_rel_size +=
            mips_elf_hash_table (info)->compact_rel_size +=
              sizeof (Elf32_External_crinfo);
              sizeof (Elf32_External_crinfo);
          break;
          break;
 
 
Line 7889... Line 8161...
          case R_MIPS16_CALL16:
          case R_MIPS16_CALL16:
          case R_MIPS_CALL16:
          case R_MIPS_CALL16:
          case R_MIPS_CALL_HI16:
          case R_MIPS_CALL_HI16:
          case R_MIPS_CALL_LO16:
          case R_MIPS_CALL_LO16:
          case R_MIPS_JALR:
          case R_MIPS_JALR:
 
          case R_MICROMIPS_CALL16:
 
          case R_MICROMIPS_CALL_HI16:
 
          case R_MICROMIPS_CALL_LO16:
 
          case R_MICROMIPS_JALR:
            break;
            break;
          }
          }
 
 
      /* See if this reloc would need to refer to a MIPS16 hard-float stub,
      /* See if this reloc would need to refer to a MIPS16 hard-float stub,
         if there is one.  We only need to handle global symbols here;
         if there is one.  We only need to handle global symbols here;
Line 7919... Line 8195...
            {
            {
            case R_MIPS16_HI16:
            case R_MIPS16_HI16:
            case R_MIPS_HI16:
            case R_MIPS_HI16:
            case R_MIPS_HIGHER:
            case R_MIPS_HIGHER:
            case R_MIPS_HIGHEST:
            case R_MIPS_HIGHEST:
 
            case R_MICROMIPS_HI16:
 
            case R_MICROMIPS_HIGHER:
 
            case R_MICROMIPS_HIGHEST:
              /* Don't refuse a high part relocation if it's against
              /* Don't refuse a high part relocation if it's against
                 no symbol (e.g. part of a compound relocation).  */
                 no symbol (e.g. part of a compound relocation).  */
              if (r_symndx == STN_UNDEF)
              if (r_symndx == STN_UNDEF)
                break;
                break;
 
 
Line 7938... Line 8217...
 
 
              /* FALLTHROUGH */
              /* FALLTHROUGH */
 
 
            case R_MIPS16_26:
            case R_MIPS16_26:
            case R_MIPS_26:
            case R_MIPS_26:
 
            case R_MICROMIPS_26_S1:
              howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
              howto = MIPS_ELF_RTYPE_TO_HOWTO (abfd, r_type, FALSE);
              (*_bfd_error_handler)
              (*_bfd_error_handler)
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"),
                 abfd, howto->name,
                 abfd, howto->name,
                 (h) ? h->root.root.string : "a local symbol");
                 (h) ? h->root.root.string : "a local symbol");
Line 8928... Line 9208...
  asection *sec;
  asection *sec;
 
 
  if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
  if (mips_elf_local_relocation_p (input_bfd, rel, local_sections))
    {
    {
      r_type = ELF_R_TYPE (output_bfd, rel->r_info);
      r_type = ELF_R_TYPE (output_bfd, rel->r_info);
      if (r_type == R_MIPS16_GPREL
      if (gprel16_reloc_p (r_type)
          || r_type == R_MIPS_GPREL16
 
          || r_type == R_MIPS_GPREL32
          || r_type == R_MIPS_GPREL32
          || r_type == R_MIPS_LITERAL)
          || literal_reloc_p (r_type))
        {
        {
          rel->r_addend += _bfd_get_gp_value (input_bfd);
          rel->r_addend += _bfd_get_gp_value (input_bfd);
          rel->r_addend -= _bfd_get_gp_value (output_bfd);
          rel->r_addend -= _bfd_get_gp_value (output_bfd);
        }
        }
 
 
Line 9202... Line 9481...
              htab = mips_elf_hash_table (info);
              htab = mips_elf_hash_table (info);
              BFD_ASSERT (htab != NULL);
              BFD_ASSERT (htab != NULL);
              BFD_ASSERT (name != NULL);
              BFD_ASSERT (name != NULL);
              if (!htab->small_data_overflow_reported
              if (!htab->small_data_overflow_reported
                  && (gprel16_reloc_p (howto->type)
                  && (gprel16_reloc_p (howto->type)
                      || howto->type == R_MIPS_LITERAL))
                      || literal_reloc_p (howto->type)))
                {
                {
                  msg = _("small-data section exceeds 64KB;"
                  msg = _("small-data section exceeds 64KB;"
                          " lower small-data size limit (see option -G)");
                          " lower small-data size limit (see option -G)");
 
 
                  htab->small_data_overflow_reported = TRUE;
                  htab->small_data_overflow_reported = TRUE;
Line 9220... Line 9499...
          break;
          break;
 
 
        case bfd_reloc_ok:
        case bfd_reloc_ok:
          break;
          break;
 
 
 
        case bfd_reloc_outofrange:
 
          if (jal_reloc_p (howto->type))
 
            {
 
              msg = _("JALX to a non-word-aligned address");
 
              info->callbacks->warning
 
                (info, msg, name, input_bfd, input_section, rel->r_offset);
 
              return FALSE;
 
            }
 
          /* Fall through.  */
 
 
        default:
        default:
          abort ();
          abort ();
          break;
          break;
        }
        }
 
 
Line 9332... Line 9621...
  target_high = ((target + 0x8000) >> 16) & 0xffff;
  target_high = ((target + 0x8000) >> 16) & 0xffff;
  target_low = (target & 0xffff);
  target_low = (target & 0xffff);
 
 
  if (stub->stub_section != htab->strampoline)
  if (stub->stub_section != htab->strampoline)
    {
    {
      /* This is a simple LUI/ADIDU stub.  Zero out the beginning
      /* This is a simple LUI/ADDIU stub.  Zero out the beginning
         of the section and write the two instructions at the end.  */
         of the section and write the two instructions at the end.  */
      memset (loc, 0, offset);
      memset (loc, 0, offset);
      loc += offset;
      loc += offset;
 
      if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
 
        {
 
          bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_1 (target_high),
 
                      loc);
 
          bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_2 (target_high),
 
                      loc + 2);
 
          bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_1 (target_low),
 
                      loc + 4);
 
          bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_2 (target_low),
 
                      loc + 6);
 
        }
 
      else
 
        {
      bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
      bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
      bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
      bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 4);
    }
    }
 
    }
  else
  else
    {
    {
      /* This is trampoline.  */
      /* This is trampoline.  */
      loc += offset;
      loc += offset;
 
      if (ELF_ST_IS_MICROMIPS (stub->h->root.other))
 
        {
 
          bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_1 (target_high),
 
                      loc);
 
          bfd_put_16 (hti->output_bfd, LA25_LUI_MICROMIPS_2 (target_high),
 
                      loc + 2);
 
          bfd_put_16 (hti->output_bfd, LA25_J_MICROMIPS_1 (target), loc + 4);
 
          bfd_put_16 (hti->output_bfd, LA25_J_MICROMIPS_2 (target), loc + 6);
 
          bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_1 (target_low),
 
                      loc + 8);
 
          bfd_put_16 (hti->output_bfd, LA25_ADDIU_MICROMIPS_2 (target_low),
 
                      loc + 10);
 
          bfd_put_32 (hti->output_bfd, 0, loc + 12);
 
        }
 
      else
 
        {
      bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
      bfd_put_32 (hti->output_bfd, LA25_LUI (target_high), loc);
      bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
      bfd_put_32 (hti->output_bfd, LA25_J (target), loc + 4);
      bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
      bfd_put_32 (hti->output_bfd, LA25_ADDIU (target_low), loc + 8);
      bfd_put_32 (hti->output_bfd, 0, loc + 12);
      bfd_put_32 (hti->output_bfd, 0, loc + 12);
    }
    }
 
    }
  return TRUE;
  return TRUE;
}
}
 
 
/* If NAME is one of the special IRIX6 symbols defined by the linker,
/* If NAME is one of the special IRIX6 symbols defined by the linker,
   adjust it appropriately now.  */
   adjust it appropriately now.  */
Line 9909... Line 10229...
                                 + (htab->srelbss->reloc_count
                                 + (htab->srelbss->reloc_count
                                    * sizeof (Elf32_External_Rela)));
                                    * sizeof (Elf32_External_Rela)));
      ++htab->srelbss->reloc_count;
      ++htab->srelbss->reloc_count;
    }
    }
 
 
  /* If this is a mips16 symbol, force the value to be even.  */
  /* If this is a mips16/microMIPS symbol, force the value to be even.  */
  if (ELF_ST_IS_MIPS16 (sym->st_other))
  if (ELF_ST_IS_COMPRESSED (sym->st_other))
    sym->st_value &= ~1;
    sym->st_value &= ~1;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
Line 11031... Line 11351...
      case R_MIPS_GOT_HI16:
      case R_MIPS_GOT_HI16:
      case R_MIPS_GOT_LO16:
      case R_MIPS_GOT_LO16:
      case R_MIPS_GOT_DISP:
      case R_MIPS_GOT_DISP:
      case R_MIPS_GOT_PAGE:
      case R_MIPS_GOT_PAGE:
      case R_MIPS_GOT_OFST:
      case R_MIPS_GOT_OFST:
 
      case R_MICROMIPS_GOT16:
 
      case R_MICROMIPS_CALL16:
 
      case R_MICROMIPS_CALL_HI16:
 
      case R_MICROMIPS_CALL_LO16:
 
      case R_MICROMIPS_GOT_HI16:
 
      case R_MICROMIPS_GOT_LO16:
 
      case R_MICROMIPS_GOT_DISP:
 
      case R_MICROMIPS_GOT_PAGE:
 
      case R_MICROMIPS_GOT_OFST:
        /* ??? It would seem that the existing MIPS code does no sort
        /* ??? It would seem that the existing MIPS code does no sort
           of reference counting or whatnot on its GOT and PLT entries,
           of reference counting or whatnot on its GOT and PLT entries,
           so it is not possible to garbage collect them at this time.  */
           so it is not possible to garbage collect them at this time.  */
        break;
        break;
 
 
Line 11204... Line 11533...
  bfd_set_section_contents (output_bfd, sec->output_section, contents,
  bfd_set_section_contents (output_bfd, sec->output_section, contents,
                            sec->output_offset, sec->size);
                            sec->output_offset, sec->size);
  return TRUE;
  return TRUE;
}
}


 
/* microMIPS code retains local labels for linker relaxation.  Omit them
 
   from output by default for clarity.  */
 
 
 
bfd_boolean
 
_bfd_mips_elf_is_target_special_symbol (bfd *abfd, asymbol *sym)
 
{
 
  return _bfd_elf_is_local_label_name (abfd, sym->name);
 
}
 
 
/* MIPS ELF uses a special find_nearest_line routine in order the
/* MIPS ELF uses a special find_nearest_line routine in order the
   handle the ECOFF debugging information.  */
   handle the ECOFF debugging information.  */
 
 
struct mips_elf_find_line
struct mips_elf_find_line
{
{
Line 11529... Line 11867...
  if (reloc_vector != NULL)
  if (reloc_vector != NULL)
    free (reloc_vector);
    free (reloc_vector);
  return NULL;
  return NULL;
}
}


 
static bfd_boolean
 
mips_elf_relax_delete_bytes (bfd *abfd,
 
                             asection *sec, bfd_vma addr, int count)
 
{
 
  Elf_Internal_Shdr *symtab_hdr;
 
  unsigned int sec_shndx;
 
  bfd_byte *contents;
 
  Elf_Internal_Rela *irel, *irelend;
 
  Elf_Internal_Sym *isym;
 
  Elf_Internal_Sym *isymend;
 
  struct elf_link_hash_entry **sym_hashes;
 
  struct elf_link_hash_entry **end_hashes;
 
  struct elf_link_hash_entry **start_hashes;
 
  unsigned int symcount;
 
 
 
  sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec);
 
  contents = elf_section_data (sec)->this_hdr.contents;
 
 
 
  irel = elf_section_data (sec)->relocs;
 
  irelend = irel + sec->reloc_count;
 
 
 
  /* Actually delete the bytes.  */
 
  memmove (contents + addr, contents + addr + count,
 
           (size_t) (sec->size - addr - count));
 
  sec->size -= count;
 
 
 
  /* Adjust all the relocs.  */
 
  for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++)
 
    {
 
      /* Get the new reloc address.  */
 
      if (irel->r_offset > addr)
 
        irel->r_offset -= count;
 
    }
 
 
 
  BFD_ASSERT (addr % 2 == 0);
 
  BFD_ASSERT (count % 2 == 0);
 
 
 
  /* Adjust the local symbols defined in this section.  */
 
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
  isym = (Elf_Internal_Sym *) symtab_hdr->contents;
 
  for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++)
 
    if (isym->st_shndx == sec_shndx && isym->st_value > addr)
 
      isym->st_value -= count;
 
 
 
  /* Now adjust the global symbols defined in this section.  */
 
  symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym)
 
              - symtab_hdr->sh_info);
 
  sym_hashes = start_hashes = elf_sym_hashes (abfd);
 
  end_hashes = sym_hashes + symcount;
 
 
 
  for (; sym_hashes < end_hashes; sym_hashes++)
 
    {
 
      struct elf_link_hash_entry *sym_hash = *sym_hashes;
 
 
 
      if ((sym_hash->root.type == bfd_link_hash_defined
 
           || sym_hash->root.type == bfd_link_hash_defweak)
 
          && sym_hash->root.u.def.section == sec)
 
        {
 
          bfd_vma value = sym_hash->root.u.def.value;
 
 
 
          if (ELF_ST_IS_MICROMIPS (sym_hash->other))
 
            value &= MINUS_TWO;
 
          if (value > addr)
 
            sym_hash->root.u.def.value -= count;
 
        }
 
    }
 
 
 
  return TRUE;
 
}
 
 
 
 
 
/* Opcodes needed for microMIPS relaxation as found in
 
   opcodes/micromips-opc.c.  */
 
 
 
struct opcode_descriptor {
 
  unsigned long match;
 
  unsigned long mask;
 
};
 
 
 
/* The $ra register aka $31.  */
 
 
 
#define RA 31
 
 
 
/* 32-bit instruction format register fields.  */
 
 
 
#define OP32_SREG(opcode) (((opcode) >> 16) & 0x1f)
 
#define OP32_TREG(opcode) (((opcode) >> 21) & 0x1f)
 
 
 
/* Check if a 5-bit register index can be abbreviated to 3 bits.  */
 
 
 
#define OP16_VALID_REG(r) \
 
  ((2 <= (r) && (r) <= 7) || (16 <= (r) && (r) <= 17))
 
 
 
 
 
/* 32-bit and 16-bit branches.  */
 
 
 
static const struct opcode_descriptor b_insns_32[] = {
 
  { /* "b",     "p",            */ 0x40400000, 0xffff0000 }, /* bgez 0 */
 
  { /* "b",     "p",            */ 0x94000000, 0xffff0000 }, /* beq 0, 0 */
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
static const struct opcode_descriptor bc_insn_32 =
 
  { /* "bc(1|2)(ft)", "N,p",    */ 0x42800000, 0xfec30000 };
 
 
 
static const struct opcode_descriptor bz_insn_32 =
 
  { /* "b(g|l)(e|t)z", "s,p",   */ 0x40000000, 0xff200000 };
 
 
 
static const struct opcode_descriptor bzal_insn_32 =
 
  { /* "b(ge|lt)zal", "s,p",    */ 0x40200000, 0xffa00000 };
 
 
 
static const struct opcode_descriptor beq_insn_32 =
 
  { /* "b(eq|ne)", "s,t,p",     */ 0x94000000, 0xdc000000 };
 
 
 
static const struct opcode_descriptor b_insn_16 =
 
  { /* "b",     "mD",           */ 0xcc00,     0xfc00 };
 
 
 
static const struct opcode_descriptor bz_insn_16 =
 
  { /* "b(eq|ne)z", "md,mE",    */ 0x8c00,     0xdc00 };
 
 
 
 
 
/* 32-bit and 16-bit branch EQ and NE zero.  */
 
 
 
/* NOTE: All opcode tables have BEQ/BNE in the same order: first the
 
   eq and second the ne.  This convention is used when replacing a
 
   32-bit BEQ/BNE with the 16-bit version.  */
 
 
 
#define BZC32_REG_FIELD(r) (((r) & 0x1f) << 16)
 
 
 
static const struct opcode_descriptor bz_rs_insns_32[] = {
 
  { /* "beqz",  "s,p",          */ 0x94000000, 0xffe00000 },
 
  { /* "bnez",  "s,p",          */ 0xb4000000, 0xffe00000 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
static const struct opcode_descriptor bz_rt_insns_32[] = {
 
  { /* "beqz",  "t,p",          */ 0x94000000, 0xfc01f000 },
 
  { /* "bnez",  "t,p",          */ 0xb4000000, 0xfc01f000 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
static const struct opcode_descriptor bzc_insns_32[] = {
 
  { /* "beqzc", "s,p",          */ 0x40e00000, 0xffe00000 },
 
  { /* "bnezc", "s,p",          */ 0x40a00000, 0xffe00000 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
static const struct opcode_descriptor bz_insns_16[] = {
 
  { /* "beqz",  "md,mE",        */ 0x8c00,     0xfc00 },
 
  { /* "bnez",  "md,mE",        */ 0xac00,     0xfc00 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
/* Switch between a 5-bit register index and its 3-bit shorthand.  */
 
 
 
#define BZ16_REG(opcode) ((((((opcode) >> 7) & 7) + 0x1e) & 0x17) + 2)
 
#define BZ16_REG_FIELD(r) \
 
  (((2 <= (r) && (r) <= 7) ? (r) : ((r) - 16)) << 7)
 
 
 
 
 
/* 32-bit instructions with a delay slot.  */
 
 
 
static const struct opcode_descriptor jal_insn_32_bd16 =
 
  { /* "jals",  "a",            */ 0x74000000, 0xfc000000 };
 
 
 
static const struct opcode_descriptor jal_insn_32_bd32 =
 
  { /* "jal",   "a",            */ 0xf4000000, 0xfc000000 };
 
 
 
static const struct opcode_descriptor jal_x_insn_32_bd32 =
 
  { /* "jal[x]", "a",           */ 0xf0000000, 0xf8000000 };
 
 
 
static const struct opcode_descriptor j_insn_32 =
 
  { /* "j",     "a",            */ 0xd4000000, 0xfc000000 };
 
 
 
static const struct opcode_descriptor jalr_insn_32 =
 
  { /* "jalr[.hb]", "t,s",      */ 0x00000f3c, 0xfc00efff };
 
 
 
/* This table can be compacted, because no opcode replacement is made.  */
 
 
 
static const struct opcode_descriptor ds_insns_32_bd16[] = {
 
  { /* "jals",  "a",            */ 0x74000000, 0xfc000000 },
 
 
 
  { /* "jalrs[.hb]", "t,s",     */ 0x00004f3c, 0xfc00efff },
 
  { /* "b(ge|lt)zals", "s,p",   */ 0x42200000, 0xffa00000 },
 
 
 
  { /* "b(g|l)(e|t)z", "s,p",   */ 0x40000000, 0xff200000 },
 
  { /* "b(eq|ne)", "s,t,p",     */ 0x94000000, 0xdc000000 },
 
  { /* "j",     "a",            */ 0xd4000000, 0xfc000000 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
/* This table can be compacted, because no opcode replacement is made.  */
 
 
 
static const struct opcode_descriptor ds_insns_32_bd32[] = {
 
  { /* "jal[x]", "a",           */ 0xf0000000, 0xf8000000 },
 
 
 
  { /* "jalr[.hb]", "t,s",      */ 0x00000f3c, 0xfc00efff },
 
  { /* "b(ge|lt)zal", "s,p",    */ 0x40200000, 0xffa00000 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
 
 
/* 16-bit instructions with a delay slot.  */
 
 
 
static const struct opcode_descriptor jalr_insn_16_bd16 =
 
  { /* "jalrs", "my,mj",        */ 0x45e0,     0xffe0 };
 
 
 
static const struct opcode_descriptor jalr_insn_16_bd32 =
 
  { /* "jalr",  "my,mj",        */ 0x45c0,     0xffe0 };
 
 
 
static const struct opcode_descriptor jr_insn_16 =
 
  { /* "jr",    "mj",           */ 0x4580,     0xffe0 };
 
 
 
#define JR16_REG(opcode) ((opcode) & 0x1f)
 
 
 
/* This table can be compacted, because no opcode replacement is made.  */
 
 
 
static const struct opcode_descriptor ds_insns_16_bd16[] = {
 
  { /* "jalrs", "my,mj",        */ 0x45e0,     0xffe0 },
 
 
 
  { /* "b",     "mD",           */ 0xcc00,     0xfc00 },
 
  { /* "b(eq|ne)z", "md,mE",    */ 0x8c00,     0xdc00 },
 
  { /* "jr",    "mj",           */ 0x4580,     0xffe0 },
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
 
 
/* LUI instruction.  */
 
 
 
static const struct opcode_descriptor lui_insn =
 
 { /* "lui",    "s,u",          */ 0x41a00000, 0xffe00000 };
 
 
 
 
 
/* ADDIU instruction.  */
 
 
 
static const struct opcode_descriptor addiu_insn =
 
  { /* "addiu", "t,r,j",        */ 0x30000000, 0xfc000000 };
 
 
 
static const struct opcode_descriptor addiupc_insn =
 
  { /* "addiu", "mb,$pc,mQ",    */ 0x78000000, 0xfc000000 };
 
 
 
#define ADDIUPC_REG_FIELD(r) \
 
  (((2 <= (r) && (r) <= 7) ? (r) : ((r) - 16)) << 23)
 
 
 
 
 
/* Relaxable instructions in a JAL delay slot: MOVE.  */
 
 
 
/* The 16-bit move has rd in 9:5 and rs in 4:0.  The 32-bit moves
 
   (ADDU, OR) have rd in 15:11 and rs in 10:16.  */
 
#define MOVE32_RD(opcode) (((opcode) >> 11) & 0x1f)
 
#define MOVE32_RS(opcode) (((opcode) >> 16) & 0x1f)
 
 
 
#define MOVE16_RD_FIELD(r) (((r) & 0x1f) << 5)
 
#define MOVE16_RS_FIELD(r) (((r) & 0x1f)     )
 
 
 
static const struct opcode_descriptor move_insns_32[] = {
 
  { /* "move",  "d,s",          */ 0x00000150, 0xffe007ff }, /* addu d,s,$0 */
 
  { /* "move",  "d,s",          */ 0x00000290, 0xffe007ff }, /* or   d,s,$0 */
 
  { 0, 0 }  /* End marker for find_match().  */
 
};
 
 
 
static const struct opcode_descriptor move_insn_16 =
 
  { /* "move",  "mp,mj",        */ 0x0c00,     0xfc00 };
 
 
 
 
 
/* NOP instructions.  */
 
 
 
static const struct opcode_descriptor nop_insn_32 =
 
  { /* "nop",   "",             */ 0x00000000, 0xffffffff };
 
 
 
static const struct opcode_descriptor nop_insn_16 =
 
  { /* "nop",   "",             */ 0x0c00,     0xffff };
 
 
 
 
 
/* Instruction match support.  */
 
 
 
#define MATCH(opcode, insn) ((opcode & insn.mask) == insn.match)
 
 
 
static int
 
find_match (unsigned long opcode, const struct opcode_descriptor insn[])
 
{
 
  unsigned long indx;
 
 
 
  for (indx = 0; insn[indx].mask != 0; indx++)
 
    if (MATCH (opcode, insn[indx]))
 
      return indx;
 
 
 
  return -1;
 
}
 
 
 
 
 
/* Branch and delay slot decoding support.  */
 
 
 
/* If PTR points to what *might* be a 16-bit branch or jump, then
 
   return the minimum length of its delay slot, otherwise return 0.
 
   Non-zero results are not definitive as we might be checking against
 
   the second half of another instruction.  */
 
 
 
static int
 
check_br16_dslot (bfd *abfd, bfd_byte *ptr)
 
{
 
  unsigned long opcode;
 
  int bdsize;
 
 
 
  opcode = bfd_get_16 (abfd, ptr);
 
  if (MATCH (opcode, jalr_insn_16_bd32) != 0)
 
    /* 16-bit branch/jump with a 32-bit delay slot.  */
 
    bdsize = 4;
 
  else if (MATCH (opcode, jalr_insn_16_bd16) != 0
 
           || find_match (opcode, ds_insns_16_bd16) >= 0)
 
    /* 16-bit branch/jump with a 16-bit delay slot.  */
 
    bdsize = 2;
 
  else
 
    /* No delay slot.  */
 
    bdsize = 0;
 
 
 
  return bdsize;
 
}
 
 
 
/* If PTR points to what *might* be a 32-bit branch or jump, then
 
   return the minimum length of its delay slot, otherwise return 0.
 
   Non-zero results are not definitive as we might be checking against
 
   the second half of another instruction.  */
 
 
 
static int
 
check_br32_dslot (bfd *abfd, bfd_byte *ptr)
 
{
 
  unsigned long opcode;
 
  int bdsize;
 
 
 
  opcode = (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
 
  if (find_match (opcode, ds_insns_32_bd32) >= 0)
 
    /* 32-bit branch/jump with a 32-bit delay slot.  */
 
    bdsize = 4;
 
  else if (find_match (opcode, ds_insns_32_bd16) >= 0)
 
    /* 32-bit branch/jump with a 16-bit delay slot.  */
 
    bdsize = 2;
 
  else
 
    /* No delay slot.  */
 
    bdsize = 0;
 
 
 
  return bdsize;
 
}
 
 
 
/* If PTR points to a 16-bit branch or jump with a 32-bit delay slot
 
   that doesn't fiddle with REG, then return TRUE, otherwise FALSE.  */
 
 
 
static bfd_boolean
 
check_br16 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
 
{
 
  unsigned long opcode;
 
 
 
  opcode = bfd_get_16 (abfd, ptr);
 
  if (MATCH (opcode, b_insn_16)
 
                                                /* B16  */
 
      || (MATCH (opcode, jr_insn_16) && reg != JR16_REG (opcode))
 
                                                /* JR16  */
 
      || (MATCH (opcode, bz_insn_16) && reg != BZ16_REG (opcode))
 
                                                /* BEQZ16, BNEZ16  */
 
      || (MATCH (opcode, jalr_insn_16_bd32)
 
                                                /* JALR16  */
 
          && reg != JR16_REG (opcode) && reg != RA))
 
    return TRUE;
 
 
 
  return FALSE;
 
}
 
 
 
/* If PTR points to a 32-bit branch or jump that doesn't fiddle with REG,
 
   then return TRUE, otherwise FALSE.  */
 
 
 
static bfd_boolean
 
check_br32 (bfd *abfd, bfd_byte *ptr, unsigned long reg)
 
{
 
  unsigned long opcode;
 
 
 
  opcode = (bfd_get_16 (abfd, ptr) << 16) | bfd_get_16 (abfd, ptr + 2);
 
  if (MATCH (opcode, j_insn_32)
 
                                                /* J  */
 
      || MATCH (opcode, bc_insn_32)
 
                                                /* BC1F, BC1T, BC2F, BC2T  */
 
      || (MATCH (opcode, jal_x_insn_32_bd32) && reg != RA)
 
                                                /* JAL, JALX  */
 
      || (MATCH (opcode, bz_insn_32) && reg != OP32_SREG (opcode))
 
                                                /* BGEZ, BGTZ, BLEZ, BLTZ  */
 
      || (MATCH (opcode, bzal_insn_32)
 
                                                /* BGEZAL, BLTZAL  */
 
          && reg != OP32_SREG (opcode) && reg != RA)
 
      || ((MATCH (opcode, jalr_insn_32) || MATCH (opcode, beq_insn_32))
 
                                                /* JALR, JALR.HB, BEQ, BNE  */
 
          && reg != OP32_SREG (opcode) && reg != OP32_TREG (opcode)))
 
    return TRUE;
 
 
 
  return FALSE;
 
}
 
 
 
/* If the instruction encoding at PTR and relocations [INTERNAL_RELOCS,
 
   IRELEND) at OFFSET indicate that there must be a compact branch there,
 
   then return TRUE, otherwise FALSE.  */
 
 
 
static bfd_boolean
 
check_relocated_bzc (bfd *abfd, const bfd_byte *ptr, bfd_vma offset,
 
                     const Elf_Internal_Rela *internal_relocs,
 
                     const Elf_Internal_Rela *irelend)
 
{
 
  const Elf_Internal_Rela *irel;
 
  unsigned long opcode;
 
 
 
  opcode   = bfd_get_16 (abfd, ptr);
 
  opcode <<= 16;
 
  opcode  |= bfd_get_16 (abfd, ptr + 2);
 
  if (find_match (opcode, bzc_insns_32) < 0)
 
    return FALSE;
 
 
 
  for (irel = internal_relocs; irel < irelend; irel++)
 
    if (irel->r_offset == offset
 
        && ELF32_R_TYPE (irel->r_info) == R_MICROMIPS_PC16_S1)
 
      return TRUE;
 
 
 
  return FALSE;
 
}
 
 
 
/* Bitsize checking.  */
 
#define IS_BITSIZE(val, N)                                              \
 
  (((((val) & ((1ULL << (N)) - 1)) ^ (1ULL << ((N) - 1)))               \
 
    - (1ULL << ((N) - 1))) == (val))
 
 
 

 
bfd_boolean
 
_bfd_mips_elf_relax_section (bfd *abfd, asection *sec,
 
                             struct bfd_link_info *link_info,
 
                             bfd_boolean *again)
 
{
 
  Elf_Internal_Shdr *symtab_hdr;
 
  Elf_Internal_Rela *internal_relocs;
 
  Elf_Internal_Rela *irel, *irelend;
 
  bfd_byte *contents = NULL;
 
  Elf_Internal_Sym *isymbuf = NULL;
 
 
 
  /* Assume nothing changes.  */
 
  *again = FALSE;
 
 
 
  /* We don't have to do anything for a relocatable link, if
 
     this section does not have relocs, or if this is not a
 
     code section.  */
 
 
 
  if (link_info->relocatable
 
      || (sec->flags & SEC_RELOC) == 0
 
      || sec->reloc_count == 0
 
      || (sec->flags & SEC_CODE) == 0)
 
    return TRUE;
 
 
 
  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
 
 
 
  /* Get a copy of the native relocations.  */
 
  internal_relocs = (_bfd_elf_link_read_relocs
 
                     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
 
                      link_info->keep_memory));
 
  if (internal_relocs == NULL)
 
    goto error_return;
 
 
 
  /* Walk through them looking for relaxing opportunities.  */
 
  irelend = internal_relocs + sec->reloc_count;
 
  for (irel = internal_relocs; irel < irelend; irel++)
 
    {
 
      unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
 
      unsigned int r_type = ELF32_R_TYPE (irel->r_info);
 
      bfd_boolean target_is_micromips_code_p;
 
      unsigned long opcode;
 
      bfd_vma symval;
 
      bfd_vma pcrval;
 
      bfd_byte *ptr;
 
      int fndopc;
 
 
 
      /* The number of bytes to delete for relaxation and from where
 
         to delete these bytes starting at irel->r_offset.  */
 
      int delcnt = 0;
 
      int deloff = 0;
 
 
 
      /* If this isn't something that can be relaxed, then ignore
 
         this reloc.  */
 
      if (r_type != R_MICROMIPS_HI16
 
          && r_type != R_MICROMIPS_PC16_S1
 
          && r_type != R_MICROMIPS_26_S1)
 
        continue;
 
 
 
      /* Get the section contents if we haven't done so already.  */
 
      if (contents == NULL)
 
        {
 
          /* Get cached copy if it exists.  */
 
          if (elf_section_data (sec)->this_hdr.contents != NULL)
 
            contents = elf_section_data (sec)->this_hdr.contents;
 
          /* Go get them off disk.  */
 
          else if (!bfd_malloc_and_get_section (abfd, sec, &contents))
 
            goto error_return;
 
        }
 
      ptr = contents + irel->r_offset;
 
 
 
      /* Read this BFD's local symbols if we haven't done so already.  */
 
      if (isymbuf == NULL && symtab_hdr->sh_info != 0)
 
        {
 
          isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
 
          if (isymbuf == NULL)
 
            isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
 
                                            symtab_hdr->sh_info, 0,
 
                                            NULL, NULL, NULL);
 
          if (isymbuf == NULL)
 
            goto error_return;
 
        }
 
 
 
      /* Get the value of the symbol referred to by the reloc.  */
 
      if (r_symndx < symtab_hdr->sh_info)
 
        {
 
          /* A local symbol.  */
 
          Elf_Internal_Sym *isym;
 
          asection *sym_sec;
 
 
 
          isym = isymbuf + r_symndx;
 
          if (isym->st_shndx == SHN_UNDEF)
 
            sym_sec = bfd_und_section_ptr;
 
          else if (isym->st_shndx == SHN_ABS)
 
            sym_sec = bfd_abs_section_ptr;
 
          else if (isym->st_shndx == SHN_COMMON)
 
            sym_sec = bfd_com_section_ptr;
 
          else
 
            sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
          symval = (isym->st_value
 
                    + sym_sec->output_section->vma
 
                    + sym_sec->output_offset);
 
          target_is_micromips_code_p = ELF_ST_IS_MICROMIPS (isym->st_other);
 
        }
 
      else
 
        {
 
          unsigned long indx;
 
          struct elf_link_hash_entry *h;
 
 
 
          /* An external symbol.  */
 
          indx = r_symndx - symtab_hdr->sh_info;
 
          h = elf_sym_hashes (abfd)[indx];
 
          BFD_ASSERT (h != NULL);
 
 
 
          if (h->root.type != bfd_link_hash_defined
 
              && h->root.type != bfd_link_hash_defweak)
 
            /* This appears to be a reference to an undefined
 
               symbol.  Just ignore it -- it will be caught by the
 
               regular reloc processing.  */
 
            continue;
 
 
 
          symval = (h->root.u.def.value
 
                    + h->root.u.def.section->output_section->vma
 
                    + h->root.u.def.section->output_offset);
 
          target_is_micromips_code_p = (!h->needs_plt
 
                                        && ELF_ST_IS_MICROMIPS (h->other));
 
        }
 
 
 
 
 
      /* For simplicity of coding, we are going to modify the
 
         section contents, the section relocs, and the BFD symbol
 
         table.  We must tell the rest of the code not to free up this
 
         information.  It would be possible to instead create a table
 
         of changes which have to be made, as is done in coff-mips.c;
 
         that would be more work, but would require less memory when
 
         the linker is run.  */
 
 
 
      /* Only 32-bit instructions relaxed.  */
 
      if (irel->r_offset + 4 > sec->size)
 
        continue;
 
 
 
      opcode  = bfd_get_16 (abfd, ptr    ) << 16;
 
      opcode |= bfd_get_16 (abfd, ptr + 2);
 
 
 
      /* This is the pc-relative distance from the instruction the
 
         relocation is applied to, to the symbol referred.  */
 
      pcrval = (symval
 
                - (sec->output_section->vma + sec->output_offset)
 
                - irel->r_offset);
 
 
 
      /* R_MICROMIPS_HI16 / LUI relaxation to nil, performing relaxation
 
         of corresponding R_MICROMIPS_LO16 to R_MICROMIPS_HI0_LO16 or
 
         R_MICROMIPS_PC23_S2.  The R_MICROMIPS_PC23_S2 condition is
 
 
 
           (symval % 4 == 0 && IS_BITSIZE (pcrval, 25))
 
 
 
         where pcrval has first to be adjusted to apply against the LO16
 
         location (we make the adjustment later on, when we have figured
 
         out the offset).  */
 
      if (r_type == R_MICROMIPS_HI16 && MATCH (opcode, lui_insn))
 
        {
 
          bfd_boolean bzc = FALSE;
 
          unsigned long nextopc;
 
          unsigned long reg;
 
          bfd_vma offset;
 
 
 
          /* Give up if the previous reloc was a HI16 against this symbol
 
             too.  */
 
          if (irel > internal_relocs
 
              && ELF32_R_TYPE (irel[-1].r_info) == R_MICROMIPS_HI16
 
              && ELF32_R_SYM (irel[-1].r_info) == r_symndx)
 
            continue;
 
 
 
          /* Or if the next reloc is not a LO16 against this symbol.  */
 
          if (irel + 1 >= irelend
 
              || ELF32_R_TYPE (irel[1].r_info) != R_MICROMIPS_LO16
 
              || ELF32_R_SYM (irel[1].r_info) != r_symndx)
 
            continue;
 
 
 
          /* Or if the second next reloc is a LO16 against this symbol too.  */
 
          if (irel + 2 >= irelend
 
              && ELF32_R_TYPE (irel[2].r_info) == R_MICROMIPS_LO16
 
              && ELF32_R_SYM (irel[2].r_info) == r_symndx)
 
            continue;
 
 
 
          /* See if the LUI instruction *might* be in a branch delay slot.
 
             We check whether what looks like a 16-bit branch or jump is
 
             actually an immediate argument to a compact branch, and let
 
             it through if so.  */
 
          if (irel->r_offset >= 2
 
              && check_br16_dslot (abfd, ptr - 2)
 
              && !(irel->r_offset >= 4
 
                   && (bzc = check_relocated_bzc (abfd,
 
                                                  ptr - 4, irel->r_offset - 4,
 
                                                  internal_relocs, irelend))))
 
            continue;
 
          if (irel->r_offset >= 4
 
              && !bzc
 
              && check_br32_dslot (abfd, ptr - 4))
 
            continue;
 
 
 
          reg = OP32_SREG (opcode);
 
 
 
          /* We only relax adjacent instructions or ones separated with
 
             a branch or jump that has a delay slot.  The branch or jump
 
             must not fiddle with the register used to hold the address.
 
             Subtract 4 for the LUI itself.  */
 
          offset = irel[1].r_offset - irel[0].r_offset;
 
          switch (offset - 4)
 
            {
 
            case 0:
 
              break;
 
            case 2:
 
              if (check_br16 (abfd, ptr + 4, reg))
 
                break;
 
              continue;
 
            case 4:
 
              if (check_br32 (abfd, ptr + 4, reg))
 
                break;
 
              continue;
 
            default:
 
              continue;
 
            }
 
 
 
          nextopc  = bfd_get_16 (abfd, contents + irel[1].r_offset    ) << 16;
 
          nextopc |= bfd_get_16 (abfd, contents + irel[1].r_offset + 2);
 
 
 
          /* Give up unless the same register is used with both
 
             relocations.  */
 
          if (OP32_SREG (nextopc) != reg)
 
            continue;
 
 
 
          /* Now adjust pcrval, subtracting the offset to the LO16 reloc
 
             and rounding up to take masking of the two LSBs into account.  */
 
          pcrval = ((pcrval - offset + 3) | 3) ^ 3;
 
 
 
          /* R_MICROMIPS_LO16 relaxation to R_MICROMIPS_HI0_LO16.  */
 
          if (IS_BITSIZE (symval, 16))
 
            {
 
              /* Fix the relocation's type.  */
 
              irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_HI0_LO16);
 
 
 
              /* Instructions using R_MICROMIPS_LO16 have the base or
 
                 source register in bits 20:16.  This register becomes $0
 
                 (zero) as the result of the R_MICROMIPS_HI16 being 0.  */
 
              nextopc &= ~0x001f0000;
 
              bfd_put_16 (abfd, (nextopc >> 16) & 0xffff,
 
                          contents + irel[1].r_offset);
 
            }
 
 
 
          /* R_MICROMIPS_LO16 / ADDIU relaxation to R_MICROMIPS_PC23_S2.
 
             We add 4 to take LUI deletion into account while checking
 
             the PC-relative distance.  */
 
          else if (symval % 4 == 0
 
                   && IS_BITSIZE (pcrval + 4, 25)
 
                   && MATCH (nextopc, addiu_insn)
 
                   && OP32_TREG (nextopc) == OP32_SREG (nextopc)
 
                   && OP16_VALID_REG (OP32_TREG (nextopc)))
 
            {
 
              /* Fix the relocation's type.  */
 
              irel[1].r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC23_S2);
 
 
 
              /* Replace ADDIU with the ADDIUPC version.  */
 
              nextopc = (addiupc_insn.match
 
                         | ADDIUPC_REG_FIELD (OP32_TREG (nextopc)));
 
 
 
              bfd_put_16 (abfd, (nextopc >> 16) & 0xffff,
 
                          contents + irel[1].r_offset);
 
              bfd_put_16 (abfd,  nextopc        & 0xffff,
 
                          contents + irel[1].r_offset + 2);
 
            }
 
 
 
          /* Can't do anything, give up, sigh...  */
 
          else
 
            continue;
 
 
 
          /* Fix the relocation's type.  */
 
          irel->r_info = ELF32_R_INFO (r_symndx, R_MIPS_NONE);
 
 
 
          /* Delete the LUI instruction: 4 bytes at irel->r_offset.  */
 
          delcnt = 4;
 
          deloff = 0;
 
        }
 
 
 
      /* Compact branch relaxation -- due to the multitude of macros
 
         employed by the compiler/assembler, compact branches are not
 
         always generated.  Obviously, this can/will be fixed elsewhere,
 
         but there is no drawback in double checking it here.  */
 
      else if (r_type == R_MICROMIPS_PC16_S1
 
               && irel->r_offset + 5 < sec->size
 
               && ((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
 
                   || (fndopc = find_match (opcode, bz_rt_insns_32)) >= 0)
 
               && MATCH (bfd_get_16 (abfd, ptr + 4), nop_insn_16))
 
        {
 
          unsigned long reg;
 
 
 
          reg = OP32_SREG (opcode) ? OP32_SREG (opcode) : OP32_TREG (opcode);
 
 
 
          /* Replace BEQZ/BNEZ with the compact version.  */
 
          opcode = (bzc_insns_32[fndopc].match
 
                    | BZC32_REG_FIELD (reg)
 
                    | (opcode & 0xffff));               /* Addend value.  */
 
 
 
          bfd_put_16 (abfd, (opcode >> 16) & 0xffff, ptr);
 
          bfd_put_16 (abfd,  opcode        & 0xffff, ptr + 2);
 
 
 
          /* Delete the 16-bit delay slot NOP: two bytes from
 
             irel->offset + 4.  */
 
          delcnt = 2;
 
          deloff = 4;
 
        }
 
 
 
      /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC10_S1.  We need
 
         to check the distance from the next instruction, so subtract 2.  */
 
      else if (r_type == R_MICROMIPS_PC16_S1
 
               && IS_BITSIZE (pcrval - 2, 11)
 
               && find_match (opcode, b_insns_32) >= 0)
 
        {
 
          /* Fix the relocation's type.  */
 
          irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC10_S1);
 
 
 
          /* Replace the the 32-bit opcode with a 16-bit opcode.  */
 
          bfd_put_16 (abfd,
 
                      (b_insn_16.match
 
                       | (opcode & 0x3ff)),             /* Addend value.  */
 
                      ptr);
 
 
 
          /* Delete 2 bytes from irel->r_offset + 2.  */
 
          delcnt = 2;
 
          deloff = 2;
 
        }
 
 
 
      /* R_MICROMIPS_PC16_S1 relaxation to R_MICROMIPS_PC7_S1.  We need
 
         to check the distance from the next instruction, so subtract 2.  */
 
      else if (r_type == R_MICROMIPS_PC16_S1
 
               && IS_BITSIZE (pcrval - 2, 8)
 
               && (((fndopc = find_match (opcode, bz_rs_insns_32)) >= 0
 
                    && OP16_VALID_REG (OP32_SREG (opcode)))
 
                   || ((fndopc = find_match (opcode, bz_rt_insns_32)) >= 0
 
                       && OP16_VALID_REG (OP32_TREG (opcode)))))
 
        {
 
          unsigned long reg;
 
 
 
          reg = OP32_SREG (opcode) ? OP32_SREG (opcode) : OP32_TREG (opcode);
 
 
 
          /* Fix the relocation's type.  */
 
          irel->r_info = ELF32_R_INFO (r_symndx, R_MICROMIPS_PC7_S1);
 
 
 
          /* Replace the the 32-bit opcode with a 16-bit opcode.  */
 
          bfd_put_16 (abfd,
 
                      (bz_insns_16[fndopc].match
 
                       | BZ16_REG_FIELD (reg)
 
                       | (opcode & 0x7f)),              /* Addend value.  */
 
                      ptr);
 
 
 
          /* Delete 2 bytes from irel->r_offset + 2.  */
 
          delcnt = 2;
 
          deloff = 2;
 
        }
 
 
 
      /* R_MICROMIPS_26_S1 -- JAL to JALS relaxation for microMIPS targets.  */
 
      else if (r_type == R_MICROMIPS_26_S1
 
               && target_is_micromips_code_p
 
               && irel->r_offset + 7 < sec->size
 
               && MATCH (opcode, jal_insn_32_bd32))
 
        {
 
          unsigned long n32opc;
 
          bfd_boolean relaxed = FALSE;
 
 
 
          n32opc  = bfd_get_16 (abfd, ptr + 4) << 16;
 
          n32opc |= bfd_get_16 (abfd, ptr + 6);
 
 
 
          if (MATCH (n32opc, nop_insn_32))
 
            {
 
              /* Replace delay slot 32-bit NOP with a 16-bit NOP.  */
 
              bfd_put_16 (abfd, nop_insn_16.match, ptr + 4);
 
 
 
              relaxed = TRUE;
 
            }
 
          else if (find_match (n32opc, move_insns_32) >= 0)
 
            {
 
              /* Replace delay slot 32-bit MOVE with 16-bit MOVE.  */
 
              bfd_put_16 (abfd,
 
                          (move_insn_16.match
 
                           | MOVE16_RD_FIELD (MOVE32_RD (n32opc))
 
                           | MOVE16_RS_FIELD (MOVE32_RS (n32opc))),
 
                          ptr + 4);
 
 
 
              relaxed = TRUE;
 
            }
 
          /* Other 32-bit instructions relaxable to 16-bit
 
             instructions will be handled here later.  */
 
 
 
          if (relaxed)
 
            {
 
              /* JAL with 32-bit delay slot that is changed to a JALS
 
                 with 16-bit delay slot.  */
 
              bfd_put_16 (abfd, (jal_insn_32_bd16.match >> 16) & 0xffff,
 
                          ptr);
 
              bfd_put_16 (abfd,  jal_insn_32_bd16.match        & 0xffff,
 
                          ptr + 2);
 
 
 
              /* Delete 2 bytes from irel->r_offset + 6.  */
 
              delcnt = 2;
 
              deloff = 6;
 
            }
 
        }
 
 
 
      if (delcnt != 0)
 
        {
 
          /* Note that we've changed the relocs, section contents, etc.  */
 
          elf_section_data (sec)->relocs = internal_relocs;
 
          elf_section_data (sec)->this_hdr.contents = contents;
 
          symtab_hdr->contents = (unsigned char *) isymbuf;
 
 
 
          /* Delete bytes depending on the delcnt and deloff.  */
 
          if (!mips_elf_relax_delete_bytes (abfd, sec,
 
                                            irel->r_offset + deloff, delcnt))
 
            goto error_return;
 
 
 
          /* That will change things, so we should relax again.
 
             Note that this is not required, and it may be slow.  */
 
          *again = TRUE;
 
        }
 
    }
 
 
 
  if (isymbuf != NULL
 
      && symtab_hdr->contents != (unsigned char *) isymbuf)
 
    {
 
      if (! link_info->keep_memory)
 
        free (isymbuf);
 
      else
 
        {
 
          /* Cache the symbols for elf_link_input_bfd.  */
 
          symtab_hdr->contents = (unsigned char *) isymbuf;
 
        }
 
    }
 
 
 
  if (contents != NULL
 
      && elf_section_data (sec)->this_hdr.contents != contents)
 
    {
 
      if (! link_info->keep_memory)
 
        free (contents);
 
      else
 
        {
 
          /* Cache the section contents for elf_link_input_bfd.  */
 
          elf_section_data (sec)->this_hdr.contents = contents;
 
        }
 
    }
 
 
 
  if (internal_relocs != NULL
 
      && elf_section_data (sec)->relocs != internal_relocs)
 
    free (internal_relocs);
 
 
 
  return TRUE;
 
 
 
 error_return:
 
  if (isymbuf != NULL
 
      && symtab_hdr->contents != (unsigned char *) isymbuf)
 
    free (isymbuf);
 
  if (contents != NULL
 
      && elf_section_data (sec)->this_hdr.contents != contents)
 
    free (contents);
 
  if (internal_relocs != NULL
 
      && elf_section_data (sec)->relocs != internal_relocs)
 
    free (internal_relocs);
 
 
 
  return FALSE;
 
}
 

/* Create a MIPS ELF linker hash table.  */
/* Create a MIPS ELF linker hash table.  */
 
 
struct bfd_link_hash_table *
struct bfd_link_hash_table *
_bfd_mips_elf_link_hash_table_create (bfd *abfd)
_bfd_mips_elf_link_hash_table_create (bfd *abfd)
{
{
Line 12696... Line 13930...
        }
        }
      new_flags &= ~EF_MIPS_ABI;
      new_flags &= ~EF_MIPS_ABI;
      old_flags &= ~EF_MIPS_ABI;
      old_flags &= ~EF_MIPS_ABI;
    }
    }
 
 
  /* For now, allow arbitrary mixing of ASEs (retain the union).  */
  /* Compare ASEs.  Forbid linking MIPS16 and microMIPS ASE modules together
 
     and allow arbitrary mixing of the remaining ASEs (retain the union).  */
  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
  if ((new_flags & EF_MIPS_ARCH_ASE) != (old_flags & EF_MIPS_ARCH_ASE))
    {
    {
 
      int old_micro = old_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
 
      int new_micro = new_flags & EF_MIPS_ARCH_ASE_MICROMIPS;
 
      int old_m16 = old_flags & EF_MIPS_ARCH_ASE_M16;
 
      int new_m16 = new_flags & EF_MIPS_ARCH_ASE_M16;
 
      int micro_mis = old_m16 && new_micro;
 
      int m16_mis = old_micro && new_m16;
 
 
 
      if (m16_mis || micro_mis)
 
        {
 
          (*_bfd_error_handler)
 
            (_("%B: ASE mismatch: linking %s module with previous %s modules"),
 
             ibfd,
 
             m16_mis ? "MIPS16" : "microMIPS",
 
             m16_mis ? "microMIPS" : "MIPS16");
 
          ok = FALSE;
 
        }
 
 
      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
      elf_elfheader (obfd)->e_flags |= new_flags & EF_MIPS_ARCH_ASE;
 
 
      new_flags &= ~ EF_MIPS_ARCH_ASE;
      new_flags &= ~ EF_MIPS_ARCH_ASE;
      old_flags &= ~ EF_MIPS_ARCH_ASE;
      old_flags &= ~ EF_MIPS_ARCH_ASE;
    }
    }
Line 12893... Line 14145...
    fprintf (file, " [mdmx]");
    fprintf (file, " [mdmx]");
 
 
  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_M16)
    fprintf (file, " [mips16]");
    fprintf (file, " [mips16]");
 
 
 
  if (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH_ASE_MICROMIPS)
 
    fprintf (file, " [micromips]");
 
 
  if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
  if (elf_elfheader (abfd)->e_flags & EF_MIPS_32BITMODE)
    fprintf (file, " [32bitmode]");
    fprintf (file, " [32bitmode]");
  else
  else
    fprintf (file, _(" [not 32bitmode]"));
    fprintf (file, _(" [not 32bitmode]"));
 
 

powered by: WebSVN 2.1.0

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