[PATCH v5 12/12] PR ld/24600: LD: Add support for file collections as artificial archives

Maciej W. Rozycki macro@orcam.me.uk
Wed Jan 28 10:55:51 GMT 2026


From: Maciej W. Rozycki <macro@redhat.com>

Implement linker support for `--start-lib' and `--end-lib' command-line 
options and an analogous LIB linker script statement for treating a list 
of object files as members of an artificial archive.  This is built upon 
BFD's fake archive feature, to support the same command-line options of 
the GOLD linker being phased out.

Usual archive semantics is preserved for such artificial archives, such 
as symbol resolution rules, archive grouping, and the `--whole-archive' 
feature, except for the `--no-link-mapless' setting which is ignored as 
meaningless for such loose file collections which cannot have a symbol 
map.

There is no support for nested archives or other members that are not 
object files, e.g. if a file supplied as a member archive is a linker 
script, it will be silently ignored, just as with actual archives.  It 
is unlike with input files passed that are not members of an artificial 
archive.

Update documentation and expand test coverage accordingly.
---
Changes from v4 (14/14), 
<https://inbox.sourceware.org/binutils/alpine.DEB.2.21.2601122202310.12909@angie.orcam.me.uk/>:

- Update a `lang_for_each_statement_worker' call with an extra argument
  for commit d75f191dc631 ("PR 33821 use after free commit e6357caf7579").

- Update ld/NEWS for the 2.46 version bump.

- Refer in the commit description the GOLD linker being phased out.

No change from v3 (18/18), 
<https://inbox.sourceware.org/binutils/alpine.DEB.2.21.2511200012330.57987@angie.orcam.me.uk/>.

Changes from v2 (16/16), 
<https://inbox.sourceware.org/binutils/alpine.DEB.2.21.2511061856050.25436@angie.orcam.me.uk/>:

- Respect any explicitly requested link emulation for file collections as
  well.

- Add complementing CRIS linker tests for emulation switching with file 
  collections.

New change in v2.
---
 bfd/archive.c                       |    2 
 bfd/elf64-ia64-vms.c                |   15 ++
 bfd/vms-alpha.c                     |   15 ++
 bfd/vms-lib.c                       |    2 
 ld/NEWS                             |    4 
 ld/emultempl/xtensaelf.em           |    1 
 ld/ld.texi                          |   39 +++++++
 ld/ldgram.y                         |   27 +++--
 ld/ldlang.c                         |  131 +++++++++++++++++++++++++
 ld/ldlang.h                         |   21 ++++
 ld/ldlex.h                          |    2 
 ld/ldlex.l                          |    1 
 ld/ldmisc.c                         |   11 +-
 ld/lexsup.c                         |   39 +++++++
 ld/testsuite/ld-archive/ab.t        |    1 
 ld/testsuite/ld-archive/abfc.vd     |   28 +++++
 ld/testsuite/ld-archive/abfcfg.vd   |   36 +++++++
 ld/testsuite/ld-archive/absc.vd     |   35 ++++++
 ld/testsuite/ld-archive/abscfg.vd   |   43 ++++++++
 ld/testsuite/ld-archive/abwfc.vd    |   30 +++++
 ld/testsuite/ld-archive/abwsc.vd    |   37 +++++++
 ld/testsuite/ld-archive/archive.exp |  183 ++++++++++++++++++++++++++++++++++++
 ld/testsuite/ld-archive/cd.t        |    1 
 ld/testsuite/ld-cris/archive.exp    |   18 +++
 24 files changed, 709 insertions(+), 13 deletions(-)

binutils-ld-start-end-lib.diff
Index: binutils-gdb/bfd/archive.c
===================================================================
--- binutils-gdb.orig/bfd/archive.c
+++ binutils-gdb/bfd/archive.c
@@ -673,7 +673,7 @@ char *
 _bfd_append_relative_path (bfd *arch, char *elt_name)
 {
   const char *arch_name = bfd_get_filename (arch);
-  const char *base_name = lbasename (arch_name);
+  const char *base_name = arch_name != NULL ? lbasename (arch_name) : NULL;
   size_t prefix_len;
   char *filename;
 
Index: binutils-gdb/bfd/elf64-ia64-vms.c
===================================================================
--- binutils-gdb.orig/bfd/elf64-ia64-vms.c
+++ binutils-gdb/bfd/elf64-ia64-vms.c
@@ -5310,6 +5310,19 @@ elf64_vms_link_add_archive_symbols (bfd
       return false;
     }
 
+  /* This can only ever happen for fake archives.  */
+  if (!bfd_has_map (abfd))
+    {
+      bfd *first_one = bfd_openr_next_archived_file (abfd, NULL);
+
+      /* An empty archive is a special case.  */
+      if (first_one == NULL)
+        return true;
+
+      if (!_bfd_make_armap (abfd, first_one))
+        return false;
+    }
+
   /* The archive_pass field in the archive itself is used to
      initialize PASS, since we may search the same archive multiple
      times.  */
@@ -5363,7 +5376,7 @@ elf64_vms_link_add_archive_symbols (bfd
 	}
 
       orig_element = element;
-      if (bfd_is_thin_archive (abfd))
+      if (bfd_is_thin_archive (abfd) && !bfd_is_fake_archive (abfd))
 	{
 	  element = _bfd_vms_lib_get_imagelib_file (element);
 	  if (element == NULL || !bfd_check_format (element, bfd_object))
Index: binutils-gdb/bfd/vms-alpha.c
===================================================================
--- binutils-gdb.orig/bfd/vms-alpha.c
+++ binutils-gdb/bfd/vms-alpha.c
@@ -9116,6 +9116,19 @@ alpha_vms_link_add_archive_symbols (bfd
       return false;
     }
 
+  /* This can only ever happen for fake archives.  */
+  if (!bfd_has_map (abfd))
+    {
+      bfd *first_one = bfd_openr_next_archived_file (abfd, NULL);
+
+      /* An empty archive is a special case.  */
+      if (first_one == NULL)
+        return true;
+
+      if (!_bfd_make_armap (abfd, first_one))
+        return false;
+    }
+
   /* The archive_pass field in the archive itself is used to
      initialize PASS, since we may search the same archive multiple
      times.  */
@@ -9175,7 +9188,7 @@ alpha_vms_link_add_archive_symbols (bfd
 	}
 
       orig_element = element;
-      if (bfd_is_thin_archive (abfd))
+      if (bfd_is_thin_archive (abfd) && !bfd_is_fake_archive (abfd))
 	{
 	  element = _bfd_vms_lib_get_imagelib_file (element);
 	  if (element == NULL || !bfd_check_format (element, bfd_object))
Index: binutils-gdb/bfd/vms-lib.c
===================================================================
--- binutils-gdb.orig/bfd/vms-lib.c
+++ binutils-gdb/bfd/vms-lib.c
@@ -1485,6 +1485,8 @@ _bfd_vms_lib_get_elt_at_index (bfd *abfd
   /* Check symidx.  */
   if (symidx > tdata->artdata.symdef_count)
     return NULL;
+  if (tdata->artdata.symdef_use_bfd)
+    return tdata->artdata.symdefs[symidx].u.abfd;
   file_off = tdata->artdata.symdefs[symidx].u.file_offset;
 
   /* Linear-scan.  */
Index: binutils-gdb/ld/NEWS
===================================================================
--- binutils-gdb.orig/ld/NEWS
+++ binutils-gdb/ld/NEWS
@@ -2,6 +2,10 @@
 
 Changes in 2.47:
 
+* Add linker support for --start-lib/--end-lib options and LIB linker script
+  statement for treating a list of object files as members of an artificial
+  archive.
+
 * Add linker support for archives with no symbol index in their all formats,
   not only XCOFF.  On by default and controlled with --no-link-mapless and
   --link-mapless options, also for XCOFF.
Index: binutils-gdb/ld/emultempl/xtensaelf.em
===================================================================
--- binutils-gdb.orig/ld/emultempl/xtensaelf.em
+++ binutils-gdb/ld/emultempl/xtensaelf.em
@@ -1395,6 +1395,7 @@ xtensa_strip_inconsistent_linkonce_secti
 	case lang_padding_statement_enum:
 	case lang_address_statement_enum:
 	case lang_fill_statement_enum:
+	case lang_lib_statement_enum:
 	  break;
 
 	default:
Index: binutils-gdb/ld/ld.texi
===================================================================
--- binutils-gdb.orig/ld/ld.texi
+++ binutils-gdb/ld/ld.texi
@@ -1790,10 +1790,35 @@ would not be able to resolve that refere
 they will all be searched repeatedly until all possible references are
 resolved.
 
+This option is not allowed within a @option{--start-lib}/@option{--end-lib}
+option pair.
+
 Using this option has a significant performance cost.  It is best to use
 it only when there are unavoidable circular references between two or
 more archives.
 
+@kindex --start-lib
+@cindex artificial archives
+@item --start-lib @var{objects} --end-lib
+The @var{objects} should be a list of object files.
+
+The specified objects are treated as if they were members of an archive
+the name of which has been placed at the location of @option{--start-lib}
+on the command line.  All the usual linker archive handling properties
+and command line options apply to such an artificial archive.
+
+This option may be used multiple times, in which case each set of the
+objects specified will be treated as an individual archive.  Nesting this
+option is not allowed though.
+
+Options that affect archive processing are not allowed between
+@option{--start-lib} and @option{--end-lib} as it would make no sense
+to apply them midway through handling an archive.  These options include:
+@option{-(}/@option{--start-group}, @option{-)}/@option{--end-group},
+@option{--whole-archive}, and @option{--no-whole-archive}, as well as
+@option{--pop-state} where it would change the state of
+@option{--whole-archive} setting.
+
 @kindex --accept-unknown-input-arch
 @kindex --no-accept-unknown-input-arch
 @item --accept-unknown-input-arch
@@ -2372,7 +2397,8 @@ library during a library search.  This o
 @kindex --no-whole-archive
 @item --no-whole-archive
 Turn off the effect of the @option{--whole-archive} option for subsequent
-archive files.
+archive files.  Not allowed within a @option{--start-lib}/@option{--end-lib}
+option pair.
 
 @kindex --no-link-mapless
 @item --no-link-mapless
@@ -3187,6 +3213,9 @@ files.  This is normally used to turn an
 library, forcing every object to be included in the resulting shared
 library.  This option may be used more than once.
 
+This option is not allowed within a @option{--start-lib}/@option{--end-lib}
+option pair.
+
 Two notes when using this option from gcc: First, gcc doesn't know
 about this option, so you have to use @option{-Wl,-whole-archive}.
 Second, don't forget to use @option{-Wl,-no-whole-archive} after your
@@ -4515,6 +4544,14 @@ files should all be archives, and they a
 new undefined references are created.  See the description of @samp{-(}
 in @ref{Options,,Command-line Options}.
 
+@item LIB(@var{file}, @var{file}, @dots{})
+@itemx LIB(@var{file} @var{file} @dots{})
+@kindex LIB(@var{files})
+@cindex artificial archives in linker scripts
+The @code{LIB} command is like @code{INPUT}, except that the named files
+are treated as if they were members of an archive.  See the description
+of @samp{--start-lib} in @ref{Options,,Command-line Options}.
+
 @item AS_NEEDED(@var{file}, @var{file}, @dots{})
 @itemx AS_NEEDED(@var{file} @var{file} @dots{})
 @kindex AS_NEEDED(@var{files})
Index: binutils-gdb/ld/ldgram.y
===================================================================
--- binutils-gdb.orig/ld/ldgram.y
+++ binutils-gdb/ld/ldgram.y
@@ -149,7 +149,7 @@ static void yyerror (const char *);
 %token SIZEOF ALIGNOF ADDR LOADADDR MAX_K MIN_K
 %token STARTUP HLL SYSLIB FLOAT NOFLOAT NOCROSSREFS NOCROSSREFS_TO
 %token ORIGIN FILL
-%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP OUTPUT CONSTRUCTORS
+%token LENGTH CREATE_OBJECT_SYMBOLS INPUT GROUP LIB OUTPUT CONSTRUCTORS
 %token ALIGNMOD AT SUBALIGN HIDDEN PROVIDE PROVIDE_HIDDEN AS_NEEDED
 %type <token> assign_op atype attributes_opt sect_constraint opt_align_with_input
 %type <name>  filename
@@ -342,6 +342,10 @@ filename:  NAME;
 		  { lang_enter_group (); }
 		    '(' input_list ')'
 		  { lang_leave_group (); }
+	|	LIB
+		  { lang_enter_lib (); }
+		    '(' input_list ')'
+		  { lang_leave_lib (); }
 	|	MAP '(' filename ')'
 		{ lang_add_map($3); }
 	|	INCLUDE filename
@@ -374,14 +378,23 @@ filename:  NAME;
 
 input_list1:
 		NAME
-		{ lang_add_input_file($1,lang_input_file_is_search_file_enum,
-				 (char *)NULL); }
+		{ lang_add_input_file ($1,
+				       (input_flags.fake_archive
+					? lang_input_file_is_search_member_enum
+					: lang_input_file_is_search_file_enum),
+				       (char *) NULL); }
 	|	input_list1 ',' NAME
-		{ lang_add_input_file($3,lang_input_file_is_search_file_enum,
-				 (char *)NULL); }
+		{ lang_add_input_file ($3,
+				       (input_flags.fake_archive
+					? lang_input_file_is_search_member_enum
+					: lang_input_file_is_search_file_enum),
+				       (char *) NULL); }
 	|	input_list1 NAME
-		{ lang_add_input_file($2,lang_input_file_is_search_file_enum,
-				 (char *)NULL); }
+		{ lang_add_input_file ($2,
+				       (input_flags.fake_archive
+					? lang_input_file_is_search_member_enum
+					: lang_input_file_is_search_file_enum),
+				       (char *) NULL); }
 	|	LNAME
 		{ lang_add_input_file($1,lang_input_file_is_l_enum,
 				 (char *)NULL); }
Index: binutils-gdb/ld/ldlang.c
===================================================================
--- binutils-gdb.orig/ld/ldlang.c
+++ binutils-gdb/ld/ldlang.c
@@ -21,6 +21,7 @@
 #include "sysdep.h"
 #include <limits.h>
 #include "bfd.h"
+#include "libbfd.h"
 #include "libiberty.h"
 #include "filenames.h"
 #include "safe-ctype.h"
@@ -1118,6 +1119,11 @@ lang_for_each_statement_worker (void (*f
 					  s->group_statement.children.head,
 					  constrained);
 	  break;
+	case lang_lib_statement_enum:
+	  lang_for_each_statement_worker (func,
+					  s->lib_statement.children.head,
+					  constrained);
+	  break;
 	case lang_data_statement_enum:
 	case lang_reloc_statement_enum:
 	case lang_object_symbols_statement_enum:
@@ -1225,6 +1231,25 @@ new_afile (const char *name,
       p->filename = name;
       p->local_sym_name = name;
       break;
+    case lang_input_file_is_fake_archive_enum:
+      p->filename = name;
+      p->flags.link_mapless = true;
+      break;
+    case lang_input_file_is_search_member_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 = stat_ldirname (from_filename);
+      p->flags.member = true;
+      p->flags.search_dirs = true;
+      break;
+    case lang_input_file_is_member_enum:
+      p->filename = name;
+      p->local_sym_name = name;
+      p->flags.member = true;
+      break;
     case lang_input_file_is_l_enum:
       if (name[0] == ':' && name[1] != '\0')
 	{
@@ -1967,6 +1992,7 @@ insert_os_after (lang_statement_union_ty
 	case lang_output_statement_enum:
 	case lang_group_statement_enum:
 	case lang_insert_statement_enum:
+	case lang_lib_statement_enum:
 	  continue;
 	case lang_input_matcher_enum:
 	  FAIL ();
@@ -3765,6 +3791,54 @@ open_input_bfds (lang_statement_union_ty
 	  if (s->assignment_statement.exp->type.node_class != etree_assert)
 	    exp_fold_tree_no_dot (s->assignment_statement.exp, os);
 	  break;
+	case lang_lib_statement_enum:
+	  {
+	    lang_statement_union_type *c;
+	    bfd *first_bfd = NULL, **next_bfd = &first_bfd;
+
+	    for (c = s->lib_statement.children.head;
+		 c != NULL;
+		 c = c->header.next)
+	      if (c->header.type == lang_input_statement_enum
+		  && c->input_statement.flags.member)
+		{
+		  bfd *abfd;
+
+		  c->input_statement.target = current_target;
+		  ldfile_open_file (&c->input_statement);
+		  abfd = c->input_statement.the_bfd;
+		  if (abfd != NULL)
+		    {
+		      *next_bfd = abfd;
+		      next_bfd = &abfd->proxy_handle.abfd;
+		    }
+		}
+
+	    if (first_bfd != NULL)
+	      {
+		lang_input_statement_type *h, *p;
+		bfd *fake_bfd;
+
+		h = &s->lib_statement.children.head->input_statement;
+		p = insert_input_file (NULL,
+				       lang_input_file_is_fake_archive_enum,
+				       h->target);
+		ASSERT (p != NULL);
+
+		fake_bfd = bfd_openr_fake_archive (first_bfd);
+		if (fake_bfd == NULL)
+		  fatal
+		    (_("cannot create --start-lib/--end-lib wrapper BFD:"
+		       " %E\n"));
+		p->the_bfd = fake_bfd;
+
+		if (!load_symbols (p, NULL))
+		  config.make_executable = false;
+	      }
+
+	    open_input_bfds (s->lib_statement.children.head, os, mode,
+			     nested_group_count_p);
+	  }
 	default:
 	  break;
 	}
@@ -4225,6 +4299,12 @@ check_input_sections
 	  if (!output_section_statement->all_input_readonly)
 	    return;
 	  break;
+	case lang_lib_statement_enum:
+	  check_input_sections (s->lib_statement.children.head,
+				output_section_statement);
+	  if (!output_section_statement->all_input_readonly)
+	    return;
+	  break;
 	default:
 	  break;
 	}
@@ -4348,6 +4428,8 @@ map_input_to_output_sections
 					target,
 					os);
 	  break;
+	case lang_lib_statement_enum:
+	  break;
 	case lang_data_statement_enum:
 	  if (os == NULL)
 	    /* This should never happen.  */
@@ -5390,6 +5472,17 @@ print_group (lang_group_statement_type *
   fprintf (config.map_file, "END GROUP\n");
 }
 
+/* Print a lib statement.  */
+
+static void
+print_lib (lang_lib_statement_type *s,
+	   lang_output_section_statement_type *os)
+{
+  fprintf (config.map_file, "START LIB\n");
+  print_statement_list (s->children.head, os);
+  fprintf (config.map_file, "END LIB\n");
+}
+
 /* Print the list of statements in S.
    This can be called for any statement type.  */
 
@@ -5472,6 +5565,9 @@ print_statement (lang_statement_union_ty
     case lang_group_statement_enum:
       print_group (&s->group_statement, os);
       break;
+    case lang_lib_statement_enum:
+      print_lib (&s->lib_statement, os);
+      break;
     case lang_insert_statement_enum:
       minfo ("INSERT %s %s\n",
 	     s->insert_statement.is_before ? "BEFORE" : "AFTER",
@@ -6484,6 +6580,9 @@ lang_size_sections_1
 	case lang_address_statement_enum:
 	  break;
 
+	case lang_lib_statement_enum:
+	  break;
+
 	default:
 	  FAIL ();
 	  break;
@@ -6879,6 +6978,9 @@ lang_do_assignments_1 (lang_statement_un
 	case lang_address_statement_enum:
 	  break;
 
+	case lang_lib_statement_enum:
+	  break;
+
 	default:
 	  FAIL ();
 	  break;
@@ -9169,6 +9271,35 @@ lang_leave_group (void)
   pop_stat_ptr ();
 }
 
+/* Enter an artificial library.  This creates a new lang_lib_statement,
+   and sets stat_ptr to build new statements within the library.  */
+
+void
+lang_enter_lib (void)
+{
+  lang_lib_statement_type *l;
+
+  ASSERT (!input_flags.fake_archive);
+  l = new_stat (lang_lib_statement, stat_ptr);
+  lang_list_init (&l->children);
+  push_stat_ptr (&l->children);
+  input_flags.fake_archive = true;
+}
+
+/* Leave an artificial library.  This just resets stat_ptr to start
+   writing to the regular list of statements again.  We only support
+   a single level of artificial libraries (i.e. they can't be nested
+   in one another) and they need to be wholly contained in any group,
+   so there's no issue with getting stat_ptr messed up.  */
+
+void
+lang_leave_lib (void)
+{
+  ASSERT (input_flags.fake_archive);
+  input_flags.fake_archive = false;
+  pop_stat_ptr ();
+}
+
 /* Add a new program header.  This is called for each entry in a PHDRS
    command in a linker script.  */
 
Index: binutils-gdb/ld/ldlang.h
===================================================================
--- binutils-gdb.orig/ld/ldlang.h
+++ binutils-gdb/ld/ldlang.h
@@ -31,6 +31,9 @@ typedef enum
   lang_input_file_is_symbols_only_enum,
   lang_input_file_is_marker_enum,
   lang_input_file_is_fake_enum,
+  lang_input_file_is_fake_archive_enum,
+  lang_input_file_is_search_member_enum,
+  lang_input_file_is_member_enum,
   lang_input_file_is_search_file_enum,
   lang_input_file_is_file_enum
 } lang_input_file_enum_type;
@@ -79,6 +82,7 @@ enum statement_enum
   lang_input_matcher_enum,
   lang_input_statement_enum,
   lang_insert_statement_enum,
+  lang_lib_statement_enum,
   lang_output_section_statement_enum,
   lang_output_statement_enum,
   lang_padding_statement_enum,
@@ -279,9 +283,15 @@ struct lang_input_statement_flags
   /* Whether to accept archives without a symbol map.  */
   unsigned int link_mapless : 1;
 
+  /* Whether we're building an artificial archive.  */
+  unsigned int fake_archive : 1;
+
   /* Set when bfd opening is successful.  */
   unsigned int loaded : 1;
 
+  /* Set for member entries of an artificial archive.  */
+  unsigned int member : 1;
+
   unsigned int real : 1;
 
   /* Set if the file does not exist.  */
@@ -439,6 +449,12 @@ typedef struct
   bool is_before;
 } lang_insert_statement_type;
 
+typedef struct
+{
+  lang_statement_header_type header;
+  lang_statement_list_type children;
+} lang_lib_statement_type;
+
 typedef union lang_statement_union
 {
   lang_statement_header_type header;
@@ -451,6 +467,7 @@ typedef union lang_statement_union
   lang_input_matcher_type input_matcher;
   lang_input_statement_type input_statement;
   lang_insert_statement_type insert_statement;
+  lang_lib_statement_type lib_statement;
   lang_output_section_statement_type output_section_statement;
   lang_output_statement_type output_statement;
   lang_padding_statement_type padding_statement;
@@ -678,6 +695,10 @@ extern void lang_enter_group
   (void);
 extern void lang_leave_group
   (void);
+extern void lang_enter_lib
+  (void);
+extern void lang_leave_lib
+  (void);
 extern void lang_add_section
   (lang_statement_list_type *, asection *, struct wildcard_list *,
    struct flag_info *, lang_output_section_statement_type *);
Index: binutils-gdb/ld/ldlex.h
===================================================================
--- binutils-gdb.orig/ld/ldlex.h
+++ binutils-gdb/ld/ldlex.h
@@ -53,6 +53,7 @@ enum option_values
   OPTION_NON_SHARED,
   OPTION_NO_WHOLE_ARCHIVE,
   OPTION_NO_LINK_MAPLESS,
+  OPTION_END_LIB,
   OPTION_OFORMAT,
   OPTION_RELAX,
   OPTION_NO_RELAX,
@@ -100,6 +101,7 @@ enum option_values
   OPTION_SPLIT_BY_FILE ,
   OPTION_WHOLE_ARCHIVE,
   OPTION_LINK_MAPLESS,
+  OPTION_START_LIB,
   OPTION_ADD_DT_NEEDED_FOR_DYNAMIC,
   OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC,
   OPTION_ADD_DT_NEEDED_FOR_REGULAR,
Index: binutils-gdb/ld/ldlex.l
===================================================================
--- binutils-gdb.orig/ld/ldlex.l
+++ binutils-gdb/ld/ldlex.l
@@ -289,6 +289,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([
 <SCRIPT>"OUTPUT"			{ RTOKEN(OUTPUT); }
 <SCRIPT>"INPUT"				{ RTOKEN(INPUT); }
 <SCRIPT>"GROUP"				{ RTOKEN(GROUP); }
+<SCRIPT>"LIB"				{ RTOKEN(LIB); }
 <INPUTLIST>"AS_NEEDED"			{ RTOKEN(AS_NEEDED); }
 <SCRIPT,EXPRESSION>"DEFINED"		{ RTOKEN(DEFINED); }
 <WILD>"CREATE_OBJECT_SYMBOLS"		{ RTOKEN(CREATE_OBJECT_SYMBOLS); }
Index: binutils-gdb/ld/ldmisc.c
===================================================================
--- binutils-gdb.orig/ld/ldmisc.c
+++ binutils-gdb/ld/ldmisc.c
@@ -482,7 +482,14 @@ vfinfo (FILE *fp, const char *fmt, va_li
 			     bfd_get_filename (abfd->my_archive),
 			     bfd_get_filename (abfd));
 		  else
-		    fprintf (fp, "%s", bfd_get_filename (abfd));
+		    {
+		      const char *filename = bfd_get_filename (abfd);
+
+		      if (filename == NULL)
+			fprintf (fp, "<no file> (%s generated)", program_name);
+		      else
+			fprintf (fp, "%s", filename);
+		    }
 		}
 	      else if (*fmt == 'I')
 		{
@@ -498,6 +505,8 @@ vfinfo (FILE *fp, const char *fmt, va_li
 		    fprintf (fp, "(%s)%s",
 			     bfd_get_filename (i->the_bfd->my_archive),
 			     i->local_sym_name);
+		  else if (i->filename == NULL)
+		    fprintf (fp, "<no file> (%s generated)", program_name);
 		  else
 		    fprintf (fp, "%s", i->filename);
 		}
Index: binutils-gdb/ld/lexsup.c
===================================================================
--- binutils-gdb.orig/ld/lexsup.c
+++ binutils-gdb/ld/lexsup.c
@@ -423,6 +423,8 @@ static const struct ld_option ld_options
     '\0', NULL, N_("Turn off --whole-archive"), TWO_DASHES },
   { {"no-link-mapless", no_argument, NULL, OPTION_NO_LINK_MAPLESS},
     '\0', NULL, N_("Reject archives without a symbol map"), TWO_DASHES },
+  { {"end-lib", no_argument, NULL, OPTION_END_LIB},
+    '\0', NULL, N_("Treat files specified as link objects"), TWO_DASHES },
   { {"noinhibit-exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC},
     '\0', NULL, N_("Create an output file even if errors occur"),
     TWO_DASHES },
@@ -607,6 +609,9 @@ static const struct ld_option ld_options
   { {"link-mapless", no_argument, NULL, OPTION_LINK_MAPLESS},
     '\0', NULL, N_("Accept archives without a symbol map"),
     TWO_DASHES },
+  { {"start-lib", no_argument, NULL, OPTION_START_LIB},
+    '\0', NULL, N_("Treat files specified as artificial archive members"),
+    TWO_DASHES },
   { {"wrap", required_argument, NULL, OPTION_WRAP},
     '\0', N_("SYMBOL"), N_("Use wrapper functions for SYMBOL"), TWO_DASHES },
   { {"ignore-unresolved-symbol", required_argument, NULL,
@@ -853,7 +858,11 @@ parse_args (unsigned argc, char **argv)
 	  break;
 
 	case 1:			/* File name.  */
-	  lang_add_input_file (optarg, lang_input_file_is_file_enum, NULL);
+	  lang_add_input_file (optarg,
+			       (input_flags.fake_archive
+				? lang_input_file_is_member_enum
+				: lang_input_file_is_file_enum),
+			       NULL);
 	  break;
 
 	case OPTION_IGNORE:
@@ -1180,11 +1189,19 @@ parse_args (unsigned argc, char **argv)
 	  config.only_cmd_line_lib_dirs = true;
 	  break;
 	case OPTION_NO_WHOLE_ARCHIVE:
+	  if (input_flags.fake_archive)
+	    fatal (_("%P: --no-whole-archive"
+		     " not allowed between --start-lib and --end-lib\n"));
 	  input_flags.whole_archive = false;
 	  break;
 	case OPTION_NO_LINK_MAPLESS:
 	  input_flags.link_mapless = false;
 	  break;
+	case OPTION_END_LIB:
+	  if (!input_flags.fake_archive)
+	    fatal (_("%P: --end-lib without --start-lib\n"));
+	  lang_leave_lib ();
+	  break;
 	case 'O':
 	  /* FIXME "-O<non-digits> <value>" used to set the address of
 	     section <non-digits>.  Was this for compatibility with
@@ -1663,11 +1680,19 @@ parse_args (unsigned argc, char **argv)
 	  link_info.warn_alternate_em = true;
 	  break;
 	case OPTION_WHOLE_ARCHIVE:
+	  if (input_flags.fake_archive)
+	    fatal (_("%P: --whole-archive"
+		     " not allowed between --start-lib and --end-lib\n"));
 	  input_flags.whole_archive = true;
 	  break;
 	case OPTION_LINK_MAPLESS:
 	  input_flags.link_mapless = true;
 	  break;
+	case OPTION_START_LIB:
+	  if (input_flags.fake_archive)
+	    fatal (_("%P: nested --start-lib not allowed\n"));
+	  lang_enter_lib ();
+	  break;
 	case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC:
 	  input_flags.add_DT_NEEDED_for_dynamic = true;
 	  break;
@@ -1732,10 +1757,16 @@ parse_args (unsigned argc, char **argv)
 	  command_line.accept_unknown_input_arch = false;
 	  break;
 	case '(':
+	  if (input_flags.fake_archive)
+	    fatal (_("%P: -( or --start-group"
+		     " not allowed between --start-lib and --end-lib\n"));
 	  lang_enter_group ();
 	  ingroup++;
 	  break;
 	case ')':
+	  if (input_flags.fake_archive)
+	    fatal (_("%P: -) or --end-group"
+		     " not allowed between --start-lib and --end-lib\n"));
 	  if (! ingroup)
 	    fatal (_("%P: group ended before it began (--help for usage)\n"));
 
@@ -1809,6 +1840,12 @@ parse_args (unsigned argc, char **argv)
 	case OPTION_POP_STATE:
 	  if (input_flags.pushed == NULL)
 	    fatal (_("%P: no state pushed before popping\n"));
+	  else if (input_flags.fake_archive
+		   && (input_flags.pushed->whole_archive
+		       != input_flags.whole_archive))
+	    fatal
+	      (_("%P: --pop-state not allowed to change --whole-archive"
+		 " setting between --start-lib and --end-lib\n"));
 	  else
 	    {
 	      struct lang_input_statement_flags *oldp = input_flags.pushed;
Index: binutils-gdb/ld/testsuite/ld-archive/ab.t
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/ab.t
@@ -0,0 +1 @@
+LIB(tmpdir/a.o tmpdir/b.o tmpdir/x.o)
Index: binutils-gdb/ld/testsuite/ld-archive/abfc.vd
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/abfc.vd
@@ -0,0 +1,28 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/abc\.o succeeded
+tmpdir/abc\.o
+attempt to open tmpdir/a\.o succeeded
+attempt to open tmpdir/b\.o succeeded
+attempt to open tmpdir/x\.o succeeded
+<no file> \(.* generated\)
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/a\.o +tmpdir/abc\.o \(aa\)
+tmpdir/a\.o
+tmpdir/b\.o +tmpdir/abc\.o \(bb\)
+tmpdir/b\.o
+!(:?\()?tmpdir/.*
+#...
+LOAD tmpdir/abc\.o
+START LIB
+LOAD tmpdir/a\.o
+LOAD tmpdir/b\.o
+LOAD tmpdir/x\.o
+END LIB
+!LOAD .*
+#pass
Index: binutils-gdb/ld/testsuite/ld-archive/abfcfg.vd
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/abfcfg.vd
@@ -0,0 +1,36 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/a\.o succeeded
+attempt to open tmpdir/b\.o succeeded
+attempt to open tmpdir/x\.o succeeded
+<no file> \(.* generated\)
+attempt to open tmpdir/abc\.o succeeded
+<no file> \(.* generated\)
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/abc\.o +\(ff\)
+tmpdir/abc\.o
+<no file> \(.* generated\)
+tmpdir/a\.o +tmpdir/abc\.o \(aa\)
+tmpdir/a\.o
+tmpdir/b\.o +tmpdir/abc\.o \(bb\)
+tmpdir/b\.o
+<no file> \(.* generated\)
+!(:?\()?tmpdir/.*
+#...
+START GROUP
+START LIB
+LOAD tmpdir/a\.o
+LOAD tmpdir/b\.o
+LOAD tmpdir/x\.o
+END LIB
+START LIB
+LOAD tmpdir/abc\.o
+END LIB
+END GROUP
+!LOAD .*
+#pass
Index: binutils-gdb/ld/testsuite/ld-archive/absc.vd
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/absc.vd
@@ -0,0 +1,35 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/abc\.o succeeded
+tmpdir/abc\.o
+attempt to open .*/ld/testsuite/ld-archive/ab\.t succeeded
+.*/ld/testsuite/ld-archive/ab\.t
+opened script file .*/ld/testsuite/ld-archive/ab\.t
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/a\.o failed
+attempt to open tmpdir/a\.o succeeded
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/b\.o failed
+attempt to open tmpdir/b\.o succeeded
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/x\.o failed
+attempt to open tmpdir/x\.o succeeded
+<no file> \(.* generated\)
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/a\.o +tmpdir/abc\.o \(aa\)
+tmpdir/a\.o
+tmpdir/b\.o +tmpdir/abc\.o \(bb\)
+tmpdir/b\.o
+!(:?\()?tmpdir/.*
+#...
+LOAD tmpdir/abc\.o
+LOAD .*/ld/testsuite/ld-archive/ab\.t
+START LIB
+LOAD tmpdir/a\.o
+LOAD tmpdir/b\.o
+LOAD tmpdir/x\.o
+END LIB
+!LOAD .*
+#pass
Index: binutils-gdb/ld/testsuite/ld-archive/abscfg.vd
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/abscfg.vd
@@ -0,0 +1,43 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open .*/ld/testsuite/ld-archive/ab\.t succeeded
+.*/ld/testsuite/ld-archive/ab\.t
+opened script file .*/ld/testsuite/ld-archive/ab\.t
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/a\.o failed
+attempt to open tmpdir/a\.o succeeded
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/b\.o failed
+attempt to open tmpdir/b\.o succeeded
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/x\.o failed
+attempt to open tmpdir/x\.o succeeded
+<no file> \(.* generated\)
+attempt to open tmpdir/abc\.o succeeded
+<no file> \(.* generated\)
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/abc\.o +\(ff\)
+tmpdir/abc\.o
+<no file> \(.* generated\)
+tmpdir/a\.o +tmpdir/abc\.o \(aa\)
+tmpdir/a\.o
+tmpdir/b\.o +tmpdir/abc\.o \(bb\)
+tmpdir/b\.o
+<no file> \(.* generated\)
+!(:?\()?tmpdir/.*
+#...
+START GROUP
+LOAD .*/ld/testsuite/ld-archive/ab\.t
+START LIB
+LOAD tmpdir/a\.o
+LOAD tmpdir/b\.o
+LOAD tmpdir/x\.o
+END LIB
+START LIB
+LOAD tmpdir/abc\.o
+END LIB
+END GROUP
+!LOAD .*
+#pass
Index: binutils-gdb/ld/testsuite/ld-archive/abwfc.vd
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/abwfc.vd
@@ -0,0 +1,30 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/abc\.o succeeded
+tmpdir/abc\.o
+attempt to open tmpdir/a\.o succeeded
+attempt to open tmpdir/b\.o succeeded
+attempt to open tmpdir/x\.o succeeded
+<no file> \(.* generated\)
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/a\.o +\(--whole-archive\)
+tmpdir/a\.o
+tmpdir/b\.o +\(--whole-archive\)
+tmpdir/b\.o
+tmpdir/x\.o +\(--whole-archive\)
+tmpdir/x\.o
+!(:?\()?tmpdir/.*
+#...
+LOAD tmpdir/abc\.o
+START LIB
+LOAD tmpdir/a\.o
+LOAD tmpdir/b\.o
+LOAD tmpdir/x\.o
+END LIB
+!LOAD .*
+#pass
Index: binutils-gdb/ld/testsuite/ld-archive/abwsc.vd
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/abwsc.vd
@@ -0,0 +1,37 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/abc\.o succeeded
+tmpdir/abc\.o
+attempt to open .*/ld/testsuite/ld-archive/ab\.t succeeded
+.*/ld/testsuite/ld-archive/ab\.t
+opened script file .*/ld/testsuite/ld-archive/ab\.t
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/a\.o failed
+attempt to open tmpdir/a\.o succeeded
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/b\.o failed
+attempt to open tmpdir/b\.o succeeded
+attempt to open .*/ld/testsuite/ld-archive/tmpdir/x\.o failed
+attempt to open tmpdir/x\.o succeeded
+<no file> \(.* generated\)
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/a\.o +\(--whole-archive\)
+tmpdir/a\.o
+tmpdir/b\.o +\(--whole-archive\)
+tmpdir/b\.o
+tmpdir/x\.o +\(--whole-archive\)
+tmpdir/x\.o
+!(:?\()?tmpdir/.*
+#...
+LOAD tmpdir/abc\.o
+LOAD .*/ld/testsuite/ld-archive/ab\.t
+START LIB
+LOAD tmpdir/a\.o
+LOAD tmpdir/b\.o
+LOAD tmpdir/x\.o
+END LIB
+!LOAD .*
+#pass
Index: binutils-gdb/ld/testsuite/ld-archive/archive.exp
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-archive/archive.exp
+++ binutils-gdb/ld/testsuite/ld-archive/archive.exp
@@ -86,6 +86,23 @@ run_ld_link_tests [list \
 				  {nm "" nx.nd}}] \
 	"abtc" \
     ] \
+    [list "Fake archive link" \
+	"-e ff" "--start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+		 --verbose --print-map" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{ld abfc.vd} \
+				  {nm "" abc.nd} \
+				  {nm "" nx.nd}}] \
+	"abfc" \
+    ] \
+    [list "Script fake archive link" \
+	"-e ff" "$srcdir/$subdir/ab.t --verbose --print-map" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{ld absc.vd} \
+				  {nm "" abc.nd} \
+				  {nm "" nx.nd}}] \
+	"absc" \
+    ] \
 ]
 
 # Single whole archive tests.
@@ -113,6 +130,24 @@ run_ld_link_tests [list \
 				  {nm "" x.nd}}] \
 	"abwtc" \
     ] \
+    [list "Fake whole archive link" \
+	"-e ff" "--whole-archive\
+		 --start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+		 --verbose --print-map" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{ld abwfc.vd} \
+				  {nm "" abc.nd} \
+				  {nm "" x.nd}}] \
+	"abwfc" \
+    ] \
+    [list "Script fake whole archive link" \
+	"-e ff" "--whole-archive $srcdir/$subdir/ab.t --verbose --print-map" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{ld abwsc.vd} \
+				  {nm "" abc.nd} \
+				  {nm "" x.nd}}] \
+	"abwsc" \
+    ] \
 ]
 
 # Group archive tests.
@@ -129,6 +164,19 @@ run_ld_link_tests [list \
 	{{ld abcn.ed}} \
 	"abtctn" \
     ] \
+    [list "Fake non-group archive link reject" \
+	"-e ff --start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+	 --start-lib" "--end-lib" \
+	"" {abc.s} \
+	{{ld abcn.ed}} \
+	"abfcfn" \
+    ] \
+    [list "Script fake non-group archive link reject" \
+	"-e ff $srcdir/$subdir/ab.t --start-lib" "--end-lib" \
+	"" {abc.s} \
+	{{ld abcn.ed}} \
+	"abscfn" \
+    ] \
     [list "Regular group archive link accept" \
 	"-e ff -\\( tmpdir/ab.a" "tmpdir/abc.a -\\) --verbose --print-map" \
 	"" {} \
@@ -154,6 +202,24 @@ run_ld_link_tests [list \
 				  {nm "" nx.nd}}] \
 	"abtctg" \
     ] \
+    [list "Fake group archive link accept" \
+	"-e ff -\\( --start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+	 --start-lib" "--end-lib -\\) --verbose --print-map" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{ld abfcfg.vd} \
+				  {nm "" abc.nd} \
+				  {nm "" nx.nd}}] \
+	"abfcfg" \
+    ] \
+    [list "Script fake group archive link accept" \
+	"-e ff -\\( $srcdir/$subdir/ab.t\
+	 --start-lib" "--end-lib -\\) --verbose --print-map" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{ld abscfg.vd} \
+				  {nm "" abc.nd} \
+				  {nm "" nx.nd}}] \
+	"abscfg" \
+    ] \
 ]
 
 # Dual archive tests.
@@ -179,6 +245,23 @@ run_ld_link_tests [list \
 				  {nm "" ny.nd}}] \
 	"abcdte" \
     ] \
+    [list "Regular archive plus fake link" \
+	"-e ff" "tmpdir/ab.a\
+		 --start-lib tmpdir/c.o tmpdir/d.o tmpdir/y.o --end-lib" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abcdfe" \
+    ] \
+    [list "Regular archive plus script fake link" \
+	"-e ff" "tmpdir/ab.a $srcdir/$subdir/cd.t" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abcdse" \
+    ] \
 ]
 setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
 setup_xfail "binutils/33485" "cris-*-*aout*" "i\[3-7\]86-*-bsd*" \
@@ -206,6 +289,81 @@ run_ld_link_tests [list \
 	"abtcdte" \
     ] \
 ]
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+setup_xfail "binutils/33485" "cris-*-*aout*" "i\[3-7\]86-*-bsd*" \
+    "i\[3-7\]86-*-msdos*" "ns32k-*-*" "pdp11-*-*"
+run_ld_link_tests [list \
+    [list "Thin archive plus fake link" \
+	"-e ff" "tmpdir/abt.a\
+		 --start-lib tmpdir/c.o tmpdir/d.o tmpdir/y.o --end-lib" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abtcdfe" \
+    ] \
+]
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+setup_xfail "binutils/33485" "cris-*-*aout*" "i\[3-7\]86-*-bsd*" \
+    "i\[3-7\]86-*-msdos*" "ns32k-*-*" "pdp11-*-*"
+run_ld_link_tests [list \
+    [list "Thin archive plus script fake link" \
+	"-e ff" "tmpdir/abt.a $srcdir/$subdir/cd.t" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abtcdse" \
+    ] \
+    [list "Fake archive plus regular link" \
+	"-e ff" "--start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+		 tmpdir/cd.a" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abfcde" \
+    ] \
+    [list "Script fake archive plus regular link" \
+	"-e ff" "$srcdir/$subdir/ab.t tmpdir/cd.a" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abscde" \
+    ] \
+]
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+setup_xfail "binutils/33485" "cris-*-*aout*" "i\[3-7\]86-*-bsd*" \
+    "i\[3-7\]86-*-msdos*" "ns32k-*-*" "pdp11-*-*"
+run_ld_link_tests [list \
+    [list "Fake archive plus thin link" \
+	"-e ff" "--start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+		 tmpdir/cdt.a" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abfcdte" \
+    ] \
+    [list "Fake archive plus fake link" \
+	"-e ff" "--start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+		 --start-lib tmpdir/c.o tmpdir/d.o tmpdir/y.o --end-lib" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abfcdfe" \
+    ] \
+    [list "Script fake archive plus script fake link" \
+	"-e ff" "$srcdir/$subdir/ab.t $srcdir/$subdir/cd.t" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" ny.nd}}] \
+	"abscdse" \
+    ] \
+]
 
 # Dual whole archive tests.
 run_ld_link_tests [list \
@@ -228,6 +386,16 @@ run_ld_link_tests [list \
 				  {nm "" y.nd}}] \
 	"abcdwte" \
     ] \
+    [list "Regular archive plus whole fake link" \
+	"-e ff" "tmpdir/ab.a\
+		 --whole-archive\
+		 --start-lib tmpdir/c.o tmpdir/d.o tmpdir/y.o --end-lib" \
+	"" {abcde.s} \
+	[ld_archive_filter_tests {{nm "" abcde.nd} \
+				  {nm "" nx.nd} \
+				  {nm "" y.nd}}] \
+	"abcdwfe" \
+    ] \
 ]
 
 # Single non-index archive accept tests.
@@ -249,6 +417,21 @@ run_ld_link_tests [list \
 				  {nm "" nx.nd}}] \
 	"abntc" \
     ] \
+    [list "Fake archive with --no-link-mapless link accept" \
+	"-e ff" "--no-link-mapless\
+		 --start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{nm "" abc.nd} \
+				  {nm "" nx.nd}}] \
+	"abnfc" \
+    ] \
+    [list "Script fake archive with --no-link-mapless link accept" \
+	"-e ff" "--no-link-mapless $srcdir/$subdir/ab.t" \
+	"" {abc.s} \
+	[ld_archive_filter_tests {{nm "" abc.nd} \
+				  {nm "" nx.nd}}] \
+	"abnsc" \
+    ] \
 ]
 
 # Dual non-index archive accept tests.
Index: binutils-gdb/ld/testsuite/ld-archive/cd.t
===================================================================
--- /dev/null
+++ binutils-gdb/ld/testsuite/ld-archive/cd.t
@@ -0,0 +1 @@
+LIB(tmpdir/c.o tmpdir/d.o tmpdir/y.o)
Index: binutils-gdb/ld/testsuite/ld-cris/archive.exp
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-cris/archive.exp
+++ binutils-gdb/ld/testsuite/ld-cris/archive.exp
@@ -76,6 +76,24 @@ run_ld_link_tests [list \
 	 {nm "" ../ld-archive/nx.nd}} \
 	"abci" \
     ] \
+    [list "CRIS fake archive link (explicit emulation)" \
+	"$ldemul -e ff" "--start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o\
+			 --end-lib --verbose --print-map" \
+	"$asemul" {../ld-archive/abc.s} \
+	{{ld ../ld-archive/abfc.vd} \
+	 {nm "" ../ld-archive/abc.nd} \
+	 {nm "" ../ld-archive/nx.nd}} \
+	"abfcx" \
+    ] \
+    [list "CRIS fake archive link (implicit emulation)" \
+	"-e ff" "--start-lib tmpdir/a.o tmpdir/b.o tmpdir/x.o --end-lib\
+		 --verbose --print-map" \
+	"$asemul" {../ld-archive/abc.s} \
+	{{ld ../ld-archive/abfc.vd} \
+	 {nm "" ../ld-archive/abc.nd} \
+	 {nm "" ../ld-archive/nx.nd}} \
+	"abfci" \
+    ] \
 ]
 if { ![istarget cris-*-*aout*] } {
     setup_xfail "binutils/33485" "*-*-*"


More information about the Binutils mailing list