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

Subversion Repositories open8_urisc

[/] [open8_urisc/] [trunk/] [gnu/] [binutils/] [bfd/] [elf64-ppc.c] - Diff between revs 161 and 163

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

Rev 161 Rev 163
Line 1280... Line 1280...
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                      /* src_mask */
         0,                      /* src_mask */
         0,                      /* dst_mask */
         0,                      /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
 
  HOWTO (R_PPC64_TOCSAVE,
 
         0,                      /* rightshift */
 
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
 
         32,                    /* bitsize */
 
         FALSE,                 /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_dont, /* complain_on_overflow */
 
         bfd_elf_generic_reloc, /* special_function */
 
         "R_PPC64_TOCSAVE",     /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0,                      /* dst_mask */
 
         FALSE),                /* pcrel_offset */
 
 
  /* Computes the load module index of the load module that contains the
  /* Computes the load module index of the load module that contains the
     definition of its TLS sym.  */
     definition of its TLS sym.  */
  HOWTO (R_PPC64_DTPMOD64,
  HOWTO (R_PPC64_DTPMOD64,
         0,                      /* rightshift */
         0,                      /* rightshift */
         4,                     /* size (0 = byte, 1 = short, 2 = long) */
         4,                     /* size (0 = byte, 1 = short, 2 = long) */
Line 2596... Line 2610...
  /* A copy of relocs before they are modified for --emit-relocs.  */
  /* A copy of relocs before they are modified for --emit-relocs.  */
  Elf_Internal_Rela *opd_relocs;
  Elf_Internal_Rela *opd_relocs;
 
 
  /* Nonzero if this bfd has small toc/got relocs, ie. that expect
  /* Nonzero if this bfd has small toc/got relocs, ie. that expect
     the reloc to be in the range -32768 to 32767.  */
     the reloc to be in the range -32768 to 32767.  */
  unsigned int has_small_toc_reloc;
  unsigned int has_small_toc_reloc : 1;
 
 
 
  /* Set if toc/got ha relocs detected not using r2, or lo reloc
 
     instruction not one we handle.  */
 
  unsigned int unexpected_toc_insn : 1;
};
};
 
 
#define ppc64_elf_tdata(bfd) \
#define ppc64_elf_tdata(bfd) \
  ((struct ppc64_elf_obj_tdata *) (bfd)->tdata.any)
  ((struct ppc64_elf_obj_tdata *) (bfd)->tdata.any)
 
 
Line 3672... Line 3690...
  struct bfd_hash_table stub_hash_table;
  struct bfd_hash_table stub_hash_table;
 
 
  /* Another hash table for plt_branch stubs.  */
  /* Another hash table for plt_branch stubs.  */
  struct bfd_hash_table branch_hash_table;
  struct bfd_hash_table branch_hash_table;
 
 
 
  /* Hash table for function prologue tocsave.  */
 
  htab_t tocsave_htab;
 
 
  /* Linker stub bfd.  */
  /* Linker stub bfd.  */
  bfd *stub_bfd;
  bfd *stub_bfd;
 
 
  /* Linker call-backs.  */
  /* Linker call-backs.  */
  asection * (*add_stub_section) (const char *, asection *);
  asection * (*add_stub_section) (const char *, asection *);
Line 3918... Line 3939...
    }
    }
 
 
  return entry;
  return entry;
}
}
 
 
 
struct tocsave_entry {
 
  asection *sec;
 
  bfd_vma offset;
 
};
 
 
 
static hashval_t
 
tocsave_htab_hash (const void *p)
 
{
 
  const struct tocsave_entry *e = (const struct tocsave_entry *) p;
 
  return ((bfd_vma)(intptr_t) e->sec ^ e->offset) >> 3;
 
}
 
 
 
static int
 
tocsave_htab_eq (const void *p1, const void *p2)
 
{
 
  const struct tocsave_entry *e1 = (const struct tocsave_entry *) p1;
 
  const struct tocsave_entry *e2 = (const struct tocsave_entry *) p2;
 
  return e1->sec == e2->sec && e1->offset == e2->offset;
 
}
 
 
/* Create a ppc64 ELF linker hash table.  */
/* Create a ppc64 ELF linker hash table.  */
 
 
static struct bfd_link_hash_table *
static struct bfd_link_hash_table *
ppc64_elf_link_hash_table_create (bfd *abfd)
ppc64_elf_link_hash_table_create (bfd *abfd)
{
{
Line 3948... Line 3989...
  /* And the branch hash table.  */
  /* And the branch hash table.  */
  if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc,
  if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc,
                            sizeof (struct ppc_branch_hash_entry)))
                            sizeof (struct ppc_branch_hash_entry)))
    return NULL;
    return NULL;
 
 
 
  htab->tocsave_htab = htab_try_create (1024,
 
                                        tocsave_htab_hash,
 
                                        tocsave_htab_eq,
 
                                        NULL);
 
  if (htab->tocsave_htab == NULL)
 
    return NULL;
 
 
  /* Initializing two fields of the union is just cosmetic.  We really
  /* Initializing two fields of the union is just cosmetic.  We really
     only care about glist, but when compiled on a 32-bit host the
     only care about glist, but when compiled on a 32-bit host the
     bfd_vma fields are larger.  Setting the bfd_vma to zero makes
     bfd_vma fields are larger.  Setting the bfd_vma to zero makes
     debugger inspection of these fields look nicer.  */
     debugger inspection of these fields look nicer.  */
  htab->elf.init_got_refcount.refcount = 0;
  htab->elf.init_got_refcount.refcount = 0;
Line 3969... Line 4017...
/* Free the derived linker hash table.  */
/* Free the derived linker hash table.  */
 
 
static void
static void
ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
ppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash)
{
{
  struct ppc_link_hash_table *ret = (struct ppc_link_hash_table *) hash;
  struct ppc_link_hash_table *htab = (struct ppc_link_hash_table *) hash;
 
 
  bfd_hash_table_free (&ret->stub_hash_table);
  bfd_hash_table_free (&htab->stub_hash_table);
  bfd_hash_table_free (&ret->branch_hash_table);
  bfd_hash_table_free (&htab->branch_hash_table);
 
  if (htab->tocsave_htab)
 
    htab_delete (htab->tocsave_htab);
  _bfd_generic_link_hash_table_free (hash);
  _bfd_generic_link_hash_table_free (hash);
}
}
 
 
/* Satisfy the ELF linker by filling in some fields in our fake bfd.  */
/* Satisfy the ELF linker by filling in some fields in our fake bfd.  */
 
 
Line 5666... Line 5716...
       || eh->elf.root.type == bfd_link_hash_defweak)
       || eh->elf.root.type == bfd_link_hash_defweak)
      && (eh->elf.ref_dynamic
      && (eh->elf.ref_dynamic
          || (!info->executable
          || (!info->executable
              && eh->elf.def_regular
              && eh->elf.def_regular
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN)))
              && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN
 
              && (strchr (eh->elf.root.root.string, ELF_VER_CHR) != NULL
 
                  || !bfd_hide_sym_by_version (info->version_info,
 
                                               eh->elf.root.root.string)))))
    {
    {
      asection *code_sec;
      asection *code_sec;
      struct ppc_link_hash_entry *fh;
      struct ppc_link_hash_entry *fh;
 
 
      eh->elf.root.u.def.section->flags |= SEC_KEEP;
      eh->elf.root.u.def.section->flags |= SEC_KEEP;
Line 6709... Line 6762...
      && (next_r == -1 || next_r == -2))
      && (next_r == -1 || next_r == -2))
    return 1 - next_r;
    return 1 - next_r;
  return 1;
  return 1;
}
}
 
 
 
/* Find (or create) an entry in the tocsave hash table.  */
 
 
 
static struct tocsave_entry *
 
tocsave_find (struct ppc_link_hash_table *htab,
 
              enum insert_option insert,
 
              Elf_Internal_Sym **local_syms,
 
              const Elf_Internal_Rela *irela,
 
              bfd *ibfd)
 
{
 
  unsigned long r_indx;
 
  struct elf_link_hash_entry *h;
 
  Elf_Internal_Sym *sym;
 
  struct tocsave_entry ent, *p;
 
  hashval_t hash;
 
  struct tocsave_entry **slot;
 
 
 
  r_indx = ELF64_R_SYM (irela->r_info);
 
  if (!get_sym_h (&h, &sym, &ent.sec, NULL, local_syms, r_indx, ibfd))
 
    return NULL;
 
  if (ent.sec == NULL || ent.sec->output_section == NULL)
 
    {
 
      (*_bfd_error_handler)
 
        (_("%B: undefined symbol on R_PPC64_TOCSAVE relocation"));
 
      return NULL;
 
    }
 
 
 
  if (h != NULL)
 
    ent.offset = h->root.u.def.value;
 
  else
 
    ent.offset = sym->st_value;
 
  ent.offset += irela->r_addend;
 
 
 
  hash = tocsave_htab_hash (&ent);
 
  slot = ((struct tocsave_entry **)
 
          htab_find_slot_with_hash (htab->tocsave_htab, &ent, hash, insert));
 
  if (slot == NULL)
 
    return NULL;
 
 
 
  if (*slot == NULL)
 
    {
 
      p = (struct tocsave_entry *) bfd_alloc (ibfd, sizeof (*p));
 
      if (p == NULL)
 
        return NULL;
 
      *p = ent;
 
      *slot = p;
 
    }
 
  return *slot;
 
}
 
 
/* Adjust all global syms defined in opd sections.  In gcc generated
/* Adjust all global syms defined in opd sections.  In gcc generated
   code for the old ABI, these will already have been done.  */
   code for the old ABI, these will already have been done.  */
 
 
static bfd_boolean
static bfd_boolean
adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
adjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED)
Line 7879... Line 7981...
{
{
  struct ppc_link_hash_entry *eh;
  struct ppc_link_hash_entry *eh;
  struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
  struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf;
  unsigned long i;
  unsigned long i;
 
 
  if (h->root.type == bfd_link_hash_indirect)
 
    return TRUE;
 
 
 
  if (h->root.type != bfd_link_hash_defined
  if (h->root.type != bfd_link_hash_defined
      && h->root.type != bfd_link_hash_defweak)
      && h->root.type != bfd_link_hash_defweak)
    return TRUE;
    return TRUE;
 
 
  eh = (struct ppc_link_hash_entry *) h;
  eh = (struct ppc_link_hash_entry *) h;
Line 7916... Line 8015...
    toc_inf->global_toc_syms = TRUE;
    toc_inf->global_toc_syms = TRUE;
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Return TRUE iff INSN is one we expect on a _LO variety toc/got reloc.  */
 
 
 
static bfd_boolean
 
ok_lo_toc_insn (unsigned int insn)
 
{
 
  return ((insn & (0x3f << 26)) == 14u << 26 /* addi */
 
          || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
 
          || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
 
          || (insn & (0x3f << 26)) == 36u << 26 /* stw */
 
          || (insn & (0x3f << 26)) == 38u << 26 /* stb */
 
          || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
 
          || (insn & (0x3f << 26)) == 42u << 26 /* lha */
 
          || (insn & (0x3f << 26)) == 44u << 26 /* sth */
 
          || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
 
          || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
 
          || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
 
          || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
 
          || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
 
          || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
 
          || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
 
              && (insn & 3) != 1)
 
          || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
 
              && ((insn & 3) == 0 || (insn & 3) == 3))
 
          || (insn & (0x3f << 26)) == 12u << 26 /* addic */);
 
}
 
 
/* Examine all relocs referencing .toc sections in order to remove
/* Examine all relocs referencing .toc sections in order to remove
   unused .toc entries.  */
   unused .toc entries.  */
 
 
bfd_boolean
bfd_boolean
ppc64_elf_edit_toc (struct bfd_link_info *info)
ppc64_elf_edit_toc (struct bfd_link_info *info)
Line 8170... Line 8295...
                unsigned long r_symndx;
                unsigned long r_symndx;
                asection *sym_sec;
                asection *sym_sec;
                struct elf_link_hash_entry *h;
                struct elf_link_hash_entry *h;
                Elf_Internal_Sym *sym;
                Elf_Internal_Sym *sym;
                bfd_vma val;
                bfd_vma val;
 
                enum {no_check, check_lo, check_ha} insn_check;
 
 
                r_type = ELF64_R_TYPE (rel->r_info);
                r_type = ELF64_R_TYPE (rel->r_info);
                switch (r_type)
                switch (r_type)
                  {
                  {
 
                  default:
 
                    insn_check = no_check;
 
                    break;
 
 
 
                  case R_PPC64_GOT_TLSLD16_HA:
 
                  case R_PPC64_GOT_TLSGD16_HA:
 
                  case R_PPC64_GOT_TPREL16_HA:
 
                  case R_PPC64_GOT_DTPREL16_HA:
 
                  case R_PPC64_GOT16_HA:
 
                  case R_PPC64_TOC16_HA:
 
                    insn_check = check_ha;
 
                    break;
 
 
 
                  case R_PPC64_GOT_TLSLD16_LO:
 
                  case R_PPC64_GOT_TLSGD16_LO:
 
                  case R_PPC64_GOT_TPREL16_LO_DS:
 
                  case R_PPC64_GOT_DTPREL16_LO_DS:
 
                  case R_PPC64_GOT16_LO:
 
                  case R_PPC64_GOT16_LO_DS:
 
                  case R_PPC64_TOC16_LO:
 
                  case R_PPC64_TOC16_LO_DS:
 
                    insn_check = check_lo;
 
                    break;
 
                  }
 
 
 
                if (insn_check != no_check)
 
                  {
 
                    bfd_vma off = rel->r_offset & ~3;
 
                    unsigned char buf[4];
 
                    unsigned int insn;
 
 
 
                    if (!bfd_get_section_contents (ibfd, sec, buf, off, 4))
 
                      {
 
                        free (used);
 
                        goto error_ret;
 
                      }
 
                    insn = bfd_get_32 (ibfd, buf);
 
                    if (insn_check == check_lo
 
                        ? !ok_lo_toc_insn (insn)
 
                        : ((insn & ((0x3f << 26) | 0x1f << 16))
 
                           != ((15u << 26) | (2 << 16)) /* addis rt,2,imm */))
 
                      {
 
                        char str[12];
 
 
 
                        ppc64_elf_tdata (ibfd)->unexpected_toc_insn = 1;
 
                        sprintf (str, "%#08x", insn);
 
                        info->callbacks->einfo
 
                          (_("%P: %H: toc optimization is not supported for"
 
                             " %s instruction.\n"),
 
                           ibfd, sec, rel->r_offset & ~3, str);
 
                      }
 
                  }
 
 
 
                switch (r_type)
 
                  {
                  case R_PPC64_TOC16:
                  case R_PPC64_TOC16:
                  case R_PPC64_TOC16_LO:
                  case R_PPC64_TOC16_LO:
                  case R_PPC64_TOC16_HI:
                  case R_PPC64_TOC16_HI:
                  case R_PPC64_TOC16_HA:
                  case R_PPC64_TOC16_HA:
                  case R_PPC64_TOC16_DS:
                  case R_PPC64_TOC16_DS:
Line 8221... Line 8402...
                        break;
                        break;
 
 
                      case R_PPC64_TOC16_LO_DS:
                      case R_PPC64_TOC16_LO_DS:
                        off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
                        off = rel->r_offset + (bfd_big_endian (ibfd) ? -2 : 3);
                        if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
                        if (!bfd_get_section_contents (ibfd, sec, &opc, off, 1))
                          return FALSE;
                          {
 
                            free (used);
 
                            goto error_ret;
 
                          }
                        if ((opc & (0x3f << 2)) == (58u << 2))
                        if ((opc & (0x3f << 2)) == (58u << 2))
                          break;
                          break;
                        /* Fall thru */
                        /* Fall thru */
 
 
                      default:
                      default:
Line 8265... Line 8449...
              *drop &= ~ref_from_discarded;
              *drop &= ~ref_from_discarded;
              if ((*drop & can_optimize) != 0)
              if ((*drop & can_optimize) != 0)
                some_unused = 1;
                some_unused = 1;
              last = 0;
              last = 0;
            }
            }
          else if (*drop & ref_from_discarded)
          else if ((*drop & ref_from_discarded) != 0)
            {
            {
              some_unused = 1;
              some_unused = 1;
              last = ref_from_discarded;
              last = ref_from_discarded;
            }
            }
          else
          else
Line 8383... Line 8567...
                        case R_PPC64_TOC16_LO_DS:
                        case R_PPC64_TOC16_LO_DS:
                          rel->r_info = ELF64_R_INFO (tsym, R_PPC64_LO_DS_OPT);
                          rel->r_info = ELF64_R_INFO (tsym, R_PPC64_LO_DS_OPT);
                          break;
                          break;
 
 
                        default:
                        default:
                          abort ();
                          if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
 
                            ppc_howto_init ();
 
                          info->callbacks->einfo
 
                            (_("%P: %H: %s relocation references "
 
                               "optimized away TOC entry\n"),
 
                             ibfd, sec, rel->r_offset,
 
                             ppc64_elf_howto_table[r_type]->name);
 
                          bfd_set_error (bfd_error_bad_value);
 
                          goto error_ret;
                        }
                        }
                      rel->r_addend = tocrel->r_addend;
                      rel->r_addend = tocrel->r_addend;
                      elf_section_data (sec)->relocs = relstart;
                      elf_section_data (sec)->relocs = relstart;
                      continue;
                      continue;
                    }
                    }
Line 9285... Line 9477...
 
 
  if (PPC_HA (offset) != 0)
  if (PPC_HA (offset) != 0)
    {
    {
      if (r != NULL)
      if (r != NULL)
        {
        {
 
          r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
          r[1].r_offset = r[0].r_offset + 8;
          r[1].r_offset = r[0].r_offset + 4;
          r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
          r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
          r[1].r_addend = r[0].r_addend;
          r[1].r_addend = r[0].r_addend;
          if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
          if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
            {
            {
              r[2].r_offset = r[1].r_offset + 4;
              r[2].r_offset = r[1].r_offset + 4;
Line 9308... Line 9501...
                  r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
                  r[3].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
                  r[3].r_addend = r[0].r_addend + 16;
                  r[3].r_addend = r[0].r_addend + 16;
                }
                }
            }
            }
        }
        }
      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),     p += 4;
 
      bfd_put_32 (obfd, STD_R2_40R1, p),                        p += 4;
      bfd_put_32 (obfd, STD_R2_40R1, p),                        p += 4;
 
      bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p),     p += 4;
      bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p),      p += 4;
      bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p),      p += 4;
      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
      if (PPC_HA (offset + 8 + 8 * plt_static_chain) != PPC_HA (offset))
        {
        {
          bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p), p += 4;
          bfd_put_32 (obfd, ADDI_R12_R12 | PPC_LO (offset), p), p += 4;
          offset = 0;
          offset = 0;
Line 11138... Line 11331...
                        goto error_ret_free_internal;
                        goto error_ret_free_internal;
                      if (*tls_mask != 0)
                      if (*tls_mask != 0)
                        continue;
                        continue;
                    }
                    }
 
 
 
                  if (stub_type == ppc_stub_plt_call
 
                      && irela + 1 < irelaend
 
                      && irela[1].r_offset == irela->r_offset + 4
 
                      && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE
 
                      && !tocsave_find (htab, INSERT,
 
                                        &local_syms, irela + 1, input_bfd))
 
                    goto error_ret_free_internal;
 
 
                  /* Support for grouping stub sections.  */
                  /* Support for grouping stub sections.  */
                  id_sec = htab->stub_group[section->id].link_sec;
                  id_sec = htab->stub_group[section->id].link_sec;
 
 
                  /* Get the name of this stub.  */
                  /* Get the name of this stub.  */
                  stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela);
                  stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela);
Line 11666... Line 11867...
    return 0;
    return 0;
 
 
  return _bfd_elf_default_action_discarded (sec);
  return _bfd_elf_default_action_discarded (sec);
}
}
 
 
/* REL points to a low-part reloc on a largetoc instruction sequence.
 
   Find the matching high-part reloc instruction and verify that it
 
   is addis REG,x,imm.  If so, set *REG to x and return a pointer to
 
   the high-part reloc.  */
 
 
 
static const Elf_Internal_Rela *
 
ha_reloc_match (const Elf_Internal_Rela *relocs,
 
                const Elf_Internal_Rela *rel,
 
                unsigned int *reg,
 
                bfd_boolean match_addend,
 
                const bfd *input_bfd,
 
                const bfd_byte *contents)
 
{
 
  enum elf_ppc64_reloc_type r_type, r_type_ha;
 
  bfd_vma r_info_ha, r_addend;
 
 
 
  r_type = ELF64_R_TYPE (rel->r_info);
 
  switch (r_type)
 
    {
 
    case R_PPC64_GOT_TLSLD16_LO:
 
    case R_PPC64_GOT_TLSGD16_LO:
 
    case R_PPC64_GOT_TPREL16_LO_DS:
 
    case R_PPC64_GOT_DTPREL16_LO_DS:
 
    case R_PPC64_GOT16_LO:
 
    case R_PPC64_TOC16_LO:
 
      r_type_ha = r_type + 2;
 
      break;
 
    case R_PPC64_GOT16_LO_DS:
 
      r_type_ha = R_PPC64_GOT16_HA;
 
      break;
 
    case R_PPC64_TOC16_LO_DS:
 
      r_type_ha = R_PPC64_TOC16_HA;
 
      break;
 
    default:
 
      abort ();
 
    }
 
  r_info_ha = ELF64_R_INFO (ELF64_R_SYM (rel->r_info), r_type_ha);
 
  r_addend = rel->r_addend;
 
 
 
  while (--rel >= relocs)
 
    if (rel->r_info == r_info_ha
 
        && (!match_addend
 
            || rel->r_addend == r_addend))
 
      {
 
        const bfd_byte *p = contents + (rel->r_offset & ~3);
 
        unsigned int insn = bfd_get_32 (input_bfd, p);
 
        if ((insn & (0x3f << 26)) == (15u << 26) /* addis rt,x,imm */
 
            && (insn & (0x1f << 21)) == (*reg << 21))
 
          {
 
            *reg = (insn >> 16) & 0x1f;
 
            return rel;
 
          }
 
        break;
 
      }
 
  return NULL;
 
}
 
 
 
/* The RELOCATE_SECTION function is called by the ELF backend linker
/* The RELOCATE_SECTION function is called by the ELF backend linker
   to handle the relocations for a section.
   to handle the relocations for a section.
 
 
   The relocs are always passed as Rela structures; if the section
   The relocs are always passed as Rela structures; if the section
   actually uses Rel structures, the r_addend field will always be
   actually uses Rel structures, the r_addend field will always be
Line 11770... Line 11914...
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *relend;
  Elf_Internal_Rela *relend;
  Elf_Internal_Rela outrel;
  Elf_Internal_Rela outrel;
  bfd_byte *loc;
  bfd_byte *loc;
  struct got_entry **local_got_ents;
  struct got_entry **local_got_ents;
  unsigned char *ha_opt;
 
  bfd_vma TOCstart;
  bfd_vma TOCstart;
  bfd_boolean no_ha_opt;
 
  bfd_boolean ret = TRUE;
  bfd_boolean ret = TRUE;
  bfd_boolean is_opd;
  bfd_boolean is_opd;
  /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
  /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
  bfd_boolean is_power4 = FALSE;
  bfd_boolean is_power4 = FALSE;
  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
Line 11798... Line 11940...
  local_got_ents = elf_local_got_ents (input_bfd);
  local_got_ents = elf_local_got_ents (input_bfd);
  TOCstart = elf_gp (output_bfd);
  TOCstart = elf_gp (output_bfd);
  symtab_hdr = &elf_symtab_hdr (input_bfd);
  symtab_hdr = &elf_symtab_hdr (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
  is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
  is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd;
  ha_opt = NULL;
 
  no_ha_opt = FALSE;
 
 
 
  rel = relocs;
  rel = relocs;
  relend = relocs + input_section->reloc_count;
  relend = relocs + input_section->reloc_count;
  for (; rel < relend; rel++)
  for (; rel < relend; rel++)
    {
    {
Line 12363... Line 12503...
      switch (r_type)
      switch (r_type)
        {
        {
        default:
        default:
          break;
          break;
 
 
 
        case R_PPC64_TOCSAVE:
 
          if (relocation + addend == (rel->r_offset
 
                                      + input_section->output_offset
 
                                      + input_section->output_section->vma)
 
              && tocsave_find (htab, NO_INSERT,
 
                               &local_syms, rel, input_bfd))
 
            {
 
              insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
 
              if (insn == NOP
 
                  || insn == CROR_151515 || insn == CROR_313131)
 
                bfd_put_32 (input_bfd, STD_R2_40R1,
 
                            contents + rel->r_offset);
 
            }
 
          break;
 
 
          /* Branch taken prediction relocations.  */
          /* Branch taken prediction relocations.  */
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_ADDR14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
          insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
          insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field.  */
          /* Fall thru.  */
          /* Fall thru.  */
Line 12515... Line 12670...
                 rather than the procedure directly.  */
                 rather than the procedure directly.  */
              relocation = (stub_entry->stub_offset
              relocation = (stub_entry->stub_offset
                            + stub_entry->stub_sec->output_offset
                            + stub_entry->stub_sec->output_offset
                            + stub_entry->stub_sec->output_section->vma);
                            + stub_entry->stub_sec->output_section->vma);
              addend = 0;
              addend = 0;
 
 
 
              if (stub_entry->stub_type == ppc_stub_plt_call
 
                  && rel + 1 < relend
 
                  && rel[1].r_offset == rel->r_offset + 4
 
                  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
 
                relocation += 4;
            }
            }
 
 
          if (insn != 0)
          if (insn != 0)
            {
            {
              if (is_power4)
              if (is_power4)
Line 12574... Line 12735...
 
 
        case R_PPC64_NONE:
        case R_PPC64_NONE:
        case R_PPC64_TLS:
        case R_PPC64_TLS:
        case R_PPC64_TLSGD:
        case R_PPC64_TLSGD:
        case R_PPC64_TLSLD:
        case R_PPC64_TLSLD:
 
        case R_PPC64_TOCSAVE:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTENTRY:
        case R_PPC64_GNU_VTENTRY:
          continue;
          continue;
 
 
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
          /* GOT16 relocations.  Like an ADDR16 using the symbol's
Line 13211... Line 13373...
        case R_PPC64_GOT_TLSGD16_HA:
        case R_PPC64_GOT_TLSGD16_HA:
        case R_PPC64_GOT_TPREL16_HA:
        case R_PPC64_GOT_TPREL16_HA:
        case R_PPC64_GOT_DTPREL16_HA:
        case R_PPC64_GOT_DTPREL16_HA:
        case R_PPC64_GOT16_HA:
        case R_PPC64_GOT16_HA:
        case R_PPC64_TOC16_HA:
        case R_PPC64_TOC16_HA:
          /* nop is done later.  */
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
 
              && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
 
            {
 
              bfd_byte *p = contents + (rel->r_offset & ~3);
 
              bfd_put_32 (input_bfd, NOP, p);
 
            }
          break;
          break;
 
 
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSGD16_LO:
        case R_PPC64_GOT_TLSGD16_LO:
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_DTPREL16_LO_DS:
        case R_PPC64_GOT_DTPREL16_LO_DS:
        case R_PPC64_GOT16_LO:
        case R_PPC64_GOT16_LO:
        case R_PPC64_GOT16_LO_DS:
        case R_PPC64_GOT16_LO_DS:
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_LO:
        case R_PPC64_TOC16_LO_DS:
        case R_PPC64_TOC16_LO_DS:
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000)
          if (htab->do_toc_opt && relocation + addend + 0x8000 < 0x10000
 
              && !ppc64_elf_tdata (input_bfd)->unexpected_toc_insn)
            {
            {
              bfd_byte *p = contents + (rel->r_offset & ~3);
              bfd_byte *p = contents + (rel->r_offset & ~3);
              insn = bfd_get_32 (input_bfd, p);
              insn = bfd_get_32 (input_bfd, p);
              if ((insn & (0x3f << 26)) == 14u << 26 /* addi */
              if ((insn & (0x3f << 26)) == 12u << 26 /* addic */)
                  || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
 
                  || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
 
                  || (insn & (0x3f << 26)) == 36u << 26 /* stw */
 
                  || (insn & (0x3f << 26)) == 38u << 26 /* stb */
 
                  || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
 
                  || (insn & (0x3f << 26)) == 42u << 26 /* lha */
 
                  || (insn & (0x3f << 26)) == 44u << 26 /* sth */
 
                  || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
 
                  || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
 
                  || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
 
                  || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
 
                  || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
 
                  || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
 
                  || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
 
                      && (insn & 3) != 1)
 
                  || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
 
                      && ((insn & 3) == 0 || (insn & 3) == 3)))
 
                {
 
                  unsigned int reg = (insn >> 16) & 0x1f;
 
                  const Elf_Internal_Rela *ha;
 
                  bfd_boolean match_addend;
 
 
 
                  match_addend = (sym != NULL
 
                                  && ELF_ST_TYPE (sym->st_info) == STT_SECTION);
 
                  ha = ha_reloc_match (relocs, rel, &reg, match_addend,
 
                                       input_bfd, contents);
 
                  if (ha != NULL)
 
                    {
                    {
                      insn &= ~(0x1f << 16);
                  /* Transform addic to addi when we change reg.  */
                      insn |= reg << 16;
                  insn &= ~((0x3f << 26) | (0x1f << 16));
                      bfd_put_32 (input_bfd, insn, p);
                  insn |= (14u << 26) | (2 << 16);
                      if (ha_opt == NULL)
 
                        {
 
                          ha_opt = bfd_zmalloc (input_section->reloc_count);
 
                          if (ha_opt == NULL)
 
                            return FALSE;
 
                        }
 
                      ha_opt[ha - relocs] = 1;
 
                    }
                    }
                  else
                  else
                    /* If we don't find a matching high part insn,
                {
                       something is fishy.  Refuse to nop any high
                  insn &= ~(0x1f << 16);
                       part insn in this section.  */
                  insn |= 2 << 16;
                    no_ha_opt = TRUE;
 
                }
                }
 
              bfd_put_32 (input_bfd, insn, p);
            }
            }
          break;
          break;
        }
        }
 
 
      /* Do any further special processing.  */
      /* Do any further special processing.  */
Line 13366... Line 13500...
      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
         because such sections are not SEC_ALLOC and thus ld.so will
         because such sections are not SEC_ALLOC and thus ld.so will
         not process them.  */
         not process them.  */
      if (unresolved_reloc
      if (unresolved_reloc
          && !((input_section->flags & SEC_DEBUGGING) != 0
          && !((input_section->flags & SEC_DEBUGGING) != 0
               && h->elf.def_dynamic))
               && h->elf.def_dynamic)
 
          && _bfd_elf_section_offset (output_bfd, info, input_section,
 
                                      rel->r_offset) != (bfd_vma) -1)
        {
        {
          info->callbacks->einfo
          info->callbacks->einfo
            (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
            (_("%P: %H: unresolvable %s relocation against symbol `%s'\n"),
             input_bfd, input_section, rel->r_offset,
             input_bfd, input_section, rel->r_offset,
             ppc64_elf_howto_table[(int) r_type]->name,
             ppc64_elf_howto_table[(int) r_type]->name,
Line 13424... Line 13560...
              ret = FALSE;
              ret = FALSE;
            }
            }
        }
        }
    }
    }
 
 
  if (ha_opt != NULL)
 
    {
 
      if (!no_ha_opt)
 
        {
 
          unsigned char *opt = ha_opt;
 
          rel = relocs;
 
          relend = relocs + input_section->reloc_count;
 
          for (; rel < relend; opt++, rel++)
 
            if (*opt != 0)
 
              {
 
                bfd_byte *p = contents + (rel->r_offset & ~3);
 
                bfd_put_32 (input_bfd, NOP, p);
 
              }
 
        }
 
      free (ha_opt);
 
    }
 
 
 
  /* If we're emitting relocations, then shortly after this function
  /* If we're emitting relocations, then shortly after this function
     returns, reloc offsets and addends for this section will be
     returns, reloc offsets and addends for this section will be
     adjusted.  Worse, reloc symbol indices will be for the output
     adjusted.  Worse, reloc symbol indices will be for the output
     file rather than the input.  Save a copy of the relocs for
     file rather than the input.  Save a copy of the relocs for
     opd_entry_value.  */
     opd_entry_value.  */

powered by: WebSVN 2.1.0

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