123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035 |
- From c6df45304e92aa2d7e9f2d8311ae5a0b1543daa8 Mon Sep 17 00:00:00 2001
- From: Nicolas Vigier <boklm@torproject.org>
- Date: Wed, 16 May 2018 11:07:52 +0200
- Subject: [PATCH] Revert "Fix LTO vs. COFF archives"
- This reverts commit 13e570f80cbfb299a8858ce6830e91a6cb40ab7b.
- ---
- bfd/aoutx.h | 2 -
- bfd/cofflink.c | 116 +++++++++++++++---
- bfd/ecoff.c | 164 +++++++++++++++++++++++--
- bfd/elflink.c | 53 ++++++--
- bfd/libbfd-in.h | 4 +-
- bfd/libbfd.h | 4 +-
- bfd/linker.c | 366 ++++++++++++++++++++++++++++++++++++++++----------------
- bfd/pdp11.c | 4 +-
- bfd/xcofflink.c | 4 +-
- 9 files changed, 560 insertions(+), 157 deletions(-)
- diff --git a/bfd/aoutx.h b/bfd/aoutx.h
- index 9385a98..6ca9c58 100644
- --- a/bfd/aoutx.h
- +++ b/bfd/aoutx.h
- @@ -3405,8 +3405,6 @@ aout_link_check_ar_symbols (bfd *abfd,
- static bfd_boolean
- aout_link_check_archive_element (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
- - const char *name ATTRIBUTE_UNUSED,
- bfd_boolean *pneeded)
- {
- bfd *oldbfd;
- diff --git a/bfd/cofflink.c b/bfd/cofflink.c
- index 2782795..3a82640 100644
- --- a/bfd/cofflink.c
- +++ b/bfd/cofflink.c
- @@ -29,11 +29,9 @@
- #include "libcoff.h"
- #include "safe-ctype.h"
-
- -static bfd_boolean coff_link_add_object_symbols (bfd *, struct bfd_link_info *);
- -static bfd_boolean coff_link_check_archive_element
- - (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *);
- -static bfd_boolean coff_link_add_symbols (bfd *, struct bfd_link_info *);
- +static bfd_boolean coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info);
- +static bfd_boolean coff_link_check_archive_element (bfd *abfd, struct bfd_link_info *info, bfd_boolean *pneeded);
- +static bfd_boolean coff_link_add_symbols (bfd *abfd, struct bfd_link_info *info);
-
- /* Return TRUE if SYM is a weak, external symbol. */
- #define IS_WEAK_EXTERNAL(abfd, sym) \
- @@ -192,6 +190,74 @@ coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
- return TRUE;
- }
-
- +/* Look through the symbols to see if this object file should be
- + included in the link. */
- +
- +static bfd_boolean
- +coff_link_check_ar_symbols (bfd *abfd,
- + struct bfd_link_info *info,
- + bfd_boolean *pneeded,
- + bfd **subsbfd)
- +{
- + bfd_size_type symesz;
- + bfd_byte *esym;
- + bfd_byte *esym_end;
- +
- + *pneeded = FALSE;
- +
- + symesz = bfd_coff_symesz (abfd);
- + esym = (bfd_byte *) obj_coff_external_syms (abfd);
- + esym_end = esym + obj_raw_syment_count (abfd) * symesz;
- + while (esym < esym_end)
- + {
- + struct internal_syment sym;
- + enum coff_symbol_classification classification;
- +
- + bfd_coff_swap_sym_in (abfd, esym, &sym);
- +
- + classification = bfd_coff_classify_symbol (abfd, &sym);
- + if (classification == COFF_SYMBOL_GLOBAL
- + || classification == COFF_SYMBOL_COMMON)
- + {
- + const char *name;
- + char buf[SYMNMLEN + 1];
- + struct bfd_link_hash_entry *h;
- +
- + /* This symbol is externally visible, and is defined by this
- + object file. */
- + name = _bfd_coff_internal_syment_name (abfd, &sym, buf);
- + if (name == NULL)
- + return FALSE;
- + h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
- +
- + /* Auto import. */
- + if (!h
- + && info->pei386_auto_import
- + && CONST_STRNEQ (name, "__imp_"))
- + h = bfd_link_hash_lookup (info->hash, name + 6, FALSE, FALSE, TRUE);
- +
- + /* We are only interested in symbols that are currently
- + undefined. If a symbol is currently known to be common,
- + COFF linkers do not bring in an object file which defines
- + it. */
- + if (h != (struct bfd_link_hash_entry *) NULL
- + && h->type == bfd_link_hash_undefined)
- + {
- + if (!(*info->callbacks
- + ->add_archive_element) (info, abfd, name, subsbfd))
- + return FALSE;
- + *pneeded = TRUE;
- + return TRUE;
- + }
- + }
- +
- + esym += (sym.n_numaux + 1) * symesz;
- + }
- +
- + /* We do not need this object file. */
- + return TRUE;
- +}
- +
- /* Check a single archive element to see if we need to include it in
- the link. *PNEEDED is set according to whether this element is
- needed in the link or not. This is called via
- @@ -200,23 +266,41 @@ coff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
- static bfd_boolean
- coff_link_check_archive_element (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h,
- - const char *name,
- bfd_boolean *pneeded)
- {
- - *pneeded = FALSE;
- + bfd *oldbfd;
- + bfd_boolean needed;
-
- - /* We are only interested in symbols that are currently undefined.
- - If a symbol is currently known to be common, COFF linkers do not
- - bring in an object file which defines it. */
- - if (h->type != bfd_link_hash_undefined)
- - return TRUE;
- + if (!_bfd_coff_get_external_symbols (abfd))
- + return FALSE;
-
- - if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd))
- + oldbfd = abfd;
- + if (!coff_link_check_ar_symbols (abfd, info, pneeded, &abfd))
- return FALSE;
- - *pneeded = TRUE;
-
- - return coff_link_add_object_symbols (abfd, info);
- + needed = *pneeded;
- + if (needed)
- + {
- + /* Potentially, the add_archive_element hook may have set a
- + substitute BFD for us. */
- + if (abfd != oldbfd)
- + {
- + if (!info->keep_memory
- + && !_bfd_coff_free_symbols (oldbfd))
- + return FALSE;
- + if (!_bfd_coff_get_external_symbols (abfd))
- + return FALSE;
- + }
- + if (!coff_link_add_symbols (abfd, info))
- + return FALSE;
- + }
- +
- + if (!info->keep_memory || !needed)
- + {
- + if (!_bfd_coff_free_symbols (abfd))
- + return FALSE;
- + }
- + return TRUE;
- }
-
- /* Add all the symbols from an object file to the hash table. */
- diff --git a/bfd/ecoff.c b/bfd/ecoff.c
- index 01f51e6..2c915f0 100644
- --- a/bfd/ecoff.c
- +++ b/bfd/ecoff.c
- @@ -3500,29 +3500,171 @@ ecoff_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
- return FALSE;
- }
-
- +/* Factored out from ecoff_link_check_archive_element. */
- +
- +static bfd_boolean
- +read_ext_syms_and_strs (HDRR **symhdr, bfd_size_type *external_ext_size,
- + bfd_size_type *esize, void **external_ext, char **ssext, bfd *abfd,
- + const struct ecoff_backend_data * const backend)
- +{
- + if (! ecoff_slurp_symbolic_header (abfd))
- + return FALSE;
- +
- + /* If there are no symbols, we don't want it. */
- + if (bfd_get_symcount (abfd) == 0)
- + return TRUE;
- +
- + *symhdr = &ecoff_data (abfd)->debug_info.symbolic_header;
- +
- + *external_ext_size = backend->debug_swap.external_ext_size;
- + *esize = (*symhdr)->iextMax * *external_ext_size;
- + *external_ext = bfd_malloc (*esize);
- + if (*external_ext == NULL && *esize != 0)
- + return FALSE;
- +
- + if (bfd_seek (abfd, (file_ptr) (*symhdr)->cbExtOffset, SEEK_SET) != 0
- + || bfd_bread (*external_ext, *esize, abfd) != *esize)
- + return FALSE;
- +
- + *ssext = (char *) bfd_malloc ((bfd_size_type) (*symhdr)->issExtMax);
- + if (*ssext == NULL && (*symhdr)->issExtMax != 0)
- + return FALSE;
- +
- + if (bfd_seek (abfd, (file_ptr) (*symhdr)->cbSsExtOffset, SEEK_SET) != 0
- + || (bfd_bread (*ssext, (bfd_size_type) (*symhdr)->issExtMax, abfd)
- + != (bfd_size_type) (*symhdr)->issExtMax))
- + return FALSE;
- + return TRUE;
- +}
- +
- +static bfd_boolean
- +reread_ext_syms_and_strs (HDRR **symhdr, bfd_size_type *external_ext_size,
- + bfd_size_type *esize, void **external_ext, char **ssext, bfd *abfd,
- + const struct ecoff_backend_data * const backend)
- +{
- + if (*external_ext != NULL)
- + free (*external_ext);
- + *external_ext = NULL;
- + if (*ssext != NULL)
- + free (*ssext);
- + *ssext = NULL;
- + return read_ext_syms_and_strs (symhdr, external_ext_size, esize,
- + external_ext, ssext, abfd, backend);
- +}
- +
- /* This is called if we used _bfd_generic_link_add_archive_symbols
- because we were not dealing with an ECOFF archive. */
-
- static bfd_boolean
- ecoff_link_check_archive_element (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h,
- - const char *name,
- bfd_boolean *pneeded)
- {
- + const struct ecoff_backend_data * const backend = ecoff_backend (abfd);
- + void (* const swap_ext_in) (bfd *, void *, EXTR *)
- + = backend->debug_swap.swap_ext_in;
- + HDRR *symhdr;
- + bfd_size_type external_ext_size = 0;
- + void * external_ext = NULL;
- + bfd_size_type esize = 0;
- + char *ssext = NULL;
- + char *ext_ptr;
- + char *ext_end;
- +
- *pneeded = FALSE;
-
- - /* Unlike the generic linker, we do not pull in elements because
- - of common symbols. */
- - if (h->type != bfd_link_hash_undefined)
- - return TRUE;
- + /* Read in the external symbols and external strings. */
- + if (!read_ext_syms_and_strs (&symhdr, &external_ext_size, &esize,
- + &external_ext, &ssext, abfd, backend))
- + goto error_return;
-
- - /* Include this element. */
- - if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd))
- - return FALSE;
- - *pneeded = TRUE;
- + /* If there are no symbols, we don't want it. */
- + if (bfd_get_symcount (abfd) == 0)
- + goto successful_return;
-
- - return ecoff_link_add_object_symbols (abfd, info);
- + /* Look through the external symbols to see if they define some
- + symbol that is currently undefined. */
- + ext_ptr = (char *) external_ext;
- + ext_end = ext_ptr + esize;
- + for (; ext_ptr < ext_end; ext_ptr += external_ext_size)
- + {
- + EXTR esym;
- + bfd_boolean def;
- + const char *name;
- + bfd *oldbfd;
- + struct bfd_link_hash_entry *h;
- +
- + (*swap_ext_in) (abfd, (void *) ext_ptr, &esym);
- +
- + /* See if this symbol defines something. */
- + if (esym.asym.st != stGlobal
- + && esym.asym.st != stLabel
- + && esym.asym.st != stProc)
- + continue;
- +
- + switch (esym.asym.sc)
- + {
- + case scText:
- + case scData:
- + case scBss:
- + case scAbs:
- + case scSData:
- + case scSBss:
- + case scRData:
- + case scCommon:
- + case scSCommon:
- + case scInit:
- + case scFini:
- + case scRConst:
- + def = TRUE;
- + break;
- + default:
- + def = FALSE;
- + break;
- + }
- +
- + if (! def)
- + continue;
- +
- + name = ssext + esym.asym.iss;
- + h = bfd_link_hash_lookup (info->hash, name, FALSE, FALSE, TRUE);
- +
- + /* Unlike the generic linker, we do not pull in elements because
- + of common symbols. */
- + if (h == NULL
- + || h->type != bfd_link_hash_undefined)
- + continue;
- +
- + /* Include this element. */
- + oldbfd = abfd;
- + if (!(*info->callbacks
- + ->add_archive_element) (info, abfd, name, &abfd))
- + goto error_return;
- + /* Potentially, the add_archive_element hook may have set a
- + substitute BFD for us. */
- + if (abfd != oldbfd
- + && !reread_ext_syms_and_strs (&symhdr, &external_ext_size, &esize,
- + &external_ext, &ssext, abfd, backend))
- + goto error_return;
- + if (! ecoff_link_add_externals (abfd, info, external_ext, ssext))
- + goto error_return;
- +
- + *pneeded = TRUE;
- + goto successful_return;
- + }
- +
- + successful_return:
- + if (external_ext != NULL)
- + free (external_ext);
- + if (ssext != NULL)
- + free (ssext);
- + return TRUE;
- + error_return:
- + if (external_ext != NULL)
- + free (external_ext);
- + if (ssext != NULL)
- + free (ssext);
- + return FALSE;
- }
-
- /* Add the symbols from an archive file to the global hash table.
- diff --git a/bfd/elflink.c b/bfd/elflink.c
- index 94ab762..164df6b 100644
- --- a/bfd/elflink.c
- +++ b/bfd/elflink.c
- @@ -2933,6 +2933,13 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef)
- if (! bfd_check_format (abfd, bfd_object))
- return FALSE;
-
- + /* If we have already included the element containing this symbol in the
- + link then we do not need to include it again. Just claim that any symbol
- + it contains is not a definition, so that our caller will not decide to
- + (re)include this element. */
- + if (abfd->archive_pass)
- + return FALSE;
- +
- /* Select the appropriate symbol table. */
- if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0)
- hdr = &elf_tdata (abfd)->symtab_hdr;
- @@ -4929,8 +4936,20 @@ _bfd_elf_archive_symbol_lookup (bfd *abfd,
- }
-
- /* Add symbols from an ELF archive file to the linker hash table. We
- - don't use _bfd_generic_link_add_archive_symbols because we need to
- - handle versioned symbols.
- + don't use _bfd_generic_link_add_archive_symbols because of a
- + problem which arises on UnixWare. The UnixWare libc.so is an
- + archive which includes an entry libc.so.1 which defines a bunch of
- + symbols. The libc.so archive also includes a number of other
- + object files, which also define symbols, some of which are the same
- + as those defined in libc.so.1. Correct linking requires that we
- + consider each object file in turn, and include it if it defines any
- + symbols we need. _bfd_generic_link_add_archive_symbols does not do
- + this; it looks through the list of undefined symbols, and includes
- + any object file which defines them. When this algorithm is used on
- + UnixWare, it winds up pulling in libc.so.1 early and defining a
- + bunch of symbols. This means that some of the other objects in the
- + archive are not included in the link, which is incorrect since they
- + precede libc.so.1 in the archive.
-
- Fortunately, ELF archive handling is simpler than that done by
- _bfd_generic_link_add_archive_symbols, which has to allow for a.out
- @@ -4945,7 +4964,8 @@ static bfd_boolean
- elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
- {
- symindex c;
- - unsigned char *included = NULL;
- + bfd_boolean *defined = NULL;
- + bfd_boolean *included = NULL;
- carsym *symdefs;
- bfd_boolean loop;
- bfd_size_type amt;
- @@ -4969,10 +4989,11 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
- if (c == 0)
- return TRUE;
- amt = c;
- - amt *= sizeof (*included);
- - included = (unsigned char *) bfd_zmalloc (amt);
- - if (included == NULL)
- - return FALSE;
- + amt *= sizeof (bfd_boolean);
- + defined = (bfd_boolean *) bfd_zmalloc (amt);
- + included = (bfd_boolean *) bfd_zmalloc (amt);
- + if (defined == NULL || included == NULL)
- + goto error_return;
-
- symdefs = bfd_ardata (abfd)->symdefs;
- bed = get_elf_backend_data (abfd);
- @@ -4997,7 +5018,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
- struct bfd_link_hash_entry *undefs_tail;
- symindex mark;
-
- - if (included[i])
- + if (defined[i] || included[i])
- continue;
- if (symdef->file_offset == last)
- {
- @@ -5032,8 +5053,7 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
- else if (h->root.type != bfd_link_hash_undefined)
- {
- if (h->root.type != bfd_link_hash_undefweak)
- - /* Symbol must be defined. Don't check it again. */
- - included[i] = TRUE;
- + defined[i] = TRUE;
- continue;
- }
-
- @@ -5045,6 +5065,16 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
- if (! bfd_check_format (element, bfd_object))
- goto error_return;
-
- + /* Doublecheck that we have not included this object
- + already--it should be impossible, but there may be
- + something wrong with the archive. */
- + if (element->archive_pass != 0)
- + {
- + bfd_set_error (bfd_error_bad_value);
- + goto error_return;
- + }
- + element->archive_pass = 1;
- +
- undefs_tail = info->hash->undefs_tail;
-
- if (!(*info->callbacks
- @@ -5082,11 +5112,14 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info)
- }
- while (loop);
-
- + free (defined);
- free (included);
-
- return TRUE;
-
- error_return:
- + if (defined != NULL)
- + free (defined);
- if (included != NULL)
- free (included);
- return FALSE;
- diff --git a/bfd/libbfd-in.h b/bfd/libbfd-in.h
- index 50a46ac..90c6018 100644
- --- a/bfd/libbfd-in.h
- +++ b/bfd/libbfd-in.h
- @@ -596,9 +596,7 @@ extern bfd_boolean _bfd_generic_link_add_symbols_collect
- /* Generic archive add symbol routine. */
- extern bfd_boolean _bfd_generic_link_add_archive_symbols
- (bfd *, struct bfd_link_info *,
- - bfd_boolean (*) (bfd *, struct bfd_link_info *,
- - struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *));
- + bfd_boolean (*) (bfd *, struct bfd_link_info *, bfd_boolean *));
-
- /* Forward declaration to avoid prototype errors. */
- typedef struct bfd_link_hash_entry _bfd_link_hash_entry;
- diff --git a/bfd/libbfd.h b/bfd/libbfd.h
- index 6c48f82..ffb6ea4 100644
- --- a/bfd/libbfd.h
- +++ b/bfd/libbfd.h
- @@ -601,9 +601,7 @@ extern bfd_boolean _bfd_generic_link_add_symbols_collect
- /* Generic archive add symbol routine. */
- extern bfd_boolean _bfd_generic_link_add_archive_symbols
- (bfd *, struct bfd_link_info *,
- - bfd_boolean (*) (bfd *, struct bfd_link_info *,
- - struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *));
- + bfd_boolean (*) (bfd *, struct bfd_link_info *, bfd_boolean *));
-
- /* Forward declaration to avoid prototype errors. */
- typedef struct bfd_link_hash_entry _bfd_link_hash_entry;
- diff --git a/bfd/linker.c b/bfd/linker.c
- index abdf5b0..4cff1e7 100644
- --- a/bfd/linker.c
- +++ b/bfd/linker.c
- @@ -229,16 +229,28 @@ SUBSUBSECTION
- @findex _bfd_generic_link_add_archive_symbols
- In most cases the work of looking through the symbols in the
- archive should be done by the
- - <<_bfd_generic_link_add_archive_symbols>> function.
- + <<_bfd_generic_link_add_archive_symbols>> function. This
- + function builds a hash table from the archive symbol table and
- + looks through the list of undefined symbols to see which
- + elements should be included.
- <<_bfd_generic_link_add_archive_symbols>> is passed a function
- to call to make the final decision about adding an archive
- element to the link and to do the actual work of adding the
- - symbols to the linker hash table. If the element is to
- + symbols to the linker hash table.
- +
- + The function passed to
- + <<_bfd_generic_link_add_archive_symbols>> must read the
- + symbols of the archive element and decide whether the archive
- + element should be included in the link. If the element is to
- be included, the <<add_archive_element>> linker callback
- routine must be called with the element as an argument, and
- the element's symbols must be added to the linker hash table
- just as though the element had itself been passed to the
- - <<_bfd_link_add_symbols>> function.
- + <<_bfd_link_add_symbols>> function. The <<add_archive_element>>
- + callback has the option to indicate that it would like to
- + replace the element archive with a substitute BFD, in which
- + case it is the symbols of that substitute BFD that must be
- + added to the linker hash table instead.
-
- When the a.out <<_bfd_link_add_symbols>> function receives an
- archive, it calls <<_bfd_generic_link_add_archive_symbols>>
- @@ -407,14 +419,11 @@ static bfd_boolean generic_link_add_object_symbols
- static bfd_boolean generic_link_add_symbols
- (bfd *, struct bfd_link_info *, bfd_boolean);
- static bfd_boolean generic_link_check_archive_element_no_collect
- - (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *);
- + (bfd *, struct bfd_link_info *, bfd_boolean *);
- static bfd_boolean generic_link_check_archive_element_collect
- - (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *);
- + (bfd *, struct bfd_link_info *, bfd_boolean *);
- static bfd_boolean generic_link_check_archive_element
- - (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *, bfd_boolean);
- + (bfd *, struct bfd_link_info *, bfd_boolean *, bfd_boolean);
- static bfd_boolean generic_link_add_symbol_list
- (bfd *, struct bfd_link_info *, bfd_size_type count, asymbol **,
- bfd_boolean);
- @@ -908,32 +917,138 @@ generic_link_add_object_symbols (bfd *abfd,
- return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
- }
-
- +/* We build a hash table of all symbols defined in an archive. */
- +
- +/* An archive symbol may be defined by multiple archive elements.
- + This linked list is used to hold the elements. */
- +
- +struct archive_list
- +{
- + struct archive_list *next;
- + unsigned int indx;
- +};
- +
- +/* An entry in an archive hash table. */
- +
- +struct archive_hash_entry
- +{
- + struct bfd_hash_entry root;
- + /* Where the symbol is defined. */
- + struct archive_list *defs;
- +};
- +
- +/* An archive hash table itself. */
- +
- +struct archive_hash_table
- +{
- + struct bfd_hash_table table;
- +};
- +
- +/* Create a new entry for an archive hash table. */
- +
- +static struct bfd_hash_entry *
- +archive_hash_newfunc (struct bfd_hash_entry *entry,
- + struct bfd_hash_table *table,
- + const char *string)
- +{
- + struct archive_hash_entry *ret = (struct archive_hash_entry *) entry;
- +
- + /* Allocate the structure if it has not already been allocated by a
- + subclass. */
- + if (ret == NULL)
- + ret = (struct archive_hash_entry *)
- + bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
- + if (ret == NULL)
- + return NULL;
- +
- + /* Call the allocation method of the superclass. */
- + ret = ((struct archive_hash_entry *)
- + bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
- +
- + if (ret)
- + {
- + /* Initialize the local fields. */
- + ret->defs = NULL;
- + }
- +
- + return &ret->root;
- +}
- +
- +/* Initialize an archive hash table. */
- +
- +static bfd_boolean
- +archive_hash_table_init
- + (struct archive_hash_table *table,
- + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *,
- + struct bfd_hash_table *,
- + const char *),
- + unsigned int entsize)
- +{
- + return bfd_hash_table_init (&table->table, newfunc, entsize);
- +}
- +
- +/* Look up an entry in an archive hash table. */
- +
- +#define archive_hash_lookup(t, string, create, copy) \
- + ((struct archive_hash_entry *) \
- + bfd_hash_lookup (&(t)->table, (string), (create), (copy)))
- +
- +/* Allocate space in an archive hash table. */
- +
- +#define archive_hash_allocate(t, size) bfd_hash_allocate (&(t)->table, (size))
- +
- +/* Free an archive hash table. */
- +
- +#define archive_hash_table_free(t) bfd_hash_table_free (&(t)->table)
- +
- /* Generic function to add symbols from an archive file to the global
- hash file. This function presumes that the archive symbol table
- has already been read in (this is normally done by the
- - bfd_check_format entry point). It looks through the archive symbol
- - table for symbols that are undefined or common in the linker global
- - symbol hash table. When one is found, the CHECKFN argument is used
- - to see if an object file should be included. This allows targets
- - to customize common symbol behaviour. CHECKFN should set *PNEEDED
- - to TRUE if the object file should be included, and must also call
- - the bfd_link_info add_archive_element callback function and handle
- - adding the symbols to the global hash table. CHECKFN must notice
- - if the callback indicates a substitute BFD, and arrange to add
- - those symbols instead if it does so. CHECKFN should only return
- - FALSE if some sort of error occurs. */
- + bfd_check_format entry point). It looks through the undefined and
- + common symbols and searches the archive symbol table for them. If
- + it finds an entry, it includes the associated object file in the
- + link.
- +
- + The old linker looked through the archive symbol table for
- + undefined symbols. We do it the other way around, looking through
- + undefined symbols for symbols defined in the archive. The
- + advantage of the newer scheme is that we only have to look through
- + the list of undefined symbols once, whereas the old method had to
- + re-search the symbol table each time a new object file was added.
- +
- + The CHECKFN argument is used to see if an object file should be
- + included. CHECKFN should set *PNEEDED to TRUE if the object file
- + should be included, and must also call the bfd_link_info
- + add_archive_element callback function and handle adding the symbols
- + to the global hash table. CHECKFN must notice if the callback
- + indicates a substitute BFD, and arrange to add those symbols instead
- + if it does so. CHECKFN should only return FALSE if some sort of
- + error occurs.
- +
- + For some formats, such as a.out, it is possible to look through an
- + object file but not actually include it in the link. The
- + archive_pass field in a BFD is used to avoid checking the symbols
- + of an object files too many times. When an object is included in
- + the link, archive_pass is set to -1. If an object is scanned but
- + not included, archive_pass is set to the pass number. The pass
- + number is incremented each time a new object file is included. The
- + pass number is used because when a new object file is included it
- + may create new undefined symbols which cause a previously examined
- + object file to be included. */
-
- bfd_boolean
- _bfd_generic_link_add_archive_symbols
- (bfd *abfd,
- struct bfd_link_info *info,
- - bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *,
- - struct bfd_link_hash_entry *, const char *,
- - bfd_boolean *))
- + bfd_boolean (*checkfn) (bfd *, struct bfd_link_info *, bfd_boolean *))
- {
- - bfd_boolean loop;
- - bfd_size_type amt;
- - unsigned char *included;
- + carsym *arsyms;
- + carsym *arsym_end;
- + register carsym *arsym;
- + int pass;
- + struct archive_hash_table arsym_hash;
- + unsigned int indx;
- + struct bfd_link_hash_entry **pundef;
-
- if (! bfd_has_map (abfd))
- {
- @@ -944,103 +1059,148 @@ _bfd_generic_link_add_archive_symbols
- return FALSE;
- }
-
- - amt = bfd_ardata (abfd)->symdef_count;
- - if (amt == 0)
- - return TRUE;
- - amt *= sizeof (*included);
- - included = (unsigned char *) bfd_zmalloc (amt);
- - if (included == NULL)
- + arsyms = bfd_ardata (abfd)->symdefs;
- + arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
- +
- + /* In order to quickly determine whether an symbol is defined in
- + this archive, we build a hash table of the symbols. */
- + if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc,
- + sizeof (struct archive_hash_entry)))
- return FALSE;
- + for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
- + {
- + struct archive_hash_entry *arh;
- + struct archive_list *l, **pp;
-
- - do
- + arh = archive_hash_lookup (&arsym_hash, arsym->name, TRUE, FALSE);
- + if (arh == NULL)
- + goto error_return;
- + l = ((struct archive_list *)
- + archive_hash_allocate (&arsym_hash, sizeof (struct archive_list)));
- + if (l == NULL)
- + goto error_return;
- + l->indx = indx;
- + for (pp = &arh->defs; *pp != NULL; pp = &(*pp)->next)
- + ;
- + *pp = l;
- + l->next = NULL;
- + }
- +
- + /* The archive_pass field in the archive itself is used to
- + initialize PASS, sine we may search the same archive multiple
- + times. */
- + pass = abfd->archive_pass + 1;
- +
- + /* New undefined symbols are added to the end of the list, so we
- + only need to look through it once. */
- + pundef = &info->hash->undefs;
- + while (*pundef != NULL)
- {
- - carsym *arsyms;
- - carsym *arsym_end;
- - carsym *arsym;
- - unsigned int indx;
- - file_ptr last_ar_offset = -1;
- - bfd_boolean needed = FALSE;
- - bfd *element = NULL;
- -
- - loop = FALSE;
- - arsyms = bfd_ardata (abfd)->symdefs;
- - arsym_end = arsyms + bfd_ardata (abfd)->symdef_count;
- - for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++)
- + struct bfd_link_hash_entry *h;
- + struct archive_hash_entry *arh;
- + struct archive_list *l;
- +
- + h = *pundef;
- +
- + /* When a symbol is defined, it is not necessarily removed from
- + the list. */
- + if (h->type != bfd_link_hash_undefined
- + && h->type != bfd_link_hash_common)
- {
- - struct bfd_link_hash_entry *h;
- - struct bfd_link_hash_entry *undefs_tail;
- + /* Remove this entry from the list, for general cleanliness
- + and because we are going to look through the list again
- + if we search any more libraries. We can't remove the
- + entry if it is the tail, because that would lose any
- + entries we add to the list later on (it would also cause
- + us to lose track of whether the symbol has been
- + referenced). */
- + if (*pundef != info->hash->undefs_tail)
- + *pundef = (*pundef)->u.undef.next;
- + else
- + pundef = &(*pundef)->u.undef.next;
- + continue;
- + }
-
- - if (included[indx])
- - continue;
- - if (needed && arsym->file_offset == last_ar_offset)
- + /* Look for this symbol in the archive symbol map. */
- + arh = archive_hash_lookup (&arsym_hash, h->root.string, FALSE, FALSE);
- + if (arh == NULL)
- + {
- + /* If we haven't found the exact symbol we're looking for,
- + let's look for its import thunk */
- + if (info->pei386_auto_import)
- + {
- + bfd_size_type amt = strlen (h->root.string) + 10;
- + char *buf = (char *) bfd_malloc (amt);
- + if (buf == NULL)
- + return FALSE;
- +
- + sprintf (buf, "__imp_%s", h->root.string);
- + arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
- + free(buf);
- + }
- + if (arh == NULL)
- {
- - included[indx] = 1;
- + pundef = &(*pundef)->u.undef.next;
- continue;
- }
- + }
- + /* Look at all the objects which define this symbol. */
- + for (l = arh->defs; l != NULL; l = l->next)
- + {
- + bfd *element;
- + bfd_boolean needed;
- +
- + /* If the symbol has gotten defined along the way, quit. */
- + if (h->type != bfd_link_hash_undefined
- + && h->type != bfd_link_hash_common)
- + break;
-
- - h = bfd_link_hash_lookup (info->hash, arsym->name,
- - FALSE, FALSE, TRUE);
- + element = bfd_get_elt_at_index (abfd, l->indx);
- + if (element == NULL)
- + goto error_return;
-
- - if (h == NULL
- - && info->pei386_auto_import
- - && CONST_STRNEQ (arsym->name, "__imp_"))
- - h = bfd_link_hash_lookup (info->hash, arsym->name + 6,
- - FALSE, FALSE, TRUE);
- - if (h == NULL)
- + /* If we've already included this element, or if we've
- + already checked it on this pass, continue. */
- + if (element->archive_pass == -1
- + || element->archive_pass == pass)
- continue;
-
- - if (h->type != bfd_link_hash_undefined
- - && h->type != bfd_link_hash_common)
- + /* If we can't figure this element out, just ignore it. */
- + if (! bfd_check_format (element, bfd_object))
- {
- - if (h->type != bfd_link_hash_undefweak)
- - /* Symbol must be defined. Don't check it again. */
- - included[indx] = 1;
- + element->archive_pass = -1;
- continue;
- }
-
- - if (last_ar_offset != arsym->file_offset)
- - {
- - last_ar_offset = arsym->file_offset;
- - element = _bfd_get_elt_at_filepos (abfd, last_ar_offset);
- - if (element == NULL
- - || !bfd_check_format (element, bfd_object))
- - goto error_return;
- - }
- -
- - undefs_tail = info->hash->undefs_tail;
- -
- /* CHECKFN will see if this element should be included, and
- go ahead and include it if appropriate. */
- - if (! (*checkfn) (element, info, h, arsym->name, &needed))
- + if (! (*checkfn) (element, info, &needed))
- goto error_return;
-
- - if (needed)
- + if (! needed)
- + element->archive_pass = pass;
- + else
- {
- - unsigned int mark;
- + element->archive_pass = -1;
-
- - /* Look backward to mark all symbols from this object file
- - which we have already seen in this pass. */
- - mark = indx;
- - do
- - {
- - included[mark] = 1;
- - if (mark == 0)
- - break;
- - --mark;
- - }
- - while (arsyms[mark].file_offset == last_ar_offset);
- -
- - if (undefs_tail != info->hash->undefs_tail)
- - loop = TRUE;
- + /* Increment the pass count to show that we may need to
- + recheck object files which were already checked. */
- + ++pass;
- }
- }
- - } while (loop);
-
- - free (included);
- + pundef = &(*pundef)->u.undef.next;
- + }
- +
- + archive_hash_table_free (&arsym_hash);
- +
- + /* Save PASS in case we are called again. */
- + abfd->archive_pass = pass;
- +
- return TRUE;
-
- error_return:
- - free (included);
- + archive_hash_table_free (&arsym_hash);
- return FALSE;
- }
-
- @@ -1050,14 +1210,12 @@ _bfd_generic_link_add_archive_symbols
- for finding them. */
-
- static bfd_boolean
- -generic_link_check_archive_element_no_collect (bfd *abfd,
- +generic_link_check_archive_element_no_collect (
- + bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h,
- - const char *name,
- bfd_boolean *pneeded)
- {
- - return generic_link_check_archive_element (abfd, info, h, name, pneeded,
- - FALSE);
- + return generic_link_check_archive_element (abfd, info, pneeded, FALSE);
- }
-
- /* See if we should include an archive element. This version is used
- @@ -1067,12 +1225,9 @@ generic_link_check_archive_element_no_collect (bfd *abfd,
- static bfd_boolean
- generic_link_check_archive_element_collect (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h,
- - const char *name,
- bfd_boolean *pneeded)
- {
- - return generic_link_check_archive_element (abfd, info, h, name, pneeded,
- - TRUE);
- + return generic_link_check_archive_element (abfd, info, pneeded, TRUE);
- }
-
- /* See if we should include an archive element. Optionally collect
- @@ -1081,8 +1236,6 @@ generic_link_check_archive_element_collect (bfd *abfd,
- static bfd_boolean
- generic_link_check_archive_element (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h,
- - const char *name ATTRIBUTE_UNUSED,
- bfd_boolean *pneeded,
- bfd_boolean collect)
- {
- @@ -1098,6 +1251,7 @@ generic_link_check_archive_element (bfd *abfd,
- for (; pp < ppend; pp++)
- {
- asymbol *p;
- + struct bfd_link_hash_entry *h;
-
- p = *pp;
-
- diff --git a/bfd/pdp11.c b/bfd/pdp11.c
- index 593c5ca..5111a51 100644
- --- a/bfd/pdp11.c
- +++ b/bfd/pdp11.c
- @@ -251,7 +251,7 @@ HOWTO( 1, 0, 1, 16, TRUE, 0, complain_overflow_signed,0,"DISP16", TRU
- #define TABLE_SIZE(TABLE) (sizeof(TABLE)/sizeof(TABLE[0]))
-
-
- -static bfd_boolean aout_link_check_archive_element (bfd *, struct bfd_link_info *, struct bfd_link_hash_entry *, const char *, bfd_boolean *);
- +static bfd_boolean aout_link_check_archive_element (bfd *, struct bfd_link_info *, bfd_boolean *);
- static bfd_boolean aout_link_add_object_symbols (bfd *, struct bfd_link_info *);
- static bfd_boolean aout_link_add_symbols (bfd *, struct bfd_link_info *);
- static bfd_boolean aout_link_write_symbols (struct aout_final_link_info *, bfd *);
- @@ -2682,8 +2682,6 @@ aout_link_check_ar_symbols (bfd *abfd,
- static bfd_boolean
- aout_link_check_archive_element (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
- - const char *name ATTRIBUTE_UNUSED,
- bfd_boolean *pneeded)
- {
- bfd *oldbfd;
- diff --git a/bfd/xcofflink.c b/bfd/xcofflink.c
- index 9522974..dcfd58f 100644
- --- a/bfd/xcofflink.c
- +++ b/bfd/xcofflink.c
- @@ -2384,8 +2384,6 @@ xcoff_link_check_ar_symbols (bfd *abfd,
- static bfd_boolean
- xcoff_link_check_archive_element (bfd *abfd,
- struct bfd_link_info *info,
- - struct bfd_link_hash_entry *h ATTRIBUTE_UNUSED,
- - const char *name ATTRIBUTE_UNUSED,
- bfd_boolean *pneeded)
- {
- bfd_boolean keep_syms_p;
- @@ -2465,7 +2463,7 @@ _bfd_xcoff_bfd_link_add_symbols (bfd *abfd, struct bfd_link_info *info)
- bfd_boolean needed;
-
- if (! xcoff_link_check_archive_element (member, info,
- - NULL, NULL, &needed))
- + &needed))
- return FALSE;
- if (needed)
- member->archive_pass = -1;
|