X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felflink.c;h=0cd85f1d94c28db63dea3e16ed98452d0763ae35;hb=d983c8c5503d680c6d4955ceb610a9beebc64460;hp=c1e794868c3861e755a21198473f106da0e36515;hpb=29a9f53e857c5d55df852d0a5d5c41a9247c16a2;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elflink.c b/bfd/elflink.c index c1e794868c..0cd85f1d94 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -1,5 +1,5 @@ /* ELF linking support for BFD. - Copyright (C) 1995-2014 Free Software Foundation, Inc. + Copyright (C) 1995-2015 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -20,6 +20,7 @@ #include "sysdep.h" #include "bfd.h" +#include "bfd_stdint.h" #include "bfdlink.h" #include "libbfd.h" #define ARCH_SIZE 0 @@ -84,6 +85,7 @@ _bfd_elf_define_linkage_sym (bfd *abfd, h = (struct elf_link_hash_entry *) bh; h->def_regular = 1; h->non_elf = 0; + h->root.linker_def = 1; h->type = STT_OBJECT; if (ELF_ST_VISIBILITY (h->other) != STV_INTERNAL) h->other = (h->other & ~ELF_ST_VISIBILITY (-1)) | STV_HIDDEN; @@ -760,6 +762,7 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, asection *p) { struct elf_link_hash_table *htab; + asection *ip; switch (elf_section_data (p)->this_hdr.sh_type) { @@ -775,18 +778,9 @@ _bfd_elf_link_omit_section_dynsym (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->text_index_section != NULL) return p != htab->text_index_section && p != htab->data_index_section; - if (strcmp (p->name, ".got") == 0 - || strcmp (p->name, ".got.plt") == 0 - || strcmp (p->name, ".plt") == 0) - { - asection *ip; - - if (htab->dynobj != NULL + return (htab->dynobj != NULL && (ip = bfd_get_linker_section (htab->dynobj, p->name)) != NULL - && ip->output_section == p) - return TRUE; - } - return FALSE; + && ip->output_section == p); /* There shouldn't be section relative relocations against any other section. */ @@ -872,6 +866,8 @@ elf_merge_st_other (bfd *abfd, struct elf_link_hash_entry *h, if (symvis - 1 < hvis - 1) h->other = symvis | (h->other & ~ELF_ST_VISIBILITY (-1)); } + else if (definition && ELF_ST_VISIBILITY (isym->st_other) != STV_DEFAULT) + h->protected_def = 1; } /* This function is called when we want to merge a new symbol with an @@ -1832,7 +1828,9 @@ _bfd_elf_link_find_version_dependencies (struct elf_link_hash_entry *h, if (!h->def_dynamic || h->def_regular || h->dynindx == -1 - || h->verinfo.verdef == NULL) + || h->verinfo.verdef == NULL + || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd) + & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED))) return TRUE; /* See if we already know about this version. */ @@ -2283,8 +2281,8 @@ _bfd_elf_link_size_reloc_section (bfd *abfd, { struct elf_link_hash_entry **p; - p = (struct elf_link_hash_entry **) - bfd_zmalloc (reldata->count * sizeof (struct elf_link_hash_entry *)); + p = ((struct elf_link_hash_entry **) + bfd_zmalloc (reldata->count * sizeof (*p))); if (p == NULL) return FALSE; @@ -2634,7 +2632,8 @@ _bfd_elf_adjust_dynamic_symbol (struct elf_link_hash_entry *h, void *data) DYNBSS. */ bfd_boolean -_bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h, +_bfd_elf_adjust_dynamic_copy (struct bfd_link_info *info, + struct elf_link_hash_entry *h, asection *dynbss) { unsigned int power_of_two; @@ -2673,6 +2672,15 @@ _bfd_elf_adjust_dynamic_copy (struct elf_link_hash_entry *h, /* Increment the size of DYNBSS to make room for the symbol. */ dynbss->size += h->size; + if (h->protected_def) + { + info->callbacks->einfo + (_("%P: copy reloc against protected `%T' is invalid\n"), + h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + return TRUE; } @@ -4077,8 +4085,7 @@ error_free_dyn: requested we not re-export it, then mark it as hidden. */ if (definition && !dynamic - && (abfd->no_export - || (abfd->my_archive && abfd->my_archive->no_export)) + && abfd->no_export && ELF_ST_VISIBILITY (isym->st_other) != STV_INTERNAL) isym->st_other = (STV_HIDDEN | (isym->st_other & ~ELF_ST_VISIBILITY (-1))); @@ -4376,8 +4383,8 @@ error_free_dyn: { amt = ((isymend - isym + 1) * sizeof (struct elf_link_hash_entry *)); - nondeflt_vers = - (struct elf_link_hash_entry **) bfd_malloc (amt); + nondeflt_vers + = (struct elf_link_hash_entry **) bfd_malloc (amt); if (!nondeflt_vers) goto error_free_vers; } @@ -4443,7 +4450,7 @@ error_free_dyn: } elf_dyn_lib_class (abfd) = (enum dynamic_lib_link_class) - (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); + (elf_dyn_lib_class (abfd) & ~DYN_AS_NEEDED); add_needed = TRUE; ret = elf_add_dt_needed_tag (abfd, info, soname, add_needed); @@ -4852,8 +4859,7 @@ error_free_dyn: /* Add this bfd to the loaded list. */ struct elf_link_loaded_list *n; - n = (struct elf_link_loaded_list *) - bfd_alloc (abfd, sizeof (struct elf_link_loaded_list)); + n = (struct elf_link_loaded_list *) bfd_alloc (abfd, sizeof (*n)); if (n == NULL) goto error_return; n->abfd = abfd; @@ -5414,7 +5420,7 @@ compute_bucket_count (struct bfd_link_info *info ATTRIBUTE_UNUSED, { best_chlen = max; best_size = i; - no_improvement_count = 0; + no_improvement_count = 0; } /* PR 11843: Avoid futile long searches for the best bucket size when there are a large number of symbols. */ @@ -6708,7 +6714,7 @@ _bfd_elf_link_hash_newfunc (struct bfd_hash_entry *entry, if (entry == NULL) { entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); + bfd_hash_allocate (table, sizeof (struct elf_link_hash_entry)); if (entry == NULL) return entry; } @@ -7259,10 +7265,10 @@ bfd_elf_match_symbols_in_sections (asection *sec1, asection *sec2, if (count1 == 0 || count2 == 0 || count1 != count2) goto done; - symtable1 = (struct elf_symbol *) - bfd_malloc (count1 * sizeof (struct elf_symbol)); - symtable2 = (struct elf_symbol *) - bfd_malloc (count2 * sizeof (struct elf_symbol)); + symtable1 + = (struct elf_symbol *) bfd_malloc (count1 * sizeof (*symtable1)); + symtable2 + = (struct elf_symbol *) bfd_malloc (count2 * sizeof (*symtable2)); if (symtable1 == NULL || symtable2 == NULL) goto done; @@ -7435,8 +7441,6 @@ struct elf_outext_info { bfd_boolean failed; bfd_boolean localsyms; - bfd_boolean need_second_pass; - bfd_boolean second_pass; bfd_boolean file_sym_done; struct elf_final_link_info *flinfo; }; @@ -7955,6 +7959,138 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd, return r; } +/* qsort comparison functions sorting external relocs by r_offset. */ + +static int +cmp_ext32l_r_offset (const void *p, const void *q) +{ + union aligned32 + { + uint32_t v; + unsigned char c[4]; + }; + const union aligned32 *a + = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset; + const union aligned32 *b + = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset; + + uint32_t aval = ( (uint32_t) a->c[0] + | (uint32_t) a->c[1] << 8 + | (uint32_t) a->c[2] << 16 + | (uint32_t) a->c[3] << 24); + uint32_t bval = ( (uint32_t) b->c[0] + | (uint32_t) b->c[1] << 8 + | (uint32_t) b->c[2] << 16 + | (uint32_t) b->c[3] << 24); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +static int +cmp_ext32b_r_offset (const void *p, const void *q) +{ + union aligned32 + { + uint32_t v; + unsigned char c[4]; + }; + const union aligned32 *a + = (const union aligned32 *) ((const Elf32_External_Rel *) p)->r_offset; + const union aligned32 *b + = (const union aligned32 *) ((const Elf32_External_Rel *) q)->r_offset; + + uint32_t aval = ( (uint32_t) a->c[0] << 24 + | (uint32_t) a->c[1] << 16 + | (uint32_t) a->c[2] << 8 + | (uint32_t) a->c[3]); + uint32_t bval = ( (uint32_t) b->c[0] << 24 + | (uint32_t) b->c[1] << 16 + | (uint32_t) b->c[2] << 8 + | (uint32_t) b->c[3]); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +#ifdef BFD_HOST_64_BIT +static int +cmp_ext64l_r_offset (const void *p, const void *q) +{ + union aligned64 + { + uint64_t v; + unsigned char c[8]; + }; + const union aligned64 *a + = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset; + const union aligned64 *b + = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset; + + uint64_t aval = ( (uint64_t) a->c[0] + | (uint64_t) a->c[1] << 8 + | (uint64_t) a->c[2] << 16 + | (uint64_t) a->c[3] << 24 + | (uint64_t) a->c[4] << 32 + | (uint64_t) a->c[5] << 40 + | (uint64_t) a->c[6] << 48 + | (uint64_t) a->c[7] << 56); + uint64_t bval = ( (uint64_t) b->c[0] + | (uint64_t) b->c[1] << 8 + | (uint64_t) b->c[2] << 16 + | (uint64_t) b->c[3] << 24 + | (uint64_t) b->c[4] << 32 + | (uint64_t) b->c[5] << 40 + | (uint64_t) b->c[6] << 48 + | (uint64_t) b->c[7] << 56); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} + +static int +cmp_ext64b_r_offset (const void *p, const void *q) +{ + union aligned64 + { + uint64_t v; + unsigned char c[8]; + }; + const union aligned64 *a + = (const union aligned64 *) ((const Elf64_External_Rel *) p)->r_offset; + const union aligned64 *b + = (const union aligned64 *) ((const Elf64_External_Rel *) q)->r_offset; + + uint64_t aval = ( (uint64_t) a->c[0] << 56 + | (uint64_t) a->c[1] << 48 + | (uint64_t) a->c[2] << 40 + | (uint64_t) a->c[3] << 32 + | (uint64_t) a->c[4] << 24 + | (uint64_t) a->c[5] << 16 + | (uint64_t) a->c[6] << 8 + | (uint64_t) a->c[7]); + uint64_t bval = ( (uint64_t) b->c[0] << 56 + | (uint64_t) b->c[1] << 48 + | (uint64_t) b->c[2] << 40 + | (uint64_t) b->c[3] << 32 + | (uint64_t) b->c[4] << 24 + | (uint64_t) b->c[5] << 16 + | (uint64_t) b->c[6] << 8 + | (uint64_t) b->c[7]); + if (aval < bval) + return -1; + else if (aval > bval) + return 1; + return 0; +} +#endif + /* When performing a relocatable link, the input relocations are preserved. But, if they reference global symbols, the indices referenced must be updated. Update all the relocations found in @@ -7962,7 +8098,8 @@ bfd_elf_perform_complex_relocation (bfd *input_bfd, static void elf_link_adjust_relocs (bfd *abfd, - struct bfd_elf_section_reloc_data *reldata) + struct bfd_elf_section_reloc_data *reldata, + bfd_boolean sort) { unsigned int i; const struct elf_backend_data *bed = get_elf_backend_data (abfd); @@ -8018,6 +8155,35 @@ elf_link_adjust_relocs (bfd *abfd, | (irela[j].r_info & r_type_mask)); (*swap_out) (abfd, irela, erela); } + + if (sort) + { + int (*compare) (const void *, const void *); + + if (bed->s->arch_size == 32) + { + if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) + compare = cmp_ext32l_r_offset; + else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) + compare = cmp_ext32b_r_offset; + else + abort (); + } + else + { +#ifdef BFD_HOST_64_BIT + if (abfd->xvec->header_byteorder == BFD_ENDIAN_LITTLE) + compare = cmp_ext64l_r_offset; + else if (abfd->xvec->header_byteorder == BFD_ENDIAN_BIG) + compare = cmp_ext64b_r_offset; + else +#endif + abort (); + } + qsort (reldata->hdr->contents, count, reldata->hdr->sh_entsize, compare); + free (reldata->hashes); + reldata->hashes = NULL; + } } struct elf_link_sort_rela @@ -8390,6 +8556,8 @@ elf_link_output_sym (struct elf_final_link_info *flinfo, struct elf_link_hash_entry *); const struct elf_backend_data *bed; + BFD_ASSERT (elf_onesymtab (flinfo->output_bfd)); + bed = get_elf_backend_data (flinfo->output_bfd); output_symbol_hook = bed->elf_backend_link_output_symbol_hook; if (output_symbol_hook != NULL) @@ -8427,7 +8595,7 @@ elf_link_output_sym (struct elf_final_link_info *flinfo, amt = flinfo->shndxbuf_size * sizeof (Elf_External_Sym_Shndx); destshndx = (Elf_External_Sym_Shndx *) bfd_realloc (destshndx, - amt * 2); + amt * 2); if (destshndx == NULL) return 0; flinfo->symshndxbuf = destshndx; @@ -8651,27 +8819,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) { if (!h->forced_local) return TRUE; - if (eoinfo->second_pass - && !((h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && h->root.u.def.section->output_section != NULL)) - return TRUE; - - if (!eoinfo->file_sym_done - && (eoinfo->second_pass ? eoinfo->flinfo->filesym_count == 1 - : eoinfo->flinfo->filesym_count > 1)) - { - /* Output a FILE symbol so that following locals are not associated - with the wrong input file. */ - memset (&sym, 0, sizeof (sym)); - sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); - sym.st_shndx = SHN_ABS; - if (!elf_link_output_sym (eoinfo->flinfo, NULL, &sym, - bfd_und_section_ptr, NULL)) - return FALSE; - - eoinfo->file_sym_done = TRUE; - } } else { @@ -8755,8 +8902,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) a regular file, or that we have been told to strip. However, if h->indx is set to -2, the symbol is used by a reloc and we must output it. */ + strip = FALSE; if (h->indx == -2) - strip = FALSE; + ; else if ((h->def_dynamic || h->ref_dynamic || h->root.type == bfd_link_hash_new) @@ -8773,7 +8921,8 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) || h->root.type == bfd_link_hash_defweak) && ((flinfo->info->strip_discarded && discarded_section (h->root.u.def.section)) - || (h->root.u.def.section->owner != NULL + || ((h->root.u.def.section->flags & SEC_LINKER_CREATED) == 0 + && h->root.u.def.section->owner != NULL && (h->root.u.def.section->owner->flags & BFD_PLUGIN) != 0))) strip = TRUE; else if ((h->root.type == bfd_link_hash_undefined @@ -8781,12 +8930,11 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) && h->root.u.undef.abfd != NULL && (h->root.u.undef.abfd->flags & BFD_PLUGIN) != 0) strip = TRUE; - else - strip = FALSE; /* If we're stripping it, and it's not a dynamic symbol, there's - nothing else to do unless it is a forced local symbol or a - STT_GNU_IFUNC symbol. */ + nothing else to do. However, if it is a forced local symbol or + an ifunc symbol we need to give the backend finish_dynamic_symbol + function a chance to make it dynamic. */ if (strip && h->dynindx == -1 && h->type != STT_GNU_IFUNC @@ -8832,19 +8980,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) input_sec = h->root.u.def.section; if (input_sec->output_section != NULL) { - if (eoinfo->localsyms && flinfo->filesym_count == 1) - { - bfd_boolean second_pass_sym - = (input_sec->owner == flinfo->output_bfd - || input_sec->owner == NULL - || (input_sec->flags & SEC_LINKER_CREATED) != 0 - || (input_sec->owner->flags & BFD_LINKER_CREATED) != 0); - - eoinfo->need_second_pass |= second_pass_sym; - if (eoinfo->second_pass != second_pass_sym) - return TRUE; - } - sym.st_shndx = _bfd_elf_section_from_bfd_section (flinfo->output_bfd, input_sec->output_section); @@ -8870,12 +9005,6 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) asection *tls_sec = elf_hash_table (flinfo->info)->tls_sec; if (tls_sec != NULL) sym.st_value -= tls_sec->vma; - else - { - /* The TLS section may have been garbage collected. */ - BFD_ASSERT (flinfo->info->gc_sections - && !input_sec->gc_mark); - } } } } @@ -9050,7 +9179,9 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) if (!h->def_regular) { - if (h->verinfo.verdef == NULL) + if (h->verinfo.verdef == NULL + || (elf_dyn_lib_class (h->verinfo.verdef->vd_bfd) + & (DYN_AS_NEEDED | DYN_DT_NEEDED | DYN_NO_NEEDED))) iversym.vs_vers = 0; else iversym.vs_vers = h->verinfo.verdef->vd_exp_refno + 1; @@ -9074,10 +9205,42 @@ elf_link_output_extsym (struct bfd_hash_entry *bh, void *data) } } - /* If we're stripping it, then it was just a dynamic symbol, and - there's nothing else to do. */ - if (strip || (input_sec->flags & SEC_EXCLUDE) != 0) + /* If the symbol is undefined, and we didn't output it to .dynsym, + strip it from .symtab too. Obviously we can't do this for + relocatable output or when needed for --emit-relocs. */ + else if (input_sec == bfd_und_section_ptr + && h->indx != -2 + && !flinfo->info->relocatable) return TRUE; + /* Also strip others that we couldn't earlier due to dynamic symbol + processing. */ + if (strip) + return TRUE; + if ((input_sec->flags & SEC_EXCLUDE) != 0) + return TRUE; + + /* Output a FILE symbol so that following locals are not associated + with the wrong input file. We need one for forced local symbols + if we've seen more than one FILE symbol or when we have exactly + one FILE symbol but global symbols are present in a file other + than the one with the FILE symbol. We also need one if linker + defined symbols are present. In practice these conditions are + always met, so just emit the FILE symbol unconditionally. */ + if (eoinfo->localsyms + && !eoinfo->file_sym_done + && eoinfo->flinfo->filesym_count != 0) + { + Elf_Internal_Sym fsym; + + memset (&fsym, 0, sizeof (fsym)); + fsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); + fsym.st_shndx = SHN_ABS; + if (!elf_link_output_sym (eoinfo->flinfo, NULL, &fsym, + bfd_und_section_ptr, NULL)) + return FALSE; + + eoinfo->file_sym_done = TRUE; + } indx = bfd_get_symcount (flinfo->output_bfd); ret = elf_link_output_sym (flinfo, h->root.root.string, &sym, input_sec, h); @@ -9301,8 +9464,9 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) *ppsection = isec; - /* Don't output the first, undefined, symbol. */ - if (ppsection == flinfo->sections) + /* Don't output the first, undefined, symbol. In fact, don't + output any undefined local symbol. */ + if (isec == bfd_und_section_ptr) continue; if (ELF_ST_TYPE (isym->st_info) == STT_SECTION) @@ -9352,6 +9516,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) if (ELF_ST_TYPE (isym->st_info) == STT_FILE) { + if (input_bfd->lto_output) + /* -flto puts a temp file name here. This means builds + are not reproducible. Discard the symbol. */ + continue; have_file_sym = TRUE; flinfo->filesym_count += 1; } @@ -9368,8 +9536,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) memset (&osym, 0, sizeof (osym)); osym.st_info = ELF_ST_INFO (STB_LOCAL, STT_FILE); osym.st_shndx = SHN_ABS; - if (!elf_link_output_sym (flinfo, input_bfd->filename, &osym, - bfd_abs_section_ptr, NULL)) + if (!elf_link_output_sym (flinfo, + (input_bfd->lto_output ? NULL + : input_bfd->filename), + &osym, bfd_abs_section_ptr, NULL)) return FALSE; } @@ -9619,6 +9789,24 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) s_type = h->type; + /* If a plugin symbol is referenced from a non-IR file, + mark the symbol as undefined. Note that the + linker may attach linker created dynamic sections + to the plugin bfd. Symbols defined in linker + created sections are not plugin symbols. */ + if (h->root.non_ir_ref + && (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && (h->root.u.def.section->flags + & SEC_LINKER_CREATED) == 0 + && h->root.u.def.section->owner != NULL + && (h->root.u.def.section->owner->flags + & BFD_PLUGIN) != 0) + { + h->root.type = bfd_link_hash_undefined; + h->root.u.undef.abfd = h->root.u.def.section->owner; + } + ps = NULL; if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) @@ -10155,7 +10343,7 @@ elf_reloc_link_order (bfd *output_bfd, size = (bfd_size_type) bfd_get_reloc_size (howto); buf = (bfd_byte *) bfd_zmalloc (size); - if (buf == NULL) + if (buf == NULL && size != 0) return FALSE; rstat = _bfd_relocate_contents (howto, output_bfd, addend, buf); switch (rstat) @@ -10429,12 +10617,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) bfd_size_type max_internal_reloc_count; bfd_size_type max_sym_count; bfd_size_type max_sym_shndx_count; - file_ptr off; Elf_Internal_Sym elfsym; unsigned int i; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Shdr *symtab_shndx_hdr; - Elf_Internal_Shdr *symstrtab_hdr; const struct elf_backend_data *bed = get_elf_backend_data (abfd); struct elf_outext_info eoinfo; bfd_boolean merged; @@ -10665,7 +10851,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* Figure out the file positions for everything but the symbol table and the relocs. We set symcount to force assign_section_numbers to create a symbol table. */ - bfd_get_symcount (abfd) = info->strip == strip_all ? 0 : 1; + bfd_get_symcount (abfd) = info->strip != strip_all || emit_relocs; BFD_ASSERT (! abfd->output_has_begun); if (! _bfd_elf_compute_section_file_positions (abfd, info)) goto error_return; @@ -10691,12 +10877,10 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) esdo->rela.count = 0; } - _bfd_elf_assign_file_positions_for_relocs (abfd); - /* We have now assigned file positions for all the sections except - .symtab and .strtab. We start the .symtab section at the current - file position, and write directly to it. We build the .strtab - section in memory. */ + .symtab, .strtab, and non-loaded reloc sections. We start the + .symtab section at the current file position, and write directly + to it. We build the .strtab section in memory. */ bfd_get_symcount (abfd) = 0; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; /* sh_name is set in prep_headers. */ @@ -10708,13 +10892,6 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* sh_offset is set just below. */ symtab_hdr->sh_addralign = (bfd_vma) 1 << bed->s->log_file_align; - off = elf_next_file_pos (abfd); - off = _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); - - /* Note that at this point elf_next_file_pos (abfd) is - incorrect. We do not yet know the size of the .symtab section. - We correct next_file_pos below, after we do know the size. */ - /* Allocate a buffer to hold swapped out symbols. This is to avoid continuously seeking to the right position in the file. */ if (! info->keep_memory || max_sym_count < 20) @@ -10737,11 +10914,18 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) goto error_return; } - /* Start writing out the symbol table. The first symbol is always a - dummy symbol. */ - if (info->strip != strip_all - || emit_relocs) + if (info->strip != strip_all || emit_relocs) { + file_ptr off = elf_next_file_pos (abfd); + + _bfd_elf_assign_file_position_for_section (symtab_hdr, off, TRUE); + + /* Note that at this point elf_next_file_pos (abfd) is + incorrect. We do not yet know the size of the .symtab section. + We correct next_file_pos below, after we do know the size. */ + + /* Start writing out the symbol table. The first symbol is always a + dummy symbol. */ elfsym.st_value = 0; elfsym.st_size = 0; elfsym.st_info = 0; @@ -10751,16 +10935,13 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) if (elf_link_output_sym (&flinfo, NULL, &elfsym, bfd_und_section_ptr, NULL) != 1) goto error_return; - } - /* Output a symbol for each section. We output these even if we are - discarding local symbols, since they are used for relocs. These - symbols have no names. We store the index of each one in the - index field of the section, so that we can find it again when - outputting relocs. */ - if (info->strip != strip_all - || emit_relocs) - { + /* Output a symbol for each section. We output these even if we are + discarding local symbols, since they are used for relocs. These + symbols have no names. We store the index of each one in the + index field of the section, so that we can find it again when + outputting relocs. */ + elfsym.st_size = 0; elfsym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); elfsym.st_other = 0; @@ -10974,24 +11155,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) eoinfo.failed = FALSE; eoinfo.flinfo = &flinfo; eoinfo.localsyms = TRUE; - eoinfo.need_second_pass = FALSE; - eoinfo.second_pass = FALSE; eoinfo.file_sym_done = FALSE; bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); if (eoinfo.failed) return FALSE; - if (eoinfo.need_second_pass) - { - eoinfo.second_pass = TRUE; - bfd_hash_traverse (&info->hash->table, elf_link_output_extsym, &eoinfo); - if (eoinfo.failed) - return FALSE; - } - /* If backend needs to output some local symbols not present in the hash table, do it now. */ - if (bed->elf_backend_output_arch_local_syms) + if (bed->elf_backend_output_arch_local_syms + && (info->strip != strip_all || emit_relocs)) { typedef int (*out_sym_func) (void *, const char *, Elf_Internal_Sym *, asection *, @@ -11101,7 +11273,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) /* If backend needs to output some symbols not present in the hash table, do it now. */ - if (bed->elf_backend_output_arch_syms) + if (bed->elf_backend_output_arch_syms + && (info->strip != strip_all || emit_relocs)) { typedef int (*out_sym_func) (void *, const char *, Elf_Internal_Sym *, asection *, @@ -11117,45 +11290,46 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) return FALSE; /* Now we know the size of the symtab section. */ - off += symtab_hdr->sh_size; - - symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; - if (symtab_shndx_hdr->sh_name != 0) + if (bfd_get_symcount (abfd) > 0) { - symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; - symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); - symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); - amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx); - symtab_shndx_hdr->sh_size = amt; + /* Finish up and write out the symbol string table (.strtab) + section. */ + Elf_Internal_Shdr *symstrtab_hdr; + file_ptr off = symtab_hdr->sh_offset + symtab_hdr->sh_size; - off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr, - off, TRUE); + symtab_shndx_hdr = &elf_tdata (abfd)->symtab_shndx_hdr; + if (symtab_shndx_hdr->sh_name != 0) + { + symtab_shndx_hdr->sh_type = SHT_SYMTAB_SHNDX; + symtab_shndx_hdr->sh_entsize = sizeof (Elf_External_Sym_Shndx); + symtab_shndx_hdr->sh_addralign = sizeof (Elf_External_Sym_Shndx); + amt = bfd_get_symcount (abfd) * sizeof (Elf_External_Sym_Shndx); + symtab_shndx_hdr->sh_size = amt; - if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 - || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt)) - return FALSE; - } + off = _bfd_elf_assign_file_position_for_section (symtab_shndx_hdr, + off, TRUE); + if (bfd_seek (abfd, symtab_shndx_hdr->sh_offset, SEEK_SET) != 0 + || (bfd_bwrite (flinfo.symshndxbuf, amt, abfd) != amt)) + return FALSE; + } - /* Finish up and write out the symbol string table (.strtab) - section. */ - symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; - /* sh_name was set in prep_headers. */ - symstrtab_hdr->sh_type = SHT_STRTAB; - symstrtab_hdr->sh_flags = 0; - symstrtab_hdr->sh_addr = 0; - symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab); - symstrtab_hdr->sh_entsize = 0; - symstrtab_hdr->sh_link = 0; - symstrtab_hdr->sh_info = 0; - /* sh_offset is set just below. */ - symstrtab_hdr->sh_addralign = 1; + symstrtab_hdr = &elf_tdata (abfd)->strtab_hdr; + /* sh_name was set in prep_headers. */ + symstrtab_hdr->sh_type = SHT_STRTAB; + symstrtab_hdr->sh_flags = 0; + symstrtab_hdr->sh_addr = 0; + symstrtab_hdr->sh_size = _bfd_stringtab_size (flinfo.symstrtab); + symstrtab_hdr->sh_entsize = 0; + symstrtab_hdr->sh_link = 0; + symstrtab_hdr->sh_info = 0; + /* sh_offset is set just below. */ + symstrtab_hdr->sh_addralign = 1; - off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, off, TRUE); - elf_next_file_pos (abfd) = off; + off = _bfd_elf_assign_file_position_for_section (symstrtab_hdr, + off, TRUE); + elf_next_file_pos (abfd) = off; - if (bfd_get_symcount (abfd) > 0) - { if (bfd_seek (abfd, symstrtab_hdr->sh_offset, SEEK_SET) != 0 || ! _bfd_stringtab_emit (abfd, flinfo.symstrtab)) return FALSE; @@ -11165,13 +11339,15 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) for (o = abfd->sections; o != NULL; o = o->next) { struct bfd_elf_section_data *esdo = elf_section_data (o); + bfd_boolean sort; if ((o->flags & SEC_RELOC) == 0) continue; + sort = bed->sort_relocs_p == NULL || (*bed->sort_relocs_p) (o); if (esdo->rel.hdr != NULL) - elf_link_adjust_relocs (abfd, &esdo->rel); + elf_link_adjust_relocs (abfd, &esdo->rel, sort); if (esdo->rela.hdr != NULL) - elf_link_adjust_relocs (abfd, &esdo->rela); + elf_link_adjust_relocs (abfd, &esdo->rela, sort); /* Set the reloc_count field to 0 to prevent write_relocs from trying to swap the relocs out itself. */ @@ -11418,6 +11594,8 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) { /* The contents of the .dynstr section are actually in a stringtab. */ + file_ptr off; + off = elf_section_data (o->output_section)->this_hdr.sh_offset; if (bfd_seek (abfd, off, SEEK_SET) != 0 || ! _bfd_elf_strtab_emit (abfd, @@ -11681,6 +11859,12 @@ _bfd_elf_gc_mark_rsec (struct bfd_link_info *info, asection *sec, || ELF_ST_BIND (cookie->locsyms[r_symndx].st_info) != STB_LOCAL) { h = cookie->sym_hashes[r_symndx - cookie->extsymoff]; + if (h == NULL) + { + info->callbacks->einfo (_("%F%P: corrupt input: %B\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; @@ -11783,6 +11967,47 @@ _bfd_elf_gc_mark (struct bfd_link_info *info, return ret; } +/* Scan and mark sections in a special or debug section group. */ + +static void +_bfd_elf_gc_mark_debug_special_section_group (asection *grp) +{ + /* Point to first section of section group. */ + asection *ssec; + /* Used to iterate the section group. */ + asection *msec; + + bfd_boolean is_special_grp = TRUE; + bfd_boolean is_debug_grp = TRUE; + + /* First scan to see if group contains any section other than debug + and special section. */ + ssec = msec = elf_next_in_group (grp); + do + { + if ((msec->flags & SEC_DEBUGGING) == 0) + is_debug_grp = FALSE; + + if ((msec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) != 0) + is_special_grp = FALSE; + + msec = elf_next_in_group (msec); + } + while (msec != ssec); + + /* If this is a pure debug section group or pure special section group, + keep all sections in this group. */ + if (is_debug_grp || is_special_grp) + { + do + { + msec->gc_mark = 1; + msec = elf_next_in_group (msec); + } + while (msec != ssec); + } +} + /* Keep debug and special sections. */ bfd_boolean @@ -11823,13 +12048,17 @@ _bfd_elf_gc_mark_extra_sections (struct bfd_link_info *info, continue; /* Keep debug and special sections like .comment when they are - not part of a group, or when we have single-member groups. */ + not part of a group. Also keep section groups that contain + just debug sections or special sections. */ for (isec = ibfd->sections; isec != NULL; isec = isec->next) - if ((elf_next_in_group (isec) == NULL - || elf_next_in_group (isec) == isec) - && ((isec->flags & SEC_DEBUGGING) != 0 - || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0)) - isec->gc_mark = 1; + { + if ((isec->flags & SEC_GROUP) != 0) + _bfd_elf_gc_mark_debug_special_section_group (isec); + else if (((isec->flags & SEC_DEBUGGING) != 0 + || (isec->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) + && elf_next_in_group (isec) == NULL) + isec->gc_mark = 1; + } if (! debug_frag_seen) continue; @@ -11888,7 +12117,7 @@ elf_gc_sweep_symbol (struct elf_link_hash_entry *h, void *data) if (!h->mark && (((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && !(h->def_regular + && !((h->def_regular || ELF_COMMON_DEF_P (h)) && h->root.u.def.section->gc_mark)) || h->root.type == bfd_link_hash_undefined || h->root.type == bfd_link_hash_undefweak)) @@ -12111,7 +12340,7 @@ bfd_elf_gc_mark_dynamic_ref_symbol (struct elf_link_hash_entry *h, void *inf) if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) && (h->ref_dynamic - || (h->def_regular + || ((h->def_regular || ELF_COMMON_DEF_P (h)) && ELF_ST_VISIBILITY (h->other) != STV_INTERNAL && ELF_ST_VISIBILITY (h->other) != STV_HIDDEN && (!info->executable @@ -12278,8 +12507,8 @@ bfd_elf_gc_record_vtinherit (bfd *abfd, win: if (!child->vtable) { - child->vtable = (struct elf_link_virtual_table_entry *) - bfd_zalloc (abfd, sizeof (*child->vtable)); + child->vtable = ((struct elf_link_virtual_table_entry *) + bfd_zalloc (abfd, sizeof (*child->vtable))); if (!child->vtable) return FALSE; } @@ -12311,8 +12540,8 @@ bfd_elf_gc_record_vtentry (bfd *abfd ATTRIBUTE_UNUSED, if (!h->vtable) { - h->vtable = (struct elf_link_virtual_table_entry *) - bfd_zalloc (abfd, sizeof (*h->vtable)); + h->vtable = ((struct elf_link_virtual_table_entry *) + bfd_zalloc (abfd, sizeof (*h->vtable))); if (!h->vtable) return FALSE; } @@ -12604,10 +12833,10 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) if ((h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) - && discarded_section (h->root.u.def.section)) + && (h->root.u.def.section->owner != rcookie->abfd + || h->root.u.def.section->kept_section != NULL + || discarded_section (h->root.u.def.section))) return TRUE; - else - return FALSE; } else { @@ -12620,7 +12849,9 @@ bfd_elf_reloc_symbol_deleted_p (bfd_vma offset, void *cookie) /* Need to: get the symbol; get the section. */ isym = &rcookie->locsyms[r_symndx]; isec = bfd_section_from_elf_index (rcookie->abfd, isym->st_shndx); - if (isec != NULL && discarded_section (isec)) + if (isec != NULL + && (isec->kept_section != NULL + || discarded_section (isec))) return TRUE; } return FALSE; @@ -12674,9 +12905,7 @@ bfd_elf_discard_info (bfd *output_bfd, struct bfd_link_info *info) } } - o = NULL; - if (!info->relocatable) - o = bfd_get_section_by_name (output_bfd, ".eh_frame"); + o = bfd_get_section_by_name (output_bfd, ".eh_frame"); if (o != NULL) { asection *i; @@ -12970,11 +13199,11 @@ _bfd_elf_get_dynamic_reloc_section (bfd * abfd, string table associated with ABFD. */ asection * -_bfd_elf_make_dynamic_reloc_section (asection * sec, - bfd * dynobj, - unsigned int alignment, - bfd * abfd, - bfd_boolean is_rela) +_bfd_elf_make_dynamic_reloc_section (asection *sec, + bfd *dynobj, + unsigned int alignment, + bfd *abfd, + bfd_boolean is_rela) { asection * reloc_sec = elf_section_data (sec)->sreloc;