From 5061a8853b6f8fb5af87b8ff4a0f7a2460ad333b Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Wed, 19 Jul 2006 01:50:23 +0000 Subject: [PATCH] bfd/ * bfd-in.h (enum notice_asneeded_action): Define. * bfd-in2.h: Regenerate. * elflink.c (elf_link_add_object_symbols): Call linker "notice" function with NULL name for as-needed handling. ld/ * ld.h (handle_asneeded_cref): Declare. * ldcref.c: Include objalloc.h. (old_table, old_count, old_tab, alloc_mark): New variables. (tabsize, entsize, refsize, old_symcount): Likewise. (add_cref): Use bfd_hash_allocate for refs. (handle_asneeded_cref): New function. * ldmain.c (notice): Call handle_asneeded_cref for NULL name. --- bfd/ChangeLog | 7 +++ bfd/bfd-in.h | 6 +++ bfd/bfd-in2.h | 6 +++ bfd/elflink.c | 16 +++++++ ld/ChangeLog | 10 +++++ ld/ld.h | 3 +- ld/ldcref.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- ld/ldmain.c | 7 +++ 8 files changed, 187 insertions(+), 2 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 4ce004e..55e6b54 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,10 @@ +2006-07-19 Alan Modra + + * bfd-in.h (enum notice_asneeded_action): Define. + * bfd-in2.h: Regenerate. + * elflink.c (elf_link_add_object_symbols): Call linker "notice" + function with NULL name for as-needed handling. + 2006-07-18 Paul Brook * bfd-in2.h: Regenerate. diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index ff9dcd6..6ceb0db 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -638,6 +638,12 @@ enum dynamic_lib_link_class { DYN_NO_NEEDED = 8 }; +enum notice_asneeded_action { + notice_as_needed, + notice_not_needed, + notice_needed +}; + extern bfd_boolean bfd_elf_record_link_assignment (bfd *, struct bfd_link_info *, const char *, bfd_boolean, bfd_boolean); diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 381ae55..b75c8e2 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -645,6 +645,12 @@ enum dynamic_lib_link_class { DYN_NO_NEEDED = 8 }; +enum notice_asneeded_action { + notice_as_needed, + notice_not_needed, + notice_needed +}; + extern bfd_boolean bfd_elf_record_link_assignment (bfd *, struct bfd_link_info *, const char *, bfd_boolean, bfd_boolean); diff --git a/bfd/elflink.c b/bfd/elflink.c index c52b42e..99f0acc 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -3551,6 +3551,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (alloc_mark == NULL) goto error_free_vers; + /* Make a special call to the linker "notice" function to + tell it that we are about to handle an as-needed lib. */ + if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, + notice_as_needed)) + return FALSE; + + /* Clone the symbol table and sym hashes. Remember some pointers into the symbol table, and dynamic symbol count. */ old_hash = (char *) old_tab + tabsize; @@ -4241,6 +4248,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } } + /* Make a special call to the linker "notice" function to + tell it that symbols added for crefs may need to be removed. */ + if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, + notice_not_needed)) + return FALSE; + free (old_tab); objalloc_free_block ((struct objalloc *) htab->root.table.memory, alloc_mark); @@ -4251,6 +4264,9 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (old_tab != NULL) { + if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, + notice_needed)) + return FALSE; free (old_tab); old_tab = NULL; } diff --git a/ld/ChangeLog b/ld/ChangeLog index bb51a4a..14c5a2a 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2006-07-19 Alan Modra + + * ld.h (handle_asneeded_cref): Declare. + * ldcref.c: Include objalloc.h. + (old_table, old_count, old_tab, alloc_mark): New variables. + (tabsize, entsize, refsize, old_symcount): Likewise. + (add_cref): Use bfd_hash_allocate for refs. + (handle_asneeded_cref): New function. + * ldmain.c (notice): Call handle_asneeded_cref for NULL name. + 2006-07-14 Michael Wetherell * configure.tgt (i[3-7]86-*-solaris2*, i[3-7]86-*-solaris*): Correct diff --git a/ld/ld.h b/ld/ld.h index 174e5b9..0b574d5 100644 --- a/ld/ld.h +++ b/ld/ld.h @@ -1,6 +1,6 @@ /* ld.h -- general linker header file Copyright 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, - 2001, 2002, 2003, 2004, 2005 + 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GLD, the Gnu Linker. @@ -288,6 +288,7 @@ extern int parsing_defsym; extern int yyparse (void); extern void add_cref (const char *, bfd *, asection *, bfd_vma); +extern bfd_boolean handle_asneeded_cref (bfd *, enum notice_asneeded_action); extern void output_cref (FILE *); extern void check_nocrossrefs (void); extern void ld_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; diff --git a/ld/ldcref.c b/ld/ldcref.c index 7445aa8..fb1d3c9 100644 --- a/ld/ldcref.c +++ b/ld/ldcref.c @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. #include "sysdep.h" #include "bfdlink.h" #include "libiberty.h" +#include "objalloc.h" #include "ld.h" #include "ldmain.h" @@ -101,6 +102,16 @@ static bfd_boolean cref_initialized; static size_t cref_symcount; +/* Used to take a snapshot of the cref hash table when starting to + add syms from an as-needed library. */ +static struct bfd_hash_entry **old_table; +static unsigned int old_size; +static unsigned int old_count; +static void *old_tab; +static void *alloc_mark; +static size_t tabsize, entsize, refsize; +static size_t old_symcount; + /* Create an entry in a cref hash table. */ static struct bfd_hash_entry * @@ -165,7 +176,9 @@ add_cref (const char *name, if (r == NULL) { - r = xmalloc (sizeof *r); + r = bfd_hash_allocate (&cref_table.root, sizeof *r); + if (r == NULL) + einfo (_("%X%P: cref alloc failed: %E\n")); r->next = h->refs; h->refs = r; r->abfd = abfd; @@ -182,6 +195,125 @@ add_cref (const char *name, r->def = TRUE; } +/* Called before loading an as-needed library to take a snapshot of + the cref hash table, and after we have loaded or found that the + library was not needed. */ + +bfd_boolean +handle_asneeded_cref (bfd *abfd ATTRIBUTE_UNUSED, + enum notice_asneeded_action act) +{ + unsigned int i; + + if (!cref_initialized) + return TRUE; + + if (act == notice_as_needed) + { + char *old_ent, *old_ref; + + for (i = 0; i < cref_table.root.size; i++) + { + struct bfd_hash_entry *p; + struct cref_hash_entry *c; + struct cref_ref *r; + + for (p = cref_table.root.table[i]; p != NULL; p = p->next) + { + entsize += cref_table.root.entsize; + c = (struct cref_hash_entry *) p; + for (r = c->refs; r != NULL; r = r->next) + refsize += sizeof (struct cref_hash_entry); + } + } + + tabsize = cref_table.root.size * sizeof (struct bfd_hash_entry *); + old_tab = xmalloc (tabsize + entsize + refsize); + + alloc_mark = bfd_hash_allocate (&cref_table.root, 1); + if (alloc_mark == NULL) + return FALSE; + + memcpy (old_tab, cref_table.root.table, tabsize); + old_ent = (char *) old_tab + tabsize; + old_ref = (char *) old_ent + entsize; + old_table = cref_table.root.table; + old_size = cref_table.root.size; + old_count = cref_table.root.count; + old_symcount = cref_symcount; + + for (i = 0; i < cref_table.root.size; i++) + { + struct bfd_hash_entry *p; + struct cref_hash_entry *c; + struct cref_ref *r; + + for (p = cref_table.root.table[i]; p != NULL; p = p->next) + { + memcpy (old_ent, p, cref_table.root.entsize); + old_ent = (char *) old_ent + cref_table.root.entsize; + c = (struct cref_hash_entry *) p; + for (r = c->refs; r != NULL; r = r->next) + { + memcpy (old_ref, r, sizeof (struct cref_hash_entry)); + old_ref = (char *) old_ref + sizeof (struct cref_hash_entry); + } + } + } + return TRUE; + } + + if (act == notice_not_needed) + { + char *old_ent, *old_ref; + + if (old_tab == NULL) + { + /* The only way old_tab can be NULL is if the cref hash table + had not been initialised when notice_as_needed. */ + bfd_hash_table_free (&cref_table.root); + cref_initialized = FALSE; + return TRUE; + } + + old_ent = (char *) old_tab + tabsize; + old_ref = (char *) old_ent + entsize; + cref_table.root.table = old_table; + cref_table.root.size = old_size; + cref_table.root.count = old_count; + memcpy (cref_table.root.table, old_tab, tabsize); + cref_symcount = old_symcount; + + for (i = 0; i < cref_table.root.size; i++) + { + struct bfd_hash_entry *p; + struct cref_hash_entry *c; + struct cref_ref *r; + + for (p = cref_table.root.table[i]; p != NULL; p = p->next) + { + memcpy (p, old_ent, cref_table.root.entsize); + old_ent = (char *) old_ent + cref_table.root.entsize; + c = (struct cref_hash_entry *) p; + for (r = c->refs; r != NULL; r = r->next) + { + memcpy (r, old_ref, sizeof (struct cref_hash_entry)); + old_ref = (char *) old_ref + sizeof (struct cref_hash_entry); + } + } + } + + objalloc_free_block ((struct objalloc *) cref_table.root.memory, + alloc_mark); + } + else if (act != notice_needed) + return FALSE; + + free (old_tab); + old_tab = NULL; + return TRUE; +} + /* Copy the addresses of the hash table entries into an array. This is called via cref_hash_traverse. We also fill in the demangled name. */ diff --git a/ld/ldmain.c b/ld/ldmain.c index ec31310..cb56a8d 100644 --- a/ld/ldmain.c +++ b/ld/ldmain.c @@ -1523,6 +1523,13 @@ notice (struct bfd_link_info *info, asection *section, bfd_vma value) { + if (name == NULL) + { + if (command_line.cref || nocrossref_list != NULL) + return handle_asneeded_cref (abfd, value); + return TRUE; + } + if (! info->notice_all || (info->notice_hash != NULL && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)) -- 2.7.4