]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Add a "-O 0" option to the linker for a faster, but less effective link.
authorNick Clifton <nickc@redhat.com>
Mon, 13 Apr 2026 08:32:09 +0000 (09:32 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 13 Apr 2026 08:32:09 +0000 (09:32 +0100)
include/bfdlink.h
ld/NEWS
ld/ld.texi
ld/ldlang.c
ld/lexsup.c
ld/testsuite/ld-elf/merge5.a.s [new file with mode: 0644]
ld/testsuite/ld-elf/merge5.b.s [new file with mode: 0644]
ld/testsuite/ld-elf/merge5.d [new file with mode: 0644]

index eac72b8c3885ff1ac996eead9e00bcf87ea7e7fe..a412f9c241a52cac731cc35f87e57b02b9054ab3 100644 (file)
@@ -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 c4f89fd389f68789e2c2eafd45ed521e7e5009c1..aa7a92518217fcd0dc6367ba7c1c39bc37351a91 100644 (file)
--- 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
index 90d19c27d57cf1845e8a183fe3c794c19a42d4c8..273c80b356bffa7e3ad47a289e82b77ece90d535 100644 (file)
@@ -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
index 656edeb4981442cf3eb7f93bdbfaff323dbbecc7..98adc90e58a2e1ef8d78986ddb749db43e2ef6e4 100644 (file)
@@ -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");
index 4e89feffb095e151e34c3351a9566cb512be30e2..a55b0e81b2fe4b4711e8f124f18533bdbbc2f28f 100644 (file)
@@ -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 (file)
index 0000000..8fe6a69
--- /dev/null
@@ -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 (file)
index 0000000..79ac2fc
--- /dev/null
@@ -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 (file)
index 0000000..38c6754
--- /dev/null
@@ -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