Avoid creating COPY relocs if possible.
authorAlan Modra <amodra@gmail.com>
Sat, 23 Jun 2001 05:54:15 +0000 (05:54 +0000)
committerAlan Modra <amodra@gmail.com>
Sat, 23 Jun 2001 05:54:15 +0000 (05:54 +0000)
* 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
bfd/elf32-i386.c

index 201938be5dc7edf85a214cf2c8b696b54d41f4e7..49fc142e4b7a57d7adfb7f3aa28766dca93e071b 100644 (file)
@@ -1,3 +1,23 @@
+2001-06-23  Alan Modra  <amodra@bigpond.net.au>
+
+       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  <bo@suse.co.uk>
 
        * elf64-x86-64.c (elf64_x86_64_relocate_section): Fix linking of
index 8388295d7b3a0d2e4103cc0349812ea51a4c389d..5d0ec03c638b15b3e8fa614e84014e2d1401c9e5 100644 (file)
@@ -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;
 }