* xcofflink.c (_bfd_xcoff_bfd_link_add_symbols): Look through the
authorIan Lance Taylor <ian@airs.com>
Wed, 24 Apr 1996 18:10:46 +0000 (18:10 +0000)
committerIan Lance Taylor <ian@airs.com>
Wed, 24 Apr 1996 18:10:46 +0000 (18:10 +0000)
members of an archive for dynamic objects with no symbols, and
pass them directly to check_archive_element.
(xcoff_link_check_ar_symbols): Pass dynamic objects to
xcoff_link_check_dynamic_ar_symbols.
(xcoff_link_check_dynamic_ar_symbols): New static function.
The above is for PR 9520.

* coff-rs6000.c (rs6000coff_vec): Change BFD_JUMP_TABLE_DYNAMIC
from _bfd_nodynamic to _bfd_xcoff.
* libcoff-in.h (_bfd_xcoff_get_dynamic_symtab_upper_bound):
Declare.
(_bfd_xcoff_canonicalize_dynamic_symtab): Declare.
(_bfd_xcoff_get_dynamic_reloc_upper_bound): Declare.
(_bfd_xcoff_canonicalize_dynamic_reloc): Declare.
* libcoff.h: Rebuild.
* xcofflink.c (xcoff_swap_ldrel_in): New static function.
(xcoff_get_section_contents): New static function.
(_bfd_xcoff_get_dynamic_symtab_upper_bound): New function.
(_bfd_xcoff_canonicalize_dynamic_symtab): New function.
(_bfd_xcoff_get_dynamic_reloc_upper_bound): New function.
(xcoff_dynamic_reloc): New static variable.
(_bfd_xcoff_canonicalize_dynamic_reloc): New function.
(xcoff_link_add_dynamic_symbols): Use xcoff_get_section_contents.

bfd/ChangeLog
bfd/libcoff-in.h
bfd/libcoff.h
bfd/xcofflink.c

index e022ca55f06d75e5bab1c0f4840268db9b4fc09e..ab619ce7a99f5eb54becae8f86292fe517660404 100644 (file)
@@ -1,3 +1,35 @@
+Wed Apr 24 14:04:07 1996  Ian Lance Taylor  <ian@cygnus.com>
+
+       * xcofflink.c (_bfd_xcoff_bfd_link_add_symbols): Look through the
+       members of an archive for dynamic objects with no symbols, and
+       pass them directly to check_archive_element.
+       (xcoff_link_check_ar_symbols): Pass dynamic objects to
+       xcoff_link_check_dynamic_ar_symbols.
+       (xcoff_link_check_dynamic_ar_symbols): New static function.
+
+       * coff-rs6000.c (rs6000coff_vec): Change BFD_JUMP_TABLE_DYNAMIC
+       from _bfd_nodynamic to _bfd_xcoff.
+       * libcoff-in.h (_bfd_xcoff_get_dynamic_symtab_upper_bound):
+       Declare.
+       (_bfd_xcoff_canonicalize_dynamic_symtab): Declare.
+       (_bfd_xcoff_get_dynamic_reloc_upper_bound): Declare.
+       (_bfd_xcoff_canonicalize_dynamic_reloc): Declare.
+       * libcoff.h: Rebuild.
+       * xcofflink.c (xcoff_swap_ldrel_in): New static function.
+       (xcoff_get_section_contents): New static function.
+       (_bfd_xcoff_get_dynamic_symtab_upper_bound): New function.
+       (_bfd_xcoff_canonicalize_dynamic_symtab): New function.
+       (_bfd_xcoff_get_dynamic_reloc_upper_bound): New function.
+       (xcoff_dynamic_reloc): New static variable.
+       (_bfd_xcoff_canonicalize_dynamic_reloc): New function.
+       (xcoff_link_add_dynamic_symbols): Use xcoff_get_section_contents.
+       
+Tue Apr 23 12:48:42 1996  Ian Lance Taylor  <ian@cygnus.com>
+
+       * coff-sparc.c (bfd_coff_generic_reloc): Return bfd_reloc_ok even
+       if reloc_entry->addend is not 0.
+       (CALC_ADDEND): Just set the addend to reloc.r_offset.
+
 Mon Apr 22 18:29:01 1996  Doug Evans  <dje@canuck.cygnus.com>
 
        * elf32-sparc.c (_bfd_sparc_elf_howto_table): Fix spelling of
index e2242f581d93f450af5ac3fc188b1944a47edb6c..aa1f530cd00ec9f34e13ed8976cf4f864f5c0f17 100644 (file)
@@ -177,6 +177,8 @@ struct coff_section_tdata
   unsigned int i;
   const char *function;
   int line_base;
+  /* A pointer used for .stab linking optimizations.  */
+  PTR stab_info;
   /* Available for individual backends.  */
   PTR tdata;
 };
@@ -236,6 +238,8 @@ struct coff_link_hash_entry
 struct coff_link_hash_table
 {
   struct bfd_link_hash_table root;
+  /* A pointer to information used to link stabs in sections.  */
+  PTR stab_info;
 };
 
 /* Look up an entry in a COFF linker hash table.  */
@@ -473,6 +477,12 @@ extern boolean _bfd_coff_reloc_link_order
 
 /* Functions in xcofflink.c.  */
 
+extern long _bfd_xcoff_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
+extern long _bfd_xcoff_canonicalize_dynamic_symtab
+  PARAMS ((bfd *, asymbol **));
+extern long _bfd_xcoff_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
+extern long _bfd_xcoff_canonicalize_dynamic_reloc
+  PARAMS ((bfd *, arelent **, asymbol **));
 extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create
   PARAMS ((bfd *));
 extern boolean _bfd_xcoff_bfd_link_add_symbols
index 2614310b8db3d102c9e41f8e3dbc02aae97c6250..307e2f70f3505eb56d65e41f9756f05857b0c968 100644 (file)
@@ -177,6 +177,8 @@ struct coff_section_tdata
   unsigned int i;
   const char *function;
   int line_base;
+  /* A pointer used for .stab linking optimizations.  */
+  PTR stab_info;
   /* Available for individual backends.  */
   PTR tdata;
 };
@@ -236,6 +238,8 @@ struct coff_link_hash_entry
 struct coff_link_hash_table
 {
   struct bfd_link_hash_table root;
+  /* A pointer to information used to link stabs in sections.  */
+  PTR stab_info;
 };
 
 /* Look up an entry in a COFF linker hash table.  */
@@ -473,6 +477,12 @@ extern boolean _bfd_coff_reloc_link_order
 
 /* Functions in xcofflink.c.  */
 
+extern long _bfd_xcoff_get_dynamic_symtab_upper_bound PARAMS ((bfd *));
+extern long _bfd_xcoff_canonicalize_dynamic_symtab
+  PARAMS ((bfd *, asymbol **));
+extern long _bfd_xcoff_get_dynamic_reloc_upper_bound PARAMS ((bfd *));
+extern long _bfd_xcoff_canonicalize_dynamic_reloc
+  PARAMS ((bfd *, arelent **, asymbol **));
 extern struct bfd_link_hash_table *_bfd_xcoff_bfd_link_hash_table_create
   PARAMS ((bfd *));
 extern boolean _bfd_xcoff_bfd_link_add_symbols
index ed4c2b8ae9e8f8c031a70eb4f68d4f5ee5d57cbd..4e1bfa7e9e3cfdc4990157c8f2d6381c61f66239 100644 (file)
@@ -435,6 +435,8 @@ static void xcoff_swap_ldsym_in
   PARAMS ((bfd *, const struct external_ldsym *, struct internal_ldsym *));
 static void xcoff_swap_ldsym_out
   PARAMS ((bfd *, const struct internal_ldsym *, struct external_ldsym *));
+static void xcoff_swap_ldrel_in
+  PARAMS ((bfd *, const struct external_ldrel *, struct internal_ldrel *));
 static void xcoff_swap_ldrel_out
   PARAMS ((bfd *, const struct internal_ldrel *, struct external_ldrel *));
 static struct bfd_hash_entry *xcoff_link_hash_newfunc
@@ -448,6 +450,8 @@ static boolean xcoff_link_check_archive_element
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static boolean xcoff_link_check_ar_symbols
   PARAMS ((bfd *, struct bfd_link_info *, boolean *));
+static boolean xcoff_link_check_dynamic_ar_symbols
+  PARAMS ((bfd *, struct bfd_link_info *, boolean *));
 static bfd_size_type xcoff_find_reloc
   PARAMS ((struct internal_reloc *, bfd_size_type, bfd_vma));
 static boolean xcoff_link_add_symbols PARAMS ((bfd *, struct bfd_link_info *));
@@ -553,7 +557,19 @@ xcoff_swap_ldsym_out (abfd, src, dst)
   bfd_put_32 (abfd, src->l_parm, dst->l_parm);
 }
 
-/* As it happens, we never need to swap in the ldrel structure.  */
+/* Swap in the ldrel structure.  */
+
+static void
+xcoff_swap_ldrel_in (abfd, src, dst)
+     bfd *abfd;
+     const struct external_ldrel *src;
+     struct internal_ldrel *dst;
+{
+  dst->l_vaddr = bfd_get_32 (abfd, src->l_vaddr);
+  dst->l_symndx = bfd_get_32 (abfd, src->l_symndx);
+  dst->l_rtype = bfd_get_16 (abfd, src->l_rtype);
+  dst->l_rsecnm = bfd_get_16 (abfd, src->l_rsecnm);
+}
 
 /* Swap out the ldrel structure.  */
 
@@ -569,6 +585,316 @@ xcoff_swap_ldrel_out (abfd, src, dst)
   bfd_put_16 (abfd, src->l_rsecnm, dst->l_rsecnm);
 }
 \f
+/* Routines to read XCOFF dynamic information.  This don't really
+   belong here, but we already have the ldsym manipulation routines
+   here.  */
+
+/* Read the contents of a section.  */
+
+static boolean
+xcoff_get_section_contents (abfd, sec)
+     bfd *abfd;
+     asection *sec;
+{
+  if (coff_section_data (abfd, sec) == NULL)
+    {
+      sec->used_by_bfd = bfd_zalloc (abfd,
+                                    sizeof (struct coff_section_tdata));
+      if (sec->used_by_bfd == NULL)
+       return false;
+    }
+
+  if (coff_section_data (abfd, sec)->contents == NULL)
+    {
+      coff_section_data (abfd, sec)->contents = bfd_malloc (sec->_raw_size);
+      if (coff_section_data (abfd, sec)->contents == NULL)
+       return false;
+
+      if (! bfd_get_section_contents (abfd, sec,
+                                     coff_section_data (abfd, sec)->contents,
+                                     (file_ptr) 0, sec->_raw_size))
+       return false;
+    }
+
+  return true;
+}
+
+/* Get the size required to hold the dynamic symbols.  */
+
+long
+_bfd_xcoff_get_dynamic_symtab_upper_bound (abfd)
+     bfd *abfd;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  return (ldhdr.l_nsyms + 1) * sizeof (asymbol *);
+}
+
+/* Get the dynamic symbols.  */
+
+long
+_bfd_xcoff_canonicalize_dynamic_symtab (abfd, psyms)
+     bfd *abfd;
+     asymbol **psyms;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
+  coff_symbol_type *symbuf;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  coff_section_data (abfd, lsec)->keep_contents = true;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  strings = (char *) contents + ldhdr.l_stoff;
+
+  symbuf = ((coff_symbol_type *)
+           bfd_zalloc (abfd, ldhdr.l_nsyms * sizeof (coff_symbol_type)));
+  if (symbuf == NULL)
+    return -1;
+
+  elsym = (struct external_ldsym *) (contents + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  for (; elsym < elsymend; elsym++, symbuf++, psyms++)
+    {
+      struct internal_ldsym ldsym;
+
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+      symbuf->symbol.the_bfd = abfd;
+
+      if (ldsym._l._l_l._l_zeroes == 0)
+       symbuf->symbol.name = strings + ldsym._l._l_l._l_offset;
+      else
+       {
+         int i;
+
+         for (i = 0; i < SYMNMLEN; i++)
+           if (ldsym._l._l_name[i] == '\0')
+             break;
+         if (i < SYMNMLEN)
+           symbuf->symbol.name = elsym->_l._l_name;
+         else
+           {
+             char *c;
+
+             c = bfd_alloc (abfd, SYMNMLEN + 1);
+             if (c == NULL)
+               return -1;
+             memcpy (c, ldsym._l._l_name, SYMNMLEN);
+             c[SYMNMLEN] = '\0';
+             symbuf->symbol.name = c;
+           }
+       }
+
+      if (ldsym.l_smclas == XMC_XO)
+       symbuf->symbol.section = bfd_abs_section_ptr;
+      else
+       symbuf->symbol.section = coff_section_from_bfd_index (abfd,
+                                                             ldsym.l_scnum);
+      symbuf->symbol.value = ldsym.l_value - symbuf->symbol.section->vma;
+
+      symbuf->symbol.flags = BSF_NO_FLAGS;
+      if ((ldsym.l_smtype & L_EXPORT) != 0)
+       symbuf->symbol.flags |= BSF_GLOBAL;
+
+      /* FIXME: We have no way to record the other information stored
+         with the loader symbol.  */
+
+      *psyms = (asymbol *) symbuf;
+    }
+
+  *psyms = NULL;
+
+  return ldhdr.l_nsyms;
+}
+
+/* Get the size required to hold the dynamic relocs.  */
+
+long
+_bfd_xcoff_get_dynamic_reloc_upper_bound (abfd)
+     bfd *abfd;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  return (ldhdr.l_nreloc + 1) * sizeof (arelent *);
+}
+
+/* The typical dynamic reloc.  */
+
+static reloc_howto_type xcoff_dynamic_reloc =
+  HOWTO (0,                    /* type */                                 
+        0,                     /* rightshift */                           
+        2,                     /* size (0 = byte, 1 = short, 2 = long) */ 
+        32,                    /* bitsize */                   
+        false,                 /* pc_relative */                          
+        0,                     /* bitpos */                               
+        complain_overflow_bitfield, /* complain_on_overflow */
+        0,                     /* special_function */                     
+        "R_POS",               /* name */                                 
+        true,                  /* partial_inplace */                      
+        0xffffffff,            /* src_mask */                             
+        0xffffffff,            /* dst_mask */                             
+        false);                /* pcrel_offset */
+
+/* Get the dynamic relocs.  */
+
+long
+_bfd_xcoff_canonicalize_dynamic_reloc (abfd, prelocs, syms)
+     bfd *abfd;
+     arelent **prelocs;
+     asymbol **syms;
+{
+  asection *lsec;
+  bfd_byte *contents;
+  struct internal_ldhdr ldhdr;
+  arelent *relbuf;
+  struct external_ldrel *elrel, *elrelend;
+
+  if ((abfd->flags & DYNAMIC) == 0)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return -1;
+    }
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      bfd_set_error (bfd_error_no_symbols);
+      return -1;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return -1;
+  contents = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) contents, &ldhdr);
+
+  relbuf = (arelent *) bfd_alloc (abfd, ldhdr.l_nreloc * sizeof (arelent));
+  if (relbuf == NULL)
+    return -1;
+
+  elrel = ((struct external_ldrel *)
+          (contents + LDHDRSZ + ldhdr.l_nsyms * LDSYMSZ));
+  elrelend = elrel + ldhdr.l_nreloc;
+  for (; elrel < elrelend; elrel++, relbuf++, prelocs++)
+    {
+      struct internal_ldrel ldrel;
+
+      xcoff_swap_ldrel_in (abfd, elrel, &ldrel);
+
+      if (ldrel.l_symndx >= 3)
+       relbuf->sym_ptr_ptr = syms + (ldrel.l_symndx - 3);
+      else
+       {
+         const char *name;
+         asection *sec;
+
+         switch (ldrel.l_symndx)
+           {
+           case 0:
+             name = ".text";
+             break;
+           case 1:
+             name = ".data";
+             break;
+           case 2:
+             name = ".bss";
+             break;
+           default:
+             abort ();
+             break;
+           }
+
+         sec = bfd_get_section_by_name (abfd, name);
+         if (sec == NULL)
+           {
+             bfd_set_error (bfd_error_bad_value);
+             return -1;
+           }
+
+         relbuf->sym_ptr_ptr = sec->symbol_ptr_ptr;
+       }
+
+      relbuf->address = ldrel.l_vaddr;
+      relbuf->addend = 0;
+
+      /* Most dynamic relocs have the same type.  FIXME: This is only
+         correct if ldrel.l_rtype == 0.  In other cases, we should use
+         a different howto.  */
+      relbuf->howto = &xcoff_dynamic_reloc;
+
+      /* FIXME: We have no way to record the l_rsecnm field.  */
+
+      *prelocs = relbuf;
+    }
+
+  *prelocs = NULL;
+
+  return ldhdr.l_nreloc;
+}
+\f
 /* Routine to create an entry in an XCOFF link hash table.  */
 
 static struct bfd_hash_entry *
@@ -736,8 +1062,34 @@ _bfd_xcoff_bfd_link_add_symbols (abfd, info)
     case bfd_object:
       return xcoff_link_add_object_symbols (abfd, info);
     case bfd_archive:
-      return (_bfd_generic_link_add_archive_symbols
-             (abfd, info, xcoff_link_check_archive_element));
+      /* We need to look through the archive for stripped dynamic
+         objects, because they will not appear in the archive map even
+         though they should, perhaps, be included.  */
+      {
+       bfd *member;
+
+       member = bfd_openr_next_archived_file (abfd, (bfd *) NULL);
+       while (member != NULL)
+         {
+           if (bfd_check_format (member, bfd_object)
+               && (member->flags & DYNAMIC) != 0
+               && (member->flags & HAS_SYMS) == 0)
+             {
+               boolean needed;
+
+               if (! xcoff_link_check_archive_element (member, info, &needed))
+                 return false;
+               if (needed)
+                 member->archive_pass = -1;
+             }
+           member = bfd_openr_next_archived_file (abfd, member);
+         }
+
+       /* Now do the usual search.  */
+       return (_bfd_generic_link_add_archive_symbols
+               (abfd, info, xcoff_link_check_archive_element));
+      }
+
     default:
       bfd_set_error (bfd_error_wrong_format);
       return false;
@@ -810,6 +1162,11 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
 
   *pneeded = false;
 
+  if ((abfd->flags & DYNAMIC) != 0
+      && ! info->static_link
+      && info->hash->creator == abfd->xvec)
+    return xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded);
+
   symesz = bfd_coff_symesz (abfd);
   esym = (bfd_byte *) obj_coff_external_syms (abfd);
   esym_end = esym + obj_raw_syment_count (abfd) * symesz;
@@ -855,6 +1212,87 @@ xcoff_link_check_ar_symbols (abfd, info, pneeded)
   return true;
 }
 
+/* Look through the loader symbols to see if this dynamic object
+   should be included in the link.  The native linker uses the loader
+   symbols, not the normal symbol table, so we do too.  */
+
+static boolean
+xcoff_link_check_dynamic_ar_symbols (abfd, info, pneeded)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     boolean *pneeded;
+{
+  asection *lsec;
+  bfd_byte *buf;
+  struct internal_ldhdr ldhdr;
+  const char *strings;
+  struct external_ldsym *elsym, *elsymend;
+
+  *pneeded = false;
+
+  lsec = bfd_get_section_by_name (abfd, ".loader");
+  if (lsec == NULL)
+    {
+      /* There are no symbols, so don't try to include it.  */
+      return true;
+    }
+
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return false;
+  buf = coff_section_data (abfd, lsec)->contents;
+
+  xcoff_swap_ldhdr_in (abfd, (struct external_ldhdr *) buf, &ldhdr);
+
+  strings = (char *) buf + ldhdr.l_stoff;
+
+  elsym = (struct external_ldsym *) (buf + LDHDRSZ);
+  elsymend = elsym + ldhdr.l_nsyms;
+  for (; elsym < elsymend; elsym++)
+    {
+      struct internal_ldsym ldsym;
+      char nambuf[SYMNMLEN + 1];
+      const char *name;
+      struct bfd_link_hash_entry *h;
+
+      xcoff_swap_ldsym_in (abfd, elsym, &ldsym);
+
+      /* We are only interested in exported symbols.  */
+      if ((ldsym.l_smtype & L_EXPORT) == 0)
+       continue;
+
+      if (ldsym._l._l_l._l_zeroes == 0)
+       name = strings + ldsym._l._l_l._l_offset;
+      else
+       {
+         memcpy (nambuf, ldsym._l._l_name, SYMNMLEN);
+         nambuf[SYMNMLEN] = '\0';
+         name = nambuf;
+       }
+
+      h = bfd_link_hash_lookup (info->hash, name, false, false, true);
+
+      /* We are only interested in symbols that are currently
+         undefined.  */
+      if (h != NULL && h->type == bfd_link_hash_undefined)
+       {
+         if (! (*info->callbacks->add_archive_element) (info, abfd, name))
+           return false;
+         *pneeded = true;
+         return true;
+       }
+    }
+
+  /* We do not need this shared object.  */
+
+  if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
+    {
+      free (coff_section_data (abfd, lsec)->contents);
+      coff_section_data (abfd, lsec)->contents = NULL;
+    }
+
+  return true;
+}
+
 /* Returns the index of reloc in RELOCS with the least address greater
    than or equal to ADDRESS.  The relocs are sorted by address.  */
 
@@ -1903,7 +2341,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
      struct bfd_link_info *info;
 {
   asection *lsec;
-  bfd_byte *buf = NULL;
+  bfd_byte *buf;
   struct internal_ldhdr ldhdr;
   const char *strings;
   struct external_ldsym *elsym, *elsymend;
@@ -1922,7 +2360,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        ("%s: XCOFF shared object when not producing XCOFF output",
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_invalid_operation);
-      goto error_return;
+      return false;
     }
 
   /* The symbols we use from a dynamic object are not the symbols in
@@ -1943,16 +2381,12 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        ("%s: dynamic object with no .loader section",
         bfd_get_filename (abfd));
       bfd_set_error (bfd_error_no_symbols);
-      goto error_return;
+      return false;
     }
 
-  buf = (bfd_byte *) bfd_malloc (lsec->_raw_size);
-  if (buf == NULL && lsec->_raw_size > 0)
-    goto error_return;
-
-  if (! bfd_get_section_contents (abfd, lsec, (PTR) buf, (file_ptr) 0,
-                                 lsec->_raw_size))
-    goto error_return;
+  if (! xcoff_get_section_contents (abfd, lsec))
+    return false;
+  buf = coff_section_data (abfd, lsec)->contents;
 
   /* Remove the sections from this object, so that they do not get
      included in the link.  */
@@ -1995,7 +2429,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
       h = xcoff_link_hash_lookup (xcoff_hash_table (info), name, true,
                                  true, true);
       if (h == NULL)
-       goto error_return;
+       return false;
 
       h->flags |= XCOFF_DEF_DYNAMIC;
 
@@ -2036,10 +2470,10 @@ xcoff_link_add_dynamic_symbols (abfd, info)
        }
     }
 
-  if (buf != NULL)
+  if (buf != NULL && ! coff_section_data (abfd, lsec)->keep_contents)
     {
-      free (buf);
-      buf = NULL;
+      free (coff_section_data (abfd, lsec)->contents);
+      coff_section_data (abfd, lsec)->contents = NULL;
     }
 
   /* Record this file in the import files.  */
@@ -2047,7 +2481,7 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   n = ((struct xcoff_import_file *)
        bfd_alloc (abfd, sizeof (struct xcoff_import_file)));
   if (n == NULL)
-    goto error_return;
+    return false;
   n->next = NULL;
 
   /* For some reason, the path entry in the import file list for a
@@ -2081,11 +2515,6 @@ xcoff_link_add_dynamic_symbols (abfd, info)
   xcoff_data (abfd)->import_file_id = c;
 
   return true;
-
- error_return:
-  if (buf != NULL)
-    free (buf);
-  return false;
 }
 \f
 /* Routines that are called after all the input files have been
@@ -4350,7 +4779,8 @@ xcoff_link_input_bfd (finfo, input_bfd)
 
                  if (ISFCN (isymp->n_type)
                      || ISTAG (isymp->n_sclass)
-                     || isymp->n_sclass == C_BLOCK)
+                     || isymp->n_sclass == C_BLOCK
+                     || isymp->n_sclass == C_FCN)
                    {
                      indx = aux.x_sym.x_fcnary.x_fcn.x_endndx.l;
                      if (indx > 0