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 163 and 166

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

Rev 163 Rev 166
Line 1... Line 1...
/* PowerPC64-specific support for 64-bit ELF.
/* PowerPC64-specific support for 64-bit ELF.
   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
   2009, 2010, 2011 Free Software Foundation, Inc.
   2009, 2010, 2011, 2012 Free Software Foundation, Inc.
   Written by Linus Nordberg, Swox AB <info@swox.com>,
   Written by Linus Nordberg, Swox AB <info@swox.com>,
   based on elf32-ppc.c by Ian Lance Taylor.
   based on elf32-ppc.c by Ian Lance Taylor.
   Largely rewritten by Alan Modra.
   Largely rewritten by Alan Modra.
 
 
   This file is part of BFD, the Binary File Descriptor library.
   This file is part of BFD, the Binary File Descriptor library.
Line 103... Line 103...
#define elf_backend_gc_mark_dynamic_ref       ppc64_elf_gc_mark_dynamic_ref
#define elf_backend_gc_mark_dynamic_ref       ppc64_elf_gc_mark_dynamic_ref
#define elf_backend_gc_mark_hook              ppc64_elf_gc_mark_hook
#define elf_backend_gc_mark_hook              ppc64_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook             ppc64_elf_gc_sweep_hook
#define elf_backend_gc_sweep_hook             ppc64_elf_gc_sweep_hook
#define elf_backend_adjust_dynamic_symbol     ppc64_elf_adjust_dynamic_symbol
#define elf_backend_adjust_dynamic_symbol     ppc64_elf_adjust_dynamic_symbol
#define elf_backend_hide_symbol               ppc64_elf_hide_symbol
#define elf_backend_hide_symbol               ppc64_elf_hide_symbol
 
#define elf_backend_maybe_function_sym        ppc64_elf_maybe_function_sym
#define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
#define elf_backend_always_size_sections      ppc64_elf_func_desc_adjust
#define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
#define elf_backend_size_dynamic_sections     ppc64_elf_size_dynamic_sections
#define elf_backend_init_index_section        _bfd_elf_init_2_index_sections
#define elf_backend_init_index_section        _bfd_elf_init_2_index_sections
#define elf_backend_action_discarded          ppc64_elf_action_discarded
#define elf_backend_action_discarded          ppc64_elf_action_discarded
#define elf_backend_relocate_section          ppc64_elf_relocate_section
#define elf_backend_relocate_section          ppc64_elf_relocate_section
Line 150... Line 151...
#define ADDIS_R12_R12   0x3d8c0000      /* addis %r12,%r12,off@ha  */
#define ADDIS_R12_R12   0x3d8c0000      /* addis %r12,%r12,off@ha  */
#define ADDI_R12_R12    0x398c0000      /* addi %r12,%r12,off@l  */
#define ADDI_R12_R12    0x398c0000      /* addi %r12,%r12,off@l  */
#define ADDIS_R2_R2     0x3c420000      /* addis %r2,%r2,off@ha  */
#define ADDIS_R2_R2     0x3c420000      /* addis %r2,%r2,off@ha  */
#define ADDI_R2_R2      0x38420000      /* addi  %r2,%r2,off@l   */
#define ADDI_R2_R2      0x38420000      /* addi  %r2,%r2,off@l   */
 
 
 
#define XOR_R11_R11_R11 0x7d6b5a78      /* xor   %r11,%r11,%r11  */
 
#define ADD_R12_R12_R11 0x7d8c5a14      /* add   %r12,%r12,%r11  */
 
#define ADD_R2_R2_R11   0x7c425a14      /* add   %r2,%r2,%r11    */
 
#define CMPLDI_R2_0     0x28220000      /* cmpldi %r2,0          */
 
#define BNECTR          0x4ca20420      /* bnectr+               */
 
#define BNECTR_P4       0x4ce20420      /* bnectr+               */
 
 
#define LD_R11_0R2      0xe9620000      /* ld    %r11,xxx+0(%r2) */
#define LD_R11_0R2      0xe9620000      /* ld    %r11,xxx+0(%r2) */
#define LD_R2_0R2       0xe8420000      /* ld    %r2,xxx+0(%r2)  */
#define LD_R2_0R2       0xe8420000      /* ld    %r2,xxx+0(%r2)  */
 
 
#define LD_R2_40R1      0xe8410028      /* ld    %r2,40(%r1)     */
#define LD_R2_40R1      0xe8410028      /* ld    %r2,40(%r1)     */
 
 
Line 2354... Line 2362...
                         bfd *output_bfd, char **error_message)
                         bfd *output_bfd, char **error_message)
{
{
  long insn;
  long insn;
  enum elf_ppc64_reloc_type r_type;
  enum elf_ppc64_reloc_type r_type;
  bfd_size_type octets;
  bfd_size_type octets;
  /* Disabled until we sort out how ld should choose 'y' vs 'at'.  */
  /* Assume 'at' branch hints.  */
  bfd_boolean is_power4 = FALSE;
  bfd_boolean is_isa_v2 = TRUE;
 
 
  /* If this is a relocatable link (output_bfd test tells us), just
  /* If this is a relocatable link (output_bfd test tells us), just
     call the generic function.  Any adjustment will be done at final
     call the generic function.  Any adjustment will be done at final
     link time.  */
     link time.  */
  if (output_bfd != NULL)
  if (output_bfd != NULL)
Line 2372... Line 2380...
  r_type = reloc_entry->howto->type;
  r_type = reloc_entry->howto->type;
  if (r_type == R_PPC64_ADDR14_BRTAKEN
  if (r_type == R_PPC64_ADDR14_BRTAKEN
      || r_type == R_PPC64_REL14_BRTAKEN)
      || r_type == 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.  */
 
 
  if (is_power4)
  if (is_isa_v2)
    {
    {
      /* Set 'a' bit.  This is 0b00010 in BO field for branch
      /* Set 'a' bit.  This is 0b00010 in BO field for branch
         on CR(BI) insns (BO == 001at or 011at), and 0b01000
         on CR(BI) insns (BO == 001at or 011at), and 0b01000
         for branch on CTR insns (BO == 1a00t or 1a01t).  */
         for branch on CTR insns (BO == 1a00t or 1a01t).  */
      if ((insn & (0x14 << 21)) == (0x04 << 21))
      if ((insn & (0x14 << 21)) == (0x04 << 21))
Line 2712... Line 2720...
      {
      {
        char data[136];
        char data[136];
        va_list ap;
        va_list ap;
 
 
        va_start (ap, note_type);
        va_start (ap, note_type);
        memset (data, 0, 40);
        memset (data, 0, sizeof (data));
        strncpy (data + 40, va_arg (ap, const char *), 16);
        strncpy (data + 40, va_arg (ap, const char *), 16);
        strncpy (data + 56, va_arg (ap, const char *), 80);
        strncpy (data + 56, va_arg (ap, const char *), 80);
        va_end (ap);
        va_end (ap);
        return elfcore_write_note (abfd, buf, bufsiz,
        return elfcore_write_note (abfd, buf, bufsiz,
                                   "CORE", note_type, data, sizeof (data));
                                   "CORE", note_type, data, sizeof (data));
Line 3582... Line 3590...
  ppc_stub_none,
  ppc_stub_none,
  ppc_stub_long_branch,
  ppc_stub_long_branch,
  ppc_stub_long_branch_r2off,
  ppc_stub_long_branch_r2off,
  ppc_stub_plt_branch,
  ppc_stub_plt_branch,
  ppc_stub_plt_branch_r2off,
  ppc_stub_plt_branch_r2off,
  ppc_stub_plt_call
  ppc_stub_plt_call,
 
  ppc_stub_plt_call_r2save
};
};
 
 
struct ppc_stub_hash_entry {
struct ppc_stub_hash_entry {
 
 
  /* Base hash table entry structure.  */
  /* Base hash table entry structure.  */
Line 3750... Line 3759...
 
 
  /* The size of reliplt used by got entry relocs.  */
  /* The size of reliplt used by got entry relocs.  */
  bfd_size_type got_reli_size;
  bfd_size_type got_reli_size;
 
 
  /* Statistics.  */
  /* Statistics.  */
  unsigned long stub_count[ppc_stub_plt_call];
  unsigned long stub_count[ppc_stub_plt_call_r2save];
 
 
  /* Number of stubs against global syms.  */
  /* Number of stubs against global syms.  */
  unsigned long stub_globals;
  unsigned long stub_globals;
 
 
 
  /* Alignment of PLT call stubs.  */
 
  unsigned int plt_stub_align:4;
 
 
  /* Set if PLT call stubs should load r11.  */
  /* Set if PLT call stubs should load r11.  */
  unsigned int plt_static_chain:1;
  unsigned int plt_static_chain:1;
 
 
 
  /* Set if PLT call stubs need a read-read barrier.  */
 
  unsigned int plt_thread_safe:1;
 
 
  /* Set if we should emit symbols for stubs.  */
  /* Set if we should emit symbols for stubs.  */
  unsigned int emit_stub_syms:1;
  unsigned int emit_stub_syms:1;
 
 
  /* Set if __tls_get_addr optimization should not be done.  */
  /* Set if __tls_get_addr optimization should not be done.  */
  unsigned int no_tls_get_addr_opt:1;
  unsigned int no_tls_get_addr_opt:1;
Line 4433... Line 4448...
  edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
  edir->elf.ref_dynamic |= eind->elf.ref_dynamic;
  edir->elf.ref_regular |= eind->elf.ref_regular;
  edir->elf.ref_regular |= eind->elf.ref_regular;
  edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
  edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak;
  edir->elf.needs_plt |= eind->elf.needs_plt;
  edir->elf.needs_plt |= eind->elf.needs_plt;
 
 
  /* If we were called to copy over info for a weak sym, that's all.  */
 
  if (eind->elf.root.type != bfd_link_hash_indirect)
 
    return;
 
 
 
  /* Copy over any dynamic relocs we may have on the indirect sym.  */
  /* Copy over any dynamic relocs we may have on the indirect sym.  */
  if (eind->dyn_relocs != NULL)
  if (eind->dyn_relocs != NULL)
    {
    {
      if (edir->dyn_relocs != NULL)
      if (edir->dyn_relocs != NULL)
        {
        {
Line 4469... Line 4480...
 
 
      edir->dyn_relocs = eind->dyn_relocs;
      edir->dyn_relocs = eind->dyn_relocs;
      eind->dyn_relocs = NULL;
      eind->dyn_relocs = NULL;
    }
    }
 
 
 
  /* If we were called to copy over info for a weak sym, that's all.
 
     You might think dyn_relocs need not be copied over;  After all,
 
     both syms will be dynamic or both non-dynamic so we're just
 
     moving reloc accounting around.  However, ELIMINATE_COPY_RELOCS
 
     code in ppc64_elf_adjust_dynamic_symbol needs to check for
 
     dyn_relocs in read-only sections, and it does so on what is the
 
     DIR sym here.  */
 
  if (eind->elf.root.type != bfd_link_hash_indirect)
 
    return;
 
 
  /* Copy over got entries that we may have already seen to the
  /* Copy over got entries that we may have already seen to the
     symbol which just became indirect.  */
     symbol which just became indirect.  */
  if (eind->elf.got.glist != NULL)
  if (eind->elf.got.glist != NULL)
    {
    {
      if (edir->elf.got.glist != NULL)
      if (edir->elf.got.glist != NULL)
Line 5506... Line 5527...
  bfd *opd_bfd = opd_sec->owner;
  bfd *opd_bfd = opd_sec->owner;
  Elf_Internal_Rela *relocs;
  Elf_Internal_Rela *relocs;
  Elf_Internal_Rela *lo, *hi, *look;
  Elf_Internal_Rela *lo, *hi, *look;
  bfd_vma val;
  bfd_vma val;
 
 
  /* No relocs implies we are linking a --just-symbols object.  */
  /* No relocs implies we are linking a --just-symbols object, or looking
 
     at a final linked executable with addr2line or somesuch.  */
  if (opd_sec->reloc_count == 0)
  if (opd_sec->reloc_count == 0)
    {
    {
      char buf[8];
      char buf[8];
 
 
      if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
      if (!bfd_get_section_contents (opd_bfd, opd_sec, buf, offset, 8))
Line 5609... Line 5631...
    }
    }
 
 
  return val;
  return val;
}
}
 
 
 
/* Return TRUE iff the ELF symbol SYM might be a function.  Set *CODE_SEC
 
   and *CODE_OFF to the function's entry point.  */
 
 
 
static bfd_boolean
 
ppc64_elf_maybe_function_sym (const asymbol *sym,
 
                              asection **code_sec, bfd_vma *code_off)
 
{
 
  if (_bfd_elf_maybe_function_sym (sym, code_sec, code_off))
 
    {
 
      if (strcmp (sym->section->name, ".opd") == 0)
 
        opd_entry_value (sym->section, sym->value, code_sec, code_off);
 
      return TRUE;
 
    }
 
  return FALSE;
 
}
 
 
/* Return true if symbol is defined in a regular object file.  */
/* Return true if symbol is defined in a regular object file.  */
 
 
static bfd_boolean
static bfd_boolean
is_static_defined (struct elf_link_hash_entry *h)
is_static_defined (struct elf_link_hash_entry *h)
{
{
Line 9463... Line 9501...
    return ppc_stub_long_branch;
    return ppc_stub_long_branch;
 
 
  return ppc_stub_none;
  return ppc_stub_none;
}
}
 
 
/* Build a .plt call stub.  */
/* With power7 weakly ordered memory model, it is possible for ld.so
 
   to update a plt entry in one thread and have another thread see a
 
   stale zero toc entry.  To avoid this we need some sort of acquire
 
   barrier in the call stub.  One solution is to make the load of the
 
   toc word seem to appear to depend on the load of the function entry
 
   word.  Another solution is to test for r2 being zero, and branch to
 
   the appropriate glink entry if so.
 
 
 
   .    fake dep barrier        compare
 
   .    ld 11,xxx(2)            ld 11,xxx(2)
 
   .    mtctr 11                mtctr 11
 
   .    xor 11,11,11            ld 2,xxx+8(2)
 
   .    add 2,2,11              cmpldi 2,0
 
   .    ld 2,xxx+8(2)           bnectr+
 
   .    bctr                    b <glink_entry>
 
 
 
   The solution involving the compare turns out to be faster, so
 
   that's what we use unless the branch won't reach.  */
 
 
 
#define ALWAYS_USE_FAKE_DEP 0
 
#define ALWAYS_EMIT_R2SAVE 0
 
 
static inline bfd_byte *
 
build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r,
 
                bfd_boolean plt_static_chain)
 
{
 
#define PPC_LO(v) ((v) & 0xffff)
#define PPC_LO(v) ((v) & 0xffff)
#define PPC_HI(v) (((v) >> 16) & 0xffff)
#define PPC_HI(v) (((v) >> 16) & 0xffff)
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 
 
static inline unsigned int
 
plt_stub_size (struct ppc_link_hash_table *htab,
 
               struct ppc_stub_hash_entry *stub_entry,
 
               bfd_vma off)
 
{
 
  unsigned size = PLT_CALL_STUB_SIZE;
 
 
 
  if (!(ALWAYS_EMIT_R2SAVE
 
        || stub_entry->stub_type == ppc_stub_plt_call_r2save))
 
    size -= 4;
 
  if (!htab->plt_static_chain)
 
    size -= 4;
 
  if (htab->plt_thread_safe)
 
    size += 8;
 
  if (PPC_HA (off) == 0)
 
    size -= 4;
 
  if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
 
    size += 4;
 
  if (stub_entry->h != NULL
 
      && (stub_entry->h == htab->tls_get_addr_fd
 
          || stub_entry->h == htab->tls_get_addr)
 
      && !htab->no_tls_get_addr_opt)
 
    size += 13 * 4;
 
  return size;
 
}
 
 
 
/* If this stub would cross fewer 2**plt_stub_align boundaries if we align,
 
   then return the padding needed to do so.  */
 
static inline unsigned int
 
plt_stub_pad (struct ppc_link_hash_table *htab,
 
              struct ppc_stub_hash_entry *stub_entry,
 
              bfd_vma plt_off)
 
{
 
  int stub_align = 1 << htab->plt_stub_align;
 
  unsigned stub_size = plt_stub_size (htab, stub_entry, plt_off);
 
  bfd_vma stub_off = stub_entry->stub_sec->size;
 
 
 
  if (((stub_off + stub_size - 1) & -stub_align) - (stub_off & -stub_align)
 
      > (stub_size & -stub_align))
 
    return stub_align - (stub_off & (stub_align - 1));
 
  return 0;
 
}
 
 
 
/* Build a .plt call stub.  */
 
 
 
static inline bfd_byte *
 
build_plt_stub (struct ppc_link_hash_table *htab,
 
                struct ppc_stub_hash_entry *stub_entry,
 
                bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
 
{
 
  bfd *obfd = htab->stub_bfd;
 
  bfd_boolean plt_static_chain = htab->plt_static_chain;
 
  bfd_boolean plt_thread_safe = htab->plt_thread_safe;
 
  bfd_boolean use_fake_dep = plt_thread_safe;
 
  bfd_vma cmp_branch_off = 0;
 
 
 
  if (!ALWAYS_USE_FAKE_DEP
 
      && plt_thread_safe
 
      && !(stub_entry->h != NULL
 
           && (stub_entry->h == htab->tls_get_addr_fd
 
               || stub_entry->h == htab->tls_get_addr)
 
           && !htab->no_tls_get_addr_opt))
 
    {
 
      bfd_vma pltoff = stub_entry->plt_ent->plt.offset & ~1;
 
      bfd_vma pltindex = (pltoff - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE;
 
      bfd_vma glinkoff = GLINK_CALL_STUB_SIZE + pltindex * 8;
 
      bfd_vma to, from;
 
 
 
      if (pltindex > 32767)
 
        glinkoff += (pltindex - 32767) * 4;
 
      to = (glinkoff
 
            + htab->glink->output_offset
 
            + htab->glink->output_section->vma);
 
      from = (p - stub_entry->stub_sec->contents
 
              + 4 * (ALWAYS_EMIT_R2SAVE
 
                     || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 
              + 4 * (PPC_HA (offset) != 0)
 
              + 4 * (PPC_HA (offset + 8 + 8 * plt_static_chain)
 
                     != PPC_HA (offset))
 
              + 4 * (plt_static_chain != 0)
 
              + 20
 
              + stub_entry->stub_sec->output_offset
 
              + stub_entry->stub_sec->output_section->vma);
 
      cmp_branch_off = to - from;
 
      use_fake_dep = cmp_branch_off + (1 << 25) >= (1 << 26);
 
    }
 
 
  if (PPC_HA (offset) != 0)
  if (PPC_HA (offset) != 0)
    {
    {
      if (r != NULL)
      if (r != NULL)
        {
        {
 
          if (ALWAYS_EMIT_R2SAVE
 
              || stub_entry->stub_type == ppc_stub_plt_call_r2save)
          r[0].r_offset += 4;
          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 + 4;
          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;
Line 9490... Line 9633...
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
              r[2].r_addend = r[0].r_addend;
              r[2].r_addend = r[0].r_addend;
            }
            }
          else
          else
            {
            {
              r[2].r_offset = r[1].r_offset + 8;
              r[2].r_offset = r[1].r_offset + 8 + 8 * use_fake_dep;
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
              r[2].r_addend = r[0].r_addend + 8;
              r[2].r_addend = r[0].r_addend + 8;
              if (plt_static_chain)
              if (plt_static_chain)
                {
                {
                  r[3].r_offset = r[2].r_offset + 4;
                  r[3].r_offset = r[2].r_offset + 4;
                  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;
                }
                }
            }
            }
        }
        }
 
      if (ALWAYS_EMIT_R2SAVE
 
          || stub_entry->stub_type == ppc_stub_plt_call_r2save)
      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, 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;
        }
        }
      bfd_put_32 (obfd, MTCTR_R11, p),                          p += 4;
      bfd_put_32 (obfd, MTCTR_R11, p),                          p += 4;
 
      if (use_fake_dep)
 
        {
 
          bfd_put_32 (obfd, XOR_R11_R11_R11, p),                p += 4;
 
          bfd_put_32 (obfd, ADD_R12_R12_R11, p),                p += 4;
 
        }
      bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p),   p += 4;
      bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset + 8), p),   p += 4;
      if (plt_static_chain)
      if (plt_static_chain)
        bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4;
        bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset + 16), p), p += 4;
      bfd_put_32 (obfd, BCTR, p),                               p += 4;
 
    }
    }
  else
  else
    {
    {
      if (r != NULL)
      if (r != NULL)
        {
        {
 
          if (ALWAYS_EMIT_R2SAVE
 
              || stub_entry->stub_type == ppc_stub_plt_call_r2save)
          r[0].r_offset += 4;
          r[0].r_offset += 4;
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
          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[1].r_offset = r[0].r_offset + 4;
              r[1].r_offset = r[0].r_offset + 4;
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
              r[1].r_addend = r[0].r_addend;
              r[1].r_addend = r[0].r_addend;
            }
            }
          else
          else
            {
            {
              r[1].r_offset = r[0].r_offset + 8;
              r[1].r_offset = r[0].r_offset + 8 + 8 * use_fake_dep;
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
              r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
              r[1].r_addend = r[0].r_addend + 8 + 8 * plt_static_chain;
              if (plt_static_chain)
              if (plt_static_chain)
                {
                {
                  r[2].r_offset = r[1].r_offset + 4;
                  r[2].r_offset = r[1].r_offset + 4;
                  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
                  r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
                  r[2].r_addend = r[0].r_addend + 8;
                  r[2].r_addend = r[0].r_addend + 8;
                }
                }
            }
            }
        }
        }
 
      if (ALWAYS_EMIT_R2SAVE
 
          || stub_entry->stub_type == ppc_stub_plt_call_r2save)
      bfd_put_32 (obfd, STD_R2_40R1, p),                        p += 4;
      bfd_put_32 (obfd, STD_R2_40R1, p),                        p += 4;
      bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset), p),       p += 4;
      bfd_put_32 (obfd, LD_R11_0R2 | 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_R2_R2 | PPC_LO (offset), p),   p += 4;
          bfd_put_32 (obfd, ADDI_R2_R2 | PPC_LO (offset), p),   p += 4;
          offset = 0;
          offset = 0;
        }
        }
      bfd_put_32 (obfd, MTCTR_R11, p),                          p += 4;
      bfd_put_32 (obfd, MTCTR_R11, p),                          p += 4;
 
      if (use_fake_dep)
 
        {
 
          bfd_put_32 (obfd, XOR_R11_R11_R11, p),                p += 4;
 
          bfd_put_32 (obfd, ADD_R2_R2_R11, p),                  p += 4;
 
        }
      if (plt_static_chain)
      if (plt_static_chain)
        bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
        bfd_put_32 (obfd, LD_R11_0R2 | PPC_LO (offset + 16), p), p += 4;
      bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p),    p += 4;
      bfd_put_32 (obfd, LD_R2_0R2 | PPC_LO (offset + 8), p),    p += 4;
      bfd_put_32 (obfd, BCTR, p),                               p += 4;
 
    }
    }
 
  if (plt_thread_safe && !use_fake_dep)
 
    {
 
      bfd_put_32 (obfd, CMPLDI_R2_0, p),                        p += 4;
 
      bfd_put_32 (obfd, BNECTR_P4, p),                          p += 4;
 
      bfd_put_32 (obfd, B_DOT + cmp_branch_off, p),             p += 4;
 
    }
 
  else
 
    bfd_put_32 (obfd, BCTR, p),                                 p += 4;
  return p;
  return p;
}
}
 
 
/* Build a special .plt call stub for __tls_get_addr.  */
/* Build a special .plt call stub for __tls_get_addr.  */
 
 
Line 9573... Line 9738...
#define LD_R11_0R1      0xe9610000
#define LD_R11_0R1      0xe9610000
#define LD_R2_0R1       0xe8410000
#define LD_R2_0R1       0xe8410000
#define MTLR_R11        0x7d6803a6
#define MTLR_R11        0x7d6803a6
 
 
static inline bfd_byte *
static inline bfd_byte *
build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
build_tls_get_addr_stub (struct ppc_link_hash_table *htab,
                         Elf_Internal_Rela *r, bfd_boolean plt_static_chain)
                         struct ppc_stub_hash_entry *stub_entry,
 
                         bfd_byte *p, bfd_vma offset, Elf_Internal_Rela *r)
{
{
 
  bfd *obfd = htab->stub_bfd;
 
 
  bfd_put_32 (obfd, LD_R11_0R3 + 0, p),          p += 4;
  bfd_put_32 (obfd, LD_R11_0R3 + 0, p),          p += 4;
  bfd_put_32 (obfd, LD_R12_0R3 + 8, p),         p += 4;
  bfd_put_32 (obfd, LD_R12_0R3 + 8, p),         p += 4;
  bfd_put_32 (obfd, MR_R0_R3, p),               p += 4;
  bfd_put_32 (obfd, MR_R0_R3, p),               p += 4;
  bfd_put_32 (obfd, CMPDI_R11_0, p),            p += 4;
  bfd_put_32 (obfd, CMPDI_R11_0, p),            p += 4;
  bfd_put_32 (obfd, ADD_R3_R12_R13, p),         p += 4;
  bfd_put_32 (obfd, ADD_R3_R12_R13, p),         p += 4;
Line 9588... Line 9756...
  bfd_put_32 (obfd, MFLR_R11, p),               p += 4;
  bfd_put_32 (obfd, MFLR_R11, p),               p += 4;
  bfd_put_32 (obfd, STD_R11_0R1 + 32, p),       p += 4;
  bfd_put_32 (obfd, STD_R11_0R1 + 32, p),       p += 4;
 
 
  if (r != NULL)
  if (r != NULL)
    r[0].r_offset += 9 * 4;
    r[0].r_offset += 9 * 4;
  p = build_plt_stub (obfd, p, offset, r, plt_static_chain);
  p = build_plt_stub (htab, stub_entry, p, offset, r);
  bfd_put_32 (obfd, BCTRL, p - 4);
  bfd_put_32 (obfd, BCTRL, p - 4);
 
 
  bfd_put_32 (obfd, LD_R11_0R1 + 32, p),        p += 4;
  bfd_put_32 (obfd, LD_R11_0R1 + 32, p),        p += 4;
  bfd_put_32 (obfd, LD_R2_0R1 + 40, p),         p += 4;
  bfd_put_32 (obfd, LD_R2_0R1 + 40, p),         p += 4;
  bfd_put_32 (obfd, MTLR_R11, p),               p += 4;
  bfd_put_32 (obfd, MTLR_R11, p),               p += 4;
Line 9935... Line 10103...
      loc += 4;
      loc += 4;
      bfd_put_32 (htab->stub_bfd, BCTR, loc);
      bfd_put_32 (htab->stub_bfd, BCTR, loc);
      break;
      break;
 
 
    case ppc_stub_plt_call:
    case ppc_stub_plt_call:
 
    case ppc_stub_plt_call_r2save:
      if (stub_entry->h != NULL
      if (stub_entry->h != NULL
          && stub_entry->h->is_func_descriptor
          && stub_entry->h->is_func_descriptor
          && stub_entry->h->oh != NULL)
          && stub_entry->h->oh != NULL)
        {
        {
          struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
          struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
Line 10001... Line 10170...
          bfd_set_error (bfd_error_bad_value);
          bfd_set_error (bfd_error_bad_value);
          htab->stub_error = TRUE;
          htab->stub_error = TRUE;
          return FALSE;
          return FALSE;
        }
        }
 
 
 
      if (htab->plt_stub_align != 0)
 
        {
 
          unsigned pad = plt_stub_pad (htab, stub_entry, off);
 
 
 
          stub_entry->stub_sec->size += pad;
 
          stub_entry->stub_offset = stub_entry->stub_sec->size;
 
          loc += pad;
 
        }
 
 
      r = NULL;
      r = NULL;
      if (info->emitrelocations)
      if (info->emitrelocations)
        {
        {
          r = get_relocs (stub_entry->stub_sec,
          r = get_relocs (stub_entry->stub_sec,
                          (2
                          (2
Line 10020... Line 10198...
        }
        }
      if (stub_entry->h != NULL
      if (stub_entry->h != NULL
          && (stub_entry->h == htab->tls_get_addr_fd
          && (stub_entry->h == htab->tls_get_addr_fd
              || stub_entry->h == htab->tls_get_addr)
              || stub_entry->h == htab->tls_get_addr)
          && !htab->no_tls_get_addr_opt)
          && !htab->no_tls_get_addr_opt)
        p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r,
        p = build_tls_get_addr_stub (htab, stub_entry, loc, off, r);
                                     htab->plt_static_chain);
 
      else
      else
        p = build_plt_stub (htab->stub_bfd, loc, off, r,
        p = build_plt_stub (htab, stub_entry, loc, off, r);
                            htab->plt_static_chain);
 
      size = p - loc;
      size = p - loc;
      break;
      break;
 
 
    default:
    default:
      BFD_FAIL ();
      BFD_FAIL ();
Line 10044... Line 10220...
      char *name;
      char *name;
      const char *const stub_str[] = { "long_branch",
      const char *const stub_str[] = { "long_branch",
                                       "long_branch_r2off",
                                       "long_branch_r2off",
                                       "plt_branch",
                                       "plt_branch",
                                       "plt_branch_r2off",
                                       "plt_branch_r2off",
 
                                       "plt_call",
                                       "plt_call" };
                                       "plt_call" };
 
 
      len1 = strlen (stub_str[stub_entry->stub_type - 1]);
      len1 = strlen (stub_str[stub_entry->stub_type - 1]);
      len2 = strlen (stub_entry->root.string);
      len2 = strlen (stub_entry->root.string);
      name = bfd_malloc (len1 + len2 + 2);
      name = bfd_malloc (len1 + len2 + 2);
Line 10094... Line 10271...
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
  if (htab == NULL)
  if (htab == NULL)
    return FALSE;
    return FALSE;
 
 
  if (stub_entry->stub_type == ppc_stub_plt_call)
  if (stub_entry->stub_type == ppc_stub_plt_call
 
      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
    {
    {
      asection *plt;
      asection *plt;
      off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
      off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
      if (off >= (bfd_vma) -2)
      if (off >= (bfd_vma) -2)
        abort ();
        abort ();
Line 10110... Line 10288...
      off += (plt->output_offset
      off += (plt->output_offset
              + plt->output_section->vma
              + plt->output_section->vma
              - elf_gp (plt->output_section->owner)
              - elf_gp (plt->output_section->owner)
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
 
      size = PLT_CALL_STUB_SIZE;
      size = plt_stub_size (htab, stub_entry, off);
      if (!htab->plt_static_chain)
      if (htab->plt_stub_align)
        size -= 4;
        size += plt_stub_pad (htab, stub_entry, off);
      if (PPC_HA (off) == 0)
 
        size -= 4;
 
      if (PPC_HA (off + 8 + 8 * htab->plt_static_chain) != PPC_HA (off))
 
        size += 4;
 
      if (stub_entry->h != NULL
 
          && (stub_entry->h == htab->tls_get_addr_fd
 
              || stub_entry->h == htab->tls_get_addr)
 
          && !htab->no_tls_get_addr_opt)
 
        size += 13 * 4;
 
      if (info->emitrelocations)
      if (info->emitrelocations)
        {
        {
          stub_entry->stub_sec->reloc_count
          stub_entry->stub_sec->reloc_count
            += (2
            += (2
                + (PPC_HA (off) != 0)
                + (PPC_HA (off) != 0)
Line 11090... Line 11259...
   PC-relative calls to a target that is unreachable with a "bl"
   PC-relative calls to a target that is unreachable with a "bl"
   instruction.  */
   instruction.  */
 
 
bfd_boolean
bfd_boolean
ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
ppc64_elf_size_stubs (struct bfd_link_info *info, bfd_signed_vma group_size,
                      bfd_boolean plt_static_chain)
                      bfd_boolean plt_static_chain, int plt_thread_safe,
 
                      int plt_stub_align)
{
{
  bfd_size_type stub_group_size;
  bfd_size_type stub_group_size;
  bfd_boolean stubs_always_before_branch;
  bfd_boolean stubs_always_before_branch;
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
 
  if (htab == NULL)
  if (htab == NULL)
    return FALSE;
    return FALSE;
 
 
  htab->plt_static_chain = plt_static_chain;
  htab->plt_static_chain = plt_static_chain;
 
  htab->plt_stub_align = plt_stub_align;
 
  if (plt_thread_safe == -1)
 
    {
 
      const char *const thread_starter[] =
 
        {
 
          "pthread_create",
 
          /* libstdc++ */
 
          "_ZNSt6thread15_M_start_threadESt10shared_ptrINS_10_Impl_baseEE",
 
          /* librt */
 
          "aio_init", "aio_read", "aio_write", "aio_fsync", "lio_listio",
 
          "mq_notify", "create_timer",
 
          /* libanl */
 
          "getaddrinfo_a",
 
          /* libgomp */
 
          "GOMP_parallel_start",
 
          "GOMP_parallel_loop_static_start",
 
          "GOMP_parallel_loop_dynamic_start",
 
          "GOMP_parallel_loop_guided_start",
 
          "GOMP_parallel_loop_runtime_start",
 
          "GOMP_parallel_sections_start",
 
        };
 
      unsigned i;
 
 
 
      for (i = 0; i < sizeof (thread_starter)/ sizeof (thread_starter[0]); i++)
 
        {
 
          struct elf_link_hash_entry *h;
 
          h = elf_link_hash_lookup (&htab->elf, thread_starter[i],
 
                                    FALSE, FALSE, TRUE);
 
          plt_thread_safe = h != NULL && h->ref_regular;
 
          if (plt_thread_safe)
 
            break;
 
        }
 
    }
 
  htab->plt_thread_safe = plt_thread_safe;
  stubs_always_before_branch = group_size < 0;
  stubs_always_before_branch = group_size < 0;
  if (group_size < 0)
  if (group_size < 0)
    stub_group_size = -group_size;
    stub_group_size = -group_size;
  else
  else
    stub_group_size = group_size;
    stub_group_size = group_size;
Line 11334... Line 11538...
                    }
                    }
 
 
                  if (stub_type == ppc_stub_plt_call
                  if (stub_type == ppc_stub_plt_call
                      && irela + 1 < irelaend
                      && irela + 1 < irelaend
                      && irela[1].r_offset == irela->r_offset + 4
                      && irela[1].r_offset == irela->r_offset + 4
                      && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE
                      && ELF64_R_TYPE (irela[1].r_info) == R_PPC64_TOCSAVE)
                      && !tocsave_find (htab, INSERT,
                    {
 
                      if (!tocsave_find (htab, INSERT,
                                        &local_syms, irela + 1, input_bfd))
                                        &local_syms, irela + 1, input_bfd))
                    goto error_ret_free_internal;
                    goto error_ret_free_internal;
 
                    }
 
                  else if (stub_type == ppc_stub_plt_call)
 
                    stub_type = ppc_stub_plt_call_r2save;
 
 
                  /* 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.  */
Line 11353... Line 11561...
                                                     stub_name, FALSE, FALSE);
                                                     stub_name, FALSE, FALSE);
                  if (stub_entry != NULL)
                  if (stub_entry != NULL)
                    {
                    {
                      /* The proper stub has already been created.  */
                      /* The proper stub has already been created.  */
                      free (stub_name);
                      free (stub_name);
 
                      if (stub_type == ppc_stub_plt_call_r2save)
 
                        stub_entry->stub_type = stub_type;
                      continue;
                      continue;
                    }
                    }
 
 
                  stub_entry = ppc_add_stub (stub_name, section, info);
                  stub_entry = ppc_add_stub (stub_name, section, info);
                  if (stub_entry == NULL)
                  if (stub_entry == NULL)
Line 11372... Line 11582...
                        free (local_syms);
                        free (local_syms);
                      return FALSE;
                      return FALSE;
                    }
                    }
 
 
                  stub_entry->stub_type = stub_type;
                  stub_entry->stub_type = stub_type;
                  if (stub_type != ppc_stub_plt_call)
                  if (stub_type != ppc_stub_plt_call
 
                      && stub_type != ppc_stub_plt_call_r2save)
                    {
                    {
                      stub_entry->target_value = code_value;
                      stub_entry->target_value = code_value;
                      stub_entry->target_section = code_sec;
                      stub_entry->target_section = code_sec;
                    }
                    }
                  else
                  else
Line 11452... Line 11663...
            size += sizeof (glink_eh_frame_cie);
            size += sizeof (glink_eh_frame_cie);
          htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
          htab->glink_eh_frame->rawsize = htab->glink_eh_frame->size;
          htab->glink_eh_frame->size = size;
          htab->glink_eh_frame->size = size;
        }
        }
 
 
 
      if (htab->plt_stub_align != 0)
 
        for (stub_sec = htab->stub_bfd->sections;
 
             stub_sec != NULL;
 
             stub_sec = stub_sec->next)
 
          if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
 
            stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1)
 
                              & (-1 << htab->plt_stub_align));
 
 
      for (stub_sec = htab->stub_bfd->sections;
      for (stub_sec = htab->stub_bfd->sections;
           stub_sec != NULL;
           stub_sec != NULL;
           stub_sec = stub_sec->next)
           stub_sec = stub_sec->next)
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
        if ((stub_sec->flags & SEC_LINKER_CREATED) == 0
            && stub_sec->rawsize != stub_sec->size)
            && stub_sec->rawsize != stub_sec->size)
Line 11777... Line 11996...
  bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
  bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info);
 
 
  if (htab->relbrlt != NULL)
  if (htab->relbrlt != NULL)
    htab->relbrlt->reloc_count = 0;
    htab->relbrlt->reloc_count = 0;
 
 
 
  if (htab->plt_stub_align != 0)
 
    for (stub_sec = htab->stub_bfd->sections;
 
         stub_sec != NULL;
 
         stub_sec = stub_sec->next)
 
      if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
 
        stub_sec->size = ((stub_sec->size + (1 << htab->plt_stub_align) - 1)
 
                          & (-1 << htab->plt_stub_align));
 
 
  for (stub_sec = htab->stub_bfd->sections;
  for (stub_sec = htab->stub_bfd->sections;
       stub_sec != NULL;
       stub_sec != NULL;
       stub_sec = stub_sec->next)
       stub_sec = stub_sec->next)
    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
    if ((stub_sec->flags & SEC_LINKER_CREATED) == 0)
      {
      {
Line 11810... Line 12037...
      sprintf (*stats, _("linker stubs in %u group%s\n"
      sprintf (*stats, _("linker stubs in %u group%s\n"
                         "  branch       %lu\n"
                         "  branch       %lu\n"
                         "  toc adjust   %lu\n"
                         "  toc adjust   %lu\n"
                         "  long branch  %lu\n"
                         "  long branch  %lu\n"
                         "  long toc adj %lu\n"
                         "  long toc adj %lu\n"
                         "  plt call     %lu"),
                         "  plt call     %lu\n"
 
                         "  plt call toc %lu"),
               stub_sec_count,
               stub_sec_count,
               stub_sec_count == 1 ? "" : "s",
               stub_sec_count == 1 ? "" : "s",
               htab->stub_count[ppc_stub_long_branch - 1],
               htab->stub_count[ppc_stub_long_branch - 1],
               htab->stub_count[ppc_stub_long_branch_r2off - 1],
               htab->stub_count[ppc_stub_long_branch_r2off - 1],
               htab->stub_count[ppc_stub_plt_branch - 1],
               htab->stub_count[ppc_stub_plt_branch - 1],
               htab->stub_count[ppc_stub_plt_branch_r2off - 1],
               htab->stub_count[ppc_stub_plt_branch_r2off - 1],
               htab->stub_count[ppc_stub_plt_call - 1]);
               htab->stub_count[ppc_stub_plt_call - 1],
 
               htab->stub_count[ppc_stub_plt_call_r2save - 1]);
    }
    }
  return TRUE;
  return TRUE;
}
}
 
 
/* This function undoes the changes made by add_symbol_adjust.  */
/* This function undoes the changes made by add_symbol_adjust.  */
Line 11917... Line 12146...
  bfd_byte *loc;
  bfd_byte *loc;
  struct got_entry **local_got_ents;
  struct got_entry **local_got_ents;
  bfd_vma TOCstart;
  bfd_vma TOCstart;
  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'.  */
  /* Assume 'at' branch hints.  */
  bfd_boolean is_power4 = FALSE;
  bfd_boolean is_isa_v2 = TRUE;
  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
 
 
  /* Initialize howto table if needed.  */
  /* Initialize howto table if needed.  */
  if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
  if (!ppc64_elf_howto_table[R_PPC64_ADDR32])
    ppc_howto_init ();
    ppc_howto_init ();
Line 12550... Line 12779...
              && h->oh->is_func_descriptor)
              && h->oh->is_func_descriptor)
            fdh = ppc_follow_link (h->oh);
            fdh = ppc_follow_link (h->oh);
          stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
          stub_entry = ppc_get_stub_entry (input_section, sec, fdh, rel, htab);
          if (stub_entry != NULL
          if (stub_entry != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
              && (stub_entry->stub_type == ppc_stub_plt_call
 
                  || stub_entry->stub_type == ppc_stub_plt_call_r2save
                  || stub_entry->stub_type == ppc_stub_plt_branch_r2off
                  || stub_entry->stub_type == ppc_stub_plt_branch_r2off
                  || stub_entry->stub_type == ppc_stub_long_branch_r2off))
                  || stub_entry->stub_type == ppc_stub_long_branch_r2off))
            {
            {
              bfd_boolean can_plt_call = FALSE;
              bfd_boolean can_plt_call = FALSE;
 
 
Line 12578... Line 12808...
                    }
                    }
                }
                }
 
 
              if (!can_plt_call)
              if (!can_plt_call)
                {
                {
                  if (stub_entry->stub_type == ppc_stub_plt_call)
                  if (stub_entry->stub_type == ppc_stub_plt_call
 
                      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
                    {
                    {
                      /* If this is a plain branch rather than a branch
                      /* If this is a plain branch rather than a branch
                         and link, don't require a nop.  However, don't
                         and link, don't require a nop.  However, don't
                         allow tail calls in a shared library as they
                         allow tail calls in a shared library as they
                         will result in r2 being corrupted.  */
                         will result in r2 being corrupted.  */
Line 12625... Line 12856...
                      ret = FALSE;
                      ret = FALSE;
                    }
                    }
                }
                }
 
 
              if (can_plt_call
              if (can_plt_call
                  && stub_entry->stub_type == ppc_stub_plt_call)
                  && (stub_entry->stub_type == ppc_stub_plt_call
 
                      || stub_entry->stub_type == ppc_stub_plt_call_r2save))
                unresolved_reloc = FALSE;
                unresolved_reloc = FALSE;
            }
            }
 
 
          if ((stub_entry == NULL
          if ((stub_entry == NULL
               || stub_entry->stub_type == ppc_stub_long_branch
               || stub_entry->stub_type == ppc_stub_long_branch
Line 12671... Line 12903...
              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
              if ((stub_entry->stub_type == ppc_stub_plt_call
 
                   || stub_entry->stub_type == ppc_stub_plt_call_r2save)
 
                  && (ALWAYS_EMIT_R2SAVE
 
                      || stub_entry->stub_type == ppc_stub_plt_call_r2save)
                  && rel + 1 < relend
                  && rel + 1 < relend
                  && rel[1].r_offset == rel->r_offset + 4
                  && rel[1].r_offset == rel->r_offset + 4
                  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
                  && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOCSAVE)
                relocation += 4;
                relocation += 4;
            }
            }
 
 
          if (insn != 0)
          if (insn != 0)
            {
            {
              if (is_power4)
              if (is_isa_v2)
                {
                {
                  /* Set 'a' bit.  This is 0b00010 in BO field for branch
                  /* Set 'a' bit.  This is 0b00010 in BO field for branch
                     on CR(BI) insns (BO == 001at or 011at), and 0b01000
                     on CR(BI) insns (BO == 001at or 011at), and 0b01000
                     for branch on CTR insns (BO == 1a00t or 1a01t).  */
                     for branch on CTR insns (BO == 1a00t or 1a01t).  */
                  if ((insn & (0x14 << 21)) == (0x04 << 21))
                  if ((insn & (0x14 << 21)) == (0x04 << 21))
Line 13898... Line 14133...
  return TRUE;
  return TRUE;
}
}
 
 
#include "elf64-target.h"
#include "elf64-target.h"
 
 
 No newline at end of file
 No newline at end of file
 
/* FreeBSD support */
 
 
 
#undef  TARGET_LITTLE_SYM
 
#undef  TARGET_LITTLE_NAME
 
 
 
#undef  TARGET_BIG_SYM
 
#define TARGET_BIG_SYM  bfd_elf64_powerpc_freebsd_vec
 
#undef  TARGET_BIG_NAME
 
#define TARGET_BIG_NAME "elf64-powerpc-freebsd"
 
 
 
#undef  ELF_OSABI
 
#define ELF_OSABI       ELFOSABI_FREEBSD
 
 
 
#undef  elf64_bed
 
#define elf64_bed       elf64_powerpc_fbsd_bed
 
 
 
#include "elf64-target.h"
 
 
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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