diff options
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 390 |
1 files changed, 220 insertions, 170 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index 309b4d7..666399b 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -96,22 +96,64 @@ _bfd_elf_link_keep_memory (struct bfd_link_info *info) return true; } -asection * -_bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie, - unsigned long r_symndx, - bool discard) +static struct elf_link_hash_entry * +get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, + unsigned int symndx, + unsigned int ext_sym_start) +{ + if (sym_hashes == NULL + /* Guard against corrupt input. See PR 32636 for an example. */ + || symndx < ext_sym_start) + return NULL; + + struct elf_link_hash_entry *h = sym_hashes[symndx - ext_sym_start]; + + /* The hash might be empty. See PR 32641 for an example of this. */ + if (h == NULL) + return NULL; + + while (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + h = (struct elf_link_hash_entry *) h->root.u.i.link; + + return h; +} + +struct elf_link_hash_entry * +_bfd_elf_get_link_hash_entry (struct elf_link_hash_entry ** sym_hashes, + unsigned int symndx, + Elf_Internal_Shdr * symtab_hdr) { + if (symtab_hdr == NULL) + return NULL; + + return get_link_hash_entry (sym_hashes, symndx, symtab_hdr->sh_info); +} + +static struct elf_link_hash_entry * +get_ext_sym_hash_from_cookie (struct elf_reloc_cookie *cookie, unsigned long r_symndx) +{ + if (cookie == NULL || cookie->sym_hashes == NULL) + return NULL; + if (r_symndx >= cookie->locsymcount || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) - { - struct elf_link_hash_entry *h; + return get_link_hash_entry (cookie->sym_hashes, r_symndx, cookie->extsymoff); - h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; + return NULL; +} - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; +asection * +_bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie, + unsigned long r_symndx, + bool discard) +{ + struct elf_link_hash_entry *h; + h = get_ext_sym_hash_from_cookie (cookie, r_symndx); + + if (h != NULL) + { if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && discarded_section (h->root.u.def.section)) @@ -119,21 +161,20 @@ _bfd_elf_section_for_symbol (struct elf_reloc_cookie *cookie, else return NULL; } - else - { - /* It's not a relocation against a global symbol, - but it could be a relocation against a local - symbol for a discarded section. */ - asection *isec; - Elf_Internal_Sym *isym; - /* Need to: get the symbol; get the section. */ - isym = &cookie->locsyms[r_symndx]; - isec = bfd_section_from_elf_index (cookie->abfd, isym->st_shndx); - if (isec != NULL - && discard ? discarded_section (isec) : 1) - return isec; - } + /* It's not a relocation against a global symbol, + but it could be a relocation against a local + symbol for a discarded section. */ + asection *isec; + Elf_Internal_Sym *isym; + + /* Need to: get the symbol; get the section. */ + isym = &cookie->locsyms[r_symndx]; + isec = bfd_section_from_elf_index (cookie->abfd, isym->st_shndx); + if (isec != NULL + && discard ? discarded_section (isec) : 1) + return isec; + return NULL; } @@ -198,8 +239,7 @@ _bfd_elf_create_got_section (bfd *abfd, struct bfd_link_info *info) s = bfd_make_section_anyway_with_flags (abfd, (bed->rela_plts_and_copies_p ? ".rela.got" : ".rel.got"), - (bed->dynamic_sec_flags - | SEC_READONLY)); + flags | SEC_READONLY); if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align)) return false; @@ -397,8 +437,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) if (info->enable_dt_relr) { s = bfd_make_section_anyway_with_flags (abfd, ".relr.dyn", - (bed->dynamic_sec_flags - | SEC_READONLY)); + flags | SEC_READONLY); if (s == NULL || !bfd_set_section_alignment (s, bed->s->log_file_align)) return false; @@ -3345,12 +3384,9 @@ _bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info, --power_of_two; } - if (power_of_two > bfd_section_alignment (dynbss)) - { - /* Adjust the section alignment if needed. */ - if (!bfd_set_section_alignment (dynbss, power_of_two)) - return false; - } + /* Adjust the section alignment if needed. */ + if (!bfd_link_align_section (dynbss, power_of_two)) + return false; /* We make sure that the symbol will be aligned properly. */ dynbss->size = BFD_ALIGN (dynbss->size, mask + 1); @@ -3570,7 +3606,7 @@ _bfd_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) /* Ensure the alignment of the first section (usually .tdata) is the largest alignment, so that the tls segment starts aligned. */ if (tls != NULL) - tls->alignment_power = align; + (void) bfd_link_align_section (tls, align); return tls; } @@ -4323,8 +4359,8 @@ elf_link_add_to_first_hash (bfd *abfd, struct bfd_link_info *info, = ((struct elf_link_first_hash_entry *) bfd_hash_lookup (htab->first_hash, name, true, copy)); if (e == NULL) - info->callbacks->einfo - (_("%F%P: %pB: failed to add %s to first hash\n"), abfd, name); + info->callbacks->fatal + (_("%P: %pB: failed to add %s to first hash\n"), abfd, name); if (e->abfd == NULL) /* Store ABFD in abfd. */ @@ -4391,8 +4427,8 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) || !bfd_hash_table_init (htab->first_hash, elf_link_first_hash_newfunc, sizeof (struct elf_link_first_hash_entry))) - info->callbacks->einfo - (_("%F%P: first_hash failed to create: %E\n")); + info->callbacks->fatal + (_("%P: first_hash failed to create: %E\n")); } } else @@ -4929,6 +4965,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) asection *sec, *new_sec; flagword flags; const char *name; + const char *defvername; bool must_copy_name = false; struct elf_link_hash_entry *h; struct elf_link_hash_entry *hi; @@ -5105,6 +5142,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) old_alignment = 0; old_bfd = NULL; new_sec = sec; + defvername = NULL; if (is_elf_hash_table (&htab->root)) { @@ -5223,7 +5261,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) default version of the symbol. */ if ((iver.vs_vers & VERSYM_HIDDEN) == 0 && isym->st_shndx != SHN_UNDEF) - *p++ = ELF_VER_CHR; + *p++ = ELF_VER_CHR, defvername = name; memcpy (p, verstr, verlen + 1); name = newname; @@ -5673,9 +5711,15 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) } else if (dynamic && h->root.u.def.section->owner == abfd) - /* Add this symbol to first hash if this shared - object has the first definition. */ - elf_link_add_to_first_hash (abfd, info, name, must_copy_name); + { + /* Add this symbol to first hash if this shared + object has the first definition. */ + elf_link_add_to_first_hash (abfd, info, name, must_copy_name); + /* And if it was the default symbol version definition, + also add the short name. */ + if (defvername) + elf_link_add_to_first_hash (abfd, info, defvername, false); + } } } } @@ -6237,12 +6281,30 @@ elf_link_add_archive_symbols (bfd *abfd, struct bfd_link_info *info) if (h->type == bfd_link_hash_undefined) { - /* If the archive element has already been loaded then one - of the symbols defined by that element might have been - made undefined due to being in a discarded section. */ - if (is_elf_hash_table (info->hash) - && ((struct elf_link_hash_entry *) h)->indx == -3) - continue; + if (is_elf_hash_table (info->hash)) + { + /* If the archive element has already been loaded then one + of the symbols defined by that element might have been + made undefined due to being in a discarded section. */ + if (((struct elf_link_hash_entry *) h)->indx == -3) + continue; + + /* In the pre-LTO-plugin pass we must not mistakenly + include this archive member if an earlier shared + library defined this symbol. */ + struct elf_link_hash_table *htab = elf_hash_table (info); + if (htab->first_hash) + { + struct elf_link_first_hash_entry *e + = ((struct elf_link_first_hash_entry *) + bfd_hash_lookup (htab->first_hash, symdef->name, + false, false)); + if (e + && (e->abfd->flags & DYNAMIC) != 0 + && e->abfd != abfd) + continue; + } + } } else if (h->type == bfd_link_hash_common) { @@ -9072,7 +9134,6 @@ set_symbol_value (bfd *bfd_with_globals, size_t symidx, bfd_vma val) { - struct elf_link_hash_entry **sym_hashes; struct elf_link_hash_entry *h; size_t extsymoff = locsymcount; @@ -9095,12 +9156,12 @@ set_symbol_value (bfd *bfd_with_globals, /* It is a global symbol: set its link type to "defined" and give it a value. */ - - sym_hashes = elf_sym_hashes (bfd_with_globals); - h = sym_hashes [symidx - extsymoff]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + h = get_link_hash_entry (elf_sym_hashes (bfd_with_globals), symidx, extsymoff); + if (h == NULL) + { + /* FIXMEL What should we do ? */ + return; + } h->root.type = bfd_link_hash_defined; h->root.u.def.value = val; h->root.u.def.section = bfd_abs_section_ptr; @@ -11578,10 +11639,19 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) || (elf_bad_symtab (input_bfd) && flinfo->sections[symndx] == NULL)) { - struct elf_link_hash_entry *h = sym_hashes[symndx - extsymoff]; - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + struct elf_link_hash_entry *h; + + h = get_link_hash_entry (sym_hashes, symndx, extsymoff); + if (h == NULL) + { + _bfd_error_handler + /* xgettext:c-format */ + (_("error: %pB: unable to create group section symbol"), + input_bfd); + bfd_set_error (bfd_error_bad_value); + return false; + } + /* Arrange for symbol to be output. */ h->indx = -2; elf_section_data (osec)->this_hdr.sh_info = -2; @@ -11716,7 +11786,7 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) || (elf_bad_symtab (input_bfd) && flinfo->sections[r_symndx] == NULL)) { - h = sym_hashes[r_symndx - extsymoff]; + h = get_link_hash_entry (sym_hashes, r_symndx, extsymoff); /* Badly formatted input files can contain relocs that reference non-existant symbols. Check here so that @@ -11725,17 +11795,13 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) { _bfd_error_handler /* xgettext:c-format */ - (_("error: %pB contains a reloc (%#" PRIx64 ") for section %pA " + (_("error: %pB contains a reloc (%#" PRIx64 ") for section '%pA' " "that references a non-existent global symbol"), input_bfd, (uint64_t) rel->r_info, o); bfd_set_error (bfd_error_bad_value); return false; } - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; - s_type = h->type; /* If a plugin symbol is referenced from a non-IR file, @@ -11951,7 +12017,6 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) && flinfo->sections[r_symndx] == NULL)) { struct elf_link_hash_entry *rh; - unsigned long indx; /* This is a reloc against a global symbol. We have not yet output all the local symbols, so @@ -11960,15 +12025,16 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) reloc to point to the global hash table entry for this symbol. The symbol index is then set at the end of bfd_elf_final_link. */ - indx = r_symndx - extsymoff; - rh = elf_sym_hashes (input_bfd)[indx]; - while (rh->root.type == bfd_link_hash_indirect - || rh->root.type == bfd_link_hash_warning) - rh = (struct elf_link_hash_entry *) rh->root.u.i.link; - - /* Setting the index to -2 tells - elf_link_output_extsym that this symbol is - used by a reloc. */ + rh = get_link_hash_entry (elf_sym_hashes (input_bfd), + r_symndx, extsymoff); + if (rh == NULL) + { + /* FIXME: Generate an error ? */ + continue; + } + + /* Setting the index to -2 tells elf_link_output_extsym + that this symbol is used by a reloc. */ BFD_ASSERT (rh->indx < 0); rh->indx = -2; *rel_hash = rh; @@ -12166,9 +12232,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) break; case SEC_INFO_TYPE_SFRAME: { - /* Merge .sframe sections into the ctf frame encoder - context of the output_bfd's section. The final .sframe - output section will be written out later. */ + /* Merge SFrame section into the SFrame encoder context of the + output_bfd's section. The final .sframe output section will + be written out later. */ if (!_bfd_elf_merge_section_sframe (output_bfd, flinfo->info, o, contents)) return false; @@ -12570,9 +12636,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) size_t relr_entsize; asection *reldyn = 0; bfd_size_type amt; - asection *attr_section = NULL; - bfd_vma attr_size = 0; - const char *std_attrs_section; struct elf_link_hash_table *htab = elf_hash_table (info); bool sections_removed; @@ -12618,12 +12681,12 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) sections from the link, and set the contents of the output section. */ sections_removed = false; - std_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section; + const char *obj_attrs_section = get_elf_backend_data (abfd)->obj_attrs_section; for (o = abfd->sections; o != NULL; o = o->next) { bool remove_section = false; - if ((std_attrs_section && strcmp (o->name, std_attrs_section) == 0) + if ((obj_attrs_section && strcmp (o->name, obj_attrs_section) == 0) || strcmp (o->name, ".gnu.attributes") == 0) { for (p = o->map_head.link_order; p != NULL; p = p->next) @@ -12638,12 +12701,16 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) input_section->flags &= ~SEC_HAS_CONTENTS; } - attr_size = bfd_elf_obj_attr_size (abfd); - bfd_set_section_size (o, attr_size); /* Skip this section later on. */ o->map_head.link_order = NULL; - if (attr_size) - attr_section = o; + + bfd_vma attr_size = bfd_elf_obj_attr_size (abfd); + /* Once ELF headers have been written, the size of a section is + frozen. We need to set the size of the attribute section before + _bfd_elf_compute_section_file_positions. */ + bfd_set_section_size (o, attr_size); + if (attr_size > 0) + elf_obj_build_attributes (abfd) = o; else remove_section = true; } @@ -13079,8 +13146,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) if (info->enable_dt_relr && bed->finish_relative_relocs && !bed->finish_relative_relocs (info)) - info->callbacks->einfo - (_("%F%P: %pB: failed to finish relative relocations\n"), abfd); + info->callbacks->fatal + (_("%P: %pB: failed to finish relative relocations\n"), abfd); /* Since ELF permits relocations to be against local symbols, we must have the local symbols available when we do the relocations. @@ -13758,21 +13825,14 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) if (! _bfd_elf_write_section_sframe (abfd, info)) goto error_return; + if (! _bfd_elf_write_section_build_attributes (abfd, info)) + goto error_ret2; + if (info->callbacks->emit_ctf) info->callbacks->emit_ctf (); elf_final_link_free (abfd, &flinfo); - if (attr_section) - { - bfd_byte *contents = (bfd_byte *) bfd_malloc (attr_size); - if (contents == NULL) - goto error_ret2; - bfd_elf_set_obj_attr_contents (abfd, contents, attr_size); - bfd_set_section_contents (abfd, attr_section, contents, 0, attr_size); - free (contents); - } - if (info->unique_symbol) bfd_hash_table_free (&flinfo.local_hash_table); return true; @@ -13932,25 +13992,21 @@ _bfd_elf_gc_mark_hook (asection *sec, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { - if (h != NULL) + if (h == NULL) + return bfd_section_from_elf_index (sec->owner, sym->st_shndx); + + switch (h->root.type) { - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - return h->root.u.def.section; + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + return h->root.u.def.section; - case bfd_link_hash_common: - return h->root.u.c.p->section; + case bfd_link_hash_common: + return h->root.u.c.p->section; - default: - break; - } + default: + return NULL; } - else - return bfd_section_from_elf_index (sec->owner, sym->st_shndx); - - return NULL; } /* Return the debug definition section. */ @@ -13999,56 +14055,49 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, if (r_symndx == STN_UNDEF) return NULL; - if (r_symndx >= cookie->locsymcount - || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) + h = get_ext_sym_hash_from_cookie (cookie, r_symndx); + if (h == NULL) { - bool was_marked; + /* A corrupt input file can lead to a situation where the index + does not reference either a local or an external symbol. */ + if (r_symndx >= cookie->locsymcount) + return NULL; - h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; - if (h == NULL) - { - info->callbacks->einfo (_("%F%P: corrupt input: %pB\n"), - sec->owner); - return NULL; - } - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + return (*gc_mark_hook) (sec, info, cookie->rel, NULL, + &cookie->locsyms[r_symndx]); + } - was_marked = h->mark; - h->mark = 1; - /* Keep all aliases of the symbol too. If an object symbol - needs to be copied into .dynbss then all of its aliases - should be present as dynamic symbols, not just the one used - on the copy relocation. */ - hw = h; - while (hw->is_weakalias) - { - hw = hw->u.alias; - hw->mark = 1; - } + bool was_marked = h->mark; - if (!was_marked && h->start_stop && !h->root.ldscript_def) - { - if (info->start_stop_gc) - return NULL; + h->mark = 1; + /* Keep all aliases of the symbol too. If an object symbol + needs to be copied into .dynbss then all of its aliases + should be present as dynamic symbols, not just the one used + on the copy relocation. */ + hw = h; + while (hw->is_weakalias) + { + hw = hw->u.alias; + hw->mark = 1; + } - /* To work around a glibc bug, mark XXX input sections - when there is a reference to __start_XXX or __stop_XXX - symbols. */ - else if (start_stop != NULL) - { - asection *s = h->u2.start_stop_section; - *start_stop = true; - return s; - } - } + if (!was_marked && h->start_stop && !h->root.ldscript_def) + { + if (info->start_stop_gc) + return NULL; - return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); + /* To work around a glibc bug, mark XXX input sections + when there is a reference to __start_XXX or __stop_XXX + symbols. */ + else if (start_stop != NULL) + { + asection *s = h->u2.start_stop_section; + *start_stop = true; + return s; + } } - return (*gc_mark_hook) (sec, info, cookie->rel, NULL, - &cookie->locsyms[r_symndx]); + return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); } /* COOKIE->rel describes a relocation against section SEC, which is @@ -14260,7 +14309,7 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, else if (strcmp (bfd_section_name (isec), "__patchable_function_entries") == 0 && elf_linked_to_section (isec) == NULL) - info->callbacks->einfo (_("%F%P: %pB(%pA): error: " + info->callbacks->fatal (_("%P: %pB(%pA): error: " "need linked-to section " "for --gc-sections\n"), isec->owner, isec); @@ -14361,7 +14410,8 @@ elf_gc_sweep (bfd *abfd, struct bfd_link_info *info) if (o->flags & SEC_GROUP) { asection *first = elf_next_in_group (o); - o->gc_mark = first->gc_mark; + if (first != NULL) + o->gc_mark = first->gc_mark; } if (o->gc_mark) @@ -15069,17 +15119,12 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) if (r_symndx == STN_UNDEF) return true; - if (r_symndx >= rcookie->locsymcount - || ELF_ST_BIND (rcookie->locsyms[r_symndx].st_info) != STB_LOCAL) - { - struct elf_link_hash_entry *h; - - h = rcookie->sym_hashes[r_symndx - rcookie->extsymoff]; - - while (h->root.type == bfd_link_hash_indirect - || h->root.type == bfd_link_hash_warning) - h = (struct elf_link_hash_entry *) h->root.u.i.link; + struct elf_link_hash_entry *h; + h = get_ext_sym_hash_from_cookie (rcookie, r_symndx); + + if (h != NULL) + { if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && (h->root.u.def.section->owner != rcookie->abfd @@ -15089,6 +15134,10 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) } else { + if (r_symndx >= rcookie->locsymcount) + /* This can happen with corrupt input. */ + return false; + /* It's not a relocation against a global symbol, but it could be a relocation against a local symbol for a discarded section. */ @@ -15103,6 +15152,7 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) || discarded_section (isec))) return true; } + return false; } return false; @@ -15437,7 +15487,7 @@ _bfd_elf_section_already_linked (bfd *abfd, /* This is the first section with this name. Record it. */ if (!bfd_section_already_linked_table_insert (already_linked_list, sec)) - info->callbacks->einfo (_("%F%P: already_linked_table: %E\n")); + info->callbacks->fatal (_("%P: already_linked_table: %E\n")); return sec->output_section == bfd_abs_section_ptr; } |