diff options
author | Nick Clifton <nickc@redhat.com> | 2016-10-11 12:04:42 +0100 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 2016-10-11 12:13:43 +0100 |
commit | 199fa1b7089d7f7438b087fa30504ea5a590f561 (patch) | |
tree | 7cbfb0745751bb172694d4d402d354d37b697e21 | |
parent | 93562a343c26f67d2bd0e93cceb18a0a793087c2 (diff) | |
download | fsf-binutils-gdb-199fa1b7089d7f7438b087fa30504ea5a590f561.zip fsf-binutils-gdb-199fa1b7089d7f7438b087fa30504ea5a590f561.tar.gz fsf-binutils-gdb-199fa1b7089d7f7438b087fa30504ea5a590f561.tar.bz2 |
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.
-rw-r--r-- | ld/ChangeLog | 10 | ||||
-rw-r--r-- | ld/config.in | 3 | ||||
-rwxr-xr-x | ld/configure | 2 | ||||
-rw-r--r-- | ld/configure.ac | 2 | ||||
-rw-r--r-- | 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; |