From: Ian Lance Taylor Date: Thu, 27 Oct 1994 21:25:31 +0000 (+0000) Subject: * libelf.h (struct bfd_elf_section_data): Add field dynindx. X-Git-Url: http://git.efficios.com/?a=commitdiff_plain;h=14cac507a88e921a16b8847ffe8ade8e7e8160b3;p=deliverable%2Fbinutils-gdb.git * libelf.h (struct bfd_elf_section_data): Add field dynindx. * elfcode.h (NAME(bfd_elf,size_dynamic_sections)): Don't finalize the .dynsym, .dynstr or .hash sections until after the backend size_dynamic_sections routine, so that it can add dynamic symbols if it wants to. * elf32-i386.c (elf_i386_adjust_dynamic_symbol): Don't define the symbol to be in the .plt section when generating a shared library if it is a defined symbol. * elf32-sparc.c (elf32_sparc_adjust_dynamic_symbol): Likewise. (elf32_sparc_size_dynamic_sections): When generating a shared library, allocate space for a dynamic symbol for each output section, storing the index in the dynindx field of the ELF section data. Adjust the other dynindx fields to account for this. (elf32_sparc_adjust_dynindx): New static function. (elf32_sparc_relocate_section): When copying a reloc into a shared library, use the original addend as appropriate. Convert an R_SPARC_32 reloc into an R_SPARC_RELATIVE reloc. Use the dynamic symbol index of the output section, not the normal symbol index. (elf32_sparc_finish_dynamic_sections): Don't die if a section does not exist when setting the value of the dynamic tags. Write out a dynamic symbol for each output section. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 2c1e06689b..414ef40761 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,27 @@ +Thu Oct 27 16:59:52 1994 Ian Lance Taylor + + * libelf.h (struct bfd_elf_section_data): Add field dynindx. + * elfcode.h (NAME(bfd_elf,size_dynamic_sections)): Don't finalize + the .dynsym, .dynstr or .hash sections until after the backend + size_dynamic_sections routine, so that it can add dynamic symbols + if it wants to. + * elf32-i386.c (elf_i386_adjust_dynamic_symbol): Don't define the + symbol to be in the .plt section when generating a shared library + if it is a defined symbol. + * elf32-sparc.c (elf32_sparc_adjust_dynamic_symbol): Likewise. + (elf32_sparc_size_dynamic_sections): When generating a shared + library, allocate space for a dynamic symbol for each output + section, storing the index in the dynindx field of the ELF section + data. Adjust the other dynindx fields to account for this. + (elf32_sparc_adjust_dynindx): New static function. + (elf32_sparc_relocate_section): When copying a reloc into a shared + library, use the original addend as appropriate. Convert an + R_SPARC_32 reloc into an R_SPARC_RELATIVE reloc. Use the dynamic + symbol index of the output section, not the normal symbol index. + (elf32_sparc_finish_dynamic_sections): Don't die if a section does + not exist when setting the value of the dynamic tags. Write out + a dynamic symbol for each output section. + Wed Oct 26 01:15:51 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) * aoutx.h (aout_link_input_section): Don't bother to read or write diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 14f4b71655..60c0f45b67 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -542,9 +542,9 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (info->shared && (sec->flags & SEC_ALLOC) != 0) { - /* When creating a shared object, we must output a - R_386_RELATIVE reloc for this location. We create a - reloc section in dynobj and make room for this reloc. */ + /* When creating a shared object, we must copy these + reloc types into the output file. We create a reloc + section in dynobj and make room for this reloc. */ if (sreloc == NULL) { const char *name; @@ -647,9 +647,15 @@ elf_i386_adjust_dynamic_symbol (info, h) if (s->_raw_size == 0) s->_raw_size += PLT_ENTRY_SIZE; - /* Set the symbol to this location in the .plt. */ - h->root.u.def.section = s; - h->root.u.def.value = s->_raw_size; + /* If we are not generating a shared library, or if the symbol + is not defined, set the symbol to this location in the .plt. + This is required to make function pointers compare as equal + between the normal executable and the shared library. */ + if (! info->shared || h->root.type != bfd_link_hash_defined) + { + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + } h->plt_offset = s->_raw_size; diff --git a/bfd/elf32-sparc.c b/bfd/elf32-sparc.c index 90130ccab2..713e855584 100644 --- a/bfd/elf32-sparc.c +++ b/bfd/elf32-sparc.c @@ -36,6 +36,8 @@ static boolean elf32_sparc_check_relocs const Elf_Internal_Rela *)); static boolean elf32_sparc_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean elf32_sparc_adjust_dynindx + PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf32_sparc_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); static boolean elf32_sparc_relocate_section @@ -617,9 +619,15 @@ elf32_sparc_adjust_dynamic_symbol (info, h) return false; } - /* Set the symbol to this location in the .plt. */ - h->root.u.def.section = s; - h->root.u.def.value = s->_raw_size; + /* If we are not generating a shared library, or if the symbol + is not defined, set the symbol to this location in the .plt. + This is required to make function pointers compare as equal + between the normal executable and the shared library. */ + if (! info->shared || h->root.type != bfd_link_hash_defined) + { + h->root.u.def.section = s; + h->root.u.def.value = s->_raw_size; + } h->plt_offset = s->_raw_size; @@ -863,6 +871,44 @@ elf32_sparc_size_dynamic_sections (output_bfd, info) } } + /* If we are generating a shared library, we generate a section + symbol for each output section. These are local symbols, which + means that they must come first in the dynamic symbol table. + That means we must increment the dynamic symbol index of every + other dynamic symbol. */ + if (info->shared) + { + int c, i; + + c = bfd_count_sections (output_bfd); + elf_link_hash_traverse (elf_hash_table (info), + elf32_sparc_adjust_dynindx, + (PTR) &c); + elf_hash_table (info)->dynsymcount += c; + + for (i = 1, s = output_bfd->sections; s != NULL; s = s->next, i++) + { + elf_section_data (s)->dynindx = i; + /* These symbols will have no names, so we don't need to + fiddle with dynstr_index. */ + } + } + + return true; +} + +/* Increment the index of a dynamic symbol by a given amount. Called + via elf_link_hash_traverse. */ + +static boolean +elf32_sparc_adjust_dynindx (h, cparg) + struct elf_link_hash_entry *h; + PTR cparg; +{ + int *cp = (int *) cparg; + + if (h->dynindx != -1) + h->dynindx += *cp; return true; } @@ -1146,37 +1192,44 @@ elf32_sparc_relocate_section (output_bfd, info, input_bfd, input_section, { BFD_ASSERT (h->dynindx != -1); outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - outrel.r_addend = 0; + outrel.r_addend = rel->r_addend; } else { - long indx; - - sym = local_syms + r_symndx; - - /* If this isn't a section symbol, we need to map it - to something that is going to be put into the - dynamic symbols. The case will probably never - arise. */ - BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_SECTION); - - sec = local_sections[r_symndx]; - if (sec != NULL && bfd_is_abs_section (sec)) - indx = 0; - else if (sec == NULL || sec->owner == NULL) + if (r_type == R_SPARC_32) { - bfd_set_error (bfd_error_bad_value); - return false; + outrel.r_info = ELF32_R_INFO (0, R_SPARC_RELATIVE); + outrel.r_addend = relocation + rel->r_addend; } else { - indx = sec->output_section->target_index; - if (indx == 0) - abort (); + long indx; + + sym = local_syms + r_symndx; + + BFD_ASSERT (ELF_ST_TYPE (sym->st_info) == STT_SECTION); + + sec = local_sections[r_symndx]; + if (sec != NULL && bfd_is_abs_section (sec)) + indx = 0; + else if (sec == NULL || sec->owner == NULL) + { + bfd_set_error (bfd_error_bad_value); + return false; + } + else + { + asection *osec; + + osec = sec->output_section; + indx = elf_section_data (osec)->dynindx; + if (indx == 0) + abort (); + } + + outrel.r_info = ELF32_R_INFO (indx, r_type); + outrel.r_addend = relocation + rel->r_addend; } - - outrel.r_info = ELF32_R_INFO (indx, r_type); - outrel.r_addend = sec->output_offset + sym->st_value; } bfd_elf32_swap_reloca_out (output_bfd, &outrel, @@ -1399,15 +1452,19 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info) asection *s; s = bfd_get_section_by_name (output_bfd, name); - BFD_ASSERT (s != NULL); - if (! size) - dyn.d_un.d_ptr = s->vma; + if (s == NULL) + dyn.d_un.d_val = 0; else { - if (s->_cooked_size != 0) - dyn.d_un.d_val = s->_cooked_size; + if (! size) + dyn.d_un.d_ptr = s->vma; else - dyn.d_un.d_val = s->_raw_size; + { + if (s->_cooked_size != 0) + dyn.d_un.d_val = s->_cooked_size; + else + dyn.d_un.d_val = s->_raw_size; + } } bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); } @@ -1442,6 +1499,43 @@ elf32_sparc_finish_dynamic_sections (output_bfd, info) elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + if (info->shared) + { + asection *sdynsym; + asection *s; + Elf_Internal_Sym sym; + + /* Set up the section symbols for the output sections. */ + + sdynsym = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (sdynsym != NULL); + + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = output_bfd->sections; s != NULL; s = s->next) + { + int indx; + + sym.st_value = s->vma; + + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + + bfd_elf32_swap_symbol_out (output_bfd, &sym, + ((Elf32_External_Sym *) sdynsym->contents + + elf_section_data (s)->dynindx)); + } + + /* Set the sh_info field of the output .dynsym section to the + index of the first global symbol. */ + elf_section_data (sdynsym->output_section)->this_hdr.sh_info = + bfd_count_sections (output_bfd) + 1; + } + return true; } diff --git a/bfd/elfcode.h b/bfd/elfcode.h index d1ef2dc494..cdb51afda8 100644 --- a/bfd/elfcode.h +++ b/bfd/elfcode.h @@ -4819,62 +4819,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, info, if (elf_hash_table (info)->dynamic_sections_created) { - size_t dynsymcount; bfd_size_type strsize; *sinterpptr = bfd_get_section_by_name (dynobj, ".interp"); BFD_ASSERT (*sinterpptr != NULL || info->shared); - /* Set the size of the .dynsym and .hash sections. We counted - the number of dynamic symbols in elf_link_add_object_symbols. - We will build the contents of .dynsym and .hash when we build - the final symbol table, because until then we do not know the - correct value to give the symbols. We built the .dynstr - section as we went along in elf_link_add_object_symbols. */ - dynsymcount = elf_hash_table (info)->dynsymcount; - s = bfd_get_section_by_name (dynobj, ".dynsym"); - BFD_ASSERT (s != NULL); - s->_raw_size = dynsymcount * sizeof (Elf_External_Sym); - s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); - if (s->contents == NULL && s->_raw_size != 0) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - - /* The first entry in .dynsym is a dummy symbol. */ - isym.st_value = 0; - isym.st_size = 0; - isym.st_name = 0; - isym.st_info = 0; - isym.st_other = 0; - isym.st_shndx = 0; - elf_swap_symbol_out (output_bfd, &isym, - (Elf_External_Sym *) s->contents); - - for (i = 0; elf_buckets[i] != 0; i++) - { - bucketcount = elf_buckets[i]; - if (dynsymcount < elf_buckets[i + 1]) - break; - } - - s = bfd_get_section_by_name (dynobj, ".hash"); - BFD_ASSERT (s != NULL); - s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8); - s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); - if (s->contents == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } - memset (s->contents, 0, s->_raw_size); - - put_word (output_bfd, bucketcount, s->contents); - put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8)); - - elf_hash_table (info)->bucketcount = bucketcount; - if (soname != NULL) { bfd_size_type indx; @@ -4897,10 +4846,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, info, return false; } - s = bfd_get_section_by_name (dynobj, ".dynstr"); - BFD_ASSERT (s != NULL); - s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr); - /* Find all symbols which were defined in a dynamic object and make the backend pick a reasonable value for them. */ elf_link_hash_traverse (elf_hash_table (info), @@ -4938,6 +4883,62 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, info, if (elf_hash_table (info)->dynamic_sections_created) { + size_t dynsymcount; + + /* Set the size of the .dynsym and .hash sections. We counted + the number of dynamic symbols in elf_link_add_object_symbols. + We will build the contents of .dynsym and .hash when we build + the final symbol table, because until then we do not know the + correct value to give the symbols. We built the .dynstr + section as we went along in elf_link_add_object_symbols. */ + dynsymcount = elf_hash_table (info)->dynsymcount; + s = bfd_get_section_by_name (dynobj, ".dynsym"); + BFD_ASSERT (s != NULL); + s->_raw_size = dynsymcount * sizeof (Elf_External_Sym); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL && s->_raw_size != 0) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + + /* The first entry in .dynsym is a dummy symbol. */ + isym.st_value = 0; + isym.st_size = 0; + isym.st_name = 0; + isym.st_info = 0; + isym.st_other = 0; + isym.st_shndx = 0; + elf_swap_symbol_out (output_bfd, &isym, + (Elf_External_Sym *) s->contents); + + for (i = 0; elf_buckets[i] != 0; i++) + { + bucketcount = elf_buckets[i]; + if (dynsymcount < elf_buckets[i + 1]) + break; + } + + s = bfd_get_section_by_name (dynobj, ".hash"); + BFD_ASSERT (s != NULL); + s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8); + s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); + if (s->contents == NULL) + { + bfd_set_error (bfd_error_no_memory); + return false; + } + memset (s->contents, 0, s->_raw_size); + + put_word (output_bfd, bucketcount, s->contents); + put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8)); + + elf_hash_table (info)->bucketcount = bucketcount; + + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); + s->_raw_size = _bfd_stringtab_size (elf_hash_table (info)->dynstr); + if (! elf_add_dynamic_entry (info, DT_NULL, 0)) return false; } diff --git a/bfd/libelf.h b/bfd/libelf.h index b752946b31..3bbde89962 100644 --- a/bfd/libelf.h +++ b/bfd/libelf.h @@ -420,6 +420,10 @@ struct bfd_elf_section_data { rather than RELA, all the r_addend fields will be zero. This pointer may be NULL. It is used by the backend linker. */ Elf_Internal_Rela *relocs; + /* Used by the backend linker when generating a shared library to + record the dynamic symbol index for a section symbol + corresponding to this section. */ + long dynindx; }; #define elf_section_data(sec) ((struct bfd_elf_section_data*)sec->used_by_bfd)