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.
This commit is contained in:
Nick Clifton 2016-10-11 12:04:42 +01:00
parent 93562a343c
commit 199fa1b708
5 changed files with 166 additions and 2 deletions

View 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

View 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

2
ld/configure vendored
View File

@ -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"

View 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)

View 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;