diff options
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 341 |
1 files changed, 160 insertions, 181 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index a95ac44..12dd273 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -26,6 +26,7 @@ #include "elf-bfd.h" #include "safe-ctype.h" #include "libiberty.h" +#include "objalloc.h" /* Define a symbol in a dynamic linkage section. */ @@ -2875,98 +2876,6 @@ elf_add_dt_needed_tag (bfd *abfd, return 0; } -/* Called via elf_link_hash_traverse, elf_smash_syms sets all symbols - belonging to NOT_NEEDED to bfd_link_hash_new. We know there are no - references from regular objects to these symbols. - - ??? Should we do something about references from other dynamic - obects? If not, we potentially lose some warnings about undefined - symbols. But how can we recover the initial undefined / undefweak - state? */ - -struct elf_smash_syms_data -{ - bfd *not_needed; - struct elf_link_hash_table *htab; - bfd_boolean twiddled; -}; - -static bfd_boolean -elf_smash_syms (struct elf_link_hash_entry *h, void *data) -{ - struct elf_smash_syms_data *inf = (struct elf_smash_syms_data *) data; - struct bfd_link_hash_entry *bh; - - switch (h->root.type) - { - default: - case bfd_link_hash_new: - return TRUE; - - case bfd_link_hash_undefined: - if (h->root.u.undef.abfd != inf->not_needed) - return TRUE; - if (h->root.u.undef.weak != NULL - && h->root.u.undef.weak != inf->not_needed) - { - /* Symbol was undefweak in u.undef.weak bfd, and has become - undefined in as-needed lib. Restore weak. */ - h->root.type = bfd_link_hash_undefweak; - h->root.u.undef.abfd = h->root.u.undef.weak; - if (h->root.u.undef.next != NULL - || inf->htab->root.undefs_tail == &h->root) - inf->twiddled = TRUE; - return TRUE; - } - break; - - case bfd_link_hash_undefweak: - if (h->root.u.undef.abfd != inf->not_needed) - return TRUE; - break; - - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - if (h->root.u.def.section->owner != inf->not_needed) - return TRUE; - break; - - case bfd_link_hash_common: - if (h->root.u.c.p->section->owner != inf->not_needed) - return TRUE; - break; - - case bfd_link_hash_warning: - case bfd_link_hash_indirect: - elf_smash_syms ((struct elf_link_hash_entry *) h->root.u.i.link, data); - if (h->root.u.i.link->type != bfd_link_hash_new) - return TRUE; - if (h->root.u.i.link->u.undef.abfd != inf->not_needed) - return TRUE; - break; - } - - /* There is no way we can undo symbol table state from defined or - defweak back to undefined. */ - if (h->ref_regular) - abort (); - - /* Set sym back to newly created state, but keep undef.next if it is - being used as a list pointer. */ - bh = h->root.u.undef.next; - if (bh == &h->root) - bh = NULL; - if (bh != NULL || inf->htab->root.undefs_tail == &h->root) - inf->twiddled = TRUE; - (*inf->htab->root.table.newfunc) (&h->root.root, - &inf->htab->root.table, - h->root.root.string); - h->root.u.undef.next = bh; - h->root.u.undef.abfd = inf->not_needed; - h->non_elf = 0; - return TRUE; -} - /* Sort symbol by value and section. */ static int elf_sort_symbol (const void *arg1, const void *arg2) @@ -3136,14 +3045,6 @@ elf_finalize_dynstr (bfd *output_bfd, struct bfd_link_info *info) static bfd_boolean elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) { - bfd_boolean (*add_symbol_hook) - (bfd *, struct bfd_link_info *, Elf_Internal_Sym *, - const char **, flagword *, asection **, bfd_vma *); - bfd_boolean (*check_relocs) - (bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *); - bfd_boolean (*check_directives) - (bfd *, struct bfd_link_info *); - bfd_boolean collect; Elf_Internal_Shdr *hdr; bfd_size_type symcount; bfd_size_type extsymcount; @@ -3160,14 +3061,20 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) Elf_Internal_Sym *isymend; const struct elf_backend_data *bed; bfd_boolean add_needed; - struct elf_link_hash_table * hash_table; + struct elf_link_hash_table *htab; bfd_size_type amt; + void *alloc_mark = NULL; + void *old_tab = NULL; + void *old_hash; + void *old_ent; + struct bfd_link_hash_entry *old_undefs = NULL; + struct bfd_link_hash_entry *old_undefs_tail = NULL; + long old_dynsymcount = 0; + size_t tabsize = 0; + size_t hashsize = 0; - hash_table = elf_hash_table (info); - + htab = elf_hash_table (info); bed = get_elf_backend_data (abfd); - add_symbol_hook = bed->elf_add_symbol_hook; - collect = bed->collect; if ((abfd->flags & DYNAMIC) == 0) dynamic = FALSE; @@ -3179,8 +3086,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) hope of using a dynamic object which does not exactly match the format of the output file. */ if (info->relocatable - || !is_elf_hash_table (hash_table) - || hash_table->root.creator != abfd->xvec) + || !is_elf_hash_table (htab) + || htab->root.creator != abfd->xvec) { if (info->relocatable) bfd_set_error (bfd_error_invalid_operation); @@ -3223,8 +3130,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) { struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (hash_table, name, - FALSE, FALSE, TRUE); + h = elf_link_hash_lookup (htab, name, FALSE, FALSE, TRUE); /* FIXME: What about bfd_link_hash_common? */ if (h != NULL @@ -3251,7 +3157,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (! (_bfd_generic_link_add_one_symbol (info, abfd, name, BSF_WARNING, s, 0, msg, - FALSE, collect, NULL))) + FALSE, bed->collect, NULL))) goto error_return; if (! info->relocatable) @@ -3277,15 +3183,15 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) format. FIXME: If there are no input BFD's of the same format as the output, we can't make a shared library. */ if (info->shared - && is_elf_hash_table (hash_table) - && hash_table->root.creator == abfd->xvec - && ! hash_table->dynamic_sections_created) + && is_elf_hash_table (htab) + && htab->root.creator == abfd->xvec + && !htab->dynamic_sections_created) { if (! _bfd_elf_link_create_dynamic_sections (abfd, info)) goto error_return; } } - else if (!is_elf_hash_table (hash_table)) + else if (!is_elf_hash_table (htab)) goto error_return; else { @@ -3360,9 +3266,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) n->name = anm; n->by = abfd; n->next = NULL; - for (pn = & hash_table->needed; - *pn != NULL; - pn = &(*pn)->next) + for (pn = &htab->needed; *pn != NULL; pn = &(*pn)->next) ; *pn = n; } @@ -3434,9 +3338,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (rpath) { struct bfd_link_needed_list **pn; - for (pn = & hash_table->runpath; - *pn != NULL; - pn = &(*pn)->next) + for (pn = &htab->runpath; *pn != NULL; pn = &(*pn)->next) ; *pn = rpath; } @@ -3544,8 +3446,57 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } } - weaks = NULL; + /* If we are loading an as-needed shared lib, save the symbol table + state before we start adding symbols. If the lib turns out + to be unneeded, restore the state. */ + if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) + { + unsigned int i; + size_t entsize; + for (entsize = 0, i = 0; i < htab->root.table.size; i++) + { + struct bfd_hash_entry *p; + + for (p = htab->root.table.table[i]; p != NULL; p = p->next) + entsize += htab->root.table.entsize; + } + + tabsize = htab->root.table.size * sizeof (struct bfd_hash_entry *); + hashsize = extsymcount * sizeof (struct elf_link_hash_entry *); + old_tab = bfd_malloc (tabsize + entsize + hashsize); + if (old_tab == NULL) + goto error_free_vers; + + /* Remember the current objalloc pointer, so that all mem for + symbols added can later be reclaimed. */ + alloc_mark = bfd_hash_allocate (&htab->root.table, 1); + if (alloc_mark == NULL) + goto error_free_vers; + + /* Clone the symbol table and sym hashes. Remember some + pointers into the symbol table, and dynamic symbol count. */ + old_hash = (char *) old_tab + tabsize; + old_ent = (char *) old_hash + hashsize; + memcpy (old_tab, htab->root.table.table, tabsize); + memcpy (old_hash, sym_hash, hashsize); + old_undefs = htab->root.undefs; + old_undefs_tail = htab->root.undefs_tail; + old_dynsymcount = htab->dynsymcount; + + for (i = 0; i < htab->root.table.size; i++) + { + struct bfd_hash_entry *p; + + for (p = htab->root.table.table[i]; p != NULL; p = p->next) + { + memcpy (old_ent, p, htab->root.table.entsize); + old_ent = (char *) old_ent + htab->root.table.entsize; + } + } + } + + weaks = NULL; ever = extversym != NULL ? extversym + extsymoff : NULL; for (isym = isymbuf, isymend = isymbuf + extsymcount; isym < isymend; @@ -3597,7 +3548,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (isym->st_shndx == SHN_UNDEF) sec = bfd_und_section_ptr; - else if (isym->st_shndx < SHN_LORESERVE || isym->st_shndx > SHN_HIRESERVE) + else if (isym->st_shndx < SHN_LORESERVE + || isym->st_shndx > SHN_HIRESERVE) { sec = bfd_section_from_elf_index (abfd, isym->st_shndx); if (sec == NULL) @@ -3608,8 +3560,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) default visibility. */ sec = bfd_und_section_ptr; isym->st_shndx = SHN_UNDEF; - isym->st_other = STV_DEFAULT - | (isym->st_other & ~ ELF_ST_VISIBILITY(-1)); + isym->st_other = (STV_DEFAULT + | (isym->st_other & ~ ELF_ST_VISIBILITY (-1))); } else if ((abfd->flags & (EXEC_P | DYNAMIC)) != 0) value -= sec->vma; @@ -3650,10 +3602,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } sec = tcomm; } - else if (add_symbol_hook) + else if (bed->elf_add_symbol_hook) { - if (! (*add_symbol_hook) (abfd, info, isym, &name, &flags, &sec, - &value)) + if (! (*bed->elf_add_symbol_hook) (abfd, info, isym, &name, &flags, + &sec, &value)) goto error_free_vers; /* The hook function sets the name to NULL if this symbol @@ -3676,12 +3628,12 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) definition = TRUE; size_change_ok = FALSE; - type_change_ok = get_elf_backend_data (abfd)->type_change_ok; + type_change_ok = bed->type_change_ok; old_alignment = 0; old_bfd = NULL; new_sec = sec; - if (is_elf_hash_table (hash_table)) + if (is_elf_hash_table (htab)) { Elf_Internal_Versym iver; unsigned int vernum = 0; @@ -3776,7 +3728,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) && isym->st_shndx != SHN_UNDEF) ++newlen; - newname = bfd_alloc (abfd, newlen); + newname = bfd_hash_allocate (&htab->root.table, newlen); if (newname == NULL) goto error_free_vers; memcpy (newname, name, namelen); @@ -3840,7 +3792,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } if (! (_bfd_generic_link_add_one_symbol - (info, abfd, name, flags, sec, value, NULL, FALSE, collect, + (info, abfd, name, flags, sec, value, NULL, FALSE, bed->collect, (struct bfd_link_hash_entry **) sym_hash))) goto error_free_vers; @@ -3855,7 +3807,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) && definition && (flags & BSF_WEAK) != 0 && ELF_ST_TYPE (isym->st_info) != STT_FUNC - && is_elf_hash_table (hash_table) + && is_elf_hash_table (htab) && h->u.weakdef == NULL) { /* Keep a list of all weak defined non function symbols from @@ -3898,7 +3850,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) h->root.u.c.p->alignment_power = old_alignment; } - if (is_elf_hash_table (hash_table)) + if (is_elf_hash_table (htab)) { bfd_boolean dynsym; @@ -3998,7 +3950,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) && (abfd->no_export || (abfd->my_archive && abfd->my_archive->no_export)) && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) - isym->st_other = STV_HIDDEN | (isym->st_other & ~ ELF_ST_VISIBILITY (-1)); + isym->st_other = (STV_HIDDEN + | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); if (isym->st_other != 0 && !dynamic) { @@ -4071,13 +4024,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) { /* Queue non-default versions so that .symver x, x@FOO aliases can be checked. */ - if (! nondeflt_vers) + if (!nondeflt_vers) { - amt = (isymend - isym + 1) - * sizeof (struct elf_link_hash_entry *); + amt = ((isymend - isym + 1) + * sizeof (struct elf_link_hash_entry *)); nondeflt_vers = bfd_malloc (amt); } - nondeflt_vers [nondeflt_vers_cnt++] = h; + nondeflt_vers[nondeflt_vers_cnt++] = h; } } @@ -4089,7 +4042,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) && ! new_weakdef && h->u.weakdef->dynindx == -1) { - if (! bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) + if (!bfd_elf_link_record_dynamic_symbol (info, h->u.weakdef)) goto error_free_vers; } } @@ -4139,6 +4092,59 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } } + if (extversym != NULL) + { + free (extversym); + extversym = NULL; + } + + if (isymbuf != NULL) + { + free (isymbuf); + isymbuf = NULL; + } + + if ((elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) + { + unsigned int i; + + /* Restore the symbol table. */ + old_hash = (char *) old_tab + tabsize; + old_ent = (char *) old_hash + hashsize; + sym_hash = elf_sym_hashes (abfd); + memcpy (htab->root.table.table, old_tab, tabsize); + memcpy (sym_hash, old_hash, hashsize); + htab->root.undefs = old_undefs; + htab->root.undefs_tail = old_undefs_tail; + for (i = 0; i < htab->root.table.size; i++) + { + struct bfd_hash_entry *p; + struct elf_link_hash_entry *h; + + for (p = htab->root.table.table[i]; p != NULL; p = p->next) + { + h = (struct elf_link_hash_entry *) p; + if (h->dynindx >= old_dynsymcount) + _bfd_elf_strtab_delref (htab->dynstr, h->dynstr_index); + memcpy (p, old_ent, htab->root.table.entsize); + old_ent = (char *) old_ent + htab->root.table.entsize; + } + } + + free (old_tab); + objalloc_free_block ((struct objalloc *) htab->root.table.memory, + alloc_mark); + if (nondeflt_vers != NULL) + free (nondeflt_vers); + return TRUE; + } + + if (old_tab != NULL) + { + free (old_tab); + old_tab = NULL; + } + /* Now that all the symbols from this input file are created, handle .symver foo, foo@BAR such that any relocs against foo become foo@BAR. */ if (nondeflt_vers != NULL) @@ -4162,7 +4168,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) shortname[amt] = '\0'; hi = (struct elf_link_hash_entry *) - bfd_link_hash_lookup (&hash_table->root, shortname, + bfd_link_hash_lookup (&htab->root, shortname, FALSE, FALSE, FALSE); if (hi != NULL && hi->root.type == h->root.type @@ -4188,31 +4194,6 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) nondeflt_vers = NULL; } - if (extversym != NULL) - { - free (extversym); - extversym = NULL; - } - - if (isymbuf != NULL) - free (isymbuf); - isymbuf = NULL; - - if (!add_needed - && (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0) - { - /* Remove symbols defined in an as-needed shared lib that wasn't - needed. */ - struct elf_smash_syms_data inf; - inf.not_needed = abfd; - inf.htab = hash_table; - inf.twiddled = FALSE; - elf_link_hash_traverse (hash_table, elf_smash_syms, &inf); - if (inf.twiddled) - bfd_link_repair_undef_list (&hash_table->root); - weaks = NULL; - } - /* Now set the weakdefs field correctly for all the weak defined symbols we found. The only way to do this is to search all the symbols. Since we only need the information for non functions in @@ -4352,9 +4333,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) free (sorted_sym_hash); } - check_directives = get_elf_backend_data (abfd)->check_directives; - if (check_directives) - check_directives (abfd, info); + if (bed->check_directives) + (*bed->check_directives) (abfd, info); /* If this object is the same format as the output object, and it is not a shared library, then let the backend look through the @@ -4373,11 +4353,10 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) I have no idea how to handle linking PIC code into a file of a different format. It probably can't be done. */ - check_relocs = get_elf_backend_data (abfd)->check_relocs; if (! dynamic - && is_elf_hash_table (hash_table) - && hash_table->root.creator == abfd->xvec - && check_relocs != NULL) + && is_elf_hash_table (htab) + && htab->root.creator == abfd->xvec + && bed->check_relocs != NULL) { asection *o; @@ -4398,7 +4377,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (internal_relocs == NULL) goto error_return; - ok = (*check_relocs) (abfd, info, o, internal_relocs); + ok = (*bed->check_relocs) (abfd, info, o, internal_relocs); if (elf_section_data (o)->relocs != internal_relocs) free (internal_relocs); @@ -4412,7 +4391,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) of the .stab/.stabstr sections. */ if (! dynamic && ! info->traditional_format - && is_elf_hash_table (hash_table) + && is_elf_hash_table (htab) && (info->strip != strip_all && info->strip != strip_debugger)) { asection *stabstr; @@ -4433,10 +4412,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) struct bfd_elf_section_data *secdata; secdata = elf_section_data (stab); - if (! _bfd_link_section_stabs (abfd, - &hash_table->stab_info, - stab, stabstr, - &secdata->sec_info, + if (! _bfd_link_section_stabs (abfd, &htab->stab_info, stab, + stabstr, &secdata->sec_info, &string_offset)) goto error_return; if (secdata->sec_info) @@ -4445,7 +4422,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } } - if (is_elf_hash_table (hash_table) && add_needed) + if (is_elf_hash_table (htab) && add_needed) { /* Add this bfd to the loaded list. */ struct elf_link_loaded_list *n; @@ -4454,13 +4431,15 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) if (n == NULL) goto error_return; n->abfd = abfd; - n->next = hash_table->loaded; - hash_table->loaded = n; + n->next = htab->loaded; + htab->loaded = n; } return TRUE; error_free_vers: + if (old_tab != NULL) + free (old_tab); if (nondeflt_vers != NULL) free (nondeflt_vers); if (extversym != NULL) |