X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=ld%2Fldcref.c;h=fb1d3c907f3141947edc023c1a7fe0ac6f73d101;hb=4e9862571357457fa20df6fb0650807d5fb5ea94;hp=10f32ca3f8b4be6e2bf02068cf78112db646518c;hpb=09c112daa3a9b33a03b9272da7e9e19e8d63dc91;p=deliverable%2Fbinutils-gdb.git diff --git a/ld/ldcref.c b/ld/ldcref.c index 10f32ca3f8..fb1d3c907f 100644 --- a/ld/ldcref.c +++ b/ld/ldcref.c @@ -1,5 +1,5 @@ /* ldcref.c -- output a cross reference table - Copyright 1996, 1997, 1998, 2000, 2002, 2003 + Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. Written by Ian Lance Taylor @@ -17,7 +17,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ /* This file holds routines that manage the cross reference table. The table is used to generate cross reference reports. It is also @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "sysdep.h" #include "bfdlink.h" #include "libiberty.h" +#include "objalloc.h" #include "ld.h" #include "ldmain.h" @@ -71,7 +72,7 @@ struct cref_hash_table { static void output_one_cref (FILE *, struct cref_hash_entry *); static void check_local_sym_xref (lang_input_statement_type *); static bfd_boolean check_nocrossref (struct cref_hash_entry *, void *); -static void check_refs (const char *, asection *, bfd *, +static void check_refs (const char *, bfd_boolean, asection *, bfd *, struct lang_nocrossrefs *); static void check_reloc_refs (bfd *, asection *, void *); @@ -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 * @@ -149,7 +160,8 @@ add_cref (const char *name, if (! cref_initialized) { - if (! bfd_hash_table_init (&cref_table.root, cref_hash_newfunc)) + if (!bfd_hash_table_init (&cref_table.root, cref_hash_newfunc, + sizeof (struct cref_hash_entry))) einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n")); cref_initialized = TRUE; } @@ -164,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; @@ -181,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. */ @@ -387,7 +520,7 @@ check_local_sym_xref (lang_input_statement_type *statement) for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next) for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) if (strcmp (ncr->name, outsecname) == 0) - check_refs (symname, sym->section, abfd, ncrs); + check_refs (symname, FALSE, sym->section, abfd, ncrs); } } @@ -429,7 +562,8 @@ check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED) for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next) if (strcmp (ncr->name, defsecname) == 0) for (ref = h->refs; ref != NULL; ref = ref->next) - check_refs (hl->root.string, hl->u.def.section, ref->abfd, ncrs); + check_refs (hl->root.string, TRUE, hl->u.def.section, + ref->abfd, ncrs); return TRUE; } @@ -442,6 +576,7 @@ struct check_refs_info { asection *defsec; struct lang_nocrossrefs *ncrs; asymbol **asymbols; + bfd_boolean global; }; /* This function is called for each symbol defined in a section which @@ -451,6 +586,7 @@ struct check_refs_info { static void check_refs (const char *name, + bfd_boolean global, asection *sec, bfd *abfd, struct lang_nocrossrefs *ncrs) @@ -488,6 +624,7 @@ check_refs (const char *name, } info.sym_name = name; + info.global = global; info.defsec = sec; info.ncrs = ncrs; info.asymbols = asymbols; @@ -513,6 +650,7 @@ check_reloc_refs (bfd *abfd, asection *sec, void *iarg) const char *outdefsecname; struct lang_nocrossref *ncr; const char *symname; + bfd_boolean global; long relsize; arelent **relpp; long relcount; @@ -538,9 +676,13 @@ check_reloc_refs (bfd *abfd, asection *sec, void *iarg) /* This section is one for which cross references are prohibited. Look through the relocations, and see if any of them are to INFO->SYM_NAME. If INFO->SYMNAME is NULL, check for relocations - against the section symbol. */ + against the section symbol. If INFO->GLOBAL is TRUE, the + definition is global, check for relocations against the global + symbols. Otherwise check for relocations against the local and + section symbols. */ symname = info->sym_name; + global = info->global; relsize = bfd_get_reloc_upper_bound (abfd, sec); if (relsize < 0) @@ -561,6 +703,14 @@ check_reloc_refs (bfd *abfd, asection *sec, void *iarg) if (q->sym_ptr_ptr != NULL && *q->sym_ptr_ptr != NULL + && ((global + && (bfd_is_und_section (bfd_get_section (*q->sym_ptr_ptr)) + || bfd_is_com_section (bfd_get_section (*q->sym_ptr_ptr)) + || ((*q->sym_ptr_ptr)->flags & (BSF_GLOBAL + | BSF_WEAK)) != 0)) + || (!global + && ((*q->sym_ptr_ptr)->flags & (BSF_LOCAL + | BSF_SECTION_SYM)) != 0)) && (symname != NULL ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0 : (((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0