+\f
+/* Create a new BFD as if by bfd_openr. Rather than opening a file,
+ reconstruct an ELF file by reading the segments out of remote memory
+ based on the ELF file header at EHDR_VMA and the ELF program headers it
+ points to. If not null, *LOADBASEP is filled in with the difference
+ between the VMAs from which the segments were read, and the VMAs the
+ file headers (and hence BFD's idea of each section's VMA) put them at.
+
+ The function TARGET_READ_MEMORY is called to copy LEN bytes from the
+ remote memory at target address VMA into the local buffer at MYADDR; it
+ should return zero on success or an `errno' code on failure. TEMPL must
+ be a BFD for an ELF target with the word size and byte order found in
+ the remote memory. */
+
+bfd *
+bfd_elf_bfd_from_remote_memory
+ (bfd *templ,
+ bfd_vma ehdr_vma,
+ bfd_vma *loadbasep,
+ int (*target_read_memory) (bfd_vma, char *, int))
+{
+ return (*get_elf_backend_data (templ)->elf_backend_bfd_from_remote_memory)
+ (templ, ehdr_vma, loadbasep, target_read_memory);
+}
+\f
+long
+_bfd_elf_get_synthetic_symtab (bfd *abfd,
+ long symcount ATTRIBUTE_UNUSED,
+ asymbol **syms ATTRIBUTE_UNUSED,
+ long dynsymcount ATTRIBUTE_UNUSED,
+ asymbol **dynsyms,
+ asymbol **ret)
+{
+ const struct elf_backend_data *bed = get_elf_backend_data (abfd);
+ asection *relplt;
+ asymbol *s;
+ const char *relplt_name;
+ bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean);
+ arelent *p;
+ long count, i, n;
+ size_t size;
+ Elf_Internal_Shdr *hdr;
+ char *names;
+ asection *plt;
+
+ if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0)
+ return 0;
+
+ *ret = NULL;
+ if (!bed->plt_sym_val)
+ return 0;
+
+ relplt_name = bed->relplt_name;
+ if (relplt_name == NULL)
+ relplt_name = bed->default_use_rela_p ? ".rela.plt" : ".rel.plt";
+ relplt = bfd_get_section_by_name (abfd, relplt_name);
+ if (relplt == NULL)
+ return 0;
+
+ hdr = &elf_section_data (relplt)->this_hdr;
+ if (hdr->sh_link != elf_dynsymtab (abfd)
+ || (hdr->sh_type != SHT_REL && hdr->sh_type != SHT_RELA))
+ return 0;
+
+ plt = bfd_get_section_by_name (abfd, ".plt");
+ if (plt == NULL)
+ return 0;
+
+ slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table;
+ if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE))
+ return -1;
+
+ count = relplt->size / hdr->sh_entsize;
+ size = count * sizeof (asymbol);
+ p = relplt->relocation;
+ for (i = 0; i < count; i++, s++, p++)
+ size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
+
+ s = *ret = bfd_malloc (size);
+ if (s == NULL)
+ return -1;
+
+ names = (char *) (s + count);
+ p = relplt->relocation;
+ n = 0;
+ for (i = 0; i < count; i++, s++, p++)
+ {
+ size_t len;
+ bfd_vma addr;
+
+ addr = bed->plt_sym_val (i, plt, p);
+ if (addr == (bfd_vma) -1)
+ continue;
+
+ *s = **p->sym_ptr_ptr;
+ s->section = plt;
+ s->value = addr - plt->vma;
+ s->name = names;
+ len = strlen ((*p->sym_ptr_ptr)->name);
+ memcpy (names, (*p->sym_ptr_ptr)->name, len);
+ names += len;
+ memcpy (names, "@plt", sizeof ("@plt"));
+ names += sizeof ("@plt");
+ ++n;
+ }
+
+ return n;
+}
+
+/* Sort symbol by binding and section. We want to put definitions
+ sorted by section at the beginning. */
+
+static int
+elf_sort_elf_symbol (const void *arg1, const void *arg2)
+{
+ const Elf_Internal_Sym *s1;
+ const Elf_Internal_Sym *s2;
+ int shndx;
+
+ /* Make sure that undefined symbols are at the end. */
+ s1 = (const Elf_Internal_Sym *) arg1;
+ if (s1->st_shndx == SHN_UNDEF)
+ return 1;
+ s2 = (const Elf_Internal_Sym *) arg2;
+ if (s2->st_shndx == SHN_UNDEF)
+ return -1;
+
+ /* Sorted by section index. */
+ shndx = s1->st_shndx - s2->st_shndx;
+ if (shndx != 0)
+ return shndx;
+
+ /* Sorted by binding. */
+ return ELF_ST_BIND (s1->st_info) - ELF_ST_BIND (s2->st_info);
+}
+
+struct elf_symbol
+{
+ Elf_Internal_Sym *sym;
+ const char *name;
+};
+
+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);
+}
+
+/* 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)
+{
+ 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;
+ Elf_Internal_Sym *isymstart1 = NULL, *isymstart2 = NULL, *isym;
+ Elf_Internal_Sym *isymend;
+ struct elf_symbol *symp, *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 (strncmp (sec1->name, ".gnu.linkonce",
+ sizeof ".gnu.linkonce" - 1) == 0
+ && strncmp (sec2->name, ".gnu.linkonce",
+ sizeof ".gnu.linkonce" - 1) == 0)
+ 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;
+
+ isymbuf1 = bfd_elf_get_elf_syms (bfd1, hdr1, symcount1, 0,
+ NULL, NULL, NULL);
+ isymbuf2 = bfd_elf_get_elf_syms (bfd2, hdr2, symcount2, 0,
+ NULL, NULL, NULL);
+
+ result = FALSE;
+ if (isymbuf1 == NULL || isymbuf2 == NULL)
+ goto done;
+
+ /* Sort symbols by binding and section. Global definitions are at
+ the beginning. */
+ qsort (isymbuf1, symcount1, sizeof (Elf_Internal_Sym),
+ elf_sort_elf_symbol);
+ qsort (isymbuf2, symcount2, sizeof (Elf_Internal_Sym),
+ elf_sort_elf_symbol);
+
+ /* Count definitions in the section. */
+ count1 = 0;
+ for (isym = isymbuf1, isymend = isym + symcount1;
+ isym < isymend; isym++)
+ {
+ if (isym->st_shndx == (unsigned int) shndx1)
+ {
+ if (count1 == 0)
+ isymstart1 = isym;
+ count1++;
+ }
+
+ if (count1 && isym->st_shndx != (unsigned int) shndx1)
+ break;
+ }
+
+ count2 = 0;
+ for (isym = isymbuf2, isymend = isym + symcount2;
+ isym < isymend; isym++)
+ {
+ if (isym->st_shndx == (unsigned int) shndx2)
+ {
+ if (count2 == 0)
+ isymstart2 = isym;
+ count2++;
+ }
+
+ if (count2 && isym->st_shndx != (unsigned int) shndx2)
+ break;
+ }
+
+ if (count1 == 0 || count2 == 0 || count1 != count2)
+ goto done;
+
+ symtable1 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+ symtable2 = bfd_malloc (count1 * sizeof (struct elf_symbol));
+
+ if (symtable1 == NULL || symtable2 == NULL)
+ goto done;
+
+ symp = symtable1;
+ for (isym = isymstart1, isymend = isym + count1;
+ isym < isymend; isym++)
+ {
+ symp->sym = isym;
+ symp->name = bfd_elf_string_from_elf_section (bfd1,
+ hdr1->sh_link,
+ isym->st_name);
+ symp++;
+ }
+
+ symp = symtable2;
+ for (isym = isymstart2, isymend = isym + count1;
+ isym < isymend; isym++)
+ {
+ symp->sym = isym;
+ symp->name = bfd_elf_string_from_elf_section (bfd2,
+ hdr2->sh_link,
+ isym->st_name);
+ symp++;
+ }
+
+ /* 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].sym->st_info != symtable2 [i].sym->st_info
+ || symtable1 [i].sym->st_other != symtable2 [i].sym->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;
+}