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 /ld/emultempl | |
parent | 93562a343c26f67d2bd0e93cceb18a0a793087c2 (diff) | |
download | gdb-199fa1b7089d7f7438b087fa30504ea5a590f561.zip gdb-199fa1b7089d7f7438b087fa30504ea5a590f561.tar.gz 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.
Diffstat (limited to 'ld/emultempl')
-rw-r--r-- | ld/emultempl/elf32.em | 151 |
1 files changed, 151 insertions, 0 deletions
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; |