public inbox for binutils-cvs@sourceware.org
 help / color / mirror / Atom feed
* [binutils-gdb] Add --remap-inputs option to the BFD linker.
@ 2023-06-14 12:40 Nick Clifton
  0 siblings, 0 replies; only message in thread
From: Nick Clifton @ 2023-06-14 12:40 UTC (permalink / raw)
  To: bfd-cvs

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=fb221fba1a5eb05355f248d6aa1e3ab4316899fd

commit fb221fba1a5eb05355f248d6aa1e3ab4316899fd
Author: Nick Clifton <nickc@redhat.com>
Date:   Wed Jun 14 13:39:03 2023 +0100

    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.

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  <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
diff --git a/ld/NEWS b/ld/NEWS
index 9920d0209b8..4dee2301158 100644
--- a/ld/NEWS
+++ b/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).
 
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.
 
+@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
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 <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.  */
 
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);
 
+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,
 
   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;
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,
 };
 
 /* 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[] =
   { {"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)
diff --git a/ld/testsuite/ld-misc/input-remap.exp b/ld/testsuite/ld-misc/input-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=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" \
+  ] \
+]
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: \<discard\>
+#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=/dev/null # A deletion
+

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-06-14 12:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-06-14 12:40 [binutils-gdb] Add --remap-inputs option to the BFD linker Nick Clifton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).