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]

[18/21] Add -bexpall and -bexpfull


The native AIX linker has two options called -bexpall and -bexpfull.
This patch adds support to the GNU linker.

Support for -bexpfull-like behaviour is already there for non-gc links,
in the form of -unix.  We simply need to extend it to gc links by
marking all symbols that need to be exported.  Support for -bexpall is a
simple extension of this.

The current code doesn't export symbols from archives that contain
shared objects:

  /* We don't export a symbol which is being defined by an object
     included from an archive which contains a shared object.  The
     rationale is that if an archive contains both an unshared and
     a shared object, then there must be some reason that the
     unshared object is unshared, and we don't want to start
     providing a shared version of it.  In particular, this solves
     a bug involving the _savefNN set of functions.  gcc will call
     those functions without providing a slot to restore the TOC,
     so it is essential that these functions be linked in directly
     and not from a shared object, which means that a shared
     object which also happens to link them in must not export
     them.  This is confusing, but I haven't been able to think of
     a different approach.  Note that the symbols can, of course,
     be exported explicitly.  */

I think this diverges from the native linker, but the reason is
explained fairly well, so I kept it.

The existing code actually walks the archive for every symbol it
is given, which seems rather inefficient, but I kept that too.
Adding some sort of cache is a possible future refinement.

There's no documentation or help output for the new options because
I couldn't find any for the existing ones.  I'm afraid fixing that
is beyond what I have time for right now.

OK to install?

Richard


include/coff/
	* xcoff.h (XCOFF_EXPALL, XCOFF_EXPFULL): New flags.
	(xcoff_loader_info): Add auto_export_flags.

bfd/
	* bfd-in.h (bfd_xcoff_size_dynamic_sections): Replace the
	bfd_boolean export_defineds parameter with an unsigned int
	auto_export_flags parameter.
	* bfd-in2.h: Regenerate.
	* xcofflink.c (xcoff_archive_contains_shared_object_p): New function,
	split out from xcoff_build_ldsyms.
	(xcoff_covered_by_expall_p): New function.
	(xcoff_auto_export_p): New function, split out from xcoff_build_ldsyms
	but with extra code to handle -bexpfull and -bexpall.
	(xcoff_mark_auto_exports): New function.
	(xcoff_build_ldsyms): Use xcoff_auto_export_p to decide whether
	a function should be automatically exported.
	(bfd_xcoff_size_dynamic_sections): Replace the export_defineds
	parameter with an auto_export_flags parameter.  Update ldinfo
	accordingly.  Use xcoff_mark_auto_exports to mark all automatically-
	exported symbols.

ld/
	* emultempl/aix.em (auto_export_flags): New variable.
	(explicit_auto_export_flags): Likewise.
	(OPTION_EXPALL, OPTION_EXPFULL): New enum values.
	(OPTION_NOEXPALL, OPTION_NOEXPFULL): Likewise.
	(gld${EMULATION_NAME}_add_options): Add -bexpall, -bexpfull,
	-bnoexpall and -bnoexpfull.
	(gld${EMULATION_NAME}_handle_option): Handle them.
	(gld${EMULATION_NAME}_before_allocation): Update the call to
	bfd_size_dynamic_sections.

ld/testsuite/
	* ld-powerpc/aix-export-1-all.dd, ld-powerpc/aix-export-1-full.dd,
	ld-powerpc/aix-export-1a.s, ld-powerpc/aix-export-1b.s: New tests.
	* ld-powerpc/aix52.exp: Run them.

Index: include/coff/xcoff.h
===================================================================
--- include/coff/xcoff.h	2009-03-10 13:51:47.000000000 +0000
+++ include/coff/xcoff.h	2009-03-10 13:52:51.000000000 +0000
@@ -394,6 +394,9 @@ struct xcoff_link_hash_table
   asection *special_sections[XCOFF_NUMBER_OF_SPECIAL_SECTIONS];
 };
 
+/* These flags indicate which of -bexpall and -bexpfull are in effect.  */
+#define XCOFF_EXPALL 1
+#define XCOFF_EXPFULL 2
 
 /* This structure is used to pass information through
    xcoff_link_hash_traverse.  */
@@ -409,8 +412,8 @@ struct xcoff_loader_info
   /* Link information structure.  */
   struct bfd_link_info *info;
 
-  /* Whether all defined symbols should be exported.  */
-  bfd_boolean export_defineds;
+  /* A mask of XCOFF_EXPALL and XCOFF_EXPFULL flags.  */
+  unsigned int auto_export_flags;
 
   /* Number of ldsym structures.  */
   size_t ldsym_count;
Index: bfd/bfd-in.h
===================================================================
--- bfd/bfd-in.h	2009-03-10 13:38:52.000000000 +0000
+++ bfd/bfd-in.h	2009-03-10 13:52:51.000000000 +0000
@@ -779,7 +779,7 @@ typedef struct _bfd_window
 extern bfd_boolean bfd_xcoff_size_dynamic_sections
   (bfd *, struct bfd_link_info *, const char *, const char *,
    unsigned long, unsigned long, unsigned long, bfd_boolean,
-   int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean);
+   int, bfd_boolean, unsigned int, struct bfd_section **, bfd_boolean);
 extern bfd_boolean bfd_xcoff_link_generate_rtinit
   (bfd *, const char *, const char *, bfd_boolean);
 
Index: bfd/bfd-in2.h
===================================================================
--- bfd/bfd-in2.h	2009-03-10 13:38:52.000000000 +0000
+++ bfd/bfd-in2.h	2009-03-10 13:52:51.000000000 +0000
@@ -786,7 +786,7 @@ typedef struct _bfd_window
 extern bfd_boolean bfd_xcoff_size_dynamic_sections
   (bfd *, struct bfd_link_info *, const char *, const char *,
    unsigned long, unsigned long, unsigned long, bfd_boolean,
-   int, bfd_boolean, bfd_boolean, struct bfd_section **, bfd_boolean);
+   int, bfd_boolean, unsigned int, struct bfd_section **, bfd_boolean);
 extern bfd_boolean bfd_xcoff_link_generate_rtinit
   (bfd *, const char *, const char *, bfd_boolean);
 
Index: bfd/xcofflink.c
===================================================================
--- bfd/xcofflink.c	2009-03-10 13:52:29.000000000 +0000
+++ bfd/xcofflink.c	2009-03-10 13:52:51.000000000 +0000
@@ -2313,6 +2313,97 @@ xcoff_set_import_path (struct bfd_link_i
   return TRUE;
 }
 
+/* Return true if the given bfd contains at least one shared object.  */
+
+static bfd_boolean
+xcoff_archive_contains_shared_object_p (bfd *archive)
+{
+  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;
+}
+
+/* Symbol H qualifies for export by -bexpfull.  Return true if it also
+   qualifies for export by -bexpall.  */
+
+static bfd_boolean
+xcoff_covered_by_expall_p (struct xcoff_link_hash_entry *h)
+{
+  /* Exclude symbols beginning with '_'.  */
+  if (h->root.root.string[0] == '_')
+    return FALSE;
+
+  /* Exclude archive members that would otherwise be unreferenced.  */
+  if ((h->flags & XCOFF_MARK) == 0
+      && (h->root.type == bfd_link_hash_defined
+	  || h->root.type == bfd_link_hash_defweak)
+      && h->root.u.def.section->owner != NULL
+      && h->root.u.def.section->owner->my_archive != NULL)
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Return true if symbol H qualifies for the forms of automatic export
+   specified by AUTO_EXPORT_FLAGS.  */
+
+static bfd_boolean
+xcoff_auto_export_p (struct xcoff_link_hash_entry *h,
+		     unsigned int auto_export_flags)
+{
+  /* Don't automatically export things that were explicitly exported.  */
+  if ((h->flags & XCOFF_EXPORT) != 0)
+    return FALSE;
+
+  /* Don't export things that we don't define.  */
+  if ((h->flags & XCOFF_DEF_REGULAR) == 0)
+    return FALSE;
+
+  /* Don't export functions; export their descriptors instead.  */
+  if (h->root.root.string[0] == '.')
+    return FALSE;
+
+  /* We don't export a symbol which is being defined by an object
+     included from an archive which contains a shared object.  The
+     rationale is that if an archive contains both an unshared and
+     a shared object, then there must be some reason that the
+     unshared object is unshared, and we don't want to start
+     providing a shared version of it.  In particular, this solves
+     a bug involving the _savefNN set of functions.  gcc will call
+     those functions without providing a slot to restore the TOC,
+     so it is essential that these functions be linked in directly
+     and not from a shared object, which means that a shared
+     object which also happens to link them in must not export
+     them.  This is confusing, but I haven't been able to think of
+     a different approach.  Note that the symbols can, of course,
+     be exported explicitly.  */
+  if (h->root.type == bfd_link_hash_defined
+      || h->root.type == bfd_link_hash_defweak)
+    {
+      bfd *owner;
+
+      owner = h->root.u.def.section->owner;
+      if (owner != NULL
+	  && owner->my_archive != NULL
+	  && xcoff_archive_contains_shared_object_p (owner->my_archive))
+	return FALSE;
+    }
+
+  /* Otherwise, all symbols are exported by -bexpfull.  */
+  if ((auto_export_flags & XCOFF_EXPFULL) != 0)
+    return TRUE;
+
+  /* Despite its name, -bexpall exports most but not all symbols.  */
+  if ((auto_export_flags & XCOFF_EXPALL) != 0
+      && xcoff_covered_by_expall_p (h))
+    return TRUE;
+
+  return FALSE;
+}
+
 /* Mark a symbol as not being garbage, including the section in which
    it is defined.  */
 
@@ -2878,6 +2969,24 @@ bfd_xcoff_record_link_assignment (bfd *o
   return TRUE;
 }
 
+/* An xcoff_link_hash_traverse callback for which DATA points to an
+   xcoff_loader_info.  Mark all symbols that should be automatically
+   exported.  */
+
+static bfd_boolean
+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_mark_symbol (ldinfo->info, h))
+	ldinfo->failed = TRUE;
+    }
+  return TRUE;
+}
+
 /* Add a symbol to the .loader symbols, if necessary.  */
 
 /* INPUT_BFD has an external symbol associated with hash table entry H
@@ -2939,50 +3048,8 @@ xcoff_build_ldsyms (struct xcoff_link_ha
   /* If all defined symbols should be exported, mark them now.  We
      don't want to export the actual functions, just the function
      descriptors.  */
-  if (ldinfo->export_defineds
-      && (h->flags & XCOFF_DEF_REGULAR) != 0
-      && h->root.root.string[0] != '.')
-    {
-      bfd_boolean export;
-
-      /* We don't export a symbol which is being defined by an object
-	 included from an archive which contains a shared object.  The
-	 rationale is that if an archive contains both an unshared and
-	 a shared object, then there must be some reason that the
-	 unshared object is unshared, and we don't want to start
-	 providing a shared version of it.  In particular, this solves
-	 a bug involving the _savefNN set of functions.  gcc will call
-	 those functions without providing a slot to restore the TOC,
-	 so it is essential that these functions be linked in directly
-	 and not from a shared object, which means that a shared
-	 object which also happens to link them in must not export
-	 them.  This is confusing, but I haven't been able to think of
-	 a different approach.  Note that the symbols can, of course,
-	 be exported explicitly.  */
-      export = TRUE;
-      if ((h->root.type == bfd_link_hash_defined
-	   || h->root.type == bfd_link_hash_defweak)
-	  && h->root.u.def.section->owner != NULL
-	  && h->root.u.def.section->owner->my_archive != NULL)
-	{
-	  bfd *arbfd, *member;
-
-	  arbfd = h->root.u.def.section->owner->my_archive;
-	  member = bfd_openr_next_archived_file (arbfd, NULL);
-	  while (member != NULL)
-	    {
-	      if ((member->flags & DYNAMIC) != 0)
-		{
-		  export = FALSE;
-		  break;
-		}
-	      member = bfd_openr_next_archived_file (arbfd, member);
-	    }
-	}
-
-      if (export)
-	h->flags |= XCOFF_EXPORT;
-    }
+  if (xcoff_auto_export_p (h, ldinfo->auto_export_flags))
+    h->flags |= XCOFF_EXPORT;
 
   /* We don't want to garbage collect symbols which are not defined in
      XCOFF files.  This is a convenient place to mark them.  */
@@ -3181,10 +3248,9 @@ xcoff_keep_symbol_p (struct bfd_link_inf
    -bmaxdata linker option).  GC is whether to do garbage collection
    (the -bgc linker option).  MODTYPE is the module type (the
    -bmodtype linker option).  TEXTRO is whether the text section must
-   be read only (the -btextro linker option).  EXPORT_DEFINEDS is
-   whether all defined symbols should be exported (the -unix linker
-   option).  SPECIAL_SECTIONS is set by this routine to csects with
-   magic names like _end.  */
+   be read only (the -btextro linker option).  AUTO_EXPORT_FLAGS
+   is a mask of XCOFF_EXPALL and XCOFF_EXPFULL.  SPECIAL_SECTIONS
+   is set by this routine to csects with magic names like _end.  */
 
 bfd_boolean
 bfd_xcoff_size_dynamic_sections (bfd *output_bfd,
@@ -3197,7 +3263,7 @@ bfd_xcoff_size_dynamic_sections (bfd *ou
 				 bfd_boolean gc,
 				 int modtype,
 				 bfd_boolean textro,
-				 bfd_boolean export_defineds,
+				 unsigned int auto_export_flags,
 				 asection **special_sections,
 				 bfd_boolean rtld)
 {
@@ -3225,7 +3291,7 @@ bfd_xcoff_size_dynamic_sections (bfd *ou
   ldinfo.failed = FALSE;
   ldinfo.output_bfd = output_bfd;
   ldinfo.info = info;
-  ldinfo.export_defineds = export_defineds;
+  ldinfo.auto_export_flags = auto_export_flags;
   ldinfo.ldsym_count = 0;
   ldinfo.string_size = 0;
   ldinfo.strings = NULL;
@@ -3328,6 +3394,13 @@ bfd_xcoff_size_dynamic_sections (bfd *ou
       if (info->fini_function != NULL
 	  && !xcoff_mark_symbol_by_name (info, info->fini_function, 0))
 	goto error_return;
+      if (auto_export_flags != 0)
+	{
+	  xcoff_link_hash_traverse (xcoff_hash_table (info),
+				    xcoff_mark_auto_exports, &ldinfo);
+	  if (ldinfo.failed)
+	    goto error_return;
+	}
       xcoff_sweep (info);
       xcoff_hash_table (info)->gc = TRUE;
     }
Index: ld/emultempl/aix.em
===================================================================
--- ld/emultempl/aix.em	2009-03-10 13:46:23.000000000 +0000
+++ ld/emultempl/aix.em	2009-03-10 13:52:51.000000000 +0000
@@ -84,6 +84,14 @@ static unsigned short modtype = ('1' << 
    permitted).  */
 static int textro;
 
+/* A mask of XCOFF_EXPALL and XCOFF_EXPFULL flags, as set by their
+   associated -b and -bno options.  */
+static unsigned int auto_export_flags;
+
+/* A mask of auto_export_flags bits that were explicitly set on the
+   command line.  */
+static unsigned int explicit_auto_export_flags;
+
 /* Whether to implement Unix like linker semantics.  */
 static int unix_ld;
 
@@ -156,6 +164,8 @@ enum
     OPTION_AUTOIMP,
     OPTION_ERNOTOK,
     OPTION_EROK,
+    OPTION_EXPALL,
+    OPTION_EXPFULL,
     OPTION_EXPORT,
     OPTION_IMPORT,
     OPTION_INITFINI,
@@ -164,6 +174,8 @@ enum
     OPTION_MAXSTACK,
     OPTION_MODTYPE,
     OPTION_NOAUTOIMP,
+    OPTION_NOEXPALL,
+    OPTION_NOEXPFULL,
     OPTION_NOSTRCMPCT,
     OPTION_PD,
     OPTION_PT,
@@ -201,6 +213,8 @@ gld${EMULATION_NAME}_add_options
     {"bernotok", no_argument, NULL, OPTION_ERNOTOK},
     {"berok", no_argument, NULL, OPTION_EROK},
     {"berrmsg", no_argument, NULL, OPTION_IGNORE},
+    {"bexpall", no_argument, NULL, OPTION_EXPALL},
+    {"bexpfull", no_argument, NULL, OPTION_EXPFULL},
     {"bexport", required_argument, NULL, OPTION_EXPORT},
     {"bf", no_argument, NULL, OPTION_ERNOTOK},
     {"bgc", no_argument, &gc, 1},
@@ -216,6 +230,8 @@ gld${EMULATION_NAME}_add_options
     {"bM", required_argument, NULL, OPTION_MODTYPE},
     {"bmodtype", required_argument, NULL, OPTION_MODTYPE},
     {"bnoautoimp", no_argument, NULL, OPTION_NOAUTOIMP},
+    {"bnoexpall", no_argument, NULL, OPTION_NOEXPALL},
+    {"bnoexpfull", no_argument, NULL, OPTION_NOEXPFULL},
     {"bnodelcsect", no_argument, NULL, OPTION_IGNORE},
     {"bnoentry", no_argument, NULL, OPTION_IGNORE},
     {"bnogc", no_argument, &gc, 0},
@@ -388,6 +404,16 @@ gld${EMULATION_NAME}_handle_option (int 
       link_info.unresolved_syms_in_shared_libs = RM_IGNORE;
       break;
 
+    case OPTION_EXPALL:
+      auto_export_flags |= XCOFF_EXPALL;
+      explicit_auto_export_flags |= XCOFF_EXPALL;
+      break;
+
+    case OPTION_EXPFULL:
+      auto_export_flags |= XCOFF_EXPFULL;
+      explicit_auto_export_flags |= XCOFF_EXPFULL;
+      break;
+
     case OPTION_EXPORT:
       gld${EMULATION_NAME}_read_file (optarg, FALSE);
       break;
@@ -444,6 +470,16 @@ gld${EMULATION_NAME}_handle_option (int 
       link_info.static_link = TRUE;
       break;
 
+    case OPTION_NOEXPALL:
+      auto_export_flags &= ~XCOFF_EXPALL;
+      explicit_auto_export_flags |= XCOFF_EXPALL;
+      break;
+
+    case OPTION_NOEXPFULL:
+      auto_export_flags &= ~XCOFF_EXPFULL;
+      explicit_auto_export_flags |= XCOFF_EXPFULL;
+      break;
+
     case OPTION_NOSTRCMPCT:
       link_info.traditional_format = TRUE;
       break;
@@ -624,7 +660,7 @@ gld${EMULATION_NAME}_before_allocation (
     ".data",
     ".bss"
   };
-  unsigned int i;
+  unsigned int i, flags;
 
   /* Handle the import and export files, if any.  */
   for (fl = import_files; fl != NULL; fl = fl->next)
@@ -710,11 +746,16 @@ gld${EMULATION_NAME}_before_allocation (
 	}
     }
 
+  /* Default to -bexpfull for SVR4-like semantics.  */
+  flags = (unix_ld ? XCOFF_EXPFULL : 0);
+  flags &= ~explicit_auto_export_flags;
+  flags |= auto_export_flags;
+
   /* Let the XCOFF backend set up the .loader section.  */
   if (!bfd_xcoff_size_dynamic_sections
       (link_info.output_bfd, &link_info, libpath, entry_symbol.name, file_align,
        maxstack, maxdata, gc && !unix_ld ? TRUE : FALSE,
-       modtype,	textro ? TRUE : FALSE, unix_ld, special_sections,
+       modtype, textro ? TRUE : FALSE, flags, special_sections,
        rtld ? TRUE : FALSE))
     einfo ("%P%F: failed to set dynamic section sizes: %E\n");
 
Index: ld/testsuite/ld-powerpc/aix-export-1-all.dd
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-export-1-all.dd	2009-03-10 13:52:51.000000000 +0000
@@ -0,0 +1,11 @@
+
+.*
+
+
+Disassembly of section \.data:
+
+0*10000000 <main1>:
+ *10000000:	10 00 00 04 	.*
+
+0*10000004 <lib1>:
+ *10000004:	11 11 00 01 	.*
Index: ld/testsuite/ld-powerpc/aix-export-1-full.dd
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-export-1-full.dd	2009-03-10 13:52:51.000000000 +0000
@@ -0,0 +1,21 @@
+
+.*
+
+
+Disassembly of section .data:
+
+0*10000000 <main1>:
+ *10000000:	10 00 00 08 	.*
+
+0*10000004 <_main2>:
+ *10000004:	10 00 00 0c 	.*
+
+0*10000008 <lib1>:
+ *10000008:	11 11 00 01 	.*
+
+0*1000000c <_lib2>:
+ *1000000c:	11 11 00 02 	.*
+
+0*10000010 <lib3>:
+ *10000010:	11 11 00 03 	.*
+ *10000014:	00 00 00 00 	.*
Index: ld/testsuite/ld-powerpc/aix-export-1a.s
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-export-1a.s	2009-03-10 13:52:51.000000000 +0000
@@ -0,0 +1,14 @@
+	.globl	lib1
+	.csect	lib1[RW]
+lib1:
+	.long	0x11110001
+
+	.globl	_lib2
+	.csect	_lib2[RW]
+_lib2:
+	.long	0x11110002
+
+	.globl	lib3
+	.csect	lib3[RW]
+lib3:
+	.long	0x11110003
Index: ld/testsuite/ld-powerpc/aix-export-1b.s
===================================================================
--- /dev/null	2009-02-06 09:11:03.343159000 +0000
+++ ld/testsuite/ld-powerpc/aix-export-1b.s	2009-03-10 13:52:51.000000000 +0000
@@ -0,0 +1,9 @@
+	.globl	main1
+	.csect	main1[RW]
+main1:
+	.long	lib1
+
+	.globl	_main2
+	.csect	_main2[RW]
+_main2:
+	.long	_lib2
Index: ld/testsuite/ld-powerpc/aix52.exp
===================================================================
--- ld/testsuite/ld-powerpc/aix52.exp	2009-03-10 13:52:29.000000000 +0000
+++ ld/testsuite/ld-powerpc/aix52.exp	2009-03-10 13:52:51.000000000 +0000
@@ -108,6 +108,26 @@ set aix52tests {
       {nm -D aix-no-dup-syms-1-dso.dnd} {objdump -R aix-no-dup-syms-1-dso.drd}}
      "aix-no-dup-syms-1.so"}
 
+    {"Export test 1 (archive)" ""
+      "" {aix-export-1a.s}
+      {} "libaix-export-1.a"}
+
+    {"Export test 1 (object)" "-r"
+      "" {aix-export-1b.s}
+      {} "aix-export-1.o"}
+
+    {"Export test 1 (-bexpall)"
+     "-shared -bexpall tmpdir/aix-export-1.o -Ltmpdir -laix-export-1"
+     "" {}
+     {{objdump -dj.data aix-export-1-all.dd}}
+     "aix-export-1-all.so"}
+
+    {"Export test 1 (-bexpfull)"
+     "-shared -bexpfull tmpdir/aix-export-1.o -Ltmpdir -laix-export-1"
+     "" {}
+     {{objdump -dj.data aix-export-1-full.dd}}
+     "aix-export-1-full.so"}
+
     {"Garbage collection test 1"
      "-shared -binitfini:init_function:fini_function -bE:aix-gc-1.ex"
      "" {aix-gc-1.s}


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