[binutils-gdb] PR ld/24600: LD: Add options to control mapless archive acceptance
Maciej W. Rozycki
macro@sourceware.org
Fri Feb 20 17:42:53 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=6cbaeac8401cdab4308bafb14a8b3498bd6427bc
commit 6cbaeac8401cdab4308bafb14a8b3498bd6427bc
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Fri Feb 20 17:29:50 2026 +0000
PR ld/24600: LD: Add options to control mapless archive acceptance
Add `--link-mapless' and `--no-link-mapless' LD command-line options, to
respectively enable and disable the acceptance of mapless archives on a
per-file basis, also with XCOFF targets, enabled by default. Update
documentation and add test cases accordingly.
Diff:
---
bfd/archive.c | 6 ++++
bfd/bfd-in2.h | 15 +++++++++
bfd/bfd.c | 17 +++++++++-
bfd/xcofflink.c | 5 +++
ld/NEWS | 6 ++++
ld/ld.texi | 15 ++++++++-
ld/ldlang.c | 2 ++
ld/ldlang.h | 3 ++
ld/ldlex.h | 2 ++
ld/ldmain.c | 2 ++
ld/lexsup.c | 11 +++++++
ld/testsuite/ld-archive/abc.ed | 2 +-
ld/testsuite/ld-archive/archive.exp | 65 +++++++++++++++++++++++++++++++++++--
13 files changed, 145 insertions(+), 6 deletions(-)
diff --git a/bfd/archive.c b/bfd/archive.c
index f26d70fcd42..85b7107938a 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -1046,6 +1046,12 @@ _bfd_make_armap (bfd *arch, bfd *first_one)
bfd **last_one;
bfd *next_one;
+ if (!bfd_link_mapless (arch))
+ {
+ bfd_set_error (bfd_error_no_armap);
+ return false;
+ }
+
last_one = &(arch->archive_next);
for (next_one = first_one;
next_one;
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 8f55c1eb077..0aad6a903e4 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -2130,6 +2130,9 @@ struct bfd
/* Have archive map. */
unsigned int has_armap : 1;
+ /* Accept a mapless archive for link. */
+ unsigned int link_mapless : 1;
+
/* Set if this is a thin archive. */
unsigned int is_thin_archive : 1;
@@ -2370,6 +2373,12 @@ bfd_has_map (const bfd *abfd)
return abfd->has_armap;
}
+static inline bool
+bfd_link_mapless (const bfd *abfd)
+{
+ return abfd->link_mapless;
+}
+
static inline bool
bfd_is_thin_archive (const bfd *abfd)
{
@@ -2390,6 +2399,12 @@ bfd_set_cacheable (bfd * abfd, bool val)
return true;
}
+static inline void
+bfd_set_link_mapless (bfd *abfd, bool val)
+{
+ abfd->link_mapless = val;
+}
+
static inline void
bfd_set_thin_archive (bfd *abfd, bool val)
{
diff --git a/bfd/bfd.c b/bfd/bfd.c
index 35669075da2..27c43ad3d85 100644
--- a/bfd/bfd.c
+++ b/bfd/bfd.c
@@ -280,6 +280,9 @@ CODE_FRAGMENT
. {* Have archive map. *}
. unsigned int has_armap : 1;
.
+. {* Accept a mapless archive for link. *}
+. unsigned int link_mapless : 1;
+.
. {* Set if this is a thin archive. *}
. unsigned int is_thin_archive : 1;
.
@@ -523,6 +526,12 @@ EXTERNAL
.}
.
.static inline bool
+.bfd_link_mapless (const bfd *abfd)
+.{
+. return abfd->link_mapless;
+.}
+.
+.static inline bool
.bfd_is_thin_archive (const bfd *abfd)
.{
. return abfd->is_thin_archive;
@@ -543,6 +552,12 @@ EXTERNAL
.}
.
.static inline void
+.bfd_set_link_mapless (bfd *abfd, bool val)
+.{
+. abfd->link_mapless = val;
+.}
+.
+.static inline void
.bfd_set_thin_archive (bfd *abfd, bool val)
.{
. abfd->is_thin_archive = val;
@@ -798,7 +813,7 @@ const char *const bfd_errmsgs[] =
N_("invalid operation"),
N_("memory exhausted"),
N_("no symbols"),
- N_("archive has no index; run ranlib to add one"),
+ N_("archive has no index; run ranlib to add one or use --link-mapless"),
N_("no more archived files"),
N_("malformed archive"),
N_("DSO missing from command line"),
diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
index 691acc854ae..fde21c9f958 100644
--- a/bfd/xcofflink.c
+++ b/bfd/xcofflink.c
@@ -2612,6 +2612,11 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
(abfd, info, xcoff_link_check_archive_element)))
return false;
}
+ else if (!bfd_link_mapless (abfd))
+ {
+ bfd_set_error (bfd_error_no_armap);
+ return false;
+ }
{
bfd *member;
diff --git a/ld/NEWS b/ld/NEWS
index 3be78507245..9c9896d950a 100644
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,11 @@
-*- text -*-
+Changes in 2.47:
+
+* Add linker support for archives with no symbol index in their all formats,
+ not only XCOFF. On by default and controlled with --no-link-mapless and
+ --link-mapless options, also for XCOFF.
+
Changes in 2.46:
* Add --gnu-tls-tag/--no-gnu-tls-tag options to i386 ELF linker to add
diff --git a/ld/ld.texi b/ld/ld.texi
index 3dc76a1f8c6..13aef27612f 100644
--- a/ld/ld.texi
+++ b/ld/ld.texi
@@ -1069,7 +1069,8 @@ restored with one corresponding @option{--pop-state} option.
The option which are covered are: @option{-Bdynamic}, @option{-Bstatic},
@option{-dn}, @option{-dy}, @option{-call_shared}, @option{-non_shared},
@option{-static}, @option{-N}, @option{-n}, @option{--whole-archive},
-@option{--no-whole-archive}, @option{-r}, @option{-Ur},
+@option{--no-whole-archive}, @option{--link-mapless},
+@option{--no-link-mapless}, @option{-r}, @option{-Ur},
@option{--copy-dt-needed-entries}, @option{--no-copy-dt-needed-entries},
@option{--as-needed}, @option{--no-as-needed}, and @option{-a}.
@@ -2373,6 +2374,12 @@ library during a library search. This option silences the warning.
Turn off the effect of the @option{--whole-archive} option for subsequent
archive files.
+@kindex --no-link-mapless
+@item --no-link-mapless
+Reject archives that lack an index aka symbol map for all the subsequent
+archives referred on the command line. If such a file is encountered,
+a link error occurs. This is the traditional behavior.
+
@cindex output file after errors
@kindex --noinhibit-exec
@item --noinhibit-exec
@@ -3186,6 +3193,12 @@ Second, don't forget to use @option{-Wl,-no-whole-archive} after your
list of archives, because gcc will add its own list of archives to
your link and you may not want this flag to affect those as well.
+@kindex --link-mapless
+@item --link-mapless
+Accept archives that lack an index aka symbol map for all the subsequent
+archives referred on the command line. If missing, such an index is made
+internally on the fly at performance cost. This is the default.
+
@kindex --wrap=@var{symbol}
@item --wrap=@var{symbol}
Use a wrapper function for @var{symbol}. Any undefined reference to
diff --git a/ld/ldlang.c b/ld/ldlang.c
index 5ce8c754eac..9f748f38ed6 100644
--- a/ld/ldlang.c
+++ b/ld/ldlang.c
@@ -1209,6 +1209,7 @@ new_afile (const char *name,
p->flags.add_DT_NEEDED_for_dynamic = input_flags.add_DT_NEEDED_for_dynamic;
p->flags.add_DT_NEEDED_for_regular = input_flags.add_DT_NEEDED_for_regular;
p->flags.whole_archive = input_flags.whole_archive;
+ p->flags.link_mapless = input_flags.link_mapless;
p->flags.sysrooted = input_flags.sysrooted;
p->sort_key = NULL;
@@ -3203,6 +3204,7 @@ load_symbols (lang_input_statement_type *entry,
case bfd_archive:
check_excluded_libs (entry->the_bfd);
+ bfd_set_link_mapless (entry->the_bfd, entry->flags.link_mapless);
bfd_set_usrdata (entry->the_bfd, entry);
if (entry->flags.whole_archive)
{
diff --git a/ld/ldlang.h b/ld/ldlang.h
index c3ee40a980c..70b91941817 100644
--- a/ld/ldlang.h
+++ b/ld/ldlang.h
@@ -276,6 +276,9 @@ struct lang_input_statement_flags
/* Whether to include the entire contents of an archive. */
unsigned int whole_archive : 1;
+ /* Whether to accept archives without a symbol map. */
+ unsigned int link_mapless : 1;
+
/* Set when bfd opening is successful. */
unsigned int loaded : 1;
diff --git a/ld/ldlex.h b/ld/ldlex.h
index 85e06b6fcc4..86718087ed5 100644
--- a/ld/ldlex.h
+++ b/ld/ldlex.h
@@ -52,6 +52,7 @@ enum option_values
OPTION_NOINHIBIT_EXEC,
OPTION_NON_SHARED,
OPTION_NO_WHOLE_ARCHIVE,
+ OPTION_NO_LINK_MAPLESS,
OPTION_OFORMAT,
OPTION_RELAX,
OPTION_NO_RELAX,
@@ -98,6 +99,7 @@ enum option_values
OPTION_SPLIT_BY_RELOC,
OPTION_SPLIT_BY_FILE ,
OPTION_WHOLE_ARCHIVE,
+ OPTION_LINK_MAPLESS,
OPTION_ADD_DT_NEEDED_FOR_DYNAMIC,
OPTION_NO_ADD_DT_NEEDED_FOR_DYNAMIC,
OPTION_ADD_DT_NEEDED_FOR_REGULAR,
diff --git a/ld/ldmain.c b/ld/ldmain.c
index afbf039b1e2..77b167fd642 100644
--- a/ld/ldmain.c
+++ b/ld/ldmain.c
@@ -799,6 +799,8 @@ main (int argc, char **argv)
link_info.start_stop_gc = false;
link_info.start_stop_visibility = STV_PROTECTED;
+ input_flags.link_mapless = true;
+
ldfile_add_arch ("");
emulation = get_emulation (argc, argv);
ldemul_choose_mode (emulation);
diff --git a/ld/lexsup.c b/ld/lexsup.c
index 158abb6dd8f..d93e8b4ca77 100644
--- a/ld/lexsup.c
+++ b/ld/lexsup.c
@@ -421,6 +421,8 @@ static const struct ld_option ld_options[] =
TWO_DASHES},
{ {"no-whole-archive", no_argument, NULL, OPTION_NO_WHOLE_ARCHIVE},
'\0', NULL, N_("Turn off --whole-archive"), TWO_DASHES },
+ { {"no-link-mapless", no_argument, NULL, OPTION_NO_LINK_MAPLESS},
+ '\0', NULL, N_("Reject archives without a symbol map"), TWO_DASHES },
{ {"noinhibit-exec", no_argument, NULL, OPTION_NOINHIBIT_EXEC},
'\0', NULL, N_("Create an output file even if errors occur"),
TWO_DASHES },
@@ -602,6 +604,9 @@ static const struct ld_option ld_options[] =
{ {"whole-archive", no_argument, NULL, OPTION_WHOLE_ARCHIVE},
'\0', NULL, N_("Include all objects from following archives"),
TWO_DASHES },
+ { {"link-mapless", no_argument, NULL, OPTION_LINK_MAPLESS},
+ '\0', NULL, N_("Accept archives without a symbol map"),
+ TWO_DASHES },
{ {"wrap", required_argument, NULL, OPTION_WRAP},
'\0', N_("SYMBOL"), N_("Use wrapper functions for SYMBOL"), TWO_DASHES },
{ {"ignore-unresolved-symbol", required_argument, NULL,
@@ -1177,6 +1182,9 @@ parse_args (unsigned argc, char **argv)
case OPTION_NO_WHOLE_ARCHIVE:
input_flags.whole_archive = false;
break;
+ case OPTION_NO_LINK_MAPLESS:
+ input_flags.link_mapless = false;
+ break;
case 'O':
/* FIXME "-O<non-digits> <value>" used to set the address of
section <non-digits>. Was this for compatibility with
@@ -1657,6 +1665,9 @@ parse_args (unsigned argc, char **argv)
case OPTION_WHOLE_ARCHIVE:
input_flags.whole_archive = true;
break;
+ case OPTION_LINK_MAPLESS:
+ input_flags.link_mapless = true;
+ break;
case OPTION_ADD_DT_NEEDED_FOR_DYNAMIC:
input_flags.add_DT_NEEDED_for_dynamic = true;
break;
diff --git a/ld/testsuite/ld-archive/abc.ed b/ld/testsuite/ld-archive/abc.ed
index 10a696e755e..fecdb767445 100644
--- a/ld/testsuite/ld-archive/abc.ed
+++ b/ld/testsuite/ld-archive/abc.ed
@@ -1 +1 @@
-[^\n]*: tmpdir/abn.a: error adding symbols: archive has no index; run ranlib to add one
+.*: error adding symbols: archive has no index; run ranlib to add one or use --link-mapless
diff --git a/ld/testsuite/ld-archive/archive.exp b/ld/testsuite/ld-archive/archive.exp
index 73742cfb560..f77c449a4f1 100644
--- a/ld/testsuite/ld-archive/archive.exp
+++ b/ld/testsuite/ld-archive/archive.exp
@@ -230,9 +230,9 @@ run_ld_link_tests [list \
] \
]
-# Single non-index archive tests.
+# Single non-index archive accept tests.
run_ld_link_tests [list \
- [list "Regular archive w/o index link" \
+ [list "Regular archive w/o index link accept" \
"-e ff" "tmpdir/abn.a" \
"" {abc.s} \
[ld_archive_filter_tests {{nm "" abc.nd} \
@@ -242,7 +242,7 @@ run_ld_link_tests [list \
]
setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
run_ld_link_tests [list \
- [list "Thin archive w/o index link" \
+ [list "Thin archive w/o index link accept" \
"-e ff" "tmpdir/abnt.a" \
"" {abc.s} \
[ld_archive_filter_tests {{nm "" abc.nd} \
@@ -251,6 +251,32 @@ run_ld_link_tests [list \
] \
]
+# Dual non-index archive accept tests.
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+setup_xfail "binutils/33485" "cris-*-*aout*" "i\[3-7\]86-*-bsd*" \
+ "i\[3-7\]86-*-msdos*" "ns32k-*-*" "pdp11-*-*"
+run_ld_link_tests [list \
+ [list "Regular archive w/o index plus thin link accept" \
+ "-e ff" "--no-link-mapless tmpdir/cdt.a --link-mapless tmpdir/abn.a" \
+ "" {abcde.s} \
+ [ld_archive_filter_tests {{nm "" abcde.nd} \
+ {nm "" nx.nd} \
+ {nm "" ny.nd}}] \
+ "abncdte" \
+ ] \
+]
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+run_ld_link_tests [list \
+ [list "Thin archive w/o index plus regular link accept" \
+ "-e ff" "--no-link-mapless tmpdir/cd.a --link-mapless tmpdir/abnt.a" \
+ "" {abcde.s} \
+ [ld_archive_filter_tests {{nm "" abcde.nd} \
+ {nm "" nx.nd} \
+ {nm "" ny.nd}}] \
+ "abntcde" \
+ ] \
+]
+
# Group non-index archive tests.
run_ld_link_tests [list \
[list "Regular non-group archive w/o index link reject" \
@@ -292,3 +318,36 @@ run_ld_link_tests [list \
]
set LDFLAGS $old_ldflags
+
+# Alpha/VMS archives always have an index; we're done with the tests.
+if { [istarget "alpha*-*-*vms*"] } {
+ return
+}
+
+# Non-index archive reject tests.
+run_ld_link_tests [list \
+ [list "Regular archive w/o index link reject" \
+ "-e ff" "--no-link-mapless tmpdir/abn.a" \
+ "" {abc.s} \
+ {{ld abc.ed}} \
+ "abnc" \
+ ] \
+ [list "Thin archive w/o index link reject" \
+ "-e ff" "--no-link-mapless tmpdir/abnt.a" \
+ "" {abc.s} \
+ {{ld abc.ed}} \
+ "abntc" \
+ ] \
+ [list "Regular archive w/o index plus thin link reject" \
+ "-e ff" "--no-link-mapless tmpdir/abn.a --link-mapless tmpdir/cdt.a" \
+ "" {abcde.s} \
+ {{ld abc.ed}} \
+ "abncdte" \
+ ] \
+ [list "Thin archive w/o index plus regular link reject" \
+ "-e ff" "--no-link-mapless tmpdir/abnt.a --link-mapless tmpdir/cd.a" \
+ "" {abcde.s} \
+ {{ld abc.ed}} \
+ "abntcde" \
+ ] \
+]
More information about the Binutils-cvs
mailing list