[PATCH v2] [RFC][ld] Introduce static bundle object support

Eyal Itkin eyal.itkin@gmail.com
Fri Oct 10 12:23:15 GMT 2025


Note: This patch is a draft for review.

Introduce a new "Static Bundle Object" which is a
relocatable object that supports symbol visibility
and finalization of local relocations. This format
is aimed to be incorporated within static archives
so to replace the current static archives of plain
object code files that are used to form static
libraries.

The full discussion about the format is available in the
generic-abi group that is responsible for the ELF standard:
https://groups.google.com/g/generic-abi/c/sT25-xfX9yc

Some questions I had about the process itself:
1. The patch is architecture dependent given that
relocations support is found in both bfd/elflink.c AND
in some arch-specific files (such as bfd/elf64-x86-64.c).
Hence, what is the standard way for marking some archs as
not yet supported? And what is the recommended process for
adding said support (especially given need to test it)?

Signed-off-by: Eyal Itkin <eyal.itkin@gmail.com>
---
 bfd/elf64-x86-64.c                            |  23 ++-
 bfd/elflink.c                                 |  43 ++++-
 include/bfdlink.h                             |   5 +
 ld/ld.h                                       |   3 +
 ld/ldlex.h                                    |   1 +
 ld/lexsup.c                                   |  15 +-
 ld/testsuite/ld-static-bundle/bundle1.c       |  15 ++
 ld/testsuite/ld-static-bundle/bundle2.c       |  12 ++
 ld/testsuite/ld-static-bundle/helper.c        |  12 ++
 ld/testsuite/ld-static-bundle/lib_helper.c    |  10 +
 ld/testsuite/ld-static-bundle/main.c          |  23 +++
 .../ld-static-bundle/static-bundle.dat        |   3 +
 .../ld-static-bundle/static-bundle.exp        | 181 ++++++++++++++++++
 ld/testsuite/ld-static-bundle/version.map     |   7 +
 14 files changed, 338 insertions(+), 15 deletions(-)
 create mode 100644 ld/testsuite/ld-static-bundle/bundle1.c
 create mode 100644 ld/testsuite/ld-static-bundle/bundle2.c
 create mode 100644 ld/testsuite/ld-static-bundle/helper.c
 create mode 100644 ld/testsuite/ld-static-bundle/lib_helper.c
 create mode 100644 ld/testsuite/ld-static-bundle/main.c
 create mode 100644 ld/testsuite/ld-static-bundle/static-bundle.dat
 create mode 100644 ld/testsuite/ld-static-bundle/static-bundle.exp
 create mode 100644 ld/testsuite/ld-static-bundle/version.map

diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c
index 59b43149897..7238590e46b 100644
--- a/bfd/elf64-x86-64.c
+++ b/bfd/elf64-x86-64.c
@@ -3227,7 +3227,9 @@ elf_x86_64_relocate_section (bfd *output_bfd,
       bool converted_reloc;
       bool need_copy_reloc_in_pie;
       bool no_copyreloc_p;
+      bool skip_reloc_registration;
 
+      skip_reloc_registration = true;
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == (int) R_X86_64_GNU_VTINHERIT
 	  || r_type == (int) R_X86_64_GNU_VTENTRY)
@@ -3286,6 +3288,15 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 				   h, sec, relocation,
 				   unresolved_reloc, warned, ignored);
 	  st_size = h->size;
+	  skip_reloc_registration = !info->static_bundle || !h->forced_local;
+
+	  struct bfd_section *input_sec_out = input_section->output_section;
+	  struct bfd_section *sym_sec_out = sec ? sec->output_section : NULL;
+
+	  /* A relocatable can not finalize a cross-section relocation.  */
+	  if (sym_sec_out != NULL
+	      && sym_sec_out->index != input_sec_out->index)
+	    skip_reloc_registration = true;
 	}
 
       if (sec != NULL && discarded_section (sec))
@@ -3310,7 +3321,7 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 	  continue;
 	}
 
-      if (bfd_link_relocatable (info))
+      if (bfd_link_relocatable (info) && skip_reloc_registration)
 	{
 	  if (wrel != rel)
 	    *wrel = *rel;
@@ -5117,6 +5128,13 @@ elf_x86_64_relocate_section (bfd *output_bfd,
 	    }
 	}
 
+      /* Skip the applied relocation if based on local relocation.  */
+      if (bfd_link_relocatable (info) && !skip_reloc_registration)
+	{
+	  wrel--;
+	  continue;
+	}
+
       if (wrel != rel)
 	*wrel = *rel;
     }
@@ -5409,7 +5427,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
   if (h->got.offset != (bfd_vma) -1
       && ! GOT_TLS_GD_ANY_P (elf_x86_hash_entry (h)->tls_type)
       && elf_x86_hash_entry (h)->tls_type != GOT_TLS_IE
-      && !local_undefweak)
+      && !local_undefweak
+      && !(bfd_link_relocatable (info) && info->static_bundle))
     {
       Elf_Internal_Rela rela;
       asection *relgot = htab->elf.srelgot;
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 3f3ea2cce51..45188272730 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -803,9 +803,9 @@ bfd_elf_record_link_assignment (bfd *output_bfd,
       (*bed->elf_backend_hide_symbol) (info, h, true);
     }
 
-  /* STV_HIDDEN and STV_INTERNAL symbols must be STB_LOCAL in shared objects
-     and executables.  */
-  if (!bfd_link_relocatable (info)
+  /* STV_HIDDEN and STV_INTERNAL symbols must be STB_LOCAL in shared objects,
+     executables and static bundles.  */
+  if (!(bfd_link_relocatable (info) && info->static_bundle)
       && h->dynindx != -1
       && (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
 	  || ELF_ST_VISIBILITY (h->other) == STV_INTERNAL))
@@ -3151,7 +3151,10 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
 	h->def_regular = 1;
     }
 
-  /* Backend specific symbol fixup.  */
+  /* Backend specific symbol fixup, only needed for dynamic case.  */
+  if (elf_hash_table (eif->info)->dynobj == NULL)
+    return true;
+
   bed = get_elf_backend_data (elf_hash_table (eif->info)->dynobj);
   if (bed->elf_backend_fixup_symbol
       && !(*bed->elf_backend_fixup_symbol) (eif->info, h))
@@ -3197,7 +3200,9 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h,
      visibility.  If the symbol has hidden or internal visibility, we
      will force it local.  */
   else if (h->needs_plt
-	   && bfd_link_pic (eif->info)
+	   && (bfd_link_pic (eif->info)
+	       || (bfd_link_relocatable (eif->info)
+		   && eif->info->static_bundle))
 	   && is_elf_hash_table (eif->info->hash)
 	   && (SYMBOLIC_BIND (eif->info, h)
 	       || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
@@ -5680,7 +5685,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
 		    goto error_free_vers;
 		}
 	    }
-	  else if (h->dynindx != -1)
+	  else if (h->dynindx != -1
+		   || (bfd_link_relocatable (info) && info->static_bundle))
 	    /* If the symbol already has a dynamic index, but
 	       visibility says it should not be visible, turn it into
 	       a local symbol.  */
@@ -6925,6 +6931,7 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 {
   bfd *dynobj;
   const struct elf_backend_data *bed;
+  struct elf_info_failed asvinfo;
 
   *sinterpptr = NULL;
 
@@ -6948,10 +6955,22 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd,
 
   dynobj = elf_hash_table (info)->dynobj;
 
-  if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
+  /* Symbol visibility should be applied in some non-dynamic cases.  */
+  if (bfd_link_relocatable (info) && info->static_bundle)
+    {
+      /* Attach all the symbols to their version information.  */
+      asvinfo.info = info;
+      asvinfo.failed = false;
+
+      elf_link_hash_traverse (elf_hash_table (info),
+			      _bfd_elf_link_assign_sym_version,
+			      &asvinfo);
+      if (asvinfo.failed)
+	return false;
+    }
+  else if (dynobj != NULL && elf_hash_table (info)->dynamic_sections_created)
     {
       struct bfd_elf_version_tree *verdefs;
-      struct elf_info_failed asvinfo;
       struct bfd_elf_version_tree *t;
       struct bfd_elf_version_expr *d;
       asection *s;
@@ -11039,11 +11058,15 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data)
        && !bfd_link_relocatable (flinfo->info))
       || ((h->dynindx != -1
 	   || h->forced_local)
-	  && ((bfd_link_pic (flinfo->info)
+	  && (((bfd_link_pic (flinfo->info)
+		|| (bfd_link_relocatable (flinfo->info)
+		    && flinfo->info->static_bundle))
 	       && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
 		   || h->root.type != bfd_link_hash_undefweak))
 	      || !h->forced_local)
-	  && elf_hash_table (flinfo->info)->dynamic_sections_created))
+	  && (elf_hash_table (flinfo->info)->dynamic_sections_created
+	      || (bfd_link_relocatable (flinfo->info)
+		  && flinfo->info->static_bundle))))
     {
       if (! ((*bed->elf_backend_finish_dynamic_symbol)
 	     (flinfo->output_bfd, flinfo->info, h, &sym)))
diff --git a/include/bfdlink.h b/include/bfdlink.h
index 3d4d71b3347..6e652a41073 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -476,6 +476,11 @@ struct bfd_link_info
      statics.  */
   unsigned int task_link: 1;
 
+  /* TRUE if BFD should generate a "static bundle" object file,
+     similar to relocatable but also with local relocations being
+     finalized.  */
+  unsigned int static_bundle: 1;
+
   /* TRUE if ok to have multiple definitions, without warning.  */
   unsigned int allow_multiple_definition: 1;
 
diff --git a/ld/ld.h b/ld/ld.h
index c8688153bd4..cd1046b4a78 100644
--- a/ld/ld.h
+++ b/ld/ld.h
@@ -332,6 +332,9 @@ typedef struct
 
   /* Compress DWARF debug sections.  */
   enum compressed_debug_section_type compress_debug;
+
+  /* If set, finalize local symbols withing the relocatable object.  */
+  bool finalize_locals;
 } ld_config_type;
 
 /* An enumeration of the linker phases for which resource usage information
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 24cac1cdfc0..4add8f53148 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -139,6 +139,7 @@ enum option_values
   OPTION_NO_ACCEPT_UNKNOWN_INPUT_ARCH,
   OPTION_PIE,
   OPTION_NO_PIE,
+  OPTION_FINALIZE_LOCALS,
   OPTION_UNRESOLVED_SYMBOLS,
   OPTION_WARN_UNRESOLVED_SYMBOLS,
   OPTION_ERROR_UNRESOLVED_SYMBOLS,
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 5cb77992733..cadfd883a45 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -208,6 +208,8 @@ static const struct ld_option ld_options[] =
     'q', NULL, "Generate relocations in final output", TWO_DASHES },
   { {"relocatable", no_argument, NULL, 'r'},
     'r', NULL, N_("Generate relocatable output"), TWO_DASHES },
+  { {"finalize-locals", no_argument, NULL, OPTION_FINALIZE_LOCALS},
+    '\0', NULL, N_("Finalize local relocations within the relocatable output"), TWO_DASHES },
   { {NULL, no_argument, NULL, '\0'},
     'i', NULL, NULL, ONE_DASH },
   { {"just-symbols", required_argument, NULL, 'R'},
@@ -1237,6 +1239,7 @@ parse_args (unsigned argc, char **argv)
 		   bfd_link_dll (&link_info) ? "-shared" : "-pie");
 
 	  link_info.type = type_relocatable;
+	  link_info.static_bundle = false;
 	  config.build_constructors = false;
 	  config.magic_demand_paged = false;
 	  config.text_read_only = false;
@@ -1357,6 +1360,12 @@ parse_args (unsigned argc, char **argv)
 	  else
 	    fatal (_("%P: -shared not supported\n"));
 	  break;
+	case OPTION_FINALIZE_LOCALS:
+	  if (!bfd_link_relocatable (&link_info))
+	    fatal (_("%P: %s may only be used together with -r\n"),
+		   "--finalize-locals");
+	  link_info.static_bundle = true;
+	  break;
 	case OPTION_NO_PIE:
 	  link_info.type = type_pde;
 	  break;
@@ -2029,12 +2038,12 @@ parse_args (unsigned argc, char **argv)
       link_info.strip = strip_all;
     }
 
-  if (!bfd_link_dll (&link_info))
+  if (!bfd_link_dll (&link_info) && !link_info.static_bundle)
     {
       if (command_line.filter_shlib)
-	fatal (_("%P: -F may not be used without -shared\n"));
+	fatal (_("%P: -F may not be used without -shared or --finalize-locals\n"));
       if (command_line.auxiliary_filters)
-	fatal (_("%P: -f may not be used without -shared\n"));
+	fatal (_("%P: -f may not be used without -shared or --finalize-locals\n"));
     }
 
   /* Treat ld -r -s as ld -r -S -x (i.e., strip all local symbols).  I
diff --git a/ld/testsuite/ld-static-bundle/bundle1.c b/ld/testsuite/ld-static-bundle/bundle1.c
new file mode 100644
index 00000000000..7b2073eba9b
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/bundle1.c
@@ -0,0 +1,15 @@
+/* This is part of the static bundle ld test.  This file becomes part
+   of a static library implemented using a static bundle.  */
+
+/* This function is defined by another file in the static bundle.  */
+extern int helper_get_value();
+
+/* This function returns the library specific values.  This is the
+   only publicly exposed function in this library.  */
+
+__attribute__((visibility("default"))) __attribute__((used))
+int
+lib_get_value ()
+{
+  return helper_get_value ();
+}
\ No newline at end of file
diff --git a/ld/testsuite/ld-static-bundle/bundle2.c b/ld/testsuite/ld-static-bundle/bundle2.c
new file mode 100644
index 00000000000..d73032a986c
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/bundle2.c
@@ -0,0 +1,12 @@
+/* This is part of the static bundle ld test.  This file becomes part
+   of a static library implemented using a static bundle.  */
+
+/* This function is defined by the helper static library.  */
+extern int helper_get_inner_value ();
+
+/* This function is called by another file in the static bundle.  */
+
+int helper_get_value ()
+{
+  return 0x0030 + helper_get_inner_value ();
+}
diff --git a/ld/testsuite/ld-static-bundle/helper.c b/ld/testsuite/ld-static-bundle/helper.c
new file mode 100644
index 00000000000..40728fbdbeb
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/helper.c
@@ -0,0 +1,12 @@
+/* This is the helper program for the static bundle library test.
+   The program is used by the main program.  */
+
+int helper_get_value()
+{
+  return 0x1000;
+}
+
+int helper_get_inner_value ()
+{
+  return 0x0200;
+}
\ No newline at end of file
diff --git a/ld/testsuite/ld-static-bundle/lib_helper.c b/ld/testsuite/ld-static-bundle/lib_helper.c
new file mode 100644
index 00000000000..d51e2ab16ed
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/lib_helper.c
@@ -0,0 +1,10 @@
+/* This is part of the static bundle ld test.  This file becomes part
+   of a helper static library.  */
+
+/* This function returns the helper library specific values.  */
+
+int
+helper_get_inner_value ()
+{
+  return 0x0004;
+}
\ No newline at end of file
diff --git a/ld/testsuite/ld-static-bundle/main.c b/ld/testsuite/ld-static-bundle/main.c
new file mode 100644
index 00000000000..5958308b32c
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/main.c
@@ -0,0 +1,23 @@
+/* This is the main program for the static bundle test.  */
+
+#include <stdio.h>
+
+/* These function (possibly) conflict with functions in the static bundle.  */
+
+extern int helper_get_value();
+extern int helper_get_inner_value ();
+
+/* This function is exported by the static bundle.  */
+
+extern int lib_get_value ();
+
+/* This is the main program.  */
+
+int
+main ()
+{
+  printf ("helper_get_value () == 0x%04x\n", helper_get_value ());
+  printf ("helper_get_inner_value () == 0x%04x\n", helper_get_inner_value ());
+  printf ("lib_get_value () == 0x%04x\n", lib_get_value ());
+  return 0;
+}
\ No newline at end of file
diff --git a/ld/testsuite/ld-static-bundle/static-bundle.dat b/ld/testsuite/ld-static-bundle/static-bundle.dat
new file mode 100644
index 00000000000..1f24c91614c
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/static-bundle.dat
@@ -0,0 +1,3 @@
+helper_get_value () == 0x1000
+helper_get_inner_value () == 0x0200
+lib_get_value () == 0x0034
diff --git a/ld/testsuite/ld-static-bundle/static-bundle.exp b/ld/testsuite/ld-static-bundle/static-bundle.exp
new file mode 100644
index 00000000000..d7469b9fdf8
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/static-bundle.exp
@@ -0,0 +1,181 @@
+# Expect script for ld-static-bundle tests
+#   Copyright (C) 1994-2025 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.
+#
+# Written by Eyal Itkin (eyal.itkin@gmail.com)
+#
+
+# Check to see if the C compiler works
+if { ![check_compiler_available] } {
+    return
+}
+
+# This test can only be run on a couple of ELF platforms.
+# Square bracket expressions seem to confuse istarget.
+if { ![istarget x86_64-*-linux*] } {
+    return
+}
+
+set tmpdir tmpdir
+
+# Disable all sanitizers.
+set old_CFLAGS "$CFLAGS_FOR_TARGET_TEST"
+append CFLAGS_FOR_TARGET_TEST " $NOSANITIZE_CFLAGS"
+
+# Strip a symbol using "strip"
+#
+proc strip_symbol { strip symbol target } {
+    set exec_output [run_host_cmd "$strip" "-N$symbol $target"]
+    set exec_output [prune_warnings $exec_output]
+
+    if [string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	return 1
+    } else {
+	return 0
+    }
+}
+
+# The test procedure.
+proc static_bundle_test { progname testname main helper bundle1 bundle2 lib_helper expect_strip args } {
+    global CC_FOR_TARGET
+    global srcdir
+    global subdir
+    global exec_output
+    global host_triplet
+    global tmpdir
+    global ar
+    global ld
+    global strip
+
+    if [llength $args] { set ldflags [lindex $args 0] } else { set ldflags "" }
+    if { [llength $args] >= 2 } { set ldflags [lindex $args 1] } else { set ldflags "" }
+
+    # Build the helper static library.
+    if {![ar_simple_create $ar "" $tmpdir/$progname.helper.a "$tmpdir/$lib_helper"]} {
+	fail "$testname - creating helper archive"
+	return
+    }
+
+    # Build the static bundle.
+    if {![ld_relocate $ld $tmpdir/$progname.bundle.o "$ldflags --finalize-locals $tmpdir/$bundle1 $tmpdir/$bundle2 $tmpdir/$progname.helper.a"]} {
+	fail "$testname - creating static bundle"
+	return
+    }
+
+    # Build the static bundle based static library.
+    if {![ar_simple_create $ar "" $tmpdir/$progname.static.a "$tmpdir/$progname.bundle.o"]} {
+	fail "$testname - creating static library"
+	return
+    }
+
+    # Link against the static library.
+    if ![ld_link $CC_FOR_TARGET $tmpdir/$progname "$ldflags $tmpdir/$main $tmpdir/$helper $tmpdir/$progname.static.a"] {
+	fail "$testname - linking the test program"
+	return
+    }
+
+    if ![isnative] {
+	unsupported $testname
+	return
+    }
+
+    # Run the resulting program
+    send_log "$tmpdir/$progname >$tmpdir/$progname.out\n"
+    verbose "$tmpdir/$progname >$tmpdir/$progname.out"
+    catch "exec $tmpdir/$progname >$tmpdir/$progname.out" exec_output
+    if ![string match "" $exec_output] then {
+	send_log "$exec_output\n"
+	verbose "$exec_output"
+	fail "$testname - executing test program"
+	return
+    }
+
+    send_log "diff $tmpdir/$progname.out $srcdir/$subdir/static-bundle.dat\n"
+    verbose "diff $tmpdir/$progname.out $srcdir/$subdir/static-bundle.dat"
+    catch "exec diff $tmpdir/$progname.out $srcdir/$subdir/static-bundle.dat" exec_output
+    set exec_output [prune_warnings $exec_output]
+
+    if {![string match "" $exec_output]} then {
+	send_log "$exec_output\n"
+	verbose "$exec_output"
+	fail "$testname - test program output"
+	return
+    }
+
+    # Check that strip results align with expectations - direct bundle function
+    if {$expect_strip != [strip_symbol $strip "helper_get_value" $tmpdir/$progname.bundle.o]} then {
+	fail "$testname - stripping main symbol"
+	return
+    }
+
+    # Check that strip results align with expectations - helper bundle function
+    if {$expect_strip != [strip_symbol $strip "helper_get_inner_value" $tmpdir/$progname.bundle.o]} then {
+	fail "$testname - stripping helper symbol"
+	return
+    }
+
+    pass "$testname"
+}
+
+# Run the test with symbol visibility flags.
+set lib_cc_flags "-fvisibility=hidden"
+if { ![ld_compile "$CC_FOR_TARGET" $srcdir/$subdir/main.c $tmpdir/mainp.o]
+     || ![ld_compile "$CC_FOR_TARGET" $srcdir/$subdir/helper.c $tmpdir/helperp.o] } {
+    unsupported "static-bundle (program, symbol visibility hidden)"
+} else {
+    if { ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/lib_helper.c $tmpdir/lib_helperp.o]
+	 || ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/bundle1.c $tmpdir/bundle1p.o]
+	 || ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/bundle2.c $tmpdir/bundle2p.o] } {
+	unsupported "static-bundle (libraries, symbol visibility hidden)"
+    } else {
+	static_bundle_test bundlep "visibility" mainp.o helperp.o bundle1p.o bundle2p.o lib_helperp.o 1
+    }
+}
+
+# Run the test with symbol version script.
+if { ![ld_compile "$CC_FOR_TARGET" $srcdir/$subdir/main.c $tmpdir/mainp.o]
+     || ![ld_compile "$CC_FOR_TARGET" $srcdir/$subdir/helper.c $tmpdir/helperp.o] } {
+    unsupported "static-bundle (program, version script)"
+} else {
+    if { ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/lib_helper.c $tmpdir/lib_helperp.o]
+	 || ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/bundle1.c $tmpdir/bundle1p.o]
+	 || ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/bundle2.c $tmpdir/bundle2p.o] } {
+	unsupported "static-bundle (libraries, version script)"
+    } else {
+	static_bundle_test bundlep "version-script" mainp.o helperp.o bundle1p.o bundle2p.o lib_helperp.o 1 "--version-script=$srcdir/$subdir/version.map"
+    }
+}
+
+# Run the test with symbol version script and function sections.
+set lib_cc_flags "-fvisibility=hidden -ffunction-sections"
+if { ![ld_compile "$CC_FOR_TARGET" $srcdir/$subdir/main.c $tmpdir/mainp.o]
+     || ![ld_compile "$CC_FOR_TARGET" $srcdir/$subdir/helper.c $tmpdir/helperp.o] } {
+    unsupported "static-bundle (program, function sections)"
+} else {
+    if { ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/lib_helper.c $tmpdir/lib_helperp.o]
+	 || ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/bundle1.c $tmpdir/bundle1p.o]
+	 || ![ld_compile "$CC_FOR_TARGET $lib_cc_flags" $srcdir/$subdir/bundle2.c $tmpdir/bundle2p.o] } {
+	unsupported "static-bundle (libraries, function sections)"
+    } else {
+	static_bundle_test bundlep "function-sections" mainp.o helperp.o bundle1p.o bundle2p.o lib_helperp.o 0 "--version-script=$srcdir/$subdir/version.map"
+    }
+}
+
+set CFLAGS_FOR_TARGET_TEST "$old_CFLAGS"
diff --git a/ld/testsuite/ld-static-bundle/version.map b/ld/testsuite/ld-static-bundle/version.map
new file mode 100644
index 00000000000..2c5e032a8b7
--- /dev/null
+++ b/ld/testsuite/ld-static-bundle/version.map
@@ -0,0 +1,7 @@
+TEST_1 {
+     global:
+
+     lib_get_value;
+
+     local: *;
+};
\ No newline at end of file
-- 
2.31.1.windows.1



More information about the Binutils mailing list