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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [bfd/] [elf64-ppc.c] - Diff between revs 157 and 225

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

Rev 157 Rev 225
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,
   Free Software Foundation, Inc.
   2009, 2010 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 <amodra@bigpond.net.au>
   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.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
Line 90... Line 90...
#define elf_backend_grok_psinfo               ppc64_elf_grok_psinfo
#define elf_backend_grok_psinfo               ppc64_elf_grok_psinfo
#define elf_backend_write_core_note           ppc64_elf_write_core_note
#define elf_backend_write_core_note           ppc64_elf_write_core_note
#define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
#define elf_backend_create_dynamic_sections   ppc64_elf_create_dynamic_sections
#define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
#define elf_backend_copy_indirect_symbol      ppc64_elf_copy_indirect_symbol
#define elf_backend_add_symbol_hook           ppc64_elf_add_symbol_hook
#define elf_backend_add_symbol_hook           ppc64_elf_add_symbol_hook
#define elf_backend_check_directives          ppc64_elf_check_directives
#define elf_backend_check_directives          ppc64_elf_process_dot_syms
#define elf_backend_as_needed_cleanup         ppc64_elf_as_needed_cleanup
#define elf_backend_as_needed_cleanup         ppc64_elf_as_needed_cleanup
#define elf_backend_archive_symbol_lookup     ppc64_elf_archive_symbol_lookup
#define elf_backend_archive_symbol_lookup     ppc64_elf_archive_symbol_lookup
#define elf_backend_check_relocs              ppc64_elf_check_relocs
#define elf_backend_check_relocs              ppc64_elf_check_relocs
#define elf_backend_gc_keep                   ppc64_elf_gc_keep
#define elf_backend_gc_keep                   ppc64_elf_gc_keep
#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
Line 110... Line 110...
#define elf_backend_finish_dynamic_symbol     ppc64_elf_finish_dynamic_symbol
#define elf_backend_finish_dynamic_symbol     ppc64_elf_finish_dynamic_symbol
#define elf_backend_reloc_type_class          ppc64_elf_reloc_type_class
#define elf_backend_reloc_type_class          ppc64_elf_reloc_type_class
#define elf_backend_finish_dynamic_sections   ppc64_elf_finish_dynamic_sections
#define elf_backend_finish_dynamic_sections   ppc64_elf_finish_dynamic_sections
#define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
#define elf_backend_link_output_symbol_hook   ppc64_elf_output_symbol_hook
#define elf_backend_special_sections          ppc64_elf_special_sections
#define elf_backend_special_sections          ppc64_elf_special_sections
 
#define elf_backend_post_process_headers      _bfd_elf_set_osabi
 
 
/* The name of the dynamic interpreter.  This is put in the .interp
/* The name of the dynamic interpreter.  This is put in the .interp
   section.  */
   section.  */
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
 
 
Line 1233... Line 1234...
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                      /* src_mask */
         0,                      /* src_mask */
         0xfffc,                /* dst_mask */
         0xfffc,                /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* Marker reloc for TLS.  */
  /* Marker relocs for TLS.  */
  HOWTO (R_PPC64_TLS,
  HOWTO (R_PPC64_TLS,
         0,                      /* rightshift */
         0,                      /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         32,                    /* bitsize */
         32,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
Line 1248... Line 1249...
         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_TLSGD,
 
         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_TLSGD",       /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0,                      /* dst_mask */
 
         FALSE),                /* pcrel_offset */
 
 
 
  HOWTO (R_PPC64_TLSLD,
 
         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_TLSLD",       /* 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 1843... Line 1872...
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                      /* src_mask */
         0,                      /* src_mask */
         0xffff,                /* dst_mask */
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
 
  HOWTO (R_PPC64_JMP_IREL,      /* type */
 
         0,                      /* rightshift */
 
         0,                      /* size (0=byte, 1=short, 2=long, 4=64 bits) */
 
         0,                      /* bitsize */
 
         FALSE,                 /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_dont, /* complain_on_overflow */
 
         ppc64_elf_unhandled_reloc, /* special_function */
 
         "R_PPC64_JMP_IREL",    /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0,                      /* dst_mask */
 
         FALSE),                /* pcrel_offset */
 
 
 
  HOWTO (R_PPC64_IRELATIVE,     /* type */
 
         0,                      /* rightshift */
 
         4,                     /* size (0=byte, 1=short, 2=long, 4=64 bits) */
 
         64,                    /* bitsize */
 
         FALSE,                 /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_dont, /* complain_on_overflow */
 
         bfd_elf_generic_reloc, /* special_function */
 
         "R_PPC64_IRELATIVE",   /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         ONES (64),             /* dst_mask */
 
         FALSE),                /* pcrel_offset */
 
 
 
  /* A 16 bit relative relocation.  */
 
  HOWTO (R_PPC64_REL16,         /* type */
 
         0,                      /* rightshift */
 
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
 
         16,                    /* bitsize */
 
         TRUE,                  /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_bitfield, /* complain_on_overflow */
 
         bfd_elf_generic_reloc, /* special_function */
 
         "R_PPC64_REL16",       /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0xffff,                /* dst_mask */
 
         TRUE),                 /* pcrel_offset */
 
 
 
  /* A 16 bit relative relocation without overflow.  */
 
  HOWTO (R_PPC64_REL16_LO,      /* type */
 
         0,                      /* rightshift */
 
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
 
         16,                    /* bitsize */
 
         TRUE,                  /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_dont,/* complain_on_overflow */
 
         bfd_elf_generic_reloc, /* special_function */
 
         "R_PPC64_REL16_LO",    /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0xffff,                /* dst_mask */
 
         TRUE),                 /* pcrel_offset */
 
 
 
  /* The high order 16 bits of a relative address.  */
 
  HOWTO (R_PPC64_REL16_HI,      /* type */
 
         16,                    /* rightshift */
 
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
 
         16,                    /* bitsize */
 
         TRUE,                  /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_dont, /* complain_on_overflow */
 
         bfd_elf_generic_reloc, /* special_function */
 
         "R_PPC64_REL16_HI",    /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0xffff,                /* dst_mask */
 
         TRUE),                 /* pcrel_offset */
 
 
 
  /* The high order 16 bits of a relative address, plus 1 if the contents of
 
     the low 16 bits, treated as a signed number, is negative.  */
 
  HOWTO (R_PPC64_REL16_HA,      /* type */
 
         16,                    /* rightshift */
 
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
 
         16,                    /* bitsize */
 
         TRUE,                  /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_dont, /* complain_on_overflow */
 
         ppc64_elf_ha_reloc,    /* special_function */
 
         "R_PPC64_REL16_HA",    /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0xffff,                /* dst_mask */
 
         TRUE),                 /* pcrel_offset */
 
 
  /* GNU extension to record C++ vtable hierarchy.  */
  /* GNU extension to record C++ vtable hierarchy.  */
  HOWTO (R_PPC64_GNU_VTINHERIT, /* type */
  HOWTO (R_PPC64_GNU_VTINHERIT, /* type */
         0,                      /* rightshift */
         0,                      /* rightshift */
         0,                      /* size (0 = byte, 1 = short, 2 = long) */
         0,                      /* size (0 = byte, 1 = short, 2 = long) */
         0,                      /* bitsize */
         0,                      /* bitsize */
Line 2029... Line 2147...
      break;
      break;
    case BFD_RELOC_PPC64_PLTGOT16_LO_DS:        r = R_PPC64_PLTGOT16_LO_DS;
    case BFD_RELOC_PPC64_PLTGOT16_LO_DS:        r = R_PPC64_PLTGOT16_LO_DS;
      break;
      break;
    case BFD_RELOC_PPC_TLS:                     r = R_PPC64_TLS;
    case BFD_RELOC_PPC_TLS:                     r = R_PPC64_TLS;
      break;
      break;
 
    case BFD_RELOC_PPC_TLSGD:                   r = R_PPC64_TLSGD;
 
      break;
 
    case BFD_RELOC_PPC_TLSLD:                   r = R_PPC64_TLSLD;
 
      break;
    case BFD_RELOC_PPC_DTPMOD:                  r = R_PPC64_DTPMOD64;
    case BFD_RELOC_PPC_DTPMOD:                  r = R_PPC64_DTPMOD64;
      break;
      break;
    case BFD_RELOC_PPC_TPREL16:                 r = R_PPC64_TPREL16;
    case BFD_RELOC_PPC_TPREL16:                 r = R_PPC64_TPREL16;
      break;
      break;
    case BFD_RELOC_PPC_TPREL16_LO:              r = R_PPC64_TPREL16_LO;
    case BFD_RELOC_PPC_TPREL16_LO:              r = R_PPC64_TPREL16_LO;
Line 2107... Line 2229...
      break;
      break;
    case BFD_RELOC_PPC64_DTPREL16_HIGHEST:      r = R_PPC64_DTPREL16_HIGHEST;
    case BFD_RELOC_PPC64_DTPREL16_HIGHEST:      r = R_PPC64_DTPREL16_HIGHEST;
      break;
      break;
    case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:     r = R_PPC64_DTPREL16_HIGHESTA;
    case BFD_RELOC_PPC64_DTPREL16_HIGHESTA:     r = R_PPC64_DTPREL16_HIGHESTA;
      break;
      break;
 
    case BFD_RELOC_16_PCREL:                    r = R_PPC64_REL16;
 
      break;
 
    case BFD_RELOC_LO16_PCREL:                  r = R_PPC64_REL16_LO;
 
      break;
 
    case BFD_RELOC_HI16_PCREL:                  r = R_PPC64_REL16_HI;
 
      break;
 
    case BFD_RELOC_HI16_S_PCREL:                r = R_PPC64_REL16_HA;
 
      break;
    case BFD_RELOC_VTABLE_INHERIT:              r = R_PPC64_GNU_VTINHERIT;
    case BFD_RELOC_VTABLE_INHERIT:              r = R_PPC64_GNU_VTINHERIT;
      break;
      break;
    case BFD_RELOC_VTABLE_ENTRY:                r = R_PPC64_GNU_VTENTRY;
    case BFD_RELOC_VTABLE_ENTRY:                r = R_PPC64_GNU_VTENTRY;
      break;
      break;
    }
    }
Line 2606... Line 2736...
 
 
      /* After editing .opd, adjust references to opd local syms.  */
      /* After editing .opd, adjust references to opd local syms.  */
      long *adjust;
      long *adjust;
    } opd;
    } opd;
 
 
    /* An array for toc sections, indexed by offset/8.
    /* An array for toc sections, indexed by offset/8.  */
       Specifies the relocation symbol index used at a given toc offset.  */
    struct _toc_sec_data
    unsigned *t_symndx;
    {
 
      /* Specifies the relocation symbol index used at a given toc offset.  */
 
      unsigned *symndx;
 
 
 
      /* And the relocation addend.  */
 
      bfd_vma *add;
 
    } toc;
  } u;
  } u;
 
 
  enum _ppc64_sec_type sec_type:2;
  enum _ppc64_sec_type sec_type:2;
 
 
  /* Flag set when small branches are detected.  Used to
  /* Flag set when small branches are detected.  Used to
Line 2649... Line 2785...
    return &ppc64_elf_section_data (sec)->u.opd;
    return &ppc64_elf_section_data (sec)->u.opd;
  return NULL;
  return NULL;
}
}


/* Parameters for the qsort hook.  */
/* Parameters for the qsort hook.  */
static asection *synthetic_opd;
 
static bfd_boolean synthetic_relocatable;
static bfd_boolean synthetic_relocatable;
 
 
/* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
/* qsort comparison function for ppc64_elf_get_synthetic_symtab.  */
 
 
static int
static int
Line 2667... Line 2802...
    return -1;
    return -1;
  if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM))
  if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM))
    return 1;
    return 1;
 
 
  /* then .opd symbols.  */
  /* then .opd symbols.  */
  if (a->section == synthetic_opd && b->section != synthetic_opd)
  if (strcmp (a->section->name, ".opd") == 0
 
      && strcmp (b->section->name, ".opd") != 0)
    return -1;
    return -1;
  if (a->section != synthetic_opd && b->section == synthetic_opd)
  if (strcmp (a->section->name, ".opd") != 0
 
      && strcmp (b->section->name, ".opd") == 0)
    return 1;
    return 1;
 
 
  /* then other code symbols.  */
  /* then other code symbols.  */
  if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
  if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
      == (SEC_CODE | SEC_ALLOC)
      == (SEC_CODE | SEC_ALLOC)
Line 2769... Line 2906...
        }
        }
    }
    }
  return NULL;
  return NULL;
}
}
 
 
 
static bfd_boolean
 
section_covers_vma (bfd *abfd ATTRIBUTE_UNUSED, asection *section, void *ptr)
 
{
 
  bfd_vma vma = *(bfd_vma *) ptr;
 
  return ((section->flags & SEC_ALLOC) != 0
 
          && section->vma <= vma
 
          && vma < section->vma + section->size);
 
}
 
 
/* Create synthetic symbols, effectively restoring "dot-symbol" function
/* Create synthetic symbols, effectively restoring "dot-symbol" function
   entry syms.  */
   entry syms.  Also generate @plt symbols for the glink branch table.  */
 
 
static long
static long
ppc64_elf_get_synthetic_symtab (bfd *abfd,
ppc64_elf_get_synthetic_symtab (bfd *abfd,
                                long static_count, asymbol **static_syms,
                                long static_count, asymbol **static_syms,
                                long dyn_count, asymbol **dyn_syms,
                                long dyn_count, asymbol **dyn_syms,
Line 2814... Line 2960...
  else if (!relocatable && static_count == 0)
  else if (!relocatable && static_count == 0)
    memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms));
    memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms));
  else
  else
    memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
    memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
 
 
  synthetic_opd = opd;
 
  synthetic_relocatable = relocatable;
  synthetic_relocatable = relocatable;
  qsort (syms, symcount, sizeof (*syms), compare_symbols);
  qsort (syms, symcount, sizeof (*syms), compare_symbols);
 
 
  if (!relocatable && symcount > 1)
  if (!relocatable && symcount > 1)
    {
    {
Line 2832... Line 2977...
          syms[j++] = syms[i];
          syms[j++] = syms[i];
      symcount = j;
      symcount = j;
    }
    }
 
 
  i = 0;
  i = 0;
  if (syms[i]->section == opd)
  if (strcmp (syms[i]->section->name, ".opd") == 0)
    ++i;
    ++i;
  codesecsym = i;
  codesecsym = i;
 
 
  for (; i < symcount; ++i)
  for (; i < symcount; ++i)
    if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
    if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
Line 2849... Line 2994...
    if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
    if ((syms[i]->flags & BSF_SECTION_SYM) == 0)
      break;
      break;
  secsymend = i;
  secsymend = i;
 
 
  for (; i < symcount; ++i)
  for (; i < symcount; ++i)
    if (syms[i]->section != opd)
    if (strcmp (syms[i]->section->name, ".opd") != 0)
      break;
      break;
  opdsymend = i;
  opdsymend = i;
 
 
  for (; i < symcount; ++i)
  for (; i < symcount; ++i)
    if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
    if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL))
        != (SEC_CODE | SEC_ALLOC))
        != (SEC_CODE | SEC_ALLOC))
      break;
      break;
  symcount = i;
  symcount = i;
 
 
  count = 0;
  count = 0;
  if (opdsymend == secsymend)
 
    goto done;
 
 
 
  if (relocatable)
  if (relocatable)
    {
    {
      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
      arelent *r;
      arelent *r;
      size_t size;
      size_t size;
      long relcount;
      long relcount;
 
 
 
      if (opdsymend == secsymend)
 
        goto done;
 
 
      slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
      slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
      relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
      relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0;
      if (relcount == 0)
      if (relcount == 0)
        goto done;
        goto done;
 
 
Line 2942... Line 3088...
                              sym->section->id, sym->value + r->addend))
                              sym->section->id, sym->value + r->addend))
            {
            {
              size_t len;
              size_t len;
 
 
              *s = *syms[i];
              *s = *syms[i];
 
              s->flags |= BSF_SYNTHETIC;
              s->section = sym->section;
              s->section = sym->section;
              s->value = sym->value + r->addend;
              s->value = sym->value + r->addend;
              s->name = names;
              s->name = names;
              *names++ = '.';
              *names++ = '.';
              len = strlen (syms[i]->name);
              len = strlen (syms[i]->name);
Line 2958... Line 3105...
            }
            }
        }
        }
    }
    }
  else
  else
    {
    {
 
      bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
      bfd_byte *contents;
      bfd_byte *contents;
      size_t size;
      size_t size;
 
      long plt_count = 0;
 
      bfd_vma glink_vma = 0, resolv_vma = 0;
 
      asection *dynamic, *glink = NULL, *relplt = NULL;
 
      arelent *p;
 
 
      if (!bfd_malloc_and_get_section (abfd, opd, &contents))
      if (!bfd_malloc_and_get_section (abfd, opd, &contents))
        {
        {
          if (contents)
          if (contents)
            {
            {
Line 2977... Line 3129...
      size = 0;
      size = 0;
      for (i = secsymend; i < opdsymend; ++i)
      for (i = secsymend; i < opdsymend; ++i)
        {
        {
          bfd_vma ent;
          bfd_vma ent;
 
 
 
          /* Ignore bogus symbols.  */
 
          if (syms[i]->value > opd->size - 8)
 
            continue;
 
 
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
            {
              ++count;
              ++count;
              size += sizeof (asymbol);
              size += sizeof (asymbol);
              size += strlen (syms[i]->name) + 2;
              size += strlen (syms[i]->name) + 2;
            }
            }
        }
        }
 
 
 
      /* Get start of .glink stubs from DT_PPC64_GLINK.  */
 
      if (dyn_count != 0
 
          && (dynamic = bfd_get_section_by_name (abfd, ".dynamic")) != NULL)
 
        {
 
          bfd_byte *dynbuf, *extdyn, *extdynend;
 
          size_t extdynsize;
 
          void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *);
 
 
 
          if (!bfd_malloc_and_get_section (abfd, dynamic, &dynbuf))
 
            goto free_contents_and_exit;
 
 
 
          extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn;
 
          swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in;
 
 
 
          extdyn = dynbuf;
 
          extdynend = extdyn + dynamic->size;
 
          for (; extdyn < extdynend; extdyn += extdynsize)
 
            {
 
              Elf_Internal_Dyn dyn;
 
              (*swap_dyn_in) (abfd, extdyn, &dyn);
 
 
 
              if (dyn.d_tag == DT_NULL)
 
                break;
 
 
 
              if (dyn.d_tag == DT_PPC64_GLINK)
 
                {
 
                  /* The first glink stub starts at offset 32; see comment in
 
                     ppc64_elf_finish_dynamic_sections. */
 
                  glink_vma = dyn.d_un.d_val + 32;
 
                  /* The .glink section usually does not survive the final
 
                     link; search for the section (usually .text) where the
 
                     glink stubs now reside.  */
 
                  glink = bfd_sections_find_if (abfd, section_covers_vma,
 
                                                &glink_vma);
 
                  break;
 
                }
 
            }
 
 
 
          free (dynbuf);
 
        }
 
 
 
      if (glink != NULL)
 
        {
 
          /* Determine __glink trampoline by reading the relative branch
 
             from the first glink stub.  */
 
          bfd_byte buf[4];
 
          if (bfd_get_section_contents (abfd, glink, buf,
 
                                        glink_vma + 4 - glink->vma, 4))
 
            {
 
              unsigned int insn = bfd_get_32 (abfd, buf);
 
              insn ^= B_DOT;
 
              if ((insn & ~0x3fffffc) == 0)
 
                resolv_vma = glink_vma + 4 + (insn ^ 0x2000000) - 0x2000000;
 
            }
 
 
 
          if (resolv_vma)
 
            size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
 
 
 
          relplt = bfd_get_section_by_name (abfd, ".rela.plt");
 
          if (relplt != NULL)
 
            {
 
              slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
 
              if (! (*slurp_relocs) (abfd, relplt, dyn_syms, TRUE))
 
                goto free_contents_and_exit;
 
 
 
              plt_count = relplt->size / sizeof (Elf64_External_Rela);
 
              size += plt_count * sizeof (asymbol);
 
 
 
              p = relplt->relocation;
 
              for (i = 0; i < plt_count; i++, p++)
 
                {
 
                  size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
 
                  if (p->addend != 0)
 
                    size += sizeof ("+0x") - 1 + 16;
 
                }
 
            }
 
        }
 
 
      s = *ret = bfd_malloc (size);
      s = *ret = bfd_malloc (size);
      if (s == NULL)
      if (s == NULL)
        goto free_contents_and_exit;
        goto free_contents_and_exit;
 
 
      names = (char *) (s + count);
      names = (char *) (s + count + plt_count + (resolv_vma != 0));
 
 
      for (i = secsymend; i < opdsymend; ++i)
      for (i = secsymend; i < opdsymend; ++i)
        {
        {
          bfd_vma ent;
          bfd_vma ent;
 
 
 
          if (syms[i]->value > opd->size - 8)
 
            continue;
 
 
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          ent = bfd_get_64 (abfd, contents + syms[i]->value);
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
          if (!sym_exists_at (syms, opdsymend, symcount, -1, ent))
            {
            {
              long lo, hi;
              long lo, hi;
              size_t len;
              size_t len;
Line 3033... Line 3270...
                      || (sec->flags & SEC_LOAD) == 0)
                      || (sec->flags & SEC_LOAD) == 0)
                    break;
                    break;
                  if ((sec->flags & SEC_CODE) != 0)
                  if ((sec->flags & SEC_CODE) != 0)
                    s->section = sec;
                    s->section = sec;
                }
                }
 
              s->flags |= BSF_SYNTHETIC;
              s->value = ent - s->section->vma;
              s->value = ent - s->section->vma;
              s->name = names;
              s->name = names;
              *names++ = '.';
              *names++ = '.';
              len = strlen (syms[i]->name);
              len = strlen (syms[i]->name);
              memcpy (names, syms[i]->name, len + 1);
              memcpy (names, syms[i]->name, len + 1);
Line 3046... Line 3284...
              s->udata.p = syms[i];
              s->udata.p = syms[i];
              s++;
              s++;
            }
            }
        }
        }
      free (contents);
      free (contents);
 
 
 
      if (glink != NULL && relplt != NULL)
 
        {
 
          if (resolv_vma)
 
            {
 
              /* Add a symbol for the main glink trampoline.  */
 
              memset (s, 0, sizeof *s);
 
              s->the_bfd = abfd;
 
              s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
 
              s->section = glink;
 
              s->value = resolv_vma - glink->vma;
 
              s->name = names;
 
              memcpy (names, "__glink_PLTresolve", sizeof ("__glink_PLTresolve"));
 
              names += sizeof ("__glink_PLTresolve");
 
              s++;
 
              count++;
 
            }
 
 
 
          /* FIXME: It would be very much nicer to put sym@plt on the
 
             stub rather than on the glink branch table entry.  The
 
             objdump disassembler would then use a sensible symbol
 
             name on plt calls.  The difficulty in doing so is
 
             a) finding the stubs, and,
 
             b) matching stubs against plt entries, and,
 
             c) there can be multiple stubs for a given plt entry.
 
 
 
             Solving (a) could be done by code scanning, but older
 
             ppc64 binaries used different stubs to current code.
 
             (b) is the tricky one since you need to known the toc
 
             pointer for at least one function that uses a pic stub to
 
             be able to calculate the plt address referenced.
 
             (c) means gdb would need to set multiple breakpoints (or
 
             find the glink branch itself) when setting breakpoints
 
             for pending shared library loads.  */
 
          p = relplt->relocation;
 
          for (i = 0; i < plt_count; i++, p++)
 
            {
 
              size_t len;
 
 
 
              *s = **p->sym_ptr_ptr;
 
              /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL set.  Since
 
                 we are defining a symbol, ensure one of them is set.  */
 
              if ((s->flags & BSF_LOCAL) == 0)
 
                s->flags |= BSF_GLOBAL;
 
              s->flags |= BSF_SYNTHETIC;
 
              s->section = glink;
 
              s->value = glink_vma - glink->vma;
 
              s->name = names;
 
              s->udata.p = NULL;
 
              len = strlen ((*p->sym_ptr_ptr)->name);
 
              memcpy (names, (*p->sym_ptr_ptr)->name, len);
 
              names += len;
 
              if (p->addend != 0)
 
                {
 
                  memcpy (names, "+0x", sizeof ("+0x") - 1);
 
                  names += sizeof ("+0x") - 1;
 
                  bfd_sprintf_vma (abfd, names, p->addend);
 
                  names += strlen (names);
 
                }
 
              memcpy (names, "@plt", sizeof ("@plt"));
 
              names += sizeof ("@plt");
 
              s++;
 
              glink_vma += 8;
 
              if (i >= 0x8000)
 
                glink_vma += 4;
 
            }
 
          count += plt_count;
 
        }
    }
    }
 
 
 done:
 done:
  free (syms);
  free (syms);
  return count;
  return count;
Line 3189... Line 3495...
      bfd_signed_vma refcount;
      bfd_signed_vma refcount;
      bfd_vma offset;
      bfd_vma offset;
    } plt;
    } plt;
};
};
 
 
/* Of those relocs that might be copied as dynamic relocs, this macro
/* Of those relocs that might be copied as dynamic relocs, this function
   selects those that must be copied when linking a shared library,
   selects those that must be copied when linking a shared library,
   even when the symbol is local.  */
   even when the symbol is local.  */
 
 
#define MUST_BE_DYN_RELOC(RTYPE)                \
static int
  ((RTYPE) != R_PPC64_REL32                     \
must_be_dyn_reloc (struct bfd_link_info *info,
   && (RTYPE) != R_PPC64_REL64                  \
                   enum elf_ppc64_reloc_type r_type)
   && (RTYPE) != R_PPC64_REL30)
{
 
  switch (r_type)
 
    {
 
    default:
 
      return 1;
 
 
 
    case R_PPC64_REL32:
 
    case R_PPC64_REL64:
 
    case R_PPC64_REL30:
 
      return 0;
 
 
 
    case R_PPC64_TPREL16:
 
    case R_PPC64_TPREL16_LO:
 
    case R_PPC64_TPREL16_HI:
 
    case R_PPC64_TPREL16_HA:
 
    case R_PPC64_TPREL16_DS:
 
    case R_PPC64_TPREL16_LO_DS:
 
    case R_PPC64_TPREL16_HIGHER:
 
    case R_PPC64_TPREL16_HIGHERA:
 
    case R_PPC64_TPREL16_HIGHEST:
 
    case R_PPC64_TPREL16_HIGHESTA:
 
    case R_PPC64_TPREL64:
 
      return !info->executable;
 
    }
 
}
 
 
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid
   copying dynamic variables from a shared lib into an app's dynbss
   copying dynamic variables from a shared lib into an app's dynbss
   section, and instead use a dynamic relocation to point into the
   section, and instead use a dynamic relocation to point into the
   shared lib.  With code that gcc generates, it's vital that this be
   shared lib.  With code that gcc generates, it's vital that this be
Line 3295... Line 3625...
  bfd_vma target_value;
  bfd_vma target_value;
  asection *target_section;
  asection *target_section;
 
 
  /* The symbol table entry, if any, that this was derived from.  */
  /* The symbol table entry, if any, that this was derived from.  */
  struct ppc_link_hash_entry *h;
  struct ppc_link_hash_entry *h;
 
  struct plt_entry *plt_ent;
 
 
  /* And the reloc addend that this was derived from.  */
  /* And the reloc addend that this was derived from.  */
  bfd_vma addend;
  bfd_vma addend;
 
 
  /* Where this stub is being called from, or, in the case of combined
  /* Where this stub is being called from, or, in the case of combined
Line 3363... Line 3694...
#define TLS_TPREL        4      /* TPREL reloc, => IE. */
#define TLS_TPREL        4      /* TPREL reloc, => IE. */
#define TLS_DTPREL       8      /* DTPREL reloc, => LD. */
#define TLS_DTPREL       8      /* DTPREL reloc, => LD. */
#define TLS_TLS         16      /* Any TLS reloc.  */
#define TLS_TLS         16      /* Any TLS reloc.  */
#define TLS_EXPLICIT    32      /* Marks TOC section TLS relocs. */
#define TLS_EXPLICIT    32      /* Marks TOC section TLS relocs. */
#define TLS_TPRELGD     64      /* TPREL reloc resulting from GD->IE. */
#define TLS_TPRELGD     64      /* TPREL reloc resulting from GD->IE. */
 
#define PLT_IFUNC      128      /* STT_GNU_IFUNC.  */
  char tls_mask;
  char tls_mask;
};
};
 
 
/* ppc64 ELF linker hash table.  */
/* ppc64 ELF linker hash table.  */
 
 
Line 3398... Line 3730...
    bfd_vma toc_off;
    bfd_vma toc_off;
  } *stub_group;
  } *stub_group;
 
 
  /* Temp used when calculating TOC pointers.  */
  /* Temp used when calculating TOC pointers.  */
  bfd_vma toc_curr;
  bfd_vma toc_curr;
 
  bfd *toc_bfd;
 
  asection *toc_first_sec;
 
 
  /* Highest input section id.  */
  /* Highest input section id.  */
  int top_id;
  int top_id;
 
 
  /* Highest output section index.  */
  /* Highest output section index.  */
Line 3415... Line 3749...
 
 
  /* Short-cuts to get to dynamic linker sections.  */
  /* Short-cuts to get to dynamic linker sections.  */
  asection *got;
  asection *got;
  asection *plt;
  asection *plt;
  asection *relplt;
  asection *relplt;
 
  asection *iplt;
 
  asection *reliplt;
  asection *dynbss;
  asection *dynbss;
  asection *relbss;
  asection *relbss;
  asection *glink;
  asection *glink;
  asection *sfpr;
  asection *sfpr;
  asection *brlt;
  asection *brlt;
Line 3435... Line 3771...
  unsigned long stub_globals;
  unsigned long stub_globals;
 
 
  /* 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.  */
 
  unsigned int no_tls_get_addr_opt:1;
 
 
  /* Support for multiple toc sections.  */
  /* Support for multiple toc sections.  */
  unsigned int no_multi_toc:1;
  unsigned int no_multi_toc:1;
  unsigned int multi_toc_needed:1;
  unsigned int multi_toc_needed:1;
 
 
  /* Set on error.  */
  /* Set on error.  */
  unsigned int stub_error:1;
  unsigned int stub_error:1;
 
 
  /* Temp used by ppc64_elf_check_directives.  */
  /* Temp used by ppc64_elf_process_dot_syms.  */
  unsigned int twiddled_syms:1;
  unsigned int twiddled_syms:1;
 
 
  /* Incremented every time we size stubs.  */
  /* Incremented every time we size stubs.  */
  unsigned int stub_iteration;
  unsigned int stub_iteration;
 
 
  /* Small local sym to section mapping cache.  */
  /* Small local sym cache.  */
  struct sym_sec_cache sym_sec;
  struct sym_cache sym_cache;
};
};
 
 
/* Rename some of the generic section flags to better document how they
/* Rename some of the generic section flags to better document how they
   are used here.  */
   are used here.  */
#define has_toc_reloc has_gp_reloc
#define has_toc_reloc has_gp_reloc
Line 3839... Line 4178...
                                                    flags);
                                                    flags);
  if (htab->glink == NULL
  if (htab->glink == NULL
      || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
      || ! bfd_set_section_alignment (dynobj, htab->glink, 3))
    return FALSE;
    return FALSE;
 
 
 
  flags = SEC_ALLOC | SEC_LINKER_CREATED;
 
  htab->iplt = bfd_make_section_anyway_with_flags (dynobj, ".iplt", flags);
 
  if (htab->iplt == NULL
 
      || ! bfd_set_section_alignment (dynobj, htab->iplt, 3))
 
    return FALSE;
 
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
 
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
  htab->reliplt = bfd_make_section_anyway_with_flags (dynobj,
 
                                                      ".rela.iplt",
 
                                                      flags);
 
  if (htab->reliplt == NULL
 
      || ! bfd_set_section_alignment (dynobj, htab->reliplt, 3))
 
    return FALSE;
 
 
  /* Create branch lookup table for plt_branch stubs.  */
  /* Create branch lookup table for plt_branch stubs.  */
  flags = (SEC_ALLOC | SEC_LOAD
  flags = (SEC_ALLOC | SEC_LOAD
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
  htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
  htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt",
                                                   flags);
                                                   flags);
Line 3856... Line 4210...
  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
           | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED);
  htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
  htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj,
                                                      ".rela.branch_lt",
                                                      ".rela.branch_lt",
                                                      flags);
                                                      flags);
  if (!htab->relbrlt
  if (htab->relbrlt == NULL
      || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
      || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3))
    return FALSE;
    return FALSE;
 
 
  return TRUE;
  return TRUE;
}
}
Line 3931... Line 4285...
    abort ();
    abort ();
 
 
  return TRUE;
  return TRUE;
}
}
 
 
 
/* Follow indirect and warning symbol links.  */
 
 
 
static inline struct bfd_link_hash_entry *
 
follow_link (struct bfd_link_hash_entry *h)
 
{
 
  while (h->type == bfd_link_hash_indirect
 
         || h->type == bfd_link_hash_warning)
 
    h = h->u.i.link;
 
  return h;
 
}
 
 
 
static inline struct elf_link_hash_entry *
 
elf_follow_link (struct elf_link_hash_entry *h)
 
{
 
  return (struct elf_link_hash_entry *) follow_link (&h->root);
 
}
 
 
 
static inline struct ppc_link_hash_entry *
 
ppc_follow_link (struct ppc_link_hash_entry *h)
 
{
 
  return (struct ppc_link_hash_entry *) follow_link (&h->elf.root);
 
}
 
 
/* Merge PLT info on FROM with that on TO.  */
/* Merge PLT info on FROM with that on TO.  */
 
 
static void
static void
move_plt_plist (struct ppc_link_hash_entry *from,
move_plt_plist (struct ppc_link_hash_entry *from,
                struct ppc_link_hash_entry *to)
                struct ppc_link_hash_entry *to)
Line 4013... Line 4390...
    }
    }
 
 
  edir->is_func |= eind->is_func;
  edir->is_func |= eind->is_func;
  edir->is_func_descriptor |= eind->is_func_descriptor;
  edir->is_func_descriptor |= eind->is_func_descriptor;
  edir->tls_mask |= eind->tls_mask;
  edir->tls_mask |= eind->tls_mask;
 
  if (eind->oh != NULL)
 
    edir->oh = ppc_follow_link (eind->oh);
 
 
  /* If called to transfer flags for a weakdef during processing
  /* If called to transfer flags for a weakdef during processing
     of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
     of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF.
     We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
     We clear it ourselves for ELIMINATE_COPY_RELOCS.  */
  if (!(ELIMINATE_COPY_RELOCS
  if (!(ELIMINATE_COPY_RELOCS
Line 4082... Line 4461...
 
 
/* Find the function descriptor hash entry from the given function code
/* Find the function descriptor hash entry from the given function code
   hash entry FH.  Link the entries via their OH fields.  */
   hash entry FH.  Link the entries via their OH fields.  */
 
 
static struct ppc_link_hash_entry *
static struct ppc_link_hash_entry *
get_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
lookup_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab)
{
{
  struct ppc_link_hash_entry *fdh = fh->oh;
  struct ppc_link_hash_entry *fdh = fh->oh;
 
 
  if (fdh == NULL)
  if (fdh == NULL)
    {
    {
      const char *fd_name = fh->elf.root.root.string + 1;
      const char *fd_name = fh->elf.root.root.string + 1;
 
 
      fdh = (struct ppc_link_hash_entry *)
      fdh = (struct ppc_link_hash_entry *)
        elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
        elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE);
      if (fdh != NULL)
      if (fdh == NULL)
        {
        return fdh;
 
 
          fdh->is_func_descriptor = 1;
          fdh->is_func_descriptor = 1;
          fdh->oh = fh;
          fdh->oh = fh;
          fh->is_func = 1;
          fh->is_func = 1;
          fh->oh = fdh;
          fh->oh = fdh;
        }
        }
    }
 
 
 
  return fdh;
  return ppc_follow_link (fdh);
}
}
 
 
/* Make a fake function descriptor sym for the code sym FH.  */
/* Make a fake function descriptor sym for the code sym FH.  */
 
 
static struct ppc_link_hash_entry *
static struct ppc_link_hash_entry *
Line 4144... Line 4523...
/* Fix function descriptor symbols defined in .opd sections to be
/* Fix function descriptor symbols defined in .opd sections to be
   function type.  */
   function type.  */
 
 
static bfd_boolean
static bfd_boolean
ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
ppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED,
                           struct bfd_link_info *info ATTRIBUTE_UNUSED,
                           struct bfd_link_info *info,
                           Elf_Internal_Sym *isym,
                           Elf_Internal_Sym *isym,
                           const char **name ATTRIBUTE_UNUSED,
                           const char **name ATTRIBUTE_UNUSED,
                           flagword *flags ATTRIBUTE_UNUSED,
                           flagword *flags ATTRIBUTE_UNUSED,
                           asection **sec,
                           asection **sec,
                           bfd_vma *value ATTRIBUTE_UNUSED)
                           bfd_vma *value ATTRIBUTE_UNUSED)
{
{
  if (*sec != NULL
  if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
 
    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
 
  else if (ELF_ST_TYPE (isym->st_info) == STT_FUNC)
 
    ;
 
  else if (*sec != NULL
      && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
      && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0)
    isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
    isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC);
 
 
  return TRUE;
  return TRUE;
}
}
Line 4219... Line 4602...
 
 
  if (eh->elf.root.root.string[0] != '.')
  if (eh->elf.root.root.string[0] != '.')
    abort ();
    abort ();
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
  fdh = get_fdh (eh, htab);
  fdh = lookup_fdh (eh, htab);
  if (fdh == NULL
  if (fdh == NULL)
      && !info->relocatable
    {
 
      if (!info->relocatable
      && (eh->elf.root.type == bfd_link_hash_undefined
      && (eh->elf.root.type == bfd_link_hash_undefined
          || eh->elf.root.type == bfd_link_hash_undefweak)
          || eh->elf.root.type == bfd_link_hash_undefweak)
      && eh->elf.ref_regular)
      && eh->elf.ref_regular)
    {
    {
      /* Make an undefweak function descriptor sym, which is enough to
      /* Make an undefweak function descriptor sym, which is enough to
         pull in an --as-needed shared lib, but won't cause link
         pull in an --as-needed shared lib, but won't cause link
         errors.  Archives are handled elsewhere.  */
         errors.  Archives are handled elsewhere.  */
      fdh = make_fdh (info, eh);
      fdh = make_fdh (info, eh);
      if (fdh == NULL)
      if (fdh == NULL)
        return FALSE;
        return FALSE;
      else
 
        fdh->elf.ref_regular = 1;
        fdh->elf.ref_regular = 1;
    }
    }
  else if (fdh != NULL)
    }
 
  else
    {
    {
      unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
      unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1;
      unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
      unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1;
      if (entry_vis < descr_vis)
      if (entry_vis < descr_vis)
        fdh->elf.other += entry_vis - descr_vis;
        fdh->elf.other += entry_vis - descr_vis;
Line 4260... Line 4644...
}
}
 
 
/* Process list of dot-symbols we made in link_hash_newfunc.  */
/* Process list of dot-symbols we made in link_hash_newfunc.  */
 
 
static bfd_boolean
static bfd_boolean
ppc64_elf_check_directives (bfd *ibfd, struct bfd_link_info *info)
ppc64_elf_process_dot_syms (bfd *ibfd, struct bfd_link_info *info)
{
{
  struct ppc_link_hash_table *htab;
  struct ppc_link_hash_table *htab;
  struct ppc_link_hash_entry **p, *eh;
  struct ppc_link_hash_entry **p, *eh;
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
Line 4310... Line 4694...
{
{
  ppc_hash_table (info)->dot_syms = NULL;
  ppc_hash_table (info)->dot_syms = NULL;
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static struct plt_entry **
update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
                       unsigned long r_symndx, bfd_vma r_addend, int tls_type)
                       unsigned long r_symndx, bfd_vma r_addend, int tls_type)
{
{
  struct got_entry **local_got_ents = elf_local_got_ents (abfd);
  struct got_entry **local_got_ents = elf_local_got_ents (abfd);
 
  struct plt_entry **local_plt;
  char *local_got_tls_masks;
  char *local_got_tls_masks;
 
 
  if (local_got_ents == NULL)
  if (local_got_ents == NULL)
    {
    {
      bfd_size_type size = symtab_hdr->sh_info;
      bfd_size_type size = symtab_hdr->sh_info;
 
 
      size *= sizeof (*local_got_ents) + sizeof (*local_got_tls_masks);
      size *= (sizeof (*local_got_ents)
 
               + sizeof (*local_plt)
 
               + sizeof (*local_got_tls_masks));
      local_got_ents = bfd_zalloc (abfd, size);
      local_got_ents = bfd_zalloc (abfd, size);
      if (local_got_ents == NULL)
      if (local_got_ents == NULL)
        return FALSE;
        return NULL;
      elf_local_got_ents (abfd) = local_got_ents;
      elf_local_got_ents (abfd) = local_got_ents;
    }
    }
 
 
  if ((tls_type & TLS_EXPLICIT) == 0)
  if ((tls_type & (PLT_IFUNC | TLS_EXPLICIT)) == 0)
    {
    {
      struct got_entry *ent;
      struct got_entry *ent;
 
 
      for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next)
      for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next)
        if (ent->addend == r_addend
        if (ent->addend == r_addend
Line 4353... Line 4740...
          local_got_ents[r_symndx] = ent;
          local_got_ents[r_symndx] = ent;
        }
        }
      ent->got.refcount += 1;
      ent->got.refcount += 1;
    }
    }
 
 
  local_got_tls_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
  local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info);
 
  local_got_tls_masks = (char *) (local_plt + symtab_hdr->sh_info);
  local_got_tls_masks[r_symndx] |= tls_type;
  local_got_tls_masks[r_symndx] |= tls_type;
  return TRUE;
 
 
  return local_plt + r_symndx;
}
}
 
 
static bfd_boolean
static bfd_boolean
update_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend)
update_plt_info (bfd *abfd, struct plt_entry **plist, bfd_vma addend)
{
{
  struct plt_entry *ent;
  struct plt_entry *ent;
 
 
  for (ent = eh->elf.plt.plist; ent != NULL; ent = ent->next)
  for (ent = *plist; ent != NULL; ent = ent->next)
    if (ent->addend == addend)
    if (ent->addend == addend)
      break;
      break;
  if (ent == NULL)
  if (ent == NULL)
    {
    {
      bfd_size_type amt = sizeof (*ent);
      bfd_size_type amt = sizeof (*ent);
      ent = bfd_alloc (abfd, amt);
      ent = bfd_alloc (abfd, amt);
      if (ent == NULL)
      if (ent == NULL)
        return FALSE;
        return FALSE;
      ent->next = eh->elf.plt.plist;
      ent->next = *plist;
      ent->addend = addend;
      ent->addend = addend;
      ent->plt.refcount = 0;
      ent->plt.refcount = 0;
      eh->elf.plt.plist = ent;
      *plist = ent;
    }
    }
  ent->plt.refcount += 1;
  ent->plt.refcount += 1;
  eh->elf.needs_plt = 1;
 
  if (eh->elf.root.root.string[0] == '.'
 
      && eh->elf.root.root.string[1] != '\0')
 
    eh->is_func = 1;
 
  return TRUE;
  return TRUE;
}
}
 
 
 
static bfd_boolean
 
is_branch_reloc (enum elf_ppc64_reloc_type r_type)
 
{
 
  return (r_type == R_PPC64_REL24
 
          || r_type == R_PPC64_REL14
 
          || r_type == R_PPC64_REL14_BRTAKEN
 
          || r_type == R_PPC64_REL14_BRNTAKEN
 
          || r_type == R_PPC64_ADDR24
 
          || r_type == R_PPC64_ADDR14
 
          || r_type == R_PPC64_ADDR14_BRTAKEN
 
          || r_type == R_PPC64_ADDR14_BRNTAKEN);
 
}
 
 
/* Look through the relocs for a section during the first phase, and
/* Look through the relocs for a section during the first phase, and
   calculate needed space in the global offset table, procedure
   calculate needed space in the global offset table, procedure
   linkage table, and dynamic reloc sections.  */
   linkage table, and dynamic reloc sections.  */
 
 
static bfd_boolean
static bfd_boolean
Line 4400... Line 4798...
  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
  struct elf_link_hash_entry **sym_hashes, **sym_hashes_end;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel_end;
  const Elf_Internal_Rela *rel_end;
  asection *sreloc;
  asection *sreloc;
  asection **opd_sym_map;
  asection **opd_sym_map;
 
  struct elf_link_hash_entry *tga, *dottga;
 
 
  if (info->relocatable)
  if (info->relocatable)
    return TRUE;
    return TRUE;
 
 
  /* Don't do anything special with non-loaded, non-alloced sections.
  /* Don't do anything special with non-loaded, non-alloced sections.
Line 4416... Line 4815...
    return TRUE;
    return TRUE;
 
 
  BFD_ASSERT (is_ppc64_elf (abfd));
  BFD_ASSERT (is_ppc64_elf (abfd));
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
 
  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
 
                              FALSE, FALSE, TRUE);
 
  dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
 
                                 FALSE, FALSE, TRUE);
  symtab_hdr = &elf_symtab_hdr (abfd);
  symtab_hdr = &elf_symtab_hdr (abfd);
 
 
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes = elf_sym_hashes (abfd);
  sym_hashes_end = (sym_hashes
  sym_hashes_end = (sym_hashes
                    + symtab_hdr->sh_size / sizeof (Elf64_External_Sym)
                    + symtab_hdr->sh_size / sizeof (Elf64_External_Sym)
Line 4455... Line 4858...
  for (rel = relocs; rel < rel_end; rel++)
  for (rel = relocs; rel < rel_end; rel++)
    {
    {
      unsigned long r_symndx;
      unsigned long r_symndx;
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
      enum elf_ppc64_reloc_type r_type;
      enum elf_ppc64_reloc_type r_type;
      int tls_type = 0;
      int tls_type;
      struct _ppc64_elf_section_data *ppc64_sec;
      struct _ppc64_elf_section_data *ppc64_sec;
 
      struct plt_entry **ifunc;
 
 
      r_symndx = ELF64_R_SYM (rel->r_info);
      r_symndx = ELF64_R_SYM (rel->r_info);
      if (r_symndx < symtab_hdr->sh_info)
      if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
        h = NULL;
      else
      else
        {
        {
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
          h = elf_follow_link (h);
                 || h->root.type == bfd_link_hash_warning)
 
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
        }
        }
 
 
      r_type = ELF64_R_TYPE (rel->r_info);
      tls_type = 0;
      switch (r_type)
      ifunc = NULL;
 
      if (h != NULL)
        {
        {
        case R_PPC64_GOT_TLSLD16:
          if (h->type == STT_GNU_IFUNC)
        case R_PPC64_GOT_TLSLD16_LO:
            {
        case R_PPC64_GOT_TLSLD16_HI:
              h->needs_plt = 1;
        case R_PPC64_GOT_TLSLD16_HA:
              ifunc = &h->plt.plist;
          tls_type = TLS_TLS | TLS_LD;
            }
          goto dogottls;
        }
 
      else
 
        {
 
          Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                                          abfd, r_symndx);
 
          if (isym == NULL)
 
            return FALSE;
 
 
        case R_PPC64_GOT_TLSGD16:
          if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
        case R_PPC64_GOT_TLSGD16_LO:
            {
        case R_PPC64_GOT_TLSGD16_HI:
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
        case R_PPC64_GOT_TLSGD16_HA:
                                             rel->r_addend, PLT_IFUNC);
          tls_type = TLS_TLS | TLS_GD;
              if (ifunc == NULL)
 
                return FALSE;
 
            }
 
        }
 
      r_type = ELF64_R_TYPE (rel->r_info);
 
      if (is_branch_reloc (r_type))
 
        {
 
          if (h != NULL && (h == tga || h == dottga))
 
            {
 
              if (rel != relocs
 
                  && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
 
                      || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
 
                /* We have a new-style __tls_get_addr call with a marker
 
                   reloc.  */
 
                ;
 
              else
 
                /* Mark this section as having an old-style call.  */
 
                sec->has_tls_get_addr_call = 1;
 
            }
 
 
 
          /* STT_GNU_IFUNC symbols must have a PLT entry.  */
 
          if (ifunc != NULL
 
              && !update_plt_info (abfd, ifunc, rel->r_addend))
 
            return FALSE;
 
        }
 
 
 
      switch (r_type)
 
        {
 
        case R_PPC64_TLSGD:
 
        case R_PPC64_TLSLD:
 
          /* These special tls relocs tie a call to __tls_get_addr with
 
             its parameter symbol.  */
 
          break;
 
 
 
        case R_PPC64_GOT_TLSLD16:
 
        case R_PPC64_GOT_TLSLD16_LO:
 
        case R_PPC64_GOT_TLSLD16_HI:
 
        case R_PPC64_GOT_TLSLD16_HA:
 
          tls_type = TLS_TLS | TLS_LD;
 
          goto dogottls;
 
 
 
        case R_PPC64_GOT_TLSGD16:
 
        case R_PPC64_GOT_TLSGD16_LO:
 
        case R_PPC64_GOT_TLSGD16_HI:
 
        case R_PPC64_GOT_TLSGD16_HA:
 
          tls_type = TLS_TLS | TLS_GD;
          goto dogottls;
          goto dogottls;
 
 
        case R_PPC64_GOT_TPREL16_DS:
        case R_PPC64_GOT_TPREL16_DS:
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_TPREL16_LO_DS:
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
        case R_PPC64_GOT_TPREL16_HA:
          if (info->shared)
          if (!info->executable)
            info->flags |= DF_STATIC_TLS;
            info->flags |= DF_STATIC_TLS;
          tls_type = TLS_TLS | TLS_TPREL;
          tls_type = TLS_TLS | TLS_TPREL;
          goto dogottls;
          goto dogottls;
 
 
        case R_PPC64_GOT_DTPREL16_DS:
        case R_PPC64_GOT_DTPREL16_DS:
Line 4568... Line 5022...
                 table entry for a local symbol.  */
                 table entry for a local symbol.  */
              bfd_set_error (bfd_error_bad_value);
              bfd_set_error (bfd_error_bad_value);
              return FALSE;
              return FALSE;
            }
            }
          else
          else
            if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
            {
                                  rel->r_addend))
              if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
              return FALSE;
              return FALSE;
 
              h->needs_plt = 1;
 
              if (h->root.root.string[0] == '.'
 
                  && h->root.root.string[1] != '\0')
 
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
 
            }
          break;
          break;
 
 
          /* The following relocations don't need to propagate the
          /* The following relocations don't need to propagate the
             relocation if linking a shared object since they are
             relocation if linking a shared object since they are
             section relative.  */
             section relative.  */
Line 4595... Line 5054...
        case R_PPC64_DTPREL16_HIGHEST:
        case R_PPC64_DTPREL16_HIGHEST:
        case R_PPC64_DTPREL16_HIGHESTA:
        case R_PPC64_DTPREL16_HIGHESTA:
          break;
          break;
 
 
          /* Nor do these.  */
          /* Nor do these.  */
 
        case R_PPC64_REL16:
 
        case R_PPC64_REL16_LO:
 
        case R_PPC64_REL16_HI:
 
        case R_PPC64_REL16_HA:
 
          break;
 
 
        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 4636... Line 5101...
                   don't assume we know where a weak sym lives.  */
                   don't assume we know where a weak sym lives.  */
                if (h->root.type == bfd_link_hash_defined)
                if (h->root.type == bfd_link_hash_defined)
                  dest = h->root.u.def.section;
                  dest = h->root.u.def.section;
              }
              }
            else
            else
              dest = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
              {
                                                sec, r_symndx);
                Elf_Internal_Sym *isym;
 
 
 
                isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                              abfd, r_symndx);
 
                if (isym == NULL)
 
                  return FALSE;
 
 
 
                dest = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
              }
 
 
            if (dest != sec)
            if (dest != sec)
              ppc64_elf_section_data (sec)->has_14bit_branch = 1;
              ppc64_elf_section_data (sec)->has_14bit_branch = 1;
          }
          }
          /* Fall through.  */
          /* Fall through.  */
 
 
        case R_PPC64_REL24:
        case R_PPC64_REL24:
          if (h != NULL)
          if (h != NULL && ifunc == NULL)
            {
            {
              /* We may need a .plt entry if the function this reloc
              /* We may need a .plt entry if the function this reloc
                 refers to is in a shared lib.  */
                 refers to is in a shared lib.  */
              if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
              if (!update_plt_info (abfd, &h->plt.plist, rel->r_addend))
                                    rel->r_addend))
 
                return FALSE;
                return FALSE;
              if (h == &htab->tls_get_addr->elf
              h->needs_plt = 1;
                  || h == &htab->tls_get_addr_fd->elf)
              if (h->root.root.string[0] == '.'
                sec->has_tls_reloc = 1;
                  && h->root.root.string[1] != '\0')
              else if (htab->tls_get_addr == NULL
                ((struct ppc_link_hash_entry *) h)->is_func = 1;
                       && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr")
              if (h == tga || h == dottga)
                       && (h->root.root.string[15] == 0
 
                           || h->root.root.string[15] == '@'))
 
                {
 
                  htab->tls_get_addr = (struct ppc_link_hash_entry *) h;
 
                  sec->has_tls_reloc = 1;
 
                }
 
              else if (htab->tls_get_addr_fd == NULL
 
                       && CONST_STRNEQ (h->root.root.string, "__tls_get_addr")
 
                       && (h->root.root.string[14] == 0
 
                           || h->root.root.string[14] == '@'))
 
                {
 
                  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h;
 
                  sec->has_tls_reloc = 1;
                  sec->has_tls_reloc = 1;
                }
                }
            }
 
          break;
          break;
 
 
        case R_PPC64_TPREL64:
        case R_PPC64_TPREL64:
          tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
          tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL;
          if (info->shared)
          if (!info->executable)
            info->flags |= DF_STATIC_TLS;
            info->flags |= DF_STATIC_TLS;
          goto dotlstoc;
          goto dotlstoc;
 
 
        case R_PPC64_DTPMOD64:
        case R_PPC64_DTPMOD64:
          if (rel + 1 < rel_end
          if (rel + 1 < rel_end
Line 4713... Line 5173...
              return FALSE;
              return FALSE;
 
 
          ppc64_sec = ppc64_elf_section_data (sec);
          ppc64_sec = ppc64_elf_section_data (sec);
          if (ppc64_sec->sec_type != sec_toc)
          if (ppc64_sec->sec_type != sec_toc)
            {
            {
 
              bfd_size_type amt;
 
 
              /* One extra to simplify get_tls_mask.  */
              /* One extra to simplify get_tls_mask.  */
              bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1;
              amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
              ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt);
              ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
              if (ppc64_sec->u.t_symndx == NULL)
              if (ppc64_sec->u.toc.symndx == NULL)
 
                return FALSE;
 
              amt = sec->size * sizeof (bfd_vma) / 8;
 
              ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
 
              if (ppc64_sec->u.toc.add == NULL)
                return FALSE;
                return FALSE;
              BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
              BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
              ppc64_sec->sec_type = sec_toc;
              ppc64_sec->sec_type = sec_toc;
            }
            }
          BFD_ASSERT (rel->r_offset % 8 == 0);
          BFD_ASSERT (rel->r_offset % 8 == 0);
          ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx;
          ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
 
          ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
 
 
          /* Mark the second slot of a GD or LD entry.
          /* Mark the second slot of a GD or LD entry.
             -1 to indicate GD and -2 to indicate LD.  */
             -1 to indicate GD and -2 to indicate LD.  */
          if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD))
          if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD))
            ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1;
            ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1;
          else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD))
          else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD))
            ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2;
            ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2;
          goto dodyn;
          goto dodyn;
 
 
        case R_PPC64_TPREL16:
        case R_PPC64_TPREL16:
        case R_PPC64_TPREL16_LO:
        case R_PPC64_TPREL16_LO:
        case R_PPC64_TPREL16_HI:
        case R_PPC64_TPREL16_HI:
Line 4744... Line 5211...
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
        case R_PPC64_TPREL16_HIGHESTA:
          if (info->shared)
          if (info->shared)
            {
            {
 
              if (!info->executable)
              info->flags |= DF_STATIC_TLS;
              info->flags |= DF_STATIC_TLS;
              goto dodyn;
              goto dodyn;
            }
            }
          break;
          break;
 
 
Line 4758... Line 5226...
            {
            {
              if (h != NULL)
              if (h != NULL)
                {
                {
                  if (h->root.root.string[0] == '.'
                  if (h->root.root.string[0] == '.'
                      && h->root.root.string[1] != 0
                      && h->root.root.string[1] != 0
                      && get_fdh ((struct ppc_link_hash_entry *) h, htab))
                      && lookup_fdh ((struct ppc_link_hash_entry *) h, htab))
                    ;
                    ;
                  else
                  else
                    ((struct ppc_link_hash_entry *) h)->is_func = 1;
                    ((struct ppc_link_hash_entry *) h)->is_func = 1;
                }
                }
              else
              else
                {
                {
                  asection *s;
                  asection *s;
 
                  Elf_Internal_Sym *isym;
 
 
                  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
                  isym = bfd_sym_from_r_symndx (&htab->sym_cache,
                                                 r_symndx);
                                                abfd, r_symndx);
                  if (s == NULL)
                  if (isym == NULL)
                    return FALSE;
                    return FALSE;
                  else if (s != sec)
 
 
                  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
                  if (s != NULL && s != sec)
                    opd_sym_map[rel->r_offset / 8] = s;
                    opd_sym_map[rel->r_offset / 8] = s;
                }
                }
            }
            }
          /* Fall through.  */
          /* Fall through.  */
 
 
Line 4830... Line 5301...
             may need to keep relocations for symbols satisfied by a
             may need to keep relocations for symbols satisfied by a
             dynamic library if we manage to avoid copy relocs for the
             dynamic library if we manage to avoid copy relocs for the
             symbol.  */
             symbol.  */
        dodyn:
        dodyn:
          if ((info->shared
          if ((info->shared
               && (MUST_BE_DYN_RELOC (r_type)
               && (must_be_dyn_reloc (info, r_type)
                   || (h != NULL
                   || (h != NULL
                       && (! info->symbolic
                       && (! info->symbolic
                           || h->root.type == bfd_link_hash_defweak
                           || h->root.type == bfd_link_hash_defweak
                           || !h->def_regular))))
                           || !h->def_regular))))
              || (ELIMINATE_COPY_RELOCS
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && !info->shared
                  && h != NULL
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
                      || !h->def_regular))
 
              || (!info->shared
 
                  && ifunc != NULL))
            {
            {
              struct ppc_dyn_relocs *p;
              struct ppc_dyn_relocs *p;
              struct ppc_dyn_relocs **head;
              struct ppc_dyn_relocs **head;
 
 
              /* We must copy these reloc types into the output file.
              /* We must copy these reloc types into the output file.
                 Create a reloc section in dynobj and make room for
                 Create a reloc section in dynobj and make room for
                 this reloc.  */
                 this reloc.  */
              if (sreloc == NULL)
              if (sreloc == NULL)
                {
                {
                  const char *name;
                  sreloc = _bfd_elf_make_dynamic_reloc_section
                  bfd *dynobj;
                    (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
 
 
                  name = (bfd_elf_string_from_elf_section
 
                          (abfd,
 
                           elf_elfheader (abfd)->e_shstrndx,
 
                           elf_section_data (sec)->rel_hdr.sh_name));
 
                  if (name == NULL)
 
                    return FALSE;
 
 
 
                  if (! CONST_STRNEQ (name, ".rela")
 
                      || strcmp (bfd_get_section_name (abfd, sec),
 
                                 name + 5) != 0)
 
                    {
 
                      (*_bfd_error_handler)
 
                        (_("%B: bad relocation section name `%s\'"),
 
                         abfd, name);
 
                      bfd_set_error (bfd_error_bad_value);
 
                    }
 
 
 
                  dynobj = htab->elf.dynobj;
 
                  sreloc = bfd_get_section_by_name (dynobj, name);
 
                  if (sreloc == NULL)
                  if (sreloc == NULL)
                    {
 
                      flagword flags;
 
 
 
                      flags = (SEC_HAS_CONTENTS | SEC_READONLY
 
                               | SEC_IN_MEMORY | SEC_LINKER_CREATED
 
                               | SEC_ALLOC | SEC_LOAD);
 
                      sreloc = bfd_make_section_with_flags (dynobj,
 
                                                            name,
 
                                                            flags);
 
                      if (sreloc == NULL
 
                          || ! bfd_set_section_alignment (dynobj, sreloc, 3))
 
                        return FALSE;
                        return FALSE;
                    }
                    }
                  elf_section_data (sec)->sreloc = sreloc;
 
                }
 
 
 
              /* If this is a global symbol, we count the number of
              /* If this is a global symbol, we count the number of
                 relocations we need for this symbol.  */
                 relocations we need for this symbol.  */
              if (h != NULL)
              if (h != NULL)
                {
                {
Line 4899... Line 5340...
              else
              else
                {
                {
                  /* Track dynamic relocs needed for local syms too.
                  /* Track dynamic relocs needed for local syms too.
                     We really need local syms available to do this
                     We really need local syms available to do this
                     easily.  Oh well.  */
                     easily.  Oh well.  */
 
 
                  asection *s;
                  asection *s;
                  void *vpp;
                  void *vpp;
 
                  Elf_Internal_Sym *isym;
 
 
                  s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
                  isym = bfd_sym_from_r_symndx (&htab->sym_cache,
                                                 sec, r_symndx);
                                                abfd, r_symndx);
                  if (s == NULL)
                  if (isym == NULL)
                    return FALSE;
                    return FALSE;
 
 
 
                  s = bfd_section_from_elf_index (abfd, isym->st_shndx);
 
                  if (s == NULL)
 
                    s = sec;
 
 
                  vpp = &elf_section_data (s)->local_dynrel;
                  vpp = &elf_section_data (s)->local_dynrel;
                  head = (struct ppc_dyn_relocs **) vpp;
                  head = (struct ppc_dyn_relocs **) vpp;
                }
                }
 
 
              p = *head;
              p = *head;
Line 4926... Line 5371...
                  p->count = 0;
                  p->count = 0;
                  p->pc_count = 0;
                  p->pc_count = 0;
                }
                }
 
 
              p->count += 1;
              p->count += 1;
              if (!MUST_BE_DYN_RELOC (r_type))
              if (!must_be_dyn_reloc (info, r_type))
                p->pc_count += 1;
                p->pc_count += 1;
            }
            }
          break;
          break;
 
 
        default:
        default:
Line 4956... Line 5401...
  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.  */
  if (opd_sec->reloc_count == 0)
  if (opd_sec->reloc_count == 0)
    {
    {
      bfd_vma val;
 
 
 
      if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
      if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8))
        return (bfd_vma) -1;
        return (bfd_vma) -1;
 
 
      if (code_sec != NULL)
      if (code_sec != NULL)
        {
        {
Line 5024... Line 5467...
                      symtab_hdr->contents = (bfd_byte *) sym;
                      symtab_hdr->contents = (bfd_byte *) sym;
                    }
                    }
 
 
                  sym += symndx;
                  sym += symndx;
                  val = sym->st_value;
                  val = sym->st_value;
                  sec = NULL;
 
                  if ((sym->st_shndx != SHN_UNDEF
 
                       && sym->st_shndx < SHN_LORESERVE)
 
                      || sym->st_shndx > SHN_HIRESERVE)
 
                    sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
                    sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx);
                  BFD_ASSERT ((sec->flags & SEC_MERGE) == 0);
                  BFD_ASSERT ((sec->flags & SEC_MERGE) == 0);
                }
                }
              else
              else
                {
                {
                  struct elf_link_hash_entry **sym_hashes;
                  struct elf_link_hash_entry **sym_hashes;
                  struct elf_link_hash_entry *rh;
                  struct elf_link_hash_entry *rh;
 
 
                  sym_hashes = elf_sym_hashes (opd_bfd);
                  sym_hashes = elf_sym_hashes (opd_bfd);
                  rh = sym_hashes[symndx - symtab_hdr->sh_info];
                  rh = sym_hashes[symndx - symtab_hdr->sh_info];
                  while (rh->root.type == bfd_link_hash_indirect
                  rh = elf_follow_link (rh);
                         || rh->root.type == bfd_link_hash_warning)
 
                    rh = ((struct elf_link_hash_entry *) rh->root.u.i.link);
 
                  BFD_ASSERT (rh->root.type == bfd_link_hash_defined
                  BFD_ASSERT (rh->root.type == bfd_link_hash_defined
                              || rh->root.type == bfd_link_hash_defweak);
                              || rh->root.type == bfd_link_hash_defweak);
                  val = rh->root.u.def.value;
                  val = rh->root.u.def.value;
                  sec = rh->root.u.def.section;
                  sec = rh->root.u.def.section;
                }
                }
Line 5061... Line 5498...
    }
    }
 
 
  return val;
  return val;
}
}
 
 
 
/* If FDH is a function descriptor symbol, return the associated code
 
   entry symbol if it is defined.  Return NULL otherwise.  */
 
 
 
static struct ppc_link_hash_entry *
 
defined_code_entry (struct ppc_link_hash_entry *fdh)
 
{
 
  if (fdh->is_func_descriptor)
 
    {
 
      struct ppc_link_hash_entry *fh = ppc_follow_link (fdh->oh);
 
      if (fh->elf.root.type == bfd_link_hash_defined
 
          || fh->elf.root.type == bfd_link_hash_defweak)
 
        return fh;
 
    }
 
  return NULL;
 
}
 
 
 
/* If FH is a function code entry symbol, return the associated
 
   function descriptor symbol if it is defined.  Return NULL otherwise.  */
 
 
 
static struct ppc_link_hash_entry *
 
defined_func_desc (struct ppc_link_hash_entry *fh)
 
{
 
  if (fh->oh != NULL
 
      && fh->oh->is_func_descriptor)
 
    {
 
      struct ppc_link_hash_entry *fdh = ppc_follow_link (fh->oh);
 
      if (fdh->elf.root.type == bfd_link_hash_defined
 
          || fdh->elf.root.type == bfd_link_hash_defweak)
 
        return fdh;
 
    }
 
  return NULL;
 
}
 
 
/* Mark all our entry sym sections, both opd and code section.  */
/* Mark all our entry sym sections, both opd and code section.  */
 
 
static void
static void
ppc64_elf_gc_keep (struct bfd_link_info *info)
ppc64_elf_gc_keep (struct bfd_link_info *info)
{
{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
  struct bfd_sym_chain *sym;
  struct bfd_sym_chain *sym;
 
 
  for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
  for (sym = info->gc_sym_list; sym != NULL; sym = sym->next)
    {
    {
      struct ppc_link_hash_entry *eh;
      struct ppc_link_hash_entry *eh, *fh;
      asection *sec;
      asection *sec;
 
 
      eh = (struct ppc_link_hash_entry *)
      eh = (struct ppc_link_hash_entry *)
        elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE);
        elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, TRUE);
      if (eh == NULL)
      if (eh == NULL)
        continue;
        continue;
      if (eh->elf.root.type != bfd_link_hash_defined
      if (eh->elf.root.type != bfd_link_hash_defined
          && eh->elf.root.type != bfd_link_hash_defweak)
          && eh->elf.root.type != bfd_link_hash_defweak)
        continue;
        continue;
 
 
      if (eh->is_func_descriptor
      fh = defined_code_entry (eh);
          && (eh->oh->elf.root.type == bfd_link_hash_defined
      if (fh != NULL)
              || eh->oh->elf.root.type == bfd_link_hash_defweak))
 
        {
        {
          sec = eh->oh->elf.root.u.def.section;
          sec = fh->elf.root.u.def.section;
          sec->flags |= SEC_KEEP;
          sec->flags |= SEC_KEEP;
        }
        }
      else if (get_opd_info (eh->elf.root.u.def.section) != NULL
      else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
                                   eh->elf.root.u.def.value,
Line 5109... Line 5578...
static bfd_boolean
static bfd_boolean
ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
ppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf)
{
{
  struct bfd_link_info *info = (struct bfd_link_info *) inf;
  struct bfd_link_info *info = (struct bfd_link_info *) inf;
  struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
  struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
 
  struct ppc_link_hash_entry *fdh;
 
 
  if (eh->elf.root.type == bfd_link_hash_warning)
  if (eh->elf.root.type == bfd_link_hash_warning)
    eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
    eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link;
 
 
  /* Dynamic linking info is on the func descriptor sym.  */
  /* Dynamic linking info is on the func descriptor sym.  */
  if (eh->oh != NULL
  fdh = defined_func_desc (eh);
      && eh->oh->is_func_descriptor
  if (fdh != NULL)
      && (eh->oh->elf.root.type == bfd_link_hash_defined
    eh = fdh;
          || eh->oh->elf.root.type == bfd_link_hash_defweak))
 
    eh = eh->oh;
 
 
 
  if ((eh->elf.root.type == bfd_link_hash_defined
  if ((eh->elf.root.type == bfd_link_hash_defined
       || 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)))
    {
    {
      asection *code_sec;
      asection *code_sec;
 
      struct ppc_link_hash_entry *fh;
 
 
      eh->elf.root.u.def.section->flags |= SEC_KEEP;
      eh->elf.root.u.def.section->flags |= SEC_KEEP;
 
 
      /* Function descriptor syms cause the associated
      /* Function descriptor syms cause the associated
         function code sym section to be marked.  */
         function code sym section to be marked.  */
      if (eh->is_func_descriptor
      fh = defined_code_entry (eh);
          && (eh->oh->elf.root.type == bfd_link_hash_defined
      if (fh != NULL)
              || eh->oh->elf.root.type == bfd_link_hash_defweak))
        {
        eh->oh->elf.root.u.def.section->flags |= SEC_KEEP;
          code_sec = fh->elf.root.u.def.section;
 
          code_sec->flags |= SEC_KEEP;
 
        }
      else if (get_opd_info (eh->elf.root.u.def.section) != NULL
      else if (get_opd_info (eh->elf.root.u.def.section) != NULL
               && opd_entry_value (eh->elf.root.u.def.section,
               && opd_entry_value (eh->elf.root.u.def.section,
                                   eh->elf.root.u.def.value,
                                   eh->elf.root.u.def.value,
                                   &code_sec, NULL) != (bfd_vma) -1)
                                   &code_sec, NULL) != (bfd_vma) -1)
        code_sec->flags |= SEC_KEEP;
        code_sec->flags |= SEC_KEEP;
Line 5169... Line 5640...
    return rsec;
    return rsec;
 
 
  if (h != NULL)
  if (h != NULL)
    {
    {
      enum elf_ppc64_reloc_type r_type;
      enum elf_ppc64_reloc_type r_type;
      struct ppc_link_hash_entry *eh;
      struct ppc_link_hash_entry *eh, *fh, *fdh;
 
 
      r_type = ELF64_R_TYPE (rel->r_info);
      r_type = ELF64_R_TYPE (rel->r_info);
      switch (r_type)
      switch (r_type)
        {
        {
        case R_PPC64_GNU_VTINHERIT:
        case R_PPC64_GNU_VTINHERIT:
Line 5184... Line 5655...
          switch (h->root.type)
          switch (h->root.type)
            {
            {
            case bfd_link_hash_defined:
            case bfd_link_hash_defined:
            case bfd_link_hash_defweak:
            case bfd_link_hash_defweak:
              eh = (struct ppc_link_hash_entry *) h;
              eh = (struct ppc_link_hash_entry *) h;
              if (eh->oh != NULL
              fdh = defined_func_desc (eh);
                  && eh->oh->is_func_descriptor
              if (fdh != NULL)
                  && (eh->oh->elf.root.type == bfd_link_hash_defined
                eh = fdh;
                      || eh->oh->elf.root.type == bfd_link_hash_defweak))
 
                eh = eh->oh;
 
 
 
              /* Function descriptor syms cause the associated
              /* Function descriptor syms cause the associated
                 function code sym section to be marked.  */
                 function code sym section to be marked.  */
              if (eh->is_func_descriptor
              fh = defined_code_entry (eh);
                  && (eh->oh->elf.root.type == bfd_link_hash_defined
              if (fh != NULL)
                      || eh->oh->elf.root.type == bfd_link_hash_defweak))
 
                {
                {
                  /* They also mark their opd section.  */
                  /* They also mark their opd section.  */
                  eh->elf.root.u.def.section->gc_mark = 1;
                  eh->elf.root.u.def.section->gc_mark = 1;
 
 
                  rsec = eh->oh->elf.root.u.def.section;
                  rsec = fh->elf.root.u.def.section;
                }
                }
              else if (get_opd_info (eh->elf.root.u.def.section) != NULL
              else if (get_opd_info (eh->elf.root.u.def.section) != NULL
                       && opd_entry_value (eh->elf.root.u.def.section,
                       && opd_entry_value (eh->elf.root.u.def.section,
                                           eh->elf.root.u.def.value,
                                           eh->elf.root.u.def.value,
                                           &rsec, NULL) != (bfd_vma) -1)
                                           &rsec, NULL) != (bfd_vma) -1)
Line 5279... Line 5747...
          struct ppc_link_hash_entry *eh;
          struct ppc_link_hash_entry *eh;
          struct ppc_dyn_relocs **pp;
          struct ppc_dyn_relocs **pp;
          struct ppc_dyn_relocs *p;
          struct ppc_dyn_relocs *p;
 
 
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          h = sym_hashes[r_symndx - symtab_hdr->sh_info];
          while (h->root.type == bfd_link_hash_indirect
          h = elf_follow_link (h);
                 || h->root.type == bfd_link_hash_warning)
 
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
          eh = (struct ppc_link_hash_entry *) h;
          eh = (struct ppc_link_hash_entry *) h;
 
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next)
            if (p->sec == sec)
            if (p->sec == sec)
              {
              {
Line 5293... Line 5759...
                *pp = p->next;
                *pp = p->next;
                break;
                break;
              }
              }
        }
        }
 
 
 
      if (is_branch_reloc (r_type))
 
        {
 
          struct plt_entry **ifunc = NULL;
 
          if (h != NULL)
 
            {
 
              if (h->type == STT_GNU_IFUNC)
 
                ifunc = &h->plt.plist;
 
            }
 
          else if (local_got_ents != NULL)
 
            {
 
              struct plt_entry **local_plt = (struct plt_entry **)
 
                (local_got_ents + symtab_hdr->sh_info);
 
              char *local_got_tls_masks = (char *)
 
                (local_plt + symtab_hdr->sh_info);
 
              if ((local_got_tls_masks[r_symndx] & PLT_IFUNC) != 0)
 
                ifunc = local_plt + r_symndx;
 
            }
 
          if (ifunc != NULL)
 
            {
 
              struct plt_entry *ent;
 
 
 
              for (ent = *ifunc; ent != NULL; ent = ent->next)
 
                if (ent->addend == rel->r_addend)
 
                  break;
 
              if (ent == NULL)
 
                abort ();
 
              if (ent->plt.refcount > 0)
 
                ent->plt.refcount -= 1;
 
              continue;
 
            }
 
        }
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_HI:
        case R_PPC64_GOT_TLSLD16_HI:
Line 5366... Line 5864...
              struct plt_entry *ent;
              struct plt_entry *ent;
 
 
              for (ent = h->plt.plist; ent != NULL; ent = ent->next)
              for (ent = h->plt.plist; ent != NULL; ent = ent->next)
                if (ent->addend == rel->r_addend)
                if (ent->addend == rel->r_addend)
                  break;
                  break;
              if (ent == NULL)
              if (ent != NULL && ent->plt.refcount > 0)
                abort ();
 
              if (ent->plt.refcount > 0)
 
                ent->plt.refcount -= 1;
                ent->plt.refcount -= 1;
            }
            }
          break;
          break;
 
 
        default:
        default:
Line 5635... Line 6131...
     in the function descriptor, if we have one in a regular object.
     in the function descriptor, if we have one in a regular object.
     This is to satisfy cases like ".quad .foo".  Calls to functions
     This is to satisfy cases like ".quad .foo".  Calls to functions
     in dynamic objects are handled elsewhere.  */
     in dynamic objects are handled elsewhere.  */
  if (fh->elf.root.type == bfd_link_hash_undefweak
  if (fh->elf.root.type == bfd_link_hash_undefweak
      && fh->was_undefined
      && fh->was_undefined
      && (fh->oh->elf.root.type == bfd_link_hash_defined
      && (fdh = defined_func_desc (fh)) != NULL
          || fh->oh->elf.root.type == bfd_link_hash_defweak)
      && get_opd_info (fdh->elf.root.u.def.section) != NULL
      && get_opd_info (fh->oh->elf.root.u.def.section) != NULL
      && opd_entry_value (fdh->elf.root.u.def.section,
      && opd_entry_value (fh->oh->elf.root.u.def.section,
                          fdh->elf.root.u.def.value,
                          fh->oh->elf.root.u.def.value,
 
                          &fh->elf.root.u.def.section,
                          &fh->elf.root.u.def.section,
                          &fh->elf.root.u.def.value) != (bfd_vma) -1)
                          &fh->elf.root.u.def.value) != (bfd_vma) -1)
    {
    {
      fh->elf.root.type = fh->oh->elf.root.type;
      fh->elf.root.type = fdh->elf.root.type;
      fh->elf.forced_local = 1;
      fh->elf.forced_local = 1;
      fh->elf.def_regular = fh->oh->elf.def_regular;
      fh->elf.def_regular = fdh->elf.def_regular;
      fh->elf.def_dynamic = fh->oh->elf.def_dynamic;
      fh->elf.def_dynamic = fdh->elf.def_dynamic;
    }
    }
 
 
  /* If this is a function code symbol, transfer dynamic linking
  /* If this is a function code symbol, transfer dynamic linking
     information to the function descriptor symbol.  */
     information to the function descriptor symbol.  */
  if (!fh->is_func)
  if (!fh->is_func)
Line 5665... Line 6160...
    return TRUE;
    return TRUE;
 
 
  /* Find the corresponding function descriptor symbol.  Create it
  /* Find the corresponding function descriptor symbol.  Create it
     as undefined if necessary.  */
     as undefined if necessary.  */
 
 
  fdh = get_fdh (fh, htab);
  fdh = lookup_fdh (fh, htab);
  if (fdh != NULL)
 
    while (fdh->elf.root.type == bfd_link_hash_indirect
 
           || fdh->elf.root.type == bfd_link_hash_warning)
 
      fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
 
 
 
  if (fdh == NULL
  if (fdh == NULL
      && info->shared
      && !info->executable
      && (fh->elf.root.type == bfd_link_hash_undefined
      && (fh->elf.root.type == bfd_link_hash_undefined
          || fh->elf.root.type == bfd_link_hash_undefweak))
          || fh->elf.root.type == bfd_link_hash_undefweak))
    {
    {
      fdh = make_fdh (info, fh);
      fdh = make_fdh (info, fh);
      if (fdh == NULL)
      if (fdh == NULL)
Line 5705... Line 6195...
        }
        }
    }
    }
 
 
  if (fdh != NULL
  if (fdh != NULL
      && !fdh->elf.forced_local
      && !fdh->elf.forced_local
      && (info->shared
      && (!info->executable
          || fdh->elf.def_dynamic
          || fdh->elf.def_dynamic
          || fdh->elf.ref_dynamic
          || fdh->elf.ref_dynamic
          || (fdh->elf.root.type == bfd_link_hash_undefweak
          || (fdh->elf.root.type == bfd_link_hash_undefweak
              && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
              && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT)))
    {
    {
Line 5807... Line 6297...
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
 
 
  /* Deal with function syms.  */
  /* Deal with function syms.  */
  if (h->type == STT_FUNC
  if (h->type == STT_FUNC
 
      || h->type == STT_GNU_IFUNC
      || h->needs_plt)
      || h->needs_plt)
    {
    {
      /* Clear procedure linkage table information for any symbol that
      /* Clear procedure linkage table information for any symbol that
         won't need a .plt entry.  */
         won't need a .plt entry.  */
      struct plt_entry *ent;
      struct plt_entry *ent;
      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
      for (ent = h->plt.plist; ent != NULL; ent = ent->next)
        if (ent->plt.refcount > 0)
        if (ent->plt.refcount > 0)
          break;
          break;
      if (ent == NULL
      if (ent == NULL
          || SYMBOL_CALLS_LOCAL (info, h)
          || (h->type != STT_GNU_IFUNC
 
              && (SYMBOL_CALLS_LOCAL (info, h)
          || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
          || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
              && h->root.type == bfd_link_hash_undefweak))
                      && h->root.type == bfd_link_hash_undefweak))))
        {
        {
          h->plt.plist = NULL;
          h->plt.plist = NULL;
          h->needs_plt = 0;
          h->needs_plt = 0;
        }
        }
    }
    }
Line 6006... Line 6498...
    {
    {
      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
 
 
      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
      while (h->root.type == bfd_link_hash_indirect
      h = elf_follow_link (h);
             || h->root.type == bfd_link_hash_warning)
 
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
 
 
      if (hp != NULL)
      if (hp != NULL)
        *hp = h;
        *hp = h;
 
 
      if (symp != NULL)
      if (symp != NULL)
Line 6058... Line 6548...
 
 
      if (symp != NULL)
      if (symp != NULL)
        *symp = sym;
        *symp = sym;
 
 
      if (symsecp != NULL)
      if (symsecp != NULL)
        {
        *symsecp = bfd_section_from_elf_index (ibfd, sym->st_shndx);
          asection *symsec = NULL;
 
          if ((sym->st_shndx != SHN_UNDEF
 
               && sym->st_shndx < SHN_LORESERVE)
 
              || sym->st_shndx > SHN_HIRESERVE)
 
            symsec = bfd_section_from_elf_index (ibfd, sym->st_shndx);
 
          *symsecp = symsec;
 
        }
 
 
 
      if (tls_maskp != NULL)
      if (tls_maskp != NULL)
        {
        {
          struct got_entry **lgot_ents;
          struct got_entry **lgot_ents;
          char *tls_mask;
          char *tls_mask;
 
 
          tls_mask = NULL;
          tls_mask = NULL;
          lgot_ents = elf_local_got_ents (ibfd);
          lgot_ents = elf_local_got_ents (ibfd);
          if (lgot_ents != NULL)
          if (lgot_ents != NULL)
            {
            {
              char *lgot_masks = (char *) (lgot_ents + symtab_hdr->sh_info);
              struct plt_entry **local_plt = (struct plt_entry **)
 
                (lgot_ents + symtab_hdr->sh_info);
 
              char *lgot_masks = (char *)
 
                (local_plt + symtab_hdr->sh_info);
              tls_mask = &lgot_masks[r_symndx];
              tls_mask = &lgot_masks[r_symndx];
            }
            }
          *tls_maskp = tls_mask;
          *tls_maskp = tls_mask;
        }
        }
    }
    }
Line 6090... Line 6576...
/* Returns TLS_MASKP for the given REL symbol.  Function return is 0 on
/* Returns TLS_MASKP for the given REL symbol.  Function return is 0 on
   error, 2 on a toc GD type suitable for optimization, 3 on a toc LD
   error, 2 on a toc GD type suitable for optimization, 3 on a toc LD
   type suitable for optimization, and 1 otherwise.  */
   type suitable for optimization, and 1 otherwise.  */
 
 
static int
static int
get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
get_tls_mask (char **tls_maskp,
 
              unsigned long *toc_symndx,
 
              bfd_vma *toc_addend,
              Elf_Internal_Sym **locsymsp,
              Elf_Internal_Sym **locsymsp,
              const Elf_Internal_Rela *rel, bfd *ibfd)
              const Elf_Internal_Rela *rel,
 
              bfd *ibfd)
{
{
  unsigned long r_symndx;
  unsigned long r_symndx;
  int next_r;
  int next_r;
  struct elf_link_hash_entry *h;
  struct elf_link_hash_entry *h;
  Elf_Internal_Sym *sym;
  Elf_Internal_Sym *sym;
Line 6120... Line 6609...
    }
    }
  else
  else
    off = sym->st_value;
    off = sym->st_value;
  off += rel->r_addend;
  off += rel->r_addend;
  BFD_ASSERT (off % 8 == 0);
  BFD_ASSERT (off % 8 == 0);
  r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8];
  r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8];
  next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1];
  next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1];
  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
 
    return 0;
 
  if (toc_symndx != NULL)
  if (toc_symndx != NULL)
    *toc_symndx = r_symndx;
    *toc_symndx = r_symndx;
 
  if (toc_addend != NULL)
 
    *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
 
  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
 
    return 0;
  if ((h == NULL
  if ((h == NULL
       || ((h->root.type == bfd_link_hash_defined
       || ((h->root.type == bfd_link_hash_defined
            || h->root.type == bfd_link_hash_defweak)
            || h->root.type == bfd_link_hash_defweak)
           && !h->def_dynamic))
           && !h->def_dynamic))
      && (next_r == -1 || next_r == -2))
      && (next_r == -1 || next_r == -2))
Line 6265... Line 6756...
      if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
      if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd))
        return FALSE;
        return FALSE;
    }
    }
 
 
  if ((info->shared
  if ((info->shared
       && (MUST_BE_DYN_RELOC (r_type)
       && (must_be_dyn_reloc (info, r_type)
           || (h != NULL
           || (h != NULL
               && (!info->symbolic
               && (!info->symbolic
                   || h->root.type == bfd_link_hash_defweak
                   || h->root.type == bfd_link_hash_defweak
                   || !h->def_regular))))
                   || !h->def_regular))))
      || (ELIMINATE_COPY_RELOCS
      || (ELIMINATE_COPY_RELOCS
Line 6305... Line 6796...
 
 
  while ((p = *pp) != NULL)
  while ((p = *pp) != NULL)
    {
    {
      if (p->sec == sec)
      if (p->sec == sec)
        {
        {
          if (!MUST_BE_DYN_RELOC (r_type))
          if (!must_be_dyn_reloc (info, r_type))
            p->pc_count -= 1;
            p->pc_count -= 1;
          p->count -= 1;
          p->count -= 1;
          if (p->count == 0)
          if (p->count == 0)
            *pp = p->next;
            *pp = p->next;
          return TRUE;
          return TRUE;
Line 6491... Line 6982...
 
 
      if (need_edit || add_aux_fields)
      if (need_edit || add_aux_fields)
        {
        {
          Elf_Internal_Rela *write_rel;
          Elf_Internal_Rela *write_rel;
          bfd_byte *rptr, *wptr;
          bfd_byte *rptr, *wptr;
          bfd_byte *new_contents = NULL;
          bfd_byte *new_contents;
          bfd_boolean skip;
          bfd_boolean skip;
          long opd_ent_size;
          long opd_ent_size;
          bfd_size_type amt;
          bfd_size_type amt;
 
 
 
          new_contents = NULL;
          amt = sec->size * sizeof (long) / 8;
          amt = sec->size * sizeof (long) / 8;
          opd = &ppc64_elf_section_data (sec)->u.opd;
          opd = &ppc64_elf_section_data (sec)->u.opd;
          opd->adjust = bfd_zalloc (obfd, amt);
          opd->adjust = bfd_zalloc (obfd, amt);
          if (opd->adjust == NULL)
          if (opd->adjust == NULL)
            return FALSE;
            return FALSE;
Line 6574... Line 7066...
                    opd_ent_size = 16;
                    opd_ent_size = 16;
 
 
                  if (h != NULL
                  if (h != NULL
                      && h->root.root.string[0] == '.')
                      && h->root.root.string[0] == '.')
                    {
                    {
                      fdh = get_fdh ((struct ppc_link_hash_entry *) h,
                      fdh = lookup_fdh ((struct ppc_link_hash_entry *) h,
                                     ppc_hash_table (info));
                                     ppc_hash_table (info));
                      if (fdh != NULL
                      if (fdh != NULL
                          && fdh->elf.root.type != bfd_link_hash_defined
                          && fdh->elf.root.type != bfd_link_hash_defined
                          && fdh->elf.root.type != bfd_link_hash_defweak)
                          && fdh->elf.root.type != bfd_link_hash_defweak)
                        fdh = NULL;
                        fdh = NULL;
Line 6725... Line 7217...
}
}
 
 
/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
 
asection *
asection *
ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
ppc64_elf_tls_setup (bfd *obfd,
 
                     struct bfd_link_info *info,
 
                     int no_tls_get_addr_opt)
{
{
  struct ppc_link_hash_table *htab;
  struct ppc_link_hash_table *htab;
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
 
  htab->tls_get_addr = ((struct ppc_link_hash_entry *)
 
                        elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
 
                                              FALSE, FALSE, TRUE));
 
  /* Move dynamic linking info to the function descriptor sym.  */
  if (htab->tls_get_addr != NULL)
  if (htab->tls_get_addr != NULL)
 
    func_desc_adjust (&htab->tls_get_addr->elf, info);
 
  htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
 
                           elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
 
                                                 FALSE, FALSE, TRUE));
 
  if (!no_tls_get_addr_opt)
 
    {
 
      struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
 
 
 
      opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt",
 
                                  FALSE, FALSE, TRUE);
 
      if (opt != NULL)
 
        func_desc_adjust (opt, info);
 
      opt_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
 
                                     FALSE, FALSE, TRUE);
 
      if (opt_fd != NULL
 
          && (opt_fd->root.type == bfd_link_hash_defined
 
              || opt_fd->root.type == bfd_link_hash_defweak))
 
        {
 
          /* If glibc supports an optimized __tls_get_addr call stub,
 
             signalled by the presence of __tls_get_addr_opt, and we'll
 
             be calling __tls_get_addr via a plt call stub, then
 
             make __tls_get_addr point to __tls_get_addr_opt.  */
 
          tga_fd = &htab->tls_get_addr_fd->elf;
 
          if (htab->elf.dynamic_sections_created
 
              && tga_fd != NULL
 
              && (tga_fd->type == STT_FUNC
 
                  || tga_fd->needs_plt)
 
              && !(SYMBOL_CALLS_LOCAL (info, tga_fd)
 
                   || (ELF_ST_VISIBILITY (tga_fd->other) != STV_DEFAULT
 
                       && tga_fd->root.type == bfd_link_hash_undefweak)))
    {
    {
      struct ppc_link_hash_entry *h = htab->tls_get_addr;
              struct plt_entry *ent;
 
 
      while (h->elf.root.type == bfd_link_hash_indirect
 
             || h->elf.root.type == bfd_link_hash_warning)
 
        h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
 
 
 
      htab->tls_get_addr = h;
 
 
 
      if (htab->tls_get_addr_fd == NULL
              for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next)
          && h->oh != NULL
                if (ent->plt.refcount > 0)
          && h->oh->is_func_descriptor
                  break;
          && (h->oh->elf.root.type == bfd_link_hash_defined
              if (ent != NULL)
              || h->oh->elf.root.type == bfd_link_hash_defweak))
                {
        htab->tls_get_addr_fd = h->oh;
                  tga_fd->root.type = bfd_link_hash_indirect;
 
                  tga_fd->root.u.i.link = &opt_fd->root;
 
                  ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
 
                  if (opt_fd->dynindx != -1)
 
                    {
 
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
 
                      opt_fd->dynindx = -1;
 
                      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
 
                                              opt_fd->dynstr_index);
 
                      if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
 
                        return FALSE;
 
                    }
 
                  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
 
                  tga = &htab->tls_get_addr->elf;
 
                  if (opt != NULL && tga != NULL)
 
                    {
 
                      tga->root.type = bfd_link_hash_indirect;
 
                      tga->root.u.i.link = &opt->root;
 
                      ppc64_elf_copy_indirect_symbol (info, opt, tga);
 
                      _bfd_elf_link_hash_hide_symbol (info, opt,
 
                                                      tga->forced_local);
 
                      htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
 
                    }
 
                  htab->tls_get_addr_fd->oh = htab->tls_get_addr;
 
                  htab->tls_get_addr_fd->is_func_descriptor = 1;
 
                  if (htab->tls_get_addr != NULL)
 
                    {
 
                      htab->tls_get_addr->oh = htab->tls_get_addr_fd;
 
                      htab->tls_get_addr->is_func = 1;
 
                    }
 
                }
    }
    }
 
        }
 
      else
 
        no_tls_get_addr_opt = TRUE;
 
    }
 
  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
 
  return _bfd_elf_tls_setup (obfd, info);
 
}
 
 
 
/* Return TRUE iff REL is a branch reloc with a global symbol matching
 
   HASH1 or HASH2.  */
 
 
  if (htab->tls_get_addr_fd != NULL)
static bfd_boolean
 
branch_reloc_hash_match (const bfd *ibfd,
 
                         const Elf_Internal_Rela *rel,
 
                         const struct ppc_link_hash_entry *hash1,
 
                         const struct ppc_link_hash_entry *hash2)
    {
    {
      struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;
  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
 
  enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
 
  unsigned int r_symndx = ELF64_R_SYM (rel->r_info);
 
 
      while (h->elf.root.type == bfd_link_hash_indirect
  if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type))
             || h->elf.root.type == bfd_link_hash_warning)
    {
        h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
 
      struct elf_link_hash_entry *h;
 
 
      htab->tls_get_addr_fd = h;
      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
      h = elf_follow_link (h);
 
      if (h == &hash1->elf || h == &hash2->elf)
 
        return TRUE;
    }
    }
 
  return FALSE;
  return _bfd_elf_tls_setup (obfd, info);
 
}
}
 
 
/* Run through all the TLS relocs looking for optimization
/* Run through all the TLS relocs looking for optimization
   opportunities.  The linker has been hacked (see ppc64elf.em) to do
   opportunities.  The linker has been hacked (see ppc64elf.em) to do
   a preliminary section layout so that we know the TLS segment
   a preliminary section layout so that we know the TLS segment
Line 6777... Line 7348...
  bfd *ibfd;
  bfd *ibfd;
  asection *sec;
  asection *sec;
  struct ppc_link_hash_table *htab;
  struct ppc_link_hash_table *htab;
  int pass;
  int pass;
 
 
  if (info->relocatable || info->shared)
  if (info->relocatable || !info->executable)
    return TRUE;
    return TRUE;
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    {
    {
Line 6838... Line 7409...
                      return FALSE;
                      return FALSE;
                    }
                    }
 
 
                  if (h != NULL)
                  if (h != NULL)
                    {
                    {
                      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)
                        continue;
 
                      value = h->root.u.def.value;
                      value = h->root.u.def.value;
 
                      else if (h->root.type == bfd_link_hash_undefweak)
 
                        value = 0;
 
                      else
 
                        continue;
                    }
                    }
                  else
                  else
                    /* Symbols referenced by TLS relocs must be of type
                    /* Symbols referenced by TLS relocs must be of type
                       STT_TLS.  So no need for .opd local sym adjust.  */
                       STT_TLS.  So no need for .opd local sym adjust.  */
                    value = sym->st_value;
                    value = sym->st_value;
Line 6854... Line 7428...
                  is_local = FALSE;
                  is_local = FALSE;
                  if (h == NULL
                  if (h == NULL
                      || !h->def_dynamic)
                      || !h->def_dynamic)
                    {
                    {
                      is_local = TRUE;
                      is_local = TRUE;
 
                      if (h != NULL
 
                          && h->root.type == bfd_link_hash_undefweak)
 
                        ok_tprel = TRUE;
 
                      else
 
                        {
                      value += sym_sec->output_offset;
                      value += sym_sec->output_offset;
                      value += sym_sec->output_section->vma;
                      value += sym_sec->output_section->vma;
                      value -= htab->elf.tls_sec->vma;
                      value -= htab->elf.tls_sec->vma;
                      ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
                      ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31)
                                  < (bfd_vma) 1 << 32);
                                  < (bfd_vma) 1 << 32);
                    }
                    }
 
                    }
 
 
                  r_type = ELF64_R_TYPE (rel->r_info);
                  r_type = ELF64_R_TYPE (rel->r_info);
                  switch (r_type)
                  switch (r_type)
                    {
                    {
                    case R_PPC64_GOT_TLSLD16:
                    case R_PPC64_GOT_TLSLD16:
Line 6917... Line 7497...
                      continue;
                      continue;
 
 
                    case R_PPC64_TOC16:
                    case R_PPC64_TOC16:
                    case R_PPC64_TOC16_LO:
                    case R_PPC64_TOC16_LO:
                    case R_PPC64_TLS:
                    case R_PPC64_TLS:
 
                    case R_PPC64_TLSGD:
 
                    case R_PPC64_TLSLD:
                      if (sym_sec == NULL || sym_sec != toc)
                      if (sym_sec == NULL || sym_sec != toc)
                        continue;
                        continue;
 
 
                      /* Mark this toc entry as referenced by a TLS
                      /* Mark this toc entry as referenced by a TLS
                         code sequence.  We can do that now in the
                         code sequence.  We can do that now in the
Line 6937... Line 7519...
                      else
                      else
                        value = sym->st_value;
                        value = sym->st_value;
                      value += rel->r_addend;
                      value += rel->r_addend;
                      BFD_ASSERT (value < toc->size && value % 8 == 0);
                      BFD_ASSERT (value < toc->size && value % 8 == 0);
                      toc_ref_index = value / 8;
                      toc_ref_index = value / 8;
                      if (r_type == R_PPC64_TLS)
                      if (r_type == R_PPC64_TLS
 
                          || r_type == R_PPC64_TLSGD
 
                          || r_type == R_PPC64_TLSLD)
                        {
                        {
                          toc_ref[toc_ref_index] = 1;
                          toc_ref[toc_ref_index] = 1;
                          continue;
                          continue;
                        }
                        }
 
 
Line 7002... Line 7586...
                      continue;
                      continue;
                    }
                    }
 
 
                  if (pass == 0)
                  if (pass == 0)
                    {
                    {
                      if (!expecting_tls_get_addr)
                      if (!expecting_tls_get_addr
 
                          || !sec->has_tls_get_addr_call)
                        continue;
                        continue;
 
 
                      if (rel + 1 < relend)
                      if (rel + 1 < relend
                        {
                          && branch_reloc_hash_match (ibfd, rel + 1,
                          Elf_Internal_Shdr *symtab_hdr;
                                                      htab->tls_get_addr,
                          enum elf_ppc64_reloc_type r_type2;
                                                      htab->tls_get_addr_fd))
                          unsigned long r_symndx2;
 
                          struct elf_link_hash_entry *h2;
 
 
 
                          symtab_hdr = &elf_symtab_hdr (ibfd);
 
 
 
                          /* The next instruction should be a call to
 
                             __tls_get_addr.  Peek at the reloc to be sure.  */
 
                          r_type2 = ELF64_R_TYPE (rel[1].r_info);
 
                          r_symndx2 = ELF64_R_SYM (rel[1].r_info);
 
                          if (r_symndx2 >= symtab_hdr->sh_info
 
                              && (r_type2 == R_PPC64_REL14
 
                                  || r_type2 == R_PPC64_REL14_BRTAKEN
 
                                  || r_type2 == R_PPC64_REL14_BRNTAKEN
 
                                  || r_type2 == R_PPC64_REL24))
 
                            {
 
                              struct elf_link_hash_entry **sym_hashes;
 
 
 
                              sym_hashes = elf_sym_hashes (ibfd);
 
 
 
                              h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
 
                              while (h2->root.type == bfd_link_hash_indirect
 
                                     || h2->root.type == bfd_link_hash_warning)
 
                                h2 = ((struct elf_link_hash_entry *)
 
                                      h2->root.u.i.link);
 
                              if (h2 != NULL
 
                                  && (h2 == &htab->tls_get_addr->elf
 
                                      || h2 == &htab->tls_get_addr_fd->elf))
 
                                {
                                {
                                  if (expecting_tls_get_addr == 2)
                                  if (expecting_tls_get_addr == 2)
                                    {
                                    {
                                      /* Check for toc tls entries.  */
                                      /* Check for toc tls entries.  */
                                      char *toc_tls;
                                      char *toc_tls;
                                      int retval;
                                      int retval;
 
 
                                      retval = get_tls_mask (&toc_tls, NULL,
                              retval = get_tls_mask (&toc_tls, NULL, NULL,
                                                             &locsyms,
                                                             &locsyms,
                                                             rel, ibfd);
                                                             rel, ibfd);
                                      if (retval == 0)
                                      if (retval == 0)
                                        goto err_free_rel;
                                        goto err_free_rel;
                                      if (retval > 1 && toc_tls != NULL)
                                      if (retval > 1 && toc_tls != NULL)
                                        toc_ref[toc_ref_index] = 1;
                                        toc_ref[toc_ref_index] = 1;
                                    }
                                    }
                                  continue;
                                  continue;
                                }
                                }
                            }
 
                        }
 
 
 
                      if (expecting_tls_get_addr != 1)
                      if (expecting_tls_get_addr != 1)
                        continue;
                        continue;
 
 
                      /* Uh oh, we didn't find the expected call.  We
                      /* Uh oh, we didn't find the expected call.  We
Line 7575... Line 8131...
              Elf_Internal_Sym *sym;
              Elf_Internal_Sym *sym;
 
 
              for (sym = local_syms;
              for (sym = local_syms;
                   sym < local_syms + symtab_hdr->sh_info;
                   sym < local_syms + symtab_hdr->sh_info;
                   ++sym)
                   ++sym)
                if (sym->st_shndx != SHN_UNDEF
                if (sym->st_value != 0
                    && (sym->st_shndx < SHN_LORESERVE
 
                        || sym->st_shndx > SHN_HIRESERVE)
 
                    && sym->st_value != 0
 
                    && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
                    && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc)
                  {
                  {
                    if (skip[sym->st_value >> 3] != (unsigned long) -1)
                    if (skip[sym->st_value >> 3] != (unsigned long) -1)
                      sym->st_value -= skip[sym->st_value >> 3];
                      sym->st_value -= skip[sym->st_value >> 3];
                    else
                    else
Line 7643... Line 8196...
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
 
  info = (struct bfd_link_info *) inf;
  info = (struct bfd_link_info *) inf;
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
 
 
  if (htab->elf.dynamic_sections_created
  if ((htab->elf.dynamic_sections_created
      && h->dynindx != -1
      && h->dynindx != -1
      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
      && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h))
 
      || h->type == STT_GNU_IFUNC)
    {
    {
      struct plt_entry *pent;
      struct plt_entry *pent;
      bfd_boolean doneone = FALSE;
      bfd_boolean doneone = FALSE;
      for (pent = h->plt.plist; pent != NULL; pent = pent->next)
      for (pent = h->plt.plist; pent != NULL; pent = pent->next)
        if (pent->plt.refcount > 0)
        if (pent->plt.refcount > 0)
          {
          {
 
            if (!htab->elf.dynamic_sections_created
 
                || h->dynindx == -1)
 
              {
 
                s = htab->iplt;
 
                pent->plt.offset = s->size;
 
                s->size += PLT_ENTRY_SIZE;
 
                s = htab->reliplt;
 
              }
 
            else
 
              {
            /* If this is the first .plt entry, make room for the special
            /* If this is the first .plt entry, make room for the special
               first entry.  */
               first entry.  */
            s = htab->plt;
            s = htab->plt;
            if (s->size == 0)
            if (s->size == 0)
              s->size += PLT_INITIAL_ENTRY_SIZE;
              s->size += PLT_INITIAL_ENTRY_SIZE;
Line 7674... Line 8238...
              s->size += 4;
              s->size += 4;
            s->size += 2*4;
            s->size += 2*4;
 
 
            /* We also need to make an entry in the .rela.plt section.  */
            /* We also need to make an entry in the .rela.plt section.  */
            s = htab->relplt;
            s = htab->relplt;
 
              }
            s->size += sizeof (Elf64_External_Rela);
            s->size += sizeof (Elf64_External_Rela);
            doneone = TRUE;
            doneone = TRUE;
          }
          }
        else
        else
          pent->plt.offset = (bfd_vma) -1;
          pent->plt.offset = (bfd_vma) -1;
Line 7721... Line 8286...
 
 
  for (gent = h->got.glist; gent != NULL; gent = gent->next)
  for (gent = h->got.glist; gent != NULL; gent = gent->next)
    if (gent->got.refcount > 0)
    if (gent->got.refcount > 0)
      {
      {
        bfd_boolean dyn;
        bfd_boolean dyn;
 
        asection *rsec;
 
 
        /* Make sure this symbol is output as a dynamic symbol.
        /* Make sure this symbol is output as a dynamic symbol.
           Undefined weak syms won't yet be marked as dynamic,
           Undefined weak syms won't yet be marked as dynamic,
           nor will all TLS symbols.  */
           nor will all TLS symbols.  */
        if (h->dynindx == -1
        if (h->dynindx == -1
            && !h->forced_local)
            && !h->forced_local
 
            && h->type != STT_GNU_IFUNC
 
            && htab->elf.dynamic_sections_created)
          {
          {
            if (! bfd_elf_link_record_dynamic_symbol (info, h))
            if (! bfd_elf_link_record_dynamic_symbol (info, h))
              return FALSE;
              return FALSE;
          }
          }
 
 
Line 7748... Line 8316...
        s = ppc64_elf_tdata (gent->owner)->got;
        s = ppc64_elf_tdata (gent->owner)->got;
        gent->got.offset = s->size;
        gent->got.offset = s->size;
        s->size
        s->size
          += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
          += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8;
        dyn = htab->elf.dynamic_sections_created;
        dyn = htab->elf.dynamic_sections_created;
 
        rsec = NULL;
        if ((info->shared
        if ((info->shared
             || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
             || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
            && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
            && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                || h->root.type != bfd_link_hash_undefweak))
                || h->root.type != bfd_link_hash_undefweak))
          ppc64_elf_tdata (gent->owner)->relgot->size
          rsec = ppc64_elf_tdata (gent->owner)->relgot;
            += (gent->tls_type & eh->tls_mask & TLS_GD
        else if (h->type == STT_GNU_IFUNC)
 
          rsec = htab->reliplt;
 
        if (rsec != NULL)
 
          rsec->size += (gent->tls_type & eh->tls_mask & TLS_GD
                ? 2 * sizeof (Elf64_External_Rela)
                ? 2 * sizeof (Elf64_External_Rela)
                : sizeof (Elf64_External_Rela));
                : sizeof (Elf64_External_Rela));
      }
      }
    else
    else
      gent->got.offset = (bfd_vma) -1;
      gent->got.offset = (bfd_vma) -1;
 
 
  if (eh->dyn_relocs == NULL)
  if (eh->dyn_relocs == NULL
 
      || (!htab->elf.dynamic_sections_created
 
          && h->type != STT_GNU_IFUNC))
    return TRUE;
    return TRUE;
 
 
  /* In the shared -Bsymbolic case, discard space allocated for
  /* In the shared -Bsymbolic case, discard space allocated for
     dynamic pc-relative relocs against symbols which turn out to be
     dynamic pc-relative relocs against symbols which turn out to be
     defined in regular objects.  For the normal shared case, discard
     defined in regular objects.  For the normal shared case, discard
Line 7772... Line 8346...
     changes.  */
     changes.  */
 
 
  if (info->shared)
  if (info->shared)
    {
    {
      /* Relocs that use pc_count are those that appear on a call insn,
      /* Relocs that use pc_count are those that appear on a call insn,
         or certain REL relocs (see MUST_BE_DYN_RELOC) that can be
         or certain REL relocs (see must_be_dyn_reloc) that can be
         generated via assembly.  We want calls to protected symbols to
         generated via assembly.  We want calls to protected symbols to
         resolve directly to the function rather than going via the plt.
         resolve directly to the function rather than going via the plt.
         If people want function pointer comparisons to work as expected
         If people want function pointer comparisons to work as expected
         then they should avoid writing weird assembly.  */
         then they should avoid writing weird assembly.  */
      if (SYMBOL_CALLS_LOCAL (info, h))
      if (SYMBOL_CALLS_LOCAL (info, h))
Line 7810... Line 8384...
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
                return FALSE;
                return FALSE;
            }
            }
        }
        }
    }
    }
 
  else if (h->type == STT_GNU_IFUNC)
 
    {
 
      if (!h->non_got_ref)
 
        eh->dyn_relocs = NULL;
 
    }
  else if (ELIMINATE_COPY_RELOCS)
  else if (ELIMINATE_COPY_RELOCS)
    {
    {
      /* For the non-shared case, discard space for relocs against
      /* For the non-shared case, discard space for relocs against
         symbols which turn out to need copy relocs or are not
         symbols which turn out to need copy relocs or are not
         dynamic.  */
         dynamic.  */
 
 
      if (!h->non_got_ref
      if (!h->non_got_ref
          && h->def_dynamic
 
          && !h->def_regular)
          && !h->def_regular)
        {
        {
          /* Make sure this symbol is output as a dynamic symbol.
          /* Make sure this symbol is output as a dynamic symbol.
             Undefined weak syms won't yet be marked as dynamic.  */
             Undefined weak syms won't yet be marked as dynamic.  */
          if (h->dynindx == -1
          if (h->dynindx == -1
Line 7844... Line 8422...
 
 
  /* Finally, allocate space.  */
  /* Finally, allocate space.  */
  for (p = eh->dyn_relocs; p != NULL; p = p->next)
  for (p = eh->dyn_relocs; p != NULL; p = p->next)
    {
    {
      asection *sreloc = elf_section_data (p->sec)->sreloc;
      asection *sreloc = elf_section_data (p->sec)->sreloc;
 
      if (!htab->elf.dynamic_sections_created)
 
        sreloc = htab->reliplt;
      sreloc->size += p->count * sizeof (Elf64_External_Rela);
      sreloc->size += p->count * sizeof (Elf64_External_Rela);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
Line 7915... Line 8495...
     relocs.  */
     relocs.  */
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    {
    {
      struct got_entry **lgot_ents;
      struct got_entry **lgot_ents;
      struct got_entry **end_lgot_ents;
      struct got_entry **end_lgot_ents;
 
      struct plt_entry **local_plt;
 
      struct plt_entry **end_local_plt;
      char *lgot_masks;
      char *lgot_masks;
      bfd_size_type locsymcount;
      bfd_size_type locsymcount;
      Elf_Internal_Shdr *symtab_hdr;
      Elf_Internal_Shdr *symtab_hdr;
      asection *srel;
      asection *srel;
 
 
Line 7940... Line 8522...
                     the relocs too.  */
                     the relocs too.  */
                }
                }
              else if (p->count != 0)
              else if (p->count != 0)
                {
                {
                  srel = elf_section_data (p->sec)->sreloc;
                  srel = elf_section_data (p->sec)->sreloc;
 
                  if (!htab->elf.dynamic_sections_created)
 
                    srel = htab->reliplt;
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  srel->size += p->count * sizeof (Elf64_External_Rela);
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                  if ((p->sec->output_section->flags & SEC_READONLY) != 0)
                    info->flags |= DF_TEXTREL;
                    info->flags |= DF_TEXTREL;
                }
                }
            }
            }
Line 7954... Line 8538...
        continue;
        continue;
 
 
      symtab_hdr = &elf_symtab_hdr (ibfd);
      symtab_hdr = &elf_symtab_hdr (ibfd);
      locsymcount = symtab_hdr->sh_info;
      locsymcount = symtab_hdr->sh_info;
      end_lgot_ents = lgot_ents + locsymcount;
      end_lgot_ents = lgot_ents + locsymcount;
      lgot_masks = (char *) end_lgot_ents;
      local_plt = (struct plt_entry **) end_lgot_ents;
 
      end_local_plt = local_plt + locsymcount;
 
      lgot_masks = (char *) end_local_plt;
      s = ppc64_elf_tdata (ibfd)->got;
      s = ppc64_elf_tdata (ibfd)->got;
      srel = ppc64_elf_tdata (ibfd)->relgot;
      srel = ppc64_elf_tdata (ibfd)->relgot;
      for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
      for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks)
        {
        {
          struct got_entry *ent;
          struct got_entry *ent;
Line 7971... Line 8557...
                    ppc64_tlsld_got (ibfd)->refcount += 1;
                    ppc64_tlsld_got (ibfd)->refcount += 1;
                    ent->got.offset = (bfd_vma) -1;
                    ent->got.offset = (bfd_vma) -1;
                  }
                  }
                else
                else
                  {
                  {
 
                    unsigned int num = 1;
                    ent->got.offset = s->size;
                    ent->got.offset = s->size;
                    if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
                    if ((ent->tls_type & *lgot_masks & TLS_GD) != 0)
                      {
                      num = 2;
                        s->size += 16;
                    s->size += num * 8;
                        if (info->shared)
                        if (info->shared)
                          srel->size += 2 * sizeof (Elf64_External_Rela);
                      srel->size += num * sizeof (Elf64_External_Rela);
 
                    else if ((*lgot_masks & PLT_IFUNC) != 0)
 
                      htab->reliplt->size += num * sizeof (Elf64_External_Rela);
                      }
                      }
                    else
 
                      {
 
                        s->size += 8;
 
                        if (info->shared)
 
                          srel->size += sizeof (Elf64_External_Rela);
 
                      }
                      }
 
            else
 
              ent->got.offset = (bfd_vma) -1;
                  }
                  }
 
 
 
      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
 
      for (; local_plt < end_local_plt; ++local_plt)
 
        {
 
          struct plt_entry *ent;
 
 
 
          for (ent = *local_plt; ent != NULL; ent = ent->next)
 
            if (ent->plt.refcount > 0)
 
              {
 
                s = htab->iplt;
 
                ent->plt.offset = s->size;
 
                s->size += PLT_ENTRY_SIZE;
 
 
 
                htab->reliplt->size += sizeof (Elf64_External_Rela);
              }
              }
            else
            else
              ent->got.offset = (bfd_vma) -1;
              ent->plt.offset = (bfd_vma) -1;
        }
        }
    }
    }
 
 
  /* Allocate global sym .plt and .got entries, and space for global
  /* Allocate global sym .plt and .got entries, and space for global
     sym dynamic relocs.  */
     sym dynamic relocs.  */
Line 8028... Line 8628...
      if (s == htab->brlt || s == htab->relbrlt)
      if (s == htab->brlt || s == htab->relbrlt)
        /* These haven't been allocated yet;  don't strip.  */
        /* These haven't been allocated yet;  don't strip.  */
        continue;
        continue;
      else if (s == htab->got
      else if (s == htab->got
               || s == htab->plt
               || s == htab->plt
 
               || s == htab->iplt
               || s == htab->glink
               || s == htab->glink
               || s == htab->dynbss)
               || s == htab->dynbss)
        {
        {
          /* Strip this section if we don't need it; see the
          /* Strip this section if we don't need it; see the
             comment below.  */
             comment below.  */
Line 8148... Line 8749...
          if (!add_dynamic_entry (DT_PPC64_OPD, 0)
          if (!add_dynamic_entry (DT_PPC64_OPD, 0)
              || !add_dynamic_entry (DT_PPC64_OPDSZ, 0))
              || !add_dynamic_entry (DT_PPC64_OPDSZ, 0))
            return FALSE;
            return FALSE;
        }
        }
 
 
 
      if (!htab->no_tls_get_addr_opt
 
          && htab->tls_get_addr_fd != NULL
 
          && htab->tls_get_addr_fd->elf.plt.plist != NULL
 
          && !add_dynamic_entry (DT_PPC64_TLSOPT, 0))
 
        return FALSE;
 
 
      if (relocs)
      if (relocs)
        {
        {
          if (!add_dynamic_entry (DT_RELA, 0)
          if (!add_dynamic_entry (DT_RELA, 0)
              || !add_dynamic_entry (DT_RELASZ, 0)
              || !add_dynamic_entry (DT_RELASZ, 0)
              || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
              || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
Line 8178... Line 8785...
 
 
static inline enum ppc_stub_type
static inline enum ppc_stub_type
ppc_type_of_stub (asection *input_sec,
ppc_type_of_stub (asection *input_sec,
                  const Elf_Internal_Rela *rel,
                  const Elf_Internal_Rela *rel,
                  struct ppc_link_hash_entry **hash,
                  struct ppc_link_hash_entry **hash,
 
                  struct plt_entry **plt_ent,
                  bfd_vma destination)
                  bfd_vma destination)
{
{
  struct ppc_link_hash_entry *h = *hash;
  struct ppc_link_hash_entry *h = *hash;
  bfd_vma location;
  bfd_vma location;
  bfd_vma branch_offset;
  bfd_vma branch_offset;
  bfd_vma max_branch_offset;
  bfd_vma max_branch_offset;
  enum elf_ppc64_reloc_type r_type;
  enum elf_ppc64_reloc_type r_type;
 
 
  if (h != NULL)
  if (h != NULL)
    {
    {
      struct ppc_link_hash_entry *fdh = h;
 
      if (fdh->oh != NULL
 
          && fdh->oh->is_func_descriptor)
 
        fdh = fdh->oh;
 
 
 
      if (fdh->elf.dynindx != -1)
 
        {
 
          struct plt_entry *ent;
          struct plt_entry *ent;
 
      struct ppc_link_hash_entry *fdh = h;
 
      if (h->oh != NULL
 
          && h->oh->is_func_descriptor)
 
        fdh = ppc_follow_link (h->oh);
 
 
          for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
          for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next)
            if (ent->addend == rel->r_addend
            if (ent->addend == rel->r_addend
                && ent->plt.offset != (bfd_vma) -1)
                && ent->plt.offset != (bfd_vma) -1)
              {
              {
                *hash = fdh;
                *hash = fdh;
 
            *plt_ent = ent;
                return ppc_stub_plt_call;
                return ppc_stub_plt_call;
              }
              }
        }
 
 
 
      /* Here, we know we don't have a plt entry.  If we don't have a
      /* Here, we know we don't have a plt entry.  If we don't have a
         either a defined function descriptor or a defined entry symbol
         either a defined function descriptor or a defined entry symbol
         in a regular object file, then it is pointless trying to make
         in a regular object file, then it is pointless trying to make
         any other type of stub.  */
         any other type of stub.  */
Line 8218... Line 8823...
          && !((h->elf.root.type == bfd_link_hash_defined
          && !((h->elf.root.type == bfd_link_hash_defined
                || h->elf.root.type == bfd_link_hash_defweak)
                || h->elf.root.type == bfd_link_hash_defweak)
               && h->elf.root.u.def.section->output_section != NULL))
               && h->elf.root.u.def.section->output_section != NULL))
        return ppc_stub_none;
        return ppc_stub_none;
    }
    }
 
  else if (elf_local_got_ents (input_sec->owner) != NULL)
 
    {
 
      Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (input_sec->owner);
 
      struct plt_entry **local_plt = (struct plt_entry **)
 
        elf_local_got_ents (input_sec->owner) + symtab_hdr->sh_info;
 
      unsigned long r_symndx = ELF64_R_SYM (rel->r_info);
 
 
  /* Determine where the call point is.  */
      if (local_plt[r_symndx] != NULL)
  location = (input_sec->output_offset
        {
              + input_sec->output_section->vma
          struct plt_entry *ent;
              + rel->r_offset);
 
 
          for (ent = local_plt[r_symndx]; ent != NULL; ent = ent->next)
 
            if (ent->addend == rel->r_addend
 
                && ent->plt.offset != (bfd_vma) -1)
 
              {
 
                *plt_ent = ent;
 
                return ppc_stub_plt_call;
 
              }
 
        }
 
    }
 
 
 
  /* Determine where the call point is.  */
 
  location = (input_sec->output_offset
 
              + input_sec->output_section->vma
 
              + rel->r_offset);
 
 
  branch_offset = destination - location;
  branch_offset = destination - location;
  r_type = ELF64_R_TYPE (rel->r_info);
  r_type = ELF64_R_TYPE (rel->r_info);
 
 
  /* Determine if a long branch stub is needed.  */
  /* Determine if a long branch stub is needed.  */
Line 8243... Line 8868...
}
}
 
 
/* Build a .plt call stub.  */
/* Build a .plt call stub.  */
 
 
static inline bfd_byte *
static inline bfd_byte *
build_plt_stub (bfd *obfd, bfd_byte *p, int offset)
build_plt_stub (bfd *obfd, bfd_byte *p, int offset, Elf_Internal_Rela *r)
{
{
#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)
 
 
  if (PPC_HA (offset) != 0)
  if (PPC_HA (offset) != 0)
    {
    {
 
      if (r != NULL)
 
        {
 
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
 
          r[1].r_offset = r[0].r_offset + 8;
 
          r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
 
          r[1].r_addend = r[0].r_addend;
 
          if (PPC_HA (offset + 16) != PPC_HA (offset))
 
            {
 
              r[2].r_offset = r[1].r_offset + 4;
 
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO);
 
              r[2].r_addend = r[0].r_addend;
 
            }
 
          else
 
            {
 
              r[2].r_offset = r[1].r_offset + 8;
 
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_LO_DS);
 
              r[2].r_addend = r[0].r_addend + 8;
 
              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_addend = r[0].r_addend + 16;
 
            }
 
        }
      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, STD_R2_40R1, p),                        p += 4;
      bfd_put_32 (obfd, STD_R2_40R1, 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 + 16) != PPC_HA (offset))
      if (PPC_HA (offset + 16) != PPC_HA (offset))
        {
        {
Line 8266... Line 8913...
      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;
      bfd_put_32 (obfd, BCTR, p),                               p += 4;
    }
    }
  else
  else
    {
    {
 
      if (r != NULL)
 
        {
 
          r[0].r_offset += 4;
 
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
 
          if (PPC_HA (offset + 16) != PPC_HA (offset))
 
            {
 
              r[1].r_offset = r[0].r_offset + 4;
 
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16);
 
              r[1].r_addend = r[0].r_addend;
 
            }
 
          else
 
            {
 
              r[1].r_offset = r[0].r_offset + 8;
 
              r[1].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
 
              r[1].r_addend = r[0].r_addend + 16;
 
              r[2].r_offset = r[1].r_offset + 4;
 
              r[2].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
 
              r[2].r_addend = r[0].r_addend + 8;
 
            }
 
        }
      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 + 16) != PPC_HA (offset))
      if (PPC_HA (offset + 16) != 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;
Line 8281... Line 8948...
      bfd_put_32 (obfd, BCTR, p),                               p += 4;
      bfd_put_32 (obfd, BCTR, p),                               p += 4;
    }
    }
  return p;
  return p;
}
}
 
 
 
/* Build a special .plt call stub for __tls_get_addr.  */
 
 
 
#define LD_R11_0R3      0xe9630000
 
#define LD_R12_0R3      0xe9830000
 
#define MR_R0_R3        0x7c601b78
 
#define CMPDI_R11_0     0x2c2b0000
 
#define ADD_R3_R12_R13  0x7c6c6a14
 
#define BEQLR           0x4d820020
 
#define MR_R3_R0        0x7c030378
 
#define MFLR_R11        0x7d6802a6
 
#define STD_R11_0R1     0xf9610000
 
#define BCTRL           0x4e800421
 
#define LD_R11_0R1      0xe9610000
 
#define LD_R2_0R1       0xe8410000
 
#define MTLR_R11        0x7d6803a6
 
 
 
static inline bfd_byte *
 
build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
 
                         Elf_Internal_Rela *r)
 
{
 
  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, MR_R0_R3, 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, BEQLR, p),                  p += 4;
 
  bfd_put_32 (obfd, MR_R3_R0, p),               p += 4;
 
  bfd_put_32 (obfd, MFLR_R11, p),               p += 4;
 
  bfd_put_32 (obfd, STD_R11_0R1 + 32, p),       p += 4;
 
 
 
  if (r != NULL)
 
    r[0].r_offset += 9 * 4;
 
  p = build_plt_stub (obfd, p, offset, r);
 
  bfd_put_32 (obfd, BCTRL, 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, MTLR_R11, p),               p += 4;
 
  bfd_put_32 (obfd, BLR, p),                    p += 4;
 
 
 
  return p;
 
}
 
 
 
static Elf_Internal_Rela *
 
get_relocs (asection *sec, int count)
 
{
 
  Elf_Internal_Rela *relocs;
 
  struct bfd_elf_section_data *elfsec_data;
 
 
 
  elfsec_data = elf_section_data (sec);
 
  relocs = elfsec_data->relocs;
 
  if (relocs == NULL)
 
    {
 
      bfd_size_type relsize;
 
      relsize = sec->reloc_count * sizeof (*relocs);
 
      relocs = bfd_alloc (sec->owner, relsize);
 
      if (relocs == NULL)
 
        return NULL;
 
      elfsec_data->relocs = relocs;
 
      elfsec_data->rel_hdr.sh_size = (sec->reloc_count
 
                                      * sizeof (Elf64_External_Rela));
 
      elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela);
 
      sec->reloc_count = 0;
 
    }
 
  relocs += sec->reloc_count;
 
  sec->reloc_count += count;
 
  return relocs;
 
}
 
 
static bfd_boolean
static bfd_boolean
ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
ppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg)
{
{
  struct ppc_stub_hash_entry *stub_entry;
  struct ppc_stub_hash_entry *stub_entry;
  struct ppc_branch_hash_entry *br_entry;
  struct ppc_branch_hash_entry *br_entry;
  struct bfd_link_info *info;
  struct bfd_link_info *info;
  struct ppc_link_hash_table *htab;
  struct ppc_link_hash_table *htab;
  bfd_byte *loc;
  bfd_byte *loc;
  bfd_byte *p;
  bfd_byte *p;
  unsigned int indx;
 
  struct plt_entry *ent;
 
  bfd_vma dest, off;
  bfd_vma dest, off;
  int size;
  int size;
 
  Elf_Internal_Rela *r;
 
  asection *plt;
 
 
  /* Massage our args to the form they really have.  */
  /* Massage our args to the form they really have.  */
  stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
  stub_entry = (struct ppc_stub_hash_entry *) gen_entry;
  info = in_arg;
  info = in_arg;
 
 
Line 8352... Line 9088...
          return FALSE;
          return FALSE;
        }
        }
 
 
      if (info->emitrelocations)
      if (info->emitrelocations)
        {
        {
          Elf_Internal_Rela *relocs, *r;
          r = get_relocs (stub_entry->stub_sec, 1);
          struct bfd_elf_section_data *elfsec_data;
          if (r == NULL)
 
 
          elfsec_data = elf_section_data (stub_entry->stub_sec);
 
          relocs = elfsec_data->relocs;
 
          if (relocs == NULL)
 
            {
 
              bfd_size_type relsize;
 
              relsize = stub_entry->stub_sec->reloc_count * sizeof (*relocs);
 
              relocs = bfd_alloc (htab->stub_bfd, relsize);
 
              if (relocs == NULL)
 
                return FALSE;
                return FALSE;
              elfsec_data->relocs = relocs;
 
              elfsec_data->rel_hdr.sh_size = (stub_entry->stub_sec->reloc_count
 
                                              * sizeof (Elf64_External_Rela));
 
              elfsec_data->rel_hdr.sh_entsize = sizeof (Elf64_External_Rela);
 
              stub_entry->stub_sec->reloc_count = 0;
 
            }
 
          r = relocs + stub_entry->stub_sec->reloc_count;
 
          stub_entry->stub_sec->reloc_count += 1;
 
          r->r_offset = loc - stub_entry->stub_sec->contents;
          r->r_offset = loc - stub_entry->stub_sec->contents;
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL24);
          r->r_addend = dest;
          r->r_addend = dest;
          if (stub_entry->h != NULL)
          if (stub_entry->h != NULL)
            {
            {
Line 8398... Line 9117...
              symndx = htab->stub_globals++;
              symndx = htab->stub_globals++;
              h = stub_entry->h;
              h = stub_entry->h;
              hashes[symndx] = &h->elf;
              hashes[symndx] = &h->elf;
              r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
              r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24);
              if (h->oh != NULL && h->oh->is_func)
              if (h->oh != NULL && h->oh->is_func)
                h = h->oh;
                h = ppc_follow_link (h->oh);
              if (h->elf.root.u.def.section != stub_entry->target_section)
              if (h->elf.root.u.def.section != stub_entry->target_section)
                /* H is an opd symbol.  The addend must be zero.  */
                /* H is an opd symbol.  The addend must be zero.  */
                r->r_addend = 0;
                r->r_addend = 0;
              else
              else
                {
                {
Line 8426... Line 9145...
                                 stub_entry->root.string);
                                 stub_entry->root.string);
          htab->stub_error = TRUE;
          htab->stub_error = TRUE;
          return FALSE;
          return FALSE;
        }
        }
 
 
      off = (stub_entry->target_value
      dest = (stub_entry->target_value
             + stub_entry->target_section->output_offset
             + stub_entry->target_section->output_offset
             + stub_entry->target_section->output_section->vma);
             + stub_entry->target_section->output_section->vma);
 
 
      bfd_put_64 (htab->brlt->owner, off,
      bfd_put_64 (htab->brlt->owner, dest,
                  htab->brlt->contents + br_entry->offset);
                  htab->brlt->contents + br_entry->offset);
 
 
      if (br_entry->iter == htab->stub_iteration)
      if (br_entry->iter == htab->stub_iteration)
        {
        {
          br_entry->iter = 0;
          br_entry->iter = 0;
Line 8447... Line 9166...
 
 
              rela.r_offset = (br_entry->offset
              rela.r_offset = (br_entry->offset
                               + htab->brlt->output_offset
                               + htab->brlt->output_offset
                               + htab->brlt->output_section->vma);
                               + htab->brlt->output_section->vma);
              rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
              rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
              rela.r_addend = off;
              rela.r_addend = dest;
 
 
              rl = htab->relbrlt->contents;
              rl = htab->relbrlt->contents;
              rl += (htab->relbrlt->reloc_count++
              rl += (htab->relbrlt->reloc_count++
                     * sizeof (Elf64_External_Rela));
                     * sizeof (Elf64_External_Rela));
              bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl);
              bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl);
            }
            }
          else if (info->emitrelocations)
          else if (info->emitrelocations)
            {
            {
              Elf_Internal_Rela *relocs, *r;
              r = get_relocs (htab->brlt, 1);
              struct bfd_elf_section_data *elfsec_data;
              if (r == NULL)
 
 
              elfsec_data = elf_section_data (htab->brlt);
 
              relocs = elfsec_data->relocs;
 
              if (relocs == NULL)
 
                {
 
                  bfd_size_type relsize;
 
                  relsize = htab->brlt->reloc_count * sizeof (*relocs);
 
                  relocs = bfd_alloc (htab->brlt->owner, relsize);
 
                  if (relocs == NULL)
 
                    return FALSE;
                    return FALSE;
                  elfsec_data->relocs = relocs;
              /* brlt, being SEC_LINKER_CREATED does not go through the
                  elfsec_data->rel_hdr.sh_size
                 normal reloc processing.  Symbols and offsets are not
                    = (stub_entry->stub_sec->reloc_count
                 translated from input file to output file form, so
                       * sizeof (Elf64_External_Rela));
                 set up the offset per the output file.  */
                  elfsec_data->rel_hdr.sh_entsize
 
                    = sizeof (Elf64_External_Rela);
 
                  htab->brlt->reloc_count = 0;
 
                }
 
              r = relocs + htab->brlt->reloc_count;
 
              htab->brlt->reloc_count += 1;
 
              r->r_offset = (br_entry->offset
              r->r_offset = (br_entry->offset
                             + htab->brlt->output_offset
                             + htab->brlt->output_offset
                             + htab->brlt->output_section->vma);
                             + htab->brlt->output_section->vma);
              r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
              r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
              r->r_addend = off;
              r->r_addend = dest;
            }
            }
        }
        }
 
 
      off = (br_entry->offset
      dest = (br_entry->offset
             + htab->brlt->output_offset
             + htab->brlt->output_offset
             + htab->brlt->output_section->vma
              + htab->brlt->output_section->vma);
 
 
 
      off = (dest
             - elf_gp (htab->brlt->output_section->owner)
             - elf_gp (htab->brlt->output_section->owner)
             - htab->stub_group[stub_entry->id_sec->id].toc_off);
             - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
 
      if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
      if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
        {
Line 8502... Line 9208...
          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;
        }
        }
 
 
      indx = off;
      if (info->emitrelocations)
 
        {
 
          r = get_relocs (stub_entry->stub_sec, 1 + (PPC_HA (off) != 0));
 
          if (r == NULL)
 
            return FALSE;
 
          r[0].r_offset = loc - stub_entry->stub_sec->contents;
 
          if (bfd_big_endian (info->output_bfd))
 
            r[0].r_offset += 2;
 
          if (stub_entry->stub_type == ppc_stub_plt_branch_r2off)
 
            r[0].r_offset += 4;
 
          r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_DS);
 
          r[0].r_addend = dest;
 
          if (PPC_HA (off) != 0)
 
            {
 
              r[0].r_info = ELF64_R_INFO (0, R_PPC64_TOC16_HA);
 
              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_addend = r[0].r_addend;
 
            }
 
        }
 
 
      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
      if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
        {
        {
          if (PPC_HA (indx) != 0)
          if (PPC_HA (off) != 0)
            {
            {
              size = 16;
              size = 16;
              bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
              bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc);
              loc += 4;
              loc += 4;
              bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
              bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc);
            }
            }
          else
          else
            {
            {
              size = 12;
              size = 12;
              bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (indx), loc);
              bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc);
            }
            }
        }
        }
      else
      else
        {
        {
          bfd_vma r2off;
          bfd_vma r2off;
Line 8527... Line 9253...
          r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
          r2off = (htab->stub_group[stub_entry->target_section->id].toc_off
                   - htab->stub_group[stub_entry->id_sec->id].toc_off);
                   - htab->stub_group[stub_entry->id_sec->id].toc_off);
          bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc);
          loc += 4;
          loc += 4;
          size = 20;
          size = 20;
          if (PPC_HA (indx) != 0)
          if (PPC_HA (off) != 0)
            {
            {
              size += 4;
              size += 4;
              bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc);
              bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (off), loc);
              loc += 4;
              loc += 4;
              bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc);
              bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (off), loc);
              loc += 4;
              loc += 4;
            }
            }
          else
          else
            {
            {
              bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (indx), loc);
              bfd_put_32 (htab->stub_bfd, LD_R11_0R2 | PPC_LO (off), loc);
              loc += 4;
              loc += 4;
            }
            }
 
 
          if (PPC_HA (r2off) != 0)
          if (PPC_HA (r2off) != 0)
            {
            {
Line 8556... Line 9282...
      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:
      /* Do the best we can for shared libraries built without
      if (stub_entry->h != NULL
         exporting ".foo" for each "foo".  This can happen when symbol
          && stub_entry->h->is_func_descriptor
         versioning scripts strip all bar a subset of symbols.  */
          && stub_entry->h->oh != NULL)
      if (stub_entry->h->oh != NULL
        {
          && stub_entry->h->oh->elf.root.type != bfd_link_hash_defined
          struct ppc_link_hash_entry *fh = ppc_follow_link (stub_entry->h->oh);
          && stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak)
 
        {
          /* If the old-ABI "dot-symbol" is undefined make it weak so
          /* Point the symbol at the stub.  There may be multiple stubs,
             we don't get a link error from RELOC_FOR_GLOBAL_SYMBOL.
             we don't really care;  The main thing is to make this sym
             FIXME: We used to define the symbol on one of the call
             defined somewhere.  Maybe defining the symbol in the stub
             stubs instead, which is why we test symbol section id
             section is a silly idea.  If we didn't do this, htab->top_id
             against htab->top_id in various places.  Likely all
             could disappear.  */
             these checks could now disappear.  */
          stub_entry->h->oh->elf.root.type = bfd_link_hash_defined;
          if (fh->elf.root.type == bfd_link_hash_undefined)
          stub_entry->h->oh->elf.root.u.def.section = stub_entry->stub_sec;
            fh->elf.root.type = bfd_link_hash_undefweak;
          stub_entry->h->oh->elf.root.u.def.value = stub_entry->stub_offset;
 
        }
        }
 
 
      /* Now build the stub.  */
      /* Now build the stub.  */
      off = (bfd_vma) -1;
      dest = stub_entry->plt_ent->plt.offset & ~1;
      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
      if (dest >= (bfd_vma) -2)
        if (ent->addend == stub_entry->addend)
        abort ();
 
 
 
      plt = htab->plt;
 
      if (!htab->elf.dynamic_sections_created
 
          || stub_entry->h == NULL
 
          || stub_entry->h->elf.dynindx == -1)
 
        plt = htab->iplt;
 
 
 
      dest += plt->output_offset + plt->output_section->vma;
 
 
 
      if (stub_entry->h == NULL
 
          && (stub_entry->plt_ent->plt.offset & 1) == 0)
          {
          {
            off = ent->plt.offset;
          Elf_Internal_Rela rela;
            break;
          bfd_byte *rl;
 
 
 
          rela.r_offset = dest;
 
          rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
 
          rela.r_addend = (stub_entry->target_value
 
                           + stub_entry->target_section->output_offset
 
                           + stub_entry->target_section->output_section->vma);
 
 
 
          rl = (htab->reliplt->contents
 
                + (htab->reliplt->reloc_count++
 
                   * sizeof (Elf64_External_Rela)));
 
          bfd_elf64_swap_reloca_out (info->output_bfd, &rela, rl);
 
          stub_entry->plt_ent->plt.offset |= 1;
          }
          }
      if (off >= (bfd_vma) -2)
 
        abort ();
 
 
 
      off &= ~ (bfd_vma) 1;
      off = (dest
      off += (htab->plt->output_offset
             - elf_gp (plt->output_section->owner)
              + htab->plt->output_section->vma
 
              - elf_gp (htab->plt->output_section->owner)
 
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
              - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
 
      if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
      if (off + 0x80008000 > 0xffffffff || (off & 7) != 0)
        {
        {
          (*_bfd_error_handler)
          (*_bfd_error_handler)
            (_("linkage table error against `%s'"),
            (_("linkage table error against `%s'"),
             stub_entry->h->elf.root.root.string);
             stub_entry->h != NULL
 
             ? stub_entry->h->elf.root.root.string
 
             : "<local sym>");
          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;
        }
        }
 
 
      p = build_plt_stub (htab->stub_bfd, loc, off);
      r = NULL;
 
      if (info->emitrelocations)
 
        {
 
          r = get_relocs (stub_entry->stub_sec,
 
                          (2 + (PPC_HA (off) != 0)
 
                           + (PPC_HA (off + 16) == PPC_HA (off))));
 
          if (r == NULL)
 
            return FALSE;
 
          r[0].r_offset = loc - stub_entry->stub_sec->contents;
 
          if (bfd_big_endian (info->output_bfd))
 
            r[0].r_offset += 2;
 
          r[0].r_addend = dest;
 
        }
 
      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)
 
        p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r);
 
      else
 
        p = build_plt_stub (htab->stub_bfd, loc, off, r);
      size = p - loc;
      size = p - loc;
      break;
      break;
 
 
    default:
    default:
      BFD_FAIL ();
      BFD_FAIL ();
Line 8670... Line 9435...
 
 
  htab = ppc_hash_table (info);
  htab = ppc_hash_table (info);
 
 
  if (stub_entry->stub_type == ppc_stub_plt_call)
  if (stub_entry->stub_type == ppc_stub_plt_call)
    {
    {
      struct plt_entry *ent;
      asection *plt;
      off = (bfd_vma) -1;
      off = stub_entry->plt_ent->plt.offset & ~(bfd_vma) 1;
      for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next)
 
        if (ent->addend == stub_entry->addend)
 
          {
 
            off = ent->plt.offset & ~(bfd_vma) 1;
 
            break;
 
          }
 
      if (off >= (bfd_vma) -2)
      if (off >= (bfd_vma) -2)
        abort ();
        abort ();
      off += (htab->plt->output_offset
      plt = htab->plt;
              + htab->plt->output_section->vma
      if (!htab->elf.dynamic_sections_created
              - elf_gp (htab->plt->output_section->owner)
          || stub_entry->h == NULL
 
          || stub_entry->h->elf.dynindx == -1)
 
        plt = htab->iplt;
 
      off += (plt->output_offset
 
              + plt->output_section->vma
 
              - 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_CALL_STUB_SIZE;
      if (PPC_HA (off) == 0)
      if (PPC_HA (off) == 0)
        size -= 4;
        size -= 4;
      if (PPC_HA (off + 16) != PPC_HA (off))
      if (PPC_HA (off + 16) != PPC_HA (off))
        size += 4;
        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)
 
        {
 
          stub_entry->stub_sec->reloc_count
 
            += 2 + (PPC_HA (off) != 0) + (PPC_HA (off + 16) == PPC_HA (off));
 
          stub_entry->stub_sec->flags |= SEC_RELOC;
 
        }
    }
    }
  else
  else
    {
    {
      /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off
      /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off
         variants.  */
         variants.  */
Line 8724... Line 9499...
 
 
      /* If the branch offset if too big, use a ppc_stub_plt_branch.  */
      /* If the branch offset if too big, use a ppc_stub_plt_branch.  */
      if (off + (1 << 25) >= (bfd_vma) (1 << 26))
      if (off + (1 << 25) >= (bfd_vma) (1 << 26))
        {
        {
          struct ppc_branch_hash_entry *br_entry;
          struct ppc_branch_hash_entry *br_entry;
          unsigned int indx;
 
 
 
          br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
          br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table,
                                             stub_entry->root.string + 9,
                                             stub_entry->root.string + 9,
                                             TRUE, FALSE);
                                             TRUE, FALSE);
          if (br_entry == NULL)
          if (br_entry == NULL)
Line 8759... Line 9533...
                 + htab->brlt->output_offset
                 + htab->brlt->output_offset
                 + htab->brlt->output_section->vma
                 + htab->brlt->output_section->vma
                 - elf_gp (htab->brlt->output_section->owner)
                 - elf_gp (htab->brlt->output_section->owner)
                 - htab->stub_group[stub_entry->id_sec->id].toc_off);
                 - htab->stub_group[stub_entry->id_sec->id].toc_off);
 
 
          indx = off;
          if (info->emitrelocations)
 
            {
 
              stub_entry->stub_sec->reloc_count += 1 + (PPC_HA (off) != 0);
 
              stub_entry->stub_sec->flags |= SEC_RELOC;
 
            }
 
 
          if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
          if (stub_entry->stub_type != ppc_stub_plt_branch_r2off)
            {
            {
              size = 12;
              size = 12;
              if (PPC_HA (indx) != 0)
              if (PPC_HA (off) != 0)
                size = 16;
                size = 16;
            }
            }
          else
          else
            {
            {
              size = 20;
              size = 20;
              if (PPC_HA (indx) != 0)
              if (PPC_HA (off) != 0)
                size += 4;
                size += 4;
 
 
              if (PPC_HA (r2off) != 0)
              if (PPC_HA (r2off) != 0)
                size += 4;
                size += 4;
            }
            }
Line 8833... Line 9612...
  /* Set toc_off for com, und, abs and ind sections.  */
  /* Set toc_off for com, und, abs and ind sections.  */
  for (id = 0; id < 3; id++)
  for (id = 0; id < 3; id++)
    htab->stub_group[id].toc_off = TOC_BASE_OFF;
    htab->stub_group[id].toc_off = TOC_BASE_OFF;
 
 
  elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd);
  elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd);
 
  htab->toc_bfd = NULL;
 
  htab->toc_first_sec = NULL;
 
 
  /* We can't use output_bfd->section_count here to find the top output
  /* We can't use output_bfd->section_count here to find the top output
     section index as some sections may have been removed, and
     section index as some sections may have been removed, and
     strip_excluded_output_sections doesn't renumber the indices.  */
     strip_excluded_output_sections doesn't renumber the indices.  */
  for (section = output_bfd->sections, top_index = 0;
  for (section = output_bfd->sections, top_index = 0;
Line 8867... Line 9648...
{
{
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
  struct ppc_link_hash_table *htab = ppc_hash_table (info);
 
 
  if (!htab->no_multi_toc)
  if (!htab->no_multi_toc)
    {
    {
      bfd_vma addr = isec->output_offset + isec->output_section->vma;
      bfd_vma addr, off;
      bfd_vma off = addr - htab->toc_curr;
 
 
 
 
      if (htab->toc_bfd != isec->owner)
 
        {
 
          htab->toc_bfd = isec->owner;
 
          htab->toc_first_sec = isec;
 
        }
 
      addr = isec->output_offset + isec->output_section->vma;
 
      off = addr - htab->toc_curr;
      if (off + isec->size > 0x10000)
      if (off + isec->size > 0x10000)
 
        {
 
          addr = (htab->toc_first_sec->output_offset
 
                  + htab->toc_first_sec->output_section->vma);
        htab->toc_curr = addr;
        htab->toc_curr = addr;
 
        }
 
 
      elf_gp (isec->owner) = (htab->toc_curr
      elf_gp (isec->owner) = (htab->toc_curr
                              - elf_gp (isec->output_section->owner)
                              - elf_gp (isec->output_section->owner)
                              + TOC_BASE_OFF);
                              + TOC_BASE_OFF);
    }
    }
Line 8936... Line 9727...
  for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
  for (rel = relstart; rel < relstart + isec->reloc_count; ++rel)
    {
    {
      enum elf_ppc64_reloc_type r_type;
      enum elf_ppc64_reloc_type r_type;
      unsigned long r_symndx;
      unsigned long r_symndx;
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
 
      struct ppc_link_hash_entry *eh;
      Elf_Internal_Sym *sym;
      Elf_Internal_Sym *sym;
      asection *sym_sec;
      asection *sym_sec;
      struct _opd_sec_data *opd;
      struct _opd_sec_data *opd;
      bfd_vma sym_value;
      bfd_vma sym_value;
      bfd_vma dest;
      bfd_vma dest;
Line 8958... Line 9750...
          ret = -1;
          ret = -1;
          break;
          break;
        }
        }
 
 
      /* Calls to dynamic lib functions go through a plt call stub
      /* Calls to dynamic lib functions go through a plt call stub
         that uses r2.  Branches to undefined symbols might be a call
         that uses r2.  */
         using old-style dot symbols that can be satisfied by a plt
      eh = (struct ppc_link_hash_entry *) h;
         call into a new-style dynamic library.  */
 
      if (sym_sec == NULL)
 
        {
 
          struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h;
 
          if (eh != NULL
          if (eh != NULL
              && eh->oh != NULL
          && (eh->elf.plt.plist != NULL
              && eh->oh->elf.plt.plist != NULL)
              || (eh->oh != NULL
 
                  && ppc_follow_link (eh->oh)->elf.plt.plist != NULL)))
            {
            {
              ret = 1;
              ret = 1;
              break;
              break;
            }
            }
 
 
 
      if (sym_sec == NULL)
          /* Ignore other undefined symbols.  */
          /* Ignore other undefined symbols.  */
          continue;
          continue;
        }
 
 
 
      /* Assume branches to other sections not included in the link need
      /* Assume branches to other sections not included in the link need
         stubs too, to cover -R and absolute syms.  */
         stubs too, to cover -R and absolute syms.  */
      if (sym_sec->output_section == NULL)
      if (sym_sec->output_section == NULL)
        {
        {
Line 9348... Line 10137...
                  enum elf_ppc64_reloc_type r_type;
                  enum elf_ppc64_reloc_type r_type;
                  unsigned int r_indx;
                  unsigned int r_indx;
                  enum ppc_stub_type stub_type;
                  enum ppc_stub_type stub_type;
                  struct ppc_stub_hash_entry *stub_entry;
                  struct ppc_stub_hash_entry *stub_entry;
                  asection *sym_sec, *code_sec;
                  asection *sym_sec, *code_sec;
                  bfd_vma sym_value;
                  bfd_vma sym_value, code_value;
                  bfd_vma destination;
                  bfd_vma destination;
                  bfd_boolean ok_dest;
                  bfd_boolean ok_dest;
                  struct ppc_link_hash_entry *hash;
                  struct ppc_link_hash_entry *hash;
                  struct ppc_link_hash_entry *fdh;
                  struct ppc_link_hash_entry *fdh;
                  struct elf_link_hash_entry *h;
                  struct elf_link_hash_entry *h;
                  Elf_Internal_Sym *sym;
                  Elf_Internal_Sym *sym;
                  char *stub_name;
                  char *stub_name;
                  const asection *id_sec;
                  const asection *id_sec;
                  struct _opd_sec_data *opd;
                  struct _opd_sec_data *opd;
 
                  struct plt_entry *plt_ent;
 
 
                  r_type = ELF64_R_TYPE (irela->r_info);
                  r_type = ELF64_R_TYPE (irela->r_info);
                  r_indx = ELF64_R_SYM (irela->r_info);
                  r_indx = ELF64_R_SYM (irela->r_info);
 
 
                  if (r_type >= R_PPC64_max)
                  if (r_type >= R_PPC64_max)
Line 9404... Line 10194...
                    {
                    {
                      /* Recognise an old ABI func code entry sym, and
                      /* Recognise an old ABI func code entry sym, and
                         use the func descriptor sym instead if it is
                         use the func descriptor sym instead if it is
                         defined.  */
                         defined.  */
                      if (hash->elf.root.root.string[0] == '.'
                      if (hash->elf.root.root.string[0] == '.'
                          && (fdh = get_fdh (hash, htab)) != NULL)
                          && (fdh = lookup_fdh (hash, htab)) != NULL)
                        {
                        {
                          if (fdh->elf.root.type == bfd_link_hash_defined
                          if (fdh->elf.root.type == bfd_link_hash_defined
                              || fdh->elf.root.type == bfd_link_hash_defweak)
                              || fdh->elf.root.type == bfd_link_hash_defweak)
                            {
                            {
                              sym_sec = fdh->elf.root.u.def.section;
                              sym_sec = fdh->elf.root.u.def.section;
Line 9434... Line 10224...
                                     + sym_sec->output_offset
                                     + sym_sec->output_offset
                                     + sym_sec->output_section->vma);
                                     + sym_sec->output_section->vma);
                    }
                    }
 
 
                  code_sec = sym_sec;
                  code_sec = sym_sec;
 
                  code_value = sym_value;
                  opd = get_opd_info (sym_sec);
                  opd = get_opd_info (sym_sec);
                  if (opd != NULL)
                  if (opd != NULL)
                    {
                    {
                      bfd_vma dest;
                      bfd_vma dest;
 
 
                      if (hash == NULL && opd->adjust != NULL)
                      if (hash == NULL && opd->adjust != NULL)
                        {
                        {
                          long adjust = opd->adjust[sym_value / 8];
                          long adjust = opd->adjust[sym_value / 8];
                          if (adjust == -1)
                          if (adjust == -1)
                            continue;
                            continue;
 
                          code_value += adjust;
                          sym_value += adjust;
                          sym_value += adjust;
                        }
                        }
                      dest = opd_entry_value (sym_sec, sym_value,
                      dest = opd_entry_value (sym_sec, sym_value,
                                              &code_sec, &sym_value);
                                              &code_sec, &code_value);
                      if (dest != (bfd_vma) -1)
                      if (dest != (bfd_vma) -1)
                        {
                        {
                          destination = dest;
                          destination = dest;
                          if (fdh != NULL)
                          if (fdh != NULL)
                            {
                            {
                              /* Fixup old ABI sym to point at code
                              /* Fixup old ABI sym to point at code
                                 entry.  */
                                 entry.  */
                              hash->elf.root.type = bfd_link_hash_defweak;
                              hash->elf.root.type = bfd_link_hash_defweak;
                              hash->elf.root.u.def.section = code_sec;
                              hash->elf.root.u.def.section = code_sec;
                              hash->elf.root.u.def.value = sym_value;
                              hash->elf.root.u.def.value = code_value;
                            }
                            }
                        }
                        }
                    }
                    }
 
 
                  /* Determine what (if any) linker stub is needed.  */
                  /* Determine what (if any) linker stub is needed.  */
 
                  plt_ent = NULL;
                  stub_type = ppc_type_of_stub (section, irela, &hash,
                  stub_type = ppc_type_of_stub (section, irela, &hash,
                                                destination);
                                                &plt_ent, destination);
 
 
                  if (stub_type != ppc_stub_plt_call)
                  if (stub_type != ppc_stub_plt_call)
                    {
                    {
                      /* Check whether we need a TOC adjusting stub.
                      /* Check whether we need a TOC adjusting stub.
                         Since the linker pastes together pieces from
                         Since the linker pastes together pieces from
Line 9497... Line 10290...
                      && irela != internal_relocs)
                      && irela != internal_relocs)
                    {
                    {
                      /* Get tls info.  */
                      /* Get tls info.  */
                      char *tls_mask;
                      char *tls_mask;
 
 
                      if (!get_tls_mask (&tls_mask, NULL, &local_syms,
                      if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
                                         irela - 1, input_bfd))
                                         irela - 1, input_bfd))
                        goto error_ret_free_internal;
                        goto error_ret_free_internal;
                      if (*tls_mask != 0)
                      if (*tls_mask != 0)
                        continue;
                        continue;
                    }
                    }
Line 9537... Line 10330...
                        free (local_syms);
                        free (local_syms);
                      return FALSE;
                      return FALSE;
                    }
                    }
 
 
                  stub_entry->stub_type = stub_type;
                  stub_entry->stub_type = stub_type;
                  stub_entry->target_value = sym_value;
                  if (stub_type != ppc_stub_plt_call)
 
                    {
 
                      stub_entry->target_value = code_value;
                  stub_entry->target_section = code_sec;
                  stub_entry->target_section = code_sec;
 
                    }
 
                  else
 
                    {
 
                      stub_entry->target_value = sym_value;
 
                      stub_entry->target_section = sym_sec;
 
                    }
                  stub_entry->h = hash;
                  stub_entry->h = hash;
 
                  stub_entry->plt_ent = plt_ent;
                  stub_entry->addend = irela->r_addend;
                  stub_entry->addend = irela->r_addend;
 
 
                  if (stub_entry->h != NULL)
                  if (stub_entry->h != NULL)
                    htab->stub_globals += 1;
                    htab->stub_globals += 1;
                }
                }
Line 9582... Line 10384...
      if (htab->relbrlt != NULL)
      if (htab->relbrlt != NULL)
        htab->relbrlt->size = 0;
        htab->relbrlt->size = 0;
 
 
      bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
      bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info);
 
 
 
      if (info->emitrelocations
 
          && htab->glink != NULL && htab->glink->size != 0)
 
        {
 
          htab->glink->reloc_count = 1;
 
          htab->glink->flags |= SEC_RELOC;
 
        }
 
 
      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 9618... Line 10427...
  bfd_vma TOCstart;
  bfd_vma TOCstart;
 
 
  /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
  /* The TOC consists of sections .got, .toc, .tocbss, .plt in that
     order.  The TOC starts where the first of these sections starts.  */
     order.  The TOC starts where the first of these sections starts.  */
  s = bfd_get_section_by_name (obfd, ".got");
  s = bfd_get_section_by_name (obfd, ".got");
  if (s == NULL)
  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
    s = bfd_get_section_by_name (obfd, ".toc");
    s = bfd_get_section_by_name (obfd, ".toc");
  if (s == NULL)
  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
    s = bfd_get_section_by_name (obfd, ".tocbss");
    s = bfd_get_section_by_name (obfd, ".tocbss");
  if (s == NULL)
  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
    s = bfd_get_section_by_name (obfd, ".plt");
    s = bfd_get_section_by_name (obfd, ".plt");
  if (s == NULL)
  if (s == NULL || (s->flags & SEC_EXCLUDE) != 0)
    {
    {
      /* This may happen for
      /* This may happen for
         o  references to TOC base (SYM@toc / TOC[tc0]) without a
         o  references to TOC base (SYM@toc / TOC[tc0]) without a
         .toc directive
         .toc directive
         o  bad linker script
         o  bad linker script
Line 9637... Line 10446...
         FIXME: Warn user?  */
         FIXME: Warn user?  */
 
 
      /* Look for a likely section.  We probably won't even be
      /* Look for a likely section.  We probably won't even be
         using TOCstart.  */
         using TOCstart.  */
      for (s = obfd->sections; s != NULL; s = s->next)
      for (s = obfd->sections; s != NULL; s = s->next)
        if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY))
        if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY
 
                         | SEC_EXCLUDE))
            == (SEC_ALLOC | SEC_SMALL_DATA))
            == (SEC_ALLOC | SEC_SMALL_DATA))
          break;
          break;
      if (s == NULL)
      if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
        for (s = obfd->sections; s != NULL; s = s->next)
          if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA))
          if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_EXCLUDE))
              == (SEC_ALLOC | SEC_SMALL_DATA))
              == (SEC_ALLOC | SEC_SMALL_DATA))
            break;
            break;
      if (s == NULL)
      if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
        for (s = obfd->sections; s != NULL; s = s->next)
          if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC)
          if ((s->flags & (SEC_ALLOC | SEC_READONLY | SEC_EXCLUDE))
 
              == SEC_ALLOC)
            break;
            break;
      if (s == NULL)
      if (s == NULL)
        for (s = obfd->sections; s != NULL; s = s->next)
        for (s = obfd->sections; s != NULL; s = s->next)
          if ((s->flags & SEC_ALLOC) == SEC_ALLOC)
          if ((s->flags & (SEC_ALLOC | SEC_EXCLUDE)) == SEC_ALLOC)
            break;
            break;
    }
    }
 
 
  TOCstart = 0;
  TOCstart = 0;
  if (s != NULL)
  if (s != NULL)
Line 9703... Line 10514...
 
 
      /* Build the .glink plt call stub.  */
      /* Build the .glink plt call stub.  */
      if (htab->emit_stub_syms)
      if (htab->emit_stub_syms)
        {
        {
          struct elf_link_hash_entry *h;
          struct elf_link_hash_entry *h;
          h = elf_link_hash_lookup (&htab->elf, "__glink", TRUE, FALSE, FALSE);
          h = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve",
 
                                    TRUE, FALSE, FALSE);
          if (h == NULL)
          if (h == NULL)
            return FALSE;
            return FALSE;
          if (h->root.type == bfd_link_hash_new)
          if (h->root.type == bfd_link_hash_new)
            {
            {
              h->root.type = bfd_link_hash_defined;
              h->root.type = bfd_link_hash_defined;
Line 9718... Line 10530...
              h->ref_regular_nonweak = 1;
              h->ref_regular_nonweak = 1;
              h->forced_local = 1;
              h->forced_local = 1;
              h->non_elf = 0;
              h->non_elf = 0;
            }
            }
        }
        }
 
      plt0 = htab->plt->output_section->vma + htab->plt->output_offset - 16;
 
      if (info->emitrelocations)
 
        {
 
          Elf_Internal_Rela *r = get_relocs (htab->glink, 1);
 
          if (r == NULL)
 
            return FALSE;
 
          r->r_offset = (htab->glink->output_offset
 
                         + htab->glink->output_section->vma);
 
          r->r_info = ELF64_R_INFO (0, R_PPC64_REL64);
 
          r->r_addend = plt0;
 
        }
      p = htab->glink->contents;
      p = htab->glink->contents;
      plt0 = (htab->plt->output_section->vma
      plt0 -= htab->glink->output_section->vma + htab->glink->output_offset;
              + htab->plt->output_offset
 
              - (htab->glink->output_section->vma
 
                 + htab->glink->output_offset
 
                 + 16));
 
      bfd_put_64 (htab->glink->owner, plt0, p);
      bfd_put_64 (htab->glink->owner, plt0, p);
      p += 8;
      p += 8;
      bfd_put_32 (htab->glink->owner, MFLR_R12, p);
      bfd_put_32 (htab->glink->owner, MFLR_R12, p);
      p += 4;
      p += 4;
      bfd_put_32 (htab->glink->owner, BCL_20_31, p);
      bfd_put_32 (htab->glink->owner, BCL_20_31, p);
Line 9974... Line 10793...
      struct elf_link_hash_entry *h_elf;
      struct elf_link_hash_entry *h_elf;
      struct ppc_link_hash_entry *h;
      struct ppc_link_hash_entry *h;
      struct ppc_link_hash_entry *fdh;
      struct ppc_link_hash_entry *fdh;
      const char *sym_name;
      const char *sym_name;
      unsigned long r_symndx, toc_symndx;
      unsigned long r_symndx, toc_symndx;
 
      bfd_vma toc_addend;
      char tls_mask, tls_gd, tls_type;
      char tls_mask, tls_gd, tls_type;
      char sym_type;
      char sym_type;
      bfd_vma relocation;
      bfd_vma relocation;
      bfd_boolean unresolved_reloc;
      bfd_boolean unresolved_reloc;
      bfd_boolean warned;
      bfd_boolean warned;
Line 10067... Line 10887...
         RELOCS so that --emit-relocs will output something sensible
         RELOCS so that --emit-relocs will output something sensible
         for the final instruction stream.  */
         for the final instruction stream.  */
      tls_mask = 0;
      tls_mask = 0;
      tls_gd = 0;
      tls_gd = 0;
      toc_symndx = 0;
      toc_symndx = 0;
      if (IS_PPC64_TLS_RELOC (r_type))
 
        {
 
          if (h != NULL)
          if (h != NULL)
            tls_mask = h->tls_mask;
            tls_mask = h->tls_mask;
          else if (local_got_ents != NULL)
          else if (local_got_ents != NULL)
            {
            {
              char *lgot_masks;
          struct plt_entry **local_plt = (struct plt_entry **)
              lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
            (local_got_ents + symtab_hdr->sh_info);
 
          char *lgot_masks = (char *)
 
            (local_plt + symtab_hdr->sh_info);
              tls_mask = lgot_masks[r_symndx];
              tls_mask = lgot_masks[r_symndx];
            }
            }
          if (tls_mask == 0 && r_type == R_PPC64_TLS)
      if (tls_mask == 0
 
          && (r_type == R_PPC64_TLS
 
              || r_type == R_PPC64_TLSGD
 
              || r_type == R_PPC64_TLSLD))
            {
            {
              /* Check for toc tls entries.  */
              /* Check for toc tls entries.  */
              char *toc_tls;
              char *toc_tls;
 
 
              if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
          if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
                                 rel, input_bfd))
                             &local_syms, rel, input_bfd))
                return FALSE;
                return FALSE;
 
 
              if (toc_tls)
              if (toc_tls)
                tls_mask = *toc_tls;
                tls_mask = *toc_tls;
            }
            }
        }
 
 
 
      /* Check that tls relocs are used with tls syms, and non-tls
      /* Check that tls relocs are used with tls syms, and non-tls
         relocs are used with non-tls syms.  */
         relocs are used with non-tls syms.  */
      if (r_symndx != 0
      if (r_symndx != 0
          && r_type != R_PPC64_NONE
          && r_type != R_PPC64_NONE
          && (h == NULL
          && (h == NULL
              || h->elf.root.type == bfd_link_hash_defined
              || h->elf.root.type == bfd_link_hash_defined
              || h->elf.root.type == bfd_link_hash_defweak)
              || h->elf.root.type == bfd_link_hash_defweak)
          && IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS))
          && (IS_PPC64_TLS_RELOC (r_type)
 
              != (sym_type == STT_TLS
 
                  || (sym_type == STT_SECTION
 
                      && (sec->flags & SEC_THREAD_LOCAL) != 0))))
        {
        {
          if (r_type == R_PPC64_TLS && tls_mask != 0)
          if (tls_mask != 0
 
              && (r_type == R_PPC64_TLS
 
                  || r_type == R_PPC64_TLSGD
 
                  || r_type == R_PPC64_TLSLD))
            /* R_PPC64_TLS is OK against a symbol in the TOC.  */
            /* R_PPC64_TLS is OK against a symbol in the TOC.  */
            ;
            ;
          else
          else
            (*_bfd_error_handler)
            (*_bfd_error_handler)
              (sym_type == STT_TLS
              (!IS_PPC64_TLS_RELOC (r_type)
               ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
               ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
               : _("%B(%A+0x%lx): %s used with non-TLS symbol %s"),
               : _("%B(%A+0x%lx): %s used with non-TLS symbol %s"),
               input_bfd,
               input_bfd,
               input_section,
               input_section,
               (long) rel->r_offset,
               (long) rel->r_offset,
Line 10142... Line 10970...
          {
          {
            /* Check for toc tls entries.  */
            /* Check for toc tls entries.  */
            char *toc_tls;
            char *toc_tls;
            int retval;
            int retval;
 
 
            retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
            retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
                                   rel, input_bfd);
                                   &local_syms, rel, input_bfd);
            if (retval == 0)
            if (retval == 0)
              return FALSE;
              return FALSE;
 
 
            if (toc_tls)
            if (toc_tls)
              {
              {
Line 10191... Line 11019...
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset);
              r_type = R_PPC64_TPREL16_HA;
              r_type = R_PPC64_TPREL16_HA;
              if (toc_symndx != 0)
              if (toc_symndx != 0)
                {
                {
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
 
                  rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
                     get h, sym, sec etc. right.  */
                  rel--;
                  rel--;
                  continue;
                  continue;
                }
                }
Line 10205... Line 11034...
 
 
        case R_PPC64_TLS:
        case R_PPC64_TLS:
          if (tls_mask != 0
          if (tls_mask != 0
              && (tls_mask & TLS_TPREL) == 0)
              && (tls_mask & TLS_TPREL) == 0)
            {
            {
              bfd_vma rtra;
 
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
              if ((insn & ((0x3f << 26) | (31 << 11)))
              insn = _bfd_elf_ppc_at_tls_transform (insn, 13);
                  == ((31 << 26) | (13 << 11)))
              if (insn == 0)
                rtra = insn & ((1 << 26) - (1 << 16));
 
              else if ((insn & ((0x3f << 26) | (31 << 16)))
 
                       == ((31 << 26) | (13 << 16)))
 
                rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5);
 
              else
 
                abort ();
                abort ();
              if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1)
 
                /* add -> addi.  */
 
                insn = 14 << 26;
 
              else if ((insn & (31 << 1)) == 23 << 1
 
                       && ((insn & (31 << 6)) < 14 << 6
 
                           || ((insn & (31 << 6)) >= 16 << 6
 
                               && (insn & (31 << 6)) < 24 << 6)))
 
                /* load and store indexed -> dform.  */
 
                insn = (32 | ((insn >> 6) & 31)) << 26;
 
              else if ((insn & (31 << 1)) == 21 << 1
 
                       && (insn & (0x1a << 6)) == 0)
 
                /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
 
                insn = (((58 | ((insn >> 6) & 4)) << 26)
 
                        | ((insn >> 6) & 1));
 
              else if ((insn & (31 << 1)) == 21 << 1
 
                       && (insn & ((1 << 11) - (1 << 1))) == 341 << 1)
 
                /* lwax -> lwa.  */
 
                insn = (58 << 26) | 2;
 
              else
 
                abort ();
 
              insn |= rtra;
 
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              /* Was PPC64_TLS which sits on insn boundary, now
              /* Was PPC64_TLS which sits on insn boundary, now
                 PPC64_TPREL16_LO which is at low-order half-word.  */
                 PPC64_TPREL16_LO which is at low-order half-word.  */
              rel->r_offset += d_offset;
              rel->r_offset += d_offset;
              r_type = R_PPC64_TPREL16_LO;
              r_type = R_PPC64_TPREL16_LO;
              if (toc_symndx != 0)
              if (toc_symndx != 0)
                {
                {
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
                  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
 
                  rel->r_addend = toc_addend;
                  /* We changed the symbol.  Start over in order to
                  /* We changed the symbol.  Start over in order to
                     get h, sym, sec etc. right.  */
                     get h, sym, sec etc. right.  */
                  rel--;
                  rel--;
                  continue;
                  continue;
                }
                }
Line 10290... Line 11093...
 
 
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16:
        case R_PPC64_GOT_TLSLD16_LO:
        case R_PPC64_GOT_TLSLD16_LO:
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
            {
            {
              bfd_vma insn1, insn2, insn3;
              unsigned int insn1, insn2, insn3;
              bfd_vma offset;
              bfd_vma offset;
 
 
            tls_ldgd_opt:
            tls_ldgd_opt:
              /* We know that the next reloc is on a tls_get_addr
              offset = (bfd_vma) -1;
                 call, since ppc64_elf_tls_optimize checks this.  */
              /* If not using the newer R_PPC64_TLSGD/LD to mark
 
                 __tls_get_addr calls, we must trust that the call
 
                 stays with its arg setup insns, ie. that the next
 
                 reloc is the __tls_get_addr call associated with
 
                 the current reloc.  Edit both insns.  */
 
              if (input_section->has_tls_get_addr_call
 
                  && rel + 1 < relend
 
                  && branch_reloc_hash_match (input_bfd, rel + 1,
 
                                              htab->tls_get_addr,
 
                                              htab->tls_get_addr_fd))
              offset = rel[1].r_offset;
              offset = rel[1].r_offset;
              insn1 = bfd_get_32 (output_bfd,
 
                                  contents + rel->r_offset - d_offset);
 
              insn3 = bfd_get_32 (output_bfd,
 
                                  contents + offset + 4);
 
              if ((tls_mask & tls_gd) != 0)
              if ((tls_mask & tls_gd) != 0)
                {
                {
                  /* IE */
                  /* IE */
 
                  insn1 = bfd_get_32 (output_bfd,
 
                                      contents + rel->r_offset - d_offset);
                  insn1 &= (1 << 26) - (1 << 2);
                  insn1 &= (1 << 26) - (1 << 2);
                  insn1 |= 58 << 26;    /* ld */
                  insn1 |= 58 << 26;    /* ld */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
                  rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
                  if (offset != (bfd_vma) -1)
                                                R_PPC64_NONE);
                    rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
                  if ((tls_mask & TLS_EXPLICIT) == 0)
                  if ((tls_mask & TLS_EXPLICIT) == 0)
                    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
                    r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
                              + R_PPC64_GOT_TPREL16_DS);
                              + R_PPC64_GOT_TPREL16_DS);
                  else
                  else
                    r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16;
                    r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16;
Line 10324... Line 11134...
                  insn1 = 0x3c6d0000;   /* addis 3,13,0 */
                  insn1 = 0x3c6d0000;   /* addis 3,13,0 */
                  insn2 = 0x38630000;   /* addi 3,3,0 */
                  insn2 = 0x38630000;   /* addi 3,3,0 */
                  if (tls_gd == 0)
                  if (tls_gd == 0)
                    {
                    {
                      /* Was an LD reloc.  */
                      /* Was an LD reloc.  */
 
                      if (toc_symndx)
 
                        sec = local_sections[toc_symndx];
 
                      for (r_symndx = 0;
 
                           r_symndx < symtab_hdr->sh_info;
 
                           r_symndx++)
 
                        if (local_sections[r_symndx] == sec)
 
                          break;
 
                      if (r_symndx >= symtab_hdr->sh_info)
                      r_symndx = 0;
                      r_symndx = 0;
                      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
                      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
                      rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
                      if (r_symndx != 0)
 
                        rel->r_addend -= (local_syms[r_symndx].st_value
 
                                          + sec->output_offset
 
                                          + sec->output_section->vma);
                    }
                    }
                  else if (toc_symndx != 0)
                  else if (toc_symndx != 0)
 
                    {
                    r_symndx = toc_symndx;
                    r_symndx = toc_symndx;
 
                      rel->r_addend = toc_addend;
 
                    }
                  r_type = R_PPC64_TPREL16_HA;
                  r_type = R_PPC64_TPREL16_HA;
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
                  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
 
                  if (offset != (bfd_vma) -1)
 
                    {
                  rel[1].r_info = ELF64_R_INFO (r_symndx,
                  rel[1].r_info = ELF64_R_INFO (r_symndx,
                                                R_PPC64_TPREL16_LO);
                                                R_PPC64_TPREL16_LO);
                  rel[1].r_offset += d_offset;
                      rel[1].r_offset = offset + d_offset;
 
                      rel[1].r_addend = rel->r_addend;
                }
                }
 
                }
 
              bfd_put_32 (output_bfd, insn1,
 
                          contents + rel->r_offset - d_offset);
 
              if (offset != (bfd_vma) -1)
 
                {
 
                  insn3 = bfd_get_32 (output_bfd,
 
                                      contents + offset + 4);
              if (insn3 == NOP
              if (insn3 == NOP
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
                {
                {
                  insn3 = insn2;
 
                  insn2 = NOP;
 
                  rel[1].r_offset += 4;
                  rel[1].r_offset += 4;
 
                      bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 
                      insn2 = NOP;
                }
                }
              bfd_put_32 (output_bfd, insn1,
 
                          contents + rel->r_offset - d_offset);
 
              bfd_put_32 (output_bfd, insn2, contents + offset);
              bfd_put_32 (output_bfd, insn2, contents + offset);
              bfd_put_32 (output_bfd, insn3, contents + offset + 4);
                }
              if (tls_gd == 0 || toc_symndx != 0)
              if ((tls_mask & tls_gd) == 0
 
                  && (tls_gd == 0 || toc_symndx != 0))
                {
                {
                  /* We changed the symbol.  Start over in order
                  /* We changed the symbol.  Start over in order
                     to get h, sym, sec etc. right.  */
                     to get h, sym, sec etc. right.  */
                  rel--;
                  rel--;
                  continue;
                  continue;
                }
                }
            }
            }
          break;
          break;
 
 
 
        case R_PPC64_TLSGD:
 
          if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
 
            {
 
              unsigned int insn2, insn3;
 
              bfd_vma offset = rel->r_offset;
 
 
 
              if ((tls_mask & TLS_TPRELGD) != 0)
 
                {
 
                  /* IE */
 
                  r_type = R_PPC64_NONE;
 
                  insn2 = 0x7c636a14;   /* add 3,3,13 */
 
                }
 
              else
 
                {
 
                  /* LE */
 
                  if (toc_symndx != 0)
 
                    {
 
                      r_symndx = toc_symndx;
 
                      rel->r_addend = toc_addend;
 
                    }
 
                  r_type = R_PPC64_TPREL16_LO;
 
                  rel->r_offset = offset + d_offset;
 
                  insn2 = 0x38630000;   /* addi 3,3,0 */
 
                }
 
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
 
              /* Zap the reloc on the _tls_get_addr call too.  */
 
              BFD_ASSERT (offset == rel[1].r_offset);
 
              rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
 
              insn3 = bfd_get_32 (output_bfd,
 
                                  contents + offset + 4);
 
              if (insn3 == NOP
 
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
 
                {
 
                  rel->r_offset += 4;
 
                  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 
                  insn2 = NOP;
 
                }
 
              bfd_put_32 (output_bfd, insn2, contents + offset);
 
              if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
 
                {
 
                  rel--;
 
                  continue;
 
                }
 
            }
 
          break;
 
 
 
        case R_PPC64_TLSLD:
 
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
 
            {
 
              unsigned int insn2, insn3;
 
              bfd_vma offset = rel->r_offset;
 
 
 
              if (toc_symndx)
 
                sec = local_sections[toc_symndx];
 
              for (r_symndx = 0;
 
                   r_symndx < symtab_hdr->sh_info;
 
                   r_symndx++)
 
                if (local_sections[r_symndx] == sec)
 
                  break;
 
              if (r_symndx >= symtab_hdr->sh_info)
 
                r_symndx = 0;
 
              rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
 
              if (r_symndx != 0)
 
                rel->r_addend -= (local_syms[r_symndx].st_value
 
                                  + sec->output_offset
 
                                  + sec->output_section->vma);
 
 
 
              r_type = R_PPC64_TPREL16_LO;
 
              rel->r_info = ELF64_R_INFO (r_symndx, r_type);
 
              rel->r_offset = offset + d_offset;
 
              /* Zap the reloc on the _tls_get_addr call too.  */
 
              BFD_ASSERT (offset == rel[1].r_offset);
 
              rel[1].r_info = ELF64_R_INFO (STN_UNDEF, R_PPC64_NONE);
 
              insn2 = 0x38630000;       /* addi 3,3,0 */
 
              insn3 = bfd_get_32 (output_bfd,
 
                                  contents + offset + 4);
 
              if (insn3 == NOP
 
                  || insn3 == CROR_151515 || insn3 == CROR_313131)
 
                {
 
                  rel->r_offset += 4;
 
                  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 
                  insn2 = NOP;
 
                }
 
              bfd_put_32 (output_bfd, insn2, contents + offset);
 
              rel--;
 
              continue;
 
            }
 
          break;
 
 
        case R_PPC64_DTPMOD64:
        case R_PPC64_DTPMOD64:
          if (rel + 1 < relend
          if (rel + 1 < relend
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
              && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
              && rel[1].r_offset == rel->r_offset + 8)
              && rel[1].r_offset == rel->r_offset + 8)
            {
            {
Line 10430... Line 11352...
             linkage stubs needs to be followed by a nop, as the nop
             linkage stubs needs to be followed by a nop, as the nop
             will be replaced with an instruction to restore the TOC
             will be replaced with an instruction to restore the TOC
             base pointer.  */
             base pointer.  */
          stub_entry = NULL;
          stub_entry = NULL;
          fdh = h;
          fdh = h;
          if (((h != NULL
          if (h != NULL
                && (((fdh = h->oh) != NULL
              && h->oh != NULL
 
              && h->oh->is_func_descriptor)
 
            fdh = ppc_follow_link (h->oh);
 
          if (((fdh != NULL
                     && fdh->elf.plt.plist != NULL)
                     && fdh->elf.plt.plist != NULL)
                    || (fdh = h)->elf.plt.plist != NULL))
 
               || (sec != NULL
               || (sec != NULL
                   && sec->output_section != NULL
                   && sec->output_section != NULL
                   && sec->id <= htab->top_id
                   && sec->id <= htab->top_id
                   && (htab->stub_group[sec->id].toc_off
                   && (htab->stub_group[sec->id].toc_off
                       != htab->stub_group[input_section->id].toc_off)))
                       != htab->stub_group[input_section->id].toc_off))
 
               || (h == NULL
 
                   && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
              && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
              && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh,
                                                   rel, htab)) != NULL
                                                   rel, htab)) != NULL
              && (stub_entry->stub_type == ppc_stub_plt_call
              && (stub_entry->stub_type == ppc_stub_plt_call
                  || 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))
Line 10454... Line 11380...
                  unsigned long nop;
                  unsigned long nop;
                  nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
                  nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4);
                  if (nop == NOP
                  if (nop == NOP
                      || nop == CROR_151515 || nop == CROR_313131)
                      || nop == CROR_151515 || nop == CROR_313131)
                    {
                    {
 
                      if (h != NULL
 
                          && (h == htab->tls_get_addr_fd
 
                              || h == htab->tls_get_addr)
 
                          && !htab->no_tls_get_addr_opt)
 
                        {
 
                          /* Special stub used, leave nop alone.  */
 
                        }
 
                      else
                      bfd_put_32 (input_bfd, LD_R2_40R1,
                      bfd_put_32 (input_bfd, LD_R2_40R1,
                                  contents + rel->r_offset + 4);
                                  contents + rel->r_offset + 4);
                      can_plt_call = TRUE;
                      can_plt_call = TRUE;
                    }
                    }
                }
                }
Line 10585... Line 11519...
          /* NOP out calls to undefined weak functions.
          /* NOP out calls to undefined weak functions.
             We can thus call a weak function without first
             We can thus call a weak function without first
             checking whether the function is defined.  */
             checking whether the function is defined.  */
          else if (h != NULL
          else if (h != NULL
                   && h->elf.root.type == bfd_link_hash_undefweak
                   && h->elf.root.type == bfd_link_hash_undefweak
 
                   && h->elf.dynindx == -1
                   && r_type == R_PPC64_REL24
                   && r_type == R_PPC64_REL24
                   && relocation == 0
                   && relocation == 0
                   && addend == 0)
                   && addend == 0)
            {
            {
              bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
              bfd_put_32 (output_bfd, NOP, contents + rel->r_offset);
Line 10610... Line 11545...
          ret = FALSE;
          ret = FALSE;
          continue;
          continue;
 
 
        case R_PPC64_NONE:
        case R_PPC64_NONE:
        case R_PPC64_TLS:
        case R_PPC64_TLS:
 
        case R_PPC64_TLSGD:
 
        case R_PPC64_TLSLD:
        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 10720... Line 11657...
            else
            else
              {
              {
                /* Generate relocs for the dynamic linker, except in
                /* Generate relocs for the dynamic linker, except in
                   the case of TLSLD where we'll use one entry per
                   the case of TLSLD where we'll use one entry per
                   module.  */
                   module.  */
                asection *relgot = ppc64_elf_tdata (input_bfd)->relgot;
                asection *relgot;
 
                bfd_boolean ifunc;
 
 
                *offp = off | 1;
                *offp = off | 1;
 
                relgot = NULL;
 
                ifunc = (h != NULL
 
                         ? h->elf.type == STT_GNU_IFUNC
 
                         : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC);
                if ((info->shared || indx != 0)
                if ((info->shared || indx != 0)
                    && (h == NULL
                    && (offp == &ppc64_tlsld_got (input_bfd)->offset
 
                        || h == NULL
                        || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                        || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                        || h->elf.root.type != bfd_link_hash_undefweak))
                        || h->elf.root.type != bfd_link_hash_undefweak))
 
                  relgot = ppc64_elf_tdata (input_bfd)->relgot;
 
                else if (ifunc)
 
                  relgot = htab->reliplt;
 
                if (relgot != NULL)
                  {
                  {
                    outrel.r_offset = (got->output_section->vma
                    outrel.r_offset = (got->output_section->vma
                                       + got->output_offset
                                       + got->output_offset
                                       + off);
                                       + off);
                    outrel.r_addend = addend;
                    outrel.r_addend = addend;
Line 10753... Line 11700...
                      }
                      }
                    else if (tls_type == (TLS_TLS | TLS_DTPREL))
                    else if (tls_type == (TLS_TLS | TLS_DTPREL))
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64);
                    else if (tls_type == (TLS_TLS | TLS_TPREL))
                    else if (tls_type == (TLS_TLS | TLS_TPREL))
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64);
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64);
                    else if (indx == 0)
                    else if (indx != 0)
 
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
 
                    else
                      {
                      {
                        outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE);
                        if (ifunc)
 
                          outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
 
                        else
 
                          outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 
 
                        /* Write the .got section contents for the sake
                        /* Write the .got section contents for the sake
                           of prelink.  */
                           of prelink.  */
                        loc = got->contents + off;
                        loc = got->contents + off;
                        bfd_put_64 (output_bfd, outrel.r_addend + relocation,
                        bfd_put_64 (output_bfd, outrel.r_addend + relocation,
                                    loc);
                                    loc);
                      }
                      }
                    else
 
                      outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT);
 
 
 
                    if (indx == 0 && tls_type != (TLS_TLS | TLS_LD))
                    if (indx == 0 && tls_type != (TLS_TLS | TLS_LD))
                      {
                      {
                        outrel.r_addend += relocation;
                        outrel.r_addend += relocation;
                        if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL))
                        if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL))
Line 10807... Line 11757...
              }
              }
 
 
            if (off >= (bfd_vma) -2)
            if (off >= (bfd_vma) -2)
              abort ();
              abort ();
 
 
            relocation = got->output_offset + off;
            relocation = got->output_section->vma + got->output_offset + off;
 
            addend = -(TOCstart + htab->stub_group[input_section->id].toc_off);
            /* TOC base (r2) is TOC start plus 0x8000.  */
 
            addend = -TOC_BASE_OFF;
 
          }
          }
          break;
          break;
 
 
        case R_PPC64_PLT16_HA:
        case R_PPC64_PLT16_HA:
        case R_PPC64_PLT16_HI:
        case R_PPC64_PLT16_HI:
Line 10883... Line 11831...
        case R_PPC64_SECTOFF_HA:
        case R_PPC64_SECTOFF_HA:
          if (sec != NULL)
          if (sec != NULL)
            addend -= sec->output_section->vma;
            addend -= sec->output_section->vma;
          break;
          break;
 
 
 
        case R_PPC64_REL16:
 
        case R_PPC64_REL16_LO:
 
        case R_PPC64_REL16_HI:
 
        case R_PPC64_REL16_HA:
 
          break;
 
 
        case R_PPC64_REL14:
        case R_PPC64_REL14:
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRNTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL14_BRTAKEN:
        case R_PPC64_REL24:
        case R_PPC64_REL24:
          break;
          break;
Line 10899... Line 11853...
        case R_PPC64_TPREL16_LO_DS:
        case R_PPC64_TPREL16_LO_DS:
        case R_PPC64_TPREL16_HIGHER:
        case R_PPC64_TPREL16_HIGHER:
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHERA:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHEST:
        case R_PPC64_TPREL16_HIGHESTA:
        case R_PPC64_TPREL16_HIGHESTA:
 
          if (h != NULL
 
              && h->elf.root.type == bfd_link_hash_undefweak
 
              && h->elf.dynindx == -1)
 
            {
 
              /* Make this relocation against an undefined weak symbol
 
                 resolve to zero.  This is really just a tweak, since
 
                 code using weak externs ought to check that they are
 
                 defined before using them.  */
 
              bfd_byte *p = contents + rel->r_offset - d_offset;
 
 
 
              insn = bfd_get_32 (output_bfd, p);
 
              insn = _bfd_elf_ppc_at_tprel_transform (insn, 13);
 
              if (insn != 0)
 
                bfd_put_32 (output_bfd, insn, p);
 
              break;
 
            }
          addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          addend -= htab->elf.tls_sec->vma + TP_OFFSET;
          if (info->shared)
          if (info->shared)
            /* The TPREL16 relocs shouldn't really be used in shared
            /* The TPREL16 relocs shouldn't really be used in shared
               libs as they will result in DT_TEXTREL being set, but
               libs as they will result in DT_TEXTREL being set, but
               support them anyway.  */
               support them anyway.  */
Line 10968... Line 11938...
 
 
          if ((info->shared
          if ((info->shared
               && (h == NULL
               && (h == NULL
                   || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                   || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
                   || h->elf.root.type != bfd_link_hash_undefweak)
                   || h->elf.root.type != bfd_link_hash_undefweak)
               && (MUST_BE_DYN_RELOC (r_type)
               && (must_be_dyn_reloc (info, r_type)
                   || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
                   || !SYMBOL_CALLS_LOCAL (info, &h->elf)))
              || (ELIMINATE_COPY_RELOCS
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && !info->shared
                  && h != NULL
                  && h != NULL
                  && h->elf.dynindx != -1
                  && h->elf.dynindx != -1
                  && !h->elf.non_got_ref
                  && !h->elf.non_got_ref
                  && h->elf.def_dynamic
                  && !h->elf.def_regular)
                  && !h->elf.def_regular))
              || (!info->shared
 
                  && (h != NULL
 
                      ? h->elf.type == STT_GNU_IFUNC
 
                      : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)))
            {
            {
              Elf_Internal_Rela outrel;
 
              bfd_boolean skip, relocate;
              bfd_boolean skip, relocate;
              asection *sreloc;
              asection *sreloc;
              bfd_byte *loc;
 
              bfd_vma out_off;
              bfd_vma out_off;
 
 
              /* When generating a dynamic object, these relocations
              /* When generating a dynamic object, these relocations
                 are copied into the output file to be resolved at run
                 are copied into the output file to be resolved at run
                 time.  */
                 time.  */
Line 11041... Line 12012...
                             bug in binutils handling of weak syms.)
                             bug in binutils handling of weak syms.)
                             In these cases we won't use the opd
                             In these cases we won't use the opd
                             entry in this lib.  */
                             entry in this lib.  */
                          unresolved_reloc = FALSE;
                          unresolved_reloc = FALSE;
                        }
                        }
 
                      if (!is_opd
 
                          && r_type == R_PPC64_ADDR64
 
                          && (h != NULL
 
                              ? h->elf.type == STT_GNU_IFUNC
 
                              : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC))
 
                        outrel.r_info = ELF64_R_INFO (0, R_PPC64_IRELATIVE);
 
                      else
 
                        {
                      outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
                      outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE);
 
 
                      /* We need to relocate .opd contents for ld.so.
                      /* We need to relocate .opd contents for ld.so.
                         Prelink also wants simple and consistent rules
                         Prelink also wants simple and consistent rules
                         for relocs.  This make all RELATIVE relocs have
                         for relocs.  This make all RELATIVE relocs have
                         *r_offset equal to r_addend.  */
                         *r_offset equal to r_addend.  */
                      relocate = TRUE;
                      relocate = TRUE;
                    }
                    }
 
                    }
                  else
                  else
                    {
                    {
                      long indx = 0;
                      long indx = 0;
 
 
                      if (bfd_is_abs_section (sec))
                      if (h != NULL
 
                          ? h->elf.type == STT_GNU_IFUNC
 
                          : ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
 
                        {
 
                          (*_bfd_error_handler)
 
                            (_("%B(%A+0x%lx): relocation %s for indirect "
 
                               "function %s unsupported"),
 
                             input_bfd,
 
                             input_section,
 
                             (long) rel->r_offset,
 
                             ppc64_elf_howto_table[r_type]->name,
 
                             sym_name);
 
                          ret = FALSE;
 
                        }
 
                      else if (r_symndx == 0 || bfd_is_abs_section (sec))
                        ;
                        ;
                      else if (sec == NULL || sec->owner == NULL)
                      else if (sec == NULL || sec->owner == NULL)
                        {
                        {
                          bfd_set_error (bfd_error_bad_value);
                          bfd_set_error (bfd_error_bad_value);
                          return FALSE;
                          return FALSE;
Line 11091... Line 12085...
                      outrel.r_info = ELF64_R_INFO (indx, r_type);
                      outrel.r_info = ELF64_R_INFO (indx, r_type);
                    }
                    }
                }
                }
 
 
              sreloc = elf_section_data (input_section)->sreloc;
              sreloc = elf_section_data (input_section)->sreloc;
 
              if (!htab->elf.dynamic_sections_created)
 
                sreloc = htab->reliplt;
              if (sreloc == NULL)
              if (sreloc == NULL)
                abort ();
                abort ();
 
 
              if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
              if (sreloc->reloc_count * sizeof (Elf64_External_Rela)
                  >= sreloc->size)
                  >= sreloc->size)
Line 11132... Line 12128...
          break;
          break;
 
 
        case R_PPC64_COPY:
        case R_PPC64_COPY:
        case R_PPC64_GLOB_DAT:
        case R_PPC64_GLOB_DAT:
        case R_PPC64_JMP_SLOT:
        case R_PPC64_JMP_SLOT:
 
        case R_PPC64_JMP_IREL:
        case R_PPC64_RELATIVE:
        case R_PPC64_RELATIVE:
          /* We shouldn't ever see these dynamic relocs in relocatable
          /* We shouldn't ever see these dynamic relocs in relocatable
             files.  */
             files.  */
          /* Fall through.  */
          /* Fall through.  */
 
 
Line 11164... Line 12161...
        {
        {
        default:
        default:
          break;
          break;
 
 
        case R_PPC64_ADDR16_HA:
        case R_PPC64_ADDR16_HA:
 
        case R_PPC64_REL16_HA:
        case R_PPC64_ADDR16_HIGHERA:
        case R_PPC64_ADDR16_HIGHERA:
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_ADDR16_HIGHESTA:
        case R_PPC64_TOC16_HA:
        case R_PPC64_TOC16_HA:
        case R_PPC64_SECTOFF_HA:
        case R_PPC64_SECTOFF_HA:
        case R_PPC64_TPREL16_HA:
        case R_PPC64_TPREL16_HA:
Line 11329... Line 12327...
  return ret;
  return ret;
}
}
 
 
/* Adjust the value of any local symbols in opd sections.  */
/* Adjust the value of any local symbols in opd sections.  */
 
 
static bfd_boolean
static int
ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
ppc64_elf_output_symbol_hook (struct bfd_link_info *info,
                              const char *name ATTRIBUTE_UNUSED,
                              const char *name ATTRIBUTE_UNUSED,
                              Elf_Internal_Sym *elfsym,
                              Elf_Internal_Sym *elfsym,
                              asection *input_sec,
                              asection *input_sec,
                              struct elf_link_hash_entry *h)
                              struct elf_link_hash_entry *h)
Line 11341... Line 12339...
  struct _opd_sec_data *opd;
  struct _opd_sec_data *opd;
  long adjust;
  long adjust;
  bfd_vma value;
  bfd_vma value;
 
 
  if (h != NULL)
  if (h != NULL)
    return TRUE;
    return 1;
 
 
  opd = get_opd_info (input_sec);
  opd = get_opd_info (input_sec);
  if (opd == NULL || opd->adjust == NULL)
  if (opd == NULL || opd->adjust == NULL)
    return TRUE;
    return 1;
 
 
  value = elfsym->st_value - input_sec->output_offset;
  value = elfsym->st_value - input_sec->output_offset;
  if (!info->relocatable)
  if (!info->relocatable)
    value -= input_sec->output_section->vma;
    value -= input_sec->output_section->vma;
 
 
  adjust = opd->adjust[value / 8];
  adjust = opd->adjust[value / 8];
  if (adjust == -1)
  if (adjust == -1)
    elfsym->st_value = 0;
    return 2;
  else
 
    elfsym->st_value += adjust;
    elfsym->st_value += adjust;
  return TRUE;
  return 1;
}
}
 
 
/* Finish up dynamic symbol handling.  We set the contents of various
/* Finish up dynamic symbol handling.  We set the contents of various
   dynamic sections here.  */
   dynamic sections here.  */
 
 
Line 11380... Line 12378...
  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
    if (ent->plt.offset != (bfd_vma) -1)
    if (ent->plt.offset != (bfd_vma) -1)
      {
      {
        /* This symbol has an entry in the procedure linkage
        /* This symbol has an entry in the procedure linkage
           table.  Set it up.  */
           table.  Set it up.  */
 
        if (!htab->elf.dynamic_sections_created
        if (htab->plt == NULL
            || h->dynindx == -1)
            || htab->relplt == NULL
          {
            || htab->glink == NULL)
            BFD_ASSERT (h->type == STT_GNU_IFUNC
          abort ();
                        && h->def_regular
 
                        && (h->root.type == bfd_link_hash_defined
        /* Create a JMP_SLOT reloc to inform the dynamic linker to
                            || h->root.type == bfd_link_hash_defweak));
           fill in the PLT entry.  */
            rela.r_offset = (htab->iplt->output_section->vma
 
                             + htab->iplt->output_offset
 
                             + ent->plt.offset);
 
            rela.r_info = ELF64_R_INFO (0, R_PPC64_JMP_IREL);
 
            rela.r_addend = (h->root.u.def.value
 
                             + h->root.u.def.section->output_offset
 
                             + h->root.u.def.section->output_section->vma
 
                             + ent->addend);
 
            loc = (htab->reliplt->contents
 
                   + (htab->reliplt->reloc_count++
 
                      * sizeof (Elf64_External_Rela)));
 
          }
 
        else
 
          {
        rela.r_offset = (htab->plt->output_section->vma
        rela.r_offset = (htab->plt->output_section->vma
                         + htab->plt->output_offset
                         + htab->plt->output_offset
                         + ent->plt.offset);
                         + ent->plt.offset);
        rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
        rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT);
        rela.r_addend = ent->addend;
        rela.r_addend = ent->addend;
 
            loc = (htab->relplt->contents
        loc = htab->relplt->contents;
                   + ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
        loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
                      / (PLT_ENTRY_SIZE / sizeof (Elf64_External_Rela))));
                * sizeof (Elf64_External_Rela));
          }
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
        bfd_elf64_swap_reloca_out (output_bfd, &rela, loc);
      }
      }
 
 
  if (h->needs_copy)
  if (h->needs_copy)
    {
    {
      Elf_Internal_Rela rela;
 
      bfd_byte *loc;
 
 
 
      /* This symbol needs a copy reloc.  Set it up.  */
      /* This symbol needs a copy reloc.  Set it up.  */
 
 
      if (h->dynindx == -1
      if (h->dynindx == -1
          || (h->root.type != bfd_link_hash_defined
          || (h->root.type != bfd_link_hash_defined
              && h->root.type != bfd_link_hash_defweak)
              && h->root.type != bfd_link_hash_defweak)
Line 11581... Line 12589...
                                       &elf_section_data (htab->brlt)->rel_hdr,
                                       &elf_section_data (htab->brlt)->rel_hdr,
                                       elf_section_data (htab->brlt)->relocs,
                                       elf_section_data (htab->brlt)->relocs,
                                       NULL))
                                       NULL))
    return FALSE;
    return FALSE;
 
 
 
  if (htab->glink != NULL
 
      && htab->glink->reloc_count != 0
 
      && !_bfd_elf_link_output_relocs (output_bfd,
 
                                       htab->glink,
 
                                       &elf_section_data (htab->glink)->rel_hdr,
 
                                       elf_section_data (htab->glink)->relocs,
 
                                       NULL))
 
    return FALSE;
 
 
  /* We need to handle writing out multiple GOT sections ourselves,
  /* We need to handle writing out multiple GOT sections ourselves,
     since we didn't add them to DYNOBJ.  We know dynobj is the first
     since we didn't add them to DYNOBJ.  We know dynobj is the first
     bfd.  */
     bfd.  */
  while ((dynobj = dynobj->link_next) != NULL)
  while ((dynobj = dynobj->link_next) != NULL)
    {
    {

powered by: WebSVN 2.1.0

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