[PATCH 8/8] PR ld/24600: LD: Add options to control mapless archive acceptance
Maciej W. Rozycki
macro@orcam.me.uk
Fri Sep 26 23:54:01 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.
---
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/abct.ed | 2 -
ld/testsuite/ld-archive/archive.exp | 48 ++++++++++++++++++++++++++++++++++--
14 files changed, 128 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
@@ -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;
@@ -2371,6 +2374,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;
@@ -2391,6 +2400,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
+[^\n]*: tmpdir/abn.a: error adding symbols: archive has no index; run ranlib to add one or use --link-mapless
Index: binutils-gdb/ld/testsuite/ld-archive/abct.ed
===================================================================
--- binutils-gdb.orig/ld/testsuite/ld-archive/abct.ed
+++ binutils-gdb/ld/testsuite/ld-archive/abct.ed
@@ -1 +1 @@
-[^\n]*: tmpdir/abnt.a: error adding symbols: archive has no index; run ranlib to add one
+[^\n]*: tmpdir/abnt.a: 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
@@ -98,7 +98,19 @@ run_ld_link_tests [list \
[expr { [istarget "*-*-msdos"] ? {} : {{nm "" abcde.nd}} }] \
"abtcdte" \
] \
- [list "Regular archive w/o index link" \
+ [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 abct.ed}} \
+ "abntc" \
+ ] \
+ [list "Regular archive w/o index link accept" \
"-e ff" "tmpdir/abn.a" \
"" {abc.s} \
[expr { [istarget "*-*-msdos"] ? {} : {{nm "" abc.nd}} }] \
@@ -107,12 +119,44 @@ run_ld_link_tests [list \
]
setup_kfail "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} \
[expr { [istarget "*-*-msdos"] ? {} : {{nm "" abc.nd}} }] \
"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 abct.ed}} \
+ "abntcde" \
+ ] \
+]
+setup_kfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+setup_kfail "binutils/33485" "i\[3-7\]86-*-bsd*" "i\[3-7\]86-*-msdos*" \
+ "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} \
+ [expr { [istarget "*-*-msdos"] ? {} : {{nm "" abcde.nd}} }] \
+ "abncdte" \
+ ] \
+]
+setup_kfail "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} \
+ [expr { [istarget "*-*-msdos"] ? {} : {{nm "" abcde.nd}} }] \
+ "abntcde" \
+ ] \
]
set LDFLAGS $old_ldflags
More information about the Binutils
mailing list