+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.
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
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
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");
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;
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. */
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;
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;
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;
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
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;
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
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;