* elf-m10300.c (_bfd_mn10300_elf_adjust_dynamic_symbol): Warn on
[deliverable/binutils-gdb.git] / bfd / elf32-ppc.c
index c9119239c6a09a475941d05f46e07dd721708a7c..bfb1ee83905a4d52d98974222a1ac68e3b8e2400 100644 (file)
@@ -32,6 +32,7 @@
 #include "elf-bfd.h"
 #include "elf/ppc.h"
 #include "elf32-ppc.h"
+#include "elf-vxworks.h"
 
 /* RELA relocations are used here.  */
 
@@ -52,12 +53,6 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
 #define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1"
 
 /* For old-style PLT.  */
-/* The size in bytes of an entry in the procedure linkage table.  */
-#define PLT_ENTRY_SIZE 12
-/* The initial size of the plt reserved for the dynamic linker.  */
-#define PLT_INITIAL_ENTRY_SIZE 72
-/* The size of the gap between entries in the PLT.  */
-#define PLT_SLOT_SIZE 8
 /* The number of single-slot PLT entries (the rest use two slots).  */
 #define PLT_NUM_SINGLE_ENTRIES 8192
 
@@ -65,6 +60,73 @@ static bfd_reloc_status_type ppc_elf_unhandled_reloc
 #define GLINK_PLTRESOLVE 16*4
 #define GLINK_ENTRY_SIZE 4*4
 
+/* VxWorks uses its own plt layout, filled in by the static linker.  */
+
+/* The standard VxWorks PLT entry.  */
+#define VXWORKS_PLT_ENTRY_SIZE 32
+static const bfd_vma ppc_elf_vxworks_plt_entry
+    [VXWORKS_PLT_ENTRY_SIZE / 4] =
+  {
+    0x3d800000, /* lis     r12,0                 */
+    0x818c0000, /* lwz     r12,0(r12)            */
+    0x7d8903a6, /* mtctr   r12                   */
+    0x4e800420, /* bctr                          */
+    0x39600000, /* li      r11,0                 */
+    0x48000000, /* b       14 <.PLT0resolve+0x4> */
+    0x60000000, /* nop                           */
+    0x60000000, /* nop                           */
+  };
+static const bfd_vma ppc_elf_vxworks_pic_plt_entry
+    [VXWORKS_PLT_ENTRY_SIZE / 4] =
+  {
+    0x3d9e0000, /* addis r12,r30,0 */
+    0x818c0000, /* lwz  r12,0(r12) */
+    0x7d8903a6, /* mtctr r12 */
+    0x4e800420, /* bctr */
+    0x39600000, /* li   r11,0 */
+    0x48000000, /* b    14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */
+    0x60000000, /* nop */
+    0x60000000, /* nop */
+  };
+
+/* The initial VxWorks PLT entry.  */
+#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32
+static const bfd_vma ppc_elf_vxworks_plt0_entry
+    [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
+  {
+    0x3d800000, /* lis     r12,0        */
+    0x398c0000, /* addi    r12,r12,0    */
+    0x800c0008, /* lwz     r0,8(r12)    */
+    0x7c0903a6, /* mtctr   r0           */
+    0x818c0004, /* lwz     r12,4(r12)   */
+    0x4e800420, /* bctr                 */
+    0x60000000, /* nop                  */
+    0x60000000, /* nop                  */
+  };
+static const bfd_vma ppc_elf_vxworks_pic_plt0_entry
+    [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] =
+  {
+    0x819e0008, /* lwz  r12,8(r30) */
+    0x7d8903a6, /* mtctr r12        */
+    0x819e0004, /* lwz  r12,4(r30) */
+    0x4e800420, /* bctr             */
+    0x60000000, /* nop              */
+    0x60000000, /* nop              */
+    0x60000000, /* nop              */
+    0x60000000, /* nop              */
+  };
+
+/* For executables, we have some additional relocations in
+   .rela.plt.unloaded, for the kernel loader.  */
+
+/* The number of non-JMP_SLOT relocations per PLT0 slot. */
+#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3
+/* The number of relocations in the PLTResolve slot. */
+#define VXWORKS_PLTRESOLVE_RELOCS 2
+/* The number of relocations in the PLTResolve slot when when creating
+   a shared library. */
+#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0
+
 /* Some instructions.  */
 #define ADDIS_11_11    0x3d6b0000
 #define ADDIS_11_30    0x3d7e0000
@@ -1606,8 +1668,8 @@ typedef struct elf_linker_section
   const char *bss_name;
   /* Associated symbol name.  */
   const char *sym_name;
-  /* Value of symbol.  */
-  bfd_vma sym_val;
+  /* Associated symbol.  */
+  struct elf_link_hash_entry *sym;
 } elf_linker_section_t;
 
 /* Linked list of allocated pointer entries.  This hangs off of the
@@ -1828,70 +1890,44 @@ ppc_elf_additional_program_headers (bfd *abfd)
    that the linker doesn't crater when trying to make more than
    2 sections.  */
 
-static struct bfd_elf_special_section const
-  ppc_special_sections_p[] =
+static const struct bfd_elf_special_section ppc_elf_special_sections[] =
 {
   { ".plt",              4,  0, SHT_NOBITS,   SHF_ALLOC + SHF_EXECINSTR },
-  { NULL,                0,  0, 0,            0 }
-};
-
-static struct bfd_elf_special_section const
-  ppc_special_sections_s[] =
-{
-  { ".sdata",            6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
   { ".sbss",             5, -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE },
-  { ".sdata2",           7, -2, SHT_PROGBITS, SHF_ALLOC },
   { ".sbss2",            6, -2, SHT_PROGBITS, SHF_ALLOC },
-  { NULL,        0, 0, 0,            0 }
-};
-
-static struct bfd_elf_special_section const
-  ppc_special_sections_t[] =
-{
+  { ".sdata",            6, -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE },
+  { ".sdata2",           7, -2, SHT_PROGBITS, SHF_ALLOC },
   { ".tags",             5,  0, SHT_ORDERED,  SHF_ALLOC },
-  { NULL,        0, 0, 0,            0 }
-};
-
-static struct bfd_elf_special_section const
-  ppc_special_sections_other[]=
-{
   { ".PPC.EMB.apuinfo", 16,  0, SHT_NOTE,     0 },
-  { ".PPC.EMB.sdata0",  15,  0, SHT_PROGBITS, SHF_ALLOC },
   { ".PPC.EMB.sbss0",   14,  0, SHT_PROGBITS, SHF_ALLOC },
-  { NULL,        0, 0, 0,            0 }
+  { ".PPC.EMB.sdata0",  15,  0, SHT_PROGBITS, SHF_ALLOC },
+  { NULL,                0,  0, 0,            0 }
 };
 
-static struct bfd_elf_special_section const *
-  ppc_elf_special_sections[27]=
+/* This is what we want for new plt/got.  */
+static struct bfd_elf_special_section ppc_alt_plt =
+  { ".plt",              4,  0, SHT_PROGBITS, SHF_ALLOC };
+
+static const struct bfd_elf_special_section *
+ppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
-  NULL,                                /* 'a' */
-  NULL,                                /* 'b' */
-  NULL,                                /* 'c' */
-  NULL,                                /* 'd' */
-  NULL,                                /* 'e' */
-  NULL,                                /* 'f' */
-  NULL,                                /* 'g' */
-  NULL,                                /* 'h' */
-  NULL,                                /* 'i' */
-  NULL,                                /* 'j' */
-  NULL,                                /* 'k' */
-  NULL,                                /* 'l' */
-  NULL,                                /* 'm' */
-  NULL,                                /* 'n' */
-  NULL,                                /* 'o' */
-  ppc_special_sections_p,      /* 'p' */
-  NULL,                                /* 'q' */
-  NULL,                                /* 'r' */
-  ppc_special_sections_s,      /* 's' */
-  ppc_special_sections_t,      /* 's' */
-  NULL,                                /* 'u' */
-  NULL,                                /* 'v' */
-  NULL,                                /* 'w' */
-  NULL,                                /* 'x' */
-  NULL,                                /* 'y' */
-  NULL,                                /* 'z' */
-  ppc_special_sections_other,  /* other */
-};
+  const struct bfd_elf_special_section *ssect;
+
+  /* See if this is one of the special sections.  */
+  if (sec->name == NULL)
+    return NULL;
+
+  ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections,
+                                       sec->use_rela_p);
+  if (ssect != NULL)
+    {
+      if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0)
+       ssect = &ppc_alt_plt;
+      return ssect;
+    }
+
+  return _bfd_elf_get_sec_type_attr (abfd, sec);
+}
 \f
 /* Very simple linked list structure for recording apuinfo values.  */
 typedef struct apuinfo_list
@@ -2319,6 +2355,25 @@ struct ppc_elf_link_hash_table
 
   /* Small local sym to section mapping cache.  */
   struct sym_sec_cache sym_sec;
+
+  /* The (unloaded but important) .rela.plt.unloaded on VxWorks.  */
+  asection *srelplt2;
+
+  /* The .got.plt section (VxWorks only)*/
+  asection *sgotplt;
+
+  /* Short-cuts to frequently used symbols on VxWorks targets.  */
+  struct elf_link_hash_entry *hplt;
+
+  /* True if the target system is VxWorks.  */
+  int is_vxworks;
+
+  /* The size of PLT entries.  */
+  int plt_entry_size;
+  /* The distance between adjacent PLT slots.  */
+  int plt_slot_size;
+  /* The size of the first PLT entry.  */
+  int plt_initial_entry_size;
 };
 
 /* Get the PPC ELF linker hash table from a link_info structure.  */
@@ -2386,10 +2441,16 @@ ppc_elf_link_hash_table_create (bfd *abfd)
   ret->sdata[1].sym_name = "_SDA2_BASE_";
   ret->sdata[1].bss_name = ".sbss2";
 
+  ret->plt_entry_size = 12;
+  ret->plt_slot_size = 8;
+  ret->plt_initial_entry_size = 72;
+  
+  ret->is_vxworks = 0;
+
   return &ret->elf.root;
 }
 
-/* The powerpc .got has a blrl instruction in it.  Mark it executable.  */
+/* Create .got and the related sections.  */
 
 static bfd_boolean
 ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
@@ -2406,10 +2467,21 @@ ppc_elf_create_got (bfd *abfd, struct bfd_link_info *info)
   if (s == NULL)
     abort ();
 
-  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY
-          | SEC_LINKER_CREATED);
-  if (!bfd_set_section_flags (abfd, s, flags))
-    return FALSE;
+  if (htab->is_vxworks)
+    {
+      htab->sgotplt = bfd_get_section_by_name (abfd, ".got.plt");
+      if (!htab->sgotplt)
+       abort ();
+    }
+  else
+    {
+      /* The powerpc .got has a blrl instruction in it.  Mark it
+        executable.  */
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS
+              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      if (!bfd_set_section_flags (abfd, s, flags))
+       return FALSE;
+    }
 
   flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
           | SEC_LINKER_CREATED | SEC_READONLY);
@@ -2467,6 +2539,20 @@ ppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
        return FALSE;
     }
 
+  /* Create the section for VxWorks static plt relocations.  */
+  if (htab->is_vxworks && !info->shared)
+    {
+      s = bfd_make_section (abfd, ".rela.plt.unloaded");
+      flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_READONLY
+              | SEC_LINKER_CREATED);
+      if (s == NULL
+         || ! bfd_set_section_flags (abfd, s, flags)
+         || ! bfd_set_section_alignment (abfd, s,
+                 get_elf_backend_data (abfd)->s->log_file_align))
+       return FALSE;
+      htab->srelplt2 = s;
+    }
+
   htab->relplt = bfd_get_section_by_name (abfd, ".rela.plt");
   htab->plt = s = bfd_get_section_by_name (abfd, ".plt");
   if (s == NULL)
@@ -2648,6 +2734,20 @@ ppc_elf_add_symbol_hook (bfd *abfd,
   return TRUE;
 }
 \f
+static bfd_boolean
+create_sdata_sym (struct ppc_elf_link_hash_table *htab,
+                 elf_linker_section_t *lsect)
+{
+  lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name,
+                                    TRUE, FALSE, TRUE);
+  if (lsect->sym == NULL)
+    return FALSE;
+  if (lsect->sym->root.type == bfd_link_hash_new)
+    lsect->sym->non_elf = 0;
+  lsect->sym->ref_regular = 1;
+  return TRUE;
+}
+
 /* Create a special linker section.  */
 
 static bfd_boolean
@@ -2674,7 +2774,7 @@ ppc_elf_create_linker_section (bfd *abfd,
     return FALSE;
   lsect->section = s;
 
-  return TRUE;
+  return create_sdata_sym (htab, lsect);
 }
 
 /* Find a linker generated pointer with a given addend and type.  */
@@ -2909,7 +3009,12 @@ ppc_elf_check_relocs (bfd *abfd,
       if (r_symndx < symtab_hdr->sh_info)
        h = NULL;
       else
-       h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+       {
+         h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+         while (h->root.type == bfd_link_hash_indirect
+                || h->root.type == bfd_link_hash_warning)
+           h = (struct elf_link_hash_entry *) h->root.u.i.link;
+       }
 
       /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got.
         This shows up in particular in an R_PPC_ADDR32 in the eabi
@@ -2999,6 +3104,11 @@ ppc_elf_check_relocs (bfd *abfd,
          if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0],
                                                  h, rel))
            return FALSE;
+         if (h != NULL)
+           {
+             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
+             h->non_got_ref = TRUE;
+           }
          break;
 
          /* Indirect .sdata2 relocation.  */
@@ -3015,12 +3125,65 @@ ppc_elf_check_relocs (bfd *abfd,
          if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1],
                                                  h, rel))
            return FALSE;
+         if (h != NULL)
+           {
+             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
+             h->non_got_ref = TRUE;
+           }
          break;
 
        case R_PPC_SDAREL16:
+         if (info->shared)
+           {
+             bad_shared_reloc (abfd, r_type);
+             return FALSE;
+           }
+         if (htab->sdata[0].sym == NULL
+             && !create_sdata_sym (htab, &htab->sdata[0]))
+           return FALSE;
+         if (h != NULL)
+           {
+             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
+             h->non_got_ref = TRUE;
+           }
+         break;
+
        case R_PPC_EMB_SDA2REL:
+         if (info->shared)
+           {
+             bad_shared_reloc (abfd, r_type);
+             return FALSE;
+           }
+         if (htab->sdata[1].sym == NULL
+             && !create_sdata_sym (htab, &htab->sdata[1]))
+           return FALSE;
+         if (h != NULL)
+           {
+             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
+             h->non_got_ref = TRUE;
+           }
+         break;
+
        case R_PPC_EMB_SDA21:
        case R_PPC_EMB_RELSDA:
+         if (info->shared)
+           {
+             bad_shared_reloc (abfd, r_type);
+             return FALSE;
+           }
+         if (htab->sdata[0].sym == NULL
+             && !create_sdata_sym (htab, &htab->sdata[0]))
+           return FALSE;
+         if (htab->sdata[1].sym == NULL
+             && !create_sdata_sym (htab, &htab->sdata[1]))
+           return FALSE;
+         if (h != NULL)
+           {
+             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
+             h->non_got_ref = TRUE;
+           }
+         break;
+
        case R_PPC_EMB_NADDR32:
        case R_PPC_EMB_NADDR16:
        case R_PPC_EMB_NADDR16_LO:
@@ -3032,11 +3195,7 @@ ppc_elf_check_relocs (bfd *abfd,
              return FALSE;
            }
          if (h != NULL)
-           {
-             ppc_elf_hash_entry (h)->has_sda_refs = TRUE;
-             /* We may need a copy reloc.  */
-             h->non_got_ref = TRUE;
-           }
+           h->non_got_ref = TRUE;
          break;
 
        case R_PPC_PLT32:
@@ -3444,15 +3603,26 @@ ppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED,
                           int force_old_plt)
 {
   struct ppc_elf_link_hash_table *htab;
+  flagword flags;
 
   htab = ppc_elf_hash_table (info);
   if (force_old_plt || !htab->new_plt)
     htab->old_plt = 1;
 
-  if (!htab->old_plt)
+  if (htab->is_vxworks)
     {
-      flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
-                       | SEC_IN_MEMORY | SEC_LINKER_CREATED);
+      /* The VxWorks PLT is a loaded section with contents.  */
+      flags = SEC_ALLOC | SEC_CODE | SEC_IN_MEMORY | SEC_LINKER_CREATED
+             | SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY;
+
+      if (htab->plt != NULL
+         && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags))
+       return -1;
+    }
+  else if (!htab->old_plt)
+    {
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS
+              | SEC_IN_MEMORY | SEC_LINKER_CREATED);
 
       /* The new PLT is a loaded section.  */
       if (htab->plt != NULL
@@ -3626,8 +3796,12 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
        case R_PPC_ADDR14_BRNTAKEN:
        case R_PPC_UADDR32:
        case R_PPC_UADDR16:
+         if (info->shared)
+           break;
+
        case R_PPC_PLT32:
        case R_PPC_PLTREL24:
+       case R_PPC_PLTREL32:
        case R_PPC_PLT16_LO:
        case R_PPC_PLT16_HI:
        case R_PPC_PLT16_HA:
@@ -3973,6 +4147,13 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
        }
     }
 
+  if (h->size == 0)
+    {
+      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
+                            h->root.root.string);
+      return TRUE;
+    }
+
   /* We must allocate the symbol in our .dynbss section, which will
      become part of the .bss section of the executable.  There will be
      an entry for this symbol in the .dynsym section.  The dynamic
@@ -4045,7 +4226,12 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
   if (htab->old_plt)
     max_before_header = 32764;
 
-  if (need <= htab->got_gap)
+  if (htab->is_vxworks)
+    {
+      where = htab->got->size;
+      htab->got->size += need;
+    }
+  else if (need <= htab->got_gap)
     {
       where = max_before_header - htab->got_gap;
       htab->got_gap -= need;
@@ -4106,7 +4292,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
              {
                asection *s = htab->plt;
 
-               if (!htab->old_plt)
+               if (!(htab->old_plt || htab->is_vxworks))
                  {
                    if (!doneone)
                      {
@@ -4137,16 +4323,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                        /* If this is the first .plt entry, make room
                           for the special first entry.  */
                        if (s->size == 0)
-                         s->size += PLT_INITIAL_ENTRY_SIZE;
+                         s->size += htab->plt_initial_entry_size;
 
                        /* The PowerPC PLT is actually composed of two
                           parts, the first part is 2 words (for a load
                           and a jump), and then there is a remaining
                           word available at the end.  */
-                       plt_offset = (PLT_INITIAL_ENTRY_SIZE
-                                     + (PLT_SLOT_SIZE
-                                        * ((s->size - PLT_INITIAL_ENTRY_SIZE)
-                                           / PLT_ENTRY_SIZE)));
+                       plt_offset = (htab->plt_initial_entry_size
+                                     + (htab->plt_slot_size
+                                        * ((s->size
+                                            - htab->plt_initial_entry_size)
+                                           / htab->plt_entry_size)));
 
                        /* If this symbol is not defined in a regular
                           file, and we are not generating a shared
@@ -4161,12 +4348,15 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                            h->root.u.def.value = plt_offset;
                          }
 
-                       /* Make room for this entry.  After the 8192nd
-                          entry, room for two entries is allocated.  */
-                       s->size += PLT_ENTRY_SIZE;
-                       if ((s->size - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE
-                           > PLT_NUM_SINGLE_ENTRIES)
-                         s->size += PLT_ENTRY_SIZE;
+                       /* Make room for this entry.  */
+                       s->size += htab->plt_entry_size;
+                       /* After the 8192nd entry, room for two entries
+                          is allocated.  */
+                       if (!htab->is_vxworks
+                           && (s->size - htab->plt_initial_entry_size)
+                               / htab->plt_entry_size
+                              > PLT_NUM_SINGLE_ENTRIES)
+                         s->size += htab->plt_entry_size;
                      }
                    ent->plt.offset = plt_offset;
                  }
@@ -4175,6 +4365,29 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
                if (!doneone)
                  {
                    htab->relplt->size += sizeof (Elf32_External_Rela);
+
+                   if (htab->is_vxworks)
+                     {
+                       /* Allocate space for the unloaded relocations.  */
+                       if (!info->shared)
+                         {
+                           if (ent->plt.offset
+                               == (bfd_vma) htab->plt_initial_entry_size)
+                             {
+                               htab->srelplt2->size
+                                 += sizeof (Elf32_External_Rela)
+                                     * VXWORKS_PLTRESOLVE_RELOCS;
+                             }
+
+                           htab->srelplt2->size
+                             += sizeof (Elf32_External_Rela)
+                                 * VXWORKS_PLT_NON_JMP_SLOT_RELOCS;
+                         }
+
+                       /* Every PLT entry has an associated GOT entry in
+                          .got.plt.  */
+                       htab->sgotplt->size += 4;
+                     }
                    doneone = TRUE;
                  }
              }
@@ -4492,21 +4705,43 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   else
     htab->tlsld_got.offset = (bfd_vma) -1;
 
+  if (htab->is_vxworks)
+    {
+      /* Save the PLT symbol in the hash table for easy access.
+        Mark GOT and PLT syms as having relocations; they might not,
+        but we won't know for sure until we build the GOT in
+        finish_dynamic_symbol.  */
+
+      if (htab->elf.hgot)
+       htab->elf.hgot->indx = -2;
+      htab->hplt = elf_link_hash_lookup (elf_hash_table (info),
+                                        "_PROCEDURE_LINKAGE_TABLE_",
+                                        FALSE, FALSE, FALSE);
+      if (htab->hplt)
+       htab->hplt->indx = -2;
+      /* If the PLT is executable then give the symbol function type.  */
+      if (htab->hplt && htab->plt->flags & SEC_CODE)
+       htab->hplt->type = STT_FUNC;
+    }
+
   /* Allocate space for global sym dynamic relocs.  */
   elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
 
-  if (htab->got != NULL)
+  if (htab->got != NULL && !htab->is_vxworks)
     {
       unsigned int g_o_t = 32768;
 
-      /* If we haven't allocated the header, do so now.  */
+      /* If we haven't allocated the header, do so now.  When we get here,
+        for old plt/got the got size will be 0 to 32764 (not allocated),
+        or 32780 to 65536 (header allocated).  For new plt/got, the
+        corresponding ranges are 0 to 32768 and 32780 to 65536.  */
       if (htab->got->size <= 32768)
        {
          g_o_t = htab->got->size;
+         if (htab->old_plt)
+           g_o_t += 4;
          htab->got->size += htab->got_header_size;
        }
-      if (htab->old_plt)
-       g_o_t += 4;
 
       htab->elf.hgot->root.u.def.value = g_o_t;
     }
@@ -4526,14 +4761,24 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
   relocs = FALSE;
   for (s = htab->elf.dynobj->sections; s != NULL; s = s->next)
     {
+      bfd_boolean strip_section = TRUE;
+
       if ((s->flags & SEC_LINKER_CREATED) == 0)
        continue;
 
       if (s == htab->plt
          || s == htab->glink
          || s == htab->got
-         || s == htab->sbss)
+         || 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've exported dynamic symbols from them we must leave them.
+            It's too late to tell BFD to get rid of the symbols.  */
+         if ((s == htab->plt || s == htab->got) && htab->hplt != NULL)
+           strip_section = FALSE;
          /* Strip this section if we don't need it; see the
             comment below.  */
        }
@@ -4544,19 +4789,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
        }
       else if (strncmp (bfd_get_section_name (dynobj, s), ".rela", 5) == 0)
        {
-         if (s->size == 0)
-           {
-             /* If we don't need this section, strip it from the
-                output file.  This is mostly to handle .rela.bss and
-                .rela.plt.  We must create both sections in
-                create_dynamic_sections, because they must be created
-                before the linker maps input sections to output
-                sections.  The linker does that before
-                adjust_dynamic_symbol is called, and it is that
-                function which decides whether anything needs to go
-                into these sections.  */
-           }
-         else
+         if (s->size != 0)
            {
              /* Remember whether there are any relocation sections.  */
              relocs = TRUE;
@@ -4572,8 +4805,17 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
          continue;
        }
 
-      if (s->size == 0)
+      if (s->size == 0 && strip_section)
        {
+         /* If we don't need this section, strip it from the
+            output file.  This is mostly to handle .rela.bss and
+            .rela.plt.  We must create both sections in
+            create_dynamic_sections, because they must be created
+            before the linker maps input sections to output
+            sections.  The linker does that before
+            adjust_dynamic_symbol is called, and it is that
+            function which decides whether anything needs to go
+            into these sections.  */
          s->flags |= SEC_EXCLUDE;
          continue;
        }
@@ -5074,54 +5316,19 @@ ppc_elf_relax_section (bfd *abfd,
   return FALSE;
 }
 \f
-/* Set _SDA_BASE_, _SDA2_BASE, and sbss start and end syms.  They are
-   set here rather than via PROVIDE in the default linker script,
-   because using PROVIDE inside an output section statement results in
-   unnecessary output sections.  Using PROVIDE outside an output section
-   statement runs the risk of section alignment affecting where the
-   section starts.  */
+/* What to do when ld finds relocations against symbols defined in
+   discarded sections.  */
 
-bfd_boolean
-ppc_elf_set_sdata_syms (bfd *obfd, struct bfd_link_info *info)
+static unsigned int
+ppc_elf_action_discarded (asection *sec)
 {
-  struct ppc_elf_link_hash_table *htab;
-  unsigned i;
-  asection *s;
-  bfd_vma val;
-
-  htab = ppc_elf_hash_table (info);
-
-  for (i = 0; i < 2; i++)
-    {
-      elf_linker_section_t *lsect = &htab->sdata[i];
-
-      s = lsect->section;
-      if (s != NULL)
-       s = s->output_section;
-      if (s == NULL)
-       s = bfd_get_section_by_name (obfd, lsect->name);
-      if (s == NULL)
-       s = bfd_get_section_by_name (obfd, lsect->bss_name);
-
-      val = 0;
-      if (s != NULL)
-       val = s->vma + 32768;
-      lsect->sym_val = val;
+  if (strcmp (".fixup", sec->name) == 0)
+    return 0;
 
-      _bfd_elf_provide_symbol (info, lsect->sym_name, val);
-    }
+  if (strcmp (".got2", sec->name) == 0)
+    return 0;
 
-  s = bfd_get_section_by_name (obfd, ".sbss");
-  val = 0;
-  if (s != NULL)
-    val = s->vma;
-  _bfd_elf_provide_symbol (info, "__sbss_start", val);
-  _bfd_elf_provide_symbol (info, "___sbss_start", val);
-  if (s != NULL)
-    val += s->size;
-  _bfd_elf_provide_symbol (info, "__sbss_end", val);
-  _bfd_elf_provide_symbol (info, "___sbss_end", val);
-  return TRUE;
+  return _bfd_elf_default_action_discarded (sec);
 }
 \f
 /* Fill in the address for a pointer generated in a linker section.  */
@@ -6152,6 +6359,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_SDAREL16:
          {
            const char *name;
+           struct elf_link_hash_entry *sh;
 
            BFD_ASSERT (sec != NULL);
            name = bfd_get_section_name (abfd, sec->output_section);
@@ -6168,7 +6376,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                   howto->name,
                   name);
              }
-           addend -= htab->sdata[0].sym_val;
+           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;
 
@@ -6176,6 +6387,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
        case R_PPC_EMB_SDA2REL:
          {
            const char *name;
+           struct elf_link_hash_entry *sh;
 
            BFD_ASSERT (sec != NULL);
            name = bfd_get_section_name (abfd, sec->output_section);
@@ -6194,7 +6406,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
                ret = FALSE;
                continue;
              }
-           addend -= htab->sdata[1].sym_val;
+           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;
 
@@ -6204,6 +6419,7 @@ ppc_elf_relocate_section (bfd *output_bfd,
          {
            const char *name;
            int reg;
+           struct elf_link_hash_entry *sh;
 
            BFD_ASSERT (sec != NULL);
            name = bfd_get_section_name (abfd, sec->output_section);
@@ -6213,14 +6429,20 @@ ppc_elf_relocate_section (bfd *output_bfd,
                     && (name[5] == 0 || name[5] == '.'))))
              {
                reg = 13;
-               addend -= htab->sdata[0].sym_val;
+               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);
              }
 
            else if (strncmp (name, ".sdata2", 7) == 0
                     || strncmp (name, ".sbss2", 6) == 0)
              {
                reg = 2;
-               addend -= htab->sdata[1].sym_val;
+               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);
              }
 
            else if (strcmp (name, ".PPC.EMB.sdata0") == 0
@@ -6442,38 +6664,172 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
            bfd_byte *loc;
            bfd_vma reloc_index;
 
+           if (!(htab->old_plt || htab->is_vxworks))
+             reloc_index = ent->plt.offset / 4;
+           else
+             {
+               reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size)
+                              / htab->plt_slot_size);
+               if (reloc_index > PLT_NUM_SINGLE_ENTRIES
+                   && !htab->is_vxworks)
+                 reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
+             }
+
            /* This symbol has an entry in the procedure linkage table.
               Set it up.  */
-           if (htab->old_plt)
+           if (htab->is_vxworks)
              {
-               /* We don't need to fill in the .plt.  The ppc dynamic
-                  linker will fill it in.  */
+               bfd_vma got_offset;
+               const bfd_vma *plt_entry;
+               
+               /* The first three entries in .got.plt are reserved.  */
+               got_offset = (reloc_index + 3) * 4;
+
+               /* Use the right PLT. */
+               plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry
+                           : ppc_elf_vxworks_plt_entry;
+
+               /* Fill in the .plt on VxWorks.  */
+               if (info->shared)
+                 {
+                   bfd_vma got_offset_hi = (got_offset >> 16)
+                                           + ((got_offset & 0x8000) >> 15);
+
+                   bfd_put_32 (output_bfd,
+                               plt_entry[0] | (got_offset_hi & 0xffff),
+                               htab->plt->contents + ent->plt.offset + 0);
+                   bfd_put_32 (output_bfd,
+                               plt_entry[1] | (got_offset & 0xffff),
+                               htab->plt->contents + ent->plt.offset + 4);
+                 }
+               else
+                 {
+                   bfd_vma got_loc
+                     = (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,
+                               plt_entry[0] | (got_loc_hi & 0xffff),
+                               htab->plt->contents + ent->plt.offset + 0);
+                   bfd_put_32 (output_bfd,
+                               plt_entry[1] | (got_loc & 0xffff),
+                               htab->plt->contents + ent->plt.offset + 4);
+                 }
+
+               bfd_put_32 (output_bfd, plt_entry[2],
+                           htab->plt->contents + ent->plt.offset + 8);
+               bfd_put_32 (output_bfd, plt_entry[3],
+                           htab->plt->contents + ent->plt.offset + 12);
+
+               /* This instruction is an immediate load.  The value loaded is
+                  the byte offset of the R_PPC_JMP_SLOT relocation from the
+                  start of the .rela.plt section.  The value is stored in the
+                  low-order 16 bits of the load instruction.  */
+               /* NOTE: It appears that this is now an index rather than a
+                  prescaled offset.  */
+               bfd_put_32 (output_bfd, 
+                           plt_entry[4] | reloc_index,
+                           htab->plt->contents + ent->plt.offset + 16);
+               /* This instruction is a PC-relative branch whose target is
+                  the start of the PLT section.  The address of this branch
+                  instruction is 20 bytes beyond the start of this PLT entry.
+                  The address is encoded in bits 6-29, inclusive.  The value
+                  stored is right-shifted by two bits, permitting a 26-bit
+                  offset.  */
+               bfd_put_32 (output_bfd, 
+                           (plt_entry[5] 
+                            | (-(ent->plt.offset + 20) & 0x03fffffc)),
+                           htab->plt->contents + ent->plt.offset + 20);
+               bfd_put_32 (output_bfd, plt_entry[6],
+                           htab->plt->contents + ent->plt.offset + 24);
+               bfd_put_32 (output_bfd, plt_entry[7],
+                           htab->plt->contents + ent->plt.offset + 28);
+
+               /* Fill in the GOT entry corresponding to this PLT slot with
+                  the address immediately after the the "bctr" instruction
+                  in this PLT entry.  */
+               bfd_put_32 (output_bfd, (htab->plt->output_section->vma
+                                        + htab->plt->output_offset
+                                        + ent->plt.offset + 16),
+                           htab->sgotplt->contents + got_offset);
+
+               if (!info->shared)
+                 {
+                   /* Fill in a couple of entries in .rela.plt.unloaded.  */
+                   loc = htab->srelplt2->contents
+                     + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index
+                         * VXWORKS_PLT_NON_JMP_SLOT_RELOCS)
+                        * sizeof (Elf32_External_Rela));
+
+                   /* Provide the @ha relocation for the first instruction.  */
+                   rela.r_offset = (htab->plt->output_section->vma
+                                    + htab->plt->output_offset
+                                    + ent->plt.offset + 2);
+                   rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
+                                               R_PPC_ADDR16_HA);
+                   rela.r_addend = got_offset;
+                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   loc += sizeof (Elf32_External_Rela);
+
+                   /* Provide the @l relocation for the second instruction.  */
+                   rela.r_offset = (htab->plt->output_section->vma
+                                    + htab->plt->output_offset
+                                    + ent->plt.offset + 6);
+                   rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx,
+                                               R_PPC_ADDR16_LO);
+                   rela.r_addend = got_offset;
+                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                   loc += sizeof (Elf32_External_Rela);
+
+                   /* Provide a relocation for the GOT entry corresponding to this
+                      PLT slot.  Point it at the middle of the .plt entry.  */
+                   rela.r_offset = (htab->sgotplt->output_section->vma
+                                    + htab->sgotplt->output_offset
+                                    + got_offset);
+                   rela.r_info = ELF32_R_INFO (htab->hplt->indx,
+                                               R_PPC_ADDR32);
+                   rela.r_addend = ent->plt.offset + 16;
+                   bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+                 }
+
+               /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT.
+                  In particular, the offset for the relocation is not the
+                  address of the PLT entry for this function, as specified
+                  by the ABI.  Instead, the offset is set to the address of
+                  the GOT slot for this function.  See EABI 4.4.4.1.  */
+               rela.r_offset = (htab->sgotplt->output_section->vma
+                                + htab->sgotplt->output_offset
+                                + got_offset);
+
              }
            else
              {
-               bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
-                              + htab->glink->output_section->vma
-                              + htab->glink->output_offset);
-               bfd_put_32 (output_bfd, val,
-                           htab->plt->contents + ent->plt.offset);
+               rela.r_offset = (htab->plt->output_section->vma
+                                + htab->plt->output_offset
+                                + ent->plt.offset);
+               if (htab->old_plt)
+                 {
+                   /* We don't need to fill in the .plt.  The ppc dynamic
+                      linker will fill it in.  */
+                 }
+               else
+                 {
+                   bfd_vma val = (htab->glink_pltresolve + ent->plt.offset
+                                  + htab->glink->output_section->vma
+                                  + htab->glink->output_offset);
+                   bfd_put_32 (output_bfd, val,
+                               htab->plt->contents + ent->plt.offset);
+                 }
              }
 
            /* Fill in the entry in the .rela.plt section.  */
-           rela.r_offset = (htab->plt->output_section->vma
-                            + htab->plt->output_offset
-                            + ent->plt.offset);
            rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT);
            rela.r_addend = 0;
 
-           if (!htab->old_plt)
-             reloc_index = ent->plt.offset / 4;
-           else
-             {
-               reloc_index = ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE)
-                              / PLT_SLOT_SIZE);
-               if (reloc_index > PLT_NUM_SINGLE_ENTRIES)
-                 reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2;
-             }
            loc = (htab->relplt->contents
                   + reloc_index * sizeof (Elf32_External_Rela));
            bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
@@ -6594,9 +6950,11 @@ ppc_elf_finish_dynamic_symbol (bfd *output_bfd,
 #endif
 
   /* Mark some specially defined symbols as absolute.  */
-  if (h == htab->elf.hgot
-      || strcmp (h->root.root.string, "_DYNAMIC") == 0
-      || strcmp (h->root.root.string, "_PROCEDURE_LINKAGE_TABLE_") == 0)
+  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
+      || (!htab->is_vxworks
+         && (h == htab->elf.hgot
+             || strcmp (h->root.root.string,
+                        "_PROCEDURE_LINKAGE_TABLE_") == 0)))
     sym->st_shndx = SHN_ABS;
 
   return TRUE;
@@ -6627,15 +6985,22 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
                                 struct bfd_link_info *info)
 {
   asection *sdyn;
+  asection *splt;
   struct ppc_elf_link_hash_table *htab;
   bfd_vma got;
+  bfd * dynobj;
 
 #ifdef DEBUG
   fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n");
 #endif
 
   htab = ppc_elf_hash_table (info);
-  sdyn = bfd_get_section_by_name (htab->elf.dynobj, ".dynamic");
+  dynobj = elf_hash_table (info)->dynobj;
+  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
+  if (htab->is_vxworks)
+    splt = bfd_get_section_by_name (dynobj, ".plt");  
+  else
+    splt = NULL;
 
   got = 0;
   if (htab->elf.hgot != NULL)
@@ -6656,12 +7021,15 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
          Elf_Internal_Dyn dyn;
          asection *s;
 
-         bfd_elf32_swap_dyn_in (htab->elf.dynobj, dyncon, &dyn);
+         bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
 
          switch (dyn.d_tag)
            {
            case DT_PLTGOT:
-             s = htab->plt;
+             if (htab->is_vxworks)
+               s = htab->sgotplt;
+             else
+               s = htab->plt;
              dyn.d_un.d_ptr = s->output_section->vma + s->output_offset;
              break;
 
@@ -6678,6 +7046,15 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
              dyn.d_un.d_ptr = got;
              break;
 
+           case DT_RELASZ:
+             if (htab->is_vxworks)
+               {
+                 if (htab->relplt)
+                   dyn.d_un.d_ptr -= htab->relplt->size;
+                 break;
+               }
+             continue;
+
            default:
              continue;
            }
@@ -6693,8 +7070,8 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       unsigned char *p = htab->got->contents;
       bfd_vma val;
 
-      p += elf_hash_table (info)->hgot->root.u.def.value;
-      if (htab->old_plt)
+      p += htab->elf.hgot->root.u.def.value;
+      if (htab->old_plt && !htab->is_vxworks)
        bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4);
 
       val = 0;
@@ -6705,6 +7082,89 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
       elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4;
     }
 
+  /* Fill in the first entry in the VxWorks procedure linkage table.  */
+  if (splt && splt->size > 0)
+    {
+      /* Use the right PLT. */
+      static const bfd_vma *plt_entry = NULL;
+      plt_entry = info->shared ? 
+       ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry;
+
+      if (!info->shared)
+       {
+         bfd_vma got_value =
+           (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),
+                     splt->contents +  0);
+         bfd_put_32 (output_bfd, plt_entry[1] | (got_value & 0xffff),
+                     splt->contents +  4);
+       }
+      else
+       {
+         bfd_put_32 (output_bfd, plt_entry[0], splt->contents +  0);
+         bfd_put_32 (output_bfd, plt_entry[1], splt->contents +  4);
+       }
+      bfd_put_32 (output_bfd, plt_entry[2], splt->contents +  8);
+      bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12);
+      bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16);
+      bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20);
+      bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24);
+      bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28);
+
+      if (! info->shared)
+       {
+         Elf_Internal_Rela rela;
+         bfd_byte *loc;
+
+         loc = htab->srelplt2->contents;
+
+         /* Output the @ha relocation for the first instruction.  */
+         rela.r_offset = (htab->plt->output_section->vma
+                          + htab->plt->output_offset
+                          + 2);
+         rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA);
+         rela.r_addend = 0;
+         bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+         loc += sizeof (Elf32_External_Rela);
+         
+         /* Output the @l relocation for the second instruction.  */
+         rela.r_offset = (htab->plt->output_section->vma
+                          + htab->plt->output_offset
+                          + 6);
+         rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO);
+         rela.r_addend = 0;
+         bfd_elf32_swap_reloca_out (output_bfd, &rela, loc);
+         loc += sizeof (Elf32_External_Rela);
+
+         /* Fix up the remaining relocations.  They may have the wrong
+            symbol index for _G_O_T_ or _P_L_T_ depending on the order
+            in which symbols were output.  */
+         while (loc < htab->srelplt2->contents + htab->srelplt2->size)
+           {
+             Elf_Internal_Rela rel;
+
+             bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+             rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA);
+             bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+             loc += sizeof (Elf32_External_Rela);
+
+             bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+             rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO);
+             bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+             loc += sizeof (Elf32_External_Rela);
+
+             bfd_elf32_swap_reloc_in (output_bfd, loc, &rel);
+             rel.r_info = ELF32_R_INFO (htab->hplt->indx, R_PPC_ADDR32);
+             bfd_elf32_swap_reloc_out (output_bfd, &rel, loc);
+             loc += sizeof (Elf32_External_Rela);
+           }
+       }
+    }
+
   if (htab->glink != NULL && htab->glink->contents != NULL)
     {
       unsigned char *p;
@@ -6941,7 +7401,131 @@ ppc_elf_finish_dynamic_sections (bfd *output_bfd,
 #define elf_backend_begin_write_processing     ppc_elf_begin_write_processing
 #define elf_backend_final_write_processing     ppc_elf_final_write_processing
 #define elf_backend_write_section              ppc_elf_write_section
-#define elf_backend_special_sections           ppc_elf_special_sections
+#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_action_discarded           ppc_elf_action_discarded
+
+#include "elf32-target.h"
+
+/* VxWorks Target */
+
+#undef TARGET_LITTLE_SYM
+#undef TARGET_LITTLE_NAME
+
+#undef TARGET_BIG_SYM
+#define TARGET_BIG_SYM         bfd_elf32_powerpc_vxworks_vec
+#undef TARGET_BIG_NAME
+#define TARGET_BIG_NAME                "elf32-powerpc-vxworks"
+
+/* VxWorks uses the elf default section flags for .plt.  */
+static const struct bfd_elf_special_section *
+ppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+  if (sec->name == NULL)
+    return NULL;
+
+  if (strcmp (sec->name, ".plt") == 0)
+    return _bfd_elf_get_sec_type_attr (abfd, sec);
+
+  return ppc_elf_get_sec_type_attr (abfd, sec);
+}
+
+/* Like ppc_elf_link_hash_table_create, but overrides
+   appropriately for VxWorks.  */
+static struct bfd_link_hash_table *
+ppc_elf_vxworks_link_hash_table_create (bfd *abfd)
+{
+  struct bfd_link_hash_table *ret;
+
+  ret = ppc_elf_link_hash_table_create (abfd);
+  if (ret)
+    {
+      struct ppc_elf_link_hash_table *htab
+        = (struct ppc_elf_link_hash_table *)ret;
+      htab->is_vxworks = 1;
+      htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE;
+      htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE;
+      htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE;
+    }
+  return ret;
+}
+
+/* Tweak magic VxWorks symbols as they are loaded.  */
+static bfd_boolean
+ppc_elf_vxworks_add_symbol_hook (bfd *abfd,
+                                struct bfd_link_info *info,
+                                Elf_Internal_Sym *sym,
+                                const char **namep ATTRIBUTE_UNUSED,
+                                flagword *flagsp ATTRIBUTE_UNUSED,
+                                asection **secp,
+                                bfd_vma *valp)
+{
+  if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp,
+                                  valp))
+    return FALSE;
+
+  return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp);
+}
+
+/* Tweak magic VxWorks symbols as they are written to the output file.  */
+static bfd_boolean
+elf_i386_vxworks_link_output_symbol_hook (struct bfd_link_info *info
+                                          ATTRIBUTE_UNUSED,
+                                        const char *name,
+                                        Elf_Internal_Sym *sym,
+                                        asection *input_sec ATTRIBUTE_UNUSED,
+                                        struct elf_link_hash_entry *h
+                                          ATTRIBUTE_UNUSED)
+{
+  /* Ignore the first dummy symbol.  */
+  if (!name)
+    return TRUE;
+
+  return elf_vxworks_link_output_symbol_hook (name, sym);
+}
+
+static void
+ppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
+{
+  ppc_elf_final_write_processing(abfd, linker);
+  elf_vxworks_final_write_processing(abfd, linker);
+}
+
+/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so
+   define it.  */
+#undef elf_backend_want_plt_sym
+#define elf_backend_want_plt_sym               1
+#undef elf_backend_want_got_plt
+#define elf_backend_want_got_plt               1
+#undef elf_backend_got_symbol_offset
+#define elf_backend_got_symbol_offset          0
+#undef elf_backend_plt_not_loaded
+#define elf_backend_plt_not_loaded             0
+#undef elf_backend_plt_readonly
+#define elf_backend_plt_readonly               1
+#undef elf_backend_got_header_size
+#define elf_backend_got_header_size            12
+
+#undef bfd_elf32_bfd_link_hash_table_create
+#define bfd_elf32_bfd_link_hash_table_create \
+  ppc_elf_vxworks_link_hash_table_create
+#undef elf_backend_add_symbol_hook
+#define elf_backend_add_symbol_hook \
+  ppc_elf_vxworks_add_symbol_hook
+#undef elf_backend_link_output_symbol_hook
+#define elf_backend_link_output_symbol_hook \
+  elf_i386_vxworks_link_output_symbol_hook
+#undef elf_backend_final_write_processing
+#define elf_backend_final_write_processing \
+  ppc_elf_vxworks_final_write_processing
+#undef elf_backend_get_sec_type_attr
+#define elf_backend_get_sec_type_attr \
+  ppc_elf_vxworks_get_sec_type_attr
+#undef elf_backend_emit_relocs
+#define elf_backend_emit_relocs \
+  elf_vxworks_emit_relocs
+
+#undef elf32_bed
+#define elf32_bed                              ppc_elf_vxworks_bed
 
 #include "elf32-target.h"
This page took 0.039612 seconds and 4 git commands to generate.