* elf32-sh.c (sh_elf_relocate_section): Don't complain about
[deliverable/binutils-gdb.git] / bfd / sunos.c
index af95a24aa3874e017c693150e1de8a0b646c3392..5fec6f91d7d1dbf75e7a7534ac2d8f408ba2ee60 100644 (file)
@@ -1,5 +1,7 @@
 /* BFD backend for SunOS binaries.
-   Copyright (C) 1990, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
+   Copyright 1990, 1991, 1992, 1994, 1995, 1996, 1997, 1998, 2000, 2001,
+   2002
+   Free Software Foundation, Inc.
    Written by Cygnus Support.
 
 This file is part of BFD, the Binary File Descriptor library.
@@ -19,7 +21,11 @@ along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 
 #define TARGETNAME "a.out-sunos-big"
-#define MY(OP) CAT(sunos_big_,OP)
+
+/* Do not "beautify" the CONCAT* macro args.  Traditional C will not
+   remove whitespace added here, and thus will fail to concatenate
+   the tokens.  */
+#define MY(OP) CONCAT2 (sunos_big_,OP)
 
 #include "bfd.h"
 #include "bfdlink.h"
@@ -78,9 +84,22 @@ static boolean sunos_finish_dynamic_link
 #define MY_check_dynamic_reloc sunos_check_dynamic_reloc
 #define MY_finish_dynamic_link sunos_finish_dynamic_link
 
+/* ??? Where should this go?  */
+#define MACHTYPE_OK(mtype) \
+  (((mtype) == M_SPARC && bfd_lookup_arch (bfd_arch_sparc, 0) != NULL) \
+   || ((mtype) == M_SPARCLET \
+       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
+   || ((mtype) == M_SPARCLITE_LE \
+       && bfd_lookup_arch (bfd_arch_sparc, bfd_mach_sparc_sparclet) != NULL) \
+   || (((mtype) == M_UNKNOWN || (mtype) == M_68010 || (mtype) == M_68020) \
+       && bfd_lookup_arch (bfd_arch_m68k, 0) != NULL))
+
 /* Include the usual a.out support.  */
 #include "aoutf1.h"
 
+/* The SunOS 4.1.4 /usr/include/locale.h defines valid as a macro.  */
+#undef valid
+
 /* SunOS shared library support.  We store a pointer to this structure
    in obj_aout_dynamic_info (abfd).  */
 
@@ -128,6 +147,7 @@ sunos_read_dynamic_info (abfd)
   struct external_sun4_dynamic dyninfo;
   unsigned long dynver;
   struct external_sun4_dynamic_link linkinfo;
+  bfd_size_type amt;
 
   if (obj_aout_dynamic_info (abfd) != (PTR) NULL)
     return true;
@@ -138,13 +158,10 @@ sunos_read_dynamic_info (abfd)
       return false;
     }
 
-  info = ((struct sunos_dynamic_info *)
-         bfd_zalloc (abfd, sizeof (struct sunos_dynamic_info)));
+  amt = sizeof (struct sunos_dynamic_info);
+  info = (struct sunos_dynamic_info *) bfd_zalloc (abfd, amt);
   if (!info)
-    {
-      bfd_set_error (bfd_error_no_memory);
-      return false;
-    }
+    return false;
   info->valid = false;
   info->dynsym = NULL;
   info->dynstr = NULL;
@@ -163,7 +180,8 @@ sunos_read_dynamic_info (abfd)
   if ((abfd->flags & DYNAMIC) == 0)
     return true;
   if (! bfd_get_section_contents (abfd, obj_datasec (abfd), (PTR) &dyninfo,
-                                 (file_ptr) 0, sizeof dyninfo))
+                                 (file_ptr) 0,
+                                 (bfd_size_type) sizeof dyninfo))
     return true;
 
   dynver = GET_WORD (abfd, dyninfo.ld_version);
@@ -184,7 +202,8 @@ sunos_read_dynamic_info (abfd)
 
   /* This executable appears to be dynamically linked in a way that we
      can understand.  */
-  if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo, dynoff,
+  if (! bfd_get_section_contents (abfd, dynsec, (PTR) &linkinfo,
+                                 (file_ptr) dynoff,
                                  (bfd_size_type) sizeof linkinfo))
     return true;
 
@@ -266,6 +285,7 @@ sunos_slurp_dynamic_symtab (abfd)
      bfd *abfd;
 {
   struct sunos_dynamic_info *info;
+  bfd_size_type amt;
 
   /* Get the general dynamic information.  */
   if (obj_aout_dynamic_info (abfd) == NULL)
@@ -284,19 +304,12 @@ sunos_slurp_dynamic_symtab (abfd)
   /* Get the dynamic nlist structures.  */
   if (info->dynsym == (struct external_nlist *) NULL)
     {
-      info->dynsym = ((struct external_nlist *)
-                     bfd_alloc (abfd,
-                                (info->dynsym_count
-                                 * EXTERNAL_NLIST_SIZE)));
+      amt = (bfd_size_type) info->dynsym_count * EXTERNAL_NLIST_SIZE;
+      info->dynsym = (struct external_nlist *) bfd_alloc (abfd, amt);
       if (info->dynsym == NULL && info->dynsym_count != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         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)
-             != info->dynsym_count * EXTERNAL_NLIST_SIZE))
+       return false;
+      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_stab, SEEK_SET) != 0
+         || bfd_bread ((PTR) info->dynsym, amt, abfd) != amt)
        {
          if (info->dynsym != NULL)
            {
@@ -310,16 +323,12 @@ sunos_slurp_dynamic_symtab (abfd)
   /* Get the dynamic strings.  */
   if (info->dynstr == (char *) NULL)
     {
-      info->dynstr = (char *) bfd_alloc (abfd, info->dyninfo.ld_symb_size);
+      amt = info->dyninfo.ld_symb_size;
+      info->dynstr = (char *) bfd_alloc (abfd, amt);
       if (info->dynstr == NULL && info->dyninfo.ld_symb_size != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         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)
-             != info->dyninfo.ld_symb_size))
+       return false;
+      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_symbols, SEEK_SET) != 0
+         || bfd_bread ((PTR) info->dynstr, amt, abfd) != amt)
        {
          if (info->dynstr != NULL)
            {
@@ -359,11 +368,11 @@ 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
-       || bfd_read ((PTR) table, 1, table_size, abfd) != table_size)
+    if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_hash, SEEK_SET) != 0
+       || bfd_bread ((PTR) table, table_size, abfd) != table_size)
       abort ();
     for (i = 0; i < info->dynsym_count; i++)
       {
@@ -393,21 +402,18 @@ sunos_canonicalize_dynamic_symtab (abfd, storage)
      structures.  */
   if (info->canonical_dynsym == (aout_symbol_type *) NULL)
     {
-      info->canonical_dynsym = ((aout_symbol_type *)
-                               bfd_alloc (abfd,
-                                          (info->dynsym_count
-                                           * sizeof (aout_symbol_type))));
+      bfd_size_type size;
+      bfd_size_type strsize = info->dyninfo.ld_symb_size;
+
+      size = (bfd_size_type) info->dynsym_count * sizeof (aout_symbol_type);
+      info->canonical_dynsym = (aout_symbol_type *) bfd_alloc (abfd, size);
       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,
-                                           info->dynstr,
-                                           info->dyninfo.ld_symb_size,
-                                           true))
+                                           info->dynsym,
+                                           (bfd_size_type) info->dynsym_count,
+                                           info->dynstr, strsize, true))
        {
          if (info->canonical_dynsym != NULL)
            {
@@ -457,6 +463,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
 {
   struct sunos_dynamic_info *info;
   unsigned long i;
+  bfd_size_type size;
 
   /* Get the general dynamic information.  */
   if (obj_aout_dynamic_info (abfd) == (PTR) NULL)
@@ -475,18 +482,12 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
   /* Get the dynamic reloc information.  */
   if (info->dynrel == NULL)
     {
-      info->dynrel = (PTR) bfd_alloc (abfd,
-                                     (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;
-       }
-      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)
-             != info->dynrel_count * obj_reloc_entry_size (abfd)))
+      size = (bfd_size_type) info->dynrel_count * obj_reloc_entry_size (abfd);
+      info->dynrel = (PTR) bfd_alloc (abfd, size);
+      if (info->dynrel == NULL && size != 0)
+       return -1;
+      if (bfd_seek (abfd, (file_ptr) info->dyninfo.ld_rel, SEEK_SET) != 0
+         || bfd_bread ((PTR) info->dynrel, size, abfd) != size)
        {
          if (info->dynrel != NULL)
            {
@@ -503,16 +504,11 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
     {
       arelent *to;
 
-      info->canonical_dynrel = ((arelent *)
-                               bfd_alloc (abfd,
-                                          (info->dynrel_count
-                                           * sizeof (arelent))));
+      size = (bfd_size_type) info->dynrel_count * sizeof (arelent);
+      info->canonical_dynrel = (arelent *) bfd_alloc (abfd, size);
       if (info->canonical_dynrel == NULL && info->dynrel_count != 0)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return -1;
-       }
-      
+       return -1;
+
       to = info->canonical_dynrel;
 
       if (obj_reloc_entry_size (abfd) == RELOC_EXT_SIZE)
@@ -524,7 +520,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
          pend = p + info->dynrel_count;
          for (; p < pend; p++, to++)
            NAME(aout,swap_ext_reloc_in) (abfd, p, to, syms,
-                                         info->dynsym_count);
+                                         (bfd_size_type) info->dynsym_count);
        }
       else
        {
@@ -535,7 +531,7 @@ sunos_canonicalize_dynamic_reloc (abfd, storage, syms)
          pend = p + info->dynrel_count;
          for (; p < pend; p++, to++)
            NAME(aout,swap_std_reloc_in) (abfd, p, to, syms,
-                                         info->dynsym_count);
+                                         (bfd_size_type) info->dynsym_count);
        }
     }
 
@@ -568,21 +564,21 @@ static const bfd_byte sparc_plt_first_entry[SPARC_PLT_ENTRY_SIZE] =
 };
 
 /* save %sp, -96, %sp */
-#define SPARC_PLT_ENTRY_WORD0 0x9de3bfa0
+#define SPARC_PLT_ENTRY_WORD0 ((bfd_vma) 0x9de3bfa0)
 /* call; address filled in later.  */
-#define SPARC_PLT_ENTRY_WORD1 0x40000000
+#define SPARC_PLT_ENTRY_WORD1 ((bfd_vma) 0x40000000)
 /* sethi; reloc index filled in later.  */
-#define SPARC_PLT_ENTRY_WORD2 0x01000000
+#define SPARC_PLT_ENTRY_WORD2 ((bfd_vma) 0x01000000)
 
 /* This sequence is used when for the jump table entry to a defined
    symbol in a complete executable.  It is used when linking PIC
    compiled code which is not being put into a shared library.  */
 /* sethi <address to be filled in later>, %g1 */
-#define SPARC_PLT_PIC_WORD0 0x03000000
+#define SPARC_PLT_PIC_WORD0 ((bfd_vma) 0x03000000)
 /* jmp %g1 + <address to be filled in later> */
-#define SPARC_PLT_PIC_WORD1 0x81c06000
+#define SPARC_PLT_PIC_WORD1 ((bfd_vma) 0x81c06000)
 /* nop */
-#define SPARC_PLT_PIC_WORD2 0x01000000
+#define SPARC_PLT_PIC_WORD2 ((bfd_vma) 0x01000000)
 
 /* An m68k procedure linkage table entry is 8 bytes.  The first entry
    in the table is a jump which is filled in the by the runtime
@@ -602,7 +598,7 @@ static const bfd_byte m68k_plt_first_entry[M68K_PLT_ENTRY_SIZE] =
 };
 
 /* bsrl */
-#define M68K_PLT_ENTRY_WORD0 (0x61ff)
+#define M68K_PLT_ENTRY_WORD0 ((bfd_vma) 0x61ff)
 /* Remaining words filled in later.  */
 
 /* An entry in the SunOS linker hash table.  */
@@ -638,9 +634,11 @@ struct sunos_link_hash_entry
   /* Symbol is defined by a regular object.  */
 #define SUNOS_DEF_REGULAR 02
   /* Symbol is referenced by a dynamic object.  */
-#define SUNOS_REF_DYNAMIC 010
+#define SUNOS_REF_DYNAMIC 04
   /* Symbol is defined by a dynamic object.  */
-#define SUNOS_DEF_DYNAMIC 020
+#define SUNOS_DEF_DYNAMIC 010
+  /* Symbol is a constructor symbol in a regular object.  */
+#define SUNOS_CONSTRUCTOR 020
 };
 
 /* The SunOS linker hash table.  */
@@ -658,6 +656,9 @@ struct sunos_link_hash_table
   /* Whether we need the dynamic sections.  */
   boolean dynamic_sections_needed;
 
+  /* Whether we need the .got table.  */
+  boolean got_needed;
+
   /* The number of dynamic symbols.  */
   size_t dynsymcount;
 
@@ -667,6 +668,9 @@ struct sunos_link_hash_table
   /* The list of dynamic objects needed by dynamic objects included in
      the link.  */
   struct bfd_link_needed_list *needed;
+
+  /* The offset of __GLOBAL_OFFSET_TABLE_ into the .got section.  */
+  bfd_vma got_base;
 };
 
 /* Routine to create an entry in an SunOS link hash table.  */
@@ -685,10 +689,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,27 +715,26 @@ sunos_link_hash_table_create (abfd)
      bfd *abfd;
 {
   struct sunos_link_hash_table *ret;
+  bfd_size_type amt = sizeof (struct sunos_link_hash_table);
 
-  ret = ((struct sunos_link_hash_table *)
-        bfd_alloc (abfd, sizeof (struct sunos_link_hash_table)));
+  ret = (struct sunos_link_hash_table *) bfd_malloc (amt);
   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))
     {
-      bfd_release (abfd, ret);
+      free (ret);
       return (struct bfd_link_hash_table *) NULL;
     }
 
   ret->dynobj = NULL;
   ret->dynamic_sections_created = false;
   ret->dynamic_sections_needed = false;
+  ret->got_needed = false;
   ret->dynsymcount = 0;
   ret->bucketcount = 0;
   ret->needed = NULL;
+  ret->got_base = 0;
 
   return &ret->root.root;
 }
@@ -783,7 +783,8 @@ sunos_create_dynamic_sections (abfd, info, needed)
 
       sunos_hash_table (info)->dynobj = abfd;
 
-      flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY;
+      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
+              | SEC_LINKER_CREATED);
 
       /* The .dynamic section holds the basic dynamic information: the
         sun4_dynamic structure, the dynamic debugger information, and
@@ -845,24 +846,26 @@ sunos_create_dynamic_sections (abfd, info, needed)
       sunos_hash_table (info)->dynamic_sections_created = true;
     }
 
-  if (needed && ! sunos_hash_table (info)->dynamic_sections_needed)
+  if ((needed && ! sunos_hash_table (info)->dynamic_sections_needed)
+      || info->shared)
     {
       bfd *dynobj;
 
       dynobj = sunos_hash_table (info)->dynobj;
 
       s = bfd_get_section_by_name (dynobj, ".got");
-      s->_raw_size = BYTES_IN_WORD;
+      if (s->_raw_size == 0)
+       s->_raw_size = BYTES_IN_WORD;
 
       sunos_hash_table (info)->dynamic_sections_needed = true;
+      sunos_hash_table (info)->got_needed = true;
     }
 
   return true;
 }
 
 /* Add dynamic symbols during a link.  This is called by the a.out
-   backend linker when it encounters an object with the DYNAMIC flag
-   set.  */
+   backend linker for each object it encounters.  */
 
 static boolean
 sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
@@ -872,18 +875,42 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
      bfd_size_type *sym_countp;
      char **stringsp;
 {
-  asection *s;
   bfd *dynobj;
   struct sunos_dynamic_info *dinfo;
   unsigned long need;
+  asection **ps;
+
+  /* Make sure we have all the required sections.  */
+  if (info->hash->creator == abfd->xvec)
+    {
+      if (! sunos_create_dynamic_sections (abfd, info,
+                                          (((abfd->flags & DYNAMIC) != 0
+                                            && ! info->relocateable)
+                                           ? true
+                                           : false)))
+       return false;
+    }
+
+  /* There is nothing else to do for a normal object.  */
+  if ((abfd->flags & DYNAMIC) == 0)
+    return true;
+
+  dynobj = sunos_hash_table (info)->dynobj;
 
   /* 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
      in the BFD.  This could be handled more cleanly by, say, a new
      section flag; the existing SEC_NEVER_LOAD flag is not the one we
      want, because that one still implies that the section takes up
-     space in the output file.  */
-  abfd->sections = NULL;
+     space in the output file.  If this is the first object we have
+     seen, we must preserve the dynamic sections we just created.  */
+  for (ps = &abfd->sections; *ps != NULL; )
+    {
+      if (abfd != dynobj || ((*ps)->flags & SEC_LINKER_CREATED) == 0)
+       bfd_section_list_remove (abfd, ps);
+      else
+       ps = &(*ps)->next;
+    }
 
   /* The native linker seems to just ignore dynamic objects when -r is
      used.  */
@@ -898,20 +925,15 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
       return false;
     }
 
-  /* Make sure we have all the required information.  */
-  if (! sunos_create_dynamic_sections (abfd, info, true))
-    return false;
-
   /* Make sure we have a .need and a .rules sections.  These are only
      needed if there really is a dynamic object in the link, so they
      are not added by sunos_create_dynamic_sections.  */
-  dynobj = sunos_hash_table (info)->dynobj;
   if (bfd_get_section_by_name (dynobj, ".need") == NULL)
     {
       /* The .need section holds the list of names of shared objets
         which must be included at runtime.  The address of this
         section is put in the ld_need field.  */
-      s = bfd_make_section (dynobj, ".need");
+      asection *s = bfd_make_section (dynobj, ".need");
       if (s == NULL
          || ! bfd_set_section_flags (dynobj, s,
                                      (SEC_ALLOC
@@ -928,7 +950,7 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
       /* The .rules section holds the path to search for shared
         objects.  The address of this section is put in the ld_rules
         field.  */
-      s = bfd_make_section (dynobj, ".rules");
+      asection *s = bfd_make_section (dynobj, ".rules");
       if (s == NULL
          || ! bfd_set_section_flags (dynobj, s,
                                      (SEC_ALLOC
@@ -957,10 +979,13 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
       unsigned long name, flags;
       unsigned short major_vno, minor_vno;
       struct bfd_link_needed_list *needed, **pp;
+      char *namebuf, *p;
+      bfd_size_type alc;
       bfd_byte b;
+      char *namecopy;
 
-      if (bfd_seek (abfd, need, SEEK_SET) != 0
-         || bfd_read (buf, 1, 16, abfd) != 16)
+      if (bfd_seek (abfd, (file_ptr) need, SEEK_SET) != 0
+         || bfd_bread (buf, (bfd_size_type) 16, abfd) != 16)
        return false;
 
       /* For the format of an ld_need entry, see aout/sun4.h.  We
@@ -968,49 +993,102 @@ sunos_add_dynamic_symbols (abfd, info, symsp, sym_countp, stringsp)
 
       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);
+      major_vno = (unsigned short) bfd_get_16 (abfd, buf + 8);
+      minor_vno = (unsigned short) 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));
+      alc = sizeof (struct bfd_link_needed_list);
+      needed = (struct bfd_link_needed_list *) bfd_alloc (abfd, alc);
       if (needed == NULL)
-       {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
-       }
+       return false;
       needed->by = abfd;
 
       /* We return the name as [-l]name[.maj][.min].  */
+      alc = 30;
+      namebuf = (char *) bfd_malloc (alc + 1);
+      if (namebuf == NULL)
+       return false;
+      p = namebuf;
 
       if ((flags & 0x80000000) != 0)
-       bfd_alloc_grow (abfd, "-l", 2);
-      if (bfd_seek (abfd, name, SEEK_SET) != 0)
-       return false;
+       {
+         *p++ = '-';
+         *p++ = 'l';
+       }
+      if (bfd_seek (abfd, (file_ptr) name, SEEK_SET) != 0)
+       {
+         free (namebuf);
+         return false;
+       }
+
       do
        {
-         if (bfd_read (&b, 1, 1, abfd) != 1)
-           return false;
-         bfd_alloc_grow (abfd, &b, 1);
+         if (bfd_bread (&b, (bfd_size_type) 1, abfd) != 1)
+           {
+             free (namebuf);
+             return false;
+           }
+
+         if ((bfd_size_type) (p - namebuf) >= alc)
+           {
+             char *n;
+
+             alc *= 2;
+             n = (char *) bfd_realloc (namebuf, alc + 1);
+             if (n == NULL)
+               {
+                 free (namebuf);
+                 return false;
+               }
+             p = n + (p - namebuf);
+             namebuf = n;
+           }
+
+         *p++ = b;
        }
       while (b != '\0');
-      if (major_vno != 0)
+
+      if (major_vno == 0)
+       *p = '\0';
+      else
        {
-         char verbuf[30];
+         char majbuf[30];
+         char minbuf[30];
+
+         sprintf (majbuf, ".%d", major_vno);
+         if (minor_vno == 0)
+           minbuf[0] = '\0';
+         else
+           sprintf (minbuf, ".%d", minor_vno);
 
-         sprintf (verbuf, ".%d", major_vno);
-         bfd_alloc_grow (abfd, verbuf, strlen (verbuf));
-         if (minor_vno != 0)
+         if ((p - namebuf) + strlen (majbuf) + strlen (minbuf) >= alc)
            {
-             sprintf (verbuf, ".%d", minor_vno);
-             bfd_alloc_grow (abfd, verbuf, strlen (verbuf));
+             char *n;
+
+             alc = (p - namebuf) + strlen (majbuf) + strlen (minbuf);
+             n = (char *) bfd_realloc (namebuf, alc + 1);
+             if (n == NULL)
+               {
+                 free (namebuf);
+                 return false;
+               }
+             p = n + (p - namebuf);
+             namebuf = n;
            }
+
+         strcpy (p, majbuf);
+         strcat (p, minbuf);
        }
-      needed->name = bfd_alloc_finish (abfd);
-      if (needed->name == NULL)
+
+      namecopy = bfd_alloc (abfd, (bfd_size_type) strlen (namebuf) + 1);
+      if (namecopy == NULL)
        {
-         bfd_set_error (bfd_error_no_memory);
+         free (namebuf);
          return false;
        }
+      strcpy (namecopy, namebuf);
+      free (namebuf);
+      needed->name = namecopy;
 
       needed->next = NULL;
 
@@ -1045,19 +1123,13 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
   struct sunos_link_hash_entry *h;
   int new_flag;
 
-  if (! sunos_hash_table (info)->dynamic_sections_created)
-    {
-      /* We must create the dynamic sections while reading the input
-         files, even though at this point we don't know if any of the
-         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, false))
-       return false;
-    }
-
-  h = sunos_link_hash_lookup (sunos_hash_table (info), name, true, copy,
-                             false);
+  if ((flags & (BSF_INDIRECT | BSF_WARNING | BSF_CONSTRUCTOR)) != 0
+      || ! bfd_is_und_section (section))
+    h = sunos_link_hash_lookup (sunos_hash_table (info), name, true, copy,
+                               false);
+  else
+    h = ((struct sunos_link_hash_entry *)
+        bfd_wrapped_link_hash_lookup (abfd, info, name, true, copy, false));
   if (h == NULL)
     return false;
 
@@ -1093,7 +1165,8 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
          /* 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;
+         h->root.root.type = bfd_link_hash_undefined;
+         h->root.root.u.undef.abfd = h->root.root.u.def.section->owner;
        }
       else if (h->root.root.type == bfd_link_hash_common
               && (h->root.root.u.c.p->section->owner->flags & DYNAMIC) != 0)
@@ -1107,6 +1180,29 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
        }
     }
 
+  if ((abfd->flags & DYNAMIC) != 0
+      && abfd->xvec == info->hash->creator
+      && (h->flags & SUNOS_CONSTRUCTOR) != 0)
+    {
+      /* The existing symbol is a constructor symbol, and this symbol
+         is from a dynamic object.  A constructor symbol is actually a
+         definition, although the type will be bfd_link_hash_undefined
+         at this point.  We want to ignore the definition from the
+         dynamic object.  */
+      section = bfd_und_section_ptr;
+    }
+  else if ((flags & BSF_CONSTRUCTOR) != 0
+          && (abfd->flags & DYNAMIC) == 0
+          && 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 symbol is defined by a dynamic object, and this
+         is a constructor symbol.  As above, we want to force the use
+         of the constructor symbol from the regular object.  */
+      h->root.root.type = bfd_link_hash_new;
+    }
+
   /* Do the usual procedure for adding a symbol.  */
   if (! _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section,
                                          value, string, copy, collect,
@@ -1142,6 +1238,10 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
          ++sunos_hash_table (info)->dynsymcount;
          h->dynindx = -2;
        }
+
+      if ((flags & BSF_CONSTRUCTOR) != 0
+         && (abfd->flags & DYNAMIC) == 0)
+       h->flags |= SUNOS_CONSTRUCTOR;
     }
 
   return true;
@@ -1152,7 +1252,7 @@ sunos_add_one_symbol (info, abfd, name, flags, section, value, string,
 /*ARGSUSED*/
 struct bfd_link_needed_list *
 bfd_sunos_get_needed_list (abfd, info)
-     bfd *abfd;
+     bfd *abfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   if (info->hash->creator != &MY(vec))
@@ -1217,11 +1317,11 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
      asection **srulesptr;
 {
   bfd *dynobj;
-  size_t dynsymcount;
+  bfd_size_type dynsymcount;
   struct sunos_link_hash_entry *h;
   asection *s;
   size_t bucketcount;
-  size_t hashalloc;
+  bfd_size_type hashalloc;
   size_t i;
   bfd *sub;
 
@@ -1229,6 +1329,9 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
   *sneedptr = NULL;
   *srulesptr = NULL;
 
+  if (info->relocateable)
+    return true;
+
   if (output_bfd->xvec != &MY(vec))
     return true;
 
@@ -1255,7 +1358,8 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
 
   /* If there were no dynamic objects in the link, and we don't need
      to build a global offset table, there is nothing to do here.  */
-  if (! sunos_hash_table (info)->dynamic_sections_needed)
+  if (! sunos_hash_table (info)->dynamic_sections_needed
+      && ! sunos_hash_table (info)->got_needed)
     return true;
 
   /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it.  */
@@ -1271,92 +1375,102 @@ bfd_sunos_size_dynamic_sections (output_bfd, info, sdynptr, sneedptr,
        }
       h->root.root.type = bfd_link_hash_defined;
       h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got");
-      h->root.root.u.def.value = 0;
-    }
 
-  /* The .dynamic section is always the same size.  */
-  s = bfd_get_section_by_name (dynobj, ".dynamic");
-  BFD_ASSERT (s != NULL);
-  s->_raw_size = (sizeof (struct external_sun4_dynamic)
-                 + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE
-                 + sizeof (struct external_sun4_dynamic_link));
-
-  /* Set the size of the .dynsym and .hash sections.  We counted the
-     number of dynamic symbols as we read the input files.  We will
-     build the dynamic symbol table (.dynsym) and the hash table
-     (.hash) when we build the final symbol table, because until then
-     we do not know the correct value to give the symbols.  We build
-     the dynamic symbol string table (.dynstr) in a traversal of the
-     symbol table using sunos_scan_dynamic_symbol.  */
-  s = bfd_get_section_by_name (dynobj, ".dynsym");
-  BFD_ASSERT (s != NULL);
-  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;
-    }
-      
-  /* The number of buckets is just the number of symbols divided by
-     four.  To compute the final size of the hash table, we must
-     actually compute the hash table.  Normally we need exactly as
-     many entries in the hash table as there are dynamic symbols, but
-     if some of the buckets are not used we will need additional
-     entries.  In the worst case, every symbol will hash to the same
-     bucket, and we will need BUCKETCOUNT - 1 extra entries.  */
-  if (dynsymcount >= 4)
-    bucketcount = dynsymcount / 4;
-  else if (dynsymcount > 0)
-    bucketcount = dynsymcount;
-  else
-    bucketcount = 1;
-  s = bfd_get_section_by_name (dynobj, ".hash");
-  BFD_ASSERT (s != NULL);
-  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;
+      /* If the .got section is more than 0x1000 bytes, we set
+         __GLOBAL_OFFSET_TABLE_ to be 0x1000 bytes into the section,
+         so that 13 bit relocations have a greater chance of working.  */
+      s = bfd_get_section_by_name (dynobj, ".got");
+      BFD_ASSERT (s != NULL);
+      if (s->_raw_size >= 0x1000)
+       h->root.root.u.def.value = 0x1000;
+      else
+       h->root.root.u.def.value = 0;
+
+      sunos_hash_table (info)->got_base = h->root.root.u.def.value;
     }
-  memset (s->contents, 0, hashalloc);
-  for (i = 0; i < bucketcount; i++)
-    PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
-  s->_raw_size = bucketcount * HASH_ENTRY_SIZE;
-
-  sunos_hash_table (info)->bucketcount = bucketcount;
-
-  /* Scan all the symbols, place them in the dynamic symbol table, and
-     build the dynamic hash table.  We reuse dynsymcount as a counter
-     for the number of symbols we have added so far.  */
-  sunos_hash_table (info)->dynsymcount = 0;
-  sunos_link_hash_traverse (sunos_hash_table (info),
-                           sunos_scan_dynamic_symbol,
-                           (PTR) info);
-  BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount);
-
-  /* The SunOS native linker seems to align the total size of the
-     symbol strings to a multiple of 8.  I don't know if this is
-     important, but it can't hurt much.  */
-  s = bfd_get_section_by_name (dynobj, ".dynstr");
-  BFD_ASSERT (s != NULL);
-  if ((s->_raw_size & 7) != 0)
+
+  /* If there are any shared objects in the link, then we need to set
+     up the dynamic linking information.  */
+  if (sunos_hash_table (info)->dynamic_sections_needed)
     {
-      bfd_size_type add;
-      bfd_byte *contents;
+      *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic");
 
-      add = 8 - (s->_raw_size & 7);
-      contents = (bfd_byte *) realloc (s->contents,
-                                      (size_t) (s->_raw_size + add));
-      if (contents == NULL)
+      /* The .dynamic section is always the same size.  */
+      s = *sdynptr;
+      BFD_ASSERT (s != NULL);
+      s->_raw_size = (sizeof (struct external_sun4_dynamic)
+                     + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE
+                     + sizeof (struct external_sun4_dynamic_link));
+
+      /* Set the size of the .dynsym and .hash sections.  We counted
+        the number of dynamic symbols as we read the input files.  We
+        will build the dynamic symbol table (.dynsym) and the hash
+        table (.hash) when we build the final symbol table, because
+        until then we do not know the correct value to give the
+        symbols.  We build the dynamic symbol string table (.dynstr)
+        in a traversal of the symbol table using
+        sunos_scan_dynamic_symbol.  */
+      s = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (s != NULL);
+      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)
+       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 actually compute the hash table.  Normally we need
+        exactly as many entries in the hash table as there are
+        dynamic symbols, but if some of the buckets are not used we
+        will need additional entries.  In the worst case, every
+        symbol will hash to the same bucket, and we will need
+        BUCKETCOUNT - 1 extra entries.  */
+      if (dynsymcount >= 4)
+       bucketcount = dynsymcount / 4;
+      else if (dynsymcount > 0)
+       bucketcount = dynsymcount;
+      else
+       bucketcount = 1;
+      s = bfd_get_section_by_name (dynobj, ".hash");
+      BFD_ASSERT (s != NULL);
+      hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE;
+      s->contents = (bfd_byte *) bfd_zalloc (dynobj, hashalloc);
+      if (s->contents == NULL && dynsymcount > 0)
+       return false;
+      for (i = 0; i < bucketcount; i++)
+       PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE);
+      s->_raw_size = bucketcount * HASH_ENTRY_SIZE;
+
+      sunos_hash_table (info)->bucketcount = bucketcount;
+
+      /* Scan all the symbols, place them in the dynamic symbol table,
+        and build the dynamic hash table.  We reuse dynsymcount as a
+        counter for the number of symbols we have added so far.  */
+      sunos_hash_table (info)->dynsymcount = 0;
+      sunos_link_hash_traverse (sunos_hash_table (info),
+                               sunos_scan_dynamic_symbol,
+                               (PTR) info);
+      BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount);
+
+      /* The SunOS native linker seems to align the total size of the
+        symbol strings to a multiple of 8.  I don't know if this is
+        important, but it can't hurt much.  */
+      s = bfd_get_section_by_name (dynobj, ".dynstr");
+      BFD_ASSERT (s != NULL);
+      if ((s->_raw_size & 7) != 0)
        {
-         bfd_set_error (bfd_error_no_memory);
-         return false;
+         bfd_size_type add;
+         bfd_byte *contents;
+
+         add = 8 - (s->_raw_size & 7);
+         contents = (bfd_byte *) bfd_realloc (s->contents,
+                                              s->_raw_size + add);
+         if (contents == NULL)
+           return false;
+         memset (contents + s->_raw_size, 0, (size_t) add);
+         s->contents = contents;
+         s->_raw_size += add;
        }
-      memset (contents + s->_raw_size, 0, (size_t) add);
-      s->contents = contents;
-      s->_raw_size += add;
     }
 
   /* Now that we have worked out the sizes of the procedure linkage
@@ -1367,10 +1481,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))
@@ -1393,10 +1504,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.  */
@@ -1406,12 +1514,8 @@ 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");
   *srulesptr = bfd_get_section_by_name (dynobj, ".rules");
 
@@ -1434,30 +1538,27 @@ 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 (rel_size);
   else
     {
       struct aout_section_data_struct *n;
+      bfd_size_type amt = sizeof (struct aout_section_data_struct);
 
-      n = ((struct aout_section_data_struct *)
-          bfd_alloc (abfd, sizeof (struct aout_section_data_struct)));
+      n = (struct aout_section_data_struct *) bfd_alloc (abfd, amt);
       if (n == NULL)
        relocs = NULL;
       else
        {
          set_aout_section_data (sec, n);
-         relocs = malloc ((size_t) rel_size);
+         relocs = bfd_malloc (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)
+      || bfd_bread (relocs, rel_size, abfd) != rel_size)
     goto error_return;
 
   if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE)
@@ -1500,7 +1601,7 @@ static boolean
 sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size)
      struct bfd_link_info *info;
      bfd *abfd;
-     asection *sec;
+     asection *sec ATTRIBUTE_UNUSED;
      const struct reloc_std_external *relocs;
      bfd_size_type rel_size;
 {
@@ -1528,7 +1629,7 @@ sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size)
       struct sunos_link_hash_entry *h;
 
       /* We only want relocs against external symbols.  */
-      if (abfd->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (abfd))
        {
          if ((rel->r_type[0] & RELOC_STD_BITS_EXTERN_BIG) == 0)
            continue;
@@ -1540,7 +1641,7 @@ sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size)
        }
 
       /* Get the symbol index.  */
-      if (abfd->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (abfd))
        r_index = ((rel->r_index[0] << 16)
                   | (rel->r_index[1] << 8)
                   | rel->r_index[2]);
@@ -1574,12 +1675,20 @@ sunos_scan_std_relocs (info, abfd, sec, relocs, rel_size)
 
       if (dynobj == NULL)
        {
-         if (! sunos_create_dynamic_sections (abfd, info, true))
+         asection *sgot;
+
+         if (! sunos_create_dynamic_sections (abfd, info, false))
            return false;
          dynobj = sunos_hash_table (info)->dynobj;
          splt = bfd_get_section_by_name (dynobj, ".plt");
          srel = bfd_get_section_by_name (dynobj, ".dynrel");
          BFD_ASSERT (splt != NULL && srel != NULL);
+
+         sgot = bfd_get_section_by_name (dynobj, ".got");
+         BFD_ASSERT (sgot != NULL);
+         if (sgot->_raw_size == 0)
+           sgot->_raw_size = BYTES_IN_WORD;
+         sunos_hash_table (info)->got_needed = true;
        }
 
       BFD_ASSERT ((h->flags & SUNOS_REF_REGULAR) != 0);
@@ -1652,7 +1761,7 @@ static boolean
 sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
      struct bfd_link_info *info;
      bfd *abfd;
-     asection *sec;
+     asection *sec ATTRIBUTE_UNUSED;
      const struct reloc_ext_external *relocs;
      bfd_size_type rel_size;
 {
@@ -1662,6 +1771,7 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
   asection *splt = NULL;
   asection *sgot = NULL;
   asection *srel = NULL;
+  bfd_size_type amt;
 
   /* We only know how to handle SPARC plt entries.  */
   if (bfd_get_arch (abfd) != bfd_arch_sparc)
@@ -1683,7 +1793,7 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
       struct sunos_link_hash_entry *h = NULL;
 
       /* Swap in the reloc information.  */
-      if (abfd->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (abfd))
        {
          r_index = ((rel->r_index[0] << 16)
                     | (rel->r_index[1] << 8)
@@ -1721,13 +1831,18 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
        {
          if (dynobj == NULL)
            {
-             if (! sunos_create_dynamic_sections (abfd, info, true))
+             if (! sunos_create_dynamic_sections (abfd, info, false))
                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);
+
+             /* Make sure we have an initial entry in the .got table.  */
+             if (sgot->_raw_size == 0)
+               sgot->_raw_size = BYTES_IN_WORD;
+             sunos_hash_table (info)->got_needed = true;
            }
 
          if (r_extern)
@@ -1748,15 +1863,12 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
 
              if (adata (abfd).local_got_offsets == NULL)
                {
+                 amt = bfd_get_symcount (abfd);
+                 amt *= sizeof (bfd_vma);
                  adata (abfd).local_got_offsets =
-                   (bfd_vma *) bfd_zalloc (abfd,
-                                           (bfd_get_symcount (abfd)
-                                            * sizeof (bfd_vma)));
+                   (bfd_vma *) bfd_zalloc (abfd, amt);
                  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)
@@ -1821,21 +1933,38 @@ sunos_scan_ext_relocs (info, abfd, sec, relocs, rel_size)
              || (h->flags & SUNOS_DEF_REGULAR) != 0))
        continue;
 
+      if (r_type == RELOC_JMP_TBL
+         && ! info->shared
+         && (h->flags & SUNOS_DEF_DYNAMIC) == 0
+         && (h->flags & SUNOS_DEF_REGULAR) == 0)
+       {
+         /* This symbol is apparently undefined.  Don't do anything
+             here; just let the relocation routine report an undefined
+             symbol.  */
+         continue;
+       }
+
       if (strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)
        continue;
 
       if (dynobj == NULL)
        {
-         if (! sunos_create_dynamic_sections (abfd, info, true))
+         if (! sunos_create_dynamic_sections (abfd, info, false))
            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);
+
+         /* Make sure we have an initial entry in the .got table.  */
+         if (sgot->_raw_size == 0)
+           sgot->_raw_size = BYTES_IN_WORD;
+         sunos_hash_table (info)->got_needed = true;
        }
 
       BFD_ASSERT (r_type == RELOC_JMP_TBL
+                 || info->shared
                  || (h->flags & SUNOS_REF_REGULAR) != 0);
       BFD_ASSERT (r_type == RELOC_JMP_TBL
                  || info->shared
@@ -1922,6 +2051,9 @@ sunos_scan_dynamic_symbol (h, data)
 {
   struct bfd_link_info *info = (struct bfd_link_info *) data;
 
+  if (h->root.root.type == bfd_link_hash_warning)
+    h = (struct sunos_link_hash_entry *) h->root.root.u.i.link;
+
   /* Set the written flag for symbols we do not want to write out as
      part of the regular symbol table.  This is all symbols which are
      not defined in a regular object file.  For some reason symbols
@@ -1990,20 +2122,14 @@ 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;
-      strcpy (contents + s->_raw_size, h->root.root.root.string);
+      strcpy ((char *) contents + s->_raw_size, h->root.root.root.string);
       s->_raw_size += len + 1;
 
       /* Add it to the dynamic hash table.  */
@@ -2045,8 +2171,8 @@ sunos_scan_dynamic_symbol (h, data)
 /*ARGSUSED*/
 static boolean
 sunos_link_dynamic_object (info, abfd)
-     struct bfd_link_info *info;
-     bfd *abfd;
+     struct bfd_link_info *info ATTRIBUTE_UNUSED;
+     bfd *abfd ATTRIBUTE_UNUSED;
 {
   return true;
 }
@@ -2066,92 +2192,6 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
   asection *s;
   struct external_nlist *outsym;
 
-  if (h->dynindx < 0)
-    return true;
-
-  switch (h->root.root.type)
-    {
-    default:
-    case bfd_link_hash_new:
-      abort ();
-      /* Avoid variable not initialized warnings.  */
-      return true;
-    case bfd_link_hash_undefined:
-      type = N_UNDF | N_EXT;
-      val = 0;
-      break;
-    case bfd_link_hash_defined:
-    case bfd_link_hash_defweak:
-      {
-       asection *sec;
-       asection *output_section;
-
-       sec = h->root.root.u.def.section;
-       output_section = sec->output_section;
-       BFD_ASSERT (bfd_is_abs_section (output_section)
-                   || output_section->owner == output_bfd);
-       if (h->plt_offset != 0
-           && (h->flags & SUNOS_DEF_REGULAR) == 0)
-         {
-           type = N_UNDF | N_EXT;
-           val = 0;
-         }
-       else
-         {
-           if (output_section == obj_textsec (output_bfd))
-             type = (h->root.root.type == bfd_link_hash_defined
-                     ? N_TEXT
-                     : N_WEAKT);
-           else if (output_section == obj_datasec (output_bfd))
-             type = (h->root.root.type == bfd_link_hash_defined
-                     ? N_DATA
-                     : N_WEAKD);
-           else if (output_section == obj_bsssec (output_bfd))
-             type = (h->root.root.type == bfd_link_hash_defined
-                     ? N_BSS
-                     : N_WEAKB);
-           else
-             type = (h->root.root.type == bfd_link_hash_defined
-                     ? N_ABS
-                     : N_WEAKA);
-           type |= N_EXT;
-           val = (h->root.root.u.def.value
-                  + output_section->vma
-                  + sec->output_offset);
-         }
-      }
-      break;
-    case bfd_link_hash_common:
-      type = N_UNDF | N_EXT;
-      val = h->root.root.u.c.size;
-      break;
-    case bfd_link_hash_undefweak:
-      type = N_WEAKU;
-      val = 0;
-      break;
-    case bfd_link_hash_indirect:
-    case bfd_link_hash_warning:
-      /* FIXME: Ignore these for now.  The circumstances under which
-        they should be written out are not clear to me.  */
-      return true;
-    }
-
-  s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym");
-  BFD_ASSERT (s != NULL);
-  outsym = ((struct external_nlist *)
-           (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE));
-
-  bfd_h_put_8 (output_bfd, type, outsym->e_type);
-  bfd_h_put_8 (output_bfd, 0, outsym->e_other);
-
-  /* FIXME: The native linker doesn't use 0 for desc.  It seems to use
-     one less than the desc value in the shared library, although that
-     seems unlikely.  */
-  bfd_h_put_16 (output_bfd, 0, outsym->e_desc);
-
-  PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx);
-  PUT_WORD (output_bfd, val, outsym->e_value);
-
   /* If this symbol is in the procedure linkage table, fill in the
      table entry.  */
   if (h->plt_offset != 0)
@@ -2159,7 +2199,6 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
       bfd *dynobj;
       asection *splt;
       bfd_byte *p;
-      asection *s;
       bfd_vma r_address;
 
       dynobj = sunos_hash_table (info)->dynobj;
@@ -2188,8 +2227,6 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
            }
          else
            {
-             bfd_vma val;
-
              val = (h->root.root.u.def.section->output_section->vma
                     + h->root.root.u.def.section->output_offset
                     + h->root.root.u.def.value);
@@ -2208,7 +2245,7 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
            abort ();
          bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p);
          bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2);
-         bfd_put_16 (output_bfd, s->reloc_count, p + 6);
+         bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6);
          r_address += 2;
          break;
 
@@ -2220,6 +2257,7 @@ 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 (h->dynindx >= 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);
@@ -2229,19 +2267,19 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
 
              srel = (struct reloc_std_external *) p;
              PUT_WORD (output_bfd, r_address, srel->r_address);
-             if (output_bfd->xvec->header_byteorder_big_p)
+             if (bfd_header_big_endian (output_bfd))
                {
-                 srel->r_index[0] = h->dynindx >> 16;
-                 srel->r_index[1] = h->dynindx >> 8;
-                 srel->r_index[2] = h->dynindx;
+                 srel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
+                 srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 srel->r_index[2] = (bfd_byte) (h->dynindx);
                  srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG
                                     | RELOC_STD_BITS_JMPTABLE_BIG);
                }
              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] = (bfd_byte) (h->dynindx >> 16);
+                 srel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 srel->r_index[0] = (bfd_byte)h->dynindx;
                  srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE
                                     | RELOC_STD_BITS_JMPTABLE_LITTLE);
                }
@@ -2252,20 +2290,20 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
 
              erel = (struct reloc_ext_external *) p;
              PUT_WORD (output_bfd, r_address, erel->r_address);
-             if (output_bfd->xvec->header_byteorder_big_p)
+             if (bfd_header_big_endian (output_bfd))
                {
-                 erel->r_index[0] = h->dynindx >> 16;
-                 erel->r_index[1] = h->dynindx >> 8;
-                 erel->r_index[2] = h->dynindx;
+                 erel->r_index[0] = (bfd_byte) (h->dynindx >> 16);
+                 erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 erel->r_index[2] = (bfd_byte)h->dynindx;
                  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_index[2] = (bfd_byte) (h->dynindx >> 16);
+                 erel->r_index[1] = (bfd_byte) (h->dynindx >> 8);
+                 erel->r_index[0] = (bfd_byte)h->dynindx;
                  erel->r_type[0] =
                    (RELOC_EXT_BITS_EXTERN_LITTLE
                     | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE));
@@ -2277,6 +2315,96 @@ sunos_write_dynamic_symbol (output_bfd, info, harg)
        }
     }
 
+  /* If this is not a dynamic symbol, we don't have to do anything
+     else.  We only check this after handling the PLT entry, because
+     we can have a PLT entry for a nondynamic symbol when linking PIC
+     compiled code from a regular object.  */
+  if (h->dynindx < 0)
+    return true;
+
+  switch (h->root.root.type)
+    {
+    default:
+    case bfd_link_hash_new:
+      abort ();
+      /* Avoid variable not initialized warnings.  */
+      return true;
+    case bfd_link_hash_undefined:
+      type = N_UNDF | N_EXT;
+      val = 0;
+      break;
+    case bfd_link_hash_defined:
+    case bfd_link_hash_defweak:
+      {
+       asection *sec;
+       asection *output_section;
+
+       sec = h->root.root.u.def.section;
+       output_section = sec->output_section;
+       BFD_ASSERT (bfd_is_abs_section (output_section)
+                   || output_section->owner == output_bfd);
+       if (h->plt_offset != 0
+           && (h->flags & SUNOS_DEF_REGULAR) == 0)
+         {
+           type = N_UNDF | N_EXT;
+           val = 0;
+         }
+       else
+         {
+           if (output_section == obj_textsec (output_bfd))
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_TEXT
+                     : N_WEAKT);
+           else if (output_section == obj_datasec (output_bfd))
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_DATA
+                     : N_WEAKD);
+           else if (output_section == obj_bsssec (output_bfd))
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_BSS
+                     : N_WEAKB);
+           else
+             type = (h->root.root.type == bfd_link_hash_defined
+                     ? N_ABS
+                     : N_WEAKA);
+           type |= N_EXT;
+           val = (h->root.root.u.def.value
+                  + output_section->vma
+                  + sec->output_offset);
+         }
+      }
+      break;
+    case bfd_link_hash_common:
+      type = N_UNDF | N_EXT;
+      val = h->root.root.u.c.size;
+      break;
+    case bfd_link_hash_undefweak:
+      type = N_WEAKU;
+      val = 0;
+      break;
+    case bfd_link_hash_indirect:
+    case bfd_link_hash_warning:
+      /* FIXME: Ignore these for now.  The circumstances under which
+        they should be written out are not clear to me.  */
+      return true;
+    }
+
+  s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym");
+  BFD_ASSERT (s != NULL);
+  outsym = ((struct external_nlist *)
+           (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE));
+
+  H_PUT_8 (output_bfd, type, outsym->e_type);
+  H_PUT_8 (output_bfd, 0, outsym->e_other);
+
+  /* FIXME: The native linker doesn't use 0 for desc.  It seems to use
+     one less than the desc value in the shared library, although that
+     seems unlikely.  */
+  H_PUT_16 (output_bfd, 0, outsym->e_desc);
+
+  PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx);
+  PUT_WORD (output_bfd, val, outsym->e_value);
+
   return true;
 }
 
@@ -2294,7 +2422,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
      asection *input_section;
      struct aout_link_hash_entry *harg;
      PTR reloc;
-     bfd_byte *contents;
+     bfd_byte *contents ATTRIBUTE_UNUSED;
      boolean *skip;
      bfd_vma *relocationp;
 {
@@ -2302,6 +2430,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
   bfd *dynobj;
   boolean baserel;
   boolean jmptbl;
+  boolean pcrel;
   asection *s;
   bfd_byte *p;
   long indx;
@@ -2310,7 +2439,10 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
 
   dynobj = sunos_hash_table (info)->dynobj;
 
-  if (h != NULL && h->plt_offset != 0)
+  if (h != NULL
+      && h->plt_offset != 0
+      && (info->shared
+         || (h->flags & SUNOS_DEF_REGULAR) == 0))
     {
       asection *splt;
 
@@ -2326,15 +2458,17 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
       struct reloc_std_external *srel;
 
       srel = (struct reloc_std_external *) reloc;
-      if (input_bfd->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (input_bfd))
        {
          baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG));
          jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG));
+         pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_BIG));
        }
       else
        {
          baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE));
          jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE));
+         pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE));
        }
     }
   else
@@ -2343,7 +2477,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
       int r_type;
 
       erel = (struct reloc_ext_external *) reloc;
-      if (input_bfd->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (input_bfd))
        r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG)
                  >> RELOC_EXT_BITS_TYPE_SH_BIG);
       else
@@ -2353,6 +2487,13 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                 || r_type == RELOC_BASE13
                 || r_type == RELOC_BASE22);
       jmptbl = r_type == RELOC_JMP_TBL;
+      pcrel = (r_type == RELOC_DISP8
+              || r_type == RELOC_DISP16
+              || r_type == RELOC_DISP32
+              || r_type == RELOC_WDISP30
+              || r_type == RELOC_WDISP22);
+      /* We don't consider the PC10 and PC22 types to be PC relative,
+         because they are pcrel_offset.  */
     }
 
   if (baserel)
@@ -2372,7 +2513,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
          srel = (struct reloc_std_external *) reloc;
          if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE)
            {
-             if (input_bfd->xvec->header_byteorder_big_p)
+             if (bfd_header_big_endian (input_bfd))
                r_index = ((srel->r_index[0] << 16)
                           | (srel->r_index[1] << 8)
                           | srel->r_index[2]);
@@ -2386,7 +2527,7 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
              struct reloc_ext_external *erel;
 
              erel = (struct reloc_ext_external *) reloc;
-             if (input_bfd->xvec->header_byteorder_big_p)
+             if (bfd_header_big_endian (input_bfd))
                r_index = ((erel->r_index[0] << 16)
                           | (erel->r_index[1] << 8)
                           | erel->r_index[2]);
@@ -2446,11 +2587,11 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                             + sgot->output_section->vma
                             + sgot->output_offset),
                            srel->r_address);
-                 if (dynobj->xvec->header_byteorder_big_p)
+                 if (bfd_header_big_endian (dynobj))
                    {
-                     srel->r_index[0] = indx >> 16;
-                     srel->r_index[1] = indx >> 8;
-                     srel->r_index[2] = indx;
+                     srel->r_index[0] = (bfd_byte) (indx >> 16);
+                     srel->r_index[1] = (bfd_byte) (indx >> 8);
+                     srel->r_index[2] = (bfd_byte)indx;
                      if (h == NULL)
                        srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG;
                      else
@@ -2462,9 +2603,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                    }
                  else
                    {
-                     srel->r_index[2] = indx >> 16;
-                     srel->r_index[1] = indx >> 8;
-                     srel->r_index[0] = indx;
+                     srel->r_index[2] = (bfd_byte) (indx >> 16);
+                     srel->r_index[1] = (bfd_byte) (indx >> 8);
+                     srel->r_index[0] = (bfd_byte)indx;
                      if (h == NULL)
                        srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE;
                      else
@@ -2485,11 +2626,11 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                             + sgot->output_section->vma
                             + sgot->output_offset),
                            erel->r_address);
-                 if (dynobj->xvec->header_byteorder_big_p)
+                 if (bfd_header_big_endian (dynobj))
                    {
-                     erel->r_index[0] = indx >> 16;
-                     erel->r_index[1] = indx >> 8;
-                     erel->r_index[2] = indx;
+                     erel->r_index[0] = (bfd_byte) (indx >> 16);
+                     erel->r_index[1] = (bfd_byte) (indx >> 8);
+                     erel->r_index[2] = (bfd_byte)indx;
                      if (h == NULL)
                        erel->r_type[0] =
                          RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG;
@@ -2500,9 +2641,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                    }
                  else
                    {
-                     erel->r_index[2] = indx >> 16;
-                     erel->r_index[1] = indx >> 8;
-                     erel->r_index[0] = indx;
+                     erel->r_index[2] = (bfd_byte) (indx >> 16);
+                     erel->r_index[1] = (bfd_byte) (indx >> 8);
+                     erel->r_index[0] = (bfd_byte)indx;
                      if (h == NULL)
                        erel->r_type[0] =
                          RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE;
@@ -2521,7 +2662,9 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
          *got_offsetp |= 1;
        }
 
-      *relocationp = sgot->vma + (*got_offsetp &~ 1);
+      *relocationp = (sgot->vma
+                     + (*got_offsetp &~ (bfd_vma) 1)
+                     - sunos_hash_table (info)->got_base);
 
       /* There is nothing else to do for a base relative reloc.  */
       return true;
@@ -2576,18 +2719,20 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                 + input_section->output_section->vma
                 + input_section->output_offset),
                srel->r_address);
-      if (dynobj->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (dynobj))
        {
-         srel->r_index[0] = indx >> 16;
-         srel->r_index[1] = indx >> 8;
-         srel->r_index[2] = indx;
+         srel->r_index[0] = (bfd_byte) (indx >> 16);
+         srel->r_index[1] = (bfd_byte) (indx >> 8);
+         srel->r_index[2] = (bfd_byte)indx;
        }
       else
        {
-         srel->r_index[2] = indx >> 16;
-         srel->r_index[1] = indx >> 8;
-         srel->r_index[0] = indx;
+         srel->r_index[2] = (bfd_byte) (indx >> 16);
+         srel->r_index[1] = (bfd_byte) (indx >> 8);
+         srel->r_index[0] = (bfd_byte)indx;
        }
+      /* FIXME: We may have to change the addend for a PC relative
+         reloc.  */
     }
   else
     {
@@ -2599,17 +2744,27 @@ sunos_check_dynamic_reloc (info, input_bfd, input_section, harg, reloc,
                 + input_section->output_section->vma
                 + input_section->output_offset),
                erel->r_address);
-      if (dynobj->xvec->header_byteorder_big_p)
+      if (bfd_header_big_endian (dynobj))
        {
-         erel->r_index[0] = indx >> 16;
-         erel->r_index[1] = indx >> 8;
-         erel->r_index[2] = indx;
+         erel->r_index[0] = (bfd_byte) (indx >> 16);
+         erel->r_index[1] = (bfd_byte) (indx >> 8);
+         erel->r_index[2] = (bfd_byte)indx;
        }
       else
        {
-         erel->r_index[2] = indx >> 16;
-         erel->r_index[1] = indx >> 8;
-         erel->r_index[0] = indx;
+         erel->r_index[2] = (bfd_byte) (indx >> 16);
+         erel->r_index[1] = (bfd_byte) (indx >> 8);
+         erel->r_index[0] = (bfd_byte)indx;
+       }
+      if (pcrel && h != NULL)
+       {
+         /* Adjust the addend for the change in address.  */
+         PUT_WORD (dynobj,
+                   (GET_WORD (dynobj, erel->r_addend)
+                    - (input_section->output_section->vma
+                       + input_section->output_offset
+                       - input_section->vma)),
+                   erel->r_addend);
        }
     }
 
@@ -2632,10 +2787,9 @@ sunos_finish_dynamic_link (abfd, info)
   asection *o;
   asection *s;
   asection *sdyn;
-  struct external_sun4_dynamic esd;
-  struct external_sun4_dynamic_link esdl;
 
-  if (! sunos_hash_table (info)->dynamic_sections_needed)
+  if (! sunos_hash_table (info)->dynamic_sections_needed
+      && ! sunos_hash_table (info)->got_needed)
     return true;
 
   dynobj = sunos_hash_table (info)->dynobj;
@@ -2672,7 +2826,7 @@ sunos_finish_dynamic_link (abfd, info)
      dynamic information, unless this is a shared library.  */
   s = bfd_get_section_by_name (dynobj, ".got");
   BFD_ASSERT (s != NULL);
-  if (info->shared)
+  if (info->shared || sdyn->_raw_size == 0)
     PUT_WORD (dynobj, 0, s->contents);
   else
     PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset,
@@ -2686,96 +2840,106 @@ sunos_finish_dynamic_link (abfd, info)
          BFD_ASSERT (o->output_section != NULL
                      && o->output_section->owner == abfd);
          if (! bfd_set_section_contents (abfd, o->output_section,
-                                         o->contents, o->output_offset,
+                                         o->contents,
+                                         (file_ptr) o->output_offset,
                                          o->_raw_size))
            return false;
        }
     }
 
-  /* Finish up the dynamic link information.  */
-  PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version);
-  PUT_WORD (dynobj,
-           sdyn->output_section->vma + sdyn->output_offset + sizeof esd,
-           esd.ldd);
-  PUT_WORD (dynobj,
-           (sdyn->output_section->vma
-            + sdyn->output_offset
-            + sizeof esd
-            + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
-           esd.ld);
-
-  if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd,
-                                 sdyn->output_offset, sizeof esd))
-    return false;
+  if (sdyn->_raw_size > 0)
+    {
+      struct external_sun4_dynamic esd;
+      struct external_sun4_dynamic_link esdl;
+      file_ptr pos;
 
+      /* Finish up the dynamic link information.  */
+      PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version);
+      PUT_WORD (dynobj,
+               sdyn->output_section->vma + sdyn->output_offset + sizeof esd,
+               esd.ldd);
+      PUT_WORD (dynobj,
+               (sdyn->output_section->vma
+                + sdyn->output_offset
+                + sizeof esd
+                + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
+               esd.ld);
+
+      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd,
+                                     (file_ptr) sdyn->output_offset,
+                                     (bfd_size_type) sizeof esd))
+       return false;
 
-  PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded);
+      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded);
 
-  s = bfd_get_section_by_name (dynobj, ".need");
-  if (s == NULL || s->_raw_size == 0)
-    PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need);
-  else
-    PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
-             esdl.ld_need);
+      s = bfd_get_section_by_name (dynobj, ".need");
+      if (s == NULL || s->_raw_size == 0)
+       PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need);
+      else
+       PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+                 esdl.ld_need);
 
-  s = bfd_get_section_by_name (dynobj, ".rules");
-  if (s == NULL || s->_raw_size == 0)
-    PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules);
-  else
-    PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
-             esdl.ld_rules);
+      s = bfd_get_section_by_name (dynobj, ".rules");
+      if (s == NULL || s->_raw_size == 0)
+       PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules);
+      else
+       PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+                 esdl.ld_rules);
 
-  s = bfd_get_section_by_name (dynobj, ".got");
-  BFD_ASSERT (s != NULL);
-  PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_got);
+      s = bfd_get_section_by_name (dynobj, ".got");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
+               esdl.ld_got);
 
-  s = bfd_get_section_by_name (dynobj, ".plt");
-  BFD_ASSERT (s != NULL);
-  PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_plt);
-  PUT_WORD (dynobj, s->_raw_size, esdl.ld_plt_sz);
+      s = bfd_get_section_by_name (dynobj, ".plt");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->vma + s->output_offset,
+               esdl.ld_plt);
+      PUT_WORD (dynobj, s->_raw_size, esdl.ld_plt_sz);
 
-  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);
-  PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
-           esdl.ld_rel);
+      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);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_rel);
 
-  s = bfd_get_section_by_name (dynobj, ".hash");
-  BFD_ASSERT (s != NULL);
-  PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
-           esdl.ld_hash);
+      s = bfd_get_section_by_name (dynobj, ".hash");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_hash);
 
-  s = bfd_get_section_by_name (dynobj, ".dynsym");
-  BFD_ASSERT (s != NULL);
-  PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
-           esdl.ld_stab);
+      s = bfd_get_section_by_name (dynobj, ".dynsym");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_stab);
 
-  PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash);
+      PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash);
 
-  PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount,
-           esdl.ld_buckets);
+      PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount,
+               esdl.ld_buckets);
 
-  s = bfd_get_section_by_name (dynobj, ".dynstr");
-  BFD_ASSERT (s != NULL);
-  PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
-           esdl.ld_symbols);
-  PUT_WORD (dynobj, s->_raw_size, esdl.ld_symb_size);
-
-  /* The size of the text area is the size of the .text section
-     rounded up to a page boundary.  FIXME: Should the page size be
-     conditional on something?  */
-  PUT_WORD (dynobj,
-           BFD_ALIGN (obj_textsec (abfd)->_raw_size, 0x2000),
-           esdl.ld_text);
-  
-  if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl,
-                                 (sdyn->output_offset
-                                  + sizeof esd
-                                  + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE),
-                                 sizeof esdl))
-    return false;
+      s = bfd_get_section_by_name (dynobj, ".dynstr");
+      BFD_ASSERT (s != NULL);
+      PUT_WORD (dynobj, s->output_section->filepos + s->output_offset,
+               esdl.ld_symbols);
+      PUT_WORD (dynobj, s->_raw_size, esdl.ld_symb_size);
 
-  abfd->flags |= DYNAMIC;
+      /* The size of the text area is the size of the .text section
+        rounded up to a page boundary.  FIXME: Should the page size be
+        conditional on something?  */
+      PUT_WORD (dynobj,
+               BFD_ALIGN (obj_textsec (abfd)->_raw_size, 0x2000),
+               esdl.ld_text);
+
+      pos = sdyn->output_offset;
+      pos += sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE;
+      if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl,
+                                     pos, (bfd_size_type) sizeof esdl))
+       return false;
+
+      abfd->flags |= DYNAMIC;
+    }
 
   return true;
 }
This page took 0.049169 seconds and 4 git commands to generate.