From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2124) id 3DEAD3858D38; Wed, 14 Jun 2023 12:40:03 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3DEAD3858D38 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Nick Clifton To: bfd-cvs@sourceware.org Subject: [binutils-gdb] Add --remap-inputs option to the BFD linker. X-Act-Checkin: binutils-gdb X-Git-Author: Nick Clifton X-Git-Refname: refs/heads/master X-Git-Oldrev: 6f860418d556d4e5492b3da9e1a52e4b85a85f3e X-Git-Newrev: fb221fba1a5eb05355f248d6aa1e3ab4316899fd Message-Id: <20230614124003.3DEAD3858D38@sourceware.org> Date: Wed, 14 Jun 2023 12:40:03 +0000 (GMT) X-BeenThere: binutils-cvs@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Binutils-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 14 Jun 2023 12:40:03 -0000 https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dfb221fba1a5e= b05355f248d6aa1e3ab4316899fd commit fb221fba1a5eb05355f248d6aa1e3ab4316899fd Author: Nick Clifton Date: Wed Jun 14 13:39:03 2023 +0100 Add --remap-inputs option to the BFD linker. =20 PR 30374 * ldfile.c (struct input_remap): New structure. (ldfile_add_remap): N= ew function. (ldfile_remap_input_free): New function. (ldfile_add_remap_fil= e): New function. (ldfile_possibly_remap_input): New function. (ldfile_prin= t_input_remaps): New function. * ldfile.h: Add prototypes for new functions. * ldlang.c (new_afile): Call ldfile_possibly_remap_input. (lang_finis= h): Call ldfile_remap_input_free. (lang_map): Call ldfile_print_input_remap= s. * 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. Diff: --- ld/ChangeLog | 22 ++++ ld/NEWS | 5 + ld/ld.texi | 60 ++++++++++ ld/ldfile.c | 210 +++++++++++++++++++++++++++++++= ++++ ld/ldfile.h | 11 ++ ld/ldlang.c | 7 ++ ld/ldlex.h | 2 + ld/lexsup.c | 27 +++++ ld/testsuite/ld-misc/input-remap.exp | 75 +++++++++++++ ld/testsuite/ld-misc/remaps.r | 6 + ld/testsuite/ld-misc/remaps.txt | 4 + 11 files changed, 429 insertions(+) diff --git a/ld/ChangeLog b/ld/ChangeLog index d722d0ba482..8fd6504fa6e 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,25 @@ +2023-06-14 Nick Clifton + + 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 =20 PR 30499 diff --git a/ld/NEWS b/ld/NEWS index 9920d0209b8..4dee2301158 100644 --- a/ld/NEWS +++ b/ld/NEWS @@ -1,5 +1,10 @@ -*- text -*- =20 +* The linker now accepts a command line option of --remap-inputs + =3D to relace any input file that matches with + . In addition the option --remap-inputs-file=3D 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). =20 diff --git a/ld/ld.texi b/ld/ld.texi index 5639de797de..a007ae7fade 100644 --- a/ld/ld.texi +++ b/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. =20 +@cindex remapping inputs +@kindex --remap-inputs=3D@file{pattern}=3D@file{filename} +@kindex --remap-inputs-file=3D@file{file} +@item --remap-inputs=3D@file{pattern}=3D@file{filename} +@itemx --remap-inputs-file=3D@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=3Dfoo.o=3Dbar.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=3Dfoo*.o=3Dbar.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=3Dfilename} 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{=3D}) 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=3Dfoo.o=3Dbar.o +@end smallexample + +Will have no effect, whereas: + +@smallexample + ld --remap-inputs=3Dfoo.o=3Dbar.o foo.o=20 +@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 diff --git a/ld/ldfile.c b/ld/ldfile.c index b8fd4e5d8e0..4976367bbf0 100644 --- a/ld/ldfile.c +++ b/ld/ldfile.c @@ -34,6 +34,7 @@ #include "ldemul.h" #include "libiberty.h" #include "filenames.h" +#include #if BFD_SUPPORTS_PLUGINS #include "plugin-api.h" #include "plugin.h" @@ -65,6 +66,215 @@ static search_dirs_type **search_tail_ptr =3D &search_h= ead; static search_arch_type *search_arch_head; static search_arch_type **search_arch_tail_ptr =3D &search_arch_head; =20 +typedef struct input_remap +{ + const char * pattern; /* Pattern to match input files. */ + const char * renamed; /* Filename to use if the pattern matche= s. */ + struct input_remap * next; /* Link in a chain of these structures. = */ +} input_remap; + +static struct input_remap * input_remaps =3D NULL; + +void +ldfile_add_remap (const char * pattern, const char * renamed) +{ + struct input_remap * new_entry; + + new_entry =3D xmalloc (sizeof * new_entry); + new_entry->pattern =3D xstrdup (pattern); + new_entry->next =3D NULL; + + /* Look for special filenames that mean that the input file should be ig= nored. */ + if (strcmp (renamed, "/dev/null") =3D=3D 0 + || strcmp (renamed, "NUL") =3D=3D 0) + new_entry->renamed =3D NULL; + else + /* FIXME: Should we add sanity checking of the 'renamed' string ? */ + new_entry->renamed =3D 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 =3D=3D NULL) + { + input_remaps =3D new_entry; + } + else + { + struct input_remap * i; + + for (i =3D input_remaps; i->next !=3D NULL; i =3D i->next) + ; + i->next =3D new_entry; + } +} + +void +ldfile_remap_input_free (void) +{ + while (input_remaps !=3D NULL) + { + struct input_remap * i =3D input_remaps; + + input_remaps =3D i->next; + free ((void *) i->pattern); + free ((void *) i->renamed); + free (i); + } +} + +bool +ldfile_add_remap_file (const char * file) +{ + FILE * f; + + f =3D fopen (file, FOPEN_RT); + if (f =3D=3D NULL) + return false; + + size_t linelen =3D 256; + char * line =3D xmalloc (linelen); + + do + { + char * p =3D line; + char * q; + + /* Normally this would use getline(3), but we need to be portable. = */ + while ((q =3D fgets (p, linelen - (p - line), f)) !=3D NULL + && strlen (q) =3D=3D linelen - (p - line) - 1 + && line[linelen - 2] !=3D '\n') + { + line =3D xrealloc (line, 2 * linelen); + p =3D line + linelen - 1; + linelen +=3D linelen; + } + + if (q =3D=3D NULL && p =3D=3D line) + break; + + p =3D strchr (line, '\n'); + if (p) + *p =3D '\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 =3D strchr (line, '#'); + if (p) + *p =3D '\0'; + + /* Remove leading whitespace. NUL is no whitespace character. */ + p =3D line; + while (*p =3D=3D ' ' || *p =3D=3D '\f' || *p =3D=3D '\r' || *p =3D= =3D '\t' || *p =3D=3D '\v') + ++p; + + /* If the line is blank it is ignored. */ + if (*p =3D=3D '\0') + continue; + + char * pattern =3D p; + + /* Advance past the pattern. We accept whitespace or '=3D' as an + end-of-pattern marker. */ + while (*p && *p !=3D '=3D' && *p !=3D ' ' && *p !=3D '\t' && *p !=3D= '\f' + && *p !=3D '\r' && *p !=3D '\v') + ++p; + + if (*p =3D=3D '\0') + { + einfo ("%F%P: malformed remap file entry: %s\n", line); + continue; + } + + * p++ =3D '\0'; + + /* Skip whitespace again. */ + while (*p =3D=3D ' ' || *p =3D=3D '\f' || *p =3D=3D '\r' || *p =3D= =3D '\t' || *p =3D=3D '\v') + ++p; + + if (*p =3D=3D '\0') + { + einfo ("%F%P: malformed remap file entry: %s\n", line); + continue; + } + + char * rename =3D p; + + /* Advance past the rename entry. */ + while (*p && *p !=3D '=3D' && *p !=3D ' ' && *p !=3D '\t' && *p !=3D= '\f' + && *p !=3D '\r' && *p !=3D '\v') + ++p; + /* And terminate it. */ + *p =3D '\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 =3D=3D NULL) + return NULL; + + for (i =3D input_remaps; i !=3D NULL; i =3D i->next) + { + if (fnmatch (i->pattern, filename, 0) =3D=3D 0) + { + if (verbose) + { + if (strpbrk ((i->pattern), "?*[") !=3D 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; + } + } + =20 + return filename; +} + +void +ldfile_print_input_remaps (void) +{ + if (input_remaps =3D=3D NULL) + return; + + minfo (_("\nInput File Remapping\n\n")); + + struct input_remap * i; + + for (i =3D input_remaps; i !=3D NULL; i =3D i->next) + minfo (_(" Pattern: %s\tMaps To: %s\n"), i->pattern, + i->renamed ? i->renamed : _("")); +} + + /* Test whether a pathname, after canonicalization, is the same or a sub-directory of the sysroot directory. */ =20 diff --git a/ld/ldfile.h b/ld/ldfile.h index defb550f76b..153fd0449bc 100644 --- a/ld/ldfile.h +++ b/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); =20 +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 diff --git a/ld/ldlang.c b/ld/ldlang.c index a9c4a4d5bd7..78716f17729 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -1125,6 +1125,10 @@ new_afile (const char *name, =20 lang_has_input_file =3D true; =20 + name =3D ldfile_possibly_remap_input (name); + if (name =3D=3D NULL) + return NULL; + p =3D 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 (); } =20 /*---------------------------------------------------------------------- @@ -2280,6 +2285,8 @@ lang_map (void) lang_memory_region_type *m; bool dis_header_printed =3D false; =20 + ldfile_print_input_remaps (); + LANG_FOR_EACH_INPUT_STATEMENT (file) { asection *s; diff --git a/ld/ldlex.h b/ld/ldlex.h index be942ec4327..87cac02141d 100644 --- a/ld/ldlex.h +++ b/ld/ldlex.h @@ -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, }; =20 /* The initial parser states. */ diff --git a/ld/lexsup.c b/ld/lexsup.c index 6090921bda4..4e20e938a49 100644 --- a/ld/lexsup.c +++ b/ld/lexsup.c @@ -219,6 +219,12 @@ static const struct ld_option ld_options[] =3D { {"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_FIL= E}, + '\0', N_("FILE"), "Provide a FILE containing input remapings", TWO_DAS= HES }, + { {"remap-inputs", required_argument, NULL, OPTION_REMAP_INPUTS}, + '\0', N_("PATTERN=3DFILE"), "Remap input files matching PATTERN to FIL= E", 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 =3D optarg; break; =20 + 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 =3D strchr (optarg, '=3D'); + if (optarg2 =3D=3D NULL) + /* FIXME: Should we allow --remap-inputs=3D@myfile as a synonym + for --remap-inputs-file=3Dmyfile ? */ + einfo (_("%F%P: invalid argument to option --remap-inputs\n")); + size_t len =3D optarg2 - optarg; + char * pattern =3D xmalloc (len + 1); + memcpy (pattern, optarg, len); + pattern[len] =3D 0; + ldfile_add_remap (pattern, optarg2 + 1); + free (pattern); + } + break; + case OPTION_REDUCE_MEMORY_OVERHEADS: link_info.reduce_memory_overheads =3D true; if (config.hash_table_size =3D=3D 0) diff --git a/ld/testsuite/ld-misc/input-remap.exp b/ld/testsuite/ld-misc/in= put-remap.exp new file mode 100644 index 00000000000..950b7e88d2f --- /dev/null +++ b/ld/testsuite/ld-misc/input-remap.exp @@ -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=3Dtmpdir/foo.o=3Dtmpdir/barzzz.o"=20 + "-e 0"=20 + "-o tmpdir/barzzz.o"=20 + {foo.s}=20 + {}=20 + "foo"=20 + } \ + { "--remap-inputs (wildcard)"=20 + "--remap-inputs=3D*/foo.o=3Dtmpdir/barzzz.o"=20 + "-e 0"=20 + "-o tmpdir/barzzz.o"=20 + {foo.s}=20 + {}=20 + "foo"=20 + } \ + [ 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" \ + ] \ +] diff --git a/ld/testsuite/ld-misc/remaps.r b/ld/testsuite/ld-misc/remaps.r new file mode 100644 index 00000000000..472021974e5 --- /dev/null +++ b/ld/testsuite/ld-misc/remaps.r @@ -0,0 +1,6 @@ +#... +Input File Remapping + + Pattern: \*/foo\.o Maps To: tmpdir/barzzz\.o + Pattern: bazzz\.o Maps To: \ +#pass diff --git a/ld/testsuite/ld-misc/remaps.txt b/ld/testsuite/ld-misc/remaps.= txt new file mode 100644 index 00000000000..4ca2a136c73 --- /dev/null +++ b/ld/testsuite/ld-misc/remaps.txt @@ -0,0 +1,4 @@ +# A comment +*/foo.o tmpdir/barzzz.o # A remapping +bazzz.o=3D/dev/null # A deletion +