OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gdb-6.8/] [bfd/] [elf32-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...
/* PowerPC-specific support for 32-bit ELF
/* PowerPC-specific support for 32-bit ELF
   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
   Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
   2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
   2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
   Written by Ian Lance Taylor, Cygnus Support.
   Written by Ian Lance Taylor, Cygnus Support.
 
 
   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
Line 59... Line 59...
#define PLT_NUM_SINGLE_ENTRIES 8192
#define PLT_NUM_SINGLE_ENTRIES 8192
 
 
/* For new-style .glink and .plt.  */
/* For new-style .glink and .plt.  */
#define GLINK_PLTRESOLVE 16*4
#define GLINK_PLTRESOLVE 16*4
#define GLINK_ENTRY_SIZE 4*4
#define GLINK_ENTRY_SIZE 4*4
 
#define TLS_GET_ADDR_GLINK_SIZE 12*4
 
 
/* VxWorks uses its own plt layout, filled in by the static linker.  */
/* VxWorks uses its own plt layout, filled in by the static linker.  */
 
 
/* The standard VxWorks PLT entry.  */
/* The standard VxWorks PLT entry.  */
#define VXWORKS_PLT_ENTRY_SIZE 32
#define VXWORKS_PLT_ENTRY_SIZE 32
Line 133... Line 134...
#define ADDIS_11_11     0x3d6b0000
#define ADDIS_11_11     0x3d6b0000
#define ADDIS_11_30     0x3d7e0000
#define ADDIS_11_30     0x3d7e0000
#define ADDIS_12_12     0x3d8c0000
#define ADDIS_12_12     0x3d8c0000
#define ADDI_11_11      0x396b0000
#define ADDI_11_11      0x396b0000
#define ADD_0_11_11     0x7c0b5a14
#define ADD_0_11_11     0x7c0b5a14
 
#define ADD_3_12_2      0x7c6c1214
#define ADD_11_0_11     0x7d605a14
#define ADD_11_0_11     0x7d605a14
#define B               0x48000000
#define B               0x48000000
#define BCL_20_31       0x429f0005
#define BCL_20_31       0x429f0005
#define BCTR            0x4e800420
#define BCTR            0x4e800420
 
#define BEQLR           0x4d820020
 
#define CMPWI_11_0      0x2c0b0000
#define LIS_11          0x3d600000
#define LIS_11          0x3d600000
#define LIS_12          0x3d800000
#define LIS_12          0x3d800000
#define LWZU_0_12       0x840c0000
#define LWZU_0_12       0x840c0000
#define LWZ_0_12        0x800c0000
#define LWZ_0_12        0x800c0000
 
#define LWZ_11_3        0x81630000
#define LWZ_11_11       0x816b0000
#define LWZ_11_11       0x816b0000
#define LWZ_11_30       0x817e0000
#define LWZ_11_30       0x817e0000
 
#define LWZ_12_3        0x81830000
#define LWZ_12_12       0x818c0000
#define LWZ_12_12       0x818c0000
 
#define MR_0_3          0x7c601b78
 
#define MR_3_0          0x7c030378
#define MFLR_0          0x7c0802a6
#define MFLR_0          0x7c0802a6
#define MFLR_12         0x7d8802a6
#define MFLR_12         0x7d8802a6
#define MTCTR_0         0x7c0903a6
#define MTCTR_0         0x7c0903a6
#define MTCTR_11        0x7d6903a6
#define MTCTR_11        0x7d6903a6
#define MTLR_0          0x7c0803a6
#define MTLR_0          0x7c0803a6
Line 155... Line 163...
#define SUB_11_11_12    0x7d6c5850
#define SUB_11_11_12    0x7d6c5850
 
 
/* Offset of tp and dtp pointers from start of TLS block.  */
/* Offset of tp and dtp pointers from start of TLS block.  */
#define TP_OFFSET       0x7000
#define TP_OFFSET       0x7000
#define DTP_OFFSET      0x8000
#define DTP_OFFSET      0x8000
 
 
 
/* The value of a defined global symbol.  */
 
#define SYM_VAL(SYM) \
 
  ((SYM)->root.u.def.section->output_section->vma       \
 
   + (SYM)->root.u.def.section->output_offset           \
 
   + (SYM)->root.u.def.value)


static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
static reloc_howto_type *ppc_elf_howto_table[R_PPC_max];
 
 
static reloc_howto_type ppc_elf_howto_raw[] = {
static reloc_howto_type ppc_elf_howto_raw[] = {
  /* This reloc does nothing.  */
  /* This reloc does nothing.  */
Line 745... Line 759...
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                      /* src_mask */
         0,                      /* src_mask */
         0xffff,                /* dst_mask */
         0xffff,                /* dst_mask */
         FALSE),                /* pcrel_offset */
         FALSE),                /* pcrel_offset */
 
 
  /* Marker reloc for TLS.  */
  /* Marker relocs for TLS.  */
  HOWTO (R_PPC_TLS,
  HOWTO (R_PPC_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 760... Line 774...
         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_PPC_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_PPC_TLSGD",         /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0,                      /* dst_mask */
 
         FALSE),                /* pcrel_offset */
 
 
 
  HOWTO (R_PPC_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_PPC_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_PPC_DTPMOD32,
  HOWTO (R_PPC_DTPMOD32,
         0,                      /* rightshift */
         0,                      /* rightshift */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
Line 1264... Line 1306...
         0,                      /* rightshift */
         0,                      /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                      /* bitpos */
         0,                      /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_EMB_SDAI16",    /* name */
         "R_PPC_EMB_SDAI16",    /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                      /* src_mask */
         0,                      /* src_mask */
         0xffff,                /* dst_mask */
         0xffff,                /* dst_mask */
Line 1281... Line 1323...
         0,                      /* rightshift */
         0,                      /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
         FALSE,                 /* pc_relative */
         FALSE,                 /* pc_relative */
         0,                      /* bitpos */
         0,                      /* bitpos */
         complain_overflow_bitfield, /* complain_on_overflow */
         complain_overflow_signed, /* complain_on_overflow */
         bfd_elf_generic_reloc, /* special_function */
         bfd_elf_generic_reloc, /* special_function */
         "R_PPC_EMB_SDA2I16",   /* name */
         "R_PPC_EMB_SDA2I16",   /* name */
         FALSE,                 /* partial_inplace */
         FALSE,                 /* partial_inplace */
         0,                      /* src_mask */
         0,                      /* src_mask */
         0xffff,                /* dst_mask */
         0xffff,                /* dst_mask */
Line 1346... Line 1388...
         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_PPC_IRELATIVE,       /* type */
 
         0,                      /* rightshift */
 
         2,                     /* size (0 = byte, 1 = short, 2 = long) */
 
         32,                    /* bitsize */
 
         FALSE,                 /* pc_relative */
 
         0,                      /* bitpos */
 
         complain_overflow_bitfield, /* complain_on_overflow */
 
         bfd_elf_generic_reloc,  /* special_function */
 
         "R_PPC_IRELATIVE",     /* name */
 
         FALSE,                 /* partial_inplace */
 
         0,                      /* src_mask */
 
         0xffffffff,            /* dst_mask */
 
         FALSE),                /* pcrel_offset */
 
 
  /* A 16 bit relative relocation.  */
  /* A 16 bit relative relocation.  */
  HOWTO (R_PPC_REL16,           /* type */
  HOWTO (R_PPC_REL16,           /* type */
         0,                      /* rightshift */
         0,                      /* rightshift */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         1,                     /* size (0 = byte, 1 = short, 2 = long) */
         16,                    /* bitsize */
         16,                    /* bitsize */
Line 1523... Line 1579...
    case BFD_RELOC_HI16_BASEREL:        r = R_PPC_SECTOFF_HI;           break;
    case BFD_RELOC_HI16_BASEREL:        r = R_PPC_SECTOFF_HI;           break;
    case BFD_RELOC_HI16_S_BASEREL:      r = R_PPC_SECTOFF_HA;           break;
    case BFD_RELOC_HI16_S_BASEREL:      r = R_PPC_SECTOFF_HA;           break;
    case BFD_RELOC_CTOR:                r = R_PPC_ADDR32;               break;
    case BFD_RELOC_CTOR:                r = R_PPC_ADDR32;               break;
    case BFD_RELOC_PPC_TOC16:           r = R_PPC_TOC16;                break;
    case BFD_RELOC_PPC_TOC16:           r = R_PPC_TOC16;                break;
    case BFD_RELOC_PPC_TLS:             r = R_PPC_TLS;                  break;
    case BFD_RELOC_PPC_TLS:             r = R_PPC_TLS;                  break;
 
    case BFD_RELOC_PPC_TLSGD:           r = R_PPC_TLSGD;                break;
 
    case BFD_RELOC_PPC_TLSLD:           r = R_PPC_TLSLD;                break;
    case BFD_RELOC_PPC_DTPMOD:          r = R_PPC_DTPMOD32;             break;
    case BFD_RELOC_PPC_DTPMOD:          r = R_PPC_DTPMOD32;             break;
    case BFD_RELOC_PPC_TPREL16:         r = R_PPC_TPREL16;              break;
    case BFD_RELOC_PPC_TPREL16:         r = R_PPC_TPREL16;              break;
    case BFD_RELOC_PPC_TPREL16_LO:      r = R_PPC_TPREL16_LO;           break;
    case BFD_RELOC_PPC_TPREL16_LO:      r = R_PPC_TPREL16_LO;           break;
    case BFD_RELOC_PPC_TPREL16_HI:      r = R_PPC_TPREL16_HI;           break;
    case BFD_RELOC_PPC_TPREL16_HI:      r = R_PPC_TPREL16_HI;           break;
    case BFD_RELOC_PPC_TPREL16_HA:      r = R_PPC_TPREL16_HA;           break;
    case BFD_RELOC_PPC_TPREL16_HA:      r = R_PPC_TPREL16_HA;           break;
Line 2289... Line 2347...
  free (buffer);
  free (buffer);
 
 
  apuinfo_list_finish ();
  apuinfo_list_finish ();
}
}


 
static bfd_boolean
 
is_nonpic_glink_stub (bfd *abfd, asection *glink, bfd_vma off)
 
{
 
  bfd_byte buf[GLINK_ENTRY_SIZE];
 
 
 
  if (!bfd_get_section_contents (abfd, glink, buf, off, GLINK_ENTRY_SIZE))
 
    return FALSE;
 
 
 
  return ((bfd_get_32 (abfd, buf + 0) & 0xffff0000) == LIS_11
 
          && (bfd_get_32 (abfd, buf + 4) & 0xffff0000) == LWZ_11_11
 
          && bfd_get_32 (abfd, buf + 8) == MTCTR_11
 
          && bfd_get_32 (abfd, buf + 12) == BCTR);
 
}
 
 
 
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);
 
}
 
 
 
static long
 
ppc_elf_get_synthetic_symtab (bfd *abfd, long symcount, asymbol **syms,
 
                              long dynsymcount, asymbol **dynsyms,
 
                              asymbol **ret)
 
{
 
  bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
 
  asection *plt, *relplt, *dynamic, *glink;
 
  bfd_vma glink_vma = 0;
 
  bfd_vma resolv_vma = 0;
 
  bfd_vma stub_vma;
 
  asymbol *s;
 
  arelent *p;
 
  long count, i;
 
  size_t size;
 
  char *names;
 
  bfd_byte buf[4];
 
 
 
  *ret = NULL;
 
 
 
  if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
 
    return 0;
 
 
 
  if (dynsymcount <= 0)
 
    return 0;
 
 
 
  relplt = bfd_get_section_by_name (abfd, ".rela.plt");
 
  if (relplt == NULL)
 
    return 0;
 
 
 
  plt = bfd_get_section_by_name (abfd, ".plt");
 
  if (plt == NULL)
 
    return 0;
 
 
 
  /* Call common code to handle old-style executable PLTs.  */
 
  if (elf_section_flags (plt) & SHF_EXECINSTR)
 
    return _bfd_elf_get_synthetic_symtab (abfd, symcount, syms,
 
                                          dynsymcount, dynsyms, ret);
 
 
 
  /* If this object was prelinked, the prelinker stored the address
 
     of .glink at got[1].  If it wasn't prelinked, got[1] will be zero.  */
 
  dynamic = bfd_get_section_by_name (abfd, ".dynamic");
 
  if (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))
 
        return -1;
 
 
 
      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_PPC_GOT)
 
            {
 
              unsigned int g_o_t = dyn.d_un.d_val;
 
              asection *got = bfd_get_section_by_name (abfd, ".got");
 
              if (got != NULL
 
                  && bfd_get_section_contents (abfd, got, buf,
 
                                               g_o_t - got->vma + 4, 4))
 
                glink_vma = bfd_get_32 (abfd, buf);
 
              break;
 
            }
 
        }
 
      free (dynbuf);
 
    }
 
 
 
  /* Otherwise we read the first plt entry.  */
 
  if (glink_vma == 0)
 
    {
 
      if (bfd_get_section_contents (abfd, plt, buf, 0, 4))
 
        glink_vma = bfd_get_32 (abfd, buf);
 
    }
 
 
 
  if (glink_vma == 0)
 
    return 0;
 
 
 
  /* 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);
 
  if (glink == NULL)
 
    return 0;
 
 
 
  /* Determine glink PLT resolver by reading the relative branch
 
     from the first glink stub.  */
 
  if (bfd_get_section_contents (abfd, glink, buf,
 
                                glink_vma - glink->vma, 4))
 
    {
 
      unsigned int insn = bfd_get_32 (abfd, buf);
 
 
 
      /* The first glink stub may either branch to the resolver ...  */
 
      insn ^= B;
 
      if ((insn & ~0x3fffffc) == 0)
 
        resolv_vma = glink_vma + (insn ^ 0x2000000) - 0x2000000;
 
 
 
      /* ... or fall through a bunch of NOPs.  */
 
      else if ((insn ^ B ^ NOP) == 0)
 
        for (i = 4;
 
             bfd_get_section_contents (abfd, glink, buf,
 
                                       glink_vma - glink->vma + i, 4);
 
             i += 4)
 
          if (bfd_get_32 (abfd, buf) != NOP)
 
            {
 
              resolv_vma = glink_vma + i;
 
              break;
 
            }
 
    }
 
 
 
  count = relplt->size / sizeof (Elf32_External_Rela);
 
  stub_vma = glink_vma - (bfd_vma) count * 16;
 
  /* If the stubs are those for -shared/-pie then we might have
 
     multiple stubs for each plt entry.  If that is the case then
 
     there is no way to associate stubs with their plt entries short
 
     of figuring out the GOT pointer value used in the stub.  */
 
  if (!is_nonpic_glink_stub (abfd, glink,
 
                             glink_vma - GLINK_ENTRY_SIZE - glink->vma))
 
    return 0;
 
 
 
  slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
 
  if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
 
    return -1;
 
 
 
  size = count * sizeof (asymbol);
 
  p = relplt->relocation;
 
  for (i = 0; i < count; i++, p++)
 
    {
 
      size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
 
      if (p->addend != 0)
 
        size += sizeof ("+0x") - 1 + 8;
 
    }
 
 
 
  size += sizeof (asymbol) + sizeof ("__glink");
 
 
 
  if (resolv_vma)
 
    size += sizeof (asymbol) + sizeof ("__glink_PLTresolve");
 
 
 
  s = *ret = bfd_malloc (size);
 
  if (s == NULL)
 
    return -1;
 
 
 
  names = (char *) (s + count + 1 + (resolv_vma != 0));
 
  p = relplt->relocation;
 
  for (i = 0; i < 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 = stub_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;
 
      stub_vma += 16;
 
    }
 
 
 
  /* Add a symbol at the start of the glink branch table.  */
 
  memset (s, 0, sizeof *s);
 
  s->the_bfd = abfd;
 
  s->flags = BSF_GLOBAL | BSF_SYNTHETIC;
 
  s->section = glink;
 
  s->value = glink_vma - glink->vma;
 
  s->name = names;
 
  memcpy (names, "__glink", sizeof ("__glink"));
 
  names += sizeof ("__glink");
 
  s++;
 
  count++;
 
 
 
  if (resolv_vma)
 
    {
 
      /* Add a symbol for the glink PLT resolver.  */
 
      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++;
 
    }
 
 
 
  return count;
 
}
 

/* The following functions are specific to the ELF linker, while
/* The following functions are specific to the ELF linker, while
   functions above are used generally.  They appear in this file more
   functions above are used generally.  They appear in this file more
   or less in the order in which they are called.  eg.
   or less in the order in which they are called.  eg.
   ppc_elf_check_relocs is called early in the link process,
   ppc_elf_check_relocs is called early in the link process,
   ppc_elf_finish_dynamic_sections is one of the last functions
   ppc_elf_finish_dynamic_sections is one of the last functions
Line 2317... Line 2611...
  /* Number of pc-relative relocs copied for the input section.  */
  /* Number of pc-relative relocs copied for the input section.  */
  bfd_size_type pc_count;
  bfd_size_type pc_count;
};
};
 
 
/* Track PLT entries needed for a given symbol.  We might need more
/* Track PLT entries needed for a given symbol.  We might need more
   than one glink entry per symbol.  */
   than one glink entry per symbol when generating a pic binary.  */
struct plt_entry
struct plt_entry
{
{
  struct plt_entry *next;
  struct plt_entry *next;
 
 
  /* -fPIC uses multiple GOT sections, one per file, called ".got2".
  /* -fPIC uses multiple GOT sections, one per file, called ".got2".
     This field stores the offset into .got2 used to initialise the
     This field stores the offset into .got2 used to initialise the
     GOT pointer reg.  It will always be at least 32768 (and for
     GOT pointer reg.  It will always be at least 32768.  (Current
     current gcc this is the only offset used).  */
     gcc always uses an offset of 32768, but ld -r will pack .got2
 
     sections together resulting in larger offsets).  */
  bfd_vma addend;
  bfd_vma addend;
 
 
  /* The .got2 section.  */
  /* The .got2 section.  */
  asection *sec;
  asection *sec;
 
 
Line 2342... Line 2637...
 
 
  /* .glink stub offset.  */
  /* .glink stub offset.  */
  bfd_vma glink_offset;
  bfd_vma glink_offset;
};
};
 
 
/* 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_PPC_REL24                       \
must_be_dyn_reloc (struct bfd_link_info *info,
   && (RTYPE) != R_PPC_REL14                    \
                   enum elf_ppc_reloc_type r_type)
   && (RTYPE) != R_PPC_REL14_BRTAKEN            \
{
   && (RTYPE) != R_PPC_REL14_BRNTAKEN           \
  switch (r_type)
   && (RTYPE) != R_PPC_REL32)
    {
 
    default:
 
      return 1;
 
 
 
    case R_PPC_REL24:
 
    case R_PPC_REL14:
 
    case R_PPC_REL14_BRTAKEN:
 
    case R_PPC_REL14_BRNTAKEN:
 
    case R_PPC_REL32:
 
      return 0;
 
 
 
    case R_PPC_TPREL32:
 
    case R_PPC_TPREL16:
 
    case R_PPC_TPREL16_LO:
 
    case R_PPC_TPREL16_HI:
 
    case R_PPC_TPREL16_HA:
 
      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.  */
   shared lib.  */
Line 2384... Line 2697...
#define TLS_LD           2      /* LD reloc. */
#define TLS_LD           2      /* LD reloc. */
#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_TPRELGD     32      /* TPREL reloc resulting from GD->IE. */
#define TLS_TPRELGD     32      /* TPREL reloc resulting from GD->IE. */
 
#define PLT_IFUNC       64      /* STT_GNU_IFUNC.  */
  char tls_mask;
  char tls_mask;
 
 
  /* Nonzero if we have seen a small data relocation referring to this
  /* Nonzero if we have seen a small data relocation referring to this
     symbol.  */
     symbol.  */
  unsigned char has_sda_refs;
  unsigned char has_sda_refs;
Line 2405... Line 2719...
  asection *got;
  asection *got;
  asection *relgot;
  asection *relgot;
  asection *glink;
  asection *glink;
  asection *plt;
  asection *plt;
  asection *relplt;
  asection *relplt;
 
  asection *iplt;
 
  asection *reliplt;
  asection *dynbss;
  asection *dynbss;
  asection *relbss;
  asection *relbss;
  asection *dynsbss;
  asection *dynsbss;
  asection *relsbss;
  asection *relsbss;
  elf_linker_section_t sdata[2];
  elf_linker_section_t sdata[2];
Line 2418... Line 2734...
  asection *srelplt2;
  asection *srelplt2;
 
 
  /* The .got.plt section (VxWorks only)*/
  /* The .got.plt section (VxWorks only)*/
  asection *sgotplt;
  asection *sgotplt;
 
 
  /* Shortcut to .__tls_get_addr.  */
  /* Shortcut to __tls_get_addr.  */
  struct elf_link_hash_entry *tls_get_addr;
  struct elf_link_hash_entry *tls_get_addr;
 
 
  /* The bfd that forced an old-style PLT.  */
  /* The bfd that forced an old-style PLT.  */
  bfd *old_bfd;
  bfd *old_bfd;
 
 
Line 2430... Line 2746...
  union {
  union {
    bfd_signed_vma refcount;
    bfd_signed_vma refcount;
    bfd_vma offset;
    bfd_vma offset;
  } tlsld_got;
  } tlsld_got;
 
 
  /* Offset of PltResolve function in glink.  */
  /* Offset of branch table to PltResolve function in glink.  */
  bfd_vma glink_pltresolve;
  bfd_vma glink_pltresolve;
 
 
  /* Size of reserved GOT entries.  */
  /* Size of reserved GOT entries.  */
  unsigned int got_header_size;
  unsigned int got_header_size;
  /* Non-zero if allocating the header left a gap.  */
  /* Non-zero if allocating the header left a gap.  */
Line 2444... Line 2760...
  enum ppc_elf_plt_type plt_type;
  enum ppc_elf_plt_type plt_type;
 
 
  /* 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;
 
 
  /* True if the target system is VxWorks.  */
  /* True if the target system is VxWorks.  */
  unsigned int is_vxworks:1;
  unsigned int is_vxworks:1;
 
 
  /* The size of PLT entries.  */
  /* The size of PLT entries.  */
  int plt_entry_size;
  int plt_entry_size;
  /* The distance between adjacent PLT slots.  */
  /* The distance between adjacent PLT slots.  */
  int plt_slot_size;
  int plt_slot_size;
  /* The size of the first PLT entry.  */
  /* The size of the first PLT entry.  */
  int plt_initial_entry_size;
  int plt_initial_entry_size;
 
 
  /* Small local sym to section mapping cache.  */
  /* Small local sym cache.  */
  struct sym_sec_cache sym_sec;
  struct sym_cache sym_cache;
};
};
 
 
/* Get the PPC ELF linker hash table from a link_info structure.  */
/* Get the PPC ELF linker hash table from a link_info structure.  */
 
 
#define ppc_elf_hash_table(p) \
#define ppc_elf_hash_table(p) \
Line 2564... Line 2883...
               | SEC_IN_MEMORY | SEC_LINKER_CREATED);
               | SEC_IN_MEMORY | SEC_LINKER_CREATED);
      if (!bfd_set_section_flags (abfd, s, flags))
      if (!bfd_set_section_flags (abfd, s, flags))
        return FALSE;
        return FALSE;
    }
    }
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
  htab->relgot = bfd_get_section_by_name (abfd, ".rela.got");
           | SEC_LINKER_CREATED | SEC_READONLY);
  if (!htab->relgot)
  htab->relgot = bfd_make_section_with_flags (abfd, ".rela.got", flags);
    abort ();
  if (!htab->relgot
 
      || ! bfd_set_section_alignment (abfd, htab->relgot, 2))
  return TRUE;
 
}
 
 
 
static bfd_boolean
 
ppc_elf_create_glink (bfd *abfd, struct bfd_link_info *info)
 
{
 
  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
  asection *s;
 
  flagword flags;
 
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY | SEC_HAS_CONTENTS
 
           | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
  s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags);
 
  htab->glink = s;
 
  if (s == NULL
 
      || !bfd_set_section_alignment (abfd, s, 4))
 
    return FALSE;
 
 
 
  flags = SEC_ALLOC | SEC_LINKER_CREATED;
 
  s = bfd_make_section_anyway_with_flags (abfd, ".iplt", flags);
 
  htab->iplt = s;
 
  if (s == NULL
 
      || !bfd_set_section_alignment (abfd, s, 4))
    return FALSE;
    return FALSE;
 
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
 
           | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
  s = bfd_make_section_with_flags (abfd, ".rela.iplt", flags);
 
  htab->reliplt = s;
 
  if (s == NULL
 
      || ! bfd_set_section_alignment (abfd, s, 2))
 
    return FALSE;
  return TRUE;
  return TRUE;
}
}
 
 
/* We have to create .dynsbss and .rela.sbss here so that they get mapped
/* We have to create .dynsbss and .rela.sbss here so that they get mapped
   to output sections (just like _bfd_elf_create_dynamic_sections has
   to output sections (just like _bfd_elf_create_dynamic_sections has
Line 2594... Line 2942...
    return FALSE;
    return FALSE;
 
 
  if (!_bfd_elf_create_dynamic_sections (abfd, info))
  if (!_bfd_elf_create_dynamic_sections (abfd, info))
    return FALSE;
    return FALSE;
 
 
  flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
  if (htab->glink == NULL
           | SEC_IN_MEMORY | SEC_LINKER_CREATED);
      && !ppc_elf_create_glink (abfd, info))
 
 
  s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags | SEC_CODE);
 
  htab->glink = s;
 
  if (s == NULL
 
      || !bfd_set_section_alignment (abfd, s, 4))
 
    return FALSE;
    return FALSE;
 
 
  htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
  htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss");
  s = bfd_make_section_with_flags (abfd, ".dynsbss",
  s = bfd_make_section_with_flags (abfd, ".dynsbss",
                                   SEC_ALLOC | SEC_LINKER_CREATED);
                                   SEC_ALLOC | SEC_LINKER_CREATED);
Line 2613... Line 2956...
    return FALSE;
    return FALSE;
 
 
  if (! info->shared)
  if (! info->shared)
    {
    {
      htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss");
      htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss");
 
      flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS
 
               | SEC_IN_MEMORY | SEC_LINKER_CREATED);
      s = bfd_make_section_with_flags (abfd, ".rela.sbss", flags);
      s = bfd_make_section_with_flags (abfd, ".rela.sbss", flags);
      htab->relsbss = s;
      htab->relsbss = s;
      if (s == NULL
      if (s == NULL
          || ! bfd_set_section_alignment (abfd, s, 2))
          || ! bfd_set_section_alignment (abfd, s, 2))
        return FALSE;
        return FALSE;
Line 2786... Line 3131...
 
 
      *secp = htab->sbss;
      *secp = htab->sbss;
      *valp = sym->st_size;
      *valp = sym->st_size;
    }
    }
 
 
 
  if (ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
 
    elf_tdata (info->output_bfd)->has_ifunc_symbols = TRUE;
 
 
  return TRUE;
  return TRUE;
}
}


static bfd_boolean
static bfd_boolean
create_sdata_sym (struct ppc_elf_link_hash_table *htab,
create_sdata_sym (struct bfd_link_info *info, elf_linker_section_t *lsect)
                  elf_linker_section_t *lsect)
 
{
{
 
  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
 
  lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
  lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
                                     TRUE, FALSE, TRUE);
                                     TRUE, FALSE, TRUE);
  if (lsect->sym == NULL)
  if (lsect->sym == NULL)
    return FALSE;
    return FALSE;
  if (lsect->sym->root.type == bfd_link_hash_new)
  if (lsect->sym->root.type == bfd_link_hash_new)
    lsect->sym->non_elf = 0;
    lsect->sym->non_elf = 0;
  lsect->sym->ref_regular = 1;
  lsect->sym->ref_regular = 1;
 
  _bfd_elf_link_hash_hide_symbol (info, lsect->sym, TRUE);
  return TRUE;
  return TRUE;
}
}
 
 
/* Create a special linker section.  */
/* Create a special linker section.  */
 
 
Line 2829... Line 3179...
  if (s == NULL
  if (s == NULL
      || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
      || !bfd_set_section_alignment (htab->elf.dynobj, s, 2))
    return FALSE;
    return FALSE;
  lsect->section = s;
  lsect->section = s;
 
 
  return create_sdata_sym (htab, lsect);
  return create_sdata_sym (info, lsect);
}
}
 
 
/* Find a linker generated pointer with a given addend and type.  */
/* Find a linker generated pointer with a given addend and type.  */
 
 
static elf_linker_section_pointers_t *
static elf_linker_section_pointers_t *
Line 2934... Line 3284...
#endif
#endif
 
 
  return TRUE;
  return TRUE;
}
}
 
 
static bfd_boolean
static struct plt_entry **
update_local_sym_info (bfd *abfd,
update_local_sym_info (bfd *abfd,
                       Elf_Internal_Shdr *symtab_hdr,
                       Elf_Internal_Shdr *symtab_hdr,
                       unsigned long r_symndx,
                       unsigned long r_symndx,
                       int tls_type)
                       int tls_type)
{
{
  bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
  bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd);
 
  struct plt_entry **local_plt;
  char *local_got_tls_masks;
  char *local_got_tls_masks;
 
 
  if (local_got_refcounts == NULL)
  if (local_got_refcounts == NULL)
    {
    {
      bfd_size_type size = symtab_hdr->sh_info;
      bfd_size_type size = symtab_hdr->sh_info;
 
 
      size *= sizeof (*local_got_refcounts) + sizeof (*local_got_tls_masks);
      size *= (sizeof (*local_got_refcounts)
 
               + sizeof (*local_plt)
 
               + sizeof (*local_got_tls_masks));
      local_got_refcounts = bfd_zalloc (abfd, size);
      local_got_refcounts = bfd_zalloc (abfd, size);
      if (local_got_refcounts == NULL)
      if (local_got_refcounts == NULL)
        return FALSE;
        return NULL;
      elf_local_got_refcounts (abfd) = local_got_refcounts;
      elf_local_got_refcounts (abfd) = local_got_refcounts;
    }
    }
 
 
  local_got_refcounts[r_symndx] += 1;
  local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info);
  local_got_tls_masks = (char *) (local_got_refcounts + 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;
  if (tls_type != PLT_IFUNC)
 
    local_got_refcounts[r_symndx] += 1;
 
  return local_plt + r_symndx;
}
}
 
 
static bfd_boolean
static bfd_boolean
update_plt_info (bfd *abfd, struct elf_link_hash_entry *h,
update_plt_info (bfd *abfd, struct plt_entry **plist,
                 asection *sec, bfd_vma addend)
                 asection *sec, bfd_vma addend)
{
{
  struct plt_entry *ent;
  struct plt_entry *ent;
 
 
  if (addend < 32768)
  if (addend < 32768)
    sec = NULL;
    sec = NULL;
  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
  for (ent = *plist; ent != NULL; ent = ent->next)
    if (ent->sec == sec && ent->addend == addend)
    if (ent->sec == sec && 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 = h->plt.plist;
      ent->next = *plist;
      ent->sec = sec;
      ent->sec = sec;
      ent->addend = addend;
      ent->addend = addend;
      ent->plt.refcount = 0;
      ent->plt.refcount = 0;
      h->plt.plist = ent;
      *plist = ent;
    }
    }
  ent->plt.refcount += 1;
  ent->plt.refcount += 1;
  return TRUE;
  return TRUE;
}
}
 
 
static struct plt_entry *
static struct plt_entry *
find_plt_ent (struct elf_link_hash_entry *h, asection *sec, bfd_vma addend)
find_plt_ent (struct plt_entry **plist, asection *sec, bfd_vma addend)
{
{
  struct plt_entry *ent;
  struct plt_entry *ent;
 
 
  if (addend < 32768)
  if (addend < 32768)
    sec = NULL;
    sec = NULL;
  for (ent = h->plt.plist; ent != NULL; ent = ent->next)
  for (ent = *plist; ent != NULL; ent = ent->next)
    if (ent->sec == sec && ent->addend == addend)
    if (ent->sec == sec && ent->addend == addend)
      break;
      break;
  return ent;
  return ent;
}
}
 
 
 
static bfd_boolean
 
is_branch_reloc (enum elf_ppc_reloc_type r_type)
 
{
 
  return (r_type == R_PPC_PLTREL24
 
          || r_type == R_PPC_LOCAL24PC
 
          || r_type == R_PPC_REL24
 
          || r_type == R_PPC_REL14
 
          || r_type == R_PPC_REL14_BRTAKEN
 
          || r_type == R_PPC_REL14_BRNTAKEN
 
          || r_type == R_PPC_ADDR24
 
          || r_type == R_PPC_ADDR14
 
          || r_type == R_PPC_ADDR14_BRTAKEN
 
          || r_type == R_PPC_ADDR14_BRNTAKEN);
 
}
 
 
static void
static void
bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
bad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type)
{
{
  (*_bfd_error_handler)
  (*_bfd_error_handler)
    (_("%B: relocation %s cannot be used when making a shared object"),
    (_("%B: relocation %s cannot be used when making a shared object"),
Line 3026... Line 3396...
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel;
  const Elf_Internal_Rela *rel_end;
  const Elf_Internal_Rela *rel_end;
  asection *got2, *sreloc;
  asection *got2, *sreloc;
 
  struct elf_link_hash_entry *tga;
 
 
  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 3051... Line 3422...
  /* Initialize howto table if not already done.  */
  /* Initialize howto table if not already done.  */
  if (!ppc_elf_howto_table[R_PPC_ADDR32])
  if (!ppc_elf_howto_table[R_PPC_ADDR32])
    ppc_elf_howto_init ();
    ppc_elf_howto_init ();
 
 
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
 
  if (htab->glink == NULL)
 
    {
 
      if (htab->elf.dynobj == NULL)
 
        htab->elf.dynobj = abfd;
 
      if (!ppc_elf_create_glink (htab->elf.dynobj, info))
 
        return FALSE;
 
    }
 
  tga = 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);
  got2 = bfd_get_section_by_name (abfd, ".got2");
  got2 = bfd_get_section_by_name (abfd, ".got2");
  sreloc = NULL;
  sreloc = NULL;
 
 
Line 3062... Line 3442...
  for (rel = relocs; rel < rel_end; rel++)
  for (rel = relocs; rel < rel_end; rel++)
    {
    {
      unsigned long r_symndx;
      unsigned long r_symndx;
      enum elf_ppc_reloc_type r_type;
      enum elf_ppc_reloc_type r_type;
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
      int tls_type = 0;
      int tls_type;
 
      struct plt_entry **ifunc;
 
 
      r_symndx = ELF32_R_SYM (rel->r_info);
      r_symndx = ELF32_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
Line 3089... Line 3470...
          if (!ppc_elf_create_got (htab->elf.dynobj, info))
          if (!ppc_elf_create_got (htab->elf.dynobj, info))
            return FALSE;
            return FALSE;
          BFD_ASSERT (h == htab->elf.hgot);
          BFD_ASSERT (h == htab->elf.hgot);
        }
        }
 
 
 
      tls_type = 0;
 
      ifunc = NULL;
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
 
      if (!htab->is_vxworks)
 
        {
 
          if (h != NULL)
 
            {
 
              if (h->type == STT_GNU_IFUNC)
 
                ifunc = &h->plt.plist;
 
            }
 
          else
 
            {
 
              Elf_Internal_Sym *isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                                              abfd, r_symndx);
 
              if (isym == NULL)
 
                return FALSE;
 
 
 
              if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC
 
                  && (!info->shared
 
                      || is_branch_reloc (r_type)))
 
                {
 
                  bfd_vma addend;
 
 
 
                  ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
 
                                                 PLT_IFUNC);
 
                  if (ifunc == NULL)
 
                    return FALSE;
 
 
 
                  /* STT_GNU_IFUNC symbols must have a PLT entry;
 
                     In a non-pie executable even when there are
 
                     no plt calls.  */
 
                  addend = 0;
 
                  if (r_type == R_PPC_PLTREL24)
 
                    {
 
                      ppc_elf_tdata (abfd)->makes_plt_call = 1;
 
                      if (info->shared)
 
                        addend = rel->r_addend;
 
                    }
 
                  if (!update_plt_info (abfd, ifunc, got2, addend))
 
                    return FALSE;
 
                }
 
            }
 
        }
 
 
 
      if (!htab->is_vxworks
 
          && is_branch_reloc (r_type)
 
          && h != NULL
 
          && h == tga)
 
        {
 
          if (rel != relocs
 
              && (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
 
                  || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_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;
 
        }
 
 
      switch (r_type)
      switch (r_type)
        {
        {
 
        case R_PPC_TLSGD:
 
        case R_PPC_TLSLD:
 
          /* These special tls relocs tie a call to __tls_get_addr with
 
             its parameter symbol.  */
 
          break;
 
 
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_HI:
        case R_PPC_GOT_TLSLD16_HI:
        case R_PPC_GOT_TLSLD16_HA:
        case R_PPC_GOT_TLSLD16_HA:
          tls_type = TLS_TLS | TLS_LD;
          tls_type = TLS_TLS | TLS_LD;
Line 3110... Line 3556...
 
 
        case R_PPC_GOT_TPREL16:
        case R_PPC_GOT_TPREL16:
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_HI:
        case R_PPC_GOT_TPREL16_HI:
        case R_PPC_GOT_TPREL16_HA:
        case R_PPC_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_PPC_GOT_DTPREL16:
        case R_PPC_GOT_DTPREL16:
Line 3146... Line 3592...
            }
            }
          else
          else
            /* This is a global offset table entry for a local symbol.  */
            /* This is a global offset table entry for a local symbol.  */
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type))
            if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type))
              return FALSE;
              return FALSE;
 
 
 
          /* We may also need a plt entry if the symbol turns out to be
 
             an ifunc.  */
 
          if (h != NULL && !info->shared)
 
            {
 
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
 
                return FALSE;
 
            }
          break;
          break;
 
 
          /* Indirect .sdata relocation.  */
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
        case R_PPC_EMB_SDAI16:
          if (info->shared)
          if (info->shared)
Line 3191... Line 3645...
              h->non_got_ref = TRUE;
              h->non_got_ref = TRUE;
            }
            }
          break;
          break;
 
 
        case R_PPC_SDAREL16:
        case R_PPC_SDAREL16:
          if (info->shared)
 
            {
 
              bad_shared_reloc (abfd, r_type);
 
              return FALSE;
 
            }
 
          if (htab->sdata[0].sym == NULL
          if (htab->sdata[0].sym == NULL
              && !create_sdata_sym (htab, &htab->sdata[0]))
              && !create_sdata_sym (info, &htab->sdata[0]))
            return FALSE;
            return FALSE;
          if (h != NULL)
          if (h != NULL)
            {
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
              h->non_got_ref = TRUE;
              h->non_got_ref = TRUE;
Line 3213... Line 3662...
            {
            {
              bad_shared_reloc (abfd, r_type);
              bad_shared_reloc (abfd, r_type);
              return FALSE;
              return FALSE;
            }
            }
          if (htab->sdata[1].sym == NULL
          if (htab->sdata[1].sym == NULL
              && !create_sdata_sym (htab, &htab->sdata[1]))
              && !create_sdata_sym (info, &htab->sdata[1]))
            return FALSE;
            return FALSE;
          if (h != NULL)
          if (h != NULL)
            {
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
              h->non_got_ref = TRUE;
              h->non_got_ref = TRUE;
Line 3230... Line 3679...
            {
            {
              bad_shared_reloc (abfd, r_type);
              bad_shared_reloc (abfd, r_type);
              return FALSE;
              return FALSE;
            }
            }
          if (htab->sdata[0].sym == NULL
          if (htab->sdata[0].sym == NULL
              && !create_sdata_sym (htab, &htab->sdata[0]))
              && !create_sdata_sym (info, &htab->sdata[0]))
            return FALSE;
            return FALSE;
          if (htab->sdata[1].sym == NULL
          if (htab->sdata[1].sym == NULL
              && !create_sdata_sym (htab, &htab->sdata[1]))
              && !create_sdata_sym (info, &htab->sdata[1]))
            return FALSE;
            return FALSE;
          if (h != NULL)
          if (h != NULL)
            {
            {
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
              ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
              h->non_got_ref = TRUE;
              h->non_got_ref = TRUE;
Line 3256... Line 3705...
            }
            }
          if (h != NULL)
          if (h != NULL)
            h->non_got_ref = TRUE;
            h->non_got_ref = TRUE;
          break;
          break;
 
 
        case R_PPC_PLT32:
 
        case R_PPC_PLTREL24:
        case R_PPC_PLTREL24:
 
          if (h == NULL)
 
            break;
 
          /* Fall through */
 
        case R_PPC_PLT32:
        case R_PPC_PLTREL32:
        case R_PPC_PLTREL32:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HA:
        case R_PPC_PLT16_HA:
#ifdef DEBUG
#ifdef DEBUG
Line 3291... Line 3743...
              bfd_vma addend = 0;
              bfd_vma addend = 0;
 
 
              if (r_type == R_PPC_PLTREL24)
              if (r_type == R_PPC_PLTREL24)
                {
                {
                  ppc_elf_tdata (abfd)->makes_plt_call = 1;
                  ppc_elf_tdata (abfd)->makes_plt_call = 1;
 
                  if (info->shared)
                  addend = rel->r_addend;
                  addend = rel->r_addend;
                }
                }
              h->needs_plt = 1;
              h->needs_plt = 1;
              if (!update_plt_info (abfd, h, got2, addend))
              if (!update_plt_info (abfd, &h->plt.plist, got2, addend))
                return FALSE;
                return FALSE;
            }
            }
          break;
          break;
 
 
          /* The following relocations don't need to propagate the
          /* The following relocations don't need to propagate the
Line 3325... Line 3778...
          /* These are just markers.  */
          /* These are just markers.  */
        case R_PPC_TLS:
        case R_PPC_TLS:
        case R_PPC_EMB_MRKREF:
        case R_PPC_EMB_MRKREF:
        case R_PPC_NONE:
        case R_PPC_NONE:
        case R_PPC_max:
        case R_PPC_max:
 
        case R_PPC_RELAX:
 
        case R_PPC_RELAX_PLT:
 
        case R_PPC_RELAX_PLTREL24:
          break;
          break;
 
 
          /* These should only appear in dynamic objects.  */
          /* These should only appear in dynamic objects.  */
        case R_PPC_COPY:
        case R_PPC_COPY:
        case R_PPC_GLOB_DAT:
        case R_PPC_GLOB_DAT:
        case R_PPC_JMP_SLOT:
        case R_PPC_JMP_SLOT:
        case R_PPC_RELATIVE:
        case R_PPC_RELATIVE:
 
        case R_PPC_IRELATIVE:
          break;
          break;
 
 
          /* These aren't handled yet.  We'll report an error later.  */
          /* These aren't handled yet.  We'll report an error later.  */
        case R_PPC_ADDR30:
        case R_PPC_ADDR30:
        case R_PPC_EMB_RELSEC16:
        case R_PPC_EMB_RELSEC16:
Line 3345... Line 3802...
        case R_PPC_EMB_BIT_FLD:
        case R_PPC_EMB_BIT_FLD:
          break;
          break;
 
 
          /* This refers only to functions defined in the shared library.  */
          /* This refers only to functions defined in the shared library.  */
        case R_PPC_LOCAL24PC:
        case R_PPC_LOCAL24PC:
          if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
          if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
            {
            {
              htab->plt_type = PLT_OLD;
              htab->plt_type = PLT_OLD;
              htab->old_bfd = abfd;
              htab->old_bfd = abfd;
            }
            }
          break;
          break;
Line 3370... Line 3827...
            return FALSE;
            return FALSE;
          break;
          break;
 
 
          /* We shouldn't really be seeing these.  */
          /* We shouldn't really be seeing these.  */
        case R_PPC_TPREL32:
        case R_PPC_TPREL32:
          if (info->shared)
        case R_PPC_TPREL16:
 
        case R_PPC_TPREL16_LO:
 
        case R_PPC_TPREL16_HI:
 
        case R_PPC_TPREL16_HA:
 
          if (!info->executable)
            info->flags |= DF_STATIC_TLS;
            info->flags |= DF_STATIC_TLS;
          goto dodyn;
          goto dodyn;
 
 
          /* Nor these.  */
          /* Nor these.  */
        case R_PPC_DTPMOD32:
        case R_PPC_DTPMOD32:
        case R_PPC_DTPREL32:
        case R_PPC_DTPREL32:
          goto dodyn;
          goto dodyn;
 
 
        case R_PPC_TPREL16:
 
        case R_PPC_TPREL16_LO:
 
        case R_PPC_TPREL16_HI:
 
        case R_PPC_TPREL16_HA:
 
          if (info->shared)
 
            info->flags |= DF_STATIC_TLS;
 
          goto dodyn;
 
 
 
        case R_PPC_REL32:
        case R_PPC_REL32:
          if (h == NULL
          if (h == NULL
              && got2 != NULL
              && got2 != NULL
              && (sec->flags & SEC_CODE) != 0
              && (sec->flags & SEC_CODE) != 0
              && (info->shared || info->pie)
              && info->shared
              && htab->plt_type == PLT_UNSET)
              && htab->plt_type == PLT_UNSET)
            {
            {
              /* Old -fPIC gcc code has .long LCTOC1-LCFx just before
              /* Old -fPIC gcc code has .long LCTOC1-LCFx just before
                 the start of a function, which assembles to a REL32
                 the start of a function, which assembles to a REL32
                 reference to .got2.  If we detect one of these, then
                 reference to .got2.  If we detect one of these, then
                 force the old PLT layout because the linker cannot
                 force the old PLT layout because the linker cannot
                 reliably deduce the GOT pointer value needed for
                 reliably deduce the GOT pointer value needed for
                 PLT call stubs.  */
                 PLT call stubs.  */
              asection *s;
              asection *s;
 
              Elf_Internal_Sym *isym;
 
 
 
              isym = bfd_sym_from_r_symndx (&htab->sym_cache,
 
                                            abfd, r_symndx);
 
              if (isym == NULL)
 
                return FALSE;
 
 
              s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec,
              s = bfd_section_from_elf_index (abfd, isym->st_shndx);
                                             r_symndx);
 
              if (s == got2)
              if (s == got2)
                {
                {
                  htab->plt_type = PLT_OLD;
                  htab->plt_type = PLT_OLD;
                  htab->old_bfd = abfd;
                  htab->old_bfd = abfd;
                }
                }
Line 3425... Line 3883...
        case R_PPC_UADDR16:
        case R_PPC_UADDR16:
          if (h != NULL && !info->shared)
          if (h != NULL && !info->shared)
            {
            {
              /* We may need a plt entry if the symbol turns out to be
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
                 a function defined in a dynamic object.  */
              if (!update_plt_info (abfd, h, NULL, 0))
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
                return FALSE;
 
 
              /* We may need a copy reloc too.  */
              /* We may need a copy reloc too.  */
              h->non_got_ref = 1;
              h->non_got_ref = 1;
              h->pointer_equality_needed = 1;
              h->pointer_equality_needed = 1;
Line 3459... Line 3917...
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
          if (h != NULL && !info->shared)
          if (h != NULL && !info->shared)
            {
            {
              /* We may need a plt entry if the symbol turns out to be
              /* We may need a plt entry if the symbol turns out to be
                 a function defined in a dynamic object.  */
                 a function defined in a dynamic object.  */
              if (!update_plt_info (abfd, h, NULL, 0))
              h->needs_plt = 1;
 
              if (!update_plt_info (abfd, &h->plt.plist, NULL, 0))
                return FALSE;
                return FALSE;
              break;
              break;
            }
            }
 
 
        dodyn:
        dodyn:
Line 3487... Line 3946...
             If on the other hand, we are creating an executable, we
             If on the other hand, we are creating an executable, we
             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.  */
          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 3499... Line 3958...
                  && h != NULL
                  && h != NULL
                  && (h->root.type == bfd_link_hash_defweak
                  && (h->root.type == bfd_link_hash_defweak
                      || !h->def_regular)))
                      || !h->def_regular)))
            {
            {
              struct ppc_elf_dyn_relocs *p;
              struct ppc_elf_dyn_relocs *p;
              struct ppc_elf_dyn_relocs **head;
              struct ppc_elf_dyn_relocs **rel_head;
 
 
#ifdef DEBUG
#ifdef DEBUG
              fprintf (stderr,
              fprintf (stderr,
                       "ppc_elf_check_relocs needs to "
                       "ppc_elf_check_relocs needs to "
                       "create relocation for %s\n",
                       "create relocation for %s\n",
                       (h && h->root.root.string
                       (h && h->root.root.string
                        ? h->root.root.string : "<unknown>"));
                        ? h->root.root.string : "<unknown>"));
#endif
#endif
              if (sreloc == NULL)
              if (sreloc == NULL)
                {
                {
                  const char *name;
 
 
 
                  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;
 
 
 
                  BFD_ASSERT (CONST_STRNEQ (name, ".rela")
 
                              && strcmp (bfd_get_section_name (abfd, sec),
 
                                         name + 5) == 0);
 
 
 
                  if (htab->elf.dynobj == NULL)
                  if (htab->elf.dynobj == NULL)
                    htab->elf.dynobj = abfd;
                    htab->elf.dynobj = abfd;
                  sreloc = bfd_get_section_by_name (htab->elf.dynobj, name);
 
                  if (sreloc == NULL)
 
                    {
 
                      flagword flags;
 
 
 
                      flags = (SEC_HAS_CONTENTS | SEC_READONLY
                  sreloc = _bfd_elf_make_dynamic_reloc_section
                               | SEC_IN_MEMORY | SEC_LINKER_CREATED
                    (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ TRUE);
                               | SEC_ALLOC | SEC_LOAD);
 
                      sreloc = bfd_make_section_with_flags (htab->elf.dynobj,
                  if (sreloc == NULL)
                                                            name,
 
                                                            flags);
 
                      if (sreloc == NULL
 
                          || ! bfd_set_section_alignment (htab->elf.dynobj,
 
                                                          sreloc, 2))
 
                        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)
                {
                {
                  head = &ppc_elf_hash_entry (h)->dyn_relocs;
                  rel_head = &ppc_elf_hash_entry (h)->dyn_relocs;
                }
                }
              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_elf_dyn_relocs **) vpp;
                  rel_head = (struct ppc_elf_dyn_relocs **) vpp;
                }
                }
 
 
              p = *head;
              p = *rel_head;
              if (p == NULL || p->sec != sec)
              if (p == NULL || p->sec != sec)
                {
                {
                  p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                  p = bfd_alloc (htab->elf.dynobj, sizeof *p);
                  if (p == NULL)
                  if (p == NULL)
                    return FALSE;
                    return FALSE;
                  p->next = *head;
                  p->next = *rel_head;
                  *head = p;
                  *rel_head = p;
                  p->sec = sec;
                  p->sec = sec;
                  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;
        }
        }
Line 3631... Line 4070...
      else if (in_attr->i == 0)
      else if (in_attr->i == 0)
        ;
        ;
      else if (out_attr->i == 1 && in_attr->i == 2)
      else if (out_attr->i == 1 && in_attr->i == 2)
        _bfd_error_handler
        _bfd_error_handler
          (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
          (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd);
      else if (out_attr->i == 2 && in_attr->i == 1)
      else if (out_attr->i == 1 && in_attr->i == 3)
 
        _bfd_error_handler
 
          (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
 
          obfd, ibfd);
 
      else if (out_attr->i == 3 && in_attr->i == 1)
 
        _bfd_error_handler
 
          (_("Warning: %B uses double-precision hard float, %B uses single-precision hard float"),
 
          ibfd, obfd);
 
      else if (out_attr->i == 3 && in_attr->i == 2)
 
        _bfd_error_handler
 
          (_("Warning: %B uses soft float, %B uses single-precision hard float"),
 
          ibfd, obfd);
 
      else if (out_attr->i == 2 && (in_attr->i == 1 || in_attr->i == 3))
        _bfd_error_handler
        _bfd_error_handler
          (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
          (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd);
      else if (in_attr->i > 2)
      else if (in_attr->i > 3)
        _bfd_error_handler
        _bfd_error_handler
          (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
          (_("Warning: %B uses unknown floating point ABI %d"), ibfd,
           in_attr->i);
           in_attr->i);
      else
      else
        _bfd_error_handler
        _bfd_error_handler
Line 3694... Line 4145...
        _bfd_error_handler
        _bfd_error_handler
          (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
          (_("Warning: %B uses vector ABI \"%s\", %B uses \"%s\""),
           ibfd, obfd, in_abi, out_abi);
           ibfd, obfd, in_abi, out_abi);
    }
    }
 
 
 
  /* Check for conflicting Tag_GNU_Power_ABI_Struct_Return attributes
 
     and merge non-conflicting ones.  */
 
  in_attr = &in_attrs[Tag_GNU_Power_ABI_Struct_Return];
 
  out_attr = &out_attrs[Tag_GNU_Power_ABI_Struct_Return];
 
  if (in_attr->i != out_attr->i)
 
    {
 
      out_attr->type = 1;
 
      if (out_attr->i == 0)
 
       out_attr->i = in_attr->i;
 
      else if (in_attr->i == 0)
 
       ;
 
      else if (out_attr->i == 1 && in_attr->i == 2)
 
       _bfd_error_handler
 
         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), obfd, ibfd);
 
      else if (out_attr->i == 2 && in_attr->i == 1)
 
       _bfd_error_handler
 
         (_("Warning: %B uses r3/r4 for small structure returns, %B uses memory"), ibfd, obfd);
 
      else if (in_attr->i > 2)
 
       _bfd_error_handler
 
         (_("Warning: %B uses unknown small structure return convention %d"), ibfd,
 
          in_attr->i);
 
      else
 
       _bfd_error_handler
 
         (_("Warning: %B uses unknown small structure return convention %d"), obfd,
 
          out_attr->i);
 
    }
 
 
  /* Merge Tag_compatibility attributes and any common GNU ones.  */
  /* Merge Tag_compatibility attributes and any common GNU ones.  */
  _bfd_elf_merge_object_attributes (ibfd, obfd);
  _bfd_elf_merge_object_attributes (ibfd, obfd);
 
 
  return TRUE;
  return TRUE;
}
}
Line 3807... Line 4285...
  struct ppc_elf_link_hash_table *htab;
  struct ppc_elf_link_hash_table *htab;
  flagword flags;
  flagword flags;
 
 
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
 
 
 
  htab->emit_stub_syms = emit_stub_syms;
 
 
  if (htab->plt_type == PLT_UNSET)
  if (htab->plt_type == PLT_UNSET)
    {
    {
      if (plt_style == PLT_OLD)
      if (plt_style == PLT_OLD)
        htab->plt_type = PLT_OLD;
        htab->plt_type = PLT_OLD;
      else
      else
Line 3840... Line 4320...
        }
        }
    }
    }
  if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
  if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
    info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd);
    info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd);
 
 
  htab->emit_stub_syms = emit_stub_syms;
 
 
 
  BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
  BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
 
 
  if (htab->plt_type == PLT_NEW)
  if (htab->plt_type == PLT_NEW)
    {
    {
      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
Line 3949... Line 4427...
                break;
                break;
              }
              }
        }
        }
 
 
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
 
      if (!htab->is_vxworks
 
          && h == NULL
 
          && local_got_refcounts != NULL
 
          && (!info->shared
 
              || is_branch_reloc (r_type)))
 
        {
 
          struct plt_entry **local_plt = (struct plt_entry **)
 
            (local_got_refcounts + 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)
 
            {
 
              struct plt_entry **ifunc = local_plt + r_symndx;
 
              bfd_vma addend = 0;
 
              struct plt_entry *ent;
 
 
 
              if (r_type == R_PPC_PLTREL24 && info->shared)
 
                addend = rel->r_addend;
 
              ent = find_plt_ent (ifunc, got2, addend);
 
              if (ent->plt.refcount > 0)
 
                ent->plt.refcount -= 1;
 
              continue;
 
            }
 
        }
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_HI:
        case R_PPC_GOT_TLSLD16_HI:
Line 3975... Line 4478...
        case R_PPC_GOT16_HA:
        case R_PPC_GOT16_HA:
          if (h != NULL)
          if (h != NULL)
            {
            {
              if (h->got.refcount > 0)
              if (h->got.refcount > 0)
                h->got.refcount--;
                h->got.refcount--;
 
              if (!info->shared)
 
                {
 
                  struct plt_entry *ent;
 
 
 
                  ent = find_plt_ent (&h->plt.plist, NULL, 0);
 
                  if (ent != NULL && ent->plt.refcount > 0)
 
                    ent->plt.refcount -= 1;
 
                }
            }
            }
          else if (local_got_refcounts != NULL)
          else if (local_got_refcounts != NULL)
            {
            {
              if (local_got_refcounts[r_symndx] > 0)
              if (local_got_refcounts[r_symndx] > 0)
                local_got_refcounts[r_symndx]--;
                local_got_refcounts[r_symndx]--;
Line 4014... Line 4525...
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HA:
        case R_PPC_PLT16_HA:
          if (h != NULL)
          if (h != NULL)
            {
            {
              bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0;
              bfd_vma addend = 0;
              struct plt_entry *ent = find_plt_ent (h, got2, addend);
              struct plt_entry *ent;
              if (ent->plt.refcount > 0)
 
 
              if (r_type == R_PPC_PLTREL24 && info->shared)
 
                addend = rel->r_addend;
 
              ent = find_plt_ent (&h->plt.plist, got2, addend);
 
              if (ent != NULL && ent->plt.refcount > 0)
                ent->plt.refcount -= 1;
                ent->plt.refcount -= 1;
            }
            }
          break;
          break;
 
 
        default:
        default:
Line 4028... Line 4543...
        }
        }
    }
    }
  return TRUE;
  return TRUE;
}
}


/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
/* Set plt output section type, htab->tls_get_addr, and call the
 
   generic ELF tls_setup function.  */
 
 
asection *
asection *
ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
ppc_elf_tls_setup (bfd *obfd,
 
                   struct bfd_link_info *info,
 
                   int no_tls_get_addr_opt)
{
{
  struct ppc_elf_link_hash_table *htab;
  struct ppc_elf_link_hash_table *htab;
 
 
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
 
  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
 
                                             FALSE, FALSE, TRUE);
 
  if (!no_tls_get_addr_opt)
 
    {
 
      struct elf_link_hash_entry *opt, *tga;
 
      opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
 
                                  FALSE, FALSE, TRUE);
 
      if (opt != NULL
 
          && (opt->root.type == bfd_link_hash_defined
 
              || opt->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 = htab->tls_get_addr;
 
          if (htab->elf.dynamic_sections_created
 
              && tga != NULL
 
              && (tga->type == STT_FUNC
 
                  || tga->needs_plt)
 
              && !(SYMBOL_CALLS_LOCAL (info, tga)
 
                   || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
 
                       && tga->root.type == bfd_link_hash_undefweak)))
 
            {
 
              struct plt_entry *ent;
 
              for (ent = tga->plt.plist; ent != NULL; ent = ent->next)
 
                if (ent->plt.refcount > 0)
 
                  break;
 
              if (ent != NULL)
 
                {
 
                  tga->root.type = bfd_link_hash_indirect;
 
                  tga->root.u.i.link = &opt->root;
 
                  ppc_elf_copy_indirect_symbol (info, opt, tga);
 
                  if (opt->dynindx != -1)
 
                    {
 
                      /* Use __tls_get_addr_opt in dynamic relocations.  */
 
                      opt->dynindx = -1;
 
                      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
 
                                              opt->dynstr_index);
 
                      if (!bfd_elf_link_record_dynamic_symbol (info, opt))
 
                        return FALSE;
 
                    }
 
                  htab->tls_get_addr = opt;
 
                }
 
            }
 
        }
 
      else
 
        no_tls_get_addr_opt = TRUE;
 
    }
 
  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
  if (htab->plt_type == PLT_NEW
  if (htab->plt_type == PLT_NEW
      && htab->plt != NULL
      && htab->plt != NULL
      && htab->plt->output_section != NULL)
      && htab->plt->output_section != NULL)
    {
    {
      elf_section_type (htab->plt->output_section) = SHT_PROGBITS;
      elf_section_type (htab->plt->output_section) = SHT_PROGBITS;
      elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
      elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
    }
    }
 
 
  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
 
                                             FALSE, FALSE, TRUE);
 
  return _bfd_elf_tls_setup (obfd, info);
  return _bfd_elf_tls_setup (obfd, info);
}
}
 
 
 
/* Return TRUE iff REL is a branch reloc with a global symbol matching
 
   HASH.  */
 
 
 
static bfd_boolean
 
branch_reloc_hash_match (const bfd *ibfd,
 
                         const Elf_Internal_Rela *rel,
 
                         const struct elf_link_hash_entry *hash)
 
{
 
  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
 
  enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
 
  unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
 
 
 
  if (r_symndx >= symtab_hdr->sh_info && is_branch_reloc (r_type))
 
    {
 
      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
 
      struct elf_link_hash_entry *h;
 
 
 
      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
 
      while (h->root.type == bfd_link_hash_indirect
 
             || h->root.type == bfd_link_hash_warning)
 
        h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
      if (h == hash)
 
        return TRUE;
 
    }
 
  return FALSE;
 
}
 
 
/* Run through all the TLS relocs looking for optimization
/* Run through all the TLS relocs looking for optimization
   opportunities.  */
   opportunities.  */
 
 
bfd_boolean
bfd_boolean
ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
Line 4061... Line 4654...
  bfd *ibfd;
  bfd *ibfd;
  asection *sec;
  asection *sec;
  struct ppc_elf_link_hash_table *htab;
  struct ppc_elf_link_hash_table *htab;
  int pass;
  int pass;
 
 
  if (info->relocatable || info->shared)
  if (info->relocatable || !info->executable)
    return TRUE;
    return TRUE;
 
 
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
  /* Make two passes through the relocs.  First time check that tls
  /* Make two passes through the relocs.  First time check that tls
     relocs involved in setting up a tls_get_addr call are indeed
     relocs involved in setting up a tls_get_addr call are indeed
Line 4074... Line 4667...
  for (pass = 0; pass < 2; ++pass)
  for (pass = 0; pass < 2; ++pass)
    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
      {
      {
        Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Sym *locsyms = NULL;
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
        Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
 
        asection *got2 = bfd_get_section_by_name (ibfd, ".got2");
 
 
        for (sec = ibfd->sections; sec != NULL; sec = sec->next)
        for (sec = ibfd->sections; sec != NULL; sec = sec->next)
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
          if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
            {
            {
              Elf_Internal_Rela *relstart, *rel, *relend;
              Elf_Internal_Rela *relstart, *rel, *relend;
Line 4167... Line 4761...
                          break;
                          break;
                        }
                        }
                      else
                      else
                        continue;
                        continue;
 
 
 
                    case R_PPC_TLSGD:
 
                    case R_PPC_TLSLD:
 
                      expecting_tls_get_addr = 2;
 
                      tls_set = 0;
 
                      tls_clear = 0;
 
                      break;
 
 
                    default:
                    default:
                      continue;
                      continue;
                    }
                    }
 
 
                  if (pass == 0)
                  if (pass == 0)
                    {
                    {
                      if (!expecting_tls_get_addr)
                      if (!expecting_tls_get_addr
 
                          || (expecting_tls_get_addr == 1
 
                              && !sec->has_tls_get_addr_call))
                        continue;
                        continue;
 
 
                      if (rel + 1 < relend)
                      if (rel + 1 < relend
                        {
                          && branch_reloc_hash_match (ibfd, rel + 1,
                          enum elf_ppc_reloc_type r_type2;
                                                      htab->tls_get_addr))
                          unsigned long r_symndx2;
 
                          struct elf_link_hash_entry *h2;
 
 
 
                          /* The next instruction should be a call to
 
                             __tls_get_addr.  Peek at the reloc to be sure.  */
 
                          r_type2 = ELF32_R_TYPE (rel[1].r_info);
 
                          r_symndx2 = ELF32_R_SYM (rel[1].r_info);
 
                          if (r_symndx2 >= symtab_hdr->sh_info
 
                              && (r_type2 == R_PPC_REL14
 
                                  || r_type2 == R_PPC_REL14_BRTAKEN
 
                                  || r_type2 == R_PPC_REL14_BRNTAKEN
 
                                  || r_type2 == R_PPC_REL24
 
                                  || r_type2 == R_PPC_PLTREL24))
 
                            {
 
                              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 == htab->tls_get_addr)
 
                                continue;
                                continue;
                            }
 
                        }
 
 
 
                      /* Uh oh, we didn't find the expected call.  We
                      /* Uh oh, we didn't find the expected call.  We
                         could just mark this symbol to exclude it
                         could just mark this symbol to exclude it
                         from tls optimization but it's safer to skip
                         from tls optimization but it's safer to skip
                         the entire section.  */
                         the entire section.  */
                      sec->has_tls_reloc = 0;
                      sec->has_tls_reloc = 0;
                      break;
                      break;
                    }
                    }
 
 
 
                  if (expecting_tls_get_addr)
 
                    {
 
                      struct plt_entry *ent;
 
                      bfd_vma addend = 0;
 
 
 
                      if (info->shared
 
                          && ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
 
                        addend = rel[1].r_addend;
 
                      ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
 
                                          got2, addend);
 
                      if (ent != NULL && ent->plt.refcount > 0)
 
                        ent->plt.refcount -= 1;
 
 
 
                      if (expecting_tls_get_addr == 2)
 
                        continue;
 
                    }
 
 
                  if (h != NULL)
                  if (h != NULL)
                    {
                    {
                      tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
                      tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
                      got_count = &h->got.refcount;
                      got_count = &h->got.refcount;
                    }
                    }
                  else
                  else
                    {
                    {
                      Elf_Internal_Sym *sym;
                      Elf_Internal_Sym *sym;
                      bfd_signed_vma *lgot_refs;
                      bfd_signed_vma *lgot_refs;
 
                      struct plt_entry **local_plt;
                      char *lgot_masks;
                      char *lgot_masks;
 
 
                      if (locsyms == NULL)
                      if (locsyms == NULL)
                        {
                        {
                          locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
                          locsyms = (Elf_Internal_Sym *) symtab_hdr->contents;
Line 4243... Line 4839...
                        }
                        }
                      sym = locsyms + r_symndx;
                      sym = locsyms + r_symndx;
                      lgot_refs = elf_local_got_refcounts (ibfd);
                      lgot_refs = elf_local_got_refcounts (ibfd);
                      if (lgot_refs == NULL)
                      if (lgot_refs == NULL)
                        abort ();
                        abort ();
                      lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info);
                      local_plt = (struct plt_entry **)
 
                        (lgot_refs + symtab_hdr->sh_info);
 
                      lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
                      tls_mask = &lgot_masks[r_symndx];
                      tls_mask = &lgot_masks[r_symndx];
                      got_count = &lgot_refs[r_symndx];
                      got_count = &lgot_refs[r_symndx];
                    }
                    }
 
 
                  if (tls_set == 0)
                  if (tls_set == 0)
Line 4255... Line 4853...
                      /* We managed to get rid of a got entry.  */
                      /* We managed to get rid of a got entry.  */
                      if (*got_count > 0)
                      if (*got_count > 0)
                        *got_count -= 1;
                        *got_count -= 1;
                    }
                    }
 
 
                  if (expecting_tls_get_addr)
 
                    {
 
                      struct plt_entry *ent;
 
 
 
                      ent = find_plt_ent (htab->tls_get_addr, NULL, 0);
 
                      if (ent != NULL && ent->plt.refcount > 0)
 
                        ent->plt.refcount -= 1;
 
                    }
 
 
 
                  *tls_mask |= tls_set;
                  *tls_mask |= tls_set;
                  *tls_mask &= ~tls_clear;
                  *tls_mask &= ~tls_clear;
                }
                }
 
 
              if (elf_section_data (sec)->relocs != relstart)
              if (elf_section_data (sec)->relocs != relstart)
Line 4325... Line 4914...
 
 
  /* Make sure we know what is going on here.  */
  /* Make sure we know what is going on here.  */
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
  BFD_ASSERT (htab->elf.dynobj != NULL
  BFD_ASSERT (htab->elf.dynobj != NULL
              && (h->needs_plt
              && (h->needs_plt
 
                  || h->type == STT_GNU_IFUNC
                  || h->u.weakdef != NULL
                  || h->u.weakdef != NULL
                  || (h->def_dynamic
                  || (h->def_dynamic
                      && h->ref_regular
                      && h->ref_regular
                      && !h->def_regular)));
                      && !h->def_regular)));
 
 
  /* 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))))
        {
        {
          /* A PLT entry is not required/allowed when:
          /* A PLT entry is not required/allowed when:
 
 
             1. We are not using ld.so; because then the PLT entry
             1. We are not using ld.so; because then the PLT entry
             can't be set up, so we can't use one.  In this case,
             can't be set up, so we can't use one.  In this case,
Line 4360... Line 4952...
          h->plt.plist = NULL;
          h->plt.plist = NULL;
          h->needs_plt = 0;
          h->needs_plt = 0;
        }
        }
      else
      else
        {
        {
          /* After adjust_dynamic_symbol, non_got_ref set means that
          /* After adjust_dynamic_symbol, non_got_ref set in the
             dyn_relocs for this symbol should be discarded.
             non-shared case means that we have allocated space in
 
             .dynbss for the symbol and thus dyn_relocs for this
 
             symbol should be discarded.
             If we get here we know we are making a PLT entry for this
             If we get here we know we are making a PLT entry for this
             symbol, and in an executable we'd normally resolve
             symbol, and in an executable we'd normally resolve
             relocations against this symbol to the PLT entry.  Allow
             relocations against this symbol to the PLT entry.  Allow
             dynamic relocs if the reference is weak, and the dynamic
             dynamic relocs if the reference is weak, and the dynamic
             relocs will not cause text relocation.  */
             relocs will not cause text relocation.  */
          if (!h->ref_regular_nonweak
          if (!h->ref_regular_nonweak
              && h->non_got_ref
              && h->non_got_ref
 
              && h->type != STT_GNU_IFUNC
              && !htab->is_vxworks
              && !htab->is_vxworks
              && !ppc_elf_hash_entry (h)->has_sda_refs
              && !ppc_elf_hash_entry (h)->has_sda_refs
              && !readonly_dynrelocs (h))
              && !readonly_dynrelocs (h))
            h->non_got_ref = 0;
            h->non_got_ref = 0;
        }
        }
Line 4487... Line 5082...
  size_t len1, len2, len3;
  size_t len1, len2, len3;
  char *name;
  char *name;
  const char *stub;
  const char *stub;
  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
 
  if (info->shared || info->pie)
  if (info->shared)
    stub = ".plt_pic32.";
    stub = ".plt_pic32.";
  else
  else
    stub = ".plt_call32.";
    stub = ".plt_call32.";
 
 
  len1 = strlen (h->root.root.string);
  len1 = strlen (h->root.root.string);
Line 4579... Line 5174...
       entry in the hash table, thus we never get to see the real
       entry in the hash table, thus we never get to see the real
       symbol in a hash traversal.  So look at it now.  */
       symbol in a hash traversal.  So look at it now.  */
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
    h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
 
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
  if (htab->elf.dynamic_sections_created)
  if (htab->elf.dynamic_sections_created
 
      || h->type == STT_GNU_IFUNC)
    {
    {
      struct plt_entry *ent;
      struct plt_entry *ent;
      bfd_boolean doneone = FALSE;
      bfd_boolean doneone = FALSE;
      bfd_vma plt_offset = 0, glink_offset = 0;
      bfd_vma plt_offset = 0, glink_offset = 0;
 
      bfd_boolean dyn;
 
 
      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)
          {
          {
            /* Make sure this symbol is output as a dynamic symbol.  */
            /* Make sure this symbol is output as a dynamic symbol.  */
            if (h->dynindx == -1
            if (h->dynindx == -1
                && !h->forced_local)
                && !h->forced_local
 
                && !h->def_regular
 
                && 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;
              }
              }
 
 
 
            dyn = htab->elf.dynamic_sections_created;
            if (info->shared
            if (info->shared
                || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
                || h->type == STT_GNU_IFUNC
 
                || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))
              {
              {
                asection *s = htab->plt;
                asection *s = htab->plt;
 
                if (!dyn || h->dynindx == -1)
 
                  s = htab->iplt;
 
 
                if (htab->plt_type == PLT_NEW)
                if (htab->plt_type == PLT_NEW || !dyn || h->dynindx == -1)
                  {
                  {
                    if (!doneone)
                    if (!doneone)
                      {
                      {
                        plt_offset = s->size;
                        plt_offset = s->size;
                        s->size += 4;
                        s->size += 4;
                      }
                      }
                    ent->plt.offset = plt_offset;
                    ent->plt.offset = plt_offset;
 
 
                    s = htab->glink;
                    s = htab->glink;
                    if (!doneone || info->shared || info->pie)
                    if (!doneone || info->shared)
                      {
                      {
                        glink_offset = s->size;
                        glink_offset = s->size;
                        s->size += GLINK_ENTRY_SIZE;
                        s->size += GLINK_ENTRY_SIZE;
 
                        if (h == htab->tls_get_addr
 
                            && !htab->no_tls_get_addr_opt)
 
                          s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
                      }
                      }
                    if (!doneone
                    if (!doneone
                        && !info->shared
                        && !info->shared
                        && h->def_dynamic
                        && h->def_dynamic
                        && !h->def_regular)
                        && !h->def_regular)
Line 4652... Line 5258...
                                            / htab->plt_entry_size)));
                                            / htab->plt_entry_size)));
 
 
                        /* If this symbol is not defined in a regular
                        /* If this symbol is not defined in a regular
                           file, and we are not generating a shared
                           file, and we are not generating a shared
                           library, then set the symbol to this location
                           library, then set the symbol to this location
                           in the .plt.  This is required to make
                           in the .plt.  This is to avoid text
 
                           relocations, and is required to make
                           function pointers compare as equal between
                           function pointers compare as equal between
                           the normal executable and the shared library.  */
                           the normal executable and the shared library.  */
                        if (! info->shared
                        if (! info->shared
                            && h->def_dynamic
                            && h->def_dynamic
                            && !h->def_regular)
                            && !h->def_regular)
Line 4679... Line 5286...
                  }
                  }
 
 
                /* We also need to make an entry in the .rela.plt section.  */
                /* We also need to make an entry in the .rela.plt section.  */
                if (!doneone)
                if (!doneone)
                  {
                  {
 
                    if (!htab->elf.dynamic_sections_created
 
                        || h->dynindx == -1)
 
                      htab->reliplt->size += sizeof (Elf32_External_Rela);
 
                    else
 
                      {
                    htab->relplt->size += sizeof (Elf32_External_Rela);
                    htab->relplt->size += sizeof (Elf32_External_Rela);
 
 
                    if (htab->plt_type == PLT_VXWORKS)
                    if (htab->plt_type == PLT_VXWORKS)
                      {
                      {
                        /* Allocate space for the unloaded relocations.  */
                        /* Allocate space for the unloaded relocations.  */
                        if (!info->shared)
                            if (!info->shared
 
                                && htab->elf.dynamic_sections_created)
                          {
                          {
                            if (ent->plt.offset
                            if (ent->plt.offset
                                == (bfd_vma) htab->plt_initial_entry_size)
                                == (bfd_vma) htab->plt_initial_entry_size)
                              {
                              {
                                htab->srelplt2->size
                                htab->srelplt2->size
                                  += sizeof (Elf32_External_Rela)
                                      += (sizeof (Elf32_External_Rela)
                                      * VXWORKS_PLTRESOLVE_RELOCS;
                                          * VXWORKS_PLTRESOLVE_RELOCS);
                              }
                              }
 
 
                            htab->srelplt2->size
                            htab->srelplt2->size
                              += sizeof (Elf32_External_Rela)
                                  += (sizeof (Elf32_External_Rela)
                                  * VXWORKS_PLT_NON_JMP_SLOT_RELOCS;
                                      * VXWORKS_PLT_NON_JMP_SLOT_RELOCS);
                          }
                          }
 
 
                        /* Every PLT entry has an associated GOT entry in
                        /* Every PLT entry has an associated GOT entry in
                           .got.plt.  */
                           .got.plt.  */
                        htab->sgotplt->size += 4;
                        htab->sgotplt->size += 4;
                      }
                      }
 
                      }
                    doneone = TRUE;
                    doneone = TRUE;
                  }
                  }
              }
              }
            else
            else
              ent->plt.offset = (bfd_vma) -1;
              ent->plt.offset = (bfd_vma) -1;
Line 4727... Line 5341...
    }
    }
 
 
  eh = (struct ppc_elf_link_hash_entry *) h;
  eh = (struct ppc_elf_link_hash_entry *) h;
  if (eh->elf.got.refcount > 0)
  if (eh->elf.got.refcount > 0)
    {
    {
 
      bfd_boolean dyn;
 
      unsigned int need;
 
 
      /* Make sure this symbol is output as a dynamic symbol.  */
      /* Make sure this symbol is output as a dynamic symbol.  */
      if (eh->elf.dynindx == -1
      if (eh->elf.dynindx == -1
          && !eh->elf.forced_local)
          && !eh->elf.forced_local
 
          && eh->elf.type != STT_GNU_IFUNC
 
          && htab->elf.dynamic_sections_created)
        {
        {
          if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
          if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf))
            return FALSE;
            return FALSE;
        }
        }
 
 
      if (eh->tls_mask == (TLS_TLS | TLS_LD)
      need = 0;
          && !eh->elf.def_dynamic)
 
        {
 
          /* If just an LD reloc, we'll just use htab->tlsld_got.offset.  */
 
          htab->tlsld_got.refcount += 1;
 
          eh->elf.got.offset = (bfd_vma) -1;
 
        }
 
      else
 
        {
 
          bfd_boolean dyn;
 
          unsigned int need = 0;
 
          if ((eh->tls_mask & TLS_TLS) != 0)
          if ((eh->tls_mask & TLS_TLS) != 0)
            {
            {
              if ((eh->tls_mask & TLS_LD) != 0)
              if ((eh->tls_mask & TLS_LD) != 0)
 
            {
 
              if (!eh->elf.def_dynamic)
 
                /* We'll just use htab->tlsld_got.offset.  This should
 
                   always be the case.  It's a little odd if we have
 
                   a local dynamic reloc against a non-local symbol.  */
 
                htab->tlsld_got.refcount += 1;
 
              else
                need += 8;
                need += 8;
 
            }
              if ((eh->tls_mask & TLS_GD) != 0)
              if ((eh->tls_mask & TLS_GD) != 0)
                need += 8;
                need += 8;
              if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
              if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
                need += 4;
                need += 4;
              if ((eh->tls_mask & TLS_DTPREL) != 0)
              if ((eh->tls_mask & TLS_DTPREL) != 0)
                need += 4;
                need += 4;
            }
            }
          else
          else
            need += 4;
            need += 4;
 
      if (need == 0)
 
        eh->elf.got.offset = (bfd_vma) -1;
 
      else
 
        {
          eh->elf.got.offset = allocate_got (htab, need);
          eh->elf.got.offset = allocate_got (htab, need);
          dyn = htab->elf.dynamic_sections_created;
          dyn = htab->elf.dynamic_sections_created;
          if ((info->shared
          if ((info->shared
               || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
               || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf))
              && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
              && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT
                  || eh->elf.root.type != bfd_link_hash_undefweak))
                  || eh->elf.root.type != bfd_link_hash_undefweak))
            {
            {
 
              asection *rsec = htab->relgot;
              /* All the entries we allocated need relocs.
              /* All the entries we allocated need relocs.
                 Except LD only needs one.  */
                 Except LD only needs one.  */
              if ((eh->tls_mask & TLS_LD) != 0)
              if ((eh->tls_mask & TLS_LD) != 0
 
                  && eh->elf.def_dynamic)
                need -= 4;
                need -= 4;
              htab->relgot->size += need * (sizeof (Elf32_External_Rela) / 4);
              rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
            }
            }
        }
        }
    }
    }
  else
  else
    eh->elf.got.offset = (bfd_vma) -1;
    eh->elf.got.offset = (bfd_vma) -1;
 
 
  if (eh->dyn_relocs == NULL)
  if (eh->dyn_relocs == NULL
 
      || !htab->elf.dynamic_sections_created)
    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 4789... Line 5413...
     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 4809... Line 5433...
              else
              else
                pp = &p->next;
                pp = &p->next;
            }
            }
        }
        }
 
 
 
      if (htab->is_vxworks)
 
        {
 
          struct ppc_elf_dyn_relocs **pp;
 
 
 
          for (pp = &eh->dyn_relocs; (p = *pp) != NULL; )
 
            {
 
              if (strcmp (p->sec->output_section->name, ".tls_vars") == 0)
 
                *pp = p->next;
 
              else
 
                pp = &p->next;
 
            }
 
        }
 
 
 
      /* Discard relocs on undefined symbols that must be local.  */
 
      if (eh->dyn_relocs != NULL
 
          && h->root.type == bfd_link_hash_undefined
 
          && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
 
              || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
 
        eh->dyn_relocs = NULL;
 
 
      /* Also discard relocs on undefined weak syms with non-default
      /* Also discard relocs on undefined weak syms with non-default
         visibility.  */
         visibility.  */
      if (eh->dyn_relocs != NULL
      if (eh->dyn_relocs != NULL
          && h->root.type == bfd_link_hash_undefweak)
          && h->root.type == bfd_link_hash_undefweak)
        {
        {
Line 4820... Line 5464...
            eh->dyn_relocs = NULL;
            eh->dyn_relocs = NULL;
 
 
          /* Make sure undefined weak symbols are output as a dynamic
          /* Make sure undefined weak symbols are output as a dynamic
             symbol in PIEs.  */
             symbol in PIEs.  */
          else if (h->dynindx == -1
          else if (h->dynindx == -1
                   && !h->forced_local)
                   && !h->forced_local
 
                   && !h->def_regular)
            {
            {
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
              if (! bfd_elf_link_record_dynamic_symbol (info, h))
                return FALSE;
                return FALSE;
            }
            }
        }
        }
Line 4860... Line 5505...
 
 
  /* 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 (Elf32_External_Rela);
      sreloc->size += p->count * sizeof (Elf32_External_Rela);
    }
    }
 
 
  return TRUE;
  return TRUE;
}
}
Line 4929... Line 5576...
     relocs.  */
     relocs.  */
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
    {
    {
      bfd_signed_vma *local_got;
      bfd_signed_vma *local_got;
      bfd_signed_vma *end_local_got;
      bfd_signed_vma *end_local_got;
 
      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;
 
 
      if (!is_ppc_elf (ibfd))
      if (!is_ppc_elf (ibfd))
Line 4953... Line 5602...
                  /* Input section has been discarded, either because
                  /* Input section has been discarded, either because
                     it is a copy of a linkonce section or due to
                     it is a copy of a linkonce section or due to
                     linker script /DISCARD/, so we'll be discarding
                     linker script /DISCARD/, so we'll be discarding
                     the relocs too.  */
                     the relocs too.  */
                }
                }
 
              else if (htab->is_vxworks
 
                       && strcmp (p->sec->output_section->name,
 
                                  ".tls_vars") == 0)
 
                {
 
                  /* Relocations in vxworks .tls_vars sections are
 
                     handled specially by the loader.  */
 
                }
              else if (p->count != 0)
              else if (p->count != 0)
                {
                {
                  elf_section_data (p->sec)->sreloc->size
                  asection *sreloc = elf_section_data (p->sec)->sreloc;
                    += p->count * sizeof (Elf32_External_Rela);
                  if (!htab->elf.dynamic_sections_created)
 
                    sreloc = htab->reliplt;
 
                  sreloc->size += p->count * sizeof (Elf32_External_Rela);
                  if ((p->sec->output_section->flags
                  if ((p->sec->output_section->flags
                       & (SEC_READONLY | SEC_ALLOC))
                       & (SEC_READONLY | SEC_ALLOC))
                      == (SEC_READONLY | SEC_ALLOC))
                      == (SEC_READONLY | SEC_ALLOC))
                    info->flags |= DF_TEXTREL;
                    info->flags |= DF_TEXTREL;
                }
                }
Line 4972... Line 5630...
        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_local_got = local_got + locsymcount;
      end_local_got = local_got + locsymcount;
      lgot_masks = (char *) end_local_got;
      local_plt = (struct plt_entry **) end_local_got;
 
      end_local_plt = local_plt + locsymcount;
 
      lgot_masks = (char *) end_local_plt;
 
 
      for (; local_got < end_local_got; ++local_got, ++lgot_masks)
      for (; local_got < end_local_got; ++local_got, ++lgot_masks)
        if (*local_got > 0)
        if (*local_got > 0)
          {
          {
            if (*lgot_masks == (TLS_TLS | TLS_LD))
 
              {
 
                /* If just an LD reloc, we'll just use
 
                   htab->tlsld_got.offset.  */
 
                htab->tlsld_got.refcount += 1;
 
                *local_got = (bfd_vma) -1;
 
              }
 
            else
 
              {
 
                unsigned int need = 0;
                unsigned int need = 0;
                if ((*lgot_masks & TLS_TLS) != 0)
                if ((*lgot_masks & TLS_TLS) != 0)
                  {
                  {
                    if ((*lgot_masks & TLS_GD) != 0)
                    if ((*lgot_masks & TLS_GD) != 0)
                      need += 8;
                      need += 8;
 
                if ((*lgot_masks & TLS_LD) != 0)
 
                  htab->tlsld_got.refcount += 1;
                    if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
                    if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
                      need += 4;
                      need += 4;
                    if ((*lgot_masks & TLS_DTPREL) != 0)
                    if ((*lgot_masks & TLS_DTPREL) != 0)
                      need += 4;
                      need += 4;
                  }
                  }
                else
                else
                  need += 4;
                  need += 4;
 
            if (need == 0)
 
              *local_got = (bfd_vma) -1;
 
            else
 
              {
                *local_got = allocate_got (htab, need);
                *local_got = allocate_got (htab, need);
                if (info->shared)
                if (info->shared)
                  htab->relgot->size += (need
                  htab->relgot->size += (need
                                         * (sizeof (Elf32_External_Rela) / 4));
                                         * (sizeof (Elf32_External_Rela) / 4));
              }
              }
          }
          }
        else
        else
          *local_got = (bfd_vma) -1;
          *local_got = (bfd_vma) -1;
 
 
 
      if (htab->is_vxworks)
 
        continue;
 
 
 
      /* Allocate space for calls to local STT_GNU_IFUNC syms in .iplt.  */
 
      for (; local_plt < end_local_plt; ++local_plt)
 
        {
 
          struct plt_entry *ent;
 
          bfd_boolean doneone = FALSE;
 
          bfd_vma plt_offset = 0, glink_offset = 0;
 
 
 
          for (ent = *local_plt; ent != NULL; ent = ent->next)
 
            if (ent->plt.refcount > 0)
 
              {
 
                s = htab->iplt;
 
 
 
                if (!doneone)
 
                  {
 
                    plt_offset = s->size;
 
                    s->size += 4;
 
                  }
 
                ent->plt.offset = plt_offset;
 
 
 
                s = htab->glink;
 
                if (!doneone || info->shared)
 
                  {
 
                    glink_offset = s->size;
 
                    s->size += GLINK_ENTRY_SIZE;
 
                  }
 
                ent->glink_offset = glink_offset;
 
 
 
                if (!doneone)
 
                  {
 
                    htab->reliplt->size += sizeof (Elf32_External_Rela);
 
                    doneone = TRUE;
 
                  }
 
              }
 
            else
 
              ent->plt.offset = (bfd_vma) -1;
 
        }
    }
    }
 
 
  /* Allocate space for global sym dynamic relocs.  */
  /* Allocate space for global sym dynamic relocs.  */
  elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
  elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
 
 
Line 5037... Line 5735...
          htab->got->size += htab->got_header_size;
          htab->got->size += htab->got_header_size;
        }
        }
 
 
      htab->elf.hgot->root.u.def.value = g_o_t;
      htab->elf.hgot->root.u.def.value = g_o_t;
    }
    }
 
  if (info->shared)
 
    {
 
      struct elf_link_hash_entry *sda = htab->sdata[0].sym;
 
      if (sda != NULL
 
          && !(sda->root.type == bfd_link_hash_defined
 
               || sda->root.type == bfd_link_hash_defweak))
 
        {
 
          sda->root.type = bfd_link_hash_defined;
 
          sda->root.u.def.section = htab->elf.hgot->root.u.def.section;
 
          sda->root.u.def.value = htab->elf.hgot->root.u.def.value;
 
        }
 
    }
 
 
  if (htab->glink != NULL && htab->glink->size != 0)
  if (htab->glink != NULL
 
      && htab->glink->size != 0
 
      && htab->elf.dynamic_sections_created)
    {
    {
      htab->glink_pltresolve = htab->glink->size;
      htab->glink_pltresolve = htab->glink->size;
      /* Space for the branch table.  */
      /* Space for the branch table.  */
      htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
      htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4;
      /* Pad out to align the start of PLTresolve.  */
      /* Pad out to align the start of PLTresolve.  */
Line 5094... Line 5806...
 
 
      if ((s->flags & SEC_LINKER_CREATED) == 0)
      if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
        continue;
 
 
      if (s == htab->plt
      if (s == htab->plt
          || s == htab->glink
          || s == htab->got)
          || s == htab->got
 
          || s == htab->sgotplt
 
          || s == htab->sbss
 
          || s == htab->dynbss
 
          || s == htab->dynsbss)
 
        {
        {
          /* We'd like to strip these sections if they aren't needed, but if
          /* We'd like to strip these sections if they aren't needed, but if
             we've exported dynamic symbols from them we must leave them.
             we've exported dynamic symbols from them we must leave them.
             It's too late to tell BFD to get rid of the symbols.  */
             It's too late to tell BFD to get rid of the symbols.  */
          if ((s == htab->plt || s == htab->got) && htab->elf.hplt != NULL)
          if (htab->elf.hplt != NULL)
            strip_section = FALSE;
            strip_section = FALSE;
          /* 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.  */
        }
        }
      else if (s == htab->sdata[0].section
      else if (s == htab->iplt
 
               || s == htab->glink
 
               || s == htab->sgotplt
 
               || s == htab->sbss
 
               || s == htab->dynbss
 
               || s == htab->dynsbss
 
               || s == htab->sdata[0].section
               || s == htab->sdata[1].section)
               || s == htab->sdata[1].section)
        {
        {
          /* Strip these too.  */
          /* Strip these too.  */
        }
        }
      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
      else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela"))
Line 5185... Line 5898...
 
 
      if (htab->glink != NULL && htab->glink->size != 0)
      if (htab->glink != NULL && htab->glink->size != 0)
        {
        {
          if (!add_dynamic_entry (DT_PPC_GOT, 0))
          if (!add_dynamic_entry (DT_PPC_GOT, 0))
            return FALSE;
            return FALSE;
 
          if (!htab->no_tls_get_addr_opt
 
              && htab->tls_get_addr != NULL
 
              && htab->tls_get_addr->plt.plist != NULL
 
              && !add_dynamic_entry (DT_PPC_TLSOPT, 0))
 
            return FALSE;
        }
        }
 
 
      if (relocs)
      if (relocs)
        {
        {
          if (!add_dynamic_entry (DT_RELA, 0)
          if (!add_dynamic_entry (DT_RELA, 0)
Line 5231... Line 5949...
  return _bfd_elf_hash_symbol (h);
  return _bfd_elf_hash_symbol (h);
}
}


#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
 
 
 
/* Relaxation trampolines.  r12 is available for clobbering (r11, is
 
   used for some functions that are allowed to break the ABI).  */
static const int shared_stub_entry[] =
static const int shared_stub_entry[] =
  {
  {
    0x7c0802a6, /* mflr 0 */
    0x7c0802a6, /* mflr 0 */
    0x429f0005, /* bcl 20, 31, .Lxxx */
    0x429f0005, /* bcl 20, 31, .Lxxx */
    0x7d6802a6, /* mflr 11 */
    0x7d8802a6, /* mflr 12 */
    0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */
    0x3d8c0000, /* addis 12, 12, (xxx-.Lxxx)@ha */
    0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */
    0x398c0008, /* addi 12, 12, (xxx-.Lxxx)@l */
    0x7c0803a6, /* mtlr 0 */
    0x7c0803a6, /* mtlr 0 */
    0x7d6903a6, /* mtctr 11 */
    0x7d8903a6, /* mtctr 12 */
    0x4e800420, /* bctr */
    0x4e800420, /* bctr */
  };
  };
 
 
static const int stub_entry[] =
static const int stub_entry[] =
  {
  {
    0x3d600000, /* lis 11,xxx@ha */
    0x3d800000, /* lis 12,xxx@ha */
    0x396b0000, /* addi 11,11,xxx@l */
    0x398c0000, /* addi 12,12,xxx@l */
    0x7d6903a6, /* mtctr 11 */
    0x7d8903a6, /* mtctr 12 */
    0x4e800420, /* bctr */
    0x4e800420, /* bctr */
  };
  };
 
 
static bfd_boolean
static bfd_boolean
ppc_elf_relax_section (bfd *abfd,
ppc_elf_relax_section (bfd *abfd,
Line 5261... Line 5981...
{
{
  struct one_fixup
  struct one_fixup
  {
  {
    struct one_fixup *next;
    struct one_fixup *next;
    asection *tsec;
    asection *tsec;
 
    /* Final link, can use the symbol offset.  For a
 
       relocatable link we use the symbol's index.  */
    bfd_vma toff;
    bfd_vma toff;
    bfd_vma trampoff;
    bfd_vma trampoff;
  };
  };
 
 
  Elf_Internal_Shdr *symtab_hdr;
  Elf_Internal_Shdr *symtab_hdr;
  bfd_byte *contents = NULL;
  bfd_byte *contents = NULL;
  Elf_Internal_Sym *isymbuf = NULL;
  Elf_Internal_Sym *isymbuf = NULL;
  Elf_Internal_Rela *internal_relocs = NULL;
  Elf_Internal_Rela *internal_relocs = NULL;
  Elf_Internal_Rela *irel, *irelend;
  Elf_Internal_Rela *irel, *irelend;
  struct one_fixup *fixups = NULL;
  struct one_fixup *fixups = NULL;
  bfd_boolean changed;
  unsigned changes = 0;
  struct ppc_elf_link_hash_table *htab;
  struct ppc_elf_link_hash_table *htab;
  bfd_size_type trampoff;
  bfd_size_type trampoff;
  asection *got2;
  asection *got2;
 
 
  *again = FALSE;
  *again = FALSE;
 
 
  /* Nothing to do if there are no relocations, and no need to do
  /* Nothing to do if there are no relocations, and no need to do
     anything with non-alloc sections.  */
     anything with non-alloc or non-code sections.  */
  if ((isec->flags & SEC_ALLOC) == 0
  if ((isec->flags & SEC_ALLOC) == 0
 
      || (isec->flags & SEC_CODE) == 0
      || (isec->flags & SEC_RELOC) == 0
      || (isec->flags & SEC_RELOC) == 0
      || isec->reloc_count == 0)
      || isec->reloc_count == 0)
    return TRUE;
    return TRUE;
 
 
 
  /* We cannot represent the required PIC relocs in the output, so don't
 
     do anything.  The linker doesn't support mixing -shared and -r
 
     anyway.  */
 
  if (link_info->relocatable && link_info->shared)
 
     return TRUE;
 
 
  trampoff = (isec->size + 3) & (bfd_vma) -4;
  trampoff = (isec->size + 3) & (bfd_vma) -4;
  /* Space for a branch around any trampolines.  */
  /* Space for a branch around any trampolines.  */
  trampoff += 4;
  trampoff += 4;
 
 
  symtab_hdr = &elf_symtab_hdr (abfd);
  symtab_hdr = &elf_symtab_hdr (abfd);
Line 5304... Line 6033...
 
 
  irelend = internal_relocs + isec->reloc_count;
  irelend = internal_relocs + isec->reloc_count;
  for (irel = internal_relocs; irel < irelend; irel++)
  for (irel = internal_relocs; irel < irelend; irel++)
    {
    {
      unsigned long r_type = ELF32_R_TYPE (irel->r_info);
      unsigned long r_type = ELF32_R_TYPE (irel->r_info);
      bfd_vma symaddr, reladdr, toff, roff;
      bfd_vma toff, roff;
      asection *tsec;
      asection *tsec;
      struct one_fixup *f;
      struct one_fixup *f;
      size_t insn_offset = 0;
      size_t insn_offset = 0;
      bfd_vma max_branch_offset, val;
      bfd_vma max_branch_offset, val;
      bfd_byte *hit_addr;
      bfd_byte *hit_addr;
      unsigned long t0;
      unsigned long t0;
 
      struct elf_link_hash_entry *h;
 
      struct plt_entry **plist;
      unsigned char sym_type;
      unsigned char sym_type;
 
 
      switch (r_type)
      switch (r_type)
        {
        {
        case R_PPC_REL24:
        case R_PPC_REL24:
Line 5332... Line 6063...
        default:
        default:
          continue;
          continue;
        }
        }
 
 
      /* Get the value of the symbol referred to by the reloc.  */
      /* Get the value of the symbol referred to by the reloc.  */
 
      h = NULL;
      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
      if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info)
        {
        {
          /* A local symbol.  */
          /* A local symbol.  */
          Elf_Internal_Sym *isym;
          Elf_Internal_Sym *isym;
 
 
Line 5350... Line 6082...
              if (isymbuf == 0)
              if (isymbuf == 0)
                goto error_return;
                goto error_return;
            }
            }
          isym = isymbuf + ELF32_R_SYM (irel->r_info);
          isym = isymbuf + ELF32_R_SYM (irel->r_info);
          if (isym->st_shndx == SHN_UNDEF)
          if (isym->st_shndx == SHN_UNDEF)
            continue;   /* We can't do anything with undefined symbols.  */
            tsec = bfd_und_section_ptr;
          else if (isym->st_shndx == SHN_ABS)
          else if (isym->st_shndx == SHN_ABS)
            tsec = bfd_abs_section_ptr;
            tsec = bfd_abs_section_ptr;
          else if (isym->st_shndx == SHN_COMMON)
          else if (isym->st_shndx == SHN_COMMON)
            tsec = bfd_com_section_ptr;
            tsec = bfd_com_section_ptr;
          else
          else
Line 5365... Line 6097...
        }
        }
      else
      else
        {
        {
          /* Global symbol handling.  */
          /* Global symbol handling.  */
          unsigned long indx;
          unsigned long indx;
          struct elf_link_hash_entry *h;
 
 
 
          indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
          indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info;
          h = elf_sym_hashes (abfd)[indx];
          h = elf_sym_hashes (abfd)[indx];
 
 
          while (h->root.type == bfd_link_hash_indirect
          while (h->root.type == bfd_link_hash_indirect
                 || h->root.type == bfd_link_hash_warning)
                 || h->root.type == bfd_link_hash_warning)
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
            h = (struct elf_link_hash_entry *) h->root.u.i.link;
 
 
          tsec = NULL;
          if (h->root.type == bfd_link_hash_defined
          toff = 0;
              || h->root.type == bfd_link_hash_defweak)
          if (r_type == R_PPC_PLTREL24
 
              && htab->plt != NULL)
 
            {
 
              struct plt_entry *ent = find_plt_ent (h, got2, irel->r_addend);
 
 
 
              if (ent != NULL)
 
                {
                {
                  if (htab->plt_type == PLT_NEW)
              tsec = h->root.u.def.section;
 
              toff = h->root.u.def.value;
 
            }
 
          else if (h->root.type == bfd_link_hash_undefined
 
                   || h->root.type == bfd_link_hash_undefweak)
                    {
                    {
                      tsec = htab->glink;
              tsec = bfd_und_section_ptr;
                      toff = ent->glink_offset;
              toff = link_info->relocatable ? indx : 0;
                    }
                    }
                  else
                  else
                    {
            continue;
                      tsec = htab->plt;
 
                      toff = ent->plt.offset;
          sym_type = h->type;
                    }
 
                }
                }
 
 
 
      /* The condition here under which we call find_plt_ent must
 
         match that in relocate_section.  If we call find_plt_ent here
 
         but not in relocate_section, or vice versa, then the branch
 
         destination used here may be incorrect.  */
 
      plist = NULL;
 
      if (h != NULL)
 
        {
 
          /* We know is_branch_reloc (r_type) is true.  */
 
          if (h->type == STT_GNU_IFUNC
 
              || r_type == R_PPC_PLTREL24)
 
            plist = &h->plt.plist;
 
        }
 
      else if (sym_type == STT_GNU_IFUNC
 
               && elf_local_got_offsets (abfd) != NULL)
 
        {
 
          bfd_vma *local_got_offsets = elf_local_got_offsets (abfd);
 
          struct plt_entry **local_plt = (struct plt_entry **)
 
            (local_got_offsets + symtab_hdr->sh_info);
 
          plist = local_plt + ELF32_R_SYM (irel->r_info);
            }
            }
          if (tsec != NULL)
      if (plist != NULL)
            ;
 
          else if (h->root.type == bfd_link_hash_defined
 
                   || h->root.type == bfd_link_hash_defweak)
 
            {
            {
              tsec = h->root.u.def.section;
          bfd_vma addend = 0;
              toff = h->root.u.def.value;
          struct plt_entry *ent;
 
 
 
          if (r_type == R_PPC_PLTREL24 && link_info->shared)
 
            addend = irel->r_addend;
 
          ent = find_plt_ent (plist, got2, addend);
 
          if (ent != NULL)
 
            {
 
              if (htab->plt_type == PLT_NEW
 
                  || h == NULL
 
                  || !htab->elf.dynamic_sections_created
 
                  || h->dynindx == -1)
 
                {
 
                  tsec = htab->glink;
 
                  toff = ent->glink_offset;
            }
            }
          else
          else
            continue;
                {
 
                  tsec = htab->plt;
          sym_type = h->type;
                  toff = ent->plt.offset;
 
                }
 
            }
        }
        }
 
 
      /* If the branch and target are in the same section, you have
      /* If the branch and target are in the same section, you have
         no hope of adding stubs.  We'll error out later should the
         no hope of adding stubs.  We'll error out later should the
         branch overflow.  */
         branch overflow.  */
Line 5456... Line 6216...
 
 
      /* Attempted -shared link of non-pic code loses.  */
      /* Attempted -shared link of non-pic code loses.  */
      if (tsec->output_section == NULL)
      if (tsec->output_section == NULL)
        continue;
        continue;
 
 
      symaddr = tsec->output_section->vma + tsec->output_offset + toff;
 
 
 
      roff = irel->r_offset;
      roff = irel->r_offset;
      reladdr = isec->output_section->vma + isec->output_offset + roff;
 
 
 
      /* If the branch is in range, no need to do anything.  */
      /* If the branch is in range, no need to do anything.  */
 
      if (tsec != bfd_und_section_ptr
 
          && (!link_info->relocatable
 
              /* A relocatable link may have sections moved during
 
                 final link, so do not presume they remain in range.  */
 
              || tsec->output_section == isec->output_section))
 
        {
 
          bfd_vma symaddr, reladdr;
 
 
 
          symaddr = tsec->output_section->vma + tsec->output_offset + toff;
 
          reladdr = isec->output_section->vma + isec->output_offset + roff;
      if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
      if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset)
        continue;
        continue;
 
        }
 
 
      /* Look for an existing fixup to this address.  */
      /* Look for an existing fixup to this address.  */
      for (f = fixups; f ; f = f->next)
      for (f = fixups; f ; f = f->next)
        if (f->tsec == tsec && f->toff == toff)
        if (f->tsec == tsec && f->toff == toff)
          break;
          break;
Line 5485... Line 6253...
 
 
          if (link_info->shared)
          if (link_info->shared)
            {
            {
              size = 4 * ARRAY_SIZE (shared_stub_entry);
              size = 4 * ARRAY_SIZE (shared_stub_entry);
              insn_offset = 12;
              insn_offset = 12;
              stub_rtype = R_PPC_RELAX32PC;
 
            }
            }
          else
          else
            {
            {
              size = 4 * ARRAY_SIZE (stub_entry);
              size = 4 * ARRAY_SIZE (stub_entry);
              insn_offset = 0;
              insn_offset = 0;
              stub_rtype = R_PPC_RELAX32;
 
            }
            }
 
          stub_rtype = R_PPC_RELAX;
          if (R_PPC_RELAX32_PLT - R_PPC_RELAX32
 
              != R_PPC_RELAX32PC_PLT - R_PPC_RELAX32PC)
 
            abort ();
 
          if (tsec == htab->plt
          if (tsec == htab->plt
              || tsec == htab->glink)
              || tsec == htab->glink)
            stub_rtype += R_PPC_RELAX32_PLT - R_PPC_RELAX32;
            {
 
              stub_rtype = R_PPC_RELAX_PLT;
 
              if (r_type == R_PPC_PLTREL24)
 
                stub_rtype = R_PPC_RELAX_PLTREL24;
 
            }
 
 
          /* Hijack the old relocation.  Since we need two
          /* Hijack the old relocation.  Since we need two
             relocations for this use a "composite" reloc.  */
             relocations for this use a "composite" reloc.  */
          irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
          irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info),
                                       stub_rtype);
                                       stub_rtype);
          irel->r_offset = trampoff + insn_offset;
          irel->r_offset = trampoff + insn_offset;
 
          if (r_type == R_PPC_PLTREL24
 
              && stub_rtype != R_PPC_RELAX_PLTREL24)
 
            irel->r_addend = 0;
 
 
          /* Record the fixup so we don't do it again this section.  */
          /* Record the fixup so we don't do it again this section.  */
          f = bfd_malloc (sizeof (*f));
          f = bfd_malloc (sizeof (*f));
          f->next = fixups;
          f->next = fixups;
          f->tsec = tsec;
          f->tsec = tsec;
          f->toff = toff;
          f->toff = toff;
          f->trampoff = trampoff;
          f->trampoff = trampoff;
          fixups = f;
          fixups = f;
 
 
          trampoff += size;
          trampoff += size;
 
          changes++;
        }
        }
      else
      else
        {
        {
          val = f->trampoff - roff;
          val = f->trampoff - roff;
          if (val >= max_branch_offset)
          if (val >= max_branch_offset)
Line 5566... Line 6337...
          break;
          break;
        }
        }
    }
    }
 
 
  /* Write out the trampolines.  */
  /* Write out the trampolines.  */
  changed = fixups != NULL;
 
  if (fixups != NULL)
  if (fixups != NULL)
    {
    {
      const int *stub;
      const int *stub;
      bfd_byte *dest;
      bfd_byte *dest;
      bfd_vma val;
      bfd_vma val;
Line 5588... Line 6358...
      if (contents == NULL)
      if (contents == NULL)
        goto error_return;
        goto error_return;
 
 
      isec->size = (isec->size + 3) & (bfd_vma) -4;
      isec->size = (isec->size + 3) & (bfd_vma) -4;
      /* Branch around the trampolines.  */
      /* Branch around the trampolines.  */
      val = trampoff - isec->size + 0x48000000;
      val = B + trampoff - isec->size;
      dest = contents + isec->size;
      dest = contents + isec->size;
      isec->size = trampoff;
      isec->size = trampoff;
      bfd_put_32 (abfd, val, dest);
      bfd_put_32 (abfd, val, dest);
      dest += 4;
      dest += 4;
 
 
Line 5632... Line 6402...
    }
    }
 
 
  if (contents != NULL
  if (contents != NULL
      && elf_section_data (isec)->this_hdr.contents != contents)
      && elf_section_data (isec)->this_hdr.contents != contents)
    {
    {
      if (!changed && !link_info->keep_memory)
      if (!changes && !link_info->keep_memory)
        free (contents);
        free (contents);
      else
      else
        {
        {
          /* Cache the section contents for elf_link_input_bfd.  */
          /* Cache the section contents for elf_link_input_bfd.  */
          elf_section_data (isec)->this_hdr.contents = contents;
          elf_section_data (isec)->this_hdr.contents = contents;
        }
        }
    }
    }
 
 
  if (elf_section_data (isec)->relocs != internal_relocs)
  if (changes != 0)
    {
    {
      if (!changed)
      /* Append sufficient NOP relocs so we can write out relocation
 
         information for the trampolines.  */
 
      Elf_Internal_Rela *new_relocs = bfd_malloc ((changes + isec->reloc_count)
 
                                                  * sizeof (*new_relocs));
 
      unsigned ix;
 
 
 
      if (!new_relocs)
 
        goto error_return;
 
      memcpy (new_relocs, internal_relocs,
 
              isec->reloc_count * sizeof (*new_relocs));
 
      for (ix = changes; ix--;)
 
        {
 
          irel = new_relocs + ix + isec->reloc_count;
 
 
 
          irel->r_info = ELF32_R_INFO (0, R_PPC_NONE);
 
        }
 
      if (internal_relocs != elf_section_data (isec)->relocs)
        free (internal_relocs);
        free (internal_relocs);
      else
      elf_section_data (isec)->relocs = new_relocs;
        elf_section_data (isec)->relocs = internal_relocs;
      isec->reloc_count += changes;
 
      elf_section_data (isec)->rel_hdr.sh_size
 
        += changes * elf_section_data (isec)->rel_hdr.sh_entsize;
 
    }
 
  else if (elf_section_data (isec)->relocs != internal_relocs)
 
    free (internal_relocs);
 
 
 
  *again = changes != 0;
 
  if (!*again && link_info->relocatable)
 
    {
 
      /* Convert the internal relax relocs to external form.  */
 
      for (irel = internal_relocs; irel < irelend; irel++)
 
        if (ELF32_R_TYPE (irel->r_info) == R_PPC_RELAX)
 
          {
 
            unsigned long r_symndx = ELF32_R_SYM (irel->r_info);
 
 
 
            /* Rewrite the reloc and convert one of the trailing nop
 
               relocs to describe this relocation.  */
 
            BFD_ASSERT (ELF32_R_TYPE (irelend[-1].r_info) == R_PPC_NONE);
 
            /* The relocs are at the bottom 2 bytes */
 
            irel[0].r_offset += 2;
 
            memmove (irel + 1, irel, (irelend - irel - 1) * sizeof (*irel));
 
            irel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
 
            irel[1].r_offset += 4;
 
            irel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
 
            irel++;
 
          }
    }
    }
 
 
  *again = changed;
 
  return TRUE;
  return TRUE;
 
 
 error_return:
 error_return:
  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
  if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents)
    free (isymbuf);
    free (isymbuf);
Line 5726... Line 6537...
                  relocation + linker_section_ptr->addend,
                  relocation + linker_section_ptr->addend,
                  lsect->section->contents + linker_section_ptr->offset);
                  lsect->section->contents + linker_section_ptr->offset);
      linker_section_ptr->offset += 1;
      linker_section_ptr->offset += 1;
    }
    }
 
 
  relocation = (lsect->section->output_offset
  relocation = (lsect->section->output_section->vma
 
                + lsect->section->output_offset
                + linker_section_ptr->offset - 1
                + linker_section_ptr->offset - 1
                - 0x8000);
                - SYM_VAL (lsect->sym));
 
 
#ifdef DEBUG
#ifdef DEBUG
  fprintf (stderr,
  fprintf (stderr,
           "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
           "Finish pointer in linker section %s, offset = %ld (0x%lx)\n",
           lsect->name, (long) relocation, (long) relocation);
           lsect->name, (long) relocation, (long) relocation);
#endif
#endif
 
 
  /* Subtract out the addend, because it will get added back in by the normal
  return relocation;
     processing.  */
}
  return relocation - linker_section_ptr->addend;
 
 
#define PPC_LO(v) ((v) & 0xffff)
 
#define PPC_HI(v) (((v) >> 16) & 0xffff)
 
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 
 
static void
 
write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
 
                  struct bfd_link_info *info)
 
{
 
  struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
 
  bfd *output_bfd = info->output_bfd;
 
  bfd_vma plt;
 
 
 
  plt = ((ent->plt.offset & ~1)
 
         + plt_sec->output_section->vma
 
         + plt_sec->output_offset);
 
 
 
  if (info->shared)
 
    {
 
      bfd_vma got = 0;
 
 
 
      if (ent->addend >= 32768)
 
        got = (ent->addend
 
               + ent->sec->output_section->vma
 
               + ent->sec->output_offset);
 
      else if (htab->elf.hgot != NULL)
 
        got = SYM_VAL (htab->elf.hgot);
 
 
 
      plt -= got;
 
 
 
      if (plt + 0x8000 < 0x10000)
 
        {
 
          bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
 
          p += 4;
 
          bfd_put_32 (output_bfd, MTCTR_11, p);
 
          p += 4;
 
          bfd_put_32 (output_bfd, BCTR, p);
 
          p += 4;
 
          bfd_put_32 (output_bfd, NOP, p);
 
          p += 4;
 
        }
 
      else
 
        {
 
          bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p);
 
          p += 4;
 
          bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
 
          p += 4;
 
          bfd_put_32 (output_bfd, MTCTR_11, p);
 
          p += 4;
 
          bfd_put_32 (output_bfd, BCTR, p);
 
          p += 4;
 
        }
 
    }
 
  else
 
    {
 
      bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p);
 
      p += 4;
 
      bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
 
      p += 4;
 
      bfd_put_32 (output_bfd, MTCTR_11, p);
 
      p += 4;
 
      bfd_put_32 (output_bfd, BCTR, p);
 
      p += 4;
 
    }
 
}
 
 
 
/* Return true if symbol is defined statically.  */
 
 
 
static bfd_boolean
 
is_static_defined (struct elf_link_hash_entry *h)
 
{
 
  return ((h->root.type == bfd_link_hash_defined
 
           || h->root.type == bfd_link_hash_defweak)
 
          && h->root.u.def.section != NULL
 
          && h->root.u.def.section->output_section != NULL);
 
}
 
 
 
/* If INSN is an opcode that may be used with an @tls operand, return
 
   the transformed insn for TLS optimisation, otherwise return 0.  If
 
   REG is non-zero only match an insn with RB or RA equal to REG.  */
 
 
 
unsigned int
 
_bfd_elf_ppc_at_tls_transform (unsigned int insn, unsigned int reg)
 
{
 
  unsigned int rtra;
 
 
 
  if ((insn & (0x3f << 26)) != 31 << 26)
 
    return 0;
 
 
 
  if (reg == 0 || ((insn >> 11) & 0x1f) == reg)
 
    rtra = insn & ((1 << 26) - (1 << 16));
 
  else if (((insn >> 16) & 0x1f) == reg)
 
    rtra = (insn & (0x1f << 21)) | ((insn & (0x1f << 11)) << 5);
 
  else
 
    return 0;
 
 
 
  if ((insn & (0x3ff << 1)) == 266 << 1)
 
    /* add -> addi.  */
 
    insn = 14 << 26;
 
  else if ((insn & (0x1f << 1)) == 23 << 1
 
           && ((insn & (0x1f << 6)) < 14 << 6
 
               || ((insn & (0x1f << 6)) >= 16 << 6
 
                   && (insn & (0x1f << 6)) < 24 << 6)))
 
    /* load and store indexed -> dform.  */
 
    insn = (32 | ((insn >> 6) & 0x1f)) << 26;
 
  else if ((insn & (((0x1a << 5) | 0x1f) << 1)) == 21 << 1)
 
    /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu.  */
 
    insn = ((58 | ((insn >> 6) & 4)) << 26) | ((insn >> 6) & 1);
 
  else if ((insn & (((0x1f << 5) | 0x1f) << 1)) == 341 << 1)
 
    /* lwax -> lwa.  */
 
    insn = (58 << 26) | 2;
 
  else
 
    return 0;
 
  insn |= rtra;
 
  return insn;
 
}
 
 
 
/* If INSN is an opcode that may be used with an @tprel operand, return
 
   the transformed insn for an undefined weak symbol, ie. with the
 
   thread pointer REG operand removed.  Otherwise return 0.  */
 
 
 
unsigned int
 
_bfd_elf_ppc_at_tprel_transform (unsigned int insn, unsigned int reg)
 
{
 
  if ((insn & (0x1f << 16)) == reg << 16
 
      && ((insn & (0x3f << 26)) == 14u << 26 /* addi */
 
          || (insn & (0x3f << 26)) == 15u << 26 /* addis */
 
          || (insn & (0x3f << 26)) == 32u << 26 /* lwz */
 
          || (insn & (0x3f << 26)) == 34u << 26 /* lbz */
 
          || (insn & (0x3f << 26)) == 36u << 26 /* stw */
 
          || (insn & (0x3f << 26)) == 38u << 26 /* stb */
 
          || (insn & (0x3f << 26)) == 40u << 26 /* lhz */
 
          || (insn & (0x3f << 26)) == 42u << 26 /* lha */
 
          || (insn & (0x3f << 26)) == 44u << 26 /* sth */
 
          || (insn & (0x3f << 26)) == 46u << 26 /* lmw */
 
          || (insn & (0x3f << 26)) == 47u << 26 /* stmw */
 
          || (insn & (0x3f << 26)) == 48u << 26 /* lfs */
 
          || (insn & (0x3f << 26)) == 50u << 26 /* lfd */
 
          || (insn & (0x3f << 26)) == 52u << 26 /* stfs */
 
          || (insn & (0x3f << 26)) == 54u << 26 /* stfd */
 
          || ((insn & (0x3f << 26)) == 58u << 26 /* lwa,ld,lmd */
 
              && (insn & 3) != 1)
 
          || ((insn & (0x3f << 26)) == 62u << 26 /* std, stmd */
 
              && ((insn & 3) == 0 || (insn & 3) == 3))))
 
    {
 
      insn &= ~(0x1f << 16);
 
    }
 
  else if ((insn & (0x1f << 21)) == reg << 21
 
           && ((insn & (0x3e << 26)) == 24u << 26 /* ori, oris */
 
               || (insn & (0x3e << 26)) == 26u << 26 /* xori,xoris */
 
               || (insn & (0x3e << 26)) == 28u << 26 /* andi,andis */))
 
    {
 
      insn &= ~(0x1f << 21);
 
      insn |= (insn & (0x1f << 16)) << 5;
 
      if ((insn & (0x3e << 26)) == 26 << 26 /* xori,xoris */)
 
        insn -= 2 >> 26;  /* convert to ori,oris */
 
    }
 
  else
 
    insn = 0;
 
  return insn;
}
}
 
 
/* The RELOCATE_SECTION function is called by the ELF backend linker
/* The RELOCATE_SECTION function is called by the ELF backend linker
   to handle the relocations for a section.
   to handle the relocations for a section.
 
 
Line 5786... Line 6757...
  struct elf_link_hash_entry **sym_hashes;
  struct elf_link_hash_entry **sym_hashes;
  struct ppc_elf_link_hash_table *htab;
  struct ppc_elf_link_hash_table *htab;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *rel;
  Elf_Internal_Rela *relend;
  Elf_Internal_Rela *relend;
  Elf_Internal_Rela outrel;
  Elf_Internal_Rela outrel;
  bfd_byte *loc;
 
  asection *got2, *sreloc = NULL;
  asection *got2, *sreloc = NULL;
  bfd_vma *local_got_offsets;
  bfd_vma *local_got_offsets;
  bfd_boolean ret = TRUE;
  bfd_boolean ret = TRUE;
  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
  bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0);
 
  bfd_boolean is_vxworks_tls;
 
 
#ifdef DEBUG
#ifdef DEBUG
  _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
  _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, "
                      "%ld relocations%s",
                      "%ld relocations%s",
                      input_bfd, input_section,
                      input_bfd, input_section,
Line 5810... Line 6781...
 
 
  htab = ppc_elf_hash_table (info);
  htab = ppc_elf_hash_table (info);
  local_got_offsets = elf_local_got_offsets (input_bfd);
  local_got_offsets = elf_local_got_offsets (input_bfd);
  symtab_hdr = &elf_symtab_hdr (input_bfd);
  symtab_hdr = &elf_symtab_hdr (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
  sym_hashes = elf_sym_hashes (input_bfd);
 
  /* We have to handle relocations in vxworks .tls_vars sections
 
     specially, because the dynamic loader is 'weird'.  */
 
  is_vxworks_tls = (htab->is_vxworks && info->shared
 
                    && !strcmp (input_section->output_section->name,
 
                                ".tls_vars"));
  rel = relocs;
  rel = relocs;
  relend = relocs + input_section->reloc_count;
  relend = relocs + input_section->reloc_count;
  for (; rel < relend; rel++)
  for (; rel < relend; rel++)
    {
    {
      enum elf_ppc_reloc_type r_type;
      enum elf_ppc_reloc_type r_type;
Line 5824... Line 6800...
      struct elf_link_hash_entry *h;
      struct elf_link_hash_entry *h;
      const char *sym_name;
      const char *sym_name;
      reloc_howto_type *howto;
      reloc_howto_type *howto;
      unsigned long r_symndx;
      unsigned long r_symndx;
      bfd_vma relocation;
      bfd_vma relocation;
      bfd_vma branch_bit, insn, from;
      bfd_vma branch_bit, from;
      bfd_boolean unresolved_reloc;
      bfd_boolean unresolved_reloc;
      bfd_boolean warned;
      bfd_boolean warned;
      unsigned int tls_type, tls_mask, tls_gd;
      unsigned int tls_type, tls_mask, tls_gd;
 
      struct plt_entry **ifunc;
 
 
      r_type = ELF32_R_TYPE (rel->r_info);
      r_type = ELF32_R_TYPE (rel->r_info);
      sym = NULL;
      sym = NULL;
      sec = NULL;
      sec = NULL;
      h = NULL;
      h = NULL;
Line 5888... Line 6865...
         based on information we collected in tls_optimize.  We edit
         based on information we collected in tls_optimize.  We edit
         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;
      if (IS_PPC_TLS_RELOC (r_type))
 
        {
 
          if (h != NULL)
          if (h != NULL)
            tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
            tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
          else if (local_got_offsets != NULL)
          else if (local_got_offsets != NULL)
            {
            {
 
          struct plt_entry **local_plt;
              char *lgot_masks;
              char *lgot_masks;
              lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
          local_plt
 
            = (struct plt_entry **) (local_got_offsets + symtab_hdr->sh_info);
 
          lgot_masks = (char *) (local_plt + symtab_hdr->sh_info);
              tls_mask = lgot_masks[r_symndx];
              tls_mask = lgot_masks[r_symndx];
            }
            }
        }
 
 
 
      /* Ensure reloc mapping code below stays sane.  */
      /* Ensure reloc mapping code below stays sane.  */
      if ((R_PPC_GOT_TLSLD16 & 3)    != (R_PPC_GOT_TLSGD16 & 3)
      if ((R_PPC_GOT_TLSLD16 & 3)    != (R_PPC_GOT_TLSGD16 & 3)
          || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3)
          || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3)
          || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3)
          || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3)
Line 5917... Line 6894...
        default:
        default:
          break;
          break;
 
 
        case R_PPC_GOT_TPREL16:
        case R_PPC_GOT_TPREL16:
        case R_PPC_GOT_TPREL16_LO:
        case R_PPC_GOT_TPREL16_LO:
          if (tls_mask != 0
          if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
              && (tls_mask & TLS_TPREL) == 0)
            {
            {
              bfd_vma insn;
              bfd_vma insn;
 
 
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset);
              insn &= 31 << 21;
              insn &= 31 << 21;
              insn |= 0x3c020000;       /* addis 0,2,0 */
              insn |= 0x3c020000;       /* addis 0,2,0 */
              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_PPC_TPREL16_HA;
              r_type = R_PPC_TPREL16_HA;
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
            }
            }
          break;
          break;
 
 
        case R_PPC_TLS:
        case R_PPC_TLS:
          if (tls_mask != 0
          if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
              && (tls_mask & TLS_TPREL) == 0)
            {
            {
              bfd_vma insn, rtra;
              bfd_vma insn;
 
 
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
              insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
              if ((insn & ((31 << 26) | (31 << 11)))
              insn = _bfd_elf_ppc_at_tls_transform (insn, 2);
                  == ((31 << 26) | (2 << 11)))
              if (insn == 0)
                rtra = insn & ((1 << 26) - (1 << 16));
 
              else if ((insn & ((31 << 26) | (31 << 16)))
 
                       == ((31 << 26) | (2 << 16)))
 
                rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5);
 
              else
 
                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 ();
                abort ();
              insn |= rtra;
 
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              r_type = R_PPC_TPREL16_LO;
              r_type = R_PPC_TPREL16_LO;
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
 
 
              /* Was PPC_TLS which sits on insn boundary, now
              /* Was PPC_TLS which sits on insn boundary, now
Line 5978... Line 6931...
          break;
          break;
 
 
        case R_PPC_GOT_TLSGD16_HI:
        case R_PPC_GOT_TLSGD16_HI:
        case R_PPC_GOT_TLSGD16_HA:
        case R_PPC_GOT_TLSGD16_HA:
          tls_gd = TLS_TPRELGD;
          tls_gd = TLS_TPRELGD;
          if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
            goto tls_gdld_hi;
            goto tls_gdld_hi;
          break;
          break;
 
 
        case R_PPC_GOT_TLSLD16_HI:
        case R_PPC_GOT_TLSLD16_HI:
        case R_PPC_GOT_TLSLD16_HA:
        case R_PPC_GOT_TLSLD16_HA:
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
            {
            {
            tls_gdld_hi:
            tls_gdld_hi:
              if ((tls_mask & tls_gd) != 0)
              if ((tls_mask & tls_gd) != 0)
                r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                          + R_PPC_GOT_TPREL16);
                          + R_PPC_GOT_TPREL16);
Line 6003... Line 6956...
          break;
          break;
 
 
        case R_PPC_GOT_TLSGD16:
        case R_PPC_GOT_TLSGD16:
        case R_PPC_GOT_TLSGD16_LO:
        case R_PPC_GOT_TLSGD16_LO:
          tls_gd = TLS_TPRELGD;
          tls_gd = TLS_TPRELGD;
          if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
            goto tls_ldgd_opt;
            goto tls_ldgd_opt;
          break;
          break;
 
 
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16:
        case R_PPC_GOT_TLSLD16_LO:
        case R_PPC_GOT_TLSLD16_LO:
          if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
            {
            {
              bfd_vma insn1, insn2;
              unsigned int insn1, insn2;
              bfd_vma offset;
              bfd_vma offset;
 
 
            tls_ldgd_opt:
            tls_ldgd_opt:
 
              offset = (bfd_vma) -1;
 
              /* If not using the newer R_PPC_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))
              offset = rel[1].r_offset;
              offset = rel[1].r_offset;
              insn1 = bfd_get_32 (output_bfd,
 
                                  contents + rel->r_offset - d_offset);
 
              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;
                  insn1 &= (1 << 26) - 1;
                  insn1 |= 32 << 26;    /* lwz */
                  insn1 |= 32 << 26;    /* lwz */
 
                  if (offset != (bfd_vma) -1)
 
                    {
 
                      rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
                  insn2 = 0x7c631214;   /* add 3,3,2 */
                  insn2 = 0x7c631214;   /* add 3,3,2 */
                  rel[1].r_info
                      bfd_put_32 (output_bfd, insn2, contents + offset);
                    = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE);
                    }
                  rel[1].r_addend = 0;
 
                  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
                            + R_PPC_GOT_TPREL16);
                            + R_PPC_GOT_TPREL16);
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
                }
                }
              else
              else
                {
                {
                  /* LE */
                  /* LE */
                  insn1 = 0x3c620000;   /* addis 3,2,0 */
                  insn1 = 0x3c620000;   /* addis 3,2,0 */
                  insn2 = 0x38630000;   /* addi 3,3,0 */
 
                  if (tls_gd == 0)
                  if (tls_gd == 0)
                    {
                    {
                      /* Was an LD reloc.  */
                      /* Was an LD reloc.  */
 
                      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;
 
                      if (r_symndx != 0)
 
                        rel->r_addend -= (local_syms[r_symndx].st_value
 
                                          + sec->output_offset
 
                                          + sec->output_section->vma);
                    }
                    }
                  r_type = R_PPC_TPREL16_HA;
                  r_type = R_PPC_TPREL16_HA;
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
                  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
                  rel[1].r_info = ELF32_R_INFO (r_symndx,
                  if (offset != (bfd_vma) -1)
                                                R_PPC_TPREL16_LO);
                    {
                  rel[1].r_offset += d_offset;
                      rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
 
                      rel[1].r_offset = offset + d_offset;
                  rel[1].r_addend = rel->r_addend;
                  rel[1].r_addend = rel->r_addend;
 
                      insn2 = 0x38630000;       /* addi 3,3,0 */
 
                      bfd_put_32 (output_bfd, insn2, contents + offset);
 
                    }
                }
                }
              bfd_put_32 (output_bfd, insn1,
              bfd_put_32 (output_bfd, insn1,
                          contents + rel->r_offset - d_offset);
                          contents + rel->r_offset - d_offset);
              bfd_put_32 (output_bfd, insn2, contents + offset);
 
              if (tls_gd == 0)
              if (tls_gd == 0)
                {
                {
                  /* We changed the symbol on an LD reloc.  Start over
                  /* We changed the symbol on an LD reloc.  Start over
                     in order to get h, sym, sec etc. right.  */
                     in order to get h, sym, sec etc. right.  */
                  rel--;
                  rel--;
                  continue;
                  continue;
                }
                }
            }
            }
          break;
          break;
 
 
 
        case R_PPC_TLSGD:
 
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
 
            {
 
              unsigned int insn2;
 
              bfd_vma offset = rel->r_offset;
 
 
 
              if ((tls_mask & TLS_TPRELGD) != 0)
 
                {
 
                  /* IE */
 
                  r_type = R_PPC_NONE;
 
                  insn2 = 0x7c631214;   /* add 3,3,2 */
 
                }
 
              else
 
                {
 
                  /* LE */
 
                  r_type = R_PPC_TPREL16_LO;
 
                  rel->r_offset += d_offset;
 
                  insn2 = 0x38630000;   /* addi 3,3,0 */
 
                }
 
              rel->r_info = ELF32_R_INFO (r_symndx, r_type);
 
              bfd_put_32 (output_bfd, insn2, contents + offset);
 
              /* Zap the reloc on the _tls_get_addr call too.  */
 
              BFD_ASSERT (offset == rel[1].r_offset);
 
              rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
 
            }
 
          break;
 
 
 
        case R_PPC_TLSLD:
 
          if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
 
            {
 
              unsigned int insn2;
 
 
 
              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);
 
 
 
              rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
 
              rel->r_offset += d_offset;
 
              insn2 = 0x38630000;       /* addi 3,3,0 */
 
              bfd_put_32 (output_bfd, insn2,
 
                          contents + rel->r_offset - d_offset);
 
              /* Zap the reloc on the _tls_get_addr call too.  */
 
              BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
 
              rel[1].r_info = ELF32_R_INFO (STN_UNDEF, R_PPC_NONE);
 
              rel--;
 
              continue;
 
            }
 
          break;
        }
        }
 
 
      /* Handle other relocations that tweak non-addend part of insn.  */
      /* Handle other relocations that tweak non-addend part of insn.  */
      branch_bit = 0;
      branch_bit = 0;
      switch (r_type)
      switch (r_type)
Line 6079... Line 7114...
          /* Fall thru */
          /* Fall thru */
 
 
          /* Branch not taken prediction relocations.  */
          /* Branch not taken prediction relocations.  */
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_REL14_BRNTAKEN:
        case R_PPC_REL14_BRNTAKEN:
 
          {
 
            bfd_vma insn;
 
 
          insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
          insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
          insn &= ~BRANCH_PREDICT_BIT;
          insn &= ~BRANCH_PREDICT_BIT;
          insn |= branch_bit;
          insn |= branch_bit;
 
 
          from = (rel->r_offset
          from = (rel->r_offset
Line 6094... Line 7132...
            insn ^= BRANCH_PREDICT_BIT;
            insn ^= BRANCH_PREDICT_BIT;
 
 
          bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
          bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
          break;
          break;
        }
        }
 
        }
 
 
 
      ifunc = NULL;
 
      if (!htab->is_vxworks)
 
        {
 
          struct plt_entry *ent;
 
 
 
          if (h != NULL)
 
            {
 
              if (h->type == STT_GNU_IFUNC)
 
                ifunc = &h->plt.plist;
 
            }
 
          else if (local_got_offsets != NULL
 
                   && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
 
            {
 
              struct plt_entry **local_plt;
 
 
 
              local_plt = (struct plt_entry **) (local_got_offsets
 
                                                 + symtab_hdr->sh_info);
 
              ifunc = local_plt + r_symndx;
 
            }
 
 
 
          ent = NULL;
 
          if (ifunc != NULL
 
              && (!info->shared
 
                  || is_branch_reloc (r_type)))
 
            {
 
              addend = 0;
 
              if (r_type == R_PPC_PLTREL24 && info->shared)
 
                addend = rel->r_addend;
 
              ent = find_plt_ent (ifunc, got2, addend);
 
            }
 
          if (ent != NULL)
 
            {
 
              if (h == NULL && (ent->plt.offset & 1) == 0)
 
                {
 
                  Elf_Internal_Rela rela;
 
                  bfd_byte *loc;
 
 
 
                  rela.r_offset = (htab->iplt->output_section->vma
 
                                   + htab->iplt->output_offset
 
                                   + ent->plt.offset);
 
                  rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
 
                  rela.r_addend = relocation;
 
                  loc = htab->reliplt->contents;
 
                  loc += (htab->reliplt->reloc_count++
 
                          * sizeof (Elf32_External_Rela));
 
                  bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
 
 
                  ent->plt.offset |= 1;
 
                }
 
              if (h == NULL && (ent->glink_offset & 1) == 0)
 
                {
 
                  unsigned char *p = ((unsigned char *) htab->glink->contents
 
                                      + ent->glink_offset);
 
                  write_glink_stub (ent, htab->iplt, p, info);
 
                  ent->glink_offset |= 1;
 
                }
 
 
 
              unresolved_reloc = FALSE;
 
              if (htab->plt_type == PLT_NEW
 
                  || !htab->elf.dynamic_sections_created
 
                  || h == NULL)
 
                relocation = (htab->glink->output_section->vma
 
                              + htab->glink->output_offset
 
                              + (ent->glink_offset & ~1));
 
              else
 
                relocation = (htab->plt->output_section->vma
 
                              + htab->plt->output_offset
 
                              + ent->plt.offset);
 
            }
 
        }
 
 
      addend = rel->r_addend;
      addend = rel->r_addend;
      tls_type = 0;
      tls_type = 0;
      howto = NULL;
      howto = NULL;
      if (r_type < R_PPC_max)
      if (r_type < R_PPC_max)
Line 6113... Line 7223...
          ret = FALSE;
          ret = FALSE;
          continue;
          continue;
 
 
        case R_PPC_NONE:
        case R_PPC_NONE:
        case R_PPC_TLS:
        case R_PPC_TLS:
 
        case R_PPC_TLSGD:
 
        case R_PPC_TLSLD:
        case R_PPC_EMB_MRKREF:
        case R_PPC_EMB_MRKREF:
        case R_PPC_GNU_VTINHERIT:
        case R_PPC_GNU_VTINHERIT:
        case R_PPC_GNU_VTENTRY:
        case R_PPC_GNU_VTENTRY:
          continue;
          continue;
 
 
Line 6154... Line 7266...
 
 
        case R_PPC_GOT16:
        case R_PPC_GOT16:
        case R_PPC_GOT16_LO:
        case R_PPC_GOT16_LO:
        case R_PPC_GOT16_HI:
        case R_PPC_GOT16_HI:
        case R_PPC_GOT16_HA:
        case R_PPC_GOT16_HA:
 
          tls_mask = 0;
        dogot:
        dogot:
          {
          {
            /* Relocation is to the entry for this symbol in the global
            /* Relocation is to the entry for this symbol in the global
               offset table.  */
               offset table.  */
            bfd_vma off;
            bfd_vma off;
Line 6243... Line 7356...
                        tls_m = 0;
                        tls_m = 0;
                      }
                      }
 
 
                    /* Generate relocs for the dynamic linker.  */
                    /* Generate relocs for the dynamic linker.  */
                    if ((info->shared || indx != 0)
                    if ((info->shared || indx != 0)
                        && (h == NULL
                        && (offp == &htab->tlsld_got.offset
 
                            || h == NULL
                            || 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))
                      {
                      {
 
                        asection *rsec = htab->relgot;
 
                        bfd_byte * loc;
 
 
                        outrel.r_offset = (htab->got->output_section->vma
                        outrel.r_offset = (htab->got->output_section->vma
                                           + htab->got->output_offset
                                           + htab->got->output_offset
                                           + off);
                                           + off);
                        outrel.r_addend = 0;
                        outrel.r_addend = 0;
                        if (tls_ty & (TLS_LD | TLS_GD))
                        if (tls_ty & (TLS_LD | TLS_GD))
                          {
                          {
                            outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
                            outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32);
                            if (tls_ty == (TLS_TLS | TLS_GD))
                            if (tls_ty == (TLS_TLS | TLS_GD))
                              {
                              {
                                loc = htab->relgot->contents;
                                loc = rsec->contents;
                                loc += (htab->relgot->reloc_count++
                                loc += (rsec->reloc_count++
                                        * sizeof (Elf32_External_Rela));
                                        * sizeof (Elf32_External_Rela));
                                bfd_elf32_swap_reloca_out (output_bfd,
                                bfd_elf32_swap_reloca_out (output_bfd,
                                                           &outrel, loc);
                                                           &outrel, loc);
                                outrel.r_offset += 4;
                                outrel.r_offset += 4;
                                outrel.r_info
                                outrel.r_info
Line 6270... Line 7387...
                          }
                          }
                        else if (tls_ty == (TLS_TLS | TLS_DTPREL))
                        else if (tls_ty == (TLS_TLS | TLS_DTPREL))
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32);
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32);
                        else if (tls_ty == (TLS_TLS | TLS_TPREL))
                        else if (tls_ty == (TLS_TLS | TLS_TPREL))
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32);
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32);
                        else if (indx == 0)
                        else if (indx != 0)
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE);
 
                        else
 
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
                          outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT);
                        if (indx == 0)
                        else if (ifunc != NULL)
 
                          outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
 
                        else
 
                          outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
 
                        if (indx == 0 && tls_ty != (TLS_TLS | TLS_LD))
                          {
                          {
                            outrel.r_addend += relocation;
                            outrel.r_addend += relocation;
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
                            if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL))
                              outrel.r_addend -= htab->elf.tls_sec->vma;
                              outrel.r_addend -= htab->elf.tls_sec->vma;
                          }
                          }
                        loc = htab->relgot->contents;
                        loc = rsec->contents;
                        loc += (htab->relgot->reloc_count++
                        loc += (rsec->reloc_count++
                                * sizeof (Elf32_External_Rela));
                                * sizeof (Elf32_External_Rela));
                        bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
                        bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
                      }
                      }
 
 
                    /* Init the .got section contents if we're not
                    /* Init the .got section contents if we're not
Line 6345... Line 7464...
                          }
                          }
                      }
                      }
                  }
                  }
              }
              }
 
 
            relocation = htab->got->output_offset + off;
            relocation = (htab->got->output_section->vma
            relocation -= htab->elf.hgot->root.u.def.value;
                          + htab->got->output_offset
 
                          + off
 
                          - SYM_VAL (htab->elf.hgot));
 
 
            /* Addends on got relocations don't make much sense.
            /* Addends on got relocations don't make much sense.
               x+off@got is actually x@got+off, and since the got is
               x+off@got is actually x@got+off, and since the got is
               generated by a hash table traversal, the value in the
               generated by a hash table traversal, the value in the
               got at entry m+n bears little relation to the entry m.  */
               got at entry m+n bears little relation to the entry m.  */
Line 6393... Line 7514...
             object.  */
             object.  */
        case R_PPC_TPREL16:
        case R_PPC_TPREL16:
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_LO:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HI:
        case R_PPC_TPREL16_HA:
        case R_PPC_TPREL16_HA:
 
          if (h != NULL
 
              && h->root.type == bfd_link_hash_undefweak
 
              && h->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;
 
              unsigned int insn = bfd_get_32 (output_bfd, p);
 
              insn = _bfd_elf_ppc_at_tprel_transform (insn, 2);
 
              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;
          /* 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.  */
          goto dodyn;
          goto dodyn;
Line 6438... Line 7574...
        case R_PPC_REL14:
        case R_PPC_REL14:
        case R_PPC_REL14_BRTAKEN:
        case R_PPC_REL14_BRTAKEN:
        case R_PPC_REL14_BRNTAKEN:
        case R_PPC_REL14_BRNTAKEN:
          /* If these relocations are not to a named symbol, they can be
          /* If these relocations are not to a named symbol, they can be
             handled right here, no need to bother the dynamic linker.  */
             handled right here, no need to bother the dynamic linker.  */
          if (SYMBOL_REFERENCES_LOCAL (info, h)
          if (SYMBOL_CALLS_LOCAL (info, h)
              || h == htab->elf.hgot)
              || h == htab->elf.hgot)
            break;
            break;
          /* fall through */
          /* fall through */
 
 
        case R_PPC_ADDR24:
        case R_PPC_ADDR24:
Line 6452... Line 7588...
          if (h != NULL && !info->shared)
          if (h != NULL && !info->shared)
            break;
            break;
          /* fall through */
          /* fall through */
 
 
        dodyn:
        dodyn:
          if ((input_section->flags & SEC_ALLOC) == 0)
          if ((input_section->flags & SEC_ALLOC) == 0
 
              || is_vxworks_tls)
            break;
            break;
 
 
          if ((info->shared
          if ((info->shared
               && (h == NULL
               && !(h != NULL
                   || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
                    && ((h->root.type == bfd_link_hash_undefined
                   || h->root.type != bfd_link_hash_undefweak)
                         && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
               && (MUST_BE_DYN_RELOC (r_type)
                             || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
 
                        || (h->root.type == bfd_link_hash_undefweak
 
                            && ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)))
 
               && (must_be_dyn_reloc (info, r_type)
                   || !SYMBOL_CALLS_LOCAL (info, h)))
                   || !SYMBOL_CALLS_LOCAL (info, h)))
              || (ELIMINATE_COPY_RELOCS
              || (ELIMINATE_COPY_RELOCS
                  && !info->shared
                  && !info->shared
                  && h != NULL
                  && h != NULL
                  && h->dynindx != -1
                  && h->dynindx != -1
                  && !h->non_got_ref
                  && !h->non_got_ref
                  && !h->def_regular))
                  && !h->def_regular))
            {
            {
              int skip;
              int skip;
 
              bfd_byte * loc;
#ifdef DEBUG
#ifdef DEBUG
              fprintf (stderr, "ppc_elf_relocate_section needs to "
              fprintf (stderr, "ppc_elf_relocate_section needs to "
                       "create relocation for %s\n",
                       "create relocation for %s\n",
                       (h && h->root.root.string
                       (h && h->root.root.string
                        ? h->root.root.string : "<unknown>"));
                        ? h->root.root.string : "<unknown>"));
Line 6482... Line 7622...
              /* When generating a shared object, these relocations
              /* When generating a shared 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.  */
              if (sreloc == NULL)
              if (sreloc == NULL)
                {
                {
                  const char *name;
                  sreloc = elf_section_data (input_section)->sreloc;
 
                  if (!htab->elf.dynamic_sections_created)
                  name = (bfd_elf_string_from_elf_section
                    sreloc = htab->reliplt;
                          (input_bfd,
                  if (sreloc == NULL)
                           elf_elfheader (input_bfd)->e_shstrndx,
 
                           elf_section_data (input_section)->rel_hdr.sh_name));
 
                  if (name == NULL)
 
                    return FALSE;
                    return FALSE;
 
 
                  BFD_ASSERT (CONST_STRNEQ (name, ".rela")
 
                              && strcmp (bfd_get_section_name (input_bfd,
 
                                                               input_section),
 
                                         name + 5) == 0);
 
 
 
                  sreloc = bfd_get_section_by_name (htab->elf.dynobj, name);
 
                  BFD_ASSERT (sreloc != NULL);
 
                }
                }
 
 
              skip = 0;
              skip = 0;
 
 
              outrel.r_offset =
              outrel.r_offset =
                _bfd_elf_section_offset (output_bfd, info, input_section,
                _bfd_elf_section_offset (output_bfd, info, input_section,
                                         rel->r_offset);
                                         rel->r_offset);
              if (outrel.r_offset == (bfd_vma) -1
              if (outrel.r_offset == (bfd_vma) -1
                  || outrel.r_offset == (bfd_vma) -2)
                  || outrel.r_offset == (bfd_vma) -2)
Line 6513... Line 7641...
              outrel.r_offset += (input_section->output_section->vma
              outrel.r_offset += (input_section->output_section->vma
                                  + input_section->output_offset);
                                  + input_section->output_offset);
 
 
              if (skip)
              if (skip)
                memset (&outrel, 0, sizeof outrel);
                memset (&outrel, 0, sizeof outrel);
              else if (!SYMBOL_REFERENCES_LOCAL (info, h))
              else if ((h != NULL
 
                        && (h->root.type == bfd_link_hash_undefined
 
                            || h->root.type == bfd_link_hash_undefweak))
 
                       || !SYMBOL_REFERENCES_LOCAL (info, h))
                {
                {
                  unresolved_reloc = FALSE;
                  unresolved_reloc = FALSE;
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
                  outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
                  outrel.r_addend = rel->r_addend;
                  outrel.r_addend = rel->r_addend;
                }
                }
              else
              else
                {
                {
                  outrel.r_addend = relocation + rel->r_addend;
                  outrel.r_addend = relocation + rel->r_addend;
 
 
                  if (r_type == R_PPC_ADDR32)
                  if (r_type != R_PPC_ADDR32)
                    outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
 
                  else
 
                    {
                    {
                      long indx;
                      long indx = 0;
 
 
                      if (bfd_is_abs_section (sec))
                      if (ifunc != NULL)
                        indx = 0;
                        {
 
                          /* If we get here when building a static
 
                             executable, then the libc startup function
 
                             responsible for applying indirect function
 
                             relocations is going to complain about
 
                             the reloc type.
 
                             If we get here when building a dynamic
 
                             executable, it will be because we have
 
                             a text relocation.  The dynamic loader
 
                             will set the text segment writable and
 
                             non-executable to apply text relocations.
 
                             So we'll segfault when trying to run the
 
                             indirection function to resolve the reloc.  */
 
                          (*_bfd_error_handler)
 
                            (_("%B(%A+0x%lx): relocation %s for indirect "
 
                               "function %s unsupported"),
 
                             input_bfd,
 
                             input_section,
 
                             (long) rel->r_offset,
 
                             howto->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;
                          ret = FALSE;
                        }
                        }
                      else
                      else
                        {
                        {
                          asection *osec;
                          asection *osec;
 
 
                          /* We are turning this relocation into one
                          /* We are turning this relocation into one
                             against a section symbol.  It would be
                             against a section symbol.  It would be
                             proper to subtract the symbol's value,
                             proper to subtract the symbol's value,
                             osec->vma, from the emitted reloc addend,
                             osec->vma, from the emitted reloc addend,
                             but ld.so expects buggy relocs.  */
                             but ld.so expects buggy relocs.
 
                             FIXME: Why not always use a zero index?  */
                          osec = sec->output_section;
                          osec = sec->output_section;
                          indx = elf_section_data (osec)->dynindx;
                          indx = elf_section_data (osec)->dynindx;
                          if (indx == 0)
                          if (indx == 0)
                            {
                            {
                              osec = htab->elf.text_index_section;
                              osec = htab->elf.text_index_section;
Line 6563... Line 7717...
#endif
#endif
                        }
                        }
 
 
                      outrel.r_info = ELF32_R_INFO (indx, r_type);
                      outrel.r_info = ELF32_R_INFO (indx, r_type);
                    }
                    }
 
                  else if (ifunc != NULL)
 
                    outrel.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
 
                  else
 
                    outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE);
                }
                }
 
 
              loc = sreloc->contents;
              loc = sreloc->contents;
              loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
              loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela);
              bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
              bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
Line 6585... Line 7743...
                  break;
                  break;
                }
                }
            }
            }
          break;
          break;
 
 
        case R_PPC_RELAX32PC_PLT:
        case R_PPC_RELAX_PLT:
        case R_PPC_RELAX32_PLT:
        case R_PPC_RELAX_PLTREL24:
 
          if (h != NULL)
          {
          {
            struct plt_entry *ent = find_plt_ent (h, got2, addend);
              struct plt_entry *ent;
 
              bfd_vma got2_addend = 0;
 
 
 
              if (r_type == R_PPC_RELAX_PLTREL24)
 
                {
 
                  if (info->shared)
 
                    got2_addend = addend;
 
                  addend = 0;
 
                }
 
              ent = find_plt_ent (&h->plt.plist, got2, got2_addend);
            if (htab->plt_type == PLT_NEW)
            if (htab->plt_type == PLT_NEW)
              relocation = (htab->glink->output_section->vma
              relocation = (htab->glink->output_section->vma
                            + htab->glink->output_offset
                            + htab->glink->output_offset
                            + ent->glink_offset);
                            + ent->glink_offset);
            else
            else
              relocation = (htab->plt->output_section->vma
              relocation = (htab->plt->output_section->vma
                            + htab->plt->output_offset
                            + htab->plt->output_offset
                            + ent->plt.offset);
                            + ent->plt.offset);
            addend = 0;
 
          }
          }
          if (r_type == R_PPC_RELAX32_PLT)
 
            goto relax32;
 
          /* Fall thru */
          /* Fall thru */
 
 
        case R_PPC_RELAX32PC:
        case R_PPC_RELAX:
 
          if (info->shared)
          relocation -= (input_section->output_section->vma
          relocation -= (input_section->output_section->vma
                         + input_section->output_offset
                         + input_section->output_offset
                         + rel->r_offset - 4);
                         + rel->r_offset - 4);
          /* Fall thru */
 
 
 
        case R_PPC_RELAX32:
 
        relax32:
 
          {
          {
            unsigned long t0;
            unsigned long t0;
            unsigned long t1;
            unsigned long t1;
 
 
            t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
            t0 = bfd_get_32 (output_bfd, contents + rel->r_offset);
Line 6631... Line 7793...
            t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
            t0 |= ((relocation + 0x8000) >> 16) & 0xffff;
            t1 |= relocation & 0xffff;
            t1 |= relocation & 0xffff;
 
 
            bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
            bfd_put_32 (output_bfd, t0, contents + rel->r_offset);
            bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
            bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4);
 
 
 
            /* Rewrite the reloc and convert one of the trailing nop
 
               relocs to describe this relocation.  */
 
            BFD_ASSERT (ELF32_R_TYPE (relend[-1].r_info) == R_PPC_NONE);
 
            /* The relocs are at the bottom 2 bytes */
 
            rel[0].r_offset += 2;
 
            memmove (rel + 1, rel, (relend - rel - 1) * sizeof (*rel));
 
            rel[0].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_HA);
 
            rel[1].r_offset += 4;
 
            rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_ADDR16_LO);
 
            rel++;
          }
          }
          continue;
          continue;
 
 
          /* Indirect .sdata relocation.  */
          /* Indirect .sdata relocation.  */
        case R_PPC_EMB_SDAI16:
        case R_PPC_EMB_SDAI16:
          BFD_ASSERT (htab->sdata[0].section != NULL);
          BFD_ASSERT (htab->sdata[0].section != NULL);
 
          if (!is_static_defined (htab->sdata[0].sym))
 
            {
 
              unresolved_reloc = TRUE;
 
              break;
 
            }
          relocation
          relocation
            = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0],
            = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0],
                                                 h, relocation, rel);
                                                 h, relocation, rel);
 
          addend = 0;
          break;
          break;
 
 
          /* Indirect .sdata2 relocation.  */
          /* Indirect .sdata2 relocation.  */
        case R_PPC_EMB_SDA2I16:
        case R_PPC_EMB_SDA2I16:
          BFD_ASSERT (htab->sdata[1].section != NULL);
          BFD_ASSERT (htab->sdata[1].section != NULL);
 
          if (!is_static_defined (htab->sdata[1].sym))
 
            {
 
              unresolved_reloc = TRUE;
 
              break;
 
            }
          relocation
          relocation
            = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1],
            = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1],
                                                 h, relocation, rel);
                                                 h, relocation, rel);
 
          addend = 0;
          break;
          break;
 
 
          /* Handle the TOC16 reloc.  We want to use the offset within the .got
          /* Handle the TOC16 reloc.  We want to use the offset within the .got
             section, not the actual VMA.  This is appropriate when generating
             section, not the actual VMA.  This is appropriate when generating
             an embedded ELF object, for which the .got section acts like the
             an embedded ELF object, for which the .got section acts like the
             AIX .toc section.  */
             AIX .toc section.  */
        case R_PPC_TOC16:                       /* phony GOT16 relocations */
        case R_PPC_TOC16:                       /* phony GOT16 relocations */
          BFD_ASSERT (sec != NULL);
          if (sec == NULL || sec->output_section == NULL)
          BFD_ASSERT (bfd_is_und_section (sec)
            {
                      || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
              unresolved_reloc = TRUE;
 
              break;
 
            }
 
          BFD_ASSERT (strcmp (bfd_get_section_name (abfd, sec), ".got") == 0
                      || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0);
                      || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0);
 
 
            addend -= sec->output_section->vma + sec->output_offset + 0x8000;
            addend -= sec->output_section->vma + sec->output_offset + 0x8000;
          break;
          break;
 
 
        case R_PPC_PLTREL24:
        case R_PPC_PLTREL24:
 
          if (h == NULL || ifunc != NULL)
 
            break;
          /* Relocation is to the entry for this symbol in the
          /* Relocation is to the entry for this symbol in the
             procedure linkage table.  */
             procedure linkage table.  */
          {
          {
            struct plt_entry *ent = find_plt_ent (h, got2, addend);
            struct plt_entry *ent = find_plt_ent (&h->plt.plist, got2,
 
                                                  info->shared ? addend : 0);
            addend = 0;
            addend = 0;
            if (ent == NULL
            if (ent == NULL
                || htab->plt == NULL)
                || htab->plt == NULL)
              {
              {
                /* We didn't make a PLT entry for this symbol.  This
                /* We didn't make a PLT entry for this symbol.  This
Line 6695... Line 7885...
 
 
          /* Relocate against _SDA_BASE_.  */
          /* Relocate against _SDA_BASE_.  */
        case R_PPC_SDAREL16:
        case R_PPC_SDAREL16:
          {
          {
            const char *name;
            const char *name;
            struct elf_link_hash_entry *sh;
            struct elf_link_hash_entry *sda = htab->sdata[0].sym;
 
 
 
            if (sec == NULL
 
                || sec->output_section == NULL
 
                || !is_static_defined (sda))
 
              {
 
                unresolved_reloc = TRUE;
 
                break;
 
              }
 
            addend -= SYM_VAL (sda);
 
 
            BFD_ASSERT (sec != NULL);
 
            name = bfd_get_section_name (abfd, sec->output_section);
            name = bfd_get_section_name (abfd, sec->output_section);
            if (! ((CONST_STRNEQ (name, ".sdata")
            if (! ((CONST_STRNEQ (name, ".sdata")
                    && (name[6] == 0 || name[6] == '.'))
                    && (name[6] == 0 || name[6] == '.'))
                   || (CONST_STRNEQ (name, ".sbss")
                   || (CONST_STRNEQ (name, ".sbss")
                       && (name[5] == 0 || name[5] == '.'))))
                       && (name[5] == 0 || name[5] == '.'))))
Line 6712... Line 7910...
                   input_bfd,
                   input_bfd,
                   sym_name,
                   sym_name,
                   howto->name,
                   howto->name,
                   name);
                   name);
              }
              }
            sh = htab->sdata[0].sym;
 
            addend -= (sh->root.u.def.value
 
                       + sh->root.u.def.section->output_offset
 
                       + sh->root.u.def.section->output_section->vma);
 
          }
          }
          break;
          break;
 
 
          /* Relocate against _SDA2_BASE_.  */
          /* Relocate against _SDA2_BASE_.  */
        case R_PPC_EMB_SDA2REL:
        case R_PPC_EMB_SDA2REL:
          {
          {
            const char *name;
            const char *name;
            struct elf_link_hash_entry *sh;
            struct elf_link_hash_entry *sda = htab->sdata[1].sym;
 
 
 
            if (sec == NULL
 
                || sec->output_section == NULL
 
                || !is_static_defined (sda))
 
              {
 
                unresolved_reloc = TRUE;
 
                break;
 
              }
 
            addend -= SYM_VAL (sda);
 
 
            BFD_ASSERT (sec != NULL);
 
            name = bfd_get_section_name (abfd, sec->output_section);
            name = bfd_get_section_name (abfd, sec->output_section);
            if (! (CONST_STRNEQ (name, ".sdata2")
            if (! (CONST_STRNEQ (name, ".sdata2")
                   || CONST_STRNEQ (name, ".sbss2")))
                   || CONST_STRNEQ (name, ".sbss2")))
              {
              {
                (*_bfd_error_handler)
                (*_bfd_error_handler)
Line 6737... Line 7939...
                     "in the wrong output section (%s)"),
                     "in the wrong output section (%s)"),
                   input_bfd,
                   input_bfd,
                   sym_name,
                   sym_name,
                   howto->name,
                   howto->name,
                   name);
                   name);
 
 
                bfd_set_error (bfd_error_bad_value);
 
                ret = FALSE;
 
                continue;
 
              }
              }
            sh = htab->sdata[1].sym;
 
            addend -= (sh->root.u.def.value
 
                       + sh->root.u.def.section->output_offset
 
                       + sh->root.u.def.section->output_section->vma);
 
          }
          }
          break;
          break;
 
 
          /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
          /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0.  */
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_RELSDA:
        case R_PPC_EMB_RELSDA:
          {
          {
            const char *name;
            const char *name;
            int reg;
            int reg;
            struct elf_link_hash_entry *sh;
            struct elf_link_hash_entry *sda = NULL;
 
 
 
            if (sec == NULL || sec->output_section == NULL)
 
              {
 
                unresolved_reloc = TRUE;
 
                break;
 
              }
 
 
            BFD_ASSERT (sec != NULL);
 
            name = bfd_get_section_name (abfd, sec->output_section);
            name = bfd_get_section_name (abfd, sec->output_section);
            if (((CONST_STRNEQ (name, ".sdata")
            if (((CONST_STRNEQ (name, ".sdata")
                  && (name[6] == 0 || name[6] == '.'))
                  && (name[6] == 0 || name[6] == '.'))
                 || (CONST_STRNEQ (name, ".sbss")
                 || (CONST_STRNEQ (name, ".sbss")
                     && (name[5] == 0 || name[5] == '.'))))
                     && (name[5] == 0 || name[5] == '.'))))
              {
              {
                reg = 13;
                reg = 13;
                sh = htab->sdata[0].sym;
                sda = htab->sdata[0].sym;
                addend -= (sh->root.u.def.value
 
                           + sh->root.u.def.section->output_offset
 
                           + sh->root.u.def.section->output_section->vma);
 
              }
              }
 
 
            else if (CONST_STRNEQ (name, ".sdata2")
            else if (CONST_STRNEQ (name, ".sdata2")
                     || CONST_STRNEQ (name, ".sbss2"))
                     || CONST_STRNEQ (name, ".sbss2"))
              {
              {
                reg = 2;
                reg = 2;
                sh = htab->sdata[1].sym;
                sda = htab->sdata[1].sym;
                addend -= (sh->root.u.def.value
 
                           + sh->root.u.def.section->output_offset
 
                           + sh->root.u.def.section->output_section->vma);
 
              }
              }
 
 
            else if (strcmp (name, ".PPC.EMB.sdata0") == 0
            else if (strcmp (name, ".PPC.EMB.sdata0") == 0
                     || strcmp (name, ".PPC.EMB.sbss0") == 0)
                     || strcmp (name, ".PPC.EMB.sbss0") == 0)
              {
              {
                reg = 0;
                reg = 0;
              }
              }
 
 
            else
            else
              {
              {
                (*_bfd_error_handler)
                (*_bfd_error_handler)
                  (_("%B: the target (%s) of a %s relocation is "
                  (_("%B: the target (%s) of a %s relocation is "
                     "in the wrong output section (%s)"),
                     "in the wrong output section (%s)"),
Line 6802... Line 7992...
                bfd_set_error (bfd_error_bad_value);
                bfd_set_error (bfd_error_bad_value);
                ret = FALSE;
                ret = FALSE;
                continue;
                continue;
              }
              }
 
 
 
            if (sda != NULL)
 
              {
 
                if (!is_static_defined (sda))
 
                  {
 
                    unresolved_reloc = TRUE;
 
                    break;
 
                  }
 
                addend -= SYM_VAL (sda);
 
              }
 
 
            if (r_type == R_PPC_EMB_SDA21)
            if (r_type == R_PPC_EMB_SDA21)
              {                 /* fill in register field */
              {
 
                bfd_vma insn;  /* Fill in register field.  */
 
 
                insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
                insn = bfd_get_32 (output_bfd, contents + rel->r_offset);
                insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
                insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT);
                bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
                bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
              }
              }
          }
          }
Line 6816... Line 8018...
          /* Relocate against the beginning of the section.  */
          /* Relocate against the beginning of the section.  */
        case R_PPC_SECTOFF:
        case R_PPC_SECTOFF:
        case R_PPC_SECTOFF_LO:
        case R_PPC_SECTOFF_LO:
        case R_PPC_SECTOFF_HI:
        case R_PPC_SECTOFF_HI:
        case R_PPC_SECTOFF_HA:
        case R_PPC_SECTOFF_HA:
          BFD_ASSERT (sec != NULL);
          if (sec == NULL || sec->output_section == NULL)
 
            {
 
              unresolved_reloc = TRUE;
 
              break;
 
            }
          addend -= sec->output_section->vma;
          addend -= sec->output_section->vma;
          break;
          break;
 
 
          /* Negative relocations.  */
          /* Negative relocations.  */
        case R_PPC_EMB_NADDR32:
        case R_PPC_EMB_NADDR32:
Line 6833... Line 8039...
 
 
        case R_PPC_COPY:
        case R_PPC_COPY:
        case R_PPC_GLOB_DAT:
        case R_PPC_GLOB_DAT:
        case R_PPC_JMP_SLOT:
        case R_PPC_JMP_SLOT:
        case R_PPC_RELATIVE:
        case R_PPC_RELATIVE:
 
        case R_PPC_IRELATIVE:
        case R_PPC_PLT32:
        case R_PPC_PLT32:
        case R_PPC_PLTREL32:
        case R_PPC_PLTREL32:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HA:
        case R_PPC_PLT16_HA:
Line 6968... Line 8175...
#endif
#endif
 
 
  return ret;
  return ret;
}
}


#define PPC_LO(v) ((v) & 0xffff)
 
#define PPC_HI(v) (((v) >> 16) & 0xffff)
 
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 
 
/* 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.  */
 
 
static bfd_boolean
static bfd_boolean
ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
Line 7003... Line 8206...
          {
          {
            Elf_Internal_Rela rela;
            Elf_Internal_Rela rela;
            bfd_byte *loc;
            bfd_byte *loc;
            bfd_vma reloc_index;
            bfd_vma reloc_index;
 
 
            if (htab->plt_type == PLT_NEW)
            if (htab->plt_type == PLT_NEW
 
                || !htab->elf.dynamic_sections_created
 
                || h->dynindx == -1)
              reloc_index = ent->plt.offset / 4;
              reloc_index = ent->plt.offset / 4;
            else
            else
              {
              {
                reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size)
                reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size)
                               / htab->plt_slot_size);
                               / htab->plt_slot_size);
Line 7016... Line 8221...
                  reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
                  reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
              }
              }
 
 
            /* This symbol has an entry in the procedure linkage table.
            /* This symbol has an entry in the procedure linkage table.
               Set it up.  */
               Set it up.  */
            if (htab->plt_type == PLT_VXWORKS)
            if (htab->plt_type == PLT_VXWORKS
 
                && htab->elf.dynamic_sections_created
 
                && h->dynindx != -1)
              {
              {
                bfd_vma got_offset;
                bfd_vma got_offset;
                const bfd_vma *plt_entry;
                const bfd_vma *plt_entry;
 
 
                /* The first three entries in .got.plt are reserved.  */
                /* The first three entries in .got.plt are reserved.  */
Line 7031... Line 8238...
                            : ppc_elf_vxworks_plt_entry;
                            : ppc_elf_vxworks_plt_entry;
 
 
                /* Fill in the .plt on VxWorks.  */
                /* Fill in the .plt on VxWorks.  */
                if (info->shared)
                if (info->shared)
                  {
                  {
                    bfd_vma got_offset_hi = (got_offset >> 16)
 
                                            + ((got_offset & 0x8000) >> 15);
 
 
 
                    bfd_put_32 (output_bfd,
                    bfd_put_32 (output_bfd,
                                plt_entry[0] | (got_offset_hi & 0xffff),
                                plt_entry[0] | PPC_HA (got_offset),
                                htab->plt->contents + ent->plt.offset + 0);
                                htab->plt->contents + ent->plt.offset + 0);
                    bfd_put_32 (output_bfd,
                    bfd_put_32 (output_bfd,
                                plt_entry[1] | (got_offset & 0xffff),
                                plt_entry[1] | PPC_LO (got_offset),
                                htab->plt->contents + ent->plt.offset + 4);
                                htab->plt->contents + ent->plt.offset + 4);
                  }
                  }
                else
                else
                  {
                  {
                    bfd_vma got_loc
                    bfd_vma got_loc = got_offset + SYM_VAL (htab->elf.hgot);
                      = (got_offset
 
                         + htab->elf.hgot->root.u.def.value
 
                         + htab->elf.hgot->root.u.def.section->output_offset
 
                         + htab->elf.hgot->root.u.def.section->output_section->vma);
 
                    bfd_vma got_loc_hi = (got_loc >> 16)
 
                                         + ((got_loc & 0x8000) >> 15);
 
 
 
                    bfd_put_32 (output_bfd,
                    bfd_put_32 (output_bfd,
                                plt_entry[0] | (got_loc_hi & 0xffff),
                                plt_entry[0] | PPC_HA (got_loc),
                                htab->plt->contents + ent->plt.offset + 0);
                                htab->plt->contents + ent->plt.offset + 0);
                    bfd_put_32 (output_bfd,
                    bfd_put_32 (output_bfd,
                                plt_entry[1] | (got_loc & 0xffff),
                                plt_entry[1] | PPC_LO (got_loc),
                                htab->plt->contents + ent->plt.offset + 4);
                                htab->plt->contents + ent->plt.offset + 4);
                  }
                  }
 
 
                bfd_put_32 (output_bfd, plt_entry[2],
                bfd_put_32 (output_bfd, plt_entry[2],
                            htab->plt->contents + ent->plt.offset + 8);
                            htab->plt->contents + ent->plt.offset + 8);
Line 7147... Line 8345...
                                 + got_offset);
                                 + got_offset);
 
 
              }
              }
            else
            else
              {
              {
                rela.r_offset = (htab->plt->output_section->vma
                asection *splt = htab->plt;
                                 + htab->plt->output_offset
                if (!htab->elf.dynamic_sections_created
 
                    || h->dynindx == -1)
 
                  splt = htab->iplt;
 
 
 
                rela.r_offset = (splt->output_section->vma
 
                                 + splt->output_offset
                                 + ent->plt.offset);
                                 + ent->plt.offset);
                if (htab->plt_type == PLT_OLD)
                if (htab->plt_type == PLT_OLD
 
                    || !htab->elf.dynamic_sections_created
 
                    || h->dynindx == -1)
                  {
                  {
                    /* We don't need to fill in the .plt.  The ppc dynamic
                    /* We don't need to fill in the .plt.  The ppc dynamic
                       linker will fill it in.  */
                       linker will fill it in.  */
                  }
                  }
                else
                else
                  {
                  {
                    bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
                    bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
                                   + htab->glink->output_section->vma
                                   + htab->glink->output_section->vma
                                   + htab->glink->output_offset);
                                   + htab->glink->output_offset);
                    bfd_put_32 (output_bfd, val,
                    bfd_put_32 (output_bfd, val,
                                htab->plt->contents + ent->plt.offset);
                                splt->contents + ent->plt.offset);
                  }
                  }
              }
              }
 
 
            /* Fill in the entry in the .rela.plt section.  */
            /* Fill in the entry in the .rela.plt section.  */
            rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
 
            rela.r_addend = 0;
            rela.r_addend = 0;
 
            if (!htab->elf.dynamic_sections_created
 
                || h->dynindx == -1)
 
              {
 
                BFD_ASSERT (h->type == STT_GNU_IFUNC
 
                            && h->def_regular
 
                            && (h->root.type == bfd_link_hash_defined
 
                                || h->root.type == bfd_link_hash_defweak));
 
                rela.r_info = ELF32_R_INFO (0, R_PPC_IRELATIVE);
 
                rela.r_addend = SYM_VAL (h);
 
              }
 
            else
 
              rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
 
 
 
            if (!htab->elf.dynamic_sections_created
 
                || h->dynindx == -1)
 
              loc = (htab->reliplt->contents
 
                     + (htab->reliplt->reloc_count++
 
                        * sizeof (Elf32_External_Rela)));
 
            else
            loc = (htab->relplt->contents
            loc = (htab->relplt->contents
                   + reloc_index * sizeof (Elf32_External_Rela));
                   + reloc_index * sizeof (Elf32_External_Rela));
            bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
            bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
 
 
            if (!h->def_regular)
            if (!h->def_regular)
Line 7193... Line 8415...
                       that is better than breaking tests for a NULL
                       that is better than breaking tests for a NULL
                       function pointer.  */
                       function pointer.  */
                    sym->st_value = 0;
                    sym->st_value = 0;
                  }
                  }
              }
              }
 
            else if (h->type == STT_GNU_IFUNC
 
                     && !info->shared)
 
              {
 
                /* Set the value of ifunc symbols in a non-pie
 
                   executable to the glink entry.  This is to avoid
 
                   text relocations.  We can't do this for ifunc in
 
                   allocate_dynrelocs, as we do for normal dynamic
 
                   function symbols with plt entries, because we need
 
                   to keep the original value around for the ifunc
 
                   relocation.  */
 
                sym->st_shndx = (_bfd_elf_section_from_bfd_section
 
                                 (output_bfd, htab->glink->output_section));
 
                sym->st_value = (ent->glink_offset +
 
                                 htab->glink->output_offset
 
                                 + htab->glink->output_section->vma);
 
              }
            doneone = TRUE;
            doneone = TRUE;
          }
          }
 
 
        if (htab->plt_type == PLT_NEW)
        if (htab->plt_type == PLT_NEW
 
            || !htab->elf.dynamic_sections_created
 
            || h->dynindx == -1)
          {
          {
            bfd_vma plt;
 
            unsigned char *p;
            unsigned char *p;
 
            asection *splt = htab->plt;
 
            if (!htab->elf.dynamic_sections_created
 
                || h->dynindx == -1)
 
              splt = htab->iplt;
 
 
            plt = (ent->plt.offset
 
                   + htab->plt->output_section->vma
 
                   + htab->plt->output_offset);
 
            p = (unsigned char *) htab->glink->contents + ent->glink_offset;
            p = (unsigned char *) htab->glink->contents + ent->glink_offset;
 
 
            if (info->shared || info->pie)
            if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt)
              {
              {
                bfd_vma got = 0;
                bfd_put_32 (output_bfd, LWZ_11_3, p);
 
 
                if (ent->addend >= 32768)
 
                  got = (ent->addend
 
                         + ent->sec->output_section->vma
 
                         + ent->sec->output_offset);
 
                else if (htab->elf.hgot != NULL)
 
                  got = (htab->elf.hgot->root.u.def.value
 
                         + htab->elf.hgot->root.u.def.section->output_section->vma
 
                         + htab->elf.hgot->root.u.def.section->output_offset);
 
 
 
                plt -= got;
 
 
 
                if (plt + 0x8000 < 0x10000)
 
                  {
 
                    bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p);
 
                    p += 4;
                    p += 4;
                    bfd_put_32 (output_bfd, MTCTR_11, p);
                bfd_put_32 (output_bfd, LWZ_12_3 + 4, p);
                    p += 4;
                    p += 4;
                    bfd_put_32 (output_bfd, BCTR, p);
                bfd_put_32 (output_bfd, MR_0_3, p);
                    p += 4;
                    p += 4;
                    bfd_put_32 (output_bfd, NOP, p);
                bfd_put_32 (output_bfd, CMPWI_11_0, p);
                    p += 4;
                    p += 4;
                  }
                bfd_put_32 (output_bfd, ADD_3_12_2, p);
                else
 
                  {
 
                    bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p);
 
                    p += 4;
                    p += 4;
                    bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
                bfd_put_32 (output_bfd, BEQLR, p);
                    p += 4;
                    p += 4;
                    bfd_put_32 (output_bfd, MTCTR_11, p);
                bfd_put_32 (output_bfd, MR_3_0, p);
                    p += 4;
                    p += 4;
                    bfd_put_32 (output_bfd, BCTR, p);
                bfd_put_32 (output_bfd, NOP, p);
                    p += 4;
                    p += 4;
                  }
                  }
              }
 
            else
 
              {
 
                bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p);
 
                p += 4;
 
                bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p);
 
                p += 4;
 
                bfd_put_32 (output_bfd, MTCTR_11, p);
 
                p += 4;
 
                bfd_put_32 (output_bfd, BCTR, p);
 
                p += 4;
 
 
 
 
            write_glink_stub (ent, splt, p, info);
 
 
 
            if (!info->shared)
                /* We only need one non-PIC glink stub.  */
                /* We only need one non-PIC glink stub.  */
                break;
                break;
              }
              }
          }
 
        else
        else
          break;
          break;
      }
      }
 
 
  if (h->needs_copy)
  if (h->needs_copy)
Line 7283... Line 8496...
        s = htab->relsbss;
        s = htab->relsbss;
      else
      else
        s = htab->relbss;
        s = htab->relbss;
      BFD_ASSERT (s != NULL);
      BFD_ASSERT (s != NULL);
 
 
      rela.r_offset = (h->root.u.def.value
      rela.r_offset = SYM_VAL (h);
                       + h->root.u.def.section->output_section->vma
 
                       + h->root.u.def.section->output_offset);
 
      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
      rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY);
      rela.r_addend = 0;
      rela.r_addend = 0;
      loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
      loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela);
      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
      bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
    }
    }
Line 7336... Line 8547...
  asection *sdyn;
  asection *sdyn;
  asection *splt;
  asection *splt;
  struct ppc_elf_link_hash_table *htab;
  struct ppc_elf_link_hash_table *htab;
  bfd_vma got;
  bfd_vma got;
  bfd * dynobj;
  bfd * dynobj;
 
  bfd_boolean ret = TRUE;
 
 
#ifdef DEBUG
#ifdef DEBUG
  fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
  fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
#endif
#endif
 
 
Line 7351... Line 8563...
  else
  else
    splt = NULL;
    splt = NULL;
 
 
  got = 0;
  got = 0;
  if (htab->elf.hgot != NULL)
  if (htab->elf.hgot != NULL)
    got = (htab->elf.hgot->root.u.def.value
    got = SYM_VAL (htab->elf.hgot);
           + htab->elf.hgot->root.u.def.section->output_section->vma
 
           + htab->elf.hgot->root.u.def.section->output_offset);
 
 
 
  if (htab->elf.dynamic_sections_created)
  if (htab->elf.dynamic_sections_created)
    {
    {
      Elf32_External_Dyn *dyncon, *dynconend;
      Elf32_External_Dyn *dyncon, *dynconend;
 
 
Line 7413... Line 8623...
 
 
          bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
          bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
        }
        }
    }
    }
 
 
  /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can
 
     easily find the address of the _GLOBAL_OFFSET_TABLE_.  */
 
  if (htab->got != NULL)
  if (htab->got != NULL)
    {
    {
      unsigned char *p = htab->got->contents;
      if (htab->elf.hgot->root.u.def.section == htab->got
      bfd_vma val;
          || htab->elf.hgot->root.u.def.section == htab->sgotplt)
 
        {
 
          unsigned char *p = htab->elf.hgot->root.u.def.section->contents;
 
 
      p += htab->elf.hgot->root.u.def.value;
      p += htab->elf.hgot->root.u.def.value;
      if (htab->plt_type == PLT_OLD)
      if (htab->plt_type == PLT_OLD)
        bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4);
            {
 
              /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4
 
                 so that a function can easily find the address of
 
                 _GLOBAL_OFFSET_TABLE_.  */
 
              BFD_ASSERT (htab->elf.hgot->root.u.def.value - 4
 
                          < htab->elf.hgot->root.u.def.section->size);
 
              bfd_put_32 (output_bfd, 0x4e800021, p - 4);
 
            }
 
 
      val = 0;
 
      if (sdyn != NULL)
      if (sdyn != NULL)
        val = sdyn->output_section->vma + sdyn->output_offset;
            {
 
              bfd_vma val = sdyn->output_section->vma + sdyn->output_offset;
 
              BFD_ASSERT (htab->elf.hgot->root.u.def.value
 
                          < htab->elf.hgot->root.u.def.section->size);
      bfd_put_32 (output_bfd, val, p);
      bfd_put_32 (output_bfd, val, p);
 
            }
 
        }
 
      else
 
        {
 
          (*_bfd_error_handler) (_("%s not defined in linker created %s"),
 
                                 htab->elf.hgot->root.root.string,
 
                                 (htab->sgotplt != NULL
 
                                  ? htab->sgotplt->name : htab->got->name));
 
          bfd_set_error (bfd_error_bad_value);
 
          ret = FALSE;
 
        }
 
 
      elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
      elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
    }
    }
 
 
  /* Fill in the first entry in the VxWorks procedure linkage table.  */
  /* Fill in the first entry in the VxWorks procedure linkage table.  */
Line 7442... Line 8672...
      plt_entry = info->shared ?
      plt_entry = info->shared ?
        ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry;
        ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry;
 
 
      if (!info->shared)
      if (!info->shared)
        {
        {
          bfd_vma got_value =
          bfd_vma got_value = SYM_VAL (htab->elf.hgot);
            (htab->elf.hgot->root.u.def.section->output_section->vma
 
             + htab->elf.hgot->root.u.def.section->output_offset
 
             + htab->elf.hgot->root.u.def.value);
 
          bfd_vma got_hi = (got_value >> 16) + ((got_value & 0x8000) >> 15);
 
 
 
          bfd_put_32 (output_bfd, plt_entry[0] | (got_hi & 0xffff),
          bfd_put_32 (output_bfd, plt_entry[0] | PPC_HA (got_value),
                      splt->contents +  0);
                      splt->contents +  0);
          bfd_put_32 (output_bfd, plt_entry[1] | (got_value & 0xffff),
          bfd_put_32 (output_bfd, plt_entry[1] | PPC_LO (got_value),
                      splt->contents +  4);
                      splt->contents +  4);
        }
        }
      else
      else
        {
        {
          bfd_put_32 (output_bfd, plt_entry[0], splt->contents +  0);
          bfd_put_32 (output_bfd, plt_entry[0], splt->contents +  0);
Line 7515... Line 8741...
              loc += sizeof (Elf32_External_Rela);
              loc += sizeof (Elf32_External_Rela);
            }
            }
        }
        }
    }
    }
 
 
  if (htab->glink != NULL && htab->glink->contents != NULL)
  if (htab->glink != NULL
 
      && htab->glink->contents != NULL
 
      && htab->elf.dynamic_sections_created)
    {
    {
      unsigned char *p;
      unsigned char *p;
      unsigned char *endp;
      unsigned char *endp;
      bfd_vma res0;
      bfd_vma res0;
      unsigned int i;
      unsigned int i;
Line 7532... Line 8760...
       *   lwz 11,(plt+(i-1)*4-got)@l(11)
       *   lwz 11,(plt+(i-1)*4-got)@l(11)
       *   mtctr 11
       *   mtctr 11
       *   bctr
       *   bctr
       *
       *
       * # A table of branches, one for each plt entry.
       * # A table of branches, one for each plt entry.
       * # The idea is that the plt call stub loads ctr (and r11) with these
       * # The idea is that the plt call stub loads ctr and r11 with these
       * # addresses, so (r11 - res_0) gives the plt index * 4.
       * # addresses, so (r11 - res_0) gives the plt index * 4.
       * res_0: b PLTresolve
       * res_0: b PLTresolve
       * res_1: b PLTresolve
       * res_1: b PLTresolve
       * .
       * .
       * # Some number of entries towards the end can be nops
       * # Some number of entries towards the end can be nops
Line 7578... Line 8806...
          BCTR,
          BCTR,
          NOP,
          NOP,
          NOP
          NOP
        };
        };
 
 
 
      /*
 
       * Non-PIC glink code is a little simpler.
 
       *
 
       * # ith PLT code stub.
 
       *   lis 11,(plt+(i-1)*4)@ha
 
       *   lwz 11,(plt+(i-1)*4)@l(11)
 
       *   mtctr 11
 
       *   bctr
 
       *
 
       * The branch table is the same, then comes
 
       *
 
       * PLTresolve:
 
       *    lis 12,(got+4)@ha
 
       *    addis 11,11,(-res_0)@ha
 
       *    lwz 0,(got+4)@l(12)         # got[1] address of dl_runtime_resolve
 
       *    addi 11,11,(-res_0)@l       # r11 = index * 4
 
       *    mtctr 0
 
       *    add 0,11,11
 
       *    lwz 12,(got+8)@l(12)        # got[2] contains the map address
 
       *    add 11,0,11                 # r11 = index * 12 = reloc offset.
 
       *    bctr
 
       */
      static const unsigned int plt_resolve[] =
      static const unsigned int plt_resolve[] =
        {
        {
          LIS_12,
          LIS_12,
          ADDIS_11_11,
          ADDIS_11_11,
          LWZ_0_12,
          LWZ_0_12,
Line 7625... Line 8875...
      res0 = (htab->glink_pltresolve
      res0 = (htab->glink_pltresolve
              + htab->glink->output_section->vma
              + htab->glink->output_section->vma
              + htab->glink->output_offset);
              + htab->glink->output_offset);
 
 
      /* Last comes the PLTresolve stub.  */
      /* Last comes the PLTresolve stub.  */
      if (info->shared || info->pie)
      if (info->shared)
        {
        {
          bfd_vma bcl;
          bfd_vma bcl;
 
 
          for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
          for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++)
            {
            {
Line 7693... Line 8943...
                          LWZ_12_12 + 4, p + 6*4);
                          LWZ_12_12 + 4, p + 6*4);
            }
            }
        }
        }
    }
    }
 
 
  return TRUE;
  return ret;
}
}


#define TARGET_LITTLE_SYM       bfd_elf32_powerpcle_vec
#define TARGET_LITTLE_SYM       bfd_elf32_powerpcle_vec
#define TARGET_LITTLE_NAME      "elf32-powerpcle"
#define TARGET_LITTLE_NAME      "elf32-powerpcle"
#define TARGET_BIG_SYM          bfd_elf32_powerpc_vec
#define TARGET_BIG_SYM          bfd_elf32_powerpc_vec
Line 7731... Line 8981...
#define bfd_elf32_bfd_relax_section             ppc_elf_relax_section
#define bfd_elf32_bfd_relax_section             ppc_elf_relax_section
#define bfd_elf32_bfd_reloc_type_lookup         ppc_elf_reloc_type_lookup
#define bfd_elf32_bfd_reloc_type_lookup         ppc_elf_reloc_type_lookup
#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup
#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup
#define bfd_elf32_bfd_set_private_flags         ppc_elf_set_private_flags
#define bfd_elf32_bfd_set_private_flags         ppc_elf_set_private_flags
#define bfd_elf32_bfd_link_hash_table_create    ppc_elf_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create    ppc_elf_link_hash_table_create
 
#define bfd_elf32_get_synthetic_symtab          ppc_elf_get_synthetic_symtab
 
 
#define elf_backend_object_p                    ppc_elf_object_p
#define elf_backend_object_p                    ppc_elf_object_p
#define elf_backend_gc_mark_hook                ppc_elf_gc_mark_hook
#define elf_backend_gc_mark_hook                ppc_elf_gc_mark_hook
#define elf_backend_gc_sweep_hook               ppc_elf_gc_sweep_hook
#define elf_backend_gc_sweep_hook               ppc_elf_gc_sweep_hook
#define elf_backend_section_from_shdr           ppc_elf_section_from_shdr
#define elf_backend_section_from_shdr           ppc_elf_section_from_shdr
Line 7759... Line 9010...
#define elf_backend_write_section               ppc_elf_write_section
#define elf_backend_write_section               ppc_elf_write_section
#define elf_backend_get_sec_type_attr           ppc_elf_get_sec_type_attr
#define elf_backend_get_sec_type_attr           ppc_elf_get_sec_type_attr
#define elf_backend_plt_sym_val                 ppc_elf_plt_sym_val
#define elf_backend_plt_sym_val                 ppc_elf_plt_sym_val
#define elf_backend_action_discarded            ppc_elf_action_discarded
#define elf_backend_action_discarded            ppc_elf_action_discarded
#define elf_backend_init_index_section          _bfd_elf_init_1_index_section
#define elf_backend_init_index_section          _bfd_elf_init_1_index_section
 
#define elf_backend_post_process_headers        _bfd_elf_set_osabi
 
 
#include "elf32-target.h"
#include "elf32-target.h"
 
 
/* VxWorks Target */
/* VxWorks Target */
 
 
Line 7845... Line 9097...
#undef elf_backend_plt_readonly
#undef elf_backend_plt_readonly
#define elf_backend_plt_readonly                1
#define elf_backend_plt_readonly                1
#undef elf_backend_got_header_size
#undef elf_backend_got_header_size
#define elf_backend_got_header_size             12
#define elf_backend_got_header_size             12
 
 
 
#undef bfd_elf32_get_synthetic_symtab
 
 
#undef bfd_elf32_bfd_link_hash_table_create
#undef bfd_elf32_bfd_link_hash_table_create
#define bfd_elf32_bfd_link_hash_table_create \
#define bfd_elf32_bfd_link_hash_table_create \
  ppc_elf_vxworks_link_hash_table_create
  ppc_elf_vxworks_link_hash_table_create
#undef elf_backend_add_symbol_hook
#undef elf_backend_add_symbol_hook
#define elf_backend_add_symbol_hook \
#define elf_backend_add_symbol_hook \
Line 7866... Line 9120...
#define elf_backend_emit_relocs \
#define elf_backend_emit_relocs \
  elf_vxworks_emit_relocs
  elf_vxworks_emit_relocs
 
 
#undef elf32_bed
#undef elf32_bed
#define elf32_bed                               ppc_elf_vxworks_bed
#define elf32_bed                               ppc_elf_vxworks_bed
 
#undef elf_backend_post_process_headers
 
 
#include "elf32-target.h"
#include "elf32-target.h"
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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