Line 1... |
Line 1... |
/* linker.c -- BFD linker routines
|
/* linker.c -- BFD linker routines
|
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
|
2003, 2004, 2005, 2006, 2007, 2008
|
2003, 2004, 2005, 2006, 2007, 2008, 2009
|
Free Software Foundation, Inc.
|
Free Software Foundation, Inc.
|
Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
|
Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support
|
|
|
This file is part of BFD, the Binary File Descriptor library.
|
This file is part of BFD, the Binary File Descriptor library.
|
|
|
Line 442... |
Line 442... |
{
|
{
|
/* Allocate the structure if it has not already been allocated by a
|
/* Allocate the structure if it has not already been allocated by a
|
subclass. */
|
subclass. */
|
if (entry == NULL)
|
if (entry == NULL)
|
{
|
{
|
entry = bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
|
entry = (struct bfd_hash_entry *)
|
|
bfd_hash_allocate (table, sizeof (struct bfd_link_hash_entry));
|
if (entry == NULL)
|
if (entry == NULL)
|
return entry;
|
return entry;
|
}
|
}
|
|
|
/* Call the allocation method of the superclass. */
|
/* Call the allocation method of the superclass. */
|
Line 546... |
Line 547... |
|
|
/* This symbol is being wrapped. We want to replace all
|
/* This symbol is being wrapped. We want to replace all
|
references to SYM with references to __wrap_SYM. */
|
references to SYM with references to __wrap_SYM. */
|
|
|
amt = strlen (l) + sizeof WRAP + 1;
|
amt = strlen (l) + sizeof WRAP + 1;
|
n = bfd_malloc (amt);
|
n = (char *) bfd_malloc (amt);
|
if (n == NULL)
|
if (n == NULL)
|
return NULL;
|
return NULL;
|
|
|
n[0] = prefix;
|
n[0] = prefix;
|
n[1] = '\0';
|
n[1] = '\0';
|
Line 577... |
Line 578... |
/* This is a reference to __real_SYM, where SYM is being
|
/* This is a reference to __real_SYM, where SYM is being
|
wrapped. We want to replace all references to __real_SYM
|
wrapped. We want to replace all references to __real_SYM
|
with references to SYM. */
|
with references to SYM. */
|
|
|
amt = strlen (l + sizeof REAL - 1) + 2;
|
amt = strlen (l + sizeof REAL - 1) + 2;
|
n = bfd_malloc (amt);
|
n = (char *) bfd_malloc (amt);
|
if (n == NULL)
|
if (n == NULL)
|
return NULL;
|
return NULL;
|
|
|
n[0] = prefix;
|
n[0] = prefix;
|
n[1] = '\0';
|
n[1] = '\0';
|
Line 676... |
Line 677... |
{
|
{
|
/* Allocate the structure if it has not already been allocated by a
|
/* Allocate the structure if it has not already been allocated by a
|
subclass. */
|
subclass. */
|
if (entry == NULL)
|
if (entry == NULL)
|
{
|
{
|
entry =
|
entry = (struct bfd_hash_entry *)
|
bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry));
|
bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry));
|
if (entry == NULL)
|
if (entry == NULL)
|
return entry;
|
return entry;
|
}
|
}
|
|
|
Line 705... |
Line 706... |
_bfd_generic_link_hash_table_create (bfd *abfd)
|
_bfd_generic_link_hash_table_create (bfd *abfd)
|
{
|
{
|
struct generic_link_hash_table *ret;
|
struct generic_link_hash_table *ret;
|
bfd_size_type amt = sizeof (struct generic_link_hash_table);
|
bfd_size_type amt = sizeof (struct generic_link_hash_table);
|
|
|
ret = bfd_malloc (amt);
|
ret = (struct generic_link_hash_table *) bfd_malloc (amt);
|
if (ret == NULL)
|
if (ret == NULL)
|
return NULL;
|
return NULL;
|
if (! _bfd_link_hash_table_init (&ret->root, abfd,
|
if (! _bfd_link_hash_table_init (&ret->root, abfd,
|
_bfd_generic_link_hash_newfunc,
|
_bfd_generic_link_hash_newfunc,
|
sizeof (struct generic_link_hash_entry)))
|
sizeof (struct generic_link_hash_entry)))
|
Line 735... |
Line 736... |
around for the entire link to ensure that we only read them once.
|
around for the entire link to ensure that we only read them once.
|
If we read them multiple times, we might wind up with relocs and
|
If we read them multiple times, we might wind up with relocs and
|
the hash table pointing to different instances of the symbol
|
the hash table pointing to different instances of the symbol
|
structure. */
|
structure. */
|
|
|
static bfd_boolean
|
bfd_boolean
|
generic_link_read_symbols (bfd *abfd)
|
bfd_generic_link_read_symbols (bfd *abfd)
|
{
|
{
|
if (bfd_get_outsymbols (abfd) == NULL)
|
if (bfd_get_outsymbols (abfd) == NULL)
|
{
|
{
|
long symsize;
|
long symsize;
|
long symcount;
|
long symcount;
|
|
|
symsize = bfd_get_symtab_upper_bound (abfd);
|
symsize = bfd_get_symtab_upper_bound (abfd);
|
if (symsize < 0)
|
if (symsize < 0)
|
return FALSE;
|
return FALSE;
|
bfd_get_outsymbols (abfd) = bfd_alloc (abfd, symsize);
|
bfd_get_outsymbols (abfd) = (struct bfd_symbol **) bfd_alloc (abfd,
|
|
symsize);
|
if (bfd_get_outsymbols (abfd) == NULL && symsize != 0)
|
if (bfd_get_outsymbols (abfd) == NULL && symsize != 0)
|
return FALSE;
|
return FALSE;
|
symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd));
|
symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd));
|
if (symcount < 0)
|
if (symcount < 0)
|
return FALSE;
|
return FALSE;
|
Line 832... |
Line 834... |
bfd_boolean collect)
|
bfd_boolean collect)
|
{
|
{
|
bfd_size_type symcount;
|
bfd_size_type symcount;
|
struct bfd_symbol **outsyms;
|
struct bfd_symbol **outsyms;
|
|
|
if (! generic_link_read_symbols (abfd))
|
if (!bfd_generic_link_read_symbols (abfd))
|
return FALSE;
|
return FALSE;
|
symcount = _bfd_generic_link_get_symcount (abfd);
|
symcount = _bfd_generic_link_get_symcount (abfd);
|
outsyms = _bfd_generic_link_get_symbols (abfd);
|
outsyms = _bfd_generic_link_get_symbols (abfd);
|
return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
|
return generic_link_add_symbol_list (abfd, info, symcount, outsyms, collect);
|
}
|
}
|
Line 878... |
Line 880... |
struct archive_hash_entry *ret = (struct archive_hash_entry *) entry;
|
struct archive_hash_entry *ret = (struct archive_hash_entry *) entry;
|
|
|
/* Allocate the structure if it has not already been allocated by a
|
/* Allocate the structure if it has not already been allocated by a
|
subclass. */
|
subclass. */
|
if (ret == NULL)
|
if (ret == NULL)
|
ret = bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
|
ret = (struct archive_hash_entry *)
|
|
bfd_hash_allocate (table, sizeof (struct archive_hash_entry));
|
if (ret == NULL)
|
if (ret == NULL)
|
return NULL;
|
return NULL;
|
|
|
/* Call the allocation method of the superclass. */
|
/* Call the allocation method of the superclass. */
|
ret = ((struct archive_hash_entry *)
|
ret = ((struct archive_hash_entry *)
|
Line 1049... |
Line 1052... |
/* If we haven't found the exact symbol we're looking for,
|
/* If we haven't found the exact symbol we're looking for,
|
let's look for its import thunk */
|
let's look for its import thunk */
|
if (info->pei386_auto_import)
|
if (info->pei386_auto_import)
|
{
|
{
|
bfd_size_type amt = strlen (h->root.string) + 10;
|
bfd_size_type amt = strlen (h->root.string) + 10;
|
char *buf = bfd_malloc (amt);
|
char *buf = (char *) bfd_malloc (amt);
|
if (buf == NULL)
|
if (buf == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
sprintf (buf, "__imp_%s", h->root.string);
|
sprintf (buf, "__imp_%s", h->root.string);
|
arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
|
arh = archive_hash_lookup (&arsym_hash, buf, FALSE, FALSE);
|
Line 1162... |
Line 1165... |
{
|
{
|
asymbol **pp, **ppend;
|
asymbol **pp, **ppend;
|
|
|
*pneeded = FALSE;
|
*pneeded = FALSE;
|
|
|
if (! generic_link_read_symbols (abfd))
|
if (!bfd_generic_link_read_symbols (abfd))
|
return FALSE;
|
return FALSE;
|
|
|
pp = _bfd_generic_link_get_symbols (abfd);
|
pp = _bfd_generic_link_get_symbols (abfd);
|
ppend = pp + _bfd_generic_link_get_symcount (abfd);
|
ppend = pp + _bfd_generic_link_get_symcount (abfd);
|
for (; pp < ppend; pp++)
|
for (; pp < ppend; pp++)
|
Line 1240... |
Line 1243... |
this function differently. This symbol is already on the
|
this function differently. This symbol is already on the
|
undefs list. We add the section to a common section
|
undefs list. We add the section to a common section
|
attached to symbfd to ensure that it is in a BFD which
|
attached to symbfd to ensure that it is in a BFD which
|
will be linked in. */
|
will be linked in. */
|
h->type = bfd_link_hash_common;
|
h->type = bfd_link_hash_common;
|
h->u.c.p =
|
h->u.c.p = (struct bfd_link_hash_common_entry *)
|
bfd_hash_allocate (&info->hash->table,
|
bfd_hash_allocate (&info->hash->table,
|
sizeof (struct bfd_link_hash_common_entry));
|
sizeof (struct bfd_link_hash_common_entry));
|
if (h->u.c.p == NULL)
|
if (h->u.c.p == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
Line 1689... |
Line 1692... |
case COM:
|
case COM:
|
/* We have found a common definition for a symbol. */
|
/* We have found a common definition for a symbol. */
|
if (h->type == bfd_link_hash_new)
|
if (h->type == bfd_link_hash_new)
|
bfd_link_add_undef (info->hash, h);
|
bfd_link_add_undef (info->hash, h);
|
h->type = bfd_link_hash_common;
|
h->type = bfd_link_hash_common;
|
h->u.c.p =
|
h->u.c.p = (struct bfd_link_hash_common_entry *)
|
bfd_hash_allocate (&info->hash->table,
|
bfd_hash_allocate (&info->hash->table,
|
sizeof (struct bfd_link_hash_common_entry));
|
sizeof (struct bfd_link_hash_common_entry));
|
if (h->u.c.p == NULL)
|
if (h->u.c.p == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
Line 1970... |
Line 1973... |
else
|
else
|
{
|
{
|
char *w;
|
char *w;
|
size_t len = strlen (string) + 1;
|
size_t len = strlen (string) + 1;
|
|
|
w = bfd_hash_allocate (&info->hash->table, len);
|
w = (char *) bfd_hash_allocate (&info->hash->table, len);
|
if (w == NULL)
|
if (w == NULL)
|
return FALSE;
|
return FALSE;
|
memcpy (w, string, len);
|
memcpy (w, string, len);
|
sub->u.i.warning = w;
|
sub->u.i.warning = w;
|
}
|
}
|
Line 2057... |
Line 2060... |
input_bfd = input_section->owner;
|
input_bfd = input_section->owner;
|
relsize = bfd_get_reloc_upper_bound (input_bfd,
|
relsize = bfd_get_reloc_upper_bound (input_bfd,
|
input_section);
|
input_section);
|
if (relsize < 0)
|
if (relsize < 0)
|
return FALSE;
|
return FALSE;
|
relocs = bfd_malloc (relsize);
|
relocs = (arelent **) bfd_malloc (relsize);
|
if (!relocs && relsize != 0)
|
if (!relocs && relsize != 0)
|
return FALSE;
|
return FALSE;
|
symbols = _bfd_generic_link_get_symbols (input_bfd);
|
symbols = _bfd_generic_link_get_symbols (input_bfd);
|
reloc_count = bfd_canonicalize_reloc (input_bfd,
|
reloc_count = bfd_canonicalize_reloc (input_bfd,
|
input_section,
|
input_section,
|
Line 2079... |
Line 2082... |
{
|
{
|
bfd_size_type amt;
|
bfd_size_type amt;
|
|
|
amt = o->reloc_count;
|
amt = o->reloc_count;
|
amt *= sizeof (arelent *);
|
amt *= sizeof (arelent *);
|
o->orelocation = bfd_alloc (abfd, amt);
|
o->orelocation = (struct reloc_cache_entry **) bfd_alloc (abfd, amt);
|
if (!o->orelocation)
|
if (!o->orelocation)
|
return FALSE;
|
return FALSE;
|
o->flags |= SEC_RELOC;
|
o->flags |= SEC_RELOC;
|
/* Reset the count so that it can be used as an index
|
/* Reset the count so that it can be used as an index
|
when putting in the output relocs. */
|
when putting in the output relocs. */
|
Line 2133... |
Line 2136... |
*psymalloc = 124;
|
*psymalloc = 124;
|
else
|
else
|
*psymalloc *= 2;
|
*psymalloc *= 2;
|
amt = *psymalloc;
|
amt = *psymalloc;
|
amt *= sizeof (asymbol *);
|
amt *= sizeof (asymbol *);
|
newsyms = bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
|
newsyms = (asymbol **) bfd_realloc (bfd_get_outsymbols (output_bfd), amt);
|
if (newsyms == NULL)
|
if (newsyms == NULL)
|
return FALSE;
|
return FALSE;
|
bfd_get_outsymbols (output_bfd) = newsyms;
|
bfd_get_outsymbols (output_bfd) = newsyms;
|
}
|
}
|
|
|
Line 2157... |
Line 2160... |
size_t *psymalloc)
|
size_t *psymalloc)
|
{
|
{
|
asymbol **sym_ptr;
|
asymbol **sym_ptr;
|
asymbol **sym_end;
|
asymbol **sym_end;
|
|
|
if (! generic_link_read_symbols (input_bfd))
|
if (!bfd_generic_link_read_symbols (input_bfd))
|
return FALSE;
|
return FALSE;
|
|
|
/* Create a filename symbol if we are supposed to. */
|
/* Create a filename symbol if we are supposed to. */
|
if (info->create_object_symbols_section != NULL)
|
if (info->create_object_symbols_section != NULL)
|
{
|
{
|
Line 2210... |
Line 2213... |
|| bfd_is_und_section (bfd_get_section (sym))
|
|| bfd_is_und_section (bfd_get_section (sym))
|
|| bfd_is_com_section (bfd_get_section (sym))
|
|| bfd_is_com_section (bfd_get_section (sym))
|
|| bfd_is_ind_section (bfd_get_section (sym)))
|
|| bfd_is_ind_section (bfd_get_section (sym)))
|
{
|
{
|
if (sym->udata.p != NULL)
|
if (sym->udata.p != NULL)
|
h = sym->udata.p;
|
h = (struct generic_link_hash_entry *) sym->udata.p;
|
else if ((sym->flags & BSF_CONSTRUCTOR) != 0)
|
else if ((sym->flags & BSF_CONSTRUCTOR) != 0)
|
{
|
{
|
/* This case normally means that the main linker code
|
/* This case normally means that the main linker code
|
deliberately ignored this constructor symbol. We
|
deliberately ignored this constructor symbol. We
|
should just pass it through. This will screw up if
|
should just pass it through. This will screw up if
|
Line 2449... |
Line 2452... |
|
|
bfd_boolean
|
bfd_boolean
|
_bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h,
|
_bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h,
|
void *data)
|
void *data)
|
{
|
{
|
struct generic_write_global_symbol_info *wginfo = data;
|
struct generic_write_global_symbol_info *wginfo =
|
|
(struct generic_write_global_symbol_info *) data;
|
asymbol *sym;
|
asymbol *sym;
|
|
|
if (h->root.type == bfd_link_hash_warning)
|
if (h->root.type == bfd_link_hash_warning)
|
h = (struct generic_link_hash_entry *) h->root.u.i.link;
|
h = (struct generic_link_hash_entry *) h->root.u.i.link;
|
|
|
Line 2506... |
Line 2510... |
if (! info->relocatable)
|
if (! info->relocatable)
|
abort ();
|
abort ();
|
if (sec->orelocation == NULL)
|
if (sec->orelocation == NULL)
|
abort ();
|
abort ();
|
|
|
r = bfd_alloc (abfd, sizeof (arelent));
|
r = (arelent *) bfd_alloc (abfd, sizeof (arelent));
|
if (r == NULL)
|
if (r == NULL)
|
return FALSE;
|
return FALSE;
|
|
|
r->address = link_order->offset;
|
r->address = link_order->offset;
|
r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
|
r->howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
|
Line 2554... |
Line 2558... |
bfd_byte *buf;
|
bfd_byte *buf;
|
bfd_boolean ok;
|
bfd_boolean ok;
|
file_ptr loc;
|
file_ptr loc;
|
|
|
size = bfd_get_reloc_size (r->howto);
|
size = bfd_get_reloc_size (r->howto);
|
buf = bfd_zmalloc (size);
|
buf = (bfd_byte *) bfd_zmalloc (size);
|
if (buf == NULL)
|
if (buf == NULL)
|
return FALSE;
|
return FALSE;
|
rstat = _bfd_relocate_contents (r->howto, abfd,
|
rstat = _bfd_relocate_contents (r->howto, abfd,
|
(bfd_vma) link_order->u.reloc.p->addend,
|
(bfd_vma) link_order->u.reloc.p->addend,
|
buf);
|
buf);
|
Line 2602... |
Line 2606... |
|
|
struct bfd_link_order *
|
struct bfd_link_order *
|
bfd_new_link_order (bfd *abfd, asection *section)
|
bfd_new_link_order (bfd *abfd, asection *section)
|
{
|
{
|
bfd_size_type amt = sizeof (struct bfd_link_order);
|
bfd_size_type amt = sizeof (struct bfd_link_order);
|
struct bfd_link_order *new;
|
struct bfd_link_order *new_lo;
|
|
|
new = bfd_zalloc (abfd, amt);
|
new_lo = (struct bfd_link_order *) bfd_zalloc (abfd, amt);
|
if (!new)
|
if (!new_lo)
|
return NULL;
|
return NULL;
|
|
|
new->type = bfd_undefined_link_order;
|
new_lo->type = bfd_undefined_link_order;
|
|
|
if (section->map_tail.link_order != NULL)
|
if (section->map_tail.link_order != NULL)
|
section->map_tail.link_order->next = new;
|
section->map_tail.link_order->next = new_lo;
|
else
|
else
|
section->map_head.link_order = new;
|
section->map_head.link_order = new_lo;
|
section->map_tail.link_order = new;
|
section->map_tail.link_order = new_lo;
|
|
|
return new;
|
return new_lo;
|
}
|
}
|
|
|
/* Default link order processing routine. Note that we can not handle
|
/* Default link order processing routine. Note that we can not handle
|
the reloc_link_order types here, since they depend upon the details
|
the reloc_link_order types here, since they depend upon the details
|
of how the particular backends generates relocs. */
|
of how the particular backends generates relocs. */
|
Line 2669... |
Line 2673... |
fill = link_order->u.data.contents;
|
fill = link_order->u.data.contents;
|
fill_size = link_order->u.data.size;
|
fill_size = link_order->u.data.size;
|
if (fill_size != 0 && fill_size < size)
|
if (fill_size != 0 && fill_size < size)
|
{
|
{
|
bfd_byte *p;
|
bfd_byte *p;
|
fill = bfd_malloc (size);
|
fill = (bfd_byte *) bfd_malloc (size);
|
if (fill == NULL)
|
if (fill == NULL)
|
return FALSE;
|
return FALSE;
|
p = fill;
|
p = fill;
|
if (fill_size == 1)
|
if (fill_size == 1)
|
memset (p, (int) link_order->u.data.contents[0], (size_t) size);
|
memset (p, (int) link_order->u.data.contents[0], (size_t) size);
|
Line 2750... |
Line 2754... |
|
|
/* Get the canonical symbols. The generic linker will always
|
/* Get the canonical symbols. The generic linker will always
|
have retrieved them by this point, but we are being called by
|
have retrieved them by this point, but we are being called by
|
a specific linker, presumably because we are linking
|
a specific linker, presumably because we are linking
|
different types of object files together. */
|
different types of object files together. */
|
if (! generic_link_read_symbols (input_bfd))
|
if (!bfd_generic_link_read_symbols (input_bfd))
|
return FALSE;
|
return FALSE;
|
|
|
/* Since we have been called by a specific linker, rather than
|
/* Since we have been called by a specific linker, rather than
|
the generic linker, the values of the symbols will not be
|
the generic linker, the values of the symbols will not be
|
right. They will be the values as seen in the input file,
|
right. They will be the values as seen in the input file,
|
Line 2779... |
Line 2783... |
|| bfd_is_ind_section (bfd_get_section (sym)))
|
|| bfd_is_ind_section (bfd_get_section (sym)))
|
{
|
{
|
/* sym->udata may have been set by
|
/* sym->udata may have been set by
|
generic_link_add_symbol_list. */
|
generic_link_add_symbol_list. */
|
if (sym->udata.p != NULL)
|
if (sym->udata.p != NULL)
|
h = sym->udata.p;
|
h = (struct bfd_link_hash_entry *) sym->udata.p;
|
else if (bfd_is_und_section (bfd_get_section (sym)))
|
else if (bfd_is_und_section (bfd_get_section (sym)))
|
h = bfd_wrapped_link_hash_lookup (output_bfd, info,
|
h = bfd_wrapped_link_hash_lookup (output_bfd, info,
|
bfd_asymbol_name (sym),
|
bfd_asymbol_name (sym),
|
FALSE, FALSE, TRUE);
|
FALSE, FALSE, TRUE);
|
else
|
else
|
Line 2794... |
Line 2798... |
set_symbol_from_hash (sym, h);
|
set_symbol_from_hash (sym, h);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
if ((output_section->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP
|
|
&& input_section->size != 0)
|
|
{
|
|
/* Group section contents are set by bfd_elf_set_group_contents. */
|
|
if (!output_bfd->output_has_begun)
|
|
{
|
|
/* FIXME: This hack ensures bfd_elf_set_group_contents is called. */
|
|
if (!bfd_set_section_contents (output_bfd, output_section, "", 0, 1))
|
|
goto error_return;
|
|
}
|
|
new_contents = output_section->contents;
|
|
BFD_ASSERT (new_contents != NULL);
|
|
BFD_ASSERT (input_section->output_offset == 0);
|
|
}
|
|
else
|
|
{
|
/* Get and relocate the section contents. */
|
/* Get and relocate the section contents. */
|
sec_size = (input_section->rawsize > input_section->size
|
sec_size = (input_section->rawsize > input_section->size
|
? input_section->rawsize
|
? input_section->rawsize
|
: input_section->size);
|
: input_section->size);
|
contents = bfd_malloc (sec_size);
|
contents = (bfd_byte *) bfd_malloc (sec_size);
|
if (contents == NULL && sec_size != 0)
|
if (contents == NULL && sec_size != 0)
|
goto error_return;
|
goto error_return;
|
new_contents = (bfd_get_relocated_section_contents
|
new_contents = (bfd_get_relocated_section_contents
|
(output_bfd, info, link_order, contents, info->relocatable,
|
(output_bfd, info, link_order, contents,
|
|
info->relocatable,
|
_bfd_generic_link_get_symbols (input_bfd)));
|
_bfd_generic_link_get_symbols (input_bfd)));
|
if (!new_contents)
|
if (!new_contents)
|
goto error_return;
|
goto error_return;
|
|
}
|
|
|
/* Output the section contents. */
|
/* Output the section contents. */
|
loc = input_section->output_offset * bfd_octets_per_byte (output_bfd);
|
loc = input_section->output_offset * bfd_octets_per_byte (output_bfd);
|
if (! bfd_set_section_contents (output_bfd, output_section,
|
if (! bfd_set_section_contents (output_bfd, output_section,
|
new_contents, loc, input_section->size))
|
new_contents, loc, input_section->size))
|
Line 2929... |
Line 2951... |
{
|
{
|
struct bfd_section_already_linked *l;
|
struct bfd_section_already_linked *l;
|
|
|
/* Allocate the memory from the same obstack as the hash table is
|
/* Allocate the memory from the same obstack as the hash table is
|
kept in. */
|
kept in. */
|
l = bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
|
l = (struct bfd_section_already_linked *)
|
|
bfd_hash_allocate (&_bfd_section_already_linked_table, sizeof *l);
|
if (l == NULL)
|
if (l == NULL)
|
return FALSE;
|
return FALSE;
|
l->sec = sec;
|
l->sec = sec;
|
l->next = already_linked_list->entry;
|
l->next = already_linked_list->entry;
|
already_linked_list->entry = l;
|
already_linked_list->entry = l;
|
Line 2944... |
Line 2967... |
already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
|
already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED,
|
struct bfd_hash_table *table,
|
struct bfd_hash_table *table,
|
const char *string ATTRIBUTE_UNUSED)
|
const char *string ATTRIBUTE_UNUSED)
|
{
|
{
|
struct bfd_section_already_linked_hash_entry *ret =
|
struct bfd_section_already_linked_hash_entry *ret =
|
|
(struct bfd_section_already_linked_hash_entry *)
|
bfd_hash_allocate (table, sizeof *ret);
|
bfd_hash_allocate (table, sizeof *ret);
|
|
|
if (ret == NULL)
|
if (ret == NULL)
|
return NULL;
|
return NULL;
|
|
|
Line 3075... |
Line 3099... |
}
|
}
|
}
|
}
|
|
|
/* This is the first section with this name. Record it. */
|
/* This is the first section with this name. Record it. */
|
if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
|
if (! bfd_section_already_linked_table_insert (already_linked_list, sec))
|
info->callbacks->einfo (_("%F%P: already_linked_table: %E"));
|
info->callbacks->einfo (_("%F%P: already_linked_table: %E\n"));
|
}
|
}
|
|
|
/* Convert symbols in excluded output sections to use a kept section. */
|
/* Convert symbols in excluded output sections to use a kept section. */
|
|
|
static bfd_boolean
|
static bfd_boolean
|
Line 3129... |
Line 3153... |
op = bfd_abs_section_ptr;
|
op = bfd_abs_section_ptr;
|
}
|
}
|
else if (op == NULL)
|
else if (op == NULL)
|
op = op1;
|
op = op1;
|
else if (((op1->flags ^ op->flags)
|
else if (((op1->flags ^ op->flags)
|
& (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
|
& (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0)
|
{
|
{
|
if (((op->flags ^ s->flags)
|
if (((op->flags ^ s->flags)
|
& (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0)
|
& (SEC_ALLOC | SEC_THREAD_LOCAL)) != 0
|
|
/* We prefer to choose a loaded section. Section S
|
|
doesn't have SEC_LOAD set (it being excluded, that
|
|
part of the flag processing didn't happen) so we
|
|
can't compare that flag to those of OP and OP1. */
|
|
|| ((op1->flags & SEC_LOAD) != 0
|
|
&& (op->flags & SEC_LOAD) == 0))
|
op = op1;
|
op = op1;
|
}
|
}
|
else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
|
else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0)
|
{
|
{
|
if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
|
if (((op->flags ^ s->flags) & SEC_READONLY) != 0)
|
Line 3167... |
Line 3197... |
_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info)
|
_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info)
|
{
|
{
|
bfd_link_hash_traverse (info->hash, fix_syms, obfd);
|
bfd_link_hash_traverse (info->hash, fix_syms, obfd);
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
/*
|
|
FUNCTION
|
|
bfd_generic_define_common_symbol
|
|
|
|
SYNOPSIS
|
|
bfd_boolean bfd_generic_define_common_symbol
|
|
(bfd *output_bfd, struct bfd_link_info *info,
|
|
struct bfd_link_hash_entry *h);
|
|
|
|
DESCRIPTION
|
|
Convert common symbol @var{h} into a defined symbol.
|
|
Return TRUE on success and FALSE on failure.
|
|
|
|
.#define bfd_define_common_symbol(output_bfd, info, h) \
|
|
. BFD_SEND (output_bfd, _bfd_define_common_symbol, (output_bfd, info, h))
|
|
.
|
|
*/
|
|
|
|
bfd_boolean
|
|
bfd_generic_define_common_symbol (bfd *output_bfd,
|
|
struct bfd_link_info *info ATTRIBUTE_UNUSED,
|
|
struct bfd_link_hash_entry *h)
|
|
{
|
|
unsigned int power_of_two;
|
|
bfd_vma alignment, size;
|
|
asection *section;
|
|
|
|
BFD_ASSERT (h != NULL && h->type == bfd_link_hash_common);
|
|
|
|
size = h->u.c.size;
|
|
power_of_two = h->u.c.p->alignment_power;
|
|
section = h->u.c.p->section;
|
|
|
|
/* Increase the size of the section to align the common symbol.
|
|
The alignment must be a power of two. */
|
|
alignment = bfd_octets_per_byte (output_bfd) << power_of_two;
|
|
BFD_ASSERT (alignment != 0 && (alignment & -alignment) == alignment);
|
|
section->size += alignment - 1;
|
|
section->size &= -alignment;
|
|
|
|
/* Adjust the section's overall alignment if necessary. */
|
|
if (power_of_two > section->alignment_power)
|
|
section->alignment_power = power_of_two;
|
|
|
|
/* Change the symbol from common to defined. */
|
|
h->type = bfd_link_hash_defined;
|
|
h->u.def.section = section;
|
|
h->u.def.value = section->size;
|
|
|
|
/* Increase the size of the section. */
|
|
section->size += size;
|
|
|
|
/* Make sure the section is allocated in memory, and make sure that
|
|
it is no longer a common section. */
|
|
section->flags |= SEC_ALLOC;
|
|
section->flags &= ~SEC_IS_COMMON;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
FUNCTION
|
|
bfd_find_version_for_sym
|
|
|
|
SYNOPSIS
|
|
struct bfd_elf_version_tree * bfd_find_version_for_sym
|
|
(struct bfd_elf_version_tree *verdefs,
|
|
const char *sym_name, bfd_boolean *hide);
|
|
|
|
DESCRIPTION
|
|
Search an elf version script tree for symbol versioning
|
|
info and export / don't-export status for a given symbol.
|
|
Return non-NULL on success and NULL on failure; also sets
|
|
the output @samp{hide} boolean parameter.
|
|
|
|
*/
|
|
|
|
struct bfd_elf_version_tree *
|
|
bfd_find_version_for_sym (struct bfd_elf_version_tree *verdefs,
|
|
const char *sym_name,
|
|
bfd_boolean *hide)
|
|
{
|
|
struct bfd_elf_version_tree *t;
|
|
struct bfd_elf_version_tree *local_ver, *global_ver, *exist_ver;
|
|
struct bfd_elf_version_tree *star_local_ver, *star_global_ver;
|
|
|
|
local_ver = NULL;
|
|
global_ver = NULL;
|
|
star_local_ver = NULL;
|
|
star_global_ver = NULL;
|
|
exist_ver = NULL;
|
|
for (t = verdefs; t != NULL; t = t->next)
|
|
{
|
|
if (t->globals.list != NULL)
|
|
{
|
|
struct bfd_elf_version_expr *d = NULL;
|
|
|
|
while ((d = (*t->match) (&t->globals, d, sym_name)) != NULL)
|
|
{
|
|
if (d->literal || strcmp (d->pattern, "*") != 0)
|
|
global_ver = t;
|
|
else
|
|
star_global_ver = t;
|
|
if (d->symver)
|
|
exist_ver = t;
|
|
d->script = 1;
|
|
/* If the match is a wildcard pattern, keep looking for
|
|
a more explicit, perhaps even local, match. */
|
|
if (d->literal)
|
|
break;
|
|
}
|
|
|
|
if (d != NULL)
|
|
break;
|
|
}
|
|
|
|
if (t->locals.list != NULL)
|
|
{
|
|
struct bfd_elf_version_expr *d = NULL;
|
|
|
|
while ((d = (*t->match) (&t->locals, d, sym_name)) != NULL)
|
|
{
|
|
if (d->literal || strcmp (d->pattern, "*") != 0)
|
|
local_ver = t;
|
|
else
|
|
star_local_ver = t;
|
|
/* If the match is a wildcard pattern, keep looking for
|
|
a more explicit, perhaps even global, match. */
|
|
if (d->literal)
|
|
{
|
|
/* An exact match overrides a global wildcard. */
|
|
global_ver = NULL;
|
|
star_global_ver = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (d != NULL)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (global_ver == NULL && local_ver == NULL)
|
|
global_ver = star_global_ver;
|
|
|
|
if (global_ver != NULL)
|
|
{
|
|
/* If we already have a versioned symbol that matches the
|
|
node for this symbol, then we don't want to create a
|
|
duplicate from the unversioned symbol. Instead hide the
|
|
unversioned symbol. */
|
|
*hide = exist_ver == global_ver;
|
|
return global_ver;
|
|
}
|
|
|
|
if (local_ver == NULL)
|
|
local_ver = star_local_ver;
|
|
|
|
if (local_ver != NULL)
|
|
{
|
|
*hide = TRUE;
|
|
return local_ver;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|