[binutils-gdb] Add support to the static linker for the tokens accepted by the dynamic linker when resolving search

Nick Clifton nickc@sourceware.org
Tue Oct 11 11:13:00 GMT 2016


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=199fa1b7089d7f7438b087fa30504ea5a590f561

commit 199fa1b7089d7f7438b087fa30504ea5a590f561
Author: Nick Clifton <nickc@redhat.com>
Date:   Tue Oct 11 12:04:42 2016 +0100

    Add support to the static linker for the tokens accepted by the dynamic linker when resolving search paths.
    
    	PR ld/20535
    	* emultempl/elf32.em (_search_needed): Add support for pseudo
    	environment variables supported by ld.so.  Namely $ORIGIN, $LIB
    	and $PLATFORM.
    	* configure.ac: Add getauxval to list AC_CHECK_FUNCS list.
    	* config.in: Regenerate.
    	* configure: Regenerate.

Diff:
---
 ld/ChangeLog          |  10 ++++
 ld/config.in          |   3 +
 ld/configure          |   2 +-
 ld/configure.ac       |   2 +-
 ld/emultempl/elf32.em | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 166 insertions(+), 2 deletions(-)

diff --git a/ld/ChangeLog b/ld/ChangeLog
index 1c71de1..4c296bf 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,13 @@
+2016-10-11  Nick Clifton  <nickc@redhat.com>
+
+	PR ld/20535
+	* emultempl/elf32.em (_search_needed): Add support for pseudo
+	environment variables supported by ld.so.  Namely $ORIGIN, $LIB
+	and $PLATFORM.
+	* configure.ac: Add getauxval to list AC_CHECK_FUNCS list.
+	* config.in: Regenerate.
+	* configure: Regenerate.
+
 2016-10-11  Alan Modra  <amodra@gmail.com>
 
 	* ldlang.c (lang_do_assignments_1): Descend into output section
diff --git a/ld/config.in b/ld/config.in
index 2c6d698..5c614ed 100644
--- a/ld/config.in
+++ b/ld/config.in
@@ -62,6 +62,9 @@
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
+/* Define to 1 if you have the `getauxval' function. */
+#undef HAVE_GETAUXVAL
+
 /* Define to 1 if you have the `getpagesize' function. */
 #undef HAVE_GETPAGESIZE
 
diff --git a/ld/configure b/ld/configure
index 3f82f35..2c55b28 100755
--- a/ld/configure
+++ b/ld/configure
@@ -16488,7 +16488,7 @@ _ACEOF
 fi
 done
 
-for ac_func in open lseek close
+for ac_func in getauxval open lseek close
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/ld/configure.ac b/ld/configure.ac
index d17281f..4542845 100644
--- a/ld/configure.ac
+++ b/ld/configure.ac
@@ -216,7 +216,7 @@ AC_CHECK_HEADERS(string.h strings.h stdlib.h unistd.h elf-hints.h limits.h local
 AC_CHECK_HEADERS(fcntl.h sys/file.h sys/time.h sys/stat.h)
 ACX_HEADER_STRING
 AC_CHECK_FUNCS(glob mkstemp realpath sbrk setlocale waitpid)
-AC_CHECK_FUNCS(open lseek close)
+AC_CHECK_FUNCS(getauxval open lseek close)
 AC_HEADER_DIRENT
 
 dnl AC_CHECK_HEADERS(sys/mman.h)
diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em
index 2815a3e..06f02c6 100644
--- a/ld/emultempl/elf32.em
+++ b/ld/emultempl/elf32.em
@@ -472,6 +472,15 @@ fragment <<EOF
   return TRUE;
 }
 
+EOF
+if [ "x${NATIVE}" = xyes ] ; then
+fragment <<EOF
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+EOF
+fi
+fragment <<EOF
 
 /* Search for a needed file in a path.  */
 
@@ -496,6 +505,7 @@ gld${EMULATION_NAME}_search_needed (const char *path,
   len = strlen (name);
   while (1)
     {
+      char * var;
       char *filename, *sset;
 
       s = strchr (path, config.rpath_separator);
@@ -524,6 +534,147 @@ gld${EMULATION_NAME}_search_needed (const char *path,
 	}
       strcpy (sset, name);
 
+      /* PR 20535: Support the same pseudo-environment variables that
+	 are supported by ld.so.  Namely, $ORIGIN, $LIB and $PLATFORM.
+         Since there can be more than one occurrence of these tokens in
+	 the path we loop until no more are found.  */
+      while ((var = strchr (filename, '$')) != NULL)
+	{
+	  /* The ld.so manual page does not say, but I am going to assume that
+	     these tokens are terminated by a directory seperator character
+	     (/) or the end of the string.  There is also an implication that
+	     $ORIGIN should only be used at the start of a path, but that is
+	     not enforced here.
+
+	     FIXME: The ld.so manual page also states that it allows ${ORIGIN}
+	     ${LIB} and ${PLATFORM}.  We should support these variants too.
+
+	     FIXME: The code could be a lot cleverer about allocating space
+	     for the processed string.  */
+	  char *    end = strchr (var, '/');
+	  char *    replacement = NULL;
+	  char *    freeme = NULL;
+	  unsigned  flen = strlen (filename);
+
+	  if (end != NULL)
+	    /* Temporarily terminate the filename at the end of the token.  */
+	    * end = 0;
+
+	  switch (var[1])
+	    {
+	    case 'O':
+	      if (strcmp (var + 2, "RIGIN") == 0)
+		{
+		  /* ORIGIN - replace with the full path to the directory
+		     containing the program or shared object.  */
+		  if (needed.by == NULL)
+		    break;
+		  replacement = bfd_get_filename (needed.by);
+		  if (replacement)
+		    {
+		      char * slash;
+
+		      if (replacement[0] == '/')
+			freeme = xstrdup (replacement);
+		      else
+			{
+			  char * current_dir = getpwd ();
+
+			  freeme = xmalloc (strlen (replacement) + strlen (current_dir));
+			  sprintf (freeme, "%s/%s", current_dir, replacement);
+			}
+
+		      replacement = freeme;
+		      if ((slash = strrchr (replacement, '/')) != NULL)
+			* slash = 0;
+		    }
+		}
+	      break;
+
+	    case 'L':
+	      if (strcmp (var + 2, "IB") == 0)
+		{
+		  /* LIB - replace with "lib" in 32-bit environments
+		     and "lib64" in 64-bit environments.  */
+
+		  /* Note - we could replace this switch statement by
+		     conditional fragments of shell script, but that is messy.
+		     Any compiler worth its salt is going to optimize away
+		     all but one of these case statements anyway.  */
+		  switch ($ELFSIZE)
+		    {
+		    case 32: replacement = "lib"; break;
+		    case 64: replacement = "lib64"; break;
+		    default:
+		      /* $ELFSIZE is not 32 or 64 ...  */
+		      abort ();
+		    }
+		}
+	      break;
+
+	    case 'P':
+	      if (strcmp (var + 2, "LATFORM") == 0)
+		{
+		  /* PLATFORM - replace with a string corresponding
+		     to the processor type of the host system.
+
+		     FIXME: Supporting this token might be a bad idea,
+		     especially for non-native linkers.  It has the potential
+		     to find incorrect results.  Maybe issuing a warning
+		     message would be safer.  Current policy: wait and see if
+		     somebody complains.  */
+		  replacement = "$OUTPUT_ARCH";
+EOF
+# We use getauxval() if it is available, but only for natives.
+if [ "x${NATIVE}" = xyes ] ; then
+fragment <<EOF
+#ifdef HAVE_GETAUXVAL
+		  replacement = (char *) getauxval (AT_PLATFORM);
+#endif
+EOF
+fi
+fragment <<EOF
+		}
+	      break;
+
+	    default:
+	      break;
+	    }
+
+	  if (replacement)
+	    {
+	      char * filename2 = xmalloc (flen + strlen (replacement));
+
+	      if (end)
+		sprintf (filename2, "%.*s%s/%s",
+			 (int)(var - filename), filename,
+			 replacement, end + 1);
+	      else
+		sprintf (filename2, "%.*s%s",
+			 (int)(var - filename), filename,
+			 replacement);
+		
+	      free (filename);
+	      filename = filename2;
+	      /* There is no need to restore the path separator (when
+		 end != NULL) as we have replaced the entire string.  */
+	    }
+	  else
+	    {
+	      if (verbose)
+		/* We only issue an "unrecognised" message in verbose mode
+		   as the $<foo> token might be a legitimate component of
+		   a path name in the target's file system.  */
+		info_msg (_("unrecognised token '%s' in search path\n"), var);
+
+	      if (end)
+		/* Restore the path separator.  */
+		* end = '/';
+	    }
+
+	  free (freeme);
+	}
+
       needed.name = filename;
       if (gld${EMULATION_NAME}_try_needed (&needed, force))
 	return TRUE;



More information about the Binutils-cvs mailing list