From: Nick Clifton Date: Mon, 13 Apr 2026 08:32:09 +0000 (+0100) Subject: Add a "-O 0" option to the linker for a faster, but less effective link. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4fe7dd9a10d15928834d8a20ec91f2b1436c8108;p=thirdparty%2Fbinutils-gdb.git Add a "-O 0" option to the linker for a faster, but less effective link. --- 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