From: Alan Modra Date: Tue, 24 Jul 2007 08:09:20 +0000 (+0000) Subject: * elflink.c (_bfd_elf_link_just_syms, merge_sections_remove_hook, X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=4d269e42e3f7970f4d54d528d0532a936e946ecf;p=binutils-gdb.git * elflink.c (_bfd_elf_link_just_syms, merge_sections_remove_hook, _bfd_elf_merge_sections, _bfd_elf_link_hash_newfunc, _bfd_elf_link_hash_copy_indirect, _bfd_elf_link_hash_hide_symbol, _bfd_elf_link_hash_table_init, _bfd_elf_link_hash_table_create, bfd_elf_set_dt_needed_name, bfd_elf_get_dyn_lib_class, bfd_elf_set_dyn_lib_class, bfd_elf_get_needed_list, bfd_elf_get_runpath_list, bfd_elf_get_dt_soname, bfd_elf_get_bfd_needed_list, struct elf_symbuf_symbol, struct elf_symbuf_head, struct elf_symbol, elf_sort_elf_symbol, elf_sym_name_compare, elf_create_symbuf, bfd_elf_match_symbols_in_sections, _bfd_elf_match_sections_by_type): Move to here.. * elf.c: ..from here. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 5d3c9392285..22f8641e2f9 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,19 @@ +2007-07-24 Alan Modra + + * elflink.c (_bfd_elf_link_just_syms, merge_sections_remove_hook, + _bfd_elf_merge_sections, _bfd_elf_link_hash_newfunc, + _bfd_elf_link_hash_copy_indirect, _bfd_elf_link_hash_hide_symbol, + _bfd_elf_link_hash_table_init, _bfd_elf_link_hash_table_create, + bfd_elf_set_dt_needed_name, bfd_elf_get_dyn_lib_class, + bfd_elf_set_dyn_lib_class, bfd_elf_get_needed_list, + bfd_elf_get_runpath_list, bfd_elf_get_dt_soname, + bfd_elf_get_bfd_needed_list, struct elf_symbuf_symbol, + struct elf_symbuf_head, struct elf_symbol, elf_sort_elf_symbol, + elf_sym_name_compare, elf_create_symbuf, + bfd_elf_match_symbols_in_sections, + _bfd_elf_match_sections_by_type): Move to here.. + * elf.c: ..from here. + 2007-07-23 Richard Sandiford * elflink.c (_bfd_elf_fix_symbol_flags): Only assert the type @@ -13,20 +29,20 @@ 2007-07-19 Doug Kwan - PR binutils/4797 - * dwarf2.c: (find_line) Do not dereference functionname_ptr if - do_line is true. + PR binutils/4797 + * dwarf2.c: (find_line) Do not dereference functionname_ptr if + do_line is true. 2007-07-18 Bob Wilson - + * elf32-xtensa.c (xtensa_callback_required_dependence): Ignore non-ELF sections. - + 2007-07-18 Bob Wilson - + * elf32-xtensa.c (elf_xtensa_finish_dynamic_sections): Get section vma and size for dynamic tags from the output sections. - + 2007-07-18 Alan Modra * elf-bfd.h (struct sym_sec_cache): Delete "sec". Add "shndx". diff --git a/bfd/elf.c b/bfd/elf.c index cf7436f59ae..f8bd7f9e35d 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -1044,61 +1044,6 @@ bfd_elf_generic_reloc (bfd *abfd ATTRIBUTE_UNUSED, return bfd_reloc_continue; } -/* Make sure sec_info_type is cleared if sec_info is cleared too. */ - -static void -merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED, - asection *sec) -{ - BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE); - sec->sec_info_type = ELF_INFO_TYPE_NONE; -} - -/* Finish SHF_MERGE section merging. */ - -bfd_boolean -_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info) -{ - bfd *ibfd; - asection *sec; - - if (!is_elf_hash_table (info->hash)) - return FALSE; - - for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) - if ((ibfd->flags & DYNAMIC) == 0) - for (sec = ibfd->sections; sec != NULL; sec = sec->next) - if ((sec->flags & SEC_MERGE) != 0 - && !bfd_is_abs_section (sec->output_section)) - { - struct bfd_elf_section_data *secdata; - - secdata = elf_section_data (sec); - if (! _bfd_add_merge_section (abfd, - &elf_hash_table (info)->merge_info, - sec, &secdata->sec_info)) - return FALSE; - else if (secdata->sec_info) - sec->sec_info_type = ELF_INFO_TYPE_MERGE; - } - - if (elf_hash_table (info)->merge_info != NULL) - _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info, - merge_sections_remove_hook); - return TRUE; -} - -void -_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info) -{ - sec->output_section = bfd_abs_section_ptr; - sec->output_offset = sec->vma; - if (!is_elf_hash_table (info->hash)) - return; - - sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS; -} - /* Copy the program header and other data from one object module to another. */ @@ -1496,319 +1441,7 @@ bfd_elf_print_symbol (bfd *abfd, break; } } - -/* Create an entry in an ELF linker hash table. */ - -struct bfd_hash_entry * -_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (entry == NULL) - { - entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = _bfd_link_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry; - struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table; - - /* Set local fields. */ - ret->indx = -1; - ret->dynindx = -1; - ret->got = htab->init_got_refcount; - ret->plt = htab->init_plt_refcount; - memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) - - offsetof (struct elf_link_hash_entry, size))); - /* Assume that we have been called by a non-ELF symbol reader. - This flag is then reset by the code which reads an ELF input - file. This ensures that a symbol created by a non-ELF symbol - reader will have the flag set correctly. */ - ret->non_elf = 1; - } - - return entry; -} - -/* Copy data from an indirect symbol to its direct symbol, hiding the - old indirect symbol. Also used for copying flags to a weakdef. */ - -void -_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_link_hash_table *htab; - - /* Copy down any references that we may have already seen to the - symbol which just became indirect. */ - - dir->ref_dynamic |= ind->ref_dynamic; - dir->ref_regular |= ind->ref_regular; - dir->ref_regular_nonweak |= ind->ref_regular_nonweak; - dir->non_got_ref |= ind->non_got_ref; - dir->needs_plt |= ind->needs_plt; - dir->pointer_equality_needed |= ind->pointer_equality_needed; - - if (ind->root.type != bfd_link_hash_indirect) - return; - - /* Copy over the global and procedure linkage table refcount entries. - These may have been already set up by a check_relocs routine. */ - htab = elf_hash_table (info); - if (ind->got.refcount > htab->init_got_refcount.refcount) - { - if (dir->got.refcount < 0) - dir->got.refcount = 0; - dir->got.refcount += ind->got.refcount; - ind->got.refcount = htab->init_got_refcount.refcount; - } - - if (ind->plt.refcount > htab->init_plt_refcount.refcount) - { - if (dir->plt.refcount < 0) - dir->plt.refcount = 0; - dir->plt.refcount += ind->plt.refcount; - ind->plt.refcount = htab->init_plt_refcount.refcount; - } - - if (ind->dynindx != -1) - { - if (dir->dynindx != -1) - _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index); - dir->dynindx = ind->dynindx; - dir->dynstr_index = ind->dynstr_index; - ind->dynindx = -1; - ind->dynstr_index = 0; - } -} - -void -_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h, - bfd_boolean force_local) -{ - h->plt = elf_hash_table (info)->init_plt_offset; - h->needs_plt = 0; - if (force_local) - { - h->forced_local = 1; - if (h->dynindx != -1) - { - h->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - h->dynstr_index); - } - } -} - -/* Initialize an ELF linker hash table. */ - -bfd_boolean -_bfd_elf_link_hash_table_init - (struct elf_link_hash_table *table, - bfd *abfd, - struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, - struct bfd_hash_table *, - const char *), - unsigned int entsize) -{ - bfd_boolean ret; - int can_refcount = get_elf_backend_data (abfd)->can_refcount; - - memset (table, 0, sizeof * table); - table->init_got_refcount.refcount = can_refcount - 1; - table->init_plt_refcount.refcount = can_refcount - 1; - table->init_got_offset.offset = -(bfd_vma) 1; - table->init_plt_offset.offset = -(bfd_vma) 1; - /* The first dynamic symbol is a dummy. */ - table->dynsymcount = 1; - - ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); - table->root.type = bfd_link_elf_hash_table; - - return ret; -} - -/* Create an ELF linker hash table. */ - -struct bfd_link_hash_table * -_bfd_elf_link_hash_table_create (bfd *abfd) -{ - struct elf_link_hash_table *ret; - bfd_size_type amt = sizeof (struct elf_link_hash_table); - - ret = bfd_malloc (amt); - if (ret == NULL) - return NULL; - - if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc, - sizeof (struct elf_link_hash_entry))) - { - free (ret); - return NULL; - } - - return &ret->root; -} - -/* This is a hook for the ELF emulation code in the generic linker to - tell the backend linker what file name to use for the DT_NEEDED - entry for a dynamic object. */ - -void -bfd_elf_set_dt_needed_name (bfd *abfd, const char *name) -{ - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && bfd_get_format (abfd) == bfd_object) - elf_dt_name (abfd) = name; -} - -int -bfd_elf_get_dyn_lib_class (bfd *abfd) -{ - int lib_class; - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && bfd_get_format (abfd) == bfd_object) - lib_class = elf_dyn_lib_class (abfd); - else - lib_class = 0; - return lib_class; -} - -void -bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class) -{ - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && bfd_get_format (abfd) == bfd_object) - elf_dyn_lib_class (abfd) = lib_class; -} - -/* Get the list of DT_NEEDED entries for a link. This is a hook for - the linker ELF emulation code. */ - -struct bfd_link_needed_list * -bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - if (! is_elf_hash_table (info->hash)) - return NULL; - return elf_hash_table (info)->needed; -} - -/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a - hook for the linker ELF emulation code. */ - -struct bfd_link_needed_list * -bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED, - struct bfd_link_info *info) -{ - if (! is_elf_hash_table (info->hash)) - return NULL; - return elf_hash_table (info)->runpath; -} - -/* Get the name actually used for a dynamic object for a link. This - is the SONAME entry if there is one. Otherwise, it is the string - passed to bfd_elf_set_dt_needed_name, or it is the filename. */ - -const char * -bfd_elf_get_dt_soname (bfd *abfd) -{ - if (bfd_get_flavour (abfd) == bfd_target_elf_flavour - && bfd_get_format (abfd) == bfd_object) - return elf_dt_name (abfd); - return NULL; -} - -/* Get the list of DT_NEEDED entries from a BFD. This is a hook for - the ELF linker emulation code. */ - -bfd_boolean -bfd_elf_get_bfd_needed_list (bfd *abfd, - struct bfd_link_needed_list **pneeded) -{ - asection *s; - bfd_byte *dynbuf = NULL; - int elfsec; - unsigned long shlink; - bfd_byte *extdyn, *extdynend; - size_t extdynsize; - void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); - - *pneeded = NULL; - - if (bfd_get_flavour (abfd) != bfd_target_elf_flavour - || bfd_get_format (abfd) != bfd_object) - return TRUE; - - s = bfd_get_section_by_name (abfd, ".dynamic"); - if (s == NULL || s->size == 0) - return TRUE; - - if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) - goto error_return; - - elfsec = _bfd_elf_section_from_bfd_section (abfd, s); - if (elfsec == -1) - goto error_return; - shlink = elf_elfsections (abfd)[elfsec]->sh_link; - - extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; - swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; - - extdyn = dynbuf; - extdynend = extdyn + s->size; - for (; extdyn < extdynend; extdyn += extdynsize) - { - Elf_Internal_Dyn dyn; - - (*swap_dyn_in) (abfd, extdyn, &dyn); - - if (dyn.d_tag == DT_NULL) - break; - - if (dyn.d_tag == DT_NEEDED) - { - const char *string; - struct bfd_link_needed_list *l; - unsigned int tagv = dyn.d_un.d_val; - bfd_size_type amt; - - string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); - if (string == NULL) - goto error_return; - - amt = sizeof *l; - l = bfd_alloc (abfd, amt); - if (l == NULL) - goto error_return; - - l->by = abfd; - l->name = string; - l->next = *pneeded; - *pneeded = l; - } - } - - free (dynbuf); - - return TRUE; - - error_return: - if (dynbuf != NULL) - free (dynbuf); - return FALSE; -} - /* Allocate an ELF string table--force the first byte to be zero. */ struct bfd_strtab_hash * @@ -8824,365 +8457,11 @@ _bfd_elf_get_synthetic_symtab (bfd *abfd, return n; } -struct elf_symbuf_symbol -{ - unsigned long st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* Visibilty, and target specific */ -}; - -struct elf_symbuf_head -{ - struct elf_symbuf_symbol *ssym; - bfd_size_type count; - unsigned int st_shndx; -}; - -struct elf_symbol -{ - union - { - Elf_Internal_Sym *isym; - struct elf_symbuf_symbol *ssym; - } u; - const char *name; -}; - -/* Sort references to symbols by ascending section number. */ - -static int -elf_sort_elf_symbol (const void *arg1, const void *arg2) -{ - const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1; - const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2; - - return s1->st_shndx - s2->st_shndx; -} - -static int -elf_sym_name_compare (const void *arg1, const void *arg2) -{ - const struct elf_symbol *s1 = (const struct elf_symbol *) arg1; - const struct elf_symbol *s2 = (const struct elf_symbol *) arg2; - return strcmp (s1->name, s2->name); -} - -static struct elf_symbuf_head * -elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf) -{ - Elf_Internal_Sym **ind, **indbufend, **indbuf - = bfd_malloc2 (symcount, sizeof (*indbuf)); - struct elf_symbuf_symbol *ssym; - struct elf_symbuf_head *ssymbuf, *ssymhead; - bfd_size_type i, shndx_count; - - if (indbuf == NULL) - return NULL; - - for (ind = indbuf, i = 0; i < symcount; i++) - if (isymbuf[i].st_shndx != SHN_UNDEF) - *ind++ = &isymbuf[i]; - indbufend = ind; - - qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *), - elf_sort_elf_symbol); - - shndx_count = 0; - if (indbufend > indbuf) - for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++) - if (ind[0]->st_shndx != ind[1]->st_shndx) - shndx_count++; - - ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf) - + (indbufend - indbuf) * sizeof (*ssymbuf)); - if (ssymbuf == NULL) - { - free (indbuf); - return NULL; - } - - ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count); - ssymbuf->ssym = NULL; - ssymbuf->count = shndx_count; - ssymbuf->st_shndx = 0; - for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++) - { - if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx) - { - ssymhead++; - ssymhead->ssym = ssym; - ssymhead->count = 0; - ssymhead->st_shndx = (*ind)->st_shndx; - } - ssym->st_name = (*ind)->st_name; - ssym->st_info = (*ind)->st_info; - ssym->st_other = (*ind)->st_other; - ssymhead->count++; - } - BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count); - - free (indbuf); - return ssymbuf; -} - -/* Check if 2 sections define the same set of local and global - symbols. */ - -bfd_boolean -bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, - struct bfd_link_info *info) -{ - bfd *bfd1, *bfd2; - const struct elf_backend_data *bed1, *bed2; - Elf_Internal_Shdr *hdr1, *hdr2; - bfd_size_type symcount1, symcount2; - Elf_Internal_Sym *isymbuf1, *isymbuf2; - struct elf_symbuf_head *ssymbuf1, *ssymbuf2; - Elf_Internal_Sym *isym, *isymend; - struct elf_symbol *symtable1 = NULL, *symtable2 = NULL; - bfd_size_type count1, count2, i; - int shndx1, shndx2; - bfd_boolean result; - - bfd1 = sec1->owner; - bfd2 = sec2->owner; - - /* If both are .gnu.linkonce sections, they have to have the same - section name. */ - if (CONST_STRNEQ (sec1->name, ".gnu.linkonce") - && CONST_STRNEQ (sec2->name, ".gnu.linkonce")) - return strcmp (sec1->name + sizeof ".gnu.linkonce", - sec2->name + sizeof ".gnu.linkonce") == 0; - - /* Both sections have to be in ELF. */ - if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour - || bfd_get_flavour (bfd2) != bfd_target_elf_flavour) - return FALSE; - - if (elf_section_type (sec1) != elf_section_type (sec2)) - return FALSE; - - if ((elf_section_flags (sec1) & SHF_GROUP) != 0 - && (elf_section_flags (sec2) & SHF_GROUP) != 0) - { - /* If both are members of section groups, they have to have the - same group name. */ - if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0) - return FALSE; - } - - shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1); - shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2); - if (shndx1 == -1 || shndx2 == -1) - return FALSE; - - bed1 = get_elf_backend_data (bfd1); - bed2 = get_elf_backend_data (bfd2); - hdr1 = &elf_tdata (bfd1)->symtab_hdr; - symcount1 = hdr1->sh_size / bed1->s->sizeof_sym; - hdr2 = &elf_tdata (bfd2)->symtab_hdr; - symcount2 = hdr2->sh_size / bed2->s->sizeof_sym; - - if (symcount1 == 0 || symcount2 == 0) - return FALSE; - - result = FALSE; - isymbuf1 = NULL; - isymbuf2 = NULL; - ssymbuf1 = elf_tdata (bfd1)->symbuf; - ssymbuf2 = elf_tdata (bfd2)->symbuf; - - if (ssymbuf1 == NULL) - { - isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, - NULL, NULL, NULL); - if (isymbuf1 == NULL) - goto done; - - if (!info->reduce_memory_overheads) - elf_tdata (bfd1)->symbuf = ssymbuf1 - = elf_create_symbuf (symcount1, isymbuf1); - } - - if (ssymbuf1 == NULL || ssymbuf2 == NULL) - { - isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, - NULL, NULL, NULL); - if (isymbuf2 == NULL) - goto done; - - if (ssymbuf1 != NULL && !info->reduce_memory_overheads) - elf_tdata (bfd2)->symbuf = ssymbuf2 - = elf_create_symbuf (symcount2, isymbuf2); - } - - if (ssymbuf1 != NULL && ssymbuf2 != NULL) - { - /* Optimized faster version. */ - bfd_size_type lo, hi, mid; - struct elf_symbol *symp; - struct elf_symbuf_symbol *ssym, *ssymend; - - lo = 0; - hi = ssymbuf1->count; - ssymbuf1++; - count1 = 0; - while (lo < hi) - { - mid = (lo + hi) / 2; - if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx) - hi = mid; - else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx) - lo = mid + 1; - else - { - count1 = ssymbuf1[mid].count; - ssymbuf1 += mid; - break; - } - } - - lo = 0; - hi = ssymbuf2->count; - ssymbuf2++; - count2 = 0; - while (lo < hi) - { - mid = (lo + hi) / 2; - if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx) - hi = mid; - else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx) - lo = mid + 1; - else - { - count2 = ssymbuf2[mid].count; - ssymbuf2 += mid; - break; - } - } - - if (count1 == 0 || count2 == 0 || count1 != count2) - goto done; - - symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol)); - symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol)); - if (symtable1 == NULL || symtable2 == NULL) - goto done; - - symp = symtable1; - for (ssym = ssymbuf1->ssym, ssymend = ssym + count1; - ssym < ssymend; ssym++, symp++) - { - symp->u.ssym = ssym; - symp->name = bfd_elf_string_from_elf_section (bfd1, - hdr1->sh_link, - ssym->st_name); - } - - symp = symtable2; - for (ssym = ssymbuf2->ssym, ssymend = ssym + count2; - ssym < ssymend; ssym++, symp++) - { - symp->u.ssym = ssym; - symp->name = bfd_elf_string_from_elf_section (bfd2, - hdr2->sh_link, - ssym->st_name); - } - - /* Sort symbol by name. */ - qsort (symtable1, count1, sizeof (struct elf_symbol), - elf_sym_name_compare); - qsort (symtable2, count1, sizeof (struct elf_symbol), - elf_sym_name_compare); - - for (i = 0; i < count1; i++) - /* Two symbols must have the same binding, type and name. */ - if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info - || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other - || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) - goto done; - - result = TRUE; - goto done; - } - - symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol)); - symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol)); - if (symtable1 == NULL || symtable2 == NULL) - goto done; - - /* Count definitions in the section. */ - count1 = 0; - for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++) - if (isym->st_shndx == (unsigned int) shndx1) - symtable1[count1++].u.isym = isym; - - count2 = 0; - for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++) - if (isym->st_shndx == (unsigned int) shndx2) - symtable2[count2++].u.isym = isym; - - if (count1 == 0 || count2 == 0 || count1 != count2) - goto done; - - for (i = 0; i < count1; i++) - symtable1[i].name - = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, - symtable1[i].u.isym->st_name); - - for (i = 0; i < count2; i++) - symtable2[i].name - = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, - symtable2[i].u.isym->st_name); - - /* Sort symbol by name. */ - qsort (symtable1, count1, sizeof (struct elf_symbol), - elf_sym_name_compare); - qsort (symtable2, count1, sizeof (struct elf_symbol), - elf_sym_name_compare); - - for (i = 0; i < count1; i++) - /* Two symbols must have the same binding, type and name. */ - if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info - || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other - || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) - goto done; - - result = TRUE; - -done: - if (symtable1) - free (symtable1); - if (symtable2) - free (symtable2); - if (isymbuf1) - free (isymbuf1); - if (isymbuf2) - free (isymbuf2); - - return result; -} - /* It is only used by x86-64 so far. */ asection _bfd_elf_large_com_section = BFD_FAKE_SECTION (_bfd_elf_large_com_section, SEC_IS_COMMON, NULL, "LARGE_COMMON", 0); -/* Return TRUE if 2 section types are compatible. */ - -bfd_boolean -_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec, - bfd *bbfd, const asection *bsec) -{ - if (asec == NULL - || bsec == NULL - || abfd->xvec->flavour != bfd_target_elf_flavour - || bbfd->xvec->flavour != bfd_target_elf_flavour) - return TRUE; - - return elf_section_type (asec) == elf_section_type (bsec); -} - void _bfd_elf_set_osabi (bfd * abfd, struct bfd_link_info * link_info ATTRIBUTE_UNUSED) diff --git a/bfd/elflink.c b/bfd/elflink.c index cd8b756d66c..2fd8f053ef9 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -6389,7 +6389,728 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) return TRUE; } + +/* Indicate that we are only retrieving symbol values from this + section. */ + +void +_bfd_elf_link_just_syms (asection *sec, struct bfd_link_info *info) +{ + if (is_elf_hash_table (info->hash)) + sec->sec_info_type = ELF_INFO_TYPE_JUST_SYMS; + _bfd_generic_link_just_syms (sec, info); +} + +/* Make sure sec_info_type is cleared if sec_info is cleared too. */ + +static void +merge_sections_remove_hook (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec) +{ + BFD_ASSERT (sec->sec_info_type == ELF_INFO_TYPE_MERGE); + sec->sec_info_type = ELF_INFO_TYPE_NONE; +} + +/* Finish SHF_MERGE section merging. */ + +bfd_boolean +_bfd_elf_merge_sections (bfd *abfd, struct bfd_link_info *info) +{ + bfd *ibfd; + asection *sec; + + if (!is_elf_hash_table (info->hash)) + return FALSE; + + for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) + if ((ibfd->flags & DYNAMIC) == 0) + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & SEC_MERGE) != 0 + && !bfd_is_abs_section (sec->output_section)) + { + struct bfd_elf_section_data *secdata; + + secdata = elf_section_data (sec); + if (! _bfd_add_merge_section (abfd, + &elf_hash_table (info)->merge_info, + sec, &secdata->sec_info)) + return FALSE; + else if (secdata->sec_info) + sec->sec_info_type = ELF_INFO_TYPE_MERGE; + } + + if (elf_hash_table (info)->merge_info != NULL) + _bfd_merge_sections (abfd, info, elf_hash_table (info)->merge_info, + merge_sections_remove_hook); + return TRUE; +} + +/* Create an entry in an ELF linker hash table. */ + +struct bfd_hash_entry * +_bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_link_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf_link_hash_entry *ret = (struct elf_link_hash_entry *) entry; + struct elf_link_hash_table *htab = (struct elf_link_hash_table *) table; + + /* Set local fields. */ + ret->indx = -1; + ret->dynindx = -1; + ret->got = htab->init_got_refcount; + ret->plt = htab->init_plt_refcount; + memset (&ret->size, 0, (sizeof (struct elf_link_hash_entry) + - offsetof (struct elf_link_hash_entry, size))); + /* Assume that we have been called by a non-ELF symbol reader. + This flag is then reset by the code which reads an ELF input + file. This ensures that a symbol created by a non-ELF symbol + reader will have the flag set correctly. */ + ret->non_elf = 1; + } + + return entry; +} + +/* Copy data from an indirect symbol to its direct symbol, hiding the + old indirect symbol. Also used for copying flags to a weakdef. */ + +void +_bfd_elf_link_hash_copy_indirect (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_link_hash_table *htab; + + /* Copy down any references that we may have already seen to the + symbol which just became indirect. */ + + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->non_got_ref |= ind->non_got_ref; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; + + if (ind->root.type != bfd_link_hash_indirect) + return; + + /* Copy over the global and procedure linkage table refcount entries. + These may have been already set up by a check_relocs routine. */ + htab = elf_hash_table (info); + if (ind->got.refcount > htab->init_got_refcount.refcount) + { + if (dir->got.refcount < 0) + dir->got.refcount = 0; + dir->got.refcount += ind->got.refcount; + ind->got.refcount = htab->init_got_refcount.refcount; + } + + if (ind->plt.refcount > htab->init_plt_refcount.refcount) + { + if (dir->plt.refcount < 0) + dir->plt.refcount = 0; + dir->plt.refcount += ind->plt.refcount; + ind->plt.refcount = htab->init_plt_refcount.refcount; + } + + if (ind->dynindx != -1) + { + if (dir->dynindx != -1) + _bfd_elf_strtab_delref (htab->dynstr, dir->dynstr_index); + dir->dynindx = ind->dynindx; + dir->dynstr_index = ind->dynstr_index; + ind->dynindx = -1; + ind->dynstr_index = 0; + } +} + +void +_bfd_elf_link_hash_hide_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h, + bfd_boolean force_local) +{ + h->plt = elf_hash_table (info)->init_plt_offset; + h->needs_plt = 0; + if (force_local) + { + h->forced_local = 1; + if (h->dynindx != -1) + { + h->dynindx = -1; + _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, + h->dynstr_index); + } + } +} + +/* Initialize an ELF linker hash table. */ + +bfd_boolean +_bfd_elf_link_hash_table_init + (struct elf_link_hash_table *table, + bfd *abfd, + struct bfd_hash_entry *(*newfunc) (struct bfd_hash_entry *, + struct bfd_hash_table *, + const char *), + unsigned int entsize) +{ + bfd_boolean ret; + int can_refcount = get_elf_backend_data (abfd)->can_refcount; + + memset (table, 0, sizeof * table); + table->init_got_refcount.refcount = can_refcount - 1; + table->init_plt_refcount.refcount = can_refcount - 1; + table->init_got_offset.offset = -(bfd_vma) 1; + table->init_plt_offset.offset = -(bfd_vma) 1; + /* The first dynamic symbol is a dummy. */ + table->dynsymcount = 1; + + ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc, entsize); + table->root.type = bfd_link_elf_hash_table; + + return ret; +} + +/* Create an ELF linker hash table. */ + +struct bfd_link_hash_table * +_bfd_elf_link_hash_table_create (bfd *abfd) +{ + struct elf_link_hash_table *ret; + bfd_size_type amt = sizeof (struct elf_link_hash_table); + + ret = bfd_malloc (amt); + if (ret == NULL) + return NULL; + + if (! _bfd_elf_link_hash_table_init (ret, abfd, _bfd_elf_link_hash_newfunc, + sizeof (struct elf_link_hash_entry))) + { + free (ret); + return NULL; + } + + return &ret->root; +} + +/* This is a hook for the ELF emulation code in the generic linker to + tell the backend linker what file name to use for the DT_NEEDED + entry for a dynamic object. */ + +void +bfd_elf_set_dt_needed_name (bfd *abfd, const char *name) +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dt_name (abfd) = name; +} + +int +bfd_elf_get_dyn_lib_class (bfd *abfd) +{ + int lib_class; + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + lib_class = elf_dyn_lib_class (abfd); + else + lib_class = 0; + return lib_class; +} + +void +bfd_elf_set_dyn_lib_class (bfd *abfd, enum dynamic_lib_link_class lib_class) +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + elf_dyn_lib_class (abfd) = lib_class; +} + +/* Get the list of DT_NEEDED entries for a link. This is a hook for + the linker ELF emulation code. */ + +struct bfd_link_needed_list * +bfd_elf_get_needed_list (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + if (! is_elf_hash_table (info->hash)) + return NULL; + return elf_hash_table (info)->needed; +} + +/* Get the list of DT_RPATH/DT_RUNPATH entries for a link. This is a + hook for the linker ELF emulation code. */ + +struct bfd_link_needed_list * +bfd_elf_get_runpath_list (bfd *abfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) +{ + if (! is_elf_hash_table (info->hash)) + return NULL; + return elf_hash_table (info)->runpath; +} + +/* Get the name actually used for a dynamic object for a link. This + is the SONAME entry if there is one. Otherwise, it is the string + passed to bfd_elf_set_dt_needed_name, or it is the filename. */ + +const char * +bfd_elf_get_dt_soname (bfd *abfd) +{ + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && bfd_get_format (abfd) == bfd_object) + return elf_dt_name (abfd); + return NULL; +} + +/* Get the list of DT_NEEDED entries from a BFD. This is a hook for + the ELF linker emulation code. */ + +bfd_boolean +bfd_elf_get_bfd_needed_list (bfd *abfd, + struct bfd_link_needed_list **pneeded) +{ + asection *s; + bfd_byte *dynbuf = NULL; + int elfsec; + unsigned long shlink; + bfd_byte *extdyn, *extdynend; + size_t extdynsize; + void (*swap_dyn_in) (bfd *, const void *, Elf_Internal_Dyn *); + + *pneeded = NULL; + + if (bfd_get_flavour (abfd) != bfd_target_elf_flavour + || bfd_get_format (abfd) != bfd_object) + return TRUE; + + s = bfd_get_section_by_name (abfd, ".dynamic"); + if (s == NULL || s->size == 0) + return TRUE; + if (!bfd_malloc_and_get_section (abfd, s, &dynbuf)) + goto error_return; + + elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + + shlink = elf_elfsections (abfd)[elfsec]->sh_link; + + extdynsize = get_elf_backend_data (abfd)->s->sizeof_dyn; + swap_dyn_in = get_elf_backend_data (abfd)->s->swap_dyn_in; + + extdyn = dynbuf; + extdynend = extdyn + s->size; + for (; extdyn < extdynend; extdyn += extdynsize) + { + Elf_Internal_Dyn dyn; + + (*swap_dyn_in) (abfd, extdyn, &dyn); + + if (dyn.d_tag == DT_NULL) + break; + + if (dyn.d_tag == DT_NEEDED) + { + const char *string; + struct bfd_link_needed_list *l; + unsigned int tagv = dyn.d_un.d_val; + bfd_size_type amt; + + string = bfd_elf_string_from_elf_section (abfd, shlink, tagv); + if (string == NULL) + goto error_return; + + amt = sizeof *l; + l = bfd_alloc (abfd, amt); + if (l == NULL) + goto error_return; + + l->by = abfd; + l->name = string; + l->next = *pneeded; + *pneeded = l; + } + } + + free (dynbuf); + + return TRUE; + + error_return: + if (dynbuf != NULL) + free (dynbuf); + return FALSE; +} + +struct elf_symbuf_symbol +{ + unsigned long st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* Visibilty, and target specific */ +}; + +struct elf_symbuf_head +{ + struct elf_symbuf_symbol *ssym; + bfd_size_type count; + unsigned int st_shndx; +}; + +struct elf_symbol +{ + union + { + Elf_Internal_Sym *isym; + struct elf_symbuf_symbol *ssym; + } u; + const char *name; +}; + +/* Sort references to symbols by ascending section number. */ + +static int +elf_sort_elf_symbol (const void *arg1, const void *arg2) +{ + const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1; + const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2; + + return s1->st_shndx - s2->st_shndx; +} + +static int +elf_sym_name_compare (const void *arg1, const void *arg2) +{ + const struct elf_symbol *s1 = (const struct elf_symbol *) arg1; + const struct elf_symbol *s2 = (const struct elf_symbol *) arg2; + return strcmp (s1->name, s2->name); +} + +static struct elf_symbuf_head * +elf_create_symbuf (bfd_size_type symcount, Elf_Internal_Sym *isymbuf) +{ + Elf_Internal_Sym **ind, **indbufend, **indbuf + = bfd_malloc2 (symcount, sizeof (*indbuf)); + struct elf_symbuf_symbol *ssym; + struct elf_symbuf_head *ssymbuf, *ssymhead; + bfd_size_type i, shndx_count; + + if (indbuf == NULL) + return NULL; + + for (ind = indbuf, i = 0; i < symcount; i++) + if (isymbuf[i].st_shndx != SHN_UNDEF) + *ind++ = &isymbuf[i]; + indbufend = ind; + + qsort (indbuf, indbufend - indbuf, sizeof (Elf_Internal_Sym *), + elf_sort_elf_symbol); + + shndx_count = 0; + if (indbufend > indbuf) + for (ind = indbuf, shndx_count++; ind < indbufend - 1; ind++) + if (ind[0]->st_shndx != ind[1]->st_shndx) + shndx_count++; + + ssymbuf = bfd_malloc ((shndx_count + 1) * sizeof (*ssymbuf) + + (indbufend - indbuf) * sizeof (*ssymbuf)); + if (ssymbuf == NULL) + { + free (indbuf); + return NULL; + } + + ssym = (struct elf_symbuf_symbol *) (ssymbuf + shndx_count); + ssymbuf->ssym = NULL; + ssymbuf->count = shndx_count; + ssymbuf->st_shndx = 0; + for (ssymhead = ssymbuf, ind = indbuf; ind < indbufend; ssym++, ind++) + { + if (ind == indbuf || ssymhead->st_shndx != (*ind)->st_shndx) + { + ssymhead++; + ssymhead->ssym = ssym; + ssymhead->count = 0; + ssymhead->st_shndx = (*ind)->st_shndx; + } + ssym->st_name = (*ind)->st_name; + ssym->st_info = (*ind)->st_info; + ssym->st_other = (*ind)->st_other; + ssymhead->count++; + } + BFD_ASSERT ((bfd_size_type) (ssymhead - ssymbuf) == shndx_count); + + free (indbuf); + return ssymbuf; +} + +/* Check if 2 sections define the same set of local and global + symbols. */ + +bfd_boolean +bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, + struct bfd_link_info *info) +{ + bfd *bfd1, *bfd2; + const struct elf_backend_data *bed1, *bed2; + Elf_Internal_Shdr *hdr1, *hdr2; + bfd_size_type symcount1, symcount2; + Elf_Internal_Sym *isymbuf1, *isymbuf2; + struct elf_symbuf_head *ssymbuf1, *ssymbuf2; + Elf_Internal_Sym *isym, *isymend; + struct elf_symbol *symtable1 = NULL, *symtable2 = NULL; + bfd_size_type count1, count2, i; + int shndx1, shndx2; + bfd_boolean result; + + bfd1 = sec1->owner; + bfd2 = sec2->owner; + + /* If both are .gnu.linkonce sections, they have to have the same + section name. */ + if (CONST_STRNEQ (sec1->name, ".gnu.linkonce") + && CONST_STRNEQ (sec2->name, ".gnu.linkonce")) + return strcmp (sec1->name + sizeof ".gnu.linkonce", + sec2->name + sizeof ".gnu.linkonce") == 0; + + /* Both sections have to be in ELF. */ + if (bfd_get_flavour (bfd1) != bfd_target_elf_flavour + || bfd_get_flavour (bfd2) != bfd_target_elf_flavour) + return FALSE; + + if (elf_section_type (sec1) != elf_section_type (sec2)) + return FALSE; + + if ((elf_section_flags (sec1) & SHF_GROUP) != 0 + && (elf_section_flags (sec2) & SHF_GROUP) != 0) + { + /* If both are members of section groups, they have to have the + same group name. */ + if (strcmp (elf_group_name (sec1), elf_group_name (sec2)) != 0) + return FALSE; + } + + shndx1 = _bfd_elf_section_from_bfd_section (bfd1, sec1); + shndx2 = _bfd_elf_section_from_bfd_section (bfd2, sec2); + if (shndx1 == -1 || shndx2 == -1) + return FALSE; + + bed1 = get_elf_backend_data (bfd1); + bed2 = get_elf_backend_data (bfd2); + hdr1 = &elf_tdata (bfd1)->symtab_hdr; + symcount1 = hdr1->sh_size / bed1->s->sizeof_sym; + hdr2 = &elf_tdata (bfd2)->symtab_hdr; + symcount2 = hdr2->sh_size / bed2->s->sizeof_sym; + + if (symcount1 == 0 || symcount2 == 0) + return FALSE; + + result = FALSE; + isymbuf1 = NULL; + isymbuf2 = NULL; + ssymbuf1 = elf_tdata (bfd1)->symbuf; + ssymbuf2 = elf_tdata (bfd2)->symbuf; + + if (ssymbuf1 == NULL) + { + isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0, + NULL, NULL, NULL); + if (isymbuf1 == NULL) + goto done; + + if (!info->reduce_memory_overheads) + elf_tdata (bfd1)->symbuf = ssymbuf1 + = elf_create_symbuf (symcount1, isymbuf1); + } + + if (ssymbuf1 == NULL || ssymbuf2 == NULL) + { + isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0, + NULL, NULL, NULL); + if (isymbuf2 == NULL) + goto done; + + if (ssymbuf1 != NULL && !info->reduce_memory_overheads) + elf_tdata (bfd2)->symbuf = ssymbuf2 + = elf_create_symbuf (symcount2, isymbuf2); + } + + if (ssymbuf1 != NULL && ssymbuf2 != NULL) + { + /* Optimized faster version. */ + bfd_size_type lo, hi, mid; + struct elf_symbol *symp; + struct elf_symbuf_symbol *ssym, *ssymend; + + lo = 0; + hi = ssymbuf1->count; + ssymbuf1++; + count1 = 0; + while (lo < hi) + { + mid = (lo + hi) / 2; + if ((unsigned int) shndx1 < ssymbuf1[mid].st_shndx) + hi = mid; + else if ((unsigned int) shndx1 > ssymbuf1[mid].st_shndx) + lo = mid + 1; + else + { + count1 = ssymbuf1[mid].count; + ssymbuf1 += mid; + break; + } + } + + lo = 0; + hi = ssymbuf2->count; + ssymbuf2++; + count2 = 0; + while (lo < hi) + { + mid = (lo + hi) / 2; + if ((unsigned int) shndx2 < ssymbuf2[mid].st_shndx) + hi = mid; + else if ((unsigned int) shndx2 > ssymbuf2[mid].st_shndx) + lo = mid + 1; + else + { + count2 = ssymbuf2[mid].count; + ssymbuf2 += mid; + break; + } + } + + if (count1 == 0 || count2 == 0 || count1 != count2) + goto done; + + symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol)); + symtable2 = bfd_malloc (count2 * sizeof (struct elf_symbol)); + if (symtable1 == NULL || symtable2 == NULL) + goto done; + + symp = symtable1; + for (ssym = ssymbuf1->ssym, ssymend = ssym + count1; + ssym < ssymend; ssym++, symp++) + { + symp->u.ssym = ssym; + symp->name = bfd_elf_string_from_elf_section (bfd1, + hdr1->sh_link, + ssym->st_name); + } + + symp = symtable2; + for (ssym = ssymbuf2->ssym, ssymend = ssym + count2; + ssym < ssymend; ssym++, symp++) + { + symp->u.ssym = ssym; + symp->name = bfd_elf_string_from_elf_section (bfd2, + hdr2->sh_link, + ssym->st_name); + } + + /* Sort symbol by name. */ + qsort (symtable1, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + qsort (symtable2, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + + for (i = 0; i < count1; i++) + /* Two symbols must have the same binding, type and name. */ + if (symtable1 [i].u.ssym->st_info != symtable2 [i].u.ssym->st_info + || symtable1 [i].u.ssym->st_other != symtable2 [i].u.ssym->st_other + || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) + goto done; + + result = TRUE; + goto done; + } + + symtable1 = bfd_malloc (symcount1 * sizeof (struct elf_symbol)); + symtable2 = bfd_malloc (symcount2 * sizeof (struct elf_symbol)); + if (symtable1 == NULL || symtable2 == NULL) + goto done; + + /* Count definitions in the section. */ + count1 = 0; + for (isym = isymbuf1, isymend = isym + symcount1; isym < isymend; isym++) + if (isym->st_shndx == (unsigned int) shndx1) + symtable1[count1++].u.isym = isym; + + count2 = 0; + for (isym = isymbuf2, isymend = isym + symcount2; isym < isymend; isym++) + if (isym->st_shndx == (unsigned int) shndx2) + symtable2[count2++].u.isym = isym; + + if (count1 == 0 || count2 == 0 || count1 != count2) + goto done; + + for (i = 0; i < count1; i++) + symtable1[i].name + = bfd_elf_string_from_elf_section (bfd1, hdr1->sh_link, + symtable1[i].u.isym->st_name); + + for (i = 0; i < count2; i++) + symtable2[i].name + = bfd_elf_string_from_elf_section (bfd2, hdr2->sh_link, + symtable2[i].u.isym->st_name); + + /* Sort symbol by name. */ + qsort (symtable1, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + qsort (symtable2, count1, sizeof (struct elf_symbol), + elf_sym_name_compare); + + for (i = 0; i < count1; i++) + /* Two symbols must have the same binding, type and name. */ + if (symtable1 [i].u.isym->st_info != symtable2 [i].u.isym->st_info + || symtable1 [i].u.isym->st_other != symtable2 [i].u.isym->st_other + || strcmp (symtable1 [i].name, symtable2 [i].name) != 0) + goto done; + + result = TRUE; + +done: + if (symtable1) + free (symtable1); + if (symtable2) + free (symtable2); + if (isymbuf1) + free (isymbuf1); + if (isymbuf2) + free (isymbuf2); + + return result; +} + +/* Return TRUE if 2 section types are compatible. */ + +bfd_boolean +_bfd_elf_match_sections_by_type (bfd *abfd, const asection *asec, + bfd *bbfd, const asection *bsec) +{ + if (asec == NULL + || bsec == NULL + || abfd->xvec->flavour != bfd_target_elf_flavour + || bbfd->xvec->flavour != bfd_target_elf_flavour) + return TRUE; + + return elf_section_type (asec) == elf_section_type (bsec); +} + /* Final phase of ELF linker. */ /* A structure we use to avoid passing large numbers of arguments. */