[PATCH v3 13/18] PR ld/24600: LD: Add options to control mapless archive acceptance
Maciej W. Rozycki
macro@orcam.me.uk
Thu Nov 20 10:56:48 GMT 2025
From: Maciej W. Rozycki <macro@redhat.com>
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.
---
No change from v2 (11/16),
<https://inbox.sourceware.org/binutils/alpine.DEB.2.21.2511061530080.25436@angie.orcam.me.uk/>.
Changes from v1 (8/8),
<https://inbox.sourceware.org/binutils/alpine.DEB.2.21.2509262216050.63399@angie.orcam.me.uk/>:
- Update archive.exp for the lack of Alpha/VMS mapless archive support.
- Update archive.exp and abc.ed for the removal of abct.ed.
- Update archive.exp with new test XFAIL annotation for CRIS and NS32k
targets as required.
---
bfd/archive.c | 6 +++
bfd/bfd-in2.h | 15 ++++++++
bfd/bfd.c | 17 ++++++++-
bfd/xcofflink.c | 5 ++
ld/NEWS | 4 ++
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, 143 insertions(+), 6 deletions(-)
binutils-ld-ar-noindex.diff
Index: binutils-gdb/bfd/archive.c
===================================================================
--- binutils-gdb.orig/bfd/archive.c
+++ binutils-gdb/bfd/archive.c
@@ -1027,6 +1027,12 @@ _bfd_make_armap (bfd *abfd, bfd *first_o
bfd **last_one;
bfd *next_one;
+ if (!bfd_link_mapless (abfd))
+ {
+ bfd_set_error (bfd_error_no_armap);
+ return false;
+ }
+
last_one = &(abfd->archive_next);
for (next_one = first_one;
next_one;
Index: binutils-gdb/bfd/bfd-in2.h
===================================================================
--- binutils-gdb.orig/bfd/bfd-in2.h
+++ binutils-gdb/bfd/bfd-in2.h
@@ -2137,6 +2137,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;
@@ -2378,6 +2381,12 @@ bfd_has_map (const bfd *abfd)
}
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;
@@ -2398,6 +2407,12 @@ bfd_set_cacheable (bfd * abfd, bool val)
}
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;
Index: binutils-gdb/bfd/bfd.c
===================================================================
--- binutils-gdb.orig/bfd/bfd.c
+++ binutils-gdb/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"),
Index: binutils-gdb/bfd/xcofflink.c
===================================================================
--- binutils-gdb.orig/bfd/xcofflink.c
+++ binutils-gdb/bfd/xcofflink.c
@@ -2612,6 +2612,11 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *ab
(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;
Index: binutils-gdb/ld/NEWS
===================================================================
--- binutils-gdb.orig/ld/NEWS
+++ binutils-gdb/ld/NEWS
@@ -1,5 +1,9 @@
-*- text -*-
+* 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.
+
* Add --gnu-tls-tag/--no-gnu-tls-tag options to i386 ELF linker to add
the GLIBC_ABI_GNU_TLS version dependency in output if input object
files call ___tls_get_addr. Also added --enable-gnu-tls-tag configure
Index: binutils-gdb/ld/ld.texi
===================================================================
--- binutils-gdb.orig/ld/ld.texi
+++ binutils-gdb/ld/ld.texi
@@ -1069,7 +1069,8 @@ restored with one corresponding @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 o
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
@@ -3182,6 +3189,12 @@ Second, don't forget to use @option{-Wl,
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
Index: binutils-gdb/ld/ldlang.c
===================================================================
--- binutils-gdb.orig/ld/ldlang.c
+++ binutils-gdb/ld/ldlang.c
@@ -1225,6 +1225,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;
@@ -3195,6 +3196,7 @@ load_symbols (lang_input_statement_type
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)
{
Index: binutils-gdb/ld/ldlang.h
===================================================================
--- binutils-gdb.orig/ld/ldlang.h
+++ binutils-gdb/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;
Index: binutils-gdb/ld/ldlex.h
===================================================================
--- binutils-gdb.orig/ld/ldlex.h
+++ binutils-gdb/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,
Index: binutils-gdb/ld/ldmain.c
===================================================================
--- binutils-gdb.orig/ld/ldmain.c
+++ binutils-gdb/ld/ldmain.c
@@ -705,6 +705,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);
Index: binutils-gdb/ld/lexsup.c
===================================================================
--- binutils-gdb.orig/ld/lexsup.c
+++ binutils-gdb/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;
Index: binutils-gdb/ld/testsuite/ld-archive/abc.ed
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-archive/abc.ed
+++ binutils-gdb/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
Index: binutils-gdb/ld/testsuite/ld-archive/archive.exp
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-archive/archive.exp
+++ binutils-gdb/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
mailing list