This is the mail archive of the binutils@sources.redhat.com 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]

[PATCH] Skipping of incompatible linker scripts in search path


Hi!

On a bi-arch linux system, there is /usr/lib/libc.so with:
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
and /usr/lib64/libc.so with:
GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a )
Now, say when linking 64-bit binary or library, as long as -L/usr/lib64
preceedes -L/usr/lib, all is fine, but if -L/usr/lib comes first, the link
will fail. If libc.so was not a linker script, ldfile_try_open_bfd would
just skip it as incompatible library and continue searching.
Now it reads it but as there is no search but full paths to objects,
it dies because the two inputs are incompatible.
The following patch skips linker scripts similarly to .so/.a/.o files when
searching, if they contain OUTPUT_FORMAT () statement which doesn't match
current output_format.
Ie. say IA-32 /usr/lib/libc.so would contain:
OUTPUT_FORMAT ( elf32-i386 )
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a )
and x86-64 /usr/lib64/libc.so would contain:
OUTPUT_FORMAT ( elf64-x86-64 )
GROUP ( /lib64/libc.so.6 /usr/lib64/libc_nonshared.a )
Unless OUTPUT_FORMAT is specified in -T linker script, linker does nothing
for it, so using OUTPUT_FORMAT is compatible with older linkers too.
I haven't used yyparse because it would require far more changes to
actually free all the various structures yyparse allocates.

2002-10-10  Jakub Jelinek  <jakub@redhat.com>

	* ldfile.c (ldfile_try_open_bfd): When searching skip linker scripts if
	they have OUTPUT_FORMAT not matching actual output format.
	* ldlang.c (lang_get_output_target): New function.
	(open_output): Use it.
	* ldlang.h (lang_get_output_target): New prototype.

--- ld/ldfile.c.jj	2002-10-01 10:26:18.000000000 +0200
+++ ld/ldfile.c	2002-10-10 01:13:27.000000000 +0200
@@ -131,7 +131,99 @@ ldfile_try_open_bfd (attempt, entry)
       if (check != NULL)
 	{
 	  if (! bfd_check_format (check, bfd_object))
-	    return true;
+	    {
+	      if (check == entry->the_bfd
+		  && bfd_get_error () == bfd_error_file_not_recognized
+		  && ! ldemul_unrecognized_file (entry))
+		{
+		  int token, skip = 0;
+		  char *arg, *arg1, *arg2, *arg3;
+		  extern FILE *yyin;
+
+		  /* Try to interpret the file as a linker script.  */
+		  ldfile_open_command_file (attempt);
+		              
+		  ldfile_assumed_script = true;
+		  parser_input = input_selected;
+		  ldlex_both ();
+		  token = INPUT_SCRIPT;
+		  while (token != 0)
+		    {
+		      switch (token)
+			{
+			case OUTPUT_FORMAT:
+			  if ((token = yylex ()) != '(')
+			    continue;
+			  if ((token = yylex ()) != NAME)
+			    continue;
+			  arg1 = yylval.name;
+			  arg2 = NULL;
+			  arg3 = NULL;
+			  token = yylex ();
+			  if (token == ',')
+			    {
+			      if ((token = yylex ()) != NAME)
+				{
+				  free (arg1);
+				  continue;
+				}
+			      arg2 = yylval.name;
+			      if ((token = yylex ()) != ','
+				  || (token = yylex ()) != NAME)
+				{
+				  free (arg1);
+				  free (arg2);
+				  continue;
+				}
+			      arg3 = yylval.name;
+			      token = yylex ();
+			    }
+			  if (token == ')')
+			    {
+			      switch (command_line.endian)
+				{
+				default:
+				case ENDIAN_UNSET:
+				  arg = arg1; break;
+				case ENDIAN_BIG:
+				  arg = arg2 ? arg2 : arg1; break;
+				case ENDIAN_LITTLE:
+				  arg = arg3 ? arg3 : arg1; break;
+				}
+			      if (strcmp (arg, lang_get_output_target ()) != 0)
+				skip = 1;
+			    }
+			  free (arg1);
+			  if (arg2) free (arg2);
+			  if (arg3) free (arg3);
+			  break;
+			case NAME:
+			case LNAME:
+			case VERS_IDENTIFIER:
+			case VERS_TAG:
+			  free (yylval.name);
+			  break;
+			case INT:
+			  if (yylval.bigint.str)
+			    free (yylval.bigint.str);
+			  break;
+		        }
+		      token = yylex ();
+		    }
+		  ldfile_assumed_script = false;
+		  fclose (yyin);
+		  yyin = NULL;
+		  if (skip)
+		    {
+		      einfo (_("%P: skipping incompatible %s when searching for %s\n"),
+			     attempt, entry->local_sym_name);
+		      bfd_close (entry->the_bfd);
+		      entry->the_bfd = NULL;
+		      return false;
+		    }
+		}
+	      return true;
+	    }
 
 	  if ((bfd_arch_get_compatible (check, output_bfd) == NULL)
 	      /* XCOFF archives can have 32 and 64 bit objects */
--- ld/ldlang.c.jj	2002-10-09 16:35:53.000000000 +0200
+++ ld/ldlang.c	2002-10-10 00:52:46.000000000 +0200
@@ -1787,6 +1787,29 @@ get_first_input_target ()
   return target;
 }
 
+const char *
+lang_get_output_target ()
+{
+  const char *target;
+
+  /* Has the user told us which output format to use?  */
+  if (output_target != (char *) NULL)
+    return output_target;
+
+  /* No - has the current target been set to something other than
+     the default?  */
+  if (current_target != default_target)
+    return current_target;
+
+  /* No - can we determine the format of the first input file?  */
+  target = get_first_input_target ();
+  if (target != NULL)
+    return target;
+
+  /* Failed - use the default output target.  */
+  return default_target;
+}
+
 /* Open the output file.  */
 
 static bfd *
@@ -1795,24 +1818,7 @@ open_output (name)
 {
   bfd *output;
 
-  /* Has the user told us which output format to use?  */
-  if (output_target == (char *) NULL)
-    {
-      /* No - has the current target been set to something other than
-         the default?  */
-      if (current_target != default_target)
-	output_target = current_target;
-
-      /* No - can we determine the format of the first input file?  */
-      else
-	{
-	  output_target = get_first_input_target ();
-
-	  /* Failed - use the default output target.  */
-	  if (output_target == NULL)
-	    output_target = default_target;
-	}
-    }
+  output_target = lang_get_output_target ();
 
   /* Has the user requested a particular endianness on the command
      line?  */
--- ld/ldlang.h.jj	2002-10-09 16:35:53.000000000 +0200
+++ ld/ldlang.h	2002-10-10 00:53:07.000000000 +0200
@@ -483,5 +483,6 @@ extern void lang_register_vers_node
 	   struct bfd_elf_version_deps *));
 boolean unique_section_p PARAMS ((const char *));
 extern void lang_add_unique PARAMS ((const char *));
+extern const char *lang_get_output_target PARAMS ((void));
 
 #endif

	Jakub


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