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.
This commit is contained in:
parent
9148c4581c
commit
5061a8853b
@ -1,3 +1,10 @@
|
||||
2006-07-19 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* 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 <paul@codesourcery.com>
|
||||
|
||||
* bfd-in2.h: Regenerate.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
10
ld/ChangeLog
10
ld/ChangeLog
@ -1,3 +1,13 @@
|
||||
2006-07-19 Alan Modra <amodra@bigpond.net.au>
|
||||
|
||||
* 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 <mike.wetherell@ntlworld.com>
|
||||
|
||||
* configure.tgt (i[3-7]86-*-solaris2*, i[3-7]86-*-solaris*): Correct
|
||||
|
3
ld/ld.h
3
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;
|
||||
|
134
ld/ldcref.c
134
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. */
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user