+2007-07-24 Alan Modra <amodra@bigpond.net.au>
+
+ * 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 <richard@codesourcery.com>
* elflink.c (_bfd_elf_fix_symbol_flags): Only assert the type
2007-07-19 Doug Kwan <dougkwan@google.com>
- 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 <bob.wilson@acm.org>
-
+
* elf32-xtensa.c (xtensa_callback_required_dependence): Ignore
non-ELF sections.
-
+
2007-07-18 Bob Wilson <bob.wilson@acm.org>
-
+
* 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 <amodra@bigpond.net.au>
* elf-bfd.h (struct sym_sec_cache): Delete "sec". Add "shndx".
return bfd_reloc_continue;
}
\f
-/* 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;
-}
-\f
/* Copy the program header and other data from one object module to
another. */
break;
}
}
-\f
-/* 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;
-}
-\f
/* Allocate an ELF string table--force the first byte to be zero. */
struct bfd_strtab_hash *
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)
return TRUE;
}
+\f
+/* 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);
+}
+\f
/* Final phase of ELF linker. */
/* A structure we use to avoid passing large numbers of arguments. */