+ /* 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. Since we might not
+ be able to substitute some of the tokens we maintain an offset
+ into the filename for where we should begin our scan. */
+ while ((var = strchr (filename + offset, '$')) != NULL)
+ {
+ /* The ld.so manual page does not say, but I am going to assume that
+ these tokens are terminated by a directory separator 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.
+
+ The ld.so manual page also states that it allows ${ORIGIN},
+ ${LIB} and ${PLATFORM}, so these are supported as well.
+
+ FIXME: The code could be a lot cleverer about allocating space
+ for the processed string. */
+ char * end = strchr (var, '/');
+ char * replacement = NULL;
+ char * v = var + 1;
+ char * freeme = NULL;
+ unsigned flen = strlen (filename);
+
+ if (end != NULL)
+ /* Temporarily terminate the filename at the end of the token. */
+ * end = 0;
+
+ if (*v == '{')
+ ++ v;
+ switch (*v++)
+ {
+ case 'O':
+ if (strcmp (v, "RIGIN") == 0 || strcmp (v, "RIGIN}") == 0)
+ {
+ /* ORIGIN - replace with the full path to the directory
+ containing the program or shared object. */
+ if (needed.by == NULL)
+ {
+ if (link_info.output_bfd == NULL)
+ {
+ break;
+ }
+ else
+ replacement = bfd_get_filename (link_info.output_bfd);
+ }
+ else
+ 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) + 2);
+ sprintf (freeme, "%s/%s", current_dir, replacement);
+ }
+
+ replacement = freeme;
+ if ((slash = strrchr (replacement, '/')) != NULL)
+ * slash = 0;
+ }
+ }
+ break;
+
+ case 'L':
+ if (strcmp (v, "IB") == 0 || strcmp (v, "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':
+ /* Supporting $PLATFORM in a cross-hosted environment is not
+ possible. Supporting it in a native environment involves
+ loading the <sys/auxv.h> header file which loads the
+ system <elf.h> header file, which conflicts with the
+ "include/elf/mips.h" header file. */
+ /* Fall through. */
+ default:
+ break;
+ }
+
+ if (replacement)
+ {
+ char * filename2 = xmalloc (flen + strlen (replacement));
+
+ if (end)
+ {
+ sprintf (filename2, "%.*s%s/%s",
+ (int)(var - filename), filename,
+ replacement, end + 1);
+ offset = (var - filename) + 1 + strlen (replacement);
+ }
+ else
+ {
+ sprintf (filename2, "%.*s%s",
+ (int)(var - filename), filename,
+ replacement);
+ offset = var - filename + strlen (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 or unsupported token '%s' in search path\n"), var);
+
+ if (end)
+ /* Restore the path separator. */
+ * end = '/';
+
+ /* PR 20784: Make sure that we resume the scan *after*
+ the token that we could not replace. */
+ offset = (var + 1) - filename;
+ }
+
+ free (freeme);
+ }
+