X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Flinker.c;h=d3ef9a43a5bca8096221870248daf58007c6ef78;hb=879c6bba6a1c00a3518aaa46930586b31f836224;hp=eb0571075bc73f477d32d05ac8df680d1efebfbd;hpb=aa820537ead0135a7c38c619039dce8a6fc74ed1;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/linker.c b/bfd/linker.c index eb0571075b..d3ef9a43a5 100644 --- a/bfd/linker.c +++ b/bfd/linker.c @@ -1,6 +1,6 @@ /* linker.c -- BFD linker routines Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. Written by Steve Chamberlain and Ian Lance Taylor, Cygnus Support @@ -223,7 +223,10 @@ SUBSUBSECTION archive and decide which elements of the archive should be included in the link. For each such element it must call the <> linker callback, and it must add the - symbols from the object file to the linker hash table. + symbols from the object file to the linker hash table. (The + callback may in fact indicate that a replacement BFD should be + used, in which case the symbols from that BFD should be added + to the linker hash table instead.) @findex _bfd_generic_link_add_archive_symbols In most cases the work of looking through the symbols in the @@ -243,9 +246,13 @@ SUBSUBSECTION element should be included in the link. If the element is to be included, the <> linker callback routine must be called with the element as an argument, and - the elements symbols must be added to the linker hash table + the element's symbols must be added to the linker hash table just as though the element had itself been passed to the - <<_bfd_link_add_symbols>> function. + <<_bfd_link_add_symbols>> function. The <> + callback has the option to indicate that it would like to + replace the element archive with a substitute BFD, in which + case it is the symbols of that substitute BFD that must be + added to the linker hash table instead. When the a.out <<_bfd_link_add_symbols>> function receives an archive, it calls <<_bfd_generic_link_add_archive_symbols>> @@ -257,7 +264,8 @@ SUBSUBSECTION symbol) it calls the <> callback and then <> calls <> to actually add the symbols to the - linker hash table. + linker hash table - possibly those of a substitute BFD, if the + <> callback avails itself of that option. The ECOFF back end is unusual in that it does not normally call <<_bfd_generic_link_add_archive_symbols>>, because ECOFF @@ -444,7 +452,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; } @@ -456,10 +465,8 @@ _bfd_link_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_link_hash_entry *h = (struct bfd_link_hash_entry *) entry; /* Initialize the local fields. */ - h->type = bfd_link_hash_new; - memset (&h->u.undef.next, 0, - (sizeof (struct bfd_link_hash_entry) - - offsetof (struct bfd_link_hash_entry, u.undef.next))); + memset ((char *) &h->root + sizeof (h->root), 0, + sizeof (*h) - sizeof (h->root)); } return entry; @@ -548,7 +555,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; @@ -579,7 +586,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; @@ -597,21 +604,32 @@ bfd_wrapped_link_hash_lookup (bfd *abfd, return bfd_link_hash_lookup (info->hash, string, create, copy, follow); } -/* Traverse a generic link hash table. The only reason this is not a - macro is to do better type checking. This code presumes that an - argument passed as a struct bfd_hash_entry * may be caught as a - struct bfd_link_hash_entry * with no explicit cast required on the - call. */ +/* Traverse a generic link hash table. Differs from bfd_hash_traverse + in the treatment of warning symbols. When warning symbols are + created they replace the real symbol, so you don't get to see the + real symbol in a bfd_hash_travere. This traversal calls func with + the real symbol. */ void bfd_link_hash_traverse - (struct bfd_link_hash_table *table, + (struct bfd_link_hash_table *htab, bfd_boolean (*func) (struct bfd_link_hash_entry *, void *), void *info) { - bfd_hash_traverse (&table->table, - (bfd_boolean (*) (struct bfd_hash_entry *, void *)) func, - info); + unsigned int i; + + htab->table.frozen = 1; + for (i = 0; i < htab->table.size; i++) + { + struct bfd_link_hash_entry *p; + + p = (struct bfd_link_hash_entry *) htab->table.table[i]; + for (; p != NULL; p = (struct bfd_link_hash_entry *) p->root.next) + if (!(*func) (p->type == bfd_link_hash_warning ? p->u.i.link : p, info)) + goto out; + } + out: + htab->table.frozen = 0; } /* Add a symbol to the linker hash table undefs list. */ @@ -678,7 +696,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; @@ -707,7 +725,7 @@ _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, @@ -748,7 +766,8 @@ bfd_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)); @@ -791,10 +810,22 @@ void _bfd_generic_link_just_syms (asection *sec, struct bfd_link_info *info ATTRIBUTE_UNUSED) { + sec->sec_info_type = SEC_INFO_TYPE_JUST_SYMS; sec->output_section = bfd_abs_section_ptr; 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 @@ -880,7 +911,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; @@ -943,8 +975,10 @@ archive_hash_table_init included. CHECKFN should set *PNEEDED to TRUE if the object file should be included, and must also call the bfd_link_info add_archive_element callback function and handle adding the symbols - to the global hash table. CHECKFN should only return FALSE if some - sort of error occurs. + to the global hash table. CHECKFN must notice if the callback + indicates a substitute BFD, and arrange to add those symbols instead + if it does so. CHECKFN should only return FALSE if some sort of + error occurs. For some formats, such as a.out, it is possible to look through an object file but not actually include it in the link. The @@ -1051,7 +1085,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; @@ -1199,10 +1233,17 @@ generic_link_check_archive_element (bfd *abfd, { bfd_size_type symcount; asymbol **symbols; + bfd *oldbfd = abfd; /* This object file defines this symbol, so pull it in. */ - if (! (*info->callbacks->add_archive_element) (info, abfd, - bfd_asymbol_name (p))) + if (!(*info->callbacks + ->add_archive_element) (info, abfd, bfd_asymbol_name (p), + &abfd)) + return FALSE; + /* Potentially, the add_archive_element hook may have set a + substitute BFD for us. */ + if (abfd != oldbfd + && !bfd_generic_link_read_symbols (abfd)) return FALSE; symcount = _bfd_generic_link_get_symcount (abfd); symbols = _bfd_generic_link_get_symbols (abfd); @@ -1227,9 +1268,13 @@ generic_link_check_archive_element (bfd *abfd, /* This symbol was created as undefined from outside BFD. We assume that we should link in the object file. This is for the -u option in the linker. */ - if (! (*info->callbacks->add_archive_element) - (info, abfd, bfd_asymbol_name (p))) + if (!(*info->callbacks + ->add_archive_element) (info, abfd, bfd_asymbol_name (p), + &abfd)) return FALSE; + /* Potentially, the add_archive_element hook may have set a + substitute BFD for us. But no symbols are going to get + registered by anything we're returning to from here. */ *pneeded = TRUE; return TRUE; } @@ -1242,7 +1287,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) @@ -1261,7 +1306,7 @@ generic_link_check_archive_element (bfd *abfd, else h->u.c.p->section = bfd_make_section_old_way (symbfd, p->section->name); - h->u.c.p->section->flags = SEC_ALLOC; + h->u.c.p->section->flags |= SEC_ALLOC; } else { @@ -1533,6 +1578,8 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, struct bfd_link_hash_entry *h; bfd_boolean cycle; + BFD_ASSERT (section != NULL); + if (bfd_is_ind_section (section) || (flags & BSF_INDIRECT) != 0) row = INDR_ROW; @@ -1574,8 +1621,8 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, || (info->notice_hash != NULL && bfd_hash_lookup (info->notice_hash, name, FALSE, FALSE) != NULL)) { - if (! (*info->callbacks->notice) (info, h->root.string, abfd, section, - value)) + if (! (*info->callbacks->notice) (info, h, + abfd, section, value, flags, string)) return FALSE; } @@ -1608,7 +1655,6 @@ _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: @@ -1616,9 +1662,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, previously common. */ BFD_ASSERT (h->type == bfd_link_hash_common); if (! ((*info->callbacks->multiple_common) - (info, h->root.string, - h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, - abfd, bfd_link_hash_defined, 0))) + (info, h, abfd, bfd_link_hash_defined, 0))) return FALSE; /* Fall through. */ case DEF: @@ -1691,7 +1735,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) @@ -1723,13 +1767,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, if (section == bfd_com_section_ptr) { h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON"); - h->u.c.p->section->flags = SEC_ALLOC; + h->u.c.p->section->flags |= SEC_ALLOC; } else if (section->owner != abfd) { h->u.c.p->section = bfd_make_section_old_way (abfd, section->name); - h->u.c.p->section->flags = SEC_ALLOC; + h->u.c.p->section->flags |= SEC_ALLOC; } else h->u.c.p->section = section; @@ -1747,9 +1791,7 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, two sizes, and use the section required by the larger symbol. */ BFD_ASSERT (h->type == bfd_link_hash_common); if (! ((*info->callbacks->multiple_common) - (info, h->root.string, - h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, - abfd, bfd_link_hash_common, value))) + (info, h, abfd, bfd_link_hash_common, value))) return FALSE; if (value > h->u.c.size) { @@ -1772,13 +1814,13 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, { h->u.c.p->section = bfd_make_section_old_way (abfd, "COMMON"); - h->u.c.p->section->flags = SEC_ALLOC; + h->u.c.p->section->flags |= SEC_ALLOC; } else if (section->owner != abfd) { h->u.c.p->section = bfd_make_section_old_way (abfd, section->name); - h->u.c.p->section->flags = SEC_ALLOC; + h->u.c.p->section->flags |= SEC_ALLOC; } else h->u.c.p->section = section; @@ -1786,23 +1828,11 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, break; case CREF: - { - bfd *obfd; - - /* We have found a common definition for a symbol which - was already defined. FIXME: It would nice if we could - report the BFD which defined an indirect symbol, but we - don't have anywhere to store the information. */ - if (h->type == bfd_link_hash_defined - || h->type == bfd_link_hash_defweak) - obfd = h->u.def.section->owner; - else - obfd = NULL; - if (! ((*info->callbacks->multiple_common) - (info, h->root.string, obfd, h->type, 0, - abfd, bfd_link_hash_common, value))) - return FALSE; - } + /* We have found a common definition for a symbol which + was already defined. */ + if (! ((*info->callbacks->multiple_common) + (info, h, abfd, bfd_link_hash_common, value))) + return FALSE; break; case MIND: @@ -1813,47 +1843,16 @@ _bfd_generic_link_add_one_symbol (struct bfd_link_info *info, /* Fall through. */ case MDEF: /* Handle a multiple definition. */ - if (!info->allow_multiple_definition) - { - asection *msec = NULL; - bfd_vma mval = 0; - - switch (h->type) - { - case bfd_link_hash_defined: - msec = h->u.def.section; - mval = h->u.def.value; - break; - case bfd_link_hash_indirect: - msec = bfd_ind_section_ptr; - mval = 0; - break; - default: - abort (); - } - - /* Ignore a redefinition of an absolute symbol to the - same value; it's harmless. */ - if (h->type == bfd_link_hash_defined - && bfd_is_abs_section (msec) - && bfd_is_abs_section (section) - && value == mval) - break; - - if (! ((*info->callbacks->multiple_definition) - (info, h->root.string, msec->owner, msec, mval, - abfd, section, value))) - return FALSE; - } + if (! ((*info->callbacks->multiple_definition) + (info, h, abfd, section, value))) + return FALSE; break; case CIND: /* Create an indirect symbol from an existing common symbol. */ BFD_ASSERT (h->type == bfd_link_hash_common); if (! ((*info->callbacks->multiple_common) - (info, h->root.string, - h->u.c.p->section->owner, bfd_link_hash_common, h->u.c.size, - abfd, bfd_link_hash_indirect, 0))) + (info, h, abfd, bfd_link_hash_indirect, 0))) return FALSE; /* Fall through. */ case IND: @@ -1972,7 +1971,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); @@ -2059,7 +2058,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); @@ -2081,7 +2080,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; @@ -2135,7 +2134,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; @@ -2212,7 +2211,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 @@ -2360,6 +2359,12 @@ _bfd_generic_link_output_symbols (bfd *output_bfd, else output = FALSE; } + else if (sym->flags == 0 + && (sym->section->owner->flags & BFD_PLUGIN) != 0) + /* LTO doesn't set symbol information. We get here with the + generic linker for a symbol that was "common" but no longer + needs to be global. */ + output = FALSE; else abort (); @@ -2451,12 +2456,10 @@ 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) - h = (struct generic_link_hash_entry *) h->root.u.i.link; - if (h->written) return TRUE; @@ -2508,7 +2511,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; @@ -2556,7 +2559,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, @@ -2668,10 +2671,17 @@ default_data_link_order (bfd *abfd, fill = link_order->u.data.contents; fill_size = link_order->u.data.size; - if (fill_size != 0 && fill_size < size) + if (fill_size == 0) + { + fill = abfd->arch_info->fill (size, bfd_big_endian (abfd), + (sec->flags & SEC_CODE) != 0); + if (fill == NULL) + return FALSE; + } + else if (fill_size < size) { bfd_byte *p; - fill = bfd_malloc (size); + fill = (bfd_byte *) bfd_malloc (size); if (fill == NULL) return FALSE; p = fill; @@ -2781,7 +2791,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), @@ -2816,7 +2826,7 @@ default_indirect_link_order (bfd *output_bfd, sec_size = (input_section->rawsize > input_section->size ? input_section->rawsize : input_section->size); - contents = bfd_malloc (sec_size); + contents = (bfd_byte *) bfd_malloc (sec_size); if (contents == NULL && sec_size != 0) goto error_return; new_contents = (bfd_get_relocated_section_contents @@ -2892,12 +2902,13 @@ FUNCTION bfd_section_already_linked SYNOPSIS - void bfd_section_already_linked (bfd *abfd, asection *sec, - struct bfd_link_info *info); + bfd_boolean 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. + Check if @var{data} has been already linked during a reloceatable + or final link. Return TRUE if it has. .#define bfd_section_already_linked(abfd, sec, info) \ . BFD_SEND (abfd, _section_already_linked, (abfd, sec, info)) @@ -2949,7 +2960,8 @@ 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; @@ -2964,7 +2976,8 @@ 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; @@ -2989,20 +3002,109 @@ bfd_section_already_linked_table_free (void) bfd_hash_table_free (&_bfd_section_already_linked_table); } +/* Report warnings as appropriate for duplicate section SEC. + Return FALSE if we decide to keep SEC after all. */ + +bfd_boolean +_bfd_handle_already_linked (asection *sec, + struct bfd_section_already_linked *l, + struct bfd_link_info *info) +{ + switch (sec->flags & SEC_LINK_DUPLICATES) + { + default: + abort (); + + case SEC_LINK_DUPLICATES_DISCARD: + /* If we found an LTO IR match for this comdat group on + the first pass, replace it with the LTO output on the + second pass. We can't simply choose real object + files over IR because the first pass may contain a + mix of LTO and normal objects and we must keep the + first match, be it IR or real. */ + if (info->loading_lto_outputs + && (l->sec->owner->flags & BFD_PLUGIN) != 0) + { + l->sec = sec; + return FALSE; + } + break; + + case SEC_LINK_DUPLICATES_ONE_ONLY: + info->callbacks->einfo + (_("%B: ignoring duplicate section `%A'\n"), + sec->owner, sec); + break; + + case SEC_LINK_DUPLICATES_SAME_SIZE: + if ((l->sec->owner->flags & BFD_PLUGIN) != 0) + ; + else if (sec->size != l->sec->size) + info->callbacks->einfo + (_("%B: duplicate section `%A' has different size\n"), + sec->owner, sec); + break; + + case SEC_LINK_DUPLICATES_SAME_CONTENTS: + if ((l->sec->owner->flags & BFD_PLUGIN) != 0) + ; + else if (sec->size != l->sec->size) + info->callbacks->einfo + (_("%B: duplicate section `%A' has different size\n"), + sec->owner, sec); + else if (sec->size != 0) + { + bfd_byte *sec_contents, *l_sec_contents = NULL; + + if (!bfd_malloc_and_get_section (sec->owner, sec, &sec_contents)) + info->callbacks->einfo + (_("%B: could not read contents of section `%A'\n"), + sec->owner, sec); + else if (!bfd_malloc_and_get_section (l->sec->owner, l->sec, + &l_sec_contents)) + info->callbacks->einfo + (_("%B: could not read contents of section `%A'\n"), + l->sec->owner, l->sec); + else if (memcmp (sec_contents, l_sec_contents, sec->size) != 0) + info->callbacks->einfo + (_("%B: duplicate section `%A' has different contents\n"), + sec->owner, sec); + + if (sec_contents) + free (sec_contents); + if (l_sec_contents) + free (l_sec_contents); + } + break; + } + + /* Set the output_section field so that lang_add_section + does not create a lang_input_section structure for this + section. Since there might be a symbol in the section + being discarded, we must retain a pointer to the section + which we are really going to use. */ + sec->output_section = bfd_abs_section_ptr; + sec->kept_section = l->sec; + return TRUE; +} + /* This is used on non-ELF inputs. */ -void -_bfd_generic_section_already_linked (bfd *abfd, asection *sec, +bfd_boolean +_bfd_generic_section_already_linked (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, struct bfd_link_info *info) { - flagword flags; const char *name; struct bfd_section_already_linked *l; struct bfd_section_already_linked_hash_entry *already_linked_list; - flags = sec->flags; - if ((flags & SEC_LINK_ONCE) == 0) - return; + if ((sec->flags & SEC_LINK_ONCE) == 0) + return FALSE; + + /* The generic linker doesn't handle section groups. */ + if ((sec->flags & SEC_GROUP) != 0) + return FALSE; /* FIXME: When doing a relocatable link, we may have trouble copying relocations in other sections that refer to local symbols @@ -3021,81 +3123,88 @@ _bfd_generic_section_already_linked (bfd *abfd, asection *sec, already_linked_list = bfd_section_already_linked_table_lookup (name); - for (l = already_linked_list->entry; l != NULL; l = l->next) + l = already_linked_list->entry; + if (l != NULL) { - bfd_boolean skip = FALSE; - struct coff_comdat_info *s_comdat - = bfd_coff_get_comdat_section (abfd, sec); - struct coff_comdat_info *l_comdat - = bfd_coff_get_comdat_section (l->sec->owner, l->sec); - - /* We may have 3 different sections on the list: group section, - comdat section and linkonce section. SEC may be a linkonce or - comdat section. We always ignore group section. For non-COFF - inputs, we also ignore comdat section. - - FIXME: Is that safe to match a linkonce section with a comdat - section for COFF inputs? */ - if ((l->sec->flags & SEC_GROUP) != 0) - skip = TRUE; - else if (bfd_get_flavour (abfd) == bfd_target_coff_flavour) - { - if (s_comdat != NULL - && l_comdat != NULL - && strcmp (s_comdat->name, l_comdat->name) != 0) - skip = TRUE; - } - else if (l_comdat != NULL) - skip = TRUE; + /* The section has already been linked. See if we should + issue a warning. */ + return _bfd_handle_already_linked (sec, l, info); + } - if (!skip) - { - /* The section has already been linked. See if we should - issue a warning. */ - switch (flags & SEC_LINK_DUPLICATES) - { - default: - abort (); + /* This is the first section with this name. Record it. */ + if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) + info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); + return FALSE; +} - case SEC_LINK_DUPLICATES_DISCARD: - break; +/* Choose a neighbouring section to S in OBFD that will be output, or + the absolute section if ADDR is out of bounds of the neighbours. */ - case SEC_LINK_DUPLICATES_ONE_ONLY: - (*_bfd_error_handler) - (_("%B: warning: ignoring duplicate section `%A'\n"), - abfd, sec); - break; +asection * +_bfd_nearby_section (bfd *obfd, asection *s, bfd_vma addr) +{ + asection *next, *prev, *best; - case SEC_LINK_DUPLICATES_SAME_CONTENTS: - /* FIXME: We should really dig out the contents of both - sections and memcmp them. The COFF/PE spec says that - the Microsoft linker does not implement this - correctly, so I'm not going to bother doing it - either. */ - /* Fall through. */ - case SEC_LINK_DUPLICATES_SAME_SIZE: - if (sec->size != l->sec->size) - (*_bfd_error_handler) - (_("%B: warning: duplicate section `%A' has different size\n"), - abfd, sec); - break; - } + /* Find preceding kept section. */ + for (prev = s->prev; prev != NULL; prev = prev->prev) + if ((prev->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, prev)) + break; - /* Set the output_section field so that lang_add_section - does not create a lang_input_section structure for this - section. Since there might be a symbol in the section - being discarded, we must retain a pointer to the section - which we are really going to use. */ - sec->output_section = bfd_abs_section_ptr; - sec->kept_section = l->sec; + /* Find following kept section. Start at prev->next because + other sections may have been added after S was removed. */ + if (s->prev != NULL) + next = s->prev->next; + else + next = s->owner->sections; + for (; next != NULL; next = next->next) + if ((next->flags & SEC_EXCLUDE) == 0 + && !bfd_section_removed_from_list (obfd, next)) + break; - return; - } + /* 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. */ + best = next; + if (prev == NULL) + { + if (next == NULL) + best = bfd_abs_section_ptr; + } + else if (next == NULL) + best = prev; + else if (((prev->flags ^ next->flags) + & (SEC_ALLOC | SEC_THREAD_LOCAL | SEC_LOAD)) != 0) + { + if (((next->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 NEXT and PREV. */ + || ((prev->flags & SEC_LOAD) != 0 + && (next->flags & SEC_LOAD) == 0)) + best = prev; + } + else if (((prev->flags ^ next->flags) & SEC_READONLY) != 0) + { + if (((next->flags ^ s->flags) & SEC_READONLY) != 0) + best = prev; + } + else if (((prev->flags ^ next->flags) & SEC_CODE) != 0) + { + if (((next->flags ^ s->flags) & SEC_CODE) != 0) + best = prev; + } + else + { + /* Flags we care about are the same. Prefer the following + section if that will result in a positive valued sym. */ + if (addr < next->vma) + best = prev; } - /* This is the first section with this name. Record it. */ - if (! bfd_section_already_linked_table_insert (already_linked_list, sec)) - info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); + return best; } /* Convert symbols in excluded output sections to use a kept section. */ @@ -3105,9 +3214,6 @@ 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) { @@ -3117,68 +3223,10 @@ fix_syms (struct bfd_link_hash_entry *h, void *data) && (s->output_section->flags & SEC_EXCLUDE) != 0 && bfd_section_removed_from_list (obfd, s->output_section)) { - asection *op, *op1; + asection *op; 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; - } - + op = _bfd_nearby_section (obfd, s->output_section, h->u.def.value); h->u.def.value -= op->vma; h->u.def.section = op; } @@ -3358,3 +3406,26 @@ bfd_find_version_for_sym (struct bfd_elf_version_tree *verdefs, return NULL; } + +/* +FUNCTION + bfd_hide_sym_by_version + +SYNOPSIS + bfd_boolean bfd_hide_sym_by_version + (struct bfd_elf_version_tree *verdefs, const char *sym_name); + +DESCRIPTION + Search an elf version script tree for symbol versioning + info for a given symbol. Return TRUE if the symbol is hidden. + +*/ + +bfd_boolean +bfd_hide_sym_by_version (struct bfd_elf_version_tree *verdefs, + const char *sym_name) +{ + bfd_boolean hidden = FALSE; + bfd_find_version_for_sym (verdefs, sym_name, &hidden); + return hidden; +}