Add support to the static linker for the tokens accepted by the dynamic linker when...
authorNick Clifton <nickc@redhat.com>
Tue, 11 Oct 2016 11:04:42 +0000 (12:04 +0100)
committerNick Clifton <nickc@redhat.com>
Tue, 11 Oct 2016 11:13:43 +0000 (12:13 +0100)
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.

ld/ChangeLog
ld/config.in
ld/configure
ld/configure.ac
ld/emultempl/elf32.em

index 1c71de1..4c296bf 100644 (file)
@@ -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
index 2c6d698..5c614ed 100644 (file)
@@ -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
 
index 3f82f35..2c55b28 100755 (executable)
@@ -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"
index d17281f..4542845 100644 (file)
@@ -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)
index 2815a3e..06f02c6 100644 (file)
@@ -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;