[binutils-gdb] PR ld/24600: BFD: Add general linker support for mapless archives
Maciej W. Rozycki
macro@sourceware.org
Fri Feb 20 17:42:42 GMT 2026
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=e34fd4bfa6d748c05786850ef410eb1bd0ae4c22
commit e34fd4bfa6d748c05786850ef410eb1bd0ae4c22
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Fri Feb 20 17:29:50 2026 +0000
PR ld/24600: BFD: Add general linker support for mapless archives
Expand linker mapless archive support from XCOFF targets only across the
remaining ones, except for VMS targets whose archive format always has a
symbol map. For this tranform BFD code used by AR to produce symbol
maps to archive files such as to have a handler supplied to either write
a map to a file or convert symbol data to an archive symbol definition
table attached to an archive BFD as if read from a symbol map, but using
pointers to member BFDs rather than file offsets. Retain XCOFF handling
code as it is.
Where the archive group feature is used a given archive may be opened
multiple times in a single link. If this happens then a reference to a
symbol the definition of which is provided by said archive will change
from undefined on the first access to the archive to defined on later
accesses. The symbol table is pulled from an archive only for undefined
references, so if a symbol table has been pulled on first access and
then dropped by on-the-fly symbol map generation on a subsequent access,
then the symbol table is never re-read. Later on when the linker wants
to access it to actually resolve symbol references it won't have been
reloaded and a crash would happen on a null pointer dereference.
To prevent this from happening add code to `_bfd_compute_and_push_armap'
to let the caller request the symbol table to be retained and ask for it
when building a symbol map on the fly in the linker. The symbol table
will likely be used further down the link anyway.
Additionally always check the format of the first member of an archive,
even if no symbol map is present, and respect the format determined, so
that the correct format is used even if it is not the default one the LD
has been configured for, preventing segmentation faults from triggering
in `cris-aout' LD with the default (`crisaout') emulation or with the
`criself' emulation explicitly requested where archive members are in
the ELF format and consequntly removing failures with new tests:
cris-aout -FAIL: CRIS regular archive w/o index link (explicit emulation)
cris-aout -FAIL: CRIS regular archive w/o index link (implicit emulation)
cris-aout -FAIL: CRIS thin archive w/o index link (explicit emulation)
cris-aout -FAIL: CRIS thin archive w/o index link (implicit emulation)
Update documentation and adjust test cases accordingly now that mapless
archives are accepted for link by all targets except for VMS ones, which
never produce them in the first place.
Diff:
---
bfd/archive.c | 153 +++++++++++++++++++++++++++++++-----
bfd/coff-alpha.c | 5 +-
bfd/coff-rs6000.c | 6 +-
bfd/ecoff.c | 9 ++-
bfd/elflink.c | 24 +++---
bfd/format.c | 11 +--
bfd/libbfd-in.h | 24 +++++-
bfd/libbfd.h | 44 ++++++++++-
bfd/linker.c | 22 +++---
binutils/doc/binutils.texi | 16 ++--
ld/testsuite/ld-archive/abct.ed | 1 -
ld/testsuite/ld-archive/abncng.vd | 28 +++++++
ld/testsuite/ld-archive/abntcntg.vd | 28 +++++++
ld/testsuite/ld-archive/archive.exp | 61 +++++++++++---
ld/testsuite/ld-cris/archive.exp | 32 ++++++++
15 files changed, 382 insertions(+), 82 deletions(-)
diff --git a/bfd/archive.c b/bfd/archive.c
index c962bd25787..f26d70fcd42 100644
--- a/bfd/archive.c
+++ b/bfd/archive.c
@@ -179,6 +179,26 @@ INTERNAL
. int namidx; {* Index into string table. *}
.};
.
+.{* Return an inexistent element reference for archive ARCH. *}
+.
+.static inline ufile_ptr_or_bfd
+._bfd_elt_nil (bfd *arch)
+.{
+. return (bfd_ardata (arch)->symdef_use_bfd
+. ? (ufile_ptr_or_bfd) { .abfd = NULL }
+. : (ufile_ptr_or_bfd) { .file_offset = -1 });
+.}
+.
+.{* Tell if ELTREF1 and ELTREF2 refer the same element of archive ARCH. *}
+.
+.static inline bool
+._bfd_elt_eq (bfd *arch, ufile_ptr_or_bfd eltref1, ufile_ptr_or_bfd eltref2)
+.{
+. return (bfd_ardata (arch)->symdef_use_bfd
+. ? eltref1.abfd == eltref2.abfd
+. : eltref1.file_offset == eltref2.file_offset);
+.}
+.
*/
/* We keep a cache of archive filepointers to archive elements to
@@ -811,7 +831,7 @@ _bfd_generic_get_elt_at_index (bfd *abfd, symindex sym_index)
carsym *entry;
entry = bfd_ardata (abfd)->symdefs + sym_index;
- return _bfd_get_elt_at_filepos (abfd, entry->u.file_offset, NULL);
+ return _bfd_get_elt_from_symdef (abfd, entry, NULL);
}
bfd *
@@ -928,17 +948,15 @@ bfd_generic_archive_p (bfd *abfd)
return NULL;
}
- if ((abfd->target_defaulted || abfd->is_linker_input)
- && bfd_has_map (abfd))
+ if (abfd->target_defaulted || abfd->is_linker_input)
{
bfd *first;
unsigned int save;
- /* This archive has a map, so we may presume that the contents
- are object files. Make sure that if the first file in the
- archive can be recognized as an object file, it is for this
- target. If not, assume that this is the wrong format. If
- the first file is not an object file, somebody is doing
+ /* Make sure that if the first file in the archive can be
+ recognized as an object file, it is for this target.
+ If not, assume that this is the wrong format. If the
+ first file is not an object file, somebody is doing
something weird, and we permit it so that ar -t will work.
This is done because any normal format will recognize any
@@ -964,6 +982,84 @@ bfd_generic_archive_p (bfd *abfd)
return _bfd_no_cleanup;
}
+/* Given archive ARCH and symbol map MAP counting ORL_COUNT entries
+ load the symbols for use by the archive. */
+
+static bool
+_bfd_load_armap (bfd *arch, unsigned int elength ATTRIBUTE_UNUSED,
+ struct orl *map, unsigned int orl_count,
+ int stridx ATTRIBUTE_UNUSED)
+{
+ struct artdata *ardata = bfd_ardata (arch);
+ size_t symdef_size;
+ size_t counter;
+ carsym *set;
+
+ if (_bfd_mul_overflow (orl_count, sizeof (carsym), &symdef_size))
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ ardata->symdefs = bfd_alloc (arch, symdef_size);
+ if (!ardata->symdefs)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ return false;
+ }
+ ardata->symdef_count = orl_count;
+
+ for (counter = 0, set = ardata->symdefs;
+ counter < ardata->symdef_count;
+ counter++, set++)
+ {
+ bfd_size_type namelen = strlen (*map[counter].name) + 1;
+ char *name = bfd_alloc (arch, namelen);
+
+ if (name == NULL)
+ {
+ bfd_set_error (bfd_error_no_memory);
+ goto release_symdefs;
+ }
+
+ memcpy (name, *map[counter].name, namelen);
+ set->name = name;
+ set->u.abfd = map[counter].abfd;
+ }
+
+ ardata->symdef_use_bfd = true;
+ arch->has_armap = true;
+ return true;
+
+ release_symdefs:
+ bfd_release (arch, ardata->symdefs);
+ ardata->symdef_count = 0;
+ ardata->symdefs = NULL;
+ return false;
+}
+
+/* Iterate over members of archive ARCH starting from FIRST_ONE and
+ load their symbols for use by the archive. */
+
+bool
+_bfd_make_armap (bfd *arch, bfd *first_one)
+{
+ bfd **last_one;
+ bfd *next_one;
+
+ last_one = &(arch->archive_next);
+ for (next_one = first_one;
+ next_one;
+ next_one = bfd_openr_next_archived_file (arch, next_one))
+ {
+ *last_one = next_one;
+ last_one = &next_one->archive_next;
+ }
+ *last_one = NULL;
+ bfd_set_archive_head (arch, first_one);
+
+ return _bfd_compute_and_push_armap (arch, 0, true, _bfd_load_armap);
+}
+
/* Some constants for a 32 bit BSD archive structure. We do not
support 64 bit archives presently; so far as I know, none actually
exist. Supporting them would require changing these constants, and
@@ -2215,7 +2311,8 @@ _bfd_write_archive_contents (bfd *arch)
if (makemap && hasobjects)
{
- if (! _bfd_compute_and_write_armap (arch, (unsigned int) elength))
+ if (!_bfd_compute_and_push_armap (arch, (unsigned int) elength, false,
+ _bfd_write_armap))
return false;
}
@@ -2313,10 +2410,32 @@ _bfd_write_archive_contents (bfd *arch)
return false;
}
-/* Note that the namidx for the first symbol is 0. */
+/* Given archive ARCH write symbol map MAP counting ORL_COUNT entries
+ and using STRIDX bytes for symbol names to the archive file, with
+ ELENGTH holding the length of any extended name table. */
+
+bool
+_bfd_write_armap (bfd *arch, unsigned int elength,
+ struct orl *map, unsigned int orl_count, int stridx)
+{
+ /* Dunno if this is the best place for this info... */
+ if (elength != 0)
+ elength += sizeof (struct ar_hdr);
+ elength += elength % 2;
+
+ return BFD_SEND (arch, write_armap,
+ (arch, elength, map, orl_count, stridx));
+}
+
+/* Iterate over members of archive ARCH retrieving their symbols and then
+ push the symbols out using PUSH_ARMAP handler, giving it extended name
+ table length ELENGTH. Retain the information according to KEEP_SYMTAB.
+ Note that the namidx for the first symbol is 0. */
bool
-_bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
+_bfd_compute_and_push_armap
+ (bfd *arch, unsigned int elength, bool keep_symtab,
+ bool (*push_armap) (bfd *, unsigned int, struct orl *, unsigned int, int))
{
char *first_name = NULL;
bfd *current;
@@ -2330,11 +2449,6 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
size_t amt;
static bool report_plugin_err = true;
- /* Dunno if this is the best place for this info... */
- if (elength != 0)
- elength += sizeof (struct ar_hdr);
- elength += elength % 2;
-
amt = orl_max * sizeof (struct orl);
map = (struct orl *) bfd_malloc (amt);
if (map == NULL)
@@ -2451,14 +2565,13 @@ _bfd_compute_and_write_armap (bfd *arch, unsigned int elength)
/* Now ask the BFD to free up any cached information, so we
don't fill all of memory with symbol tables. */
- if (! bfd_free_cached_info (current))
+ if (!keep_symtab && !bfd_free_cached_info (current))
goto error_return;
}
}
- /* OK, now we have collected all the data, let's write them out. */
- ret = BFD_SEND (arch, write_armap,
- (arch, elength, map, orl_count, stridx));
+ /* OK, now we have collected all the data, let's push them out. */
+ ret = push_armap (arch, elength, map, orl_count, stridx);
free (syms);
free (map);
diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c
index f623e0a5e18..e1793035a15 100644
--- a/bfd/coff-alpha.c
+++ b/bfd/coff-alpha.c
@@ -2240,7 +2240,10 @@ alpha_ecoff_get_elt_at_index (bfd *abfd, symindex sym_index)
carsym *entry;
entry = bfd_ardata (abfd)->symdefs + sym_index;
- return alpha_ecoff_get_elt_at_filepos (abfd, entry->u.file_offset, NULL);
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ return entry->u.abfd;
+ else
+ return alpha_ecoff_get_elt_at_filepos (abfd, entry->u.file_offset, NULL);
}
static void
diff --git a/bfd/coff-rs6000.c b/bfd/coff-rs6000.c
index 65dc831f3ec..c1b34c479f9 100644
--- a/bfd/coff-rs6000.c
+++ b/bfd/coff-rs6000.c
@@ -2498,7 +2498,8 @@ xcoff_write_archive_contents_old (bfd *abfd)
BFD_ASSERT (nextoff == bfd_tell (abfd));
sprintf (fhdr->symoff, "%ld", (long) nextoff);
bfd_ardata (abfd)->tdata = &xtdata;
- bool ret = _bfd_compute_and_write_armap (abfd, 0);
+ bool ret = _bfd_compute_and_push_armap (abfd, 0, false,
+ _bfd_write_armap);
bfd_ardata (abfd)->tdata = NULL;
if (!ret)
return false;
@@ -2766,7 +2767,8 @@ xcoff_write_archive_contents_big (bfd *abfd)
PRINT20 (fhdr->symoff, nextoff);
bfd_ardata (abfd)->tdata = &xtdata;
- bool ret = _bfd_compute_and_write_armap (abfd, 0);
+ bool ret = _bfd_compute_and_push_armap (abfd, 0, false,
+ _bfd_write_armap);
bfd_ardata (abfd)->tdata = NULL;
if (!ret)
return false;
diff --git a/bfd/ecoff.c b/bfd/ecoff.c
index f7767eedbf9..09fd1900502 100644
--- a/bfd/ecoff.c
+++ b/bfd/ecoff.c
@@ -3606,11 +3606,14 @@ ecoff_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
if (! bfd_has_map (abfd))
{
+ bfd *first_one = bfd_openr_next_archived_file (abfd, NULL);
+
/* An empty archive is a special case. */
- if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
+ if (first_one == NULL)
return true;
- bfd_set_error (bfd_error_no_armap);
- return false;
+
+ if (!_bfd_make_armap (abfd, first_one))
+ return false;
}
/* If we don't have any raw data for this archive, as can happen on
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 049ef7571ec..60c1ccb6c8d 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3708,7 +3708,7 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
Elf_Internal_Sym *isymend;
bool result;
- abfd = _bfd_get_elt_at_filepos (abfd, symdef->u.file_offset, NULL);
+ abfd = _bfd_get_elt_from_symdef (abfd, symdef, NULL);
if (abfd == NULL)
return false;
@@ -6262,11 +6262,14 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
if (! bfd_has_map (abfd))
{
+ bfd *first_one = bfd_openr_next_archived_file (abfd, NULL);
+
/* An empty archive is a special case. */
- if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
+ if (first_one == NULL)
return true;
- bfd_set_error (bfd_error_no_armap);
- return false;
+
+ if (!_bfd_make_armap (abfd, first_one))
+ return false;
}
/* Keep track of all symbols we know to be already defined, and all
@@ -6286,13 +6289,13 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
do
{
- ufile_ptr last;
+ ufile_ptr_or_bfd last;
symindex i;
carsym *symdef;
carsym *symdefend;
loop = false;
- last = -1;
+ last = _bfd_elt_nil (abfd);
symdef = symdefs;
symdefend = symdef + c;
@@ -6305,7 +6308,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
if (included[i])
continue;
- if (symdef->u.file_offset == last)
+ if (_bfd_elt_eq (abfd, symdef->u, last))
{
included[i] = true;
continue;
@@ -6390,8 +6393,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
}
/* We need to include this archive member. */
- element = _bfd_get_elt_at_filepos (abfd, symdef->u.file_offset,
- info);
+ element = _bfd_get_elt_from_symdef (abfd, symdef, info);
if (element == NULL)
goto error_return;
@@ -6426,11 +6428,11 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
break;
--mark;
}
- while (symdefs[mark].u.file_offset == symdef->u.file_offset);
+ while (_bfd_elt_eq (abfd, symdefs[mark].u, symdef->u));
/* We mark subsequent symbols from this object file as we go
on through the loop. */
- last = symdef->u.file_offset;
+ last = symdef->u;
}
}
while (loop);
diff --git a/bfd/format.c b/bfd/format.c
index 2d35f59cd85..9e597877084 100644
--- a/bfd/format.c
+++ b/bfd/format.c
@@ -551,13 +551,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
/* An archive with object files matching the archive
target is OK. Other archives should be further
tested. */
- || (bfd_has_map (abfd)
- && bfd_get_error () != bfd_error_wrong_object_format)
- /* Empty archives can match the current target.
- Attempting to read the armap will result in a file
- truncated error. */
- || (!bfd_has_map (abfd)
- && bfd_get_error () == bfd_error_file_truncated))
+ || bfd_get_error () != bfd_error_wrong_object_format)
goto ok_ret;
}
else
@@ -629,8 +623,7 @@ bfd_check_format_matches (bfd *abfd, bfd_format format, char ***matching)
if (cleanup)
{
if (abfd->format != bfd_archive
- || (bfd_has_map (abfd)
- && bfd_get_error () != bfd_error_wrong_object_format))
+ || bfd_get_error () != bfd_error_wrong_object_format)
{
/* If this is the default target, accept it, even if
other targets might match. People who want those
diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
index a5186b5e6f0..fe263e27ec8 100644
--- a/bfd/libbfd-in.h
+++ b/bfd/libbfd-in.h
@@ -66,6 +66,7 @@ struct artdata
htab_t cache;
carsym *symdefs; /* The symdef entries. */
symindex symdef_count; /* How many there are. */
+ unsigned int symdef_use_bfd:1; /* Whether entries hold a BFD pointer. */
char *extended_names; /* Clever intel extension. */
bfd_size_type extended_names_size; /* Size of extended names. */
/* When more compilers are standard C, this can be a time_t. */
@@ -121,6 +122,8 @@ extern char *_bfd_append_relative_path
(bfd *, char *) ATTRIBUTE_HIDDEN;
extern bfd_cleanup bfd_generic_archive_p
(bfd *) ATTRIBUTE_HIDDEN;
+extern bool _bfd_make_armap
+ (bfd *, bfd *) ATTRIBUTE_HIDDEN;
extern bool bfd_slurp_armap
(bfd *) ATTRIBUTE_HIDDEN;
#define bfd_slurp_bsd_armap bfd_slurp_armap
@@ -153,13 +156,30 @@ extern bool _bfd_construct_extended_name_table
(bfd *, bool, char **, bfd_size_type *) ATTRIBUTE_HIDDEN;
extern bool _bfd_write_archive_contents
(bfd *) ATTRIBUTE_HIDDEN;
-extern bool _bfd_compute_and_write_armap
- (bfd *, unsigned int) ATTRIBUTE_HIDDEN;
+extern bool _bfd_write_armap
+ (bfd *, unsigned int, struct orl *, unsigned int, int) ATTRIBUTE_HIDDEN;
+extern bool _bfd_compute_and_push_armap
+ (bfd *, unsigned int, bool,
+ bool (*) (bfd *, unsigned int, struct orl *, unsigned int, int))
+ ATTRIBUTE_HIDDEN;
extern bfd *_bfd_get_elt_at_filepos
(bfd *, file_ptr, struct bfd_link_info *) ATTRIBUTE_HIDDEN;
extern bfd *_bfd_generic_get_elt_at_index
(bfd *, symindex) ATTRIBUTE_HIDDEN;
+/* Get a handle for the element of archive ARCH referred by archive symbol
+ definition SYMDEF and using linker information INFO. */
+
+static inline bfd *
+_bfd_get_elt_from_symdef (bfd *arch, carsym *symdef,
+ struct bfd_link_info *info)
+{
+ if (bfd_ardata (arch)->symdef_use_bfd)
+ return symdef->u.abfd;
+ else
+ return _bfd_get_elt_at_filepos (arch, symdef->u.file_offset, info);
+}
+
extern bool _bfd_bool_bfd_false
(bfd *) ATTRIBUTE_HIDDEN;
extern bool _bfd_bool_bfd_asymbol_false
diff --git a/bfd/libbfd.h b/bfd/libbfd.h
index a27134dcd78..18f12e84bb0 100644
--- a/bfd/libbfd.h
+++ b/bfd/libbfd.h
@@ -72,6 +72,7 @@ struct artdata
htab_t cache;
carsym *symdefs; /* The symdef entries. */
symindex symdef_count; /* How many there are. */
+ unsigned int symdef_use_bfd:1; /* Whether entries hold a BFD pointer. */
char *extended_names; /* Clever intel extension. */
bfd_size_type extended_names_size; /* Size of extended names. */
/* When more compilers are standard C, this can be a time_t. */
@@ -127,6 +128,8 @@ extern char *_bfd_append_relative_path
(bfd *, char *) ATTRIBUTE_HIDDEN;
extern bfd_cleanup bfd_generic_archive_p
(bfd *) ATTRIBUTE_HIDDEN;
+extern bool _bfd_make_armap
+ (bfd *, bfd *) ATTRIBUTE_HIDDEN;
extern bool bfd_slurp_armap
(bfd *) ATTRIBUTE_HIDDEN;
#define bfd_slurp_bsd_armap bfd_slurp_armap
@@ -159,13 +162,30 @@ extern bool _bfd_construct_extended_name_table
(bfd *, bool, char **, bfd_size_type *) ATTRIBUTE_HIDDEN;
extern bool _bfd_write_archive_contents
(bfd *) ATTRIBUTE_HIDDEN;
-extern bool _bfd_compute_and_write_armap
- (bfd *, unsigned int) ATTRIBUTE_HIDDEN;
+extern bool _bfd_write_armap
+ (bfd *, unsigned int, struct orl *, unsigned int, int) ATTRIBUTE_HIDDEN;
+extern bool _bfd_compute_and_push_armap
+ (bfd *, unsigned int, bool,
+ bool (*) (bfd *, unsigned int, struct orl *, unsigned int, int))
+ ATTRIBUTE_HIDDEN;
extern bfd *_bfd_get_elt_at_filepos
(bfd *, file_ptr, struct bfd_link_info *) ATTRIBUTE_HIDDEN;
extern bfd *_bfd_generic_get_elt_at_index
(bfd *, symindex) ATTRIBUTE_HIDDEN;
+/* Get a handle for the element of archive ARCH referred by archive symbol
+ definition SYMDEF and using linker information INFO. */
+
+static inline bfd *
+_bfd_get_elt_from_symdef (bfd *arch, carsym *symdef,
+ struct bfd_link_info *info)
+{
+ if (bfd_ardata (arch)->symdef_use_bfd)
+ return symdef->u.abfd;
+ else
+ return _bfd_get_elt_at_filepos (arch, symdef->u.file_offset, info);
+}
+
extern bool _bfd_bool_bfd_false
(bfd *) ATTRIBUTE_HIDDEN;
extern bool _bfd_bool_bfd_asymbol_false
@@ -1011,6 +1031,26 @@ struct orl /* Output ranlib. */
int namidx; /* Index into string table. */
};
+/* Return an inexistent element reference for archive ARCH. */
+
+static inline ufile_ptr_or_bfd
+_bfd_elt_nil (bfd *arch)
+{
+ return (bfd_ardata (arch)->symdef_use_bfd
+ ? (ufile_ptr_or_bfd) { .abfd = NULL }
+ : (ufile_ptr_or_bfd) { .file_offset = -1 });
+}
+
+/* Tell if ELTREF1 and ELTREF2 refer the same element of archive ARCH. */
+
+static inline bool
+_bfd_elt_eq (bfd *arch, ufile_ptr_or_bfd eltref1, ufile_ptr_or_bfd eltref2)
+{
+ return (bfd_ardata (arch)->symdef_use_bfd
+ ? eltref1.abfd == eltref2.abfd
+ : eltref1.file_offset == eltref2.file_offset);
+}
+
/* Extracted from archures.c. */
extern const bfd_arch_info_type bfd_default_arch_struct;
diff --git a/bfd/linker.c b/bfd/linker.c
index 3fac038c7d2..b579737fdda 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -939,11 +939,14 @@ _bfd_generic_link_add_archive_symbols
if (! bfd_has_map (abfd))
{
+ bfd *first_one = bfd_openr_next_archived_file (abfd, NULL);
+
/* An empty archive is a special case. */
- if (bfd_openr_next_archived_file (abfd, NULL) == NULL)
+ if (first_one == NULL)
return true;
- bfd_set_error (bfd_error_no_armap);
- return false;
+
+ if (!_bfd_make_armap (abfd, first_one))
+ return false;
}
amt = bfd_ardata (abfd)->symdef_count;
@@ -960,7 +963,7 @@ _bfd_generic_link_add_archive_symbols
carsym *arsym_end;
carsym *arsym;
unsigned int indx;
- ufile_ptr last_ar_offset = -1;
+ ufile_ptr_or_bfd last = _bfd_elt_nil (abfd);
bool needed = false;
bfd *element = NULL;
@@ -974,7 +977,7 @@ _bfd_generic_link_add_archive_symbols
if (included[indx])
continue;
- if (needed && arsym->u.file_offset == last_ar_offset)
+ if (needed && _bfd_elt_eq (abfd, arsym->u, last))
{
included[indx] = 1;
continue;
@@ -1003,11 +1006,10 @@ _bfd_generic_link_add_archive_symbols
continue;
}
- if (last_ar_offset != arsym->u.file_offset)
+ if (!_bfd_elt_eq (abfd, last, arsym->u))
{
- last_ar_offset = arsym->u.file_offset;
- element = _bfd_get_elt_at_filepos (abfd, last_ar_offset,
- info);
+ last = arsym->u;
+ element = _bfd_get_elt_from_symdef (abfd, arsym, info);
if (element == NULL
|| !bfd_check_format (element, bfd_object))
goto error_return;
@@ -1034,7 +1036,7 @@ _bfd_generic_link_add_archive_symbols
break;
--mark;
}
- while (arsyms[mark].u.file_offset == last_ar_offset);
+ while (_bfd_elt_eq (abfd, arsyms[mark].u, last));
if (undefs_tail != info->hash->undefs_tail)
loop = true;
diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi
index 5fa31d13deb..239a50f9e07 100644
--- a/binutils/doc/binutils.texi
+++ b/binutils/doc/binutils.texi
@@ -205,9 +205,7 @@ subroutines. Since libraries often will depend on other libraries,
object modules in the archive when you specify the modifier @samp{s}.
Once created, this index is updated in the archive whenever @command{ar}
makes a change to its contents (save for the @samp{q} update operation).
-An archive with such an index speeds up linking to the library, and
-allows routines in the library to call each other without regard to
-their placement in the archive.
+An archive with such an index speeds up linking to the library.
You may use @samp{nm -s} or @samp{nm --print-armap} to list this index
table. If an archive lacks the table, another form of @command{ar} called
@@ -501,10 +499,10 @@ archive is equivalent to running @samp{ranlib} on it.
@item S
@cindex not writing archive index
Do not generate an archive symbol table. This can speed up building a
-large library in several steps. The resulting archive can not be used
-with the linker. In order to build a symbol table, you must omit the
-@samp{S} modifier on the last execution of @samp{ar}, or you must run
-@samp{ranlib} on the archive.
+large library in several steps, but will negatively impact performance
+if the resulting archive is used with the linker. In order to build a
+symbol table, you must omit the @samp{S} modifier on the last execution
+of @samp{ar}, or you must run @samp{ranlib} on the archive.
@item T
Deprecated alias for @option{--thin}. @option{T} is not recommended because in
@@ -3191,9 +3189,7 @@ member of an archive that is a relocatable object file.
You may use @samp{nm -s} or @samp{nm --print-armap} to list this index.
-An archive with such an index speeds up linking to the library and
-allows routines in the library to call each other without regard to
-their placement in the archive.
+An archive with such an index speeds up linking to the library.
The @sc{gnu} @command{ranlib} program is another form of @sc{gnu} @command{ar}; running
@command{ranlib} is completely equivalent to executing @samp{ar -s}.
diff --git a/ld/testsuite/ld-archive/abct.ed b/ld/testsuite/ld-archive/abct.ed
deleted file mode 100644
index c19b479dfc2..00000000000
--- a/ld/testsuite/ld-archive/abct.ed
+++ /dev/null
@@ -1 +0,0 @@
-[^\n]*: tmpdir/abnt.a: error adding symbols: archive has no index; run ranlib to add one
diff --git a/ld/testsuite/ld-archive/abncng.vd b/ld/testsuite/ld-archive/abncng.vd
new file mode 100644
index 00000000000..9b43b10f5d9
--- /dev/null
+++ b/ld/testsuite/ld-archive/abncng.vd
@@ -0,0 +1,28 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/abn\.a succeeded
+tmpdir/abn\.a
+attempt to open tmpdir/abcn\.a succeeded
+tmpdir/abcn\.a
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/abcn\.a\(abc\.o(:?bj)?\) +\(ff\)
+\(tmpdir/abcn\.a\)abc\.o(:?bj)?
+tmpdir/abn\.a
+tmpdir/abn\.a\(a\.o(:?bj)?\) +tmpdir/abcn\.a\(abc\.o(:?bj)?\) \(aa\)
+\(tmpdir/abn\.a\)a\.o(:?bj)?
+tmpdir/abn\.a\(b\.o(:?bj)?\) +tmpdir/abcn\.a\(abc\.o(:?bj)?\) \(bb\)
+\(tmpdir/abn\.a\)b\.o(:?bj)?
+tmpdir/abcn\.a
+!(:?\()?tmpdir/.*
+#...
+START GROUP
+LOAD tmpdir/abn\.a
+LOAD tmpdir/abcn\.a
+END GROUP
+!LOAD .*
+#pass
diff --git a/ld/testsuite/ld-archive/abntcntg.vd b/ld/testsuite/ld-archive/abntcntg.vd
new file mode 100644
index 00000000000..1058089573f
--- /dev/null
+++ b/ld/testsuite/ld-archive/abntcntg.vd
@@ -0,0 +1,28 @@
+#...
+using ..ternal linker script:.*
+==================================================
+#...
+==================================================
+.*: mode .*
+attempt to open tmpdir/abnt\.a succeeded
+tmpdir/abnt\.a
+attempt to open tmpdir/abcnt\.a succeeded
+tmpdir/abcnt\.a
+Archive member included to satisfy reference by file \(symbol\)
+
+tmpdir/abc\.o +\(ff\)
+tmpdir/abc\.o
+tmpdir/abnt\.a
+tmpdir/a\.o +tmpdir/abc\.o \(aa\)
+tmpdir/a\.o
+tmpdir/b\.o +tmpdir/abc\.o \(bb\)
+tmpdir/b\.o
+tmpdir/abcnt\.a
+!(:?\()?tmpdir/.*
+#...
+START GROUP
+LOAD tmpdir/abnt\.a
+LOAD tmpdir/abcnt\.a
+END GROUP
+!LOAD .*
+#pass
diff --git a/ld/testsuite/ld-archive/archive.exp b/ld/testsuite/ld-archive/archive.exp
index e8722c2ca42..73742cfb560 100644
--- a/ld/testsuite/ld-archive/archive.exp
+++ b/ld/testsuite/ld-archive/archive.exp
@@ -230,26 +230,65 @@ run_ld_link_tests [list \
] \
]
-set LDFLAGS $old_ldflags
-
-# Alpha/VMS archives always have an index and XCOFF targets currently
-# accept archives without one.
-if { [istarget "alpha*-*-*vms*"] || [is_xcoff_format] } {
- return
-}
-
# Single non-index archive tests.
run_ld_link_tests [list \
[list "Regular archive w/o index link" \
"-e ff" "tmpdir/abn.a" \
"" {abc.s} \
- {{ld abc.ed}} \
+ [ld_archive_filter_tests {{nm "" abc.nd} \
+ {nm "" nx.nd}}] \
"abnc" \
] \
+]
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+run_ld_link_tests [list \
[list "Thin archive w/o index link" \
"-e ff" "tmpdir/abnt.a" \
"" {abc.s} \
- {{ld abct.ed}} \
- "abnct" \
+ [ld_archive_filter_tests {{nm "" abc.nd} \
+ {nm "" nx.nd}}] \
+ "abntc" \
] \
]
+
+# Group non-index archive tests.
+run_ld_link_tests [list \
+ [list "Regular non-group archive w/o index link reject" \
+ "-e ff tmpdir/abn.a" "tmpdir/abcn.a" \
+ "" {} \
+ {{ld abcn.ed}} \
+ "abncnn" \
+ ] \
+ [list "Thin non-group archive w/o index link reject" \
+ "-e ff tmpdir/abnt.a" "tmpdir/abcnt.a" \
+ "" {} \
+ {{ld abcn.ed}} \
+ "abntcntn" \
+ ] \
+ [list "Regular group archive w/o index link accept" \
+ "-e ff -\\( tmpdir/abn.a" "tmpdir/abcn.a -\\) --verbose --print-map" \
+ "" {} \
+ [ld_archive_filter_tests {{ld abncng.vd} \
+ {nm "" abc.nd} \
+ {nm "" nx.nd}}] \
+ "abncng" \
+ ] \
+]
+setup_xfail "binutils/33484" "alpha*-*-linux*ecoff*" "alpha*-*-osf*"
+setup_xfail "binutils/33600" "alpha*-*-*vms*"
+if { [is_xcoff_format] } {
+ setup_xfail "binutils/33600" "*-*-*"
+}
+run_ld_link_tests [list \
+ [list "Thin group archive w/o index link accept" \
+ "-e ff\
+ -\\( tmpdir/abnt.a" "tmpdir/abcnt.a -\\) --verbose --print-map" \
+ "" {} \
+ [ld_archive_filter_tests {{ld abntcntg.vd} \
+ {nm "" abc.nd} \
+ {nm "" nx.nd}}] \
+ "abntcntg" \
+ ] \
+]
+
+set LDFLAGS $old_ldflags
diff --git a/ld/testsuite/ld-cris/archive.exp b/ld/testsuite/ld-cris/archive.exp
index 12768e80458..4a9d49adf44 100644
--- a/ld/testsuite/ld-cris/archive.exp
+++ b/ld/testsuite/ld-cris/archive.exp
@@ -123,3 +123,35 @@ run_ld_link_tests [list \
"abtci" \
] \
]
+
+# Single non-index archive tests.
+run_ld_link_tests [list \
+ [list "CRIS regular archive w/o index link (explicit emulation)" \
+ "$ldemul -e ff" "tmpdir/abn.a" \
+ "$asemul" {../ld-archive/abc.s} \
+ {{nm "" ../ld-archive/abc.nd} \
+ {nm "" ../ld-archive/nx.nd}} \
+ "abncx" \
+ ] \
+ [list "CRIS regular archive w/o index link (implicit emulation)" \
+ "-e ff" "tmpdir/abn.a" \
+ "$asemul" {../ld-archive/abc.s} \
+ {{nm "" ../ld-archive/abc.nd} \
+ {nm "" ../ld-archive/nx.nd}} \
+ "abnci" \
+ ] \
+ [list "CRIS thin archive w/o index link (explicit emulation)" \
+ "$ldemul -e ff" "tmpdir/abnt.a" \
+ "$asemul" {../ld-archive/abc.s} \
+ {{nm "" ../ld-archive/abc.nd} \
+ {nm "" ../ld-archive/nx.nd}} \
+ "abntcx" \
+ ] \
+ [list "CRIS thin archive w/o index link (implicit emulation)" \
+ "-e ff" "tmpdir/abnt.a" \
+ "$asemul" {../ld-archive/abc.s} \
+ {{nm "" ../ld-archive/abc.nd} \
+ {nm "" ../ld-archive/nx.nd}} \
+ "abntci" \
+ ] \
+]
More information about the Binutils-cvs
mailing list