aboutsummaryrefslogtreecommitdiff
path: root/bfd/cofflink.c
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2014-08-05 10:46:57 +0930
committerAlan Modra <amodra@gmail.com>2014-08-05 10:46:57 +0930
commit13e570f80cbfb299a8858ce6830e91a6cb40ab7b (patch)
tree771ad9d8322d503019dff64816234bd09566e21c /bfd/cofflink.c
parent241fd515ad94fa11d4608d4fe8108c382792d3be (diff)
downloadbinutils-13e570f80cbfb299a8858ce6830e91a6cb40ab7b.zip
binutils-13e570f80cbfb299a8858ce6830e91a6cb40ab7b.tar.gz
binutils-13e570f80cbfb299a8858ce6830e91a6cb40ab7b.tar.bz2
Fix LTO vs. COFF archives
Avoid scan of symbols on objects in coff archives since we don't need to do anything special with common symbols. The scan is quite useless, and breaks LTO due to slim LTO objects not having symbols available until after the plugin has claimed them. Instead we can add objects based on their archive symbol map. Also, rip out the archive symbol hash table used by the generic linker. Using a hash breaks one feature of unix archive linking; The first object file in an archive defining any given symbol should be the object extracted to satisfy that symbol. What's more a hash isn't much faster except in pathological cases where object file ordering causes many scans of the archive. See the comment which I'm removing from elf_link_add_archive_symbols. Finally, tidy elflink.c archive handling a little. PR 13557 * linker.c (struct archive_list, struct archive_hash_entry, struct archive_hash_table, archive_hash_newfunc, archive_hash_table_init, archive_hash_lookup, archive_hash_allocate, archive_hash_table_free): Delete. (_bfd_generic_link_add_archive_symbols): Add h and name params to checkfn. Rewrite using a straight-forward scan over archive map. (generic_link_check_archive_element_no_collect, generic_link_check_archive_element_collect, generic_link_check_archive_element): Add h and name params. * aoutx.h (aout_link_check_archive_element): Likewise. * pdp11.c (aout_link_check_archive_element): Likewise. * xcofflink.c (xcoff_link_check_archive_element): Likewise. * cofflink.c (coff_link_check_archive_element): Likewise. Don't scan symbols, simply add archive element whenever h is undefined. (coff_link_check_ar_symbols): Delete. * ecoff.c (read_ext_syms_and_strs): Delete. (reread_ext_syms_and_strs): Delete. (ecoff_link_check_archive_element): Add h and name param. Don't scan symbols, simply add based on h. Use ecoff_link_add_object_symbols. * elflink.c (elf_link_is_defined_archive_symbol): Don't test archive_pass. (elf_link_add_archive_symbols): Delete "defined" array, merge functionality into "included". Make "included" a char array. Don't set or test archive_pass. * libbfd-in.h (_bfd_generic_link_add_archive_symbols): Update. * libbfd.h: Regenerate.
Diffstat (limited to 'bfd/cofflink.c')
-rw-r--r--bfd/cofflink.c116
1 files changed, 16 insertions, 100 deletions
diff --git a/bfd/cofflink.c b/bfd/cofflink.c
index d4e3345..8c3f71b 100644
--- a/bfd/cofflink.c
+++ b/bfd/cofflink.c
@@ -29,9 +29,11 @@
#include "libcoff.h"
#include "safe-ctype.h"
-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);
+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 *);
/* Return TRUE if SYM is a weak, external symbol. */
#define IS_WEAK_EXTERNAL(abfd, sym) \
@@ -190,74 +192,6 @@ 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
@@ -266,41 +200,23 @@ coff_link_check_ar_symbols (bfd *abfd,
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)
{
- bfd *oldbfd;
- bfd_boolean needed;
+ *pneeded = FALSE;
- if (!_bfd_coff_get_external_symbols (abfd))
- return FALSE;
+ /* 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;
- oldbfd = abfd;
- if (!coff_link_check_ar_symbols (abfd, info, pneeded, &abfd))
+ if (!(*info->callbacks->add_archive_element) (info, abfd, name, &abfd))
return FALSE;
+ *pneeded = TRUE;
- 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;
+ return coff_link_add_object_symbols (abfd, info);
}
/* Add all the symbols from an object file to the hash table. */