This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[committed] Tweak handling of import paths in XCOFF files


The native AIX 6.1 linker behaves more-or-less like an ELF linker when
it comes to hard-coding library paths in an object.  Libraries found
by a search path have no hard-coded directory component, but explicit
.a and .so files do.  We currently don't add a directory component
for either case.

If libtool is anything to go by, the native behaviour applies universally
to AIX 4 and above, so I think GNU ld should do the same thing.

We need some way of attaching XCOFF-specific information to an archive.
I wondered about storing it in the artdata.tdata field (which for XCOFF
stores the archive file header).  However, given BFD's attempt to handle
other file formats, I don't think it's correct to assume that every archive
is handled by the XCOFF ocde.  I therefore used a hash table instead.

I don't think we have any GNU tools to print the import paths,
so I'm afraid there's no testcase.  The libtool testsuite does
test this though.

Tested on powerpc-ibm-aix6.1 and applied.

Richard


bfd/
	* bfd-in.h (bfd_xcoff_split_import_path): Declare.
	(bfd_xcoff_set_archive_import_path): Likewise.
	* bfd-in2.h: Regenerate.
	* xcofflink.c: Include libiberty.h.
	(xcoff_archive_info): New structure.
	(xcoff_archive_info_hash): New function.
	(xcoff_archive_info_eq): Likewise.
	(xcoff_get_archive_info): Likewise.
	(_bfd_xcoff_bfd_link_hash_table_create): Initialize archive_info.
	(bfd_xcoff_split_import_path): New function.
	(bfd_xcoff_set_archive_import_path): Likewise.
	(xcoff_set_import_path): Move earlier in file.
	(xcoff_link_add_dynamic_symbols): Set the import path of a non-archive
	object to the the directory part of the bfd's filename.  Get the
	import path and filename of an archive object from the archive's
	xcoff_tdata, initializing it if necessary.  Update use of
	import_file_id.
	(bfd_link_input_bfd): Update use of import_file_id.
	(xcoff_write_global_symbol): Likewise.

ld/
	* emultempl/aix.em (gld${EMULATION_NAME}_open_dynamic_archive): New
	function.
	(ld_${EMULATION_NAME}_emulation): Use it.

Index: bfd/bfd-in.h
===================================================================
--- bfd/bfd-in.h	2009-04-01 19:00:45.000000000 +0100
+++ bfd/bfd-in.h	2009-04-01 19:03:28.000000000 +0100
@@ -765,6 +765,10 @@ typedef struct _bfd_window
 
 /* XCOFF support routines for the linker.  */
 
+extern bfd_boolean bfd_xcoff_split_import_path
+  (bfd *, const char *, const char **, const char **);
+extern bfd_boolean bfd_xcoff_set_archive_import_path
+  (struct bfd_link_info *, bfd *, const char *);
 extern bfd_boolean bfd_xcoff_link_record_set
   (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type);
 extern bfd_boolean bfd_xcoff_import_symbol
Index: bfd/bfd-in2.h
===================================================================
--- bfd/bfd-in2.h	2009-04-01 19:00:45.000000000 +0100
+++ bfd/bfd-in2.h	2009-04-01 19:03:28.000000000 +0100
@@ -772,6 +772,10 @@ typedef struct _bfd_window
 
 /* XCOFF support routines for the linker.  */
 
+extern bfd_boolean bfd_xcoff_split_import_path
+  (bfd *, const char *, const char **, const char **);
+extern bfd_boolean bfd_xcoff_set_archive_import_path
+  (struct bfd_link_info *, bfd *, const char *);
 extern bfd_boolean bfd_xcoff_link_record_set
   (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, bfd_size_type);
 extern bfd_boolean bfd_xcoff_import_symbol
Index: bfd/xcofflink.c
===================================================================
--- bfd/xcofflink.c	2009-04-01 19:03:27.000000000 +0100
+++ bfd/xcofflink.c	2009-04-01 19:03:28.000000000 +0100
@@ -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,18 @@ 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;
+};
+
 struct xcoff_link_hash_table
 {
   struct bfd_link_hash_table root;
@@ -132,6 +145,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 +480,56 @@ _bfd_xcoff_canonicalize_dynamic_reloc (b
   return ldhdr.l_nreloc;
 }
 
+/* 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;
+}
+
 /* Routine to create an entry in an XCOFF link hash table.  */
 
 static struct bfd_hash_entry *
@@ -530,6 +596,8 @@ _bfd_xcoff_bfd_link_hash_table_create (b
   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 +674,109 @@ xcoff_read_internal_relocs (bfd *abfd,
 					 require_internal, internal_relocs);
 }
 
+/* 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 *basename;
+  size_t length;
+  char *path;
+
+  basename = lbasename (filename);
+  length = basename - 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 = basename;
+  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;
+}
+
 /* H is the bfd symbol associated with exported .loader symbol LDSYM.
    Return true if LDSYM defines H.  */
 
@@ -648,9 +819,6 @@ xcoff_link_add_dynamic_symbols (bfd *abf
   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 +995,30 @@ xcoff_link_add_dynamic_symbols (bfd *abf
     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.  */
@@ -2327,58 +2500,6 @@ xcoff_find_function (struct bfd_link_inf
     }
   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;
-}
 
 /* Return true if the given bfd contains at least one shared object.  */
 
Index: ld/emultempl/aix.em
===================================================================
--- ld/emultempl/aix.em	2009-04-01 19:00:45.000000000 +0100
+++ ld/emultempl/aix.em	2009-04-01 19:03:28.000000000 +0100
@@ -1096,32 +1096,18 @@ gld${EMULATION_NAME}_read_file (const ch
 	  else
 	    {
 	      char cs;
-	      char *file;
+	      char *start;
 
 	      (void) obstack_finish (o);
 	      keep = TRUE;
-	      imppath = s;
-	      file = NULL;
+	      start = s;
 	      while (!ISSPACE (*s) && *s != '(' && *s != '\0')
-		{
-		  if (*s == '/')
-		    file = s + 1;
-		  ++s;
-		}
-	      if (file != NULL)
-		{
-		  file[-1] = '\0';
-		  impfile = file;
-		  if (imppath == file - 1)
-		    imppath = "/";
-		}
-	      else
-		{
-		  impfile = imppath;
-		  imppath = "";
-		}
+		++s;
 	      cs = *s;
 	      *s = '\0';
+	      if (!bfd_xcoff_split_import_path (link_info.output_bfd,
+						start, &imppath, &impfile))
+		einfo ("%F%P: Could not parse import path: %E\n");
 	      while (ISSPACE (cs))
 		{
 		  ++s;
@@ -1433,6 +1419,31 @@ gld${EMULATION_NAME}_set_output_arch (vo
   ldfile_output_machine_name = bfd_printable_name (link_info.output_bfd);
 }
 
+static bfd_boolean
+gld${EMULATION_NAME}_open_dynamic_archive (const char *arch,
+					   search_dirs_type *search,
+					   lang_input_statement_type *entry)
+{
+  const char *filename;
+  char *path;
+
+  if (!entry->is_archive)
+    return FALSE;
+
+  filename = entry->filename;
+  path = concat (search->name, "/lib", entry->filename, arch, ".a", NULL);
+  if (!ldfile_try_open_bfd (path, entry))
+    {
+      free (path);
+      return FALSE;
+    }
+  /* Don't include the searched directory in the import path.  */
+  bfd_xcoff_set_archive_import_path (&link_info, entry->the_bfd,
+				     path + strlen (search->name) + 1);
+  entry->filename = path;
+  return TRUE;
+}
+
 struct ld_emulation_xfer_struct ld_${EMULATION_NAME}_emulation = {
   gld${EMULATION_NAME}_before_parse,
   syslib_default,
@@ -1448,7 +1459,7 @@ struct ld_emulation_xfer_struct ld_${EMU
   "${OUTPUT_FORMAT}",
   finish_default,
   gld${EMULATION_NAME}_create_output_section_statements,
-  0,				/* open_dynamic_archive */
+  gld${EMULATION_NAME}_open_dynamic_archive,
   0,				/* place_orphan */
   0,				/* set_symbols */
   gld${EMULATION_NAME}_parse_args,


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]