From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 23770 invoked by alias); 19 Jul 2006 01:54:04 -0000 Received: (qmail 23239 invoked by uid 22791); 19 Jul 2006 01:54:02 -0000 X-Spam-Check-By: sourceware.org Received: from omta03ps.mx.bigpond.com (HELO omta03ps.mx.bigpond.com) (144.140.82.155) by sourceware.org (qpsmtpd/0.31) with ESMTP; Wed, 19 Jul 2006 01:54:00 +0000 Received: from grove.modra.org ([60.226.255.233]) by omta03ps.mx.bigpond.com with ESMTP id <20060719015356.PRRW21217.omta03ps.mx.bigpond.com@grove.modra.org>; Wed, 19 Jul 2006 01:53:56 +0000 Received: by bubble.grove.modra.org (Postfix, from userid 500) id 0382C1DD3A6; Wed, 19 Jul 2006 11:23:55 +0930 (CST) Date: Wed, 19 Jul 2006 01:54:00 -0000 From: Alan Modra To: "H. J. Lu" , Paul Nash , binutils@sourceware.org Subject: Re: binutils-2.17: --cref broken? Extra warnings and corrupted data Message-ID: <20060719015355.GP18571@bubble.grove.modra.org> Mail-Followup-To: "H. J. Lu" , Paul Nash , binutils@sourceware.org References: <20060717020350.GH18571@bubble.grove.modra.org> <20060717223053.GA11150@lucon.org> <20060718030409.GN18571@bubble.grove.modra.org> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20060718030409.GN18571@bubble.grove.modra.org> User-Agent: Mutt/1.4i X-IsSubscribed: yes Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org X-SW-Source: 2006-07/txt/msg00245.txt.bz2 On Tue, Jul 18, 2006 at 12:34:09PM +0930, Alan Modra wrote: > On Mon, Jul 17, 2006 at 03:30:53PM -0700, H. J. Lu wrote: > > --cref was broken by --as-needed. > > Ah. My bug then. This extends the horrible hack of saving the main symbol table to saving the cref table too. I'm not proud at all of this hack for --as-needed. Some day when I have a some time on my hands I'll look at implementing a two-pass approach to loading --as-needed library syms. 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. Index: bfd/bfd-in.h =================================================================== RCS file: /cvs/src/src/bfd/bfd-in.h,v retrieving revision 1.115 diff -u -p -r1.115 bfd-in.h --- bfd/bfd-in.h 15 May 2006 19:57:34 -0000 1.115 +++ bfd/bfd-in.h 18 Jul 2006 11:15:14 -0000 @@ -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); Index: bfd/elflink.c =================================================================== RCS file: /cvs/src/src/bfd/elflink.c,v retrieving revision 1.224 diff -u -p -r1.224 elflink.c --- bfd/elflink.c 14 Jul 2006 13:48:06 -0000 1.224 +++ bfd/elflink.c 18 Jul 2006 11:15:39 -0000 @@ -3551,6 +3551,13 @@ elf_link_add_object_symbols (bfd *abfd, 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, } } + /* 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, if (old_tab != NULL) { + if (!(*info->callbacks->notice) (info, NULL, abfd, NULL, + notice_needed)) + return FALSE; free (old_tab); old_tab = NULL; } Index: ld/ld.h =================================================================== RCS file: /cvs/src/src/ld/ld.h,v retrieving revision 1.31 diff -u -p -r1.31 ld.h --- ld/ld.h 30 May 2006 16:45:31 -0000 1.31 +++ ld/ld.h 18 Jul 2006 11:16:11 -0000 @@ -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; Index: ld/ldcref.c =================================================================== RCS file: /cvs/src/src/ld/ldcref.c,v retrieving revision 1.14 diff -u -p -r1.14 ldcref.c --- ld/ldcref.c 16 Mar 2006 12:20:16 -0000 1.14 +++ ld/ldcref.c 18 Jul 2006 11:16:12 -0000 @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street - F #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. */ Index: ld/ldmain.c =================================================================== RCS file: /cvs/src/src/ld/ldmain.c,v retrieving revision 1.108 diff -u -p -r1.108 ldmain.c --- ld/ldmain.c 10 Jul 2006 21:40:22 -0000 1.108 +++ ld/ldmain.c 18 Jul 2006 11:16:12 -0000 @@ -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)) -- Alan Modra IBM OzLabs - Linux Technology Centre