diff options
Diffstat (limited to 'bfd/elf.c')
-rw-r--r-- | bfd/elf.c | 721 |
1 files changed, 0 insertions, 721 deletions
@@ -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) |