Add --remap-inputs option to the BFD linker.
PR 30374 * ldfile.c (struct input_remap): New structure. (ldfile_add_remap): New function. (ldfile_remap_input_free): New function. (ldfile_add_remap_file): New function. (ldfile_possibly_remap_input): New function. (ldfile_print_input_remaps): New function. * ldfile.h: Add prototypes for new functions. * ldlang.c (new_afile): Call ldfile_possibly_remap_input. (lang_finish): Call ldfile_remap_input_free. (lang_map): Call ldfile_print_input_remaps. * ldlex.h (OPTION_REMAP_INPUTS, OPTION_REMAP_INPUTS_FILE): Define. * lexsup.c (ld_options): Add --remap-inputs-file and --remap-inputs. (parse_args): Handle new options. * NEWS: Mention the new feature. * ld.texi: Document the new options. * testsuite/ld-misc/input-remap.exp: New test driver. * testsuite/ld-misc/remaps.r: New file: Expected linker output. * testsuite/ld-misc/remaps.txt: New file. Input remaps file.
This commit is contained in:
parent
6f860418d5
commit
fb221fba1a
22
ld/ChangeLog
22
ld/ChangeLog
@ -1,3 +1,25 @@
|
||||
2023-06-14 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR 30374
|
||||
* ldfile.c (struct input_remap): New structure.
|
||||
(ldfile_add_remap): New function.
|
||||
(ldfile_remap_input_free): New function.
|
||||
(ldfile_add_remap_file): New function.
|
||||
(ldfile_possibly_remap_input): New function.
|
||||
(ldfile_print_input_remaps): New function.
|
||||
* ldfile.h: Add prototypes for new functions.
|
||||
* ldlang.c (new_afile): Call ldfile_possibly_remap_input.
|
||||
(lang_finish): Call ldfile_remap_input_free.
|
||||
(lang_map): Call ldfile_print_input_remaps.
|
||||
* ldlex.h (OPTION_REMAP_INPUTS, OPTION_REMAP_INPUTS_FILE): Define.
|
||||
* lexsup.c (ld_options): Add --remap-inputs-file and --remap-inputs.
|
||||
(parse_args): Handle new options.
|
||||
* NEWS: Mention the new feature.
|
||||
* ld.texi: Document the new options.
|
||||
* testsuite/ld-misc/input-remap.exp: New test driver.
|
||||
* testsuite/ld-misc/remaps.r: New file: Expected linker output.
|
||||
* testsuite/ld-misc/remaps.txt: New file. Input remaps file.
|
||||
|
||||
2023-06-07 Nick Clifton <nickc@redhat.com>
|
||||
|
||||
PR 30499
|
||||
|
5
ld/NEWS
5
ld/NEWS
@ -1,5 +1,10 @@
|
||||
-*- text -*-
|
||||
|
||||
* The linker now accepts a command line option of --remap-inputs
|
||||
<PATTERN>=<FILE> to relace any input file that matches <PATTERN> with
|
||||
<FILE>. In addition the option --remap-inputs-file=<FILE> can be used to
|
||||
specify a file containing any number of these remapping directives.
|
||||
|
||||
* The linker command line option --print-map-locals can be used to include
|
||||
local symbols in a linker map. (ELF targets only).
|
||||
|
||||
|
60
ld/ld.texi
60
ld/ld.texi
@ -793,6 +793,66 @@ If the @samp{-m} option is not used, the emulation is taken from the
|
||||
Otherwise, the default emulation depends upon how the linker was
|
||||
configured.
|
||||
|
||||
@cindex remapping inputs
|
||||
@kindex --remap-inputs=@file{pattern}=@file{filename}
|
||||
@kindex --remap-inputs-file=@file{file}
|
||||
@item --remap-inputs=@file{pattern}=@file{filename}
|
||||
@itemx --remap-inputs-file=@file{file}
|
||||
These options allow the names of input files to be changed before the
|
||||
linker attempts to open them. The option
|
||||
@option{--remap-inputs=foo.o=bar.o} will cause any attempt to load a
|
||||
file called @file{foo.o} to instead try to load a file called
|
||||
@file{bar.o}. Wildcard patterns are permitted in the first filename,
|
||||
so @option{--remap-inputs=foo*.o=bar.o} will rename any input file that
|
||||
matches @file{foo*.o} to @file{bar.o}.
|
||||
|
||||
An alternative form of the option
|
||||
@option{--remap-inputs-file=filename} allows the remappings to be read
|
||||
from a file. Each line in the file can contain a single remapping.
|
||||
Blank lines are ignored. Anything from a hash character (@samp{#}) to
|
||||
the end of a line is considered to be a comment and is also ignored.
|
||||
The mapping pattern can be separated from the filename by whitespace
|
||||
or an equals (@samp{=}) character.
|
||||
|
||||
The options can be specified multiple times. Their contents
|
||||
accumulate. The remappings will be processed in the order in which
|
||||
they occur on the command line, and if they come from a file, in the
|
||||
order in which they occur in the file. If a match is made, no further
|
||||
checking for that filename will be performed.
|
||||
|
||||
If the replacement filename is @file{/dev/null} or just @file{NUL}
|
||||
then the remapping will actually cause the input file to be ignored.
|
||||
This can be a convenient way to experiment with removing input files
|
||||
from a complicated build environment.
|
||||
|
||||
Note that this option is position dependent and only affects filenames
|
||||
that come after it on the command line. Thus:
|
||||
|
||||
@smallexample
|
||||
ld foo.o --remap-inputs=foo.o=bar.o
|
||||
@end smallexample
|
||||
|
||||
Will have no effect, whereas:
|
||||
|
||||
@smallexample
|
||||
ld --remap-inputs=foo.o=bar.o foo.o
|
||||
@end smallexample
|
||||
|
||||
Will rename the input file @file{foo.o} to @file{bar.o}.
|
||||
|
||||
Note - these options also affect files referenced by @emph{INPUT}
|
||||
statements in linker scripts. But since linker scripts are processed
|
||||
after the entire command line is read, the position of the remap
|
||||
options on the command line is not significant.
|
||||
|
||||
If the @option{verbose} option is enabled then any mappings that match
|
||||
will be reported, although again the @option{verbose} option needs to
|
||||
be enabled on the command line @emph{before} the remaped filenames
|
||||
appear.
|
||||
|
||||
If the @option{-Map} or @option{--print-map} options are enabled then
|
||||
the remapping list will be included in the map output.
|
||||
|
||||
@cindex link map
|
||||
@kindex -M
|
||||
@kindex --print-map
|
||||
|
210
ld/ldfile.c
210
ld/ldfile.c
@ -34,6 +34,7 @@
|
||||
#include "ldemul.h"
|
||||
#include "libiberty.h"
|
||||
#include "filenames.h"
|
||||
#include <fnmatch.h>
|
||||
#if BFD_SUPPORTS_PLUGINS
|
||||
#include "plugin-api.h"
|
||||
#include "plugin.h"
|
||||
@ -65,6 +66,215 @@ static search_dirs_type **search_tail_ptr = &search_head;
|
||||
static search_arch_type *search_arch_head;
|
||||
static search_arch_type **search_arch_tail_ptr = &search_arch_head;
|
||||
|
||||
typedef struct input_remap
|
||||
{
|
||||
const char * pattern; /* Pattern to match input files. */
|
||||
const char * renamed; /* Filename to use if the pattern matches. */
|
||||
struct input_remap * next; /* Link in a chain of these structures. */
|
||||
} input_remap;
|
||||
|
||||
static struct input_remap * input_remaps = NULL;
|
||||
|
||||
void
|
||||
ldfile_add_remap (const char * pattern, const char * renamed)
|
||||
{
|
||||
struct input_remap * new_entry;
|
||||
|
||||
new_entry = xmalloc (sizeof * new_entry);
|
||||
new_entry->pattern = xstrdup (pattern);
|
||||
new_entry->next = NULL;
|
||||
|
||||
/* Look for special filenames that mean that the input file should be ignored. */
|
||||
if (strcmp (renamed, "/dev/null") == 0
|
||||
|| strcmp (renamed, "NUL") == 0)
|
||||
new_entry->renamed = NULL;
|
||||
else
|
||||
/* FIXME: Should we add sanity checking of the 'renamed' string ? */
|
||||
new_entry->renamed = xstrdup (renamed);
|
||||
|
||||
/* It would be easier to add this new node at the start of the chain,
|
||||
but users expect that remapping will occur in the order in which
|
||||
they occur on the command line, and in the remapping files. */
|
||||
if (input_remaps == NULL)
|
||||
{
|
||||
input_remaps = new_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct input_remap * i;
|
||||
|
||||
for (i = input_remaps; i->next != NULL; i = i->next)
|
||||
;
|
||||
i->next = new_entry;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ldfile_remap_input_free (void)
|
||||
{
|
||||
while (input_remaps != NULL)
|
||||
{
|
||||
struct input_remap * i = input_remaps;
|
||||
|
||||
input_remaps = i->next;
|
||||
free ((void *) i->pattern);
|
||||
free ((void *) i->renamed);
|
||||
free (i);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ldfile_add_remap_file (const char * file)
|
||||
{
|
||||
FILE * f;
|
||||
|
||||
f = fopen (file, FOPEN_RT);
|
||||
if (f == NULL)
|
||||
return false;
|
||||
|
||||
size_t linelen = 256;
|
||||
char * line = xmalloc (linelen);
|
||||
|
||||
do
|
||||
{
|
||||
char * p = line;
|
||||
char * q;
|
||||
|
||||
/* Normally this would use getline(3), but we need to be portable. */
|
||||
while ((q = fgets (p, linelen - (p - line), f)) != NULL
|
||||
&& strlen (q) == linelen - (p - line) - 1
|
||||
&& line[linelen - 2] != '\n')
|
||||
{
|
||||
line = xrealloc (line, 2 * linelen);
|
||||
p = line + linelen - 1;
|
||||
linelen += linelen;
|
||||
}
|
||||
|
||||
if (q == NULL && p == line)
|
||||
break;
|
||||
|
||||
p = strchr (line, '\n');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
/* Because the file format does not know any form of quoting we
|
||||
can search forward for the next '#' character and if found
|
||||
make it terminating the line. */
|
||||
p = strchr (line, '#');
|
||||
if (p)
|
||||
*p = '\0';
|
||||
|
||||
/* Remove leading whitespace. NUL is no whitespace character. */
|
||||
p = line;
|
||||
while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v')
|
||||
++p;
|
||||
|
||||
/* If the line is blank it is ignored. */
|
||||
if (*p == '\0')
|
||||
continue;
|
||||
|
||||
char * pattern = p;
|
||||
|
||||
/* Advance past the pattern. We accept whitespace or '=' as an
|
||||
end-of-pattern marker. */
|
||||
while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f'
|
||||
&& *p != '\r' && *p != '\v')
|
||||
++p;
|
||||
|
||||
if (*p == '\0')
|
||||
{
|
||||
einfo ("%F%P: malformed remap file entry: %s\n", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
* p++ = '\0';
|
||||
|
||||
/* Skip whitespace again. */
|
||||
while (*p == ' ' || *p == '\f' || *p == '\r' || *p == '\t' || *p == '\v')
|
||||
++p;
|
||||
|
||||
if (*p == '\0')
|
||||
{
|
||||
einfo ("%F%P: malformed remap file entry: %s\n", line);
|
||||
continue;
|
||||
}
|
||||
|
||||
char * rename = p;
|
||||
|
||||
/* Advance past the rename entry. */
|
||||
while (*p && *p != '=' && *p != ' ' && *p != '\t' && *p != '\f'
|
||||
&& *p != '\r' && *p != '\v')
|
||||
++p;
|
||||
/* And terminate it. */
|
||||
*p = '\0';
|
||||
|
||||
ldfile_add_remap (pattern, rename);
|
||||
}
|
||||
while (! feof (f));
|
||||
|
||||
free (line);
|
||||
fclose (f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *
|
||||
ldfile_possibly_remap_input (const char * filename)
|
||||
{
|
||||
struct input_remap * i;
|
||||
|
||||
if (filename == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = input_remaps; i != NULL; i = i->next)
|
||||
{
|
||||
if (fnmatch (i->pattern, filename, 0) == 0)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
if (strpbrk ((i->pattern), "?*[") != NULL)
|
||||
{
|
||||
if (i->renamed)
|
||||
info_msg (_("remap input file '%s' to '%s' based upon pattern '%s'\n"),
|
||||
filename, i->renamed, i->pattern);
|
||||
else
|
||||
info_msg (_("remove input file '%s' based upon pattern '%s'\n"),
|
||||
filename, i->pattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (i->renamed)
|
||||
info_msg (_("remap input file '%s' to '%s'\n"),
|
||||
filename, i->renamed);
|
||||
else
|
||||
info_msg (_("remove input file '%s'\n"),
|
||||
filename);
|
||||
}
|
||||
}
|
||||
|
||||
return i->renamed;
|
||||
}
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
void
|
||||
ldfile_print_input_remaps (void)
|
||||
{
|
||||
if (input_remaps == NULL)
|
||||
return;
|
||||
|
||||
minfo (_("\nInput File Remapping\n\n"));
|
||||
|
||||
struct input_remap * i;
|
||||
|
||||
for (i = input_remaps; i != NULL; i = i->next)
|
||||
minfo (_(" Pattern: %s\tMaps To: %s\n"), i->pattern,
|
||||
i->renamed ? i->renamed : _("<discard>"));
|
||||
}
|
||||
|
||||
|
||||
/* Test whether a pathname, after canonicalization, is the same or a
|
||||
sub-directory of the sysroot directory. */
|
||||
|
||||
|
11
ld/ldfile.h
11
ld/ldfile.h
@ -60,4 +60,15 @@ extern bool ldfile_open_file_search
|
||||
(const char *arch, struct lang_input_statement_struct *,
|
||||
const char *lib, const char *suffix);
|
||||
|
||||
extern void ldfile_add_remap
|
||||
(const char *, const char *);
|
||||
extern bool ldfile_add_remap_file
|
||||
(const char *);
|
||||
extern void ldfile_remap_input_free
|
||||
(void);
|
||||
extern const char * ldfile_possibly_remap_input
|
||||
(const char *);
|
||||
extern void ldfile_print_input_remaps
|
||||
(void);
|
||||
|
||||
#endif
|
||||
|
@ -1125,6 +1125,10 @@ new_afile (const char *name,
|
||||
|
||||
lang_has_input_file = true;
|
||||
|
||||
name = ldfile_possibly_remap_input (name);
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
p = new_stat (lang_input_statement, stat_ptr);
|
||||
memset (&p->the_bfd, 0,
|
||||
sizeof (*p) - offsetof (lang_input_statement_type, the_bfd));
|
||||
@ -1328,6 +1332,7 @@ void
|
||||
lang_finish (void)
|
||||
{
|
||||
output_section_statement_table_free ();
|
||||
ldfile_remap_input_free ();
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
@ -2280,6 +2285,8 @@ lang_map (void)
|
||||
lang_memory_region_type *m;
|
||||
bool dis_header_printed = false;
|
||||
|
||||
ldfile_print_input_remaps ();
|
||||
|
||||
LANG_FOR_EACH_INPUT_STATEMENT (file)
|
||||
{
|
||||
asection *s;
|
||||
|
@ -174,6 +174,8 @@ enum option_values
|
||||
OPTION_NO_WARN_RWX_SEGMENTS,
|
||||
OPTION_ENABLE_LINKER_VERSION,
|
||||
OPTION_DISABLE_LINKER_VERSION,
|
||||
OPTION_REMAP_INPUTS,
|
||||
OPTION_REMAP_INPUTS_FILE,
|
||||
};
|
||||
|
||||
/* The initial parser states. */
|
||||
|
27
ld/lexsup.c
27
ld/lexsup.c
@ -219,6 +219,12 @@ static const struct ld_option ld_options[] =
|
||||
{ {"just-symbols", required_argument, NULL, 'R'},
|
||||
'R', N_("FILE"), N_("Just link symbols (if directory, same as --rpath)"),
|
||||
TWO_DASHES },
|
||||
|
||||
{ {"remap-inputs-file", required_argument, NULL, OPTION_REMAP_INPUTS_FILE},
|
||||
'\0', N_("FILE"), "Provide a FILE containing input remapings", TWO_DASHES },
|
||||
{ {"remap-inputs", required_argument, NULL, OPTION_REMAP_INPUTS},
|
||||
'\0', N_("PATTERN=FILE"), "Remap input files matching PATTERN to FILE", TWO_DASHES },
|
||||
|
||||
{ {"strip-all", no_argument, NULL, 's'},
|
||||
's', NULL, N_("Strip all symbols"), TWO_DASHES },
|
||||
{ {"strip-debug", no_argument, NULL, 'S'},
|
||||
@ -1682,6 +1688,27 @@ parse_args (unsigned argc, char **argv)
|
||||
link_info.fini_function = optarg;
|
||||
break;
|
||||
|
||||
case OPTION_REMAP_INPUTS_FILE:
|
||||
if (! ldfile_add_remap_file (optarg))
|
||||
einfo (_("%F%P: failed to add remap file %s\n"), optarg);
|
||||
break;
|
||||
|
||||
case OPTION_REMAP_INPUTS:
|
||||
{
|
||||
char *optarg2 = strchr (optarg, '=');
|
||||
if (optarg2 == NULL)
|
||||
/* FIXME: Should we allow --remap-inputs=@myfile as a synonym
|
||||
for --remap-inputs-file=myfile ? */
|
||||
einfo (_("%F%P: invalid argument to option --remap-inputs\n"));
|
||||
size_t len = optarg2 - optarg;
|
||||
char * pattern = xmalloc (len + 1);
|
||||
memcpy (pattern, optarg, len);
|
||||
pattern[len] = 0;
|
||||
ldfile_add_remap (pattern, optarg2 + 1);
|
||||
free (pattern);
|
||||
}
|
||||
break;
|
||||
|
||||
case OPTION_REDUCE_MEMORY_OVERHEADS:
|
||||
link_info.reduce_memory_overheads = true;
|
||||
if (config.hash_table_size == 0)
|
||||
|
75
ld/testsuite/ld-misc/input-remap.exp
Normal file
75
ld/testsuite/ld-misc/input-remap.exp
Normal file
@ -0,0 +1,75 @@
|
||||
# Test handling of --input-remap
|
||||
# Copyright (C) 2023-2023 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of the GNU Binutils.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
|
||||
# MA 02110-1301, USA.
|
||||
#
|
||||
|
||||
|
||||
# First make sure that linking without remapping does not work:
|
||||
file delete tmpdir/foo.o
|
||||
setup_xfail *-*-*
|
||||
run_ld_link_tests {
|
||||
{ "--remap-inputs (expected fail)"
|
||||
""
|
||||
"-e 0"
|
||||
"-o tmpdir/barzzz.o"
|
||||
{foo.s}
|
||||
{}
|
||||
"foo" }
|
||||
}
|
||||
|
||||
global srcdir
|
||||
global subdir
|
||||
|
||||
# Now use the remap options to allow the linking to succeed.
|
||||
# Note: we have to use the [list... format when we need to
|
||||
# have $-substitutions.
|
||||
run_ld_link_tests [list \
|
||||
{ "--remap-inputs (simple)"
|
||||
"--remap-inputs=tmpdir/foo.o=tmpdir/barzzz.o"
|
||||
"-e 0"
|
||||
"-o tmpdir/barzzz.o"
|
||||
{foo.s}
|
||||
{}
|
||||
"foo"
|
||||
} \
|
||||
{ "--remap-inputs (wildcard)"
|
||||
"--remap-inputs=*/foo.o=tmpdir/barzzz.o"
|
||||
"-e 0"
|
||||
"-o tmpdir/barzzz.o"
|
||||
{foo.s}
|
||||
{}
|
||||
"foo"
|
||||
} \
|
||||
[ list "--remap-inputs-file" \
|
||||
"--remap-inputs-file $srcdir/$subdir/remaps.txt" \
|
||||
"-e 0 bazzz.o" \
|
||||
"-o tmpdir/barzzz.o" \
|
||||
{foo.s} \
|
||||
{} \
|
||||
"foo" \
|
||||
] \
|
||||
[ list "--remap-inputs-file (with map output)" \
|
||||
"--remap-inputs-file $srcdir/$subdir/remaps.txt" \
|
||||
"-e 0 --print-map" \
|
||||
"-o tmpdir/barzzz.o" \
|
||||
{foo.s} \
|
||||
{ { ld remaps.r } } \
|
||||
"foo" \
|
||||
] \
|
||||
]
|
6
ld/testsuite/ld-misc/remaps.r
Normal file
6
ld/testsuite/ld-misc/remaps.r
Normal file
@ -0,0 +1,6 @@
|
||||
#...
|
||||
Input File Remapping
|
||||
|
||||
Pattern: \*/foo\.o Maps To: tmpdir/barzzz\.o
|
||||
Pattern: bazzz\.o Maps To: \<discard\>
|
||||
#pass
|
4
ld/testsuite/ld-misc/remaps.txt
Normal file
4
ld/testsuite/ld-misc/remaps.txt
Normal file
@ -0,0 +1,4 @@
|
||||
# A comment
|
||||
*/foo.o tmpdir/barzzz.o # A remapping
|
||||
bazzz.o=/dev/null # A deletion
|
||||
|
Loading…
x
Reference in New Issue
Block a user