2009-12-15 Tristan Gingold <gingold@adacore.com>
[binutils-gdb.git] / bfd / xcofflink.c
index 1c205f934b85b7c100478d36c6c6f2a941acd70c..6ad148b5836bbbfd1ffafbdff61ca385c4f19269 100644 (file)
@@ -1,6 +1,6 @@
 /* POWER/PowerPC XCOFF linker support.
    Copyright 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+   2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
    Written by Ian Lance Taylor <ian@cygnus.com>, Cygnus Support.
 
    This file is part of BFD, the Binary File Descriptor library.
@@ -28,6 +28,7 @@
 #include "coff/xcoff.h"
 #include "libcoff.h"
 #include "libxcoff.h"
+#include "libiberty.h"
 
 /* This file holds the XCOFF linker code.  */
 
@@ -75,6 +76,24 @@ struct xcoff_link_section_info
   } *toc_rel_hashes;
 };
 
+/* Information that the XCOFF linker collects about an archive.  */
+struct xcoff_archive_info
+{
+  /* The archive described by this entry.  */
+  bfd *archive;
+
+  /* The import path and import filename to use when referring to
+     this archive in the .loader section.  */
+  const char *imppath;
+  const char *impfile;
+
+  /* True if the archive contains a dynamic object.  */
+  unsigned int contains_shared_object_p : 1;
+
+  /* True if the previous field is valid.  */
+  unsigned int know_contains_shared_object_p : 1;
+};
+
 struct xcoff_link_hash_table
 {
   struct bfd_link_hash_table root;
@@ -132,6 +151,9 @@ struct xcoff_link_hash_table
   } 
   *size_list;
 
+  /* Information about archives.  */
+  htab_t archive_info;
+
   /* Magic sections: _text, _etext, _data, _edata, _end, end. */
   asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS];
 };
@@ -464,6 +486,56 @@ _bfd_xcoff_canonicalize_dynamic_reloc (bfd *abfd,
   return ldhdr.l_nreloc;
 }
 \f
+/* Hash functions for xcoff_link_hash_table's archive_info.  */
+
+static hashval_t
+xcoff_archive_info_hash (const void *data)
+{
+  const struct xcoff_archive_info *info;
+
+  info = (const struct xcoff_archive_info *) data;
+  return htab_hash_pointer (info->archive);
+}
+
+static int
+xcoff_archive_info_eq (const void *data1, const void *data2)
+{
+  const struct xcoff_archive_info *info1;
+  const struct xcoff_archive_info *info2;
+
+  info1 = (const struct xcoff_archive_info *) data1;
+  info2 = (const struct xcoff_archive_info *) data2;
+  return info1->archive == info2->archive;
+}
+
+/* Return information about archive ARCHIVE.  Return NULL on error.  */
+
+static struct xcoff_archive_info *
+xcoff_get_archive_info (struct bfd_link_info *info, bfd *archive)
+{
+  struct xcoff_link_hash_table *htab;
+  struct xcoff_archive_info *entryp, entry;
+  void **slot;
+
+  htab = xcoff_hash_table (info);
+  entry.archive = archive;
+  slot = htab_find_slot (htab->archive_info, &entry, INSERT);
+  if (!slot)
+    return NULL;
+
+  entryp = *slot;
+  if (!entryp)
+    {
+      entryp = bfd_zalloc (archive, sizeof (entry));
+      if (!entryp)
+       return NULL;
+
+      entryp->archive = archive;
+      *slot = entryp;
+    }
+  return entryp;
+}
+\f
 /* Routine to create an entry in an XCOFF link hash table.  */
 
 static struct bfd_hash_entry *
@@ -530,6 +602,8 @@ _bfd_xcoff_bfd_link_hash_table_create (bfd *abfd)
   ret->file_align = 0;
   ret->textro = FALSE;
   ret->gc = FALSE;
+  ret->archive_info = htab_create (37, xcoff_archive_info_hash,
+                                  xcoff_archive_info_eq, NULL);
   memset (ret->special_sections, 0, sizeof ret->special_sections);
 
   /* The linker will always generate a full a.out header.  We need to
@@ -606,6 +680,109 @@ xcoff_read_internal_relocs (bfd *abfd,
                                         require_internal, internal_relocs);
 }
 \f
+/* Split FILENAME into an import path and an import filename,
+   storing them in *IMPPATH and *IMPFILE respectively.  */
+
+bfd_boolean
+bfd_xcoff_split_import_path (bfd *abfd, const char *filename,
+                            const char **imppath, const char **impfile)
+{
+  const char *base;
+  size_t length;
+  char *path;
+
+  base = lbasename (filename);
+  length = base - filename;
+  if (length == 0)
+    /* The filename has no directory component, so use an empty path.  */
+    *imppath = "";
+  else if (length == 1)
+    /* The filename is in the root directory.  */
+    *imppath = "/";
+  else
+    {
+      /* Extract the (non-empty) directory part.  Note that we don't
+        need to strip duplicate directory separators from any part
+        of the string; the native linker doesn't do that either.  */
+      path = bfd_alloc (abfd, length);
+      if (path == NULL)
+       return FALSE;
+      memcpy (path, filename, length - 1);
+      path[length - 1] = 0;
+      *imppath = path;
+    }
+  *impfile = base;
+  return TRUE;
+}
+
+/* Set ARCHIVE's import path as though its filename had been given
+   as FILENAME.  */
+
+bfd_boolean
+bfd_xcoff_set_archive_import_path (struct bfd_link_info *info,
+                                  bfd *archive, const char *filename)
+{
+  struct xcoff_archive_info *archive_info;
+
+  archive_info = xcoff_get_archive_info (info, archive);
+  return (archive_info != NULL
+         && bfd_xcoff_split_import_path (archive, filename,
+                                         &archive_info->imppath,
+                                         &archive_info->impfile));
+}
+
+/* H is an imported symbol.  Set the import module's path, file and member
+   to IMPATH, IMPFILE and IMPMEMBER respectively.  All three are null if
+   no specific import module is specified.  */
+
+static bfd_boolean
+xcoff_set_import_path (struct bfd_link_info *info,
+                      struct xcoff_link_hash_entry *h,
+                      const char *imppath, const char *impfile,
+                      const char *impmember)
+{
+  unsigned int c;
+  struct xcoff_import_file **pp;
+
+  /* We overload the ldindx field to hold the l_ifile value for this
+     symbol.  */
+  BFD_ASSERT (h->ldsym == NULL);
+  BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
+  if (imppath == NULL)
+    h->ldindx = -1;
+  else
+    {
+      /* We start c at 1 because the first entry in the import list is
+        reserved for the library search path.  */
+      for (pp = &xcoff_hash_table (info)->imports, c = 1;
+          *pp != NULL;
+          pp = &(*pp)->next, ++c)
+       {
+         if (strcmp ((*pp)->path, imppath) == 0
+             && strcmp ((*pp)->file, impfile) == 0
+             && strcmp ((*pp)->member, impmember) == 0)
+           break;
+       }
+
+      if (*pp == NULL)
+       {
+         struct xcoff_import_file *n;
+         bfd_size_type amt = sizeof (* n);
+
+         n = bfd_alloc (info->output_bfd, amt);
+         if (n == NULL)
+           return FALSE;
+         n->next = NULL;
+         n->path = imppath;
+         n->file = impfile;
+         n->member = impmember;
+         *pp = n;
+       }
+      h->ldindx = c;
+    }
+  return TRUE;
+}
+\f
 /* H is the bfd symbol associated with exported .loader symbol LDSYM.
    Return true if LDSYM defines H.  */
 
@@ -648,9 +825,6 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info)
   const char *strings;
   bfd_byte *elsym, *elsymend;
   struct xcoff_import_file *n;
-  const char *bname;
-  const char *mname;
-  const char *s;
   unsigned int c;
   struct xcoff_import_file **pp;
 
@@ -827,25 +1001,30 @@ xcoff_link_add_dynamic_symbols (bfd *abfd, struct bfd_link_info *info)
     return FALSE;
   n->next = NULL;
 
-  /* For some reason, the path entry in the import file list for a
-     shared object appears to always be empty.  The file name is the
-     base name.  */
-  n->path = "";
   if (abfd->my_archive == NULL)
     {
-      bname = bfd_get_filename (abfd);
-      mname = "";
+      if (!bfd_xcoff_split_import_path (abfd, abfd->filename,
+                                       &n->path, &n->file))
+       return FALSE;
+      n->member = "";
     }
   else
     {
-      bname = bfd_get_filename (abfd->my_archive);
-      mname = bfd_get_filename (abfd);
+      struct xcoff_archive_info *archive_info;
+
+      archive_info = xcoff_get_archive_info (info, abfd->my_archive);
+      if (!archive_info->impfile)
+       {
+         if (!bfd_xcoff_split_import_path (archive_info->archive,
+                                           archive_info->archive->filename,
+                                           &archive_info->imppath,
+                                           &archive_info->impfile))
+           return FALSE;
+       }
+      n->path = archive_info->imppath;
+      n->file = archive_info->impfile;
+      n->member = bfd_get_filename (abfd);
     }
-  s = strrchr (bname, '/');
-  if (s != NULL)
-    bname = s + 1;
-  n->file = bname;
-  n->member = mname;
 
   /* We start c at 1 because the first import file number is reserved
      for LIBPATH.  */
@@ -1710,6 +1889,15 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
              || sym._n._n_n._n_offset == 0)
            copy = TRUE;
 
+         /* Ignore global linkage code when linking statically.  */
+         if (info->static_link
+             && (smtyp == XTY_SD || smtyp == XTY_LD)
+             && aux.x_csect.x_smclas == XMC_GL)
+           {
+             section = bfd_und_section_ptr;
+             value = 0;
+           }
+
          /* The AIX linker appears to only detect multiple symbol
             definitions when there is a reference to the symbol.  If
             a symbol is defined multiple times, and the only
@@ -1734,8 +1922,7 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
             We also have to handle the case of statically linking a
             shared object, which will cause symbol redefinitions,
             although this is an easier case to detect.  */
-
-         if (info->output_bfd->xvec == abfd->xvec)
+         else if (info->output_bfd->xvec == abfd->xvec)
            {
              if (! bfd_is_und_section (section))
                *sym_hash = xcoff_link_hash_lookup (xcoff_hash_table (info),
@@ -1755,23 +1942,8 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
                  && ! bfd_is_com_section (section))
                {
                  /* This is a second definition of a defined symbol.  */
-                 if ((abfd->flags & DYNAMIC) != 0
-                     && ((*sym_hash)->smclas != XMC_GL
-                         || aux.x_csect.x_smclas == XMC_GL
-                         || ((*sym_hash)->root.u.def.section->owner->flags
-                             & DYNAMIC) == 0))
-                   {
-                     /* The new symbol is from a shared library, and
-                        either the existing symbol is not global
-                        linkage code or this symbol is global linkage
-                        code.  If the existing symbol is global
-                        linkage code and the new symbol is not, then
-                        we want to use the new symbol.  */
-                     section = bfd_und_section_ptr;
-                     value = 0;
-                   }
-                 else if (((*sym_hash)->flags & XCOFF_DEF_REGULAR) == 0
-                          && ((*sym_hash)->flags & XCOFF_DEF_DYNAMIC) != 0)
+                 if (((*sym_hash)->flags & XCOFF_DEF_REGULAR) == 0
+                     && ((*sym_hash)->flags & XCOFF_DEF_DYNAMIC) != 0)
                    {
                      /* The existing symbol is from a shared library.
                         Replace it.  */
@@ -1870,7 +2042,9 @@ xcoff_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
            {
              int flag;
 
-             if (smtyp == XTY_ER || smtyp == XTY_CM)
+             if (smtyp == XTY_ER
+                 || smtyp == XTY_CM
+                 || section == bfd_und_section_ptr)
                flag = XCOFF_REF_REGULAR;
              else
                flag = XCOFF_DEF_REGULAR;
@@ -2292,6 +2466,21 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
     }
 }
 \f
+bfd_boolean
+_bfd_xcoff_define_common_symbol (bfd *output_bfd ATTRIBUTE_UNUSED,
+                                struct bfd_link_info *info ATTRIBUTE_UNUSED,
+                                struct bfd_link_hash_entry *harg)
+{
+  struct xcoff_link_hash_entry *h;
+
+  if (!bfd_generic_define_common_symbol (output_bfd, info, harg))
+    return FALSE;
+
+  h = (struct xcoff_link_hash_entry *) harg;
+  h->flags |= XCOFF_DEF_REGULAR;
+  return TRUE;
+}
+\f
 /* If symbol H has not been interpreted as a function descriptor,
    see whether it should be.  Set up its descriptor information if so.  */
 
@@ -2327,70 +2516,27 @@ xcoff_find_function (struct bfd_link_info *info,
     }
   return TRUE;
 }
-
-/* H is an imported symbol.  Set the import module's path, file and member
-   to IMPATH, IMPFILE and IMPMEMBER respectively.  All three are null if
-   no specific import module is specified.  */
-
-static bfd_boolean
-xcoff_set_import_path (struct bfd_link_info *info,
-                      struct xcoff_link_hash_entry *h,
-                      const char *imppath, const char *impfile,
-                      const char *impmember)
-{
-  unsigned int c;
-  struct xcoff_import_file **pp;
-
-  /* We overload the ldindx field to hold the l_ifile value for this
-     symbol.  */
-  BFD_ASSERT (h->ldsym == NULL);
-  BFD_ASSERT ((h->flags & XCOFF_BUILT_LDSYM) == 0);
-  if (imppath == NULL)
-    h->ldindx = -1;
-  else
-    {
-      /* We start c at 1 because the first entry in the import list is
-        reserved for the library search path.  */
-      for (pp = &xcoff_hash_table (info)->imports, c = 1;
-          *pp != NULL;
-          pp = &(*pp)->next, ++c)
-       {
-         if (strcmp ((*pp)->path, imppath) == 0
-             && strcmp ((*pp)->file, impfile) == 0
-             && strcmp ((*pp)->member, impmember) == 0)
-           break;
-       }
-
-      if (*pp == NULL)
-       {
-         struct xcoff_import_file *n;
-         bfd_size_type amt = sizeof (* n);
-
-         n = bfd_alloc (info->output_bfd, amt);
-         if (n == NULL)
-           return FALSE;
-         n->next = NULL;
-         n->path = imppath;
-         n->file = impfile;
-         n->member = impmember;
-         *pp = n;
-       }
-      h->ldindx = c;
-    }
-  return TRUE;
-}
 \f
 /* Return true if the given bfd contains at least one shared object.  */
 
 static bfd_boolean
-xcoff_archive_contains_shared_object_p (bfd *archive)
+xcoff_archive_contains_shared_object_p (struct bfd_link_info *info,
+                                       bfd *archive)
 {
+  struct xcoff_archive_info *archive_info;
   bfd *member;
 
-  member = bfd_openr_next_archived_file (archive, NULL);
-  while (member != NULL && (member->flags & DYNAMIC) == 0)
-    member = bfd_openr_next_archived_file (archive, member);
-  return member != NULL;
+  archive_info = xcoff_get_archive_info (info, archive);
+  if (!archive_info->know_contains_shared_object_p)
+    {
+      member = bfd_openr_next_archived_file (archive, NULL);
+      while (member != NULL && (member->flags & DYNAMIC) == 0)
+       member = bfd_openr_next_archived_file (archive, member);
+
+      archive_info->contains_shared_object_p = (member != NULL);
+      archive_info->know_contains_shared_object_p = 1;
+    }
+  return archive_info->contains_shared_object_p;
 }
 
 /* Symbol H qualifies for export by -bexpfull.  Return true if it also
@@ -2418,7 +2564,8 @@ xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h)
    specified by AUTO_EXPORT_FLAGS.  */
 
 static bfd_boolean
-xcoff_auto_export_p (struct xcoff_link_hash_entry *h,
+xcoff_auto_export_p (struct bfd_link_info *info,
+                    struct xcoff_link_hash_entry *h,
                     unsigned int auto_export_flags)
 {
   /* Don't automatically export things that were explicitly exported.  */
@@ -2455,7 +2602,7 @@ xcoff_auto_export_p (struct xcoff_link_hash_entry *h,
       owner = h->root.u.def.section->owner;
       if (owner != NULL
          && owner->my_archive != NULL
-         && xcoff_archive_contains_shared_object_p (owner->my_archive))
+         && xcoff_archive_contains_shared_object_p (info, owner->my_archive))
        return FALSE;
     }
 
@@ -2589,6 +2736,10 @@ xcoff_mark_symbol (struct bfd_link_info *info, struct xcoff_link_hash_entry *h)
          /* We handle writing out the contents of the descriptor in
             xcoff_write_global_symbol.  */
        }
+      else if (info->static_link)
+       /* We can't get a symbol value dynamically, so just assume
+          that it's undefined.  */
+       h->flags |= XCOFF_WAS_UNDEFINED;
       else if ((h->flags & XCOFF_CALLED) != 0)
        {
          /* This is a function symbol for which we need to create
@@ -3075,7 +3226,7 @@ xcoff_mark_auto_exports (struct xcoff_link_hash_entry *h, void *data)
   struct xcoff_loader_info *ldinfo;
 
   ldinfo = (struct xcoff_loader_info *) data;
-  if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+  if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags))
     {
       if (!xcoff_mark_symbol (ldinfo->info, h))
        ldinfo->failed = TRUE;
@@ -3193,19 +3344,6 @@ xcoff_post_gc_symbol (struct xcoff_link_hash_entry *h, void * p)
   if (h->flags & XCOFF_RTINIT)
     return TRUE;
 
-  /* If this is a final link, and the symbol was defined as a common
-     symbol in a regular object file, and there was no definition in
-     any dynamic object, then the linker will have allocated space for
-     the symbol in a common section but the XCOFF_DEF_REGULAR flag
-     will not have been set.  */
-  if (h->root.type == bfd_link_hash_defined
-      && (h->flags & XCOFF_DEF_REGULAR) == 0
-      && (h->flags & XCOFF_REF_REGULAR) != 0
-      && (h->flags & XCOFF_DEF_DYNAMIC) == 0
-      && (bfd_is_abs_section (h->root.u.def.section)
-         || (h->root.u.def.section->owner->flags & DYNAMIC) == 0))
-    h->flags |= XCOFF_DEF_REGULAR;
-
   /* We don't want to garbage collect symbols which are not defined in
      XCOFF files.  This is a convenient place to mark them.  */
   if (xcoff_hash_table (ldinfo->info)->gc
@@ -3234,7 +3372,7 @@ xcoff_post_gc_symbol (struct xcoff_link_hash_entry *h, void * p)
 
   if (xcoff_hash_table (ldinfo->info)->loader_section)
     {
-      if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+      if (xcoff_auto_export_p (ldinfo->info, h, ldinfo->auto_export_flags))
        h->flags |= XCOFF_EXPORT;
 
       if (!xcoff_build_ldsym (ldinfo, h))
@@ -4168,6 +4306,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
 
   esym = (bfd_byte *) obj_coff_external_syms (input_bfd);
   esym_end = esym + obj_raw_syment_count (input_bfd) * isymesz;
+  sym_hash = obj_xcoff_sym_hashes (input_bfd);
   isymp = finfo->internal_syms;
   indexp = finfo->sym_indices;
   csectpp = xcoff_data (input_bfd)->csects;
@@ -4215,6 +4354,16 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
                }
            }
 
+         /* Make __rtinit C_HIDEXT rather than C_EXT.  This avoids
+            multiple definition problems when linking a shared object
+            statically.  (The native linker doesn't enter __rtinit into
+            the normal table at all, but having a local symbol can make
+            the objdump output easier to read.)  */
+         if (isym.n_sclass == C_EXT
+             && *sym_hash
+             && ((*sym_hash)->flags & XCOFF_RTINIT) != 0)
+           isym.n_sclass = C_HIDEXT;
+
          /* The value of a C_FILE symbol is the symbol index of the
             next C_FILE symbol.  The value of the last C_FILE symbol
             is -1.  We try to get this right, below, just before we
@@ -4543,6 +4692,7 @@ xcoff_link_input_bfd (struct xcoff_final_link_info *finfo,
            }
        }
 
+      sym_hash += add;
       indexp += add;
       isymp += add;
       csectpp += add;