From 12d0ee4aca6285a5f459434761b3f7577caae138 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 23 Jun 2001 05:54:15 +0000 Subject: [PATCH] Avoid creating COPY relocs if possible. * elf32-i386.c (elf_i386_check_relocs): Tweak condition under which .got created. Mark symbols used by R_386_32 and R_386_PC32 relocs as ELF_LINK_NON_GOT_REF to create COPY relocs only when the reloc is in a read-only section. Instead, allocate space for a dynamic reloc to reference the library symbol directly. Keep track of space we allocate using pcrel_relocs_copied. (discard_copies): Delete, and move code to .. (allocate_plt_and_got): ..here. Rename to allocate_plt_and_got_and_discard_relocs. Remove unneeded dynamic relocs for non-shared link. (elf_i386_size_dynamic_sections): Update calls to above functions. (elf_i386_relocate_section): Write out the dynamic relocs. Add more ugly logic to avoid "unresolvable relocation" error. Use htab shortcut in place of elf_hash_table macro. (elf_i386_finish_dynamic_sections): Allow that dynamic .got may not always be created now. --- bfd/ChangeLog | 20 +++++ bfd/elf32-i386.c | 230 ++++++++++++++++++++++++----------------------- 2 files changed, 139 insertions(+), 111 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 201938be5dc..49fc142e4b7 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,23 @@ +2001-06-23 Alan Modra + + Avoid creating COPY relocs if possible. + * elf32-i386.c (elf_i386_check_relocs): Tweak condition under + which .got created. Mark symbols used by R_386_32 and R_386_PC32 + relocs as ELF_LINK_NON_GOT_REF to create COPY relocs only when the + reloc is in a read-only section. Instead, allocate space for a + dynamic reloc to reference the library symbol directly. Keep + track of space we allocate using pcrel_relocs_copied. + (discard_copies): Delete, and move code to .. + (allocate_plt_and_got): ..here. Rename to + allocate_plt_and_got_and_discard_relocs. Remove unneeded dynamic + relocs for non-shared link. + (elf_i386_size_dynamic_sections): Update calls to above functions. + (elf_i386_relocate_section): Write out the dynamic relocs. Add + more ugly logic to avoid "unresolvable relocation" error. Use + htab shortcut in place of elf_hash_table macro. + (elf_i386_finish_dynamic_sections): Allow that dynamic .got may + not always be created now. + 2001-06-20 Bo Thorsen * elf64-x86-64.c (elf64_x86_64_relocate_section): Fix linking of diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 8388295d7b3..5d0ec03c638 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -43,12 +43,10 @@ static boolean elf_i386_check_relocs const Elf_Internal_Rela *)); static boolean elf_i386_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); -static boolean allocate_plt_and_got +static boolean allocate_plt_and_got_and_discard_relocs PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf_i386_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); -static boolean discard_copies - PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf_i386_relocate_section PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); @@ -591,14 +589,15 @@ elf_i386_check_relocs (abfd, info, sec, relocs) h = sym_hashes[r_symndx - symtab_hdr->sh_info]; /* Some relocs require a global offset table. */ - if (dynobj == NULL) + if (htab->sgot == NULL) { switch (ELF32_R_TYPE (rel->r_info)) { case R_386_GOT32: case R_386_GOTOFF: case R_386_GOTPC: - elf_hash_table (info)->dynobj = dynobj = abfd; + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; if (!create_got_section (dynobj, info)) return false; break; @@ -673,19 +672,19 @@ elf_i386_check_relocs (abfd, info, sec, relocs) case R_386_32: case R_386_PC32: - if (h != NULL) + if (h != NULL && !info->shared) { - h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; - - if (!info->shared) - { - /* We may need a .plt entry if the function this - reloc refers to is in a shared lib. */ - if (h->plt.refcount == -1) - h->plt.refcount = 1; - else - h->plt.refcount += 1; - } + /* If this reloc is in a read-only section, we might + need a copy reloc. */ + if ((sec->flags & SEC_READONLY) != 0) + h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + if (h->plt.refcount == -1) + h->plt.refcount = 1; + else + h->plt.refcount += 1; } /* If we are creating a shared library, and this is a reloc @@ -703,19 +702,32 @@ elf_i386_check_relocs (abfd, info, sec, relocs) storing information in the relocs_copied field of the hash table entry. A similar situation occurs when creating shared libraries and symbol visibility changes render the - symbol local. */ - if (info->shared - && (sec->flags & SEC_ALLOC) != 0 - && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 - || (h != NULL - && (! info->symbolic - || h->root.type == bfd_link_hash_defweak - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + symbol local. + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ + if ((info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 + || (h != NULL + && (! info->symbolic + || h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (!info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) { - /* 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. */ + /* We must copy these reloc types into the output file. + Create a reloc section in dynobj and make room for + this reloc. */ + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; if (sreloc == NULL) { const char *name; @@ -767,8 +779,9 @@ elf_i386_check_relocs (abfd, info, sec, relocs) that this function is only called if we are using an elf_i386 linker hash table, which means that h is really a pointer to an elf_i386_link_hash_entry. */ - if (h != NULL - && ELF32_R_TYPE (rel->r_info) == R_386_PC32) + if (!info->shared + || (h != NULL + && ELF32_R_TYPE (rel->r_info) == R_386_PC32)) { struct elf_i386_link_hash_entry *eh; struct elf_i386_pcrel_relocs_copied *p; @@ -1095,10 +1108,12 @@ elf_i386_adjust_dynamic_symbol (info, h) || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) /* Allocate space in .plt, .got and associated reloc sections for - global syms. */ + global syms. Also discards space allocated for relocs in the + check_relocs function that we subsequently have found to be + unneeded. */ static boolean -allocate_plt_and_got (h, inf) +allocate_plt_and_got_and_discard_relocs (h, inf) struct elf_link_hash_entry *h; PTR inf; { @@ -1175,6 +1190,29 @@ allocate_plt_and_got (h, inf) else h->got.offset = (bfd_vma) -1; + /* In the shared -Bsymbolic case, discard space allocated to copy + PC relative relocs against symbols which turn out to be defined + in regular objects. For the normal shared case, discard space + for relocs that have become local due to symbol visibility + changes. For the non-shared case, discard space for symbols + which turn out to need copy relocs or are not dynamic. */ + + if ((info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 + || info->symbolic)) + || (!info->shared + && ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) != 0 + || h->dynindx == -1))) + { + struct elf_i386_link_hash_entry *eh; + struct elf_i386_pcrel_relocs_copied *c; + + eh = (struct elf_i386_link_hash_entry *) h; + for (c = eh->pcrel_relocs_copied; c != NULL; c = c->next) + c->section->_raw_size -= c->count * sizeof (Elf32_External_Rel); + } + return true; } @@ -1198,7 +1236,6 @@ elf_i386_size_dynamic_sections (output_bfd, info) if (htab->root.dynamic_sections_created) { - /* Set the contents of the .interp section to the interpreter. */ if (! info->shared) { @@ -1244,20 +1281,12 @@ elf_i386_size_dynamic_sections (output_bfd, info) } } - /* Allocate global sym .plt and .got entries. */ + /* Allocate global sym .plt and .got entries. Also discard all + unneeded relocs. */ elf_link_hash_traverse (&htab->root, - allocate_plt_and_got, + allocate_plt_and_got_and_discard_relocs, (PTR) info); - /* If this is a -Bsymbolic shared link, then we need to discard all - PC relative relocs against symbols defined in a regular object. - We allocated space for them in the check_relocs routine, but we - will not fill them in in the relocate_section routine. */ - if (info->shared) - elf_link_hash_traverse (&htab->root, - discard_copies, - (PTR) info); - /* The check_relocs and adjust_dynamic_symbol entry points have determined the sizes of the various dynamic sections. Allocate memory for them. */ @@ -1384,41 +1413,6 @@ elf_i386_size_dynamic_sections (output_bfd, info) return true; } -/* This function is called via elf_link_hash_traverse if we are - creating a shared object. In the -Bsymbolic case, it discards the - space allocated to copy PC relative relocs against symbols which - are defined in regular objects. For the normal non-symbolic case, - we also discard space for relocs that have become local due to - symbol visibility changes. We allocated space for them in the - check_relocs routine, but we won't fill them in in the - relocate_section routine. */ - -static boolean -discard_copies (h, inf) - struct elf_link_hash_entry *h; - PTR inf; -{ - struct elf_i386_pcrel_relocs_copied *s; - struct bfd_link_info *info; - struct elf_i386_link_hash_entry *eh; - - info = (struct bfd_link_info *) inf; - eh = (struct elf_i386_link_hash_entry *) h; - - /* If a symbol has been forced local or we have found a regular - definition for the symbolic link case, then we won't be needing - any relocs. */ - if ((eh->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 - && ((eh->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 - || info->symbolic)) - { - for (s = eh->pcrel_relocs_copied; s != NULL; s = s->next) - s->section->_raw_size -= s->count * sizeof (Elf32_External_Rel); - } - - return true; -} - /* Relocate an i386 ELF section. */ static boolean @@ -1539,12 +1533,18 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, & ELF_LINK_FORCED_LOCAL)) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) - || (info->shared - && ((! info->symbolic && h->dynindx != -1) - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0) - && (r_type == R_386_32 - || r_type == R_386_PC32) + || ((r_type == R_386_32 + || r_type == R_386_PC32) + && ((info->shared + && ((!info->symbolic && h->dynindx != -1) + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + || (!info->shared + && h->dynindx != -1 + && (h->elf_link_hash_flags + & ELF_LINK_NON_GOT_REF) == 0 + && (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) && ((input_section->flags & SEC_ALLOC) != 0 /* DWARF will emit R_386_32 relocations in its sections against symbols defined externally @@ -1723,14 +1723,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, case R_386_32: case R_386_PC32: - if (info->shared - && (input_section->flags & SEC_ALLOC) != 0 - && (r_type != R_386_PC32 - || (h != NULL - && h->dynindx != -1 - && (! info->symbolic - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + if ((info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && (r_type != R_386_PC32 + || (h != NULL + && h->dynindx != -1 + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (!info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && h != NULL + && h->dynindx != -1 + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) { Elf_Internal_Rel outrel; boolean skip, relocate; @@ -1780,8 +1788,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma off; off = (_bfd_stab_section_offset - (output_bfd, &elf_hash_table (info)->stab_info, - input_section, + (output_bfd, htab->root.stab_info, input_section, &elf_section_data (input_section)->stab_info, rel->r_offset)); if (off == (bfd_vma) -1) @@ -1808,7 +1815,8 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, /* h->dynindx may be -1 if this symbol was marked to become local. */ if (h == NULL - || ((info->symbolic || h->dynindx == -1) + || (info->shared + && (info->symbolic || h->dynindx == -1) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0)) { @@ -2056,15 +2064,13 @@ elf_i386_finish_dynamic_sections (output_bfd, info) htab = elf_i386_hash_table (info); dynobj = htab->root.dynobj; - - BFD_ASSERT (htab->sgot != NULL); sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); if (htab->root.dynamic_sections_created) { Elf32_External_Dyn *dyncon, *dynconend; - BFD_ASSERT (sdyn != NULL); + BFD_ASSERT (sdyn != NULL && htab->sgot != NULL); dyncon = (Elf32_External_Dyn *) sdyn->contents; dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); @@ -2148,19 +2154,21 @@ elf_i386_finish_dynamic_sections (output_bfd, info) } } - /* Fill in the first three entries in the global offset table. */ - if (htab->sgotplt->_raw_size > 0) + if (htab->sgotplt) { - bfd_put_32 (output_bfd, - (sdyn == NULL ? (bfd_vma) 0 - : sdyn->output_section->vma + sdyn->output_offset), - htab->sgotplt->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 8); - } - - elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 4; + /* Fill in the first three entries in the global offset table. */ + if (htab->sgotplt->_raw_size > 0) + { + bfd_put_32 (output_bfd, + (sdyn == NULL ? (bfd_vma) 0 + : sdyn->output_section->vma + sdyn->output_offset), + htab->sgotplt->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 8); + } + elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 4; + } return true; } -- 2.30.2