* configure: Ignore new autoconf configure options.
[binutils-gdb.git] / bfd / sunos.c
index f5e2bc814fc1de4d622150d120194c533a944e38..25b9072c3066b0e5a75871efe3bd14eeb1ef7fd8 100644 (file)
@@ -141,10 +141,7 @@ sunos_read_dynamic_info (abfd)
   info = ((struct sunos_dynamic_info *)
          bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info)));
   if (!info)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   info->valid = false;
   info->dynsym = NULL;
   info->dynstr = NULL;
@@ -289,10 +286,7 @@ sunos_slurp_dynamic_symtab (abfd)
                                 (info->dynsym_count
                                  * EXTERNAL_NLIST_SIZE)));
       if (info->dynsym == NULL && info->dynsym_count != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       if (bfd_seek (abfd, info->dyninfo.ld_stab, SEEK_SET) != 0
          || (bfd_read ((PTR) info->dynsym, info->dynsym_count,
                        EXTERNAL_NLIST_SIZE, abfd)
@@ -312,10 +306,7 @@ sunos_slurp_dynamic_symtab (abfd)
     {
       info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size);
       if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       if (bfd_seek (abfd, info->dyninfo.ld_symbols, SEEK_SET) != 0
          || (bfd_read ((PTR) info->dynstr, 1, info->dyninfo.ld_symb_size,
                        abfd)
@@ -359,7 +350,7 @@ sunos_canonicalize_dynamic_symtab (abfd, storage)
     if (info->dyninfo.ld_buckets > info->dynsym_count)
       abort ();
     table_size = info->dyninfo.ld_stab - info->dyninfo.ld_hash;
-    table = (bfd_byte *) malloc (table_size);
+    table = (bfd_byte *) bfd_malloc (table_size);
     if (table == NULL && table_size != 0)
       abort ();
     if (bfd_seek (abfd, info->dyninfo.ld_hash, SEEK_SET) != 0
@@ -398,10 +389,7 @@ sunos_canonicalize_dynamic_symtab (abfd, storage)
                                           (info->dynsym_count
                                            * sizeof (aout_symbol_type))));
       if (info->canonical_dynsym == NULL && info->dynsym_count != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return -1;
-       }
+       return -1;
 
       if (! aout_32_translate_symbol_table (abfd, info->canonical_dynsym,
                                            info->dynsym, info->dynsym_count,
@@ -479,10 +467,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
                                      (info->dynrel_count
                                       * obj_reloc_entry_size (abfd)));
       if (info->dynrel == NULL && info->dynrel_count != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return -1;
-       }
+       return -1;
       if (bfd_seek (abfd, info->dyninfo.ld_rel, SEEK_SET) != 0
          || (bfd_read ((PTR) info->dynrel, info->dynrel_count,
                        obj_reloc_entry_size (abfd), abfd)
@@ -508,10 +493,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
                                           (info->dynrel_count
                                            * sizeof (arelent))));
       if (info->canonical_dynrel == NULL && info->dynrel_count != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return -1;
-       }
+       return -1;
       
       to = info->canonical_dynrel;
 
@@ -663,6 +645,10 @@ struct sunos_link_hash_table
 
   /* The number of buckets in the hash table.  */
   size_t bucketcount;
+
+  /* The list of dynamic objects needed by dynamic objects included in
+     the link.  */
+  struct bfd_link_needed_list *needed;
 };
 
 /* Routine to create an entry in an SunOS link hash table.  */
@@ -681,10 +667,7 @@ sunos_link_hash_newfunc (entry, table, string)
     ret = ((struct sunos_link_hash_entry *)
           bfd_hash_allocate (table, sizeof (struct sunos_link_hash_entry)));
   if (ret == (struct sunos_link_hash_entry *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return (struct bfd_hash_entry *) ret;
-    }
+    return (struct bfd_hash_entry *) ret;
 
   /* Call the allocation method of the superclass.  */
   ret = ((struct sunos_link_hash_entry *)
@@ -714,14 +697,11 @@ sunos_link_hash_table_create (abfd)
   ret = ((struct sunos_link_hash_table *)
         bfd_alloc (abfd, sizeof (struct sunos_link_hash_table)));
   if (ret == (struct sunos_link_hash_table *) NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return (struct bfd_link_hash_table *) NULL;
-    }
+    return (struct bfd_link_hash_table *) NULL;
   if (! NAME(aout,link_hash_table_init) (&ret->root, abfd,
                                         sunos_link_hash_newfunc))
     {
-      free (ret);
+      bfd_release (abfd, ret);
       return (struct bfd_link_hash_table *) NULL;
     }
 
@@ -730,6 +710,7 @@ sunos_link_hash_table_create (abfd)
   ret->dynamic_sections_needed = false;
   ret->dynsymcount = 0;
   ret->bucketcount = 0;
+  ret->needed = NULL;
 
   return &ret->root.root;
 }
@@ -870,6 +851,7 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
   asection *s;
   bfd *dynobj;
   struct sunos_dynamic_info *dinfo;
+  unsigned long need;
 
   /* We do not want to include the sections in a dynamic object in the
      output file.  We hack by simply clobbering the list of sections
@@ -943,6 +925,72 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
   *sym_countp = dinfo->dynsym_count;
   *stringsp = dinfo->dynstr;
 
+  /* Record information about any other objects needed by this one.  */
+  need = dinfo->dyninfo.ld_need;
+  while (need != 0)
+    {
+      bfd_byte buf[16];
+      unsigned long name, flags;
+      unsigned short major_vno, minor_vno;
+      struct bfd_link_needed_list *needed, **pp;
+      bfd_byte b;
+
+      if (bfd_seek (abfd, need, SEEK_SET) != 0
+         || bfd_read (buf, 1, 16, abfd) != 16)
+       return false;
+
+      /* For the format of an ld_need entry, see aout/sun4.h.  We
+         should probably define structs for this manipulation.  */
+
+      name = bfd_get_32 (abfd, buf);
+      flags = bfd_get_32 (abfd, buf + 4);
+      major_vno = bfd_get_16 (abfd, buf + 8);
+      minor_vno = bfd_get_16 (abfd, buf + 10);
+      need = bfd_get_32 (abfd, buf + 12);
+
+      needed = (struct bfd_link_needed_list *) bfd_alloc (abfd, sizeof (struct bfd_link_needed_list));
+      if (needed == NULL)
+       return false;
+      needed->by = abfd;
+
+      /* We return the name as [-l]name[.maj][.min].  */
+
+      if ((flags & 0x80000000) != 0)
+       bfd_alloc_grow (abfd, "-l", 2);
+      if (bfd_seek (abfd, name, SEEK_SET) != 0)
+       return false;
+      do
+       {
+         if (bfd_read (&b, 1, 1, abfd) != 1)
+           return false;
+         bfd_alloc_grow (abfd, &b, 1);
+       }
+      while (b != '\0');
+      if (major_vno != 0)
+       {
+         char verbuf[30];
+
+         sprintf (verbuf, ".%d", major_vno);
+         bfd_alloc_grow (abfd, verbuf, strlen (verbuf));
+         if (minor_vno != 0)
+           {
+             sprintf (verbuf, ".%d", minor_vno);
+             bfd_alloc_grow (abfd, verbuf, strlen (verbuf));
+           }
+       }
+      needed->name = bfd_alloc_finish (abfd);
+      if (needed->name == NULL)
+       return false;
+
+      needed->next = NULL;
+
+      for (pp = &sunos_hash_table (info)->needed;
+          *pp != NULL;
+          pp = &(*pp)->next)
+       ;
+      *pp = needed;
+    }
+
   return true;
 }
 
@@ -974,7 +1022,7 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
          sections will be needed.  This will ensure that the dynamic
          sections are mapped to the right output section.  It does no
          harm to create these sections if they are not needed.  */
-      if (! sunos_create_dynamic_sections (abfd, info, info->shared))
+      if (! sunos_create_dynamic_sections (abfd, info, false))
        return false;
     }
 
@@ -1008,18 +1056,25 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
             reference.  */
          section = bfd_und_section_ptr;
        }
-      else if ((h->root.root.type == bfd_link_hash_defined
-               && h->root.root.u.def.section->owner != NULL
-               && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
-              || (h->root.root.type == bfd_link_hash_common
-                  && ((h->root.root.u.c.p->section->owner->flags & DYNAMIC)
-                      != 0)))
+      else if (h->root.root.type == bfd_link_hash_defined
+              && h->root.root.u.def.section->owner != NULL
+              && (h->root.root.u.def.section->owner->flags & DYNAMIC) != 0)
        {
          /* The existing definition is from a dynamic object.  We
             want to override it with the definition we just found.
             Clobber the existing definition.  */
          h->root.root.type = bfd_link_hash_new;
        }
+      else if (h->root.root.type == bfd_link_hash_common
+              && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0)
+       {
+         /* The existing definition is from a dynamic object.  We
+            want to override it with the definition we just found.
+            Clobber the existing definition.  We can't set it to new,
+            because it is on the undefined list.  */
+         h->root.root.type = bfd_link_hash_undefined;
+         h->root.root.u.undef.abfd = h->root.root.u.c.p->section->owner;
+       }
     }
 
   /* Do the usual procedure for adding a symbol.  */
@@ -1062,6 +1117,19 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
   return true;
 }
 
+/* Return the list of objects needed by BFD.  */
+
+/*ARGSUSED*/
+struct bfd_link_needed_list *
+bfd_sunos_get_needed_list (abfd, info)
+     bfd *abfd;
+     struct bfd_link_info *info;
+{
+  if (info->hash->creator != &MY(vec))
+    return NULL;
+  return sunos_hash_table (info)->needed;
+}
+
 /* Record an assignment made to a symbol by a linker script.  We need
    this in case some dynamic object refers to this symbol.  */
 
@@ -1073,6 +1141,9 @@ bfd_sunos_record_link_assignment (output_bfd, info, name)
 {
   struct sunos_link_hash_entry *h;
 
+  if (output_bfd->xvec != &MY(vec))
+    return true;
+
   /* This is called after we have examined all the input objects.  If
      the symbol does not exist, it merely means that no object refers
      to it, and we can just ignore it at this point.  */
@@ -1081,12 +1152,17 @@ bfd_sunos_record_link_assignment (output_bfd, info, name)
   if (h == NULL)
     return true;
 
-  h->flags |= SUNOS_DEF_REGULAR;
-
-  if (h->dynindx == -1)
+  /* In a shared library, the __DYNAMIC symbol does not appear in the
+     dynamic symbol table.  */
+  if (! info->shared || strcmp (name, "__DYNAMIC") != 0)
     {
-      ++sunos_hash_table (info)->dynsymcount;
-      h->dynindx = -2;
+      h->flags |= SUNOS_DEF_REGULAR;
+
+      if (h->dynindx == -1)
+       {
+         ++sunos_hash_table (info)->dynsymcount;
+         h->dynindx = -2;
+       }
     }
 
   return true;
@@ -1123,6 +1199,9 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
   *sneedptr = NULL;
   *srulesptr = NULL;
 
+  if (output_bfd->xvec != &MY(vec))
+    return true;
+
   /* Look through all the input BFD's and read their relocs.  It would
      be better if we didn't have to do this, but there is no other way
      to determine the number of dynamic relocs we need, and, more
@@ -1130,7 +1209,8 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
      get an entry in the procedure linkage table.  */
   for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
     {
-      if ((sub->flags & DYNAMIC) == 0)
+      if ((sub->flags & DYNAMIC) == 0
+         && sub->xvec == output_bfd->xvec)
        {
          if (! sunos_scan_relocs (info, sub, obj_textsec (sub),
                                   exec_hdr (sub)->a_trsize)
@@ -1183,10 +1263,7 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
   s->_raw_size = dynsymcount * sizeof (struct external_nlist);
   s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
   if (s->contents == NULL && s->_raw_size != 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
       
   /* The number of buckets is just the number of symbols divided by
      four.  To compute the final size of the hash table, we must
@@ -1206,10 +1283,7 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
   hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE;
   s->contents = (bfd_byte *) bfd_alloc (dynobj, hashalloc);
   if (s->contents == NULL && dynsymcount > 0)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   memset (s->contents, 0, hashalloc);
   for (i = 0; i < bucketcount; i++)
     PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
@@ -1237,13 +1311,10 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
       bfd_byte *contents;
 
       add = 8 - (s->_raw_size & 7);
-      contents = (bfd_byte *) realloc (s->contents,
-                                      (size_t) (s->_raw_size + add));
+      contents = (bfd_byte *) bfd_realloc (s->contents,
+                                          (size_t) (s->_raw_size + add));
       if (contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       memset (contents + s->_raw_size, 0, (size_t) add);
       s->contents = contents;
       s->_raw_size += add;
@@ -1257,10 +1328,7 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
     {
       s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
       if (s->contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
 
       /* Fill in the first entry in the table.  */
       switch (bfd_get_arch (dynobj))
@@ -1283,10 +1351,7 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
     {
       s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
       if (s->contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
     }
   /* We use the reloc_count field to keep track of how many of the
      relocs we have output so far.  */
@@ -1296,10 +1361,7 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
   s = bfd_get_section_by_name (dynobj, ".got");
   s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size);
   if (s->contents == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic");
   *sneedptr = bfd_get_section_by_name (dynobj, ".need");
@@ -1324,7 +1386,7 @@ sunos_scan_relocs (info, abfd, sec, rel_size)
     return true;
 
   if (! info->keep_memory)
-    relocs = free_relocs = malloc ((size_t) rel_size);
+    relocs = free_relocs = bfd_malloc ((size_t) rel_size);
   else
     {
       struct aout_section_data_struct *n;
@@ -1336,15 +1398,12 @@ sunos_scan_relocs (info, abfd, sec, rel_size)
       else
        {
          set_aout_section_data (sec, n);
-         relocs = malloc ((size_t) rel_size);
+         relocs = bfd_malloc ((size_t) rel_size);
          aout_section_data (sec)->relocs = relocs;
        }
     }
   if (relocs == NULL)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
 
   if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
       || bfd_read (relocs, 1, rel_size, abfd) != rel_size)
@@ -1602,15 +1661,6 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
              continue;
            }
        }
-      else
-       {
-         if (r_index >= bfd_get_symcount (abfd))
-           {
-             /* This is abnormal, but should be caught in the
-                 relocation phase.  */
-             continue;
-           }
-       }
 
       /* If this is a base relative reloc, we need to make an entry in
          the .got section.  */
@@ -1638,6 +1688,13 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
            }
          else
            {
+             if (r_index >= bfd_get_symcount (abfd))
+               {
+                 /* This is abnormal, but should be caught in the
+                    relocation phase.  */
+                 continue;
+               }
+
              if (adata (abfd).local_got_offsets == NULL)
                {
                  adata (abfd).local_got_offsets =
@@ -1645,10 +1702,7 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
                                            (bfd_get_symcount (abfd)
                                             * sizeof (bfd_vma)));
                  if (adata (abfd).local_got_offsets == NULL)
-                   {
-                     bfd_set_error (bfd_error_no_memory);
-                     return false;
-                   }
+                   return false;
                }
 
              if (adata (abfd).local_got_offsets[r_index] != 0)
@@ -1675,7 +1729,27 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
          defined in dynamic objects but not in regular objects.  We
          only need to consider relocs against external symbols.  */
       if (! r_extern)
-       continue;
+       {
+         /* But, if we are creating a shared library, we need to
+             generate an absolute reloc.  */
+         if (info->shared)
+           {
+             if (dynobj == NULL)
+               {
+                 if (! sunos_create_dynamic_sections (abfd, info, true))
+                   return false;
+                 dynobj = sunos_hash_table (info)->dynobj;
+                 splt = bfd_get_section_by_name (dynobj, ".plt");
+                 sgot = bfd_get_section_by_name (dynobj, ".got");
+                 srel = bfd_get_section_by_name (dynobj, ".dynrel");
+                 BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL);
+               }
+
+             srel->_raw_size += RELOC_EXT_SIZE;
+           }
+
+         continue;
+       }
 
       /* At this point common symbols have already been allocated, so
         we don't have to worry about them.  We need to consider that
@@ -1688,6 +1762,7 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
        continue;
 
       if (r_type != RELOC_JMP_TBL
+         && ! info->shared
          && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
              || (h->flags & SUNOS_DEF_REGULAR) != 0))
        continue;
@@ -1709,6 +1784,7 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
       BFD_ASSERT (r_type == RELOC_JMP_TBL
                  || (h->flags & SUNOS_REF_REGULAR) != 0);
       BFD_ASSERT (r_type == RELOC_JMP_TBL
+                 || info->shared
                  || h->plt_offset != 0
                  || ((h->root.root.type == bfd_link_hash_defined
                       || h->root.root.type == bfd_link_hash_defweak)
@@ -1719,24 +1795,28 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
       /* This reloc is against a symbol defined only by a dynamic
         object, or it is a jump table reloc from PIC compiled code.  */
 
-      if (h->root.root.type == bfd_link_hash_undefined)
+      if (r_type != RELOC_JMP_TBL
+         && h->root.root.type == bfd_link_hash_undefined)
        {
          /* Presumably this symbol was marked as being undefined by
             an earlier reloc.  */
          srel->_raw_size += RELOC_EXT_SIZE;
        }
-      else if ((h->root.root.u.def.section->flags & SEC_CODE) == 0)
+      else if (r_type != RELOC_JMP_TBL
+              && (h->root.root.u.def.section->flags & SEC_CODE) == 0)
        {
          bfd *sub;
 
          /* This reloc is not in the .text section.  It must be
             copied into the dynamic relocs.  We mark the symbol as
             being undefined.  */
-         BFD_ASSERT (r_type != RELOC_JMP_TBL);
          srel->_raw_size += RELOC_EXT_SIZE;
-         sub = h->root.root.u.def.section->owner;
-         h->root.root.type = bfd_link_hash_undefined;
-         h->root.root.u.undef.abfd = sub;
+         if ((h->flags & SUNOS_DEF_REGULAR) == 0)
+           {
+             sub = h->root.root.u.def.section->owner;
+             h->root.root.type = bfd_link_hash_undefined;
+             h->root.root.u.undef.abfd = sub;
+           }
        }
       else
        {
@@ -1753,6 +1833,8 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
 
              if ((h->flags & SUNOS_DEF_REGULAR) == 0)
                {
+                 if (h->root.root.type == bfd_link_hash_undefined)
+                   h->root.root.type = bfd_link_hash_defined;
                  h->root.root.u.def.section = splt;
                  h->root.root.u.def.value = splt->_raw_size;
                }
@@ -1765,6 +1847,11 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
              if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
                srel->_raw_size += RELOC_EXT_SIZE;
            }
+
+         /* If we are creating a shared library, we need to copy over
+             any reloc other than a jump table reloc.  */
+         if (info->shared && r_type != RELOC_JMP_TBL)
+           srel->_raw_size += RELOC_EXT_SIZE;
        }
     }
 
@@ -1785,8 +1872,14 @@ sunos_scan_dynamic_symbol (h, data)
      part of the regular symbol table.  This is all symbols which are
      not defined in a regular object file.  For some reason symbols
      which are referenced by a regular object and defined by a dynamic
-     object do not seem to show up in the regular symbol table.  */
-  if ((h->flags & SUNOS_DEF_REGULAR) == 0)
+     object do not seem to show up in the regular symbol table.  It is
+     possible for a symbol to have only SUNOS_REF_REGULAR set here, it
+     is an undefined symbol which was turned into a common symbol
+     because it was found in an archive object which was not included
+     in the link.  */
+  if ((h->flags & SUNOS_DEF_REGULAR) == 0
+      && (h->flags & SUNOS_DEF_DYNAMIC) != 0
+      && strcmp (h->root.root.root.string, "__DYNAMIC") != 0)
     h->root.written = true;
 
   /* If this symbol is defined by a dynamic object and referenced by a
@@ -1843,16 +1936,10 @@ sunos_scan_dynamic_symbol (h, data)
         There are no debugging symbols in the dynamic symbols.  */
       s = bfd_get_section_by_name (dynobj, ".dynstr");
       BFD_ASSERT (s != NULL);
-      if (s->contents == NULL)
-       contents = (bfd_byte *) malloc (len + 1);
-      else
-       contents = (bfd_byte *) realloc (s->contents,
-                                        (size_t) (s->_raw_size + len + 1));
+      contents = (bfd_byte *) bfd_realloc (s->contents,
+                                          s->_raw_size + len + 1);
       if (contents == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       s->contents = contents;
 
       h->dynstr_index = s->_raw_size;
@@ -2021,9 +2108,9 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
 
       s = bfd_get_section_by_name (dynobj, ".dynrel");
 
-      r_address = (h->root.root.u.def.section->output_section->vma
-                  + h->root.root.u.def.section->output_offset
-                  + h->root.root.u.def.value);
+      r_address = (splt->output_section->vma
+                  + splt->output_offset
+                  + h->plt_offset);
 
       switch (bfd_get_arch (output_bfd))
        {
@@ -2073,6 +2160,8 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
          result of a JMP_TBL reloc from PIC compiled code.  */
       if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)
        {
+         BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
+                     < s->_raw_size);
          p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd);
          if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE)
            {
@@ -2108,16 +2197,18 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
                  erel->r_index[0] = h->dynindx >> 16;
                  erel->r_index[1] = h->dynindx >> 8;
                  erel->r_index[2] = h->dynindx;
-                 erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_BIG
-                                    | (22 << RELOC_EXT_BITS_TYPE_SH_BIG));
+                 erel->r_type[0] =
+                   (RELOC_EXT_BITS_EXTERN_BIG
+                    | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG));
                }
              else
                {
                  erel->r_index[2] = h->dynindx >> 16;
                  erel->r_index[1] = h->dynindx >> 8;
                  erel->r_index[0] = h->dynindx;
-                 erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_LITTLE
-                                    | (22 << RELOC_EXT_BITS_TYPE_SH_LITTLE));
+                 erel->r_type[0] =
+                   (RELOC_EXT_BITS_EXTERN_LITTLE
+                    | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE));
                }
              PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend);
            }
@@ -2150,8 +2241,10 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
   struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg;
   bfd *dynobj;
   boolean baserel;
+  boolean jmptbl;
   asection *s;
   bfd_byte *p;
+  long indx;
 
   *skip = false;
 
@@ -2174,9 +2267,15 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
 
       srel = (struct reloc_std_external *) reloc;
       if (input_bfd->xvec->header_byteorder_big_p)
-       baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+       {
+         baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
+         jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+       }
       else
-       baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
+       {
+         baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
+         jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
+       }
     }
   else
     {
@@ -2193,6 +2292,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
       baserel = (r_type == RELOC_BASE10
                 || r_type == RELOC_BASE13
                 || r_type == RELOC_BASE22);
+      jmptbl = r_type == RELOC_JMP_TBL;
     }
 
   if (baserel)
@@ -2247,21 +2347,35 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
         already initialized the GOT entry.  */
       if ((*got_offsetp & 1) == 0)
        {
-         PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp);
+         if (h == NULL
+             || (! info->shared
+                 && ((h->flags & SUNOS_DEF_DYNAMIC) == 0
+                     || (h->flags & SUNOS_DEF_REGULAR) != 0)))
+           PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp);
+         else
+           PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp);
 
-         if (h != NULL
-             && (h->flags & SUNOS_DEF_DYNAMIC) != 0
-             && (h->flags & SUNOS_DEF_REGULAR) == 0)
+         if (info->shared
+             || (h != NULL
+                 && (h->flags & SUNOS_DEF_DYNAMIC) != 0
+                 && (h->flags & SUNOS_DEF_REGULAR) == 0))
            {
-             /* We need to create a GLOB_DAT reloc to tell the
+             /* We need to create a GLOB_DAT or 32 reloc to tell the
                  dynamic linker to fill in this entry in the table.  */
 
              s = bfd_get_section_by_name (dynobj, ".dynrel");
              BFD_ASSERT (s != NULL);
+             BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj)
+                         < s->_raw_size);
 
              p = (s->contents
                   + s->reloc_count * obj_reloc_entry_size (dynobj));
 
+             if (h != NULL)
+               indx = h->dynindx;
+             else
+               indx = 0;
+
              if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
                {
                  struct reloc_std_external *srel;
@@ -2274,25 +2388,31 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                            srel->r_address);
                  if (dynobj->xvec->header_byteorder_big_p)
                    {
-                     srel->r_index[0] = h->dynindx >> 16;
-                     srel->r_index[1] = h->dynindx >> 8;
-                     srel->r_index[2] = h->dynindx;
-                     srel->r_type[0] =
-                       (RELOC_STD_BITS_EXTERN_BIG
-                        | RELOC_STD_BITS_BASEREL_BIG
-                        | RELOC_STD_BITS_RELATIVE_BIG
-                        | (2 << RELOC_STD_BITS_LENGTH_SH_BIG));
+                     srel->r_index[0] = indx >> 16;
+                     srel->r_index[1] = indx >> 8;
+                     srel->r_index[2] = indx;
+                     if (h == NULL)
+                       srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG;
+                     else
+                       srel->r_type[0] =
+                         (RELOC_STD_BITS_EXTERN_BIG
+                          | RELOC_STD_BITS_BASEREL_BIG
+                          | RELOC_STD_BITS_RELATIVE_BIG
+                          | (2 << RELOC_STD_BITS_LENGTH_SH_BIG));
                    }
                  else
                    {
-                     srel->r_index[2] = h->dynindx >> 16;
-                     srel->r_index[1] = h->dynindx >> 8;
-                     srel->r_index[0] = h->dynindx;
-                     srel->r_type[0] =
-                       (RELOC_STD_BITS_EXTERN_LITTLE
-                        | RELOC_STD_BITS_BASEREL_LITTLE
-                        | RELOC_STD_BITS_RELATIVE_LITTLE
-                        | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE));
+                     srel->r_index[2] = indx >> 16;
+                     srel->r_index[1] = indx >> 8;
+                     srel->r_index[0] = indx;
+                     if (h == NULL)
+                       srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE;
+                     else
+                       srel->r_type[0] =
+                         (RELOC_STD_BITS_EXTERN_LITTLE
+                          | RELOC_STD_BITS_BASEREL_LITTLE
+                          | RELOC_STD_BITS_RELATIVE_LITTLE
+                          | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE));
                    }
                }
              else
@@ -2307,21 +2427,30 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                            erel->r_address);
                  if (dynobj->xvec->header_byteorder_big_p)
                    {
-                     erel->r_index[0] = h->dynindx >> 16;
-                     erel->r_index[1] = h->dynindx >> 8;
-                     erel->r_index[2] = h->dynindx;
-                     erel->r_type[0] =
-                       (RELOC_EXT_BITS_EXTERN_BIG
-                        | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG));
+                     erel->r_index[0] = indx >> 16;
+                     erel->r_index[1] = indx >> 8;
+                     erel->r_index[2] = indx;
+                     if (h == NULL)
+                       erel->r_type[0] =
+                         RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG;
+                     else
+                       erel->r_type[0] =
+                         (RELOC_EXT_BITS_EXTERN_BIG
+                          | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG));
                    }
                  else
                    {
-                     erel->r_index[2] = h->dynindx >> 16;
-                     erel->r_index[1] = h->dynindx >> 8;
-                     erel->r_index[0] = h->dynindx;
-                     erel->r_type[0] =
-                       (RELOC_EXT_BITS_EXTERN_LITTLE
-                        | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_LITTLE));
+                     erel->r_index[2] = indx >> 16;
+                     erel->r_index[1] = indx >> 8;
+                     erel->r_index[0] = indx;
+                     if (h == NULL)
+                       erel->r_type[0] =
+                         RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE;
+                     else
+                       erel->r_type[0] =
+                         (RELOC_EXT_BITS_EXTERN_LITTLE
+                          | (RELOC_GLOB_DAT
+                             << RELOC_EXT_BITS_TYPE_SH_LITTLE));
                    }
                  PUT_WORD (dynobj, 0, erel->r_addend);
                }
@@ -2338,25 +2467,44 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
       return true;
     }
 
-  if (! sunos_hash_table (info)->dynamic_sections_needed
-      || h == NULL
-      || h->dynindx == -1
-      || h->root.root.type != bfd_link_hash_undefined
-      || (h->flags & SUNOS_DEF_REGULAR) != 0
-      || (h->flags & SUNOS_DEF_DYNAMIC) == 0
-      || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0)
+  if (! sunos_hash_table (info)->dynamic_sections_needed)
     return true;
+  if (! info->shared)
+    {
+      if (h == NULL
+         || h->dynindx == -1
+         || h->root.root.type != bfd_link_hash_undefined
+         || (h->flags & SUNOS_DEF_REGULAR) != 0
+         || (h->flags & SUNOS_DEF_DYNAMIC) == 0
+         || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0)
+       return true;
+    }
+  else
+    {
+      if (h != NULL
+         && (h->dynindx == -1
+             || jmptbl
+             || strcmp (h->root.root.root.string,
+                        "__GLOBAL_OFFSET_TABLE_") == 0))
+       return true;
+    }
 
   /* It looks like this is a reloc we are supposed to copy.  */
 
   s = bfd_get_section_by_name (dynobj, ".dynrel");
   BFD_ASSERT (s != NULL);
+  BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->_raw_size);
 
   p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj);
 
   /* Copy the reloc over.  */
   memcpy (p, reloc, obj_reloc_entry_size (dynobj));
 
+  if (h != NULL)
+    indx = h->dynindx;
+  else
+    indx = 0;
+
   /* Adjust the address and symbol index.  */
   if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE)
     {
@@ -2370,15 +2518,15 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                srel->r_address);
       if (dynobj->xvec->header_byteorder_big_p)
        {
-         srel->r_index[0] = h->dynindx >> 16;
-         srel->r_index[1] = h->dynindx >> 8;
-         srel->r_index[2] = h->dynindx;
+         srel->r_index[0] = indx >> 16;
+         srel->r_index[1] = indx >> 8;
+         srel->r_index[2] = indx;
        }
       else
        {
-         srel->r_index[2] = h->dynindx >> 16;
-         srel->r_index[1] = h->dynindx >> 8;
-         srel->r_index[0] = h->dynindx;
+         srel->r_index[2] = indx >> 16;
+         srel->r_index[1] = indx >> 8;
+         srel->r_index[0] = indx;
        }
     }
   else
@@ -2393,21 +2541,22 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                erel->r_address);
       if (dynobj->xvec->header_byteorder_big_p)
        {
-         erel->r_index[0] = h->dynindx >> 16;
-         erel->r_index[1] = h->dynindx >> 8;
-         erel->r_index[2] = h->dynindx;
+         erel->r_index[0] = indx >> 16;
+         erel->r_index[1] = indx >> 8;
+         erel->r_index[2] = indx;
        }
       else
        {
-         erel->r_index[2] = h->dynindx >> 16;
-         erel->r_index[1] = h->dynindx >> 8;
-         erel->r_index[0] = h->dynindx;
+         erel->r_index[2] = indx >> 16;
+         erel->r_index[1] = indx >> 8;
+         erel->r_index[0] = indx;
        }
     }
 
   ++s->reloc_count;
 
-  *skip = true;
+  if (h != NULL)
+    *skip = true;
 
   return true;
 }
@@ -2459,12 +2608,15 @@ sunos_finish_dynamic_link (abfd, info)
        }
     }
 
-  /* The first entry in the .got section is the address of the dynamic
-     information.  */
+  /* The first entry in the .got section is the address of the
+     dynamic information, unless this is a shared library.  */
   s = bfd_get_section_by_name (dynobj, ".got");
   BFD_ASSERT (s != NULL);
-  PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
-           s->contents);
+  if (info->shared)
+    PUT_WORD (dynobj, 0, s->contents);
+  else
+    PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
+             s->contents);
 
   for (o = dynobj->sections; o != NULL; o = o->next)
     {