[PATCH] ld: Find files relative to the current linker script for INPUT() and GROUP()
Fangrui Song
maskray@google.com
Mon Apr 20 06:07:12 GMT 2020
For relative paths in INPUT() and GROUP(), search the directory of the
current linker script before searching other paths. This feature makes
it feasible to use relative paths in a linker script to refer to files
not in a library path, e.g.
GROUP(libm-3.a libmvec.a)
or
INPUT(libc++.a.1 libc++abi.a)
Note, extra_search_path does not apply to -l
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 | 10 ++++++++++
ld/ldfile.c | 14 ++++++++++++++
ld/ldlang.c | 30 ++++++++++++++++++++++++++----
ld/ldlang.h | 3 +++
4 files changed, 53 insertions(+), 4 deletions(-)
diff --git a/ld/ChangeLog b/ld/ChangeLog
index dffd363494..d03acbbc28 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -1,3 +1,13 @@
+2020-04-20 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.
+
2020-04-20 Alan Modra <amodra@gmail.com>
* testsuite/ld-powerpc/tlsopt5.s: Rename foo to aaaaa.
diff --git a/ld/ldfile.c b/ld/ldfile.c
index d98429d7b8..2e877d5584 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -416,6 +416,20 @@ ldfile_open_file (lang_input_statement_type *entry)
search_arch_type *arch;
bfd_boolean found = FALSE;
+ /* If extra_search_path is set, entry->filename is a relative path.
+ Search the directory of the current linkerscript 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;
+ }
+ }
+
/* Try to open <filename><suffix> or lib<filename><suffix>.a */
for (arch = search_arch_head; arch != NULL; arch = arch->next)
{
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 0bb5f3c044..f1fc7900f2 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -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,19 @@ name_match (const char *pattern, const char *name)
return strcmp (pattern, name);
}
+static char *
+ldirname (const char *name)
+{
+ const char *base = lbasename (name);
+ while (base > name && IS_DIR_SEPARATOR (base[-1]))
+ --base;
+ if (base == name)
+ return strdup (".");
+ char *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 +1107,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 +1117,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 +1158,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 +1201,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 +2929,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 +3071,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
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 8dd4bfda19..8152659faf 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -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;
--
2.26.1.301.g55bc3eb7cb9-goog
More information about the Binutils
mailing list