aboutsummaryrefslogtreecommitdiff
path: root/ld
diff options
context:
space:
mode:
Diffstat (limited to 'ld')
-rw-r--r--ld/NEWS5
-rw-r--r--ld/ld.texi10
-rw-r--r--ld/ldlang.c19
-rw-r--r--ld/lexsup.c20
-rw-r--r--ld/testsuite/ld-elf/merge5.a.s4
-rw-r--r--ld/testsuite/ld-elf/merge5.b.s4
-rw-r--r--ld/testsuite/ld-elf/merge5.d10
7 files changed, 63 insertions, 9 deletions
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