[PATCH v2 10/16] PR ld/24600: BFD: Add general linker support for mapless archives
Maciej W. Rozycki
macro@orcam.me.uk
Thu Nov 6 21:19:45 GMT 2025
From: Maciej W. Rozycki <macro@redhat.com>
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.
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.
---
Hi,
The oddity with the CRIS target has been resolved since v1, but the
underlying BFD issue remains.
Specifically, for mapless archives code in `bfd_check_format_matches'
ignores the BFD target supplied by the linker and resorts to iterating
over all the BFD formats to find one to match. Then, when called in the
linker `bfd_generic_archive_p' accepts any archive file without any
verification of its member files.
The issue with CRIS was recently discussed[1], but the change applied
doesn't seem sufficient, and it seems to go back to an attempt to fix PR
binutils/13278 issue with the plugin target[2], where archive validation
has been disabled for the !target_defaulted case, which stands when
`bfd_generic_archive_p' is called in the linker.
Consequently any BFD target supplied is accepted for an archive with a
map regardless of whether the target is compatible with the archive's
members or not, and then for mapless archives all the elaborate target
selection code in `bfd_check_format_matches' seems to be doing nothing,
except for resorting to the default BFD target, which just happens to work
for most targets.
I think the checks that prevent archive validation need to be revisited
and we also need to validate mapless archives; I fail to see the reason
why we should not. But then I don't think the lack of such a cleanup
should be a showstopper for this feature; it works for the common case and
there's no regression in existing functionality after all.
I'll try and see if I can come up with a satisfactory fix for the format
matching issue, but I'll appreciate any insights regardless.
Maciej
References:
[1] commit 28daddd33acc ("Make bfd_check_format better respect given
target"),
<https://inbox.sourceware.org/binutils/aJ_XqdlGa2fvBHi6@squeak.grove.modra.org/>
[2] commit b228303dd14e ("PR binutils/13278: --plugin doesn't work on
archive"),
<https://inbox.sourceware.org/binutils/20111011064345.GM25970@bubble.grove.modra.org/>
Changes from v1 (7/8),
<https://inbox.sourceware.org/binutils/alpine.DEB.2.21.2509262121560.63399@angie.orcam.me.uk/>:
- Update to use `ufile_ptr_or_bfd' rather than `file_ptr_or_bfd'.
- Retain the symbol table loaded with maps created by the linker.
- Set an archive's `has_armap' flag once a map has been built on the fly.
- Also update `alpha_ecoff_get_elt_at_index', although the function does
not appear to be used.
- Update archive.exp according to changes for Alpha/VMS made with 02/16.
- Add archive group tests.
- Remove ld/testsuite/ld-archive/abct.ed.
- Update the description according to the VMS situation.
- Update the description according to the current CRIS target situation.
---
bfd/archive.c | 124 ++++++++++++++++++++++++++++++++----
bfd/coff-alpha.c | 5 +
bfd/coff-rs6000.c | 6 +
bfd/ecoff.c | 9 +-
bfd/elflink.c | 38 +++++++----
bfd/libbfd-in.h | 11 ++-
bfd/libbfd.h | 11 ++-
bfd/linker.c | 38 ++++++++---
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 ++++++++++++++---
13 files changed, 310 insertions(+), 66 deletions(-)
binutils-bfd-ar-noindex.diff
Index: binutils-gdb/bfd/archive.c
===================================================================
--- binutils-gdb.orig/bfd/archive.c
+++ binutils-gdb/bfd/archive.c
@@ -811,7 +811,10 @@ _bfd_generic_get_elt_at_index (bfd *abfd
carsym *entry;
entry = bfd_ardata (abfd)->symdefs + sym_index;
- return _bfd_get_elt_at_filepos (abfd, entry->u.file_offset, NULL);
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ return entry->u.abfd;
+ else
+ return _bfd_get_elt_at_filepos (abfd, entry->u.file_offset, NULL);
}
bfd *
@@ -961,6 +964,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 *abfd, unsigned int elength ATTRIBUTE_UNUSED,
+ struct orl *map, unsigned int orl_count,
+ int stridx ATTRIBUTE_UNUSED)
+{
+ struct artdata *ardata = bfd_ardata (abfd);
+ 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 = (struct carsym *) bfd_alloc (abfd, 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 (abfd, 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;
+ abfd->has_armap = true;
+ return true;
+
+ release_symdefs:
+ bfd_release (abfd, 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 *abfd, bfd *first_one)
+{
+ bfd **last_one;
+ bfd *next_one;
+
+ last_one = &(abfd->archive_next);
+ for (next_one = first_one;
+ next_one;
+ next_one = bfd_openr_next_archived_file (abfd, next_one))
+ {
+ *last_one = next_one;
+ last_one = &next_one->archive_next;
+ }
+ *last_one = NULL;
+ bfd_set_archive_head (abfd, first_one);
+
+ return _bfd_compute_and_push_armap (abfd, 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
@@ -2212,7 +2293,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;
}
@@ -2310,10 +2392,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_compute_and_write_armap (bfd *arch, unsigned int elength)
+_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_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;
@@ -2327,11 +2431,6 @@ _bfd_compute_and_write_armap (bfd *arch,
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)
@@ -2448,14 +2547,13 @@ _bfd_compute_and_write_armap (bfd *arch,
/* 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);
Index: binutils-gdb/bfd/coff-alpha.c
===================================================================
--- binutils-gdb.orig/bfd/coff-alpha.c
+++ binutils-gdb/bfd/coff-alpha.c
@@ -2273,7 +2273,10 @@ alpha_ecoff_get_elt_at_index (bfd *abfd,
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
Index: binutils-gdb/bfd/coff-rs6000.c
===================================================================
--- binutils-gdb.orig/bfd/coff-rs6000.c
+++ binutils-gdb/bfd/coff-rs6000.c
@@ -2498,7 +2498,8 @@ xcoff_write_archive_contents_old (bfd *a
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 *a
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;
Index: binutils-gdb/bfd/ecoff.c
===================================================================
--- binutils-gdb.orig/bfd/ecoff.c
+++ binutils-gdb/bfd/ecoff.c
@@ -3596,11 +3596,14 @@ ecoff_link_add_archive_symbols (bfd *abf
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
Index: binutils-gdb/bfd/elflink.c
===================================================================
--- binutils-gdb.orig/bfd/elflink.c
+++ binutils-gdb/bfd/elflink.c
@@ -3697,7 +3697,10 @@ elf_link_is_defined_archive_symbol (bfd
Elf_Internal_Sym *isymend;
bool result;
- abfd = _bfd_get_elt_at_filepos (abfd, symdef->u.file_offset, NULL);
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ abfd = symdef->u.abfd;
+ else
+ abfd = _bfd_get_elt_at_filepos (abfd, symdef->u.file_offset, NULL);
if (abfd == NULL)
return false;
@@ -6250,11 +6253,14 @@ elf_link_add_archive_symbols (bfd *abfd,
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
@@ -6274,13 +6280,16 @@ elf_link_add_archive_symbols (bfd *abfd,
do
{
- ufile_ptr last;
+ ufile_ptr_or_bfd last;
symindex i;
carsym *symdef;
carsym *symdefend;
loop = false;
- last = ~0ULL;
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ last.abfd = NULL;
+ else
+ last.file_offset = ~0ULL;
symdef = symdefs;
symdefend = symdef + c;
@@ -6293,7 +6302,9 @@ elf_link_add_archive_symbols (bfd *abfd,
if (included[i])
continue;
- if (symdef->u.file_offset == last)
+ if (bfd_ardata (abfd)->symdef_use_bfd
+ ? symdef->u.abfd == last.abfd
+ : symdef->u.file_offset == last.file_offset)
{
included[i] = true;
continue;
@@ -6378,8 +6389,11 @@ elf_link_add_archive_symbols (bfd *abfd,
}
/* We need to include this archive member. */
- element = _bfd_get_elt_at_filepos (abfd, symdef->u.file_offset,
- info);
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ element = symdef->u.abfd;
+ else
+ element = _bfd_get_elt_at_filepos (abfd, symdef->u.file_offset,
+ info);
if (element == NULL)
goto error_return;
@@ -6414,11 +6428,13 @@ elf_link_add_archive_symbols (bfd *abfd,
break;
--mark;
}
- while (symdefs[mark].u.file_offset == symdef->u.file_offset);
+ while (bfd_ardata (abfd)->symdef_use_bfd
+ ? symdefs[mark].u.abfd == symdef->u.abfd
+ : symdefs[mark].u.file_offset == symdef->u.file_offset);
/* 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);
Index: binutils-gdb/bfd/libbfd-in.h
===================================================================
--- binutils-gdb.orig/bfd/libbfd-in.h
+++ binutils-gdb/bfd/libbfd-in.h
@@ -73,6 +73,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. */
@@ -128,6 +129,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
@@ -160,8 +163,12 @@ extern bool _bfd_construct_extended_name
(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
Index: binutils-gdb/bfd/libbfd.h
===================================================================
--- binutils-gdb.orig/bfd/libbfd.h
+++ binutils-gdb/bfd/libbfd.h
@@ -79,6 +79,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. */
@@ -134,6 +135,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
@@ -166,8 +169,12 @@ extern bool _bfd_construct_extended_name
(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
Index: binutils-gdb/bfd/linker.c
===================================================================
--- binutils-gdb.orig/bfd/linker.c
+++ binutils-gdb/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,11 +963,16 @@ _bfd_generic_link_add_archive_symbols
carsym *arsym_end;
carsym *arsym;
unsigned int indx;
- ufile_ptr last_ar_offset = ~0ULL;
+ ufile_ptr_or_bfd last;
bool needed = false;
bfd *element = NULL;
loop = false;
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ last.abfd = NULL;
+ else
+ last.file_offset = ~0ULL;
+
arsyms = bfd_ardata (abfd)->symdefs;
arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
@@ -974,7 +982,10 @@ _bfd_generic_link_add_archive_symbols
if (included[indx])
continue;
- if (needed && arsym->u.file_offset == last_ar_offset)
+ if (needed
+ && (bfd_ardata (abfd)->symdef_use_bfd
+ ? arsym->u.abfd == last.abfd
+ : arsym->u.file_offset == last.file_offset))
{
included[indx] = 1;
continue;
@@ -1003,11 +1014,16 @@ _bfd_generic_link_add_archive_symbols
continue;
}
- if (last_ar_offset != arsym->u.file_offset)
+ if (bfd_ardata (abfd)->symdef_use_bfd
+ ? last.abfd != arsym->u.abfd
+ : last.file_offset != arsym->u.file_offset)
{
- last_ar_offset = arsym->u.file_offset;
- element = _bfd_get_elt_at_filepos (abfd, last_ar_offset,
- info);
+ last = arsym->u;
+ if (bfd_ardata (abfd)->symdef_use_bfd)
+ element = last.abfd;
+ else
+ element = _bfd_get_elt_at_filepos (abfd, last.file_offset,
+ info);
if (element == NULL
|| !bfd_check_format (element, bfd_object))
goto error_return;
@@ -1034,7 +1050,9 @@ _bfd_generic_link_add_archive_symbols
break;
--mark;
}
- while (arsyms[mark].u.file_offset == last_ar_offset);
+ while (bfd_ardata (abfd)->symdef_use_bfd
+ ? arsyms[mark].u.abfd == last.abfd
+ : arsyms[mark].u.file_offset == last.file_offset);
if (undefs_tail != info->hash->undefs_tail)
loop = true;
Index: binutils-gdb/binutils/doc/binutils.texi
===================================================================
--- binutils-gdb.orig/binutils/doc/binutils.texi
+++ binutils-gdb/binutils/doc/binutils.texi
@@ -205,9 +205,7 @@ subroutines. Since libraries often will
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{r
@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
@@ -3164,9 +3162,7 @@ member of an archive that is a relocatab
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}.
Index: binutils-gdb/ld/testsuite/ld-archive/abct.ed
===================================================================
--- binutils-gdb.orig/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
Index: binutils-gdb/ld/testsuite/ld-archive/abncng.vd
===================================================================
--- /dev/null
+++ binutils-gdb/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
Index: binutils-gdb/ld/testsuite/ld-archive/abntcntg.vd
===================================================================
--- /dev/null
+++ binutils-gdb/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
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,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
More information about the Binutils
mailing list