This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: binutils-2.17: --cref broken? Extra warnings and corrupted data
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