[binutils-gdb] Add a "-O 0" option to the linker for a faster, but less effective link.

Nick Clifton via Binutils-cvs <[email protected]>
Newsgroups gmane.comp.gnu.binutils.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4fe7dd9a10d15928834d8a20ec91f2b1436c8108

commit 4fe7dd9a10d15928834d8a20ec91f2b1436c8108
Author: Nick Clifton <[email protected]>
Date:   Mon Apr 13 09:32:09 2026 +0100

    Add a "-O 0" option to the linker for a faster, but less effective link.

Diff:
---
 include/bfdlink.h              |  7 ++++++-
 ld/NEWS                        |  5 +++++
 ld/ld.texi                     | 10 ++++++++++
 ld/ldlang.c                    | 19 +++++++++++--------
 ld/lexsup.c                    | 20 +++++++++++++++++++-
 ld/testsuite/ld-elf/merge5.a.s |  4 ++++
 ld/testsuite/ld-elf/merge5.b.s |  4 ++++
 ld/testsuite/ld-elf/merge5.d   | 10 ++++++++++
 8 files changed, 69 insertions(+), 10 deletions(-)

diff --git a/include/bfdlink.h b/include/bfdlink.h
index eac72b8c388..a412f9c241a 100644
--- a/include/bfdlink.h
+++ b/include/bfdlink.h
@@ -551,10 +551,15 @@ struct bfd_link_info
      an executable stack.  */
   unsigned int default_execstack : 1;
   
-  /* TRUE if we want to produced optimized output files.  This might
+  /* TRUE if we want to produce optimized output files.  This might
      need much more time and therefore must be explicitly selected.  */
   unsigned int optimize: 1;
 
+  /* TRUE if we want to skip optional steps during linking.  This can
+     include section merging for example.  This is effectively the opposite
+     of the 'optimize' field, and both should not be TRUE at the same time.  */
+  unsigned int skip_optional: 1;
+
   /* TRUE if user should be informed of removed unreferenced sections.  */
   unsigned int print_gc_sections: 1;
 
diff --git a/ld/NEWS b/ld/NEWS
index c4f89fd389f..aa7a9251821 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,10 @@
 -*- text -*-
 
+* Add a linker optimization level of zero.  Using "-O 0" on the linker command
+  line will stop it from combining the contents of mergeable sections.  This
+  can significantly speed up the link process at the cost of producing larger
+  binaries.
+
 Changes in 2.47:
 
 * Add linker support for --start-lib/--end-lib options and LIB linker script
diff --git a/ld/ld.texi b/ld/ld.texi
index 90d19c27d57..273c80b356b 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1043,6 +1043,16 @@ the linker may make more use of this option.  Also currently there is
 no difference in the linker's behaviour for different non-zero values
 of this option.  Again this may change with future releases.
 
+If @var{level} is zero or the string @samp{fast} then @command{ld}
+instead skips operations that are optional, resulting in a faster link
+but producing slower, larger binaries.  Currently the only operation
+that is skipped is the combining of mergeable sections, but this may
+change in the future.
+
+If @var{level} is the string @samp{default} or just the @samp{-}
+character then the linker's default behaviour of neither optimizing
+nor skipping operations is selected.
+
 @kindex -plugin @var{name}
 @item -plugin @var{name}
 Involve a plugin in the linking process.  The @var{name} parameter is
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 656edeb4981..98adc90e58a 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -8820,16 +8820,19 @@ lang_process (void)
     {
       asection *found;
 
-      ld_start_phase (PHASE_MERGE);
+      if (! link_info.skip_optional)
+	{
+	  ld_start_phase (PHASE_MERGE);
 
-      /* Merge SEC_MERGE sections.  This has to be done after GC of
-	 sections, so that GCed sections are not merged, but before
-	 assigning dynamic symbols, since removing whole input sections
-	 is hard then.  */
-      if (!bfd_merge_sections (link_info.output_bfd, &link_info))
-	fatal (_("%P: bfd_merge_sections failed: %E\n"));
+	  /* Merge SEC_MERGE sections.  This has to be done after GC of
+	     sections, so that GCed sections are not merged, but before
+	     assigning dynamic symbols, since removing whole input sections
+	     is hard then.  */
+	  if (!bfd_merge_sections (link_info.output_bfd, &link_info))
+	    fatal (_("%P: bfd_merge_sections failed: %E\n"));
 
-      ld_stop_phase (PHASE_MERGE);
+	  ld_stop_phase (PHASE_MERGE);
+	}
 
       /* Look for a text section and set the readonly attribute in it.  */
       found = bfd_get_section_by_name (link_info.output_bfd, ".text");
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 4e89feffb09..a55b0e81b2f 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -177,7 +177,7 @@ static const struct ld_option ld_options[] =
   { {"output", required_argument, NULL, 'o'},
     'o', N_("FILE"), N_("Set output file name"), EXACTLY_TWO_DASHES },
   { {NULL, required_argument, NULL, '\0'},
-    'O', NULL, N_("Optimize output file"), ONE_DASH },
+    'O', N_("LEVEL"), N_("Optimize output file"), ONE_DASH },
   { {"out-implib", required_argument, NULL, OPTION_OUT_IMPLIB},
     '\0', N_("FILE"), N_("Generate import library"), TWO_DASHES },
   { {"plugin", required_argument, NULL, OPTION_PLUGIN},
@@ -1211,6 +1211,24 @@ parse_args (unsigned argc, char **argv)
 
 	  /* Enable optimizations of output files.  */
 	  link_info.optimize = strtoul (optarg, NULL, 0) != 0;
+	  if (link_info.optimize == 0)
+	    {
+	      /* "-O -" or "-O default" means restore the linker's default behaviour.  */
+	      if ((optarg[0] == '-' && optarg[1] == 0) || strcmp (optarg, "default") == 0)
+		{
+		  link_info.optimize = link_info.skip_optional = 0;
+		}
+	      /* "-O 0" or "-O fast" means disable optimizations and skip optional features.  */
+	      else if ((optarg[0] == '0' && optarg[1] == 0) || strcmp (optarg, "fast") == 0)
+		{
+		  link_info.optimize = 0;
+		  link_info.skip_optional = 1;
+		}
+	      else
+		fatal (_("%P: -O requires a numerical argument or '-' or 'fast' or 'default'"));
+	    }
+	  else
+	    link_info.skip_optional = 0;
 	  break;
 	case 'o':
 	  lang_add_output (optarg, 0);
diff --git a/ld/testsuite/ld-elf/merge5.a.s b/ld/testsuite/ld-elf/merge5.a.s
new file mode 100644
index 00000000000..8fe6a6967f2
--- /dev/null
+++ b/ld/testsuite/ld-elf/merge5.a.s
@@ -0,0 +1,4 @@
+.section .rodata.str,"aMS","progbits",1 
+.global .merge1
+.merge1: 
+	.asciz "abc" 
diff --git a/ld/testsuite/ld-elf/merge5.b.s b/ld/testsuite/ld-elf/merge5.b.s
new file mode 100644
index 00000000000..79ac2fc4e6c
--- /dev/null
+++ b/ld/testsuite/ld-elf/merge5.b.s
@@ -0,0 +1,4 @@
+.section .rodata.str,"aMS","progbits",1 
+.global .merge2
+.merge2: 
+	.asciz "abc" 
diff --git a/ld/testsuite/ld-elf/merge5.d b/ld/testsuite/ld-elf/merge5.d
new file mode 100644
index 00000000000..38c6754670c
--- /dev/null
+++ b/ld/testsuite/ld-elf/merge5.d
@@ -0,0 +1,10 @@
+# Checks to see that linking with "-O 0" does not merge strings.
+# The various other -O options are there just to make sure that the parser handles them.
+#source: merge5.a.s
+#source: merge5.b.s
+#ld: -T merge.ld -O 2 -O - -O 99 -O default -O fast -O 0
+#nm: -s
+
+0+1100 R .merge1
+0+1104 R .merge2
+#pass
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.