For relative paths in INPUT() and GROUP(), search the directory of the current linker...
authorFangrui Song <maskray@google.com>
Wed, 22 Apr 2020 15:20:02 +0000 (16:20 +0100)
committerNick Clifton <nickc@redhat.com>
Wed, 22 Apr 2020 15:20:02 +0000 (16:20 +0100)
PR ld/25806
* ldlang.h (struct lang_input_statement_struct): Add extra_search_path.
* ldlang.c (current_input_file): New.
(ldirname): New.
(new_afile): Add from_filename parameter. Set extra_search_path.
(lang_add_input_file): Pass current_input_file to new_afile.
(load_symbols): Set current_input_file.

ld/ChangeLog
ld/NEWS
ld/ld.texi
ld/ldfile.c
ld/ldlang.c
ld/ldlang.h

index 79f8e63adccc3c4da764e9be36c4e866e03cdcf5..341ad1d90dcd6712bda4444b3eeafac683792908 100644 (file)
@@ -1,3 +1,17 @@
+2020-04-22  Fangrui Song <maskray@google.com>
+
+       PR ld/25806
+       * ldlang.h (struct lang_input_statement_struct): Add extra_search_path.
+       * ldlang.c (current_input_file): New.
+       (ldirname): New.
+       (new_afile): Add from_filename parameter.  Set extra_search_path.
+       (lang_add_input_file): Pass current_input_file to new_afile.
+       (load_symbols): Set current_input_file.
+       * ldfile.c (ldfile_open_file): If extra_search_path has been set
+       then scan it for the file that needs to be opened.
+       * ld.texi: Document the new behaviour.
+       * NEWS: Mention the new feature.
+
 2020-04-22  Alan Modra  <amodra@gmail.com>
 
        * testsuite/ld-scripts/default-script1.d: Correct mingw skip.
diff --git a/ld/NEWS b/ld/NEWS
index 9795b58a5f11ac406a6d13e836f5d21218f91de6..9f5bbe51cf61e6c2ffc60c2eae82828e461c67e2 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -7,6 +7,10 @@
   IMAGIC (0411) for separate instruction and data spaces, and change the
   default format option for pdp11-aout to be --omagic.
 
+* Relative pathnames in INPUT() and GROUP() directives in linker scripts are
+  searched relative to the directory of the linker script before other search
+  paths.
+
 Changes in 2.34:
 
 * The ld check for "PHDR segment not covered by LOAD segment" is more
index 8286af65eefdf9d8b454c1c06eb5af985b1da058..4dc78e65fa251aa5487e3811fff97214b63136c4 100644 (file)
@@ -3657,13 +3657,16 @@ script, and then invoke the linker with nothing but a @samp{-T} option.
 In case a @dfn{sysroot prefix} is configured, and the filename starts
 with the @samp{/} character, and the script being processed was
 located inside the @dfn{sysroot prefix}, the filename will be looked
-for in the @dfn{sysroot prefix}.  Otherwise, the linker will try to
-open the file in the current directory.  If it is not found, the
-linker will search through the archive library search path.
-The @dfn{sysroot prefix} can also be forced by specifying @code{=}
-as the first character in the filename path, or prefixing the filename
-path with @code{$SYSROOT}.  See also the description of @samp{-L} in
-@ref{Options,,Command-line Options}.
+for in the @dfn{sysroot prefix}.  The @dfn{sysroot prefix} can also be forced by specifying
+@code{=} as the first character in the filename path, or prefixing the
+filename path with @code{$SYSROOT}. See also the description of
+@samp{-L} in @ref{Options,,Command-line Options}.
+
+If a @dfn{sysroot prefix} is not used then the linker will try to open
+the file in the directory containing the linker script.  If it is not
+found the linker will then search the current directory.  If it is still
+not found the linker will search through the archive library search
+path.
 
 If you use @samp{INPUT (-l@var{file})}, @command{ld} will transform the
 name to @code{lib@var{file}.a}, as with the command-line argument
index d98429d7b8846f6465a33ec30db722b1c5cf6387..53112c86947fdf222e9517f5b3db4a36a56ff5ad 100644 (file)
@@ -416,7 +416,24 @@ ldfile_open_file (lang_input_statement_type *entry)
       search_arch_type *arch;
       bfd_boolean found = FALSE;
 
-      /* Try to open <filename><suffix> or lib<filename><suffix>.a */
+      /* If extra_search_path is set, entry->filename is a relative path.
+         Search the directory of the current linker script before searching
+         other paths. */
+      if (entry->extra_search_path)
+        {
+          char *path = concat (entry->extra_search_path, slash, entry->filename,
+                               (const char *)0);
+          if (ldfile_try_open_bfd (path, entry))
+            {
+              entry->filename = path;
+              entry->flags.search_dirs = FALSE;
+              return;
+            }
+
+         free (path);
+        }
+
+      /* Try to open <filename><suffix> or lib<filename><suffix>.a.  */
       for (arch = search_arch_head; arch != NULL; arch = arch->next)
        {
          found = ldfile_open_file_search (arch->name, entry, "lib", ".a");
index 0bb5f3c044c23f3ea3c8ddb1b9e70bc27ebf8076..2ef234f90b2324acb176b24878528beeeaa63a52 100644 (file)
@@ -117,6 +117,7 @@ lang_statement_list_type file_chain = { NULL, NULL };
    lang_input_statement_type statement (reached via input_statement field in a
    lang_statement_union).  */
 lang_statement_list_type input_file_chain;
+static const char *current_input_file;
 struct bfd_sym_chain entry_symbol = { NULL, NULL };
 const char *entry_section = ".text";
 struct lang_input_statement_flags input_flags;
@@ -176,6 +177,21 @@ name_match (const char *pattern, const char *name)
   return strcmp (pattern, name);
 }
 
+static char *
+ldirname (const char *name)
+{
+  const char *base = lbasename (name);
+  char *dirname;
+
+  while (base > name && IS_DIR_SEPARATOR (base[-1]))
+    --base;
+  if (base == name)
+    return strdup (".");
+  dirname = strdup (name);
+  dirname[base - name] = '\0';
+  return dirname;
+}
+
 /* If PATTERN is of the form archive:file, return a pointer to the
    separator.  If not, return NULL.  */
 
@@ -1093,7 +1109,8 @@ new_statement (enum statement_enum type,
 static lang_input_statement_type *
 new_afile (const char *name,
           lang_input_file_enum_type file_type,
-          const char *target)
+          const char *target,
+          const char *from_filename)
 {
   lang_input_statement_type *p;
 
@@ -1102,6 +1119,7 @@ new_afile (const char *name,
   p = new_stat (lang_input_statement, stat_ptr);
   memset (&p->the_bfd, 0,
          sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
+  p->extra_search_path = NULL;
   p->target = target;
   p->flags.dynamic = input_flags.dynamic;
   p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic;
@@ -1142,6 +1160,10 @@ new_afile (const char *name,
     case lang_input_file_is_search_file_enum:
       p->filename = name;
       p->local_sym_name = name;
+      /* If name is a relative path, search the directory of the current linker
+         script first. */
+      if (from_filename && !IS_ABSOLUTE_PATH (name))
+        p->extra_search_path = ldirname (from_filename);
       p->flags.real = TRUE;
       p->flags.search_dirs = TRUE;
       break;
@@ -1181,12 +1203,12 @@ lang_add_input_file (const char *name,
         within the sysroot subdirectory.)  */
       unsigned int outer_sysrooted = input_flags.sysrooted;
       input_flags.sysrooted = 0;
-      ret = new_afile (sysrooted_name, file_type, target);
+      ret = new_afile (sysrooted_name, file_type, target, NULL);
       input_flags.sysrooted = outer_sysrooted;
       return ret;
     }
 
-  return new_afile (name, file_type, target);
+  return new_afile (name, file_type, target, current_input_file);
 }
 
 struct out_section_hash_entry
@@ -2909,7 +2931,7 @@ lookup_name (const char *name)
       lang_statement_union_type *rest = *after;
       stat_ptr->tail = after;
       search = new_afile (name, lang_input_file_is_search_file_enum,
-                         default_target);
+                         default_target, NULL);
       *stat_ptr->tail = rest;
       if (*tail == NULL)
        stat_ptr->tail = tail;
@@ -3051,7 +3073,9 @@ load_symbols (lang_input_statement_type *entry,
 
       ldfile_assumed_script = TRUE;
       parser_input = input_script;
+      current_input_file = entry->filename;
       yyparse ();
+      current_input_file = NULL;
       ldfile_assumed_script = FALSE;
 
       /* missing_file is sticky.  sysrooted will already have been
index 8dd4bfda1909675ca7d0eae8022fa821bdae7033..2aa3930f95a31ba1a868d5aab27739fe70938e08 100644 (file)
@@ -293,6 +293,9 @@ typedef struct lang_input_statement_struct
      Usually the same as filename, but for a file spec'd with
      -l this is the -l switch itself rather than the filename.  */
   const char *local_sym_name;
+  /* Extra search path. Used to find a file relative to the
+     directory of the current linker script.  */
+  const char *extra_search_path;
 
   bfd *the_bfd;