X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Flinker.c;h=76bc70af0933c2351fe014172722e7f2572825aa;hb=60e5ef9f190902591c6228d470a85fd82994f2c4;hp=8abf35967011d6cdd01b42d2d24cd6a110dacceb;hpb=f6e332e6604aa0bbc05b745d677222e25da2133e;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/linker.c b/bfd/linker.c index 8abf359670..76bc70af09 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1,13 +1,14 @@ /* linker.c -- BFD linker routines Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support This file is part of BFD, the Binary File Descriptor library. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -17,10 +18,11 @@ 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. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "libbfd.h" #include "bfdlink.h" #include "genlink.h" @@ -149,9 +151,9 @@ SUBSUBSECTION Sometimes the <<_bfd_link_add_symbols>> function must store some information in the hash table entry to be used by the - <<_bfd_final_link>> function. In such a case the <> - field of the hash table must be checked to make sure that the - hash table was created by an object file of the same format. + <<_bfd_final_link>> function. In such a case the output bfd + xvec must be checked to make sure that the hash table was + created by an object file of the same format. The <<_bfd_final_link>> routine must be prepared to handle a hash entry without any extra information added by the @@ -163,7 +165,7 @@ SUBSUBSECTION initialization function. See <> for an example of how to - check the <> field before saving information (in this + check the output bfd before saving information (in this case, the ECOFF external symbol debugging information) in a hash table entry. @@ -309,7 +311,7 @@ SUBSUBSECTION of the <> structure. Each section in the output file will have a list of - <> structures attached to the <> + <> structures attached to the <> field (the <> structure is defined in <>). These structures describe how to create the contents of the output section in terms of the contents of @@ -442,7 +444,8 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry, subclass. */ 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) return entry; } @@ -455,7 +458,9 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry, /* Initialize the local fields. */ h->type = bfd_link_hash_new; - h->u.undef.next = NULL; + memset (&h->u.undef.next, 0, + (sizeof (struct bfd_link_hash_entry) + - offsetof (struct bfd_link_hash_entry, u.undef.next))); } return entry; @@ -467,17 +472,17 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry, bfd_boolean _bfd_link_hash_table_init (struct bfd_link_hash_table *table, - bfd *abfd, + bfd *abfd ATTRIBUTE_UNUSED, struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, struct bfd_hash_table *, - const char *)) + const char *), + unsigned int entsize) { - table->creator = abfd->xvec; table->undefs = NULL; table->undefs_tail = NULL; table->type = bfd_link_generic_hash_table; - return bfd_hash_table_init (&table->table, newfunc); + return bfd_hash_table_init (&table->table, newfunc, entsize); } /* Look up a symbol in a link hash table. If follow is TRUE, we @@ -544,7 +549,7 @@ bfd_wrapped_link_hash_lookup (bfd *abfd, references to SYM with references to __wrap_SYM. */ amt = strlen (l) + sizeof WRAP + 1; - n = bfd_malloc (amt); + n = (char *) bfd_malloc (amt); if (n == NULL) return NULL; @@ -559,11 +564,11 @@ bfd_wrapped_link_hash_lookup (bfd *abfd, #undef WRAP -#undef REAL +#undef REAL #define REAL "__real_" if (*l == '_' - && strncmp (l, REAL, sizeof REAL - 1) == 0 + && CONST_STRNEQ (l, REAL) && bfd_hash_lookup (info->wrap_hash, l + sizeof REAL - 1, FALSE, FALSE) != NULL) { @@ -575,7 +580,7 @@ bfd_wrapped_link_hash_lookup (bfd *abfd, with references to SYM. */ amt = strlen (l + sizeof REAL - 1) + 2; - n = bfd_malloc (amt); + n = (char *) bfd_malloc (amt); if (n == NULL) return NULL; @@ -623,6 +628,45 @@ bfd_link_add_undef (struct bfd_link_hash_table *table, table->undefs = h; table->undefs_tail = h; } + +/* The undefs list was designed so that in normal use we don't need to + remove entries. However, if symbols on the list are changed from + bfd_link_hash_undefined to either bfd_link_hash_undefweak or + bfd_link_hash_new for some reason, then they must be removed from the + list. Failure to do so might result in the linker attempting to add + the symbol to the list again at a later stage. */ + +void +bfd_link_repair_undef_list (struct bfd_link_hash_table *table) +{ + struct bfd_link_hash_entry **pun; + + pun = &table->undefs; + while (*pun != NULL) + { + struct bfd_link_hash_entry *h = *pun; + + if (h->type == bfd_link_hash_new + || h->type == bfd_link_hash_undefweak) + { + *pun = h->u.undef.next; + h->u.undef.next = NULL; + if (h == table->undefs_tail) + { + if (pun == &table->undefs) + table->undefs_tail = NULL; + else + /* pun points at an u.undef.next field. Go back to + the start of the link_hash_entry. */ + table->undefs_tail = (struct bfd_link_hash_entry *) + ((char *) pun - ((char *) &h->u.undef.next - (char *) h)); + break; + } + } + else + pun = &h->u.undef.next; + } +} /* Routine to create an entry in a generic link hash table. */ @@ -635,7 +679,7 @@ _bfd_generic_link_hash_newfunc (struct bfd_hash_entry *entry, subclass. */ if (entry == NULL) { - entry = + entry = (struct bfd_hash_entry *) bfd_hash_allocate (table, sizeof (struct generic_link_hash_entry)); if (entry == NULL) return entry; @@ -664,11 +708,12 @@ _bfd_generic_link_hash_table_create (bfd *abfd) struct generic_link_hash_table *ret; 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) return NULL; 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))) { free (ret); return NULL; @@ -693,8 +738,8 @@ _bfd_generic_link_hash_table_free (struct bfd_link_hash_table *hash) the hash table pointing to different instances of the symbol structure. */ -static bfd_boolean -generic_link_read_symbols (bfd *abfd) +bfd_boolean +bfd_generic_link_read_symbols (bfd *abfd) { if (bfd_get_outsymbols (abfd) == NULL) { @@ -704,7 +749,8 @@ generic_link_read_symbols (bfd *abfd) symsize = bfd_get_symtab_upper_bound (abfd); if (symsize < 0) 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) return FALSE; symcount = bfd_canonicalize_symtab (abfd, bfd_get_outsymbols (abfd)); @@ -751,6 +797,17 @@ _bfd_generic_link_just_syms (asection *sec, sec->output_offset = sec->vma; } +/* Copy the type of a symbol assiciated with a linker hast table entry. + Override this so that symbols created in linker scripts get their + type from the RHS of the assignment. + The default implementation does nothing. */ +void +_bfd_generic_copy_link_hash_symbol_type (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_hash_entry * hdest ATTRIBUTE_UNUSED, + struct bfd_link_hash_entry * hsrc ATTRIBUTE_UNUSED) +{ +} + /* Add symbols from an object file to the global hash table. */ static bfd_boolean @@ -790,7 +847,7 @@ generic_link_add_object_symbols (bfd *abfd, bfd_size_type symcount; struct bfd_symbol **outsyms; - if (! generic_link_read_symbols (abfd)) + if (!bfd_generic_link_read_symbols (abfd)) return FALSE; symcount = _bfd_generic_link_get_symcount (abfd); outsyms = _bfd_generic_link_get_symbols (abfd); @@ -836,7 +893,8 @@ archive_hash_newfunc (struct bfd_hash_entry *entry, /* Allocate the structure if it has not already been allocated by a subclass. */ 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) return NULL; @@ -860,9 +918,10 @@ archive_hash_table_init (struct archive_hash_table *table, struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, struct bfd_hash_table *, - const char *)) + const char *), + unsigned int entsize) { - return bfd_hash_table_init (&table->table, newfunc); + return bfd_hash_table_init (&table->table, newfunc, entsize); } /* Look up an entry in an archive hash table. */ @@ -940,7 +999,8 @@ _bfd_generic_link_add_archive_symbols /* In order to quickly determine whether an symbol is defined in this archive, we build a hash table of the symbols. */ - if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc)) + if (! archive_hash_table_init (&arsym_hash, archive_hash_newfunc, + sizeof (struct archive_hash_entry))) return FALSE; for (arsym = arsyms, indx = 0; arsym < arsym_end; arsym++, indx++) { @@ -1005,7 +1065,7 @@ _bfd_generic_link_add_archive_symbols if (info->pei386_auto_import) { bfd_size_type amt = strlen (h->root.string) + 10; - char *buf = bfd_malloc (amt); + char *buf = (char *) bfd_malloc (amt); if (buf == NULL) return FALSE; @@ -1118,7 +1178,7 @@ generic_link_check_archive_element (bfd *abfd, *pneeded = FALSE; - if (! generic_link_read_symbols (abfd)) + if (!bfd_generic_link_read_symbols (abfd)) return FALSE; pp = _bfd_generic_link_get_symbols (abfd); @@ -1196,7 +1256,7 @@ generic_link_check_archive_element (bfd *abfd, attached to symbfd to ensure that it is in a BFD which will be linked in. */ 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, sizeof (struct bfd_link_hash_common_entry)); if (h->u.c.p == NULL) @@ -1269,7 +1329,7 @@ generic_link_add_symbol_list (bfd *abfd, struct generic_link_hash_entry *h; struct bfd_link_hash_entry *bh; - name = bfd_asymbol_name (p); + string = name = bfd_asymbol_name (p); if (((p->flags & BSF_INDIRECT) != 0 || bfd_is_ind_section (p->section)) && pp + 1 < ppend) @@ -1282,12 +1342,9 @@ generic_link_add_symbol_list (bfd *abfd, { /* The name of P is actually the warning string, and the next symbol is the one to warn about. */ - string = name; pp++; name = bfd_asymbol_name (*pp); } - else - string = NULL; bh = NULL; if (! (_bfd_generic_link_add_one_symbol @@ -1315,7 +1372,7 @@ generic_link_add_symbol_list (bfd *abfd, hash table other than the generic hash table, so we only do this if we are certain that the hash table is a generic one. */ - if (info->hash->creator == abfd->xvec) + if (info->output_bfd->xvec == abfd->xvec) { if (h->sym == NULL || (! bfd_is_und_section (bfd_get_section (p)) @@ -1565,6 +1622,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, /* Make a new weak undefined symbol. */ h->type = bfd_link_hash_undefweak; h->u.undef.abfd = abfd; + h->u.undef.weak = abfd; break; case CDEF: @@ -1613,8 +1671,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, s = name + 1; while (*s == '_') ++s; - if (s[0] == 'G' - && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0) + if (s[0] == 'G' && CONST_STRNEQ (s, CONS_PREFIX)) { char c; @@ -1648,7 +1705,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, if (h->type == bfd_link_hash_new) bfd_link_add_undef (info->hash, h); 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, sizeof (struct bfd_link_hash_common_entry)); if (h->u.c.p == NULL) @@ -1929,7 +1986,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, char *w; 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) return FALSE; memcpy (w, string, len); @@ -1967,7 +2024,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info) /* Mark all sections which will be included in the output file. */ for (o = abfd->sections; o != NULL; o = o->next) - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) if (p->type == bfd_indirect_link_order) p->u.indirect.section->linker_mark = TRUE; @@ -1996,7 +2053,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info) for (o = abfd->sections; o != NULL; o = o->next) { o->reloc_count = 0; - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { if (p->type == bfd_section_reloc_link_order || p->type == bfd_symbol_reloc_link_order) @@ -2016,7 +2073,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info) input_section); if (relsize < 0) return FALSE; - relocs = bfd_malloc (relsize); + relocs = (arelent **) bfd_malloc (relsize); if (!relocs && relsize != 0) return FALSE; symbols = _bfd_generic_link_get_symbols (input_bfd); @@ -2038,7 +2095,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info) amt = o->reloc_count; amt *= sizeof (arelent *); - o->orelocation = bfd_alloc (abfd, amt); + o->orelocation = (struct reloc_cache_entry **) bfd_alloc (abfd, amt); if (!o->orelocation) return FALSE; o->flags |= SEC_RELOC; @@ -2052,7 +2109,7 @@ _bfd_generic_final_link (bfd *abfd, struct bfd_link_info *info) /* Handle all the link order information for the sections. */ for (o = abfd->sections; o != NULL; o = o->next) { - for (p = o->link_order_head; p != NULL; p = p->next) + for (p = o->map_head.link_order; p != NULL; p = p->next) { switch (p->type) { @@ -2092,7 +2149,7 @@ generic_add_output_symbol (bfd *output_bfd, size_t *psymalloc, asymbol *sym) *psymalloc *= 2; amt = *psymalloc; 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) return FALSE; bfd_get_outsymbols (output_bfd) = newsyms; @@ -2116,7 +2173,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd, asymbol **sym_ptr; asymbol **sym_end; - if (! generic_link_read_symbols (input_bfd)) + if (!bfd_generic_link_read_symbols (input_bfd)) return FALSE; /* Create a filename symbol if we are supposed to. */ @@ -2169,7 +2226,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd, || bfd_is_ind_section (bfd_get_section (sym))) { 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) { /* This case normally means that the main linker code @@ -2199,7 +2256,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd, this routine will be called with a hash table other than a generic hash table, so we double check that. */ - if (info->hash->creator == input_bfd->xvec) + if (info->output_bfd->xvec == input_bfd->xvec) { if (h->sym != NULL) *sym_ptr = sym = h->sym; @@ -2321,12 +2378,11 @@ _bfd_generic_link_output_symbols (bfd *output_bfd, abort (); /* If this symbol is in a section which is not being included - in the output file, then we don't want to output the symbol. - - Gross. .bss and similar sections won't have the linker_mark - field set. */ - if ((sym->section->flags & SEC_HAS_CONTENTS) != 0 - && ! sym->section->linker_mark) + in the output file, then we don't want to output the + symbol. */ + if (!bfd_is_abs_section (sym->section) + && bfd_section_removed_from_list (output_bfd, + sym->section->output_section)) output = FALSE; if (output) @@ -2409,7 +2465,8 @@ bfd_boolean _bfd_generic_link_write_global_symbol (struct generic_link_hash_entry *h, 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; if (h->root.type == bfd_link_hash_warning) @@ -2466,7 +2523,7 @@ _bfd_generic_reloc_link_order (bfd *abfd, if (sec->orelocation == NULL) abort (); - r = bfd_alloc (abfd, sizeof (arelent)); + r = (arelent *) bfd_alloc (abfd, sizeof (arelent)); if (r == NULL) return FALSE; @@ -2514,7 +2571,7 @@ _bfd_generic_reloc_link_order (bfd *abfd, file_ptr loc; size = bfd_get_reloc_size (r->howto); - buf = bfd_zmalloc (size); + buf = (bfd_byte *) bfd_zmalloc (size); if (buf == NULL) return FALSE; rstat = _bfd_relocate_contents (r->howto, abfd, @@ -2529,7 +2586,7 @@ _bfd_generic_reloc_link_order (bfd *abfd, abort (); case bfd_reloc_overflow: if (! ((*info->callbacks->reloc_overflow) - (info, + (info, NULL, (link_order->type == bfd_section_reloc_link_order ? bfd_section_name (abfd, link_order->u.reloc.p->u.section) : link_order->u.reloc.p->u.name), @@ -2562,21 +2619,21 @@ struct bfd_link_order * bfd_new_link_order (bfd *abfd, asection *section) { 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); - if (!new) + new_lo = (struct bfd_link_order *) bfd_zalloc (abfd, amt); + if (!new_lo) return NULL; - new->type = bfd_undefined_link_order; + new_lo->type = bfd_undefined_link_order; - if (section->link_order_tail != NULL) - section->link_order_tail->next = new; + if (section->map_tail.link_order != NULL) + section->map_tail.link_order->next = new_lo; else - section->link_order_head = new; - section->link_order_tail = new; + section->map_head.link_order = new_lo; + section->map_tail.link_order = new_lo; - return new; + return new_lo; } /* Default link order processing routine. Note that we can not handle @@ -2629,7 +2686,7 @@ default_data_link_order (bfd *abfd, if (fill_size != 0 && fill_size < size) { bfd_byte *p; - fill = bfd_malloc (size); + fill = (bfd_byte *) bfd_malloc (size); if (fill == NULL) return FALSE; p = fill; @@ -2676,11 +2733,10 @@ default_indirect_link_order (bfd *output_bfd, BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0); - if (link_order->size == 0) - return TRUE; - input_section = link_order->u.indirect.section; input_bfd = input_section->owner; + if (input_section->size == 0) + return TRUE; BFD_ASSERT (input_section->output_section == output_section); BFD_ASSERT (input_section->output_offset == link_order->offset); @@ -2711,7 +2767,7 @@ default_indirect_link_order (bfd *output_bfd, have retrieved them by this point, but we are being called by a specific linker, presumably because we are linking different types of object files together. */ - if (! generic_link_read_symbols (input_bfd)) + if (!bfd_generic_link_read_symbols (input_bfd)) return FALSE; /* Since we have been called by a specific linker, rather than @@ -2740,7 +2796,7 @@ default_indirect_link_order (bfd *output_bfd, /* sym->udata may have been set by generic_link_add_symbol_list. */ 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))) h = bfd_wrapped_link_hash_lookup (output_bfd, info, bfd_asymbol_name (sym), @@ -2755,23 +2811,41 @@ default_indirect_link_order (bfd *output_bfd, } } - /* Get and relocate the section contents. */ - sec_size = (input_section->rawsize > input_section->size - ? input_section->rawsize - : input_section->size); - contents = bfd_malloc (sec_size); - if (contents == NULL && sec_size != 0) - goto error_return; - new_contents = (bfd_get_relocated_section_contents - (output_bfd, info, link_order, contents, info->relocatable, - _bfd_generic_link_get_symbols (input_bfd))); - if (!new_contents) - goto error_return; + 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. */ + sec_size = (input_section->rawsize > input_section->size + ? input_section->rawsize + : input_section->size); + contents = (bfd_byte *) bfd_malloc (sec_size); + if (contents == NULL && sec_size != 0) + goto error_return; + new_contents = (bfd_get_relocated_section_contents + (output_bfd, info, link_order, contents, + info->relocatable, + _bfd_generic_link_get_symbols (input_bfd))); + if (!new_contents) + goto error_return; + } /* Output the section contents. */ - loc = link_order->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, - new_contents, loc, link_order->size)) + new_contents, loc, input_section->size)) goto error_return; if (contents != NULL) @@ -2833,14 +2907,15 @@ FUNCTION bfd_section_already_linked SYNOPSIS - void bfd_section_already_linked (bfd *abfd, asection *sec); + void bfd_section_already_linked (bfd *abfd, asection *sec, + struct bfd_link_info *info); DESCRIPTION Check if @var{sec} has been already linked during a reloceatable or final link. -.#define bfd_section_already_linked(abfd, sec) \ -. BFD_SEND (abfd, _section_already_linked, (abfd, sec)) +.#define bfd_section_already_linked(abfd, sec, info) \ +. BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) . */ @@ -2880,7 +2955,7 @@ bfd_section_already_linked_table_lookup (const char *name) TRUE, FALSE)); } -void +bfd_boolean bfd_section_already_linked_table_insert (struct bfd_section_already_linked_hash_entry *already_linked_list, asection *sec) @@ -2889,10 +2964,14 @@ bfd_section_already_linked_table_insert /* Allocate the memory from the same obstack as the hash table is 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) + return FALSE; l->sec = sec; l->next = already_linked_list->entry; already_linked_list->entry = l; + return TRUE; } static struct bfd_hash_entry * @@ -2901,7 +2980,11 @@ already_linked_newfunc (struct bfd_hash_entry *entry ATTRIBUTE_UNUSED, const char *string ATTRIBUTE_UNUSED) { struct bfd_section_already_linked_hash_entry *ret = - bfd_hash_allocate (table, sizeof *ret); + (struct bfd_section_already_linked_hash_entry *) + bfd_hash_allocate (table, sizeof *ret); + + if (ret == NULL) + return NULL; ret->entry = NULL; @@ -2912,7 +2995,9 @@ bfd_boolean bfd_section_already_linked_table_init (void) { return bfd_hash_table_init_n (&_bfd_section_already_linked_table, - already_linked_newfunc, 42); + already_linked_newfunc, + sizeof (struct bfd_section_already_linked_hash_entry), + 42); } void @@ -2924,7 +3009,8 @@ bfd_section_already_linked_table_free (void) /* This is used on non-ELF inputs. */ void -_bfd_generic_section_already_linked (bfd *abfd, asection *sec) +_bfd_generic_section_already_linked (bfd *abfd, asection *sec, + struct bfd_link_info *info) { flagword flags; const char *name; @@ -3025,5 +3111,267 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec) } /* This is the first section with this name. Record it. */ - 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\n")); +} + +/* Convert symbols in excluded output sections to use a kept section. */ + +static bfd_boolean +fix_syms (struct bfd_link_hash_entry *h, void *data) +{ + bfd *obfd = (bfd *) data; + + if (h->type == bfd_link_hash_warning) + h = h->u.i.link; + + if (h->type == bfd_link_hash_defined + || h->type == bfd_link_hash_defweak) + { + asection *s = h->u.def.section; + if (s != NULL + && s->output_section != NULL + && (s->output_section->flags & SEC_EXCLUDE) != 0 + && bfd_section_removed_from_list (obfd, s->output_section)) + { + asection *op, *op1; + + h->u.def.value += s->output_offset + s->output_section->vma; + + /* Find preceding kept section. */ + for (op1 = s->output_section->prev; op1 != NULL; op1 = op1->prev) + if ((op1->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, op1)) + break; + + /* Find following kept section. Start at prev->next because + other sections may have been added after S was removed. */ + if (s->output_section->prev != NULL) + op = s->output_section->prev->next; + else + op = s->output_section->owner->sections; + for (; op != NULL; op = op->next) + if ((op->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, op)) + break; + + /* Choose better of two sections, based on flags. The idea + is to choose a section that will be in the same segment + as S would have been if it was kept. */ + if (op1 == NULL) + { + if (op == NULL) + op = bfd_abs_section_ptr; + } + else if (op == NULL) + op = op1; + else if (((op1->flags ^ op->flags) + & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0) + { + if (((op->flags ^ s->flags) + & (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; + } + else if (((op1->flags ^ op->flags) & SEC_READONLY) != 0) + { + if (((op->flags ^ s->flags) & SEC_READONLY) != 0) + op = op1; + } + else if (((op1->flags ^ op->flags) & SEC_CODE) != 0) + { + if (((op->flags ^ s->flags) & SEC_CODE) != 0) + op = op1; + } + else + { + /* Flags we care about are the same. Prefer the following + section if that will result in a positive valued sym. */ + if (h->u.def.value < op->vma) + op = op1; + } + + h->u.def.value -= op->vma; + h->u.def.section = op; + } + } + + return TRUE; +} + +void +_bfd_fix_excluded_sec_syms (bfd *obfd, struct bfd_link_info *info) +{ + bfd_link_hash_traverse (info->hash, fix_syms, obfd); +} + +/* +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; }