aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
authorFangrui Song <maskray@google.com>2020-04-22 16:20:02 +0100
committerNick Clifton <nickc@redhat.com>2020-04-22 16:20:02 +0100
commit161719466ac9ea5f186514312f6bce842181804f (patch)
tree8f5243eadc4f7266ca8362b1da384e9a9aa057c6 /ld
parent31c89d6038f2658f5e06a762aa9e20e78e74651f (diff)
downloadbinutils-161719466ac9ea5f186514312f6bce842181804f.zip
binutils-161719466ac9ea5f186514312f6bce842181804f.tar.gz
binutils-161719466ac9ea5f186514312f6bce842181804f.tar.bz2
For relative paths in INPUT() and GROUP(), search the directory of the current linker script before searching other paths.
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.
Diffstat (limited to 'ld')
-rw-r--r--ld/ChangeLog14
-rw-r--r--ld/NEWS4
-rw-r--r--ld/ld.texi17
-rw-r--r--ld/ldfile.c19
-rw-r--r--ld/ldlang.c32
-rw-r--r--ld/ldlang.h3
6 files changed, 77 insertions, 12 deletions
diff --git a/ld/ChangeLog b/ld/ChangeLog
index 79f8e63..341ad1d 100644
--- a/ld/ChangeLog
+++ b/ld/ChangeLog
@@ -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 9795b58..9f5bbe5 100644
--- 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
diff --git a/ld/ld.texi b/ld/ld.texi
index 8286af6..4dc78e6 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -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
diff --git a/ld/ldfile.c b/ld/ldfile.c
index d98429d..53112c8 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -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");
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 0bb5f3c..2ef234f 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,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
diff --git a/ld/ldlang.h b/ld/ldlang.h
index 8dd4bfd..2aa3930 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;