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]

stateful handling of some ld flags


This patch is a possible solution for a problem that bugged me for a
very long time.  If you provide rules to link with a set of libraries
(for instance, when using pkg-config) one cannot use --as-needed,
--copy-dt-needed-entries, --whole-archive (and the respective inverse
versions) because it is not known what the current state is.  One cannot
switch back.

Other programs, for instance, gcc have similar problems.  A solution is
to use push/pop pairs.

This patch implements this for this three sets of command line options.
No need to do this for the linker script equivalent, it already does the
right thing.

I don't think it is possible to have a general push state/pop state
pair, there are simply too many settings which can or cannot be assumed
to be affected.

What do you think?


2014-06-28  Ulrich Drepper  <drepper@gmail.com>

	* ldang.h (struct lang_input_statements_flags): Change type of
	add_DT_NEEDED_for_dynamic, add_DT_NEEDED_for_regular, and whole_archive
	to use unsigned.
	* ldlex.h (enum option_values): Add OPTION_NO_WHOLE_ARCHIVE_PUSH,
	OPTION_WHOLE_ARCHIVE_PUSH, OPTION_WHOLE_ARCHIVE_POP,
	OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH,
	OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH,
	OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_POP,
	OPTION_ADD_DT_NEEDED_FOR_REGULAR_PUSH,
	OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR_PUSH, and
	OPTION_ADD_DT_NEEDED_POP.
	* lexsup.c (ld_optins): Add --as-needed-push, --no-as-needed-push,
	-- as-needed-pop, --copy-dt-needed-entries-push,
	--no-copy-dt-needed-entries-push, --copy-dt-needed-entries-pop,
	--no-whole-archive-push, --whole-archive-push, --whole-archive-pop.
	(parse_args): Handle the new options.
	* ldlang.c (load_symbols): Use only least bit of
	entry->flags.whole_archive.
	(open_input_bfds): Likewise of s->input_statement.flags.whole_archive
	and s->input_statement.flags.add_DT_NEEDED_for_regular.
	* ldgram.y: Use 1 instead of TRUE in AS_NEEDED rules.
	* emultempl/elf32.em (gld${EMULATION_NAME}_load_symbols): Use only
	least bit of entry->flags.add_DT_NEEDED_for_regular and
	entry->flags.add_DT_NEEDED_for_dynamic.


diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 39b4ccd..da949e7 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -119,13 +119,13 @@ gld${EMULATION_NAME}_load_symbols (lang_input_statement_type *entry)
   /* Tell the ELF linker that we don't want the output file to have a
      DT_NEEDED entry for this file, unless it is used to resolve
      references in a regular object.  */
-  if (entry->flags.add_DT_NEEDED_for_regular)
+  if (entry->flags.add_DT_NEEDED_for_regular & 1)
     link_class = DYN_AS_NEEDED;

   /* Tell the ELF linker that we don't want the output file to have a
      DT_NEEDED entry for any dynamic library in DT_NEEDED tags from
      this file at all.  */
-  if (!entry->flags.add_DT_NEEDED_for_dynamic)
+  if (!(entry->flags.add_DT_NEEDED_for_dynamic & 1))
     link_class |= DYN_NO_ADD_NEEDED;

   if (entry->flags.just_syms
diff --git a/ld/ldgram.y b/ld/ldgram.y
index 4875fa7..ff1e561 100644
--- a/ld/ldgram.y
+++ b/ld/ldgram.y
@@ -385,17 +385,17 @@ input_list:
				 (char *)NULL); }
	|	AS_NEEDED '('
		  { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
-		    input_flags.add_DT_NEEDED_for_regular = TRUE; }
+		    input_flags.add_DT_NEEDED_for_regular = 1; }
		     input_list ')'
		  { input_flags.add_DT_NEEDED_for_regular = $<integer>3; }
	|	input_list ',' AS_NEEDED '('
		  { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
-		    input_flags.add_DT_NEEDED_for_regular = TRUE; }
+		    input_flags.add_DT_NEEDED_for_regular = 1; }
		     input_list ')'
		  { input_flags.add_DT_NEEDED_for_regular = $<integer>5; }
	|	input_list AS_NEEDED '('
		  { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
-		    input_flags.add_DT_NEEDED_for_regular = TRUE; }
+		    input_flags.add_DT_NEEDED_for_regular = 1; }
		     input_list ')'
		  { input_flags.add_DT_NEEDED_for_regular = $<integer>4; }
	;
diff --git a/ld/ldlang.c b/ld/ldlang.c
index e7c9669..69be3c1 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -2801,7 +2801,7 @@ load_symbols (lang_input_statement_type *entry,
     case bfd_archive:
       check_excluded_libs (entry->the_bfd);

-      if (entry->flags.whole_archive)
+      if (entry->flags.whole_archive & 1)
	{
	  bfd *member = NULL;
	  bfd_boolean loaded = TRUE;
@@ -3280,7 +3280,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
		  && ((mode & OPEN_BFD_RESCAN) == 0
		      || plugin_insert == NULL)
 #endif
-		  && !s->input_statement.flags.whole_archive
+		  && !(s->input_statement.flags.whole_archive & 1)
		  && s->input_statement.flags.loaded
		  && s->input_statement.the_bfd != NULL
		  && bfd_check_format (s->input_statement.the_bfd,
@@ -3291,7 +3291,7 @@ open_input_bfds (lang_statement_union_type *s, enum open_bfd_mode mode)
	      else if ((mode & OPEN_BFD_RESCAN) != 0
		       && plugin_insert == NULL
		       && s->input_statement.flags.loaded
-		       && s->input_statement.flags.add_DT_NEEDED_for_regular
+		       && (s->input_statement.flags.add_DT_NEEDED_for_regular & 1)
		       && s->input_statement.the_bfd != NULL
		       && ((s->input_statement.the_bfd->flags) & DYNAMIC) != 0
		       && plugin_should_reload (s->input_statement.the_bfd))
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 7d69c56..c031830 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -252,18 +252,6 @@ struct lang_input_statement_flags
   /* Whether to search for this entry as a dynamic archive.  */
   unsigned int dynamic : 1;

-  /* Set if a DT_NEEDED tag should be added not just for the dynamic library
-     explicitly given by this entry but also for any dynamic libraries in
-     this entry's needed list.  */
-  unsigned int add_DT_NEEDED_for_dynamic : 1;
-
-  /* Set if this entry should cause a DT_NEEDED tag only when some
-     regular file references its symbols (ie. --as-needed is in effect).  */
-  unsigned int add_DT_NEEDED_for_regular : 1;
-
-  /* Whether to include the entire contents of an archive.  */
-  unsigned int whole_archive : 1;
-
   /* Set when bfd opening is successful.  */
   unsigned int loaded : 1;

@@ -282,6 +270,27 @@ struct lang_input_statement_flags
   /* Set if reloading an --as-needed lib.  */
   unsigned int reload : 1;
 #endif /* ENABLE_PLUGINS */
+
+  /* The lowest bit is set if a DT_NEEDED tag should be added not just for
+     the dynamic library explicitly given by this entry but also for any
+     dynamic libraries in this entry's needed list.  The higher bits are
+     previously set values which can be restored with an appropriate pop
+     operation.  The even bits is the value, the odd bits indicate whether
+     the pair of bits is actually valid.  */
+  unsigned int add_DT_NEEDED_for_dynamic;
+
+  /* The lowest bit is set if this entry should cause a DT_NEEDED tag only
+     when some regular file references its symbols (ie. --as-needed is in
+     effect).  The higher bits are previously set values which can be
+     restored with an appropriate pop operation.  The even bits is the value,
+     the odd bits indicate whether the pair of bits is actually valid.  */
+  unsigned int add_DT_NEEDED_for_regular;
+
+  /* The lowest bit indicated whether to include the entire contents of
+     an archive. The higher bits are previously set values which can be
+     restored with an appropriate pop operation.  The even bits is the value,
+     the odd bits indicate whether the pair of bits is actually valid.  */
+  unsigned int whole_archive;
 };

 typedef struct lang_input_statement_struct
diff --git a/ld/ldlex.h b/ld/ldlex.h
index b2753c3..8b50184 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -49,6 +49,7 @@ enum option_values
   OPTION_NOINHIBIT_EXEC,
   OPTION_NON_SHARED,
   OPTION_NO_WHOLE_ARCHIVE,
+  OPTION_NO_WHOLE_ARCHIVE_PUSH,
   OPTION_OFORMAT,
   OPTION_RELAX,
   OPTION_NO_RELAX,
@@ -89,10 +90,18 @@ enum option_values
   OPTION_SPLIT_BY_RELOC,
   OPTION_SPLIT_BY_FILE ,
   OPTION_WHOLE_ARCHIVE,
+  OPTION_WHOLE_ARCHIVE_PUSH,
+  OPTION_WHOLE_ARCHIVE_POP,
   OPTION_ADD_DT_NEEDED_FOR_DYNAMIC,
   OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC,
+  OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH,
+  OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH,
+  OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_POP,
   OPTION_ADD_DT_NEEDED_FOR_REGULAR,
   OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR,
+  OPTION_ADD_DT_NEEDED_FOR_REGULAR_PUSH,
+  OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR_PUSH,
+  OPTION_ADD_DT_NEEDED_POP,
   OPTION_WRAP,
   OPTION_FORCE_EXE_SUFFIX,
   OPTION_GC_SECTIONS,
diff --git a/ld/lexsup.c b/ld/lexsup.c
index a8c57d2..2f54231 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -255,6 +255,18 @@ static const struct ld_option ld_options[] =
     '\0', NULL, N_("Always set DT_NEEDED for dynamic libraries mentioned on\n"
		   "                                the command line"),
     TWO_DASHES },
+  { {"as-needed-push", no_argument, NULL, OPTION_ADD_DT_NEEDED_FOR_REGULAR_PUSH},
+    '\0', NULL, N_("Only set DT_NEEDED for following dynamic libs if used,\n"
+		   "                                remember previous setting"),
+    TWO_DASHES },
+  { {"no-as-needed-push", no_argument, NULL, OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR_PUSH},
+    '\0', NULL, N_("Always set DT_NEEDED for dynamic libraries mentioned on\n"
+		   "                                the command line, remember\n"
+		   "                                previous setting"),
+    TWO_DASHES },
+  { {"as-needed-pop", no_argument, NULL, OPTION_ADD_DT_NEEDED_POP},
+    '\0', NULL, N_("Restore previous setting of DT_NEEDED for dynamic libs"),
+    TWO_DASHES },
   { {"assert", required_argument, NULL, OPTION_ASSERT},
     '\0', N_("KEYWORD"), N_("Ignored for SunOS compatibility"), ONE_DASH },
   { {"Bdynamic", no_argument, NULL, OPTION_CALL_SHARED},
@@ -289,6 +301,21 @@ static const struct ld_option ld_options[] =
      OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC},
     '\0', NULL, N_("Do not copy DT_NEEDED links mentioned inside DSOs that follow"),
     TWO_DASHES },
+  { {"copy-dt-needed-entries-push", no_argument, NULL,
+     OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH},
+    '\0', NULL, N_("Copy DT_NEEDED links mentioned inside DSOs that follow,\n"
+		   "                                remember previous setting"),
+    TWO_DASHES },
+  { {"no-copy-dt-needed-entries-push", no_argument, NULL,
+     OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH},
+    '\0', NULL, N_("Do not copy DT_NEEDED links mentioned inside DSOs that follow,\n"
+		   "                                remember previous setting"),
+    TWO_DASHES },
+  { {"copy-dt-needed-entries-pop", no_argument, NULL,
+     OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_POP},
+    '\0', NULL, N_("Restore previous setting for copy DT_NEEDED links mentioned\n"
+		   "                                inside DSOs that follow"),
+    TWO_DASHES },

   { {"cref", no_argument, NULL, OPTION_CREF},
     '\0', NULL, N_("Output cross reference table"), TWO_DASHES },
@@ -365,6 +392,9 @@ static const struct ld_option ld_options[] =
     TWO_DASHES},
   { {"no-whole-archive", no_argument, NULL, OPTION_NO_WHOLE_ARCHIVE},
     '\0', NULL, N_("Turn off --whole-archive"), TWO_DASHES },
+  { {"no-whole-archive-push", no_argument, NULL, OPTION_NO_WHOLE_ARCHIVE_PUSH},
+    '\0', NULL, N_("Turn off --whole-archive, preserve previous setting"),
+    TWO_DASHES },
   { {"noinhibit-exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC},
     '\0', NULL, N_("Create an output file even if errors occur"),
     TWO_DASHES },
@@ -499,6 +529,14 @@ static const struct ld_option ld_options[] =
   { {"whole-archive", no_argument, NULL, OPTION_WHOLE_ARCHIVE},
     '\0', NULL, N_("Include all objects from following archives"),
     TWO_DASHES },
+  { {"whole-archive-push", no_argument, NULL, OPTION_WHOLE_ARCHIVE_PUSH},
+    '\0', NULL, N_("Include all objects from following archives,\n"
+		   "                                preserve previous setting"),
+    TWO_DASHES },
+  { {"whole-archive-pop", no_argument, NULL, OPTION_WHOLE_ARCHIVE_POP},
+    '\0', NULL, N_("Restore previous setting for include all objects from\n"
+		   "                                following archives"),
+    TWO_DASHES },
   { {"wrap", required_argument, NULL, OPTION_WRAP},
     '\0', N_("SYMBOL"), N_("Use wrapper functions for SYMBOL"), TWO_DASHES },
   { {"ignore-unresolved-symbol", required_argument, NULL,
@@ -936,7 +974,14 @@ parse_args (unsigned argc, char **argv)
	  config.only_cmd_line_lib_dirs = TRUE;
	  break;
	case OPTION_NO_WHOLE_ARCHIVE:
-	  input_flags.whole_archive = FALSE;
+	  input_flags.whole_archive &= ~1u;
+	  break;
+	case OPTION_NO_WHOLE_ARCHIVE_PUSH:
+          if (input_flags.whole_archive
+	      & (1u << ((8 * sizeof (unsigned int)) - 1)))
+	    einfo (_("%P%F: nesting of whole archive setting too deep\n"));
+	  input_flags.whole_archive
+	    = (input_flags.whole_archive << 2) | 8u;
	  break;
	case 'O':
	  /* FIXME "-O<non-digits> <value>" used to set the address of
@@ -1337,19 +1382,69 @@ parse_args (unsigned argc, char **argv)
	  link_info.warn_alternate_em = TRUE;
	  break;
	case OPTION_WHOLE_ARCHIVE:
-	  input_flags.whole_archive = TRUE;
+	  input_flags.whole_archive |= 1u;
+	  break;
+	case OPTION_WHOLE_ARCHIVE_PUSH:
+          if (input_flags.whole_archive
+	      & (1u << ((8 * sizeof (unsigned int)) - 1)))
+	    einfo (_("%P%F: nesting of whole archive setting too deep\n"));
+	  input_flags.whole_archive
+	    = (input_flags.whole_archive << 2) | 9u;
+	  break;
+	case OPTION_WHOLE_ARCHIVE_POP:
+          if ((input_flags.whole_archive & 8u) == 0)
+	    einfo (_("%P%F: pop of whole archive setting without push\n"));
+	  input_flags.whole_archive >>= 2;
	  break;
	case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC:
-	  input_flags.add_DT_NEEDED_for_dynamic = TRUE;
+	  input_flags.add_DT_NEEDED_for_dynamic |= 1u;
	  break;
	case OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC:
-	  input_flags.add_DT_NEEDED_for_dynamic = FALSE;
+	  input_flags.add_DT_NEEDED_for_dynamic &= ~1u;
+	  break;
+	case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH:
+          if (input_flags.add_DT_NEEDED_for_dynamic
+	      & (1u << ((8 * sizeof (unsigned int)) - 1)))
+	    einfo (_("%P%F: nesting of DT_NEEDED for links inside mentioned libs settings too deep\n"));
+	  input_flags.add_DT_NEEDED_for_dynamic
+	    = (input_flags.add_DT_NEEDED_for_dynamic << 2) | 9u;
+	  break;
+	case OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC_PUSH:
+          if (input_flags.add_DT_NEEDED_for_dynamic
+	      & (1u << ((8 * sizeof (unsigned int)) - 1)))
+	    einfo (_("%P%F: nesting of DT_NEEDED for links inside mentioned libs settings too deep\n"));
+	  input_flags.add_DT_NEEDED_for_dynamic
+	    = (input_flags.add_DT_NEEDED_for_dynamic << 2) | 8u;
+	  break;
+	case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC_POP:
+          if ((input_flags.add_DT_NEEDED_for_dynamic & 8u) == 0)
+	    einfo (_("%P%F: pop of DT_NEEDED for links inside mentioned libs settings without push\n"));
+	  input_flags.add_DT_NEEDED_for_dynamic >>= 2;
	  break;
	case OPTION_ADD_DT_NEEDED_FOR_REGULAR:
-	  input_flags.add_DT_NEEDED_for_regular = TRUE;
+	  input_flags.add_DT_NEEDED_for_regular |= 1u;
	  break;
	case OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR:
-	  input_flags.add_DT_NEEDED_for_regular = FALSE;
+	  input_flags.add_DT_NEEDED_for_regular &= ~1u;
+	  break;
+	case OPTION_ADD_DT_NEEDED_FOR_REGULAR_PUSH:
+          if (input_flags.add_DT_NEEDED_for_regular
+	      & (1u << ((8 * sizeof (unsigned int)) - 1)))
+	    einfo (_("%P%F: nesting of DT_NEEDED for mentioned libs settings too deep\n"));
+	  input_flags.add_DT_NEEDED_for_regular
+	    = (input_flags.add_DT_NEEDED_for_regular << 2) | 9u;
+	  break;
+	case OPTION_NO_ADD_DT_NEEDED_FOR_REGULAR_PUSH:
+          if (input_flags.add_DT_NEEDED_for_regular
+	      & (1u << ((8 * sizeof (unsigned int)) - 1)))
+	    einfo (_("%P%F: nesting of DT_NEEDED for mentioned libs settings too deep\n"));
+	  input_flags.add_DT_NEEDED_for_regular
+	    = (input_flags.add_DT_NEEDED_for_regular << 2) | 8u;
+	  break;
+	case OPTION_ADD_DT_NEEDED_POP:
+          if ((input_flags.add_DT_NEEDED_for_regular & 8u) == 0)
+	    einfo (_("%P%F: pop of DT_NEEDED for mentioned libs settings without push\n"));
+	  input_flags.add_DT_NEEDED_for_regular >>= 2;
	  break;
	case OPTION_WRAP:
	  add_wrap (optarg);


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