* elf-bfd.h (enum elf_reloc_type_class): New.
authorJakub Jelinek <jakub@redhat.com>
Thu, 23 Aug 2001 15:14:18 +0000 (15:14 +0000)
committerJakub Jelinek <jakub@redhat.com>
Thu, 23 Aug 2001 15:14:18 +0000 (15:14 +0000)
(struct elf_backend_data): Add elf_backend_reloc_type_class.
(_bfd_elf_reloc_type_class): New.
* elfxx-target.h (elf_backend_reloc_type_class): Define.
(elfNN_bed): Add elf_backend_reloc_type_class.
* elf.c (_bfd_elf_reloc_type_class): New.
* elf32-i386.c (elf_i386_check_relocs): Set DF_TEXTREL if the reloc
is against read-only section.
(elf_i386_size_dynamic_sections): Use DF_TEXTREL flag instead of
looking up section names for DT_TEXTREL.
(elf_i386_reloc_type_class): New.
(elf_backend_reloc_type_class): Define.
* elf32-sparc.c (elf32_sparc_check_relocs): Set DF_TEXTREL if the
reloc is against read-only section.
(elf32_sparc_size_dynamic_sections): Use DF_TEXTREL flag instead of
looking up section names for DT_TEXTREL.
(elf32_sparc_reloc_type_class): New.
(elf_backend_reloc_type_class): Define.
* elf64-sparc.c (sparc64_elf_check_relocs): Set DF_TEXTREL if the
reloc is against read-only section.
(sparc64_elf_size_dynamic_sections): Use DF_TEXTREL flag instead of
looking up section names for DT_TEXTREL.
(sparc64_elf_reloc_type_class): New.
(elf_backend_reloc_type_class): Define.
* elfxx-ia64.c (struct elfNN_ia64_link_hash_table): Add reltext field.
(elfNN_ia64_hash_table_create): Clear ia64_info.
(get_reloc_section): Set DF_TEXTREL if the reloc is against read-only
section.
(elfNN_ia64_size_dynamic_sections): Use ia64_info->reltext flag
instead of looking up section names for DT_TEXTREL.
(elfNN_ia64_reloc_type_class): New.
(elf_backend_reloc_type_class): Define.
* elflink.h (size_dynamic_sections): Add spare DT_NULL tags.
(struct elf_link_sort_rela): New.
(elf_link_sort_cmp1, elf_link_sort_cmp2, elf_link_sort_relocs): New.
(elf_bfd_final_link): Call elf_link_sort_relocs.
Convert one spare DT_NULL into DT_RELCOUNT resp. DT_RELACOUNT if
necessary.

* bfdlink.h (struct bfd_link_info): Add combreloc and
spare_dynamic_tags fields.

* emultempl/elf32.em (place_orphan): Place orphan .rel* sections
into .rel.dyn resp. .rela.dyn if combreloc.
(get_script): If .x linker script is equal to .xn, only put it
once into the binary.
Add .xc and .xsc scripts.
(parse_args): Handle -z combreloc and -z nocombreloc.
* scripttempl/elf.sc (.rela.sbss): Fix a typo.
For .xc and .xsc scripts put all .rel* or .rela* input sections
but .rel*.plt and PLT-like sections into .rel.dyn resp. .rela.dyn.
* genscripts.sh (GENERATE_COMBRELOC_SCRIPT): Set if SCRIPT_NAME
is elf.
Strip trailing whitespace from script.
Generate .xc and .xsc scripts if requested.
* ldmain.c (main): Initialize link_info.combreloc and
link_info.spare_dynamic_tags.
* lexsup.c (OPTION_SPARE_DYNAMIC_TAGS): Define.
(ld_options): Add --spare-dynamic-tags option.
(parse_args): Likewise.
* ld.texinfo: Document -z combreloc and -z nocombreloc.
* ldint.texinfo: Document .xc and .xsc linker scripts.
* NEWS: Add notes about -z combreloc and SHF_MERGE.

20 files changed:
bfd/ChangeLog
bfd/elf-bfd.h
bfd/elf.c
bfd/elf32-i386.c
bfd/elf32-sparc.c
bfd/elf64-sparc.c
bfd/elflink.h
bfd/elfxx-ia64.c
bfd/elfxx-target.h
include/ChangeLog
include/bfdlink.h
ld/ChangeLog
ld/NEWS
ld/emultempl/elf32.em
ld/genscripts.sh
ld/ld.texinfo
ld/ldint.texinfo
ld/ldmain.c
ld/lexsup.c
ld/scripttempl/elf.sc

index 7010dfa248c24625de03f3d38440ebd95de16d68..551b9d0a02d6bdfc06352ef7babba643e69953a3 100644 (file)
@@ -1,3 +1,44 @@
+2001-08-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf-bfd.h (enum elf_reloc_type_class): New.
+       (struct elf_backend_data): Add elf_backend_reloc_type_class.
+       (_bfd_elf_reloc_type_class): New.
+       * elfxx-target.h (elf_backend_reloc_type_class): Define.
+       (elfNN_bed): Add elf_backend_reloc_type_class.
+       * elf.c (_bfd_elf_reloc_type_class): New.
+       * elf32-i386.c (elf_i386_check_relocs): Set DF_TEXTREL if the reloc
+       is against read-only section.
+       (elf_i386_size_dynamic_sections): Use DF_TEXTREL flag instead of
+       looking up section names for DT_TEXTREL.
+       (elf_i386_reloc_type_class): New.
+       (elf_backend_reloc_type_class): Define.
+       * elf32-sparc.c (elf32_sparc_check_relocs): Set DF_TEXTREL if the
+       reloc is against read-only section.
+       (elf32_sparc_size_dynamic_sections): Use DF_TEXTREL flag instead of
+       looking up section names for DT_TEXTREL.
+       (elf32_sparc_reloc_type_class): New.
+       (elf_backend_reloc_type_class): Define.
+       * elf64-sparc.c (sparc64_elf_check_relocs): Set DF_TEXTREL if the
+       reloc is against read-only section.
+       (sparc64_elf_size_dynamic_sections): Use DF_TEXTREL flag instead of
+       looking up section names for DT_TEXTREL.
+       (sparc64_elf_reloc_type_class): New.
+       (elf_backend_reloc_type_class): Define.
+       * elfxx-ia64.c (struct elfNN_ia64_link_hash_table): Add reltext field.
+       (elfNN_ia64_hash_table_create): Clear ia64_info.
+       (get_reloc_section): Set DF_TEXTREL if the reloc is against read-only
+       section.
+       (elfNN_ia64_size_dynamic_sections): Use ia64_info->reltext flag
+       instead of looking up section names for DT_TEXTREL.
+       (elfNN_ia64_reloc_type_class): New.
+       (elf_backend_reloc_type_class): Define.
+       * elflink.h (size_dynamic_sections): Add spare DT_NULL tags.
+       (struct elf_link_sort_rela): New.
+       (elf_link_sort_cmp1, elf_link_sort_cmp2, elf_link_sort_relocs): New.
+       (elf_bfd_final_link): Call elf_link_sort_relocs.
+       Convert one spare DT_NULL into DT_RELCOUNT resp. DT_RELACOUNT if
+       necessary.
+
 2001-08-23  Nick Clifton  <nickc@cambridge.redhat.com>
 
        * configure.in (x86-bsdi): No corefile support.
index 66095422e047a6e187f597a99ce7c4737435905b..a048e6f5f4393fd258f8292c180735c0fd6ac3fc 100644 (file)
@@ -331,6 +331,13 @@ struct elf_size_info {
         ? (elf_symbol_type *) (S) \
         : 0)
 
+enum elf_reloc_type_class {
+  reloc_class_normal,
+  reloc_class_relative,
+  reloc_class_plt,
+  reloc_class_copy
+};
+
 struct elf_backend_data
 {
   /* The architecture for this backend.  */
@@ -636,10 +643,13 @@ struct elf_backend_data
      note is found in a core file. */
   boolean (*elf_backend_grok_psinfo) PARAMS ((bfd *, Elf_Internal_Note *));
 
-    /* Functions to print VMAs.  Special code to handle 64 bit ELF files.  */
+  /* Functions to print VMAs.  Special code to handle 64 bit ELF files.  */
   void (* elf_backend_sprintf_vma) PARAMS ((bfd *, char *, bfd_vma));
   void (* elf_backend_fprintf_vma) PARAMS ((bfd *, PTR, bfd_vma));
 
+  /* This function returns class of a reloc type.  */
+  enum elf_reloc_type_class (* elf_backend_reloc_type_class) PARAMS ((int));
+
   /* The swapping table to use when dealing with ECOFF information.
      Used for the MIPS ELF .mdebug section.  */
   const struct ecoff_debug_swap *elf_backend_ecoff_debug_swap;
@@ -1008,6 +1018,8 @@ extern void bfd_elf_print_symbol PARAMS ((bfd *, PTR, asymbol *,
 extern void _bfd_elf_sprintf_vma PARAMS ((bfd *, char *, bfd_vma));
 extern void _bfd_elf_fprintf_vma PARAMS ((bfd *, PTR, bfd_vma));
 
+extern enum elf_reloc_type_class _bfd_elf_reloc_type_class PARAMS ((int));
+
 extern unsigned long bfd_elf_hash PARAMS ((const char *));
 
 extern bfd_reloc_status_type bfd_elf_generic_reloc PARAMS ((bfd *,
index 79998036d61ed1c2a45655e6dea658ffdfe87b45..1cbb18033954230da2d9d578be91a56f0504cd76 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -6053,3 +6053,10 @@ _bfd_elf_fprintf_vma (abfd, stream, value)
   fprintf_vma ((FILE *) stream, value);
 #endif
 }
+
+enum elf_reloc_type_class
+_bfd_elf_reloc_type_class (type)
+     int type;
+{
+  return reloc_class_normal;
+}
index 00ca185004239362b8f3574c17b1b37b25386db9..8c4955998ab0d7fa67efde6d3626acb4c4f8ce9c 100644 (file)
@@ -63,6 +63,7 @@ static boolean elf_i386_finish_dynamic_sections
   PARAMS ((bfd *, struct bfd_link_info *));
 static boolean elf_i386_fake_sections
   PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *));
+static enum elf_reloc_type_class elf_i386_reloc_type_class PARAMS ((int));
 
 #define USE_REL        1               /* 386 uses REL relocations instead of RELA */
 
@@ -767,6 +768,8 @@ elf_i386_check_relocs (abfd, info, sec, relocs)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf32_External_Rel);
@@ -1243,14 +1246,13 @@ allocate_plt_and_got_and_discard_relocs (h, inf)
 
 static boolean
 elf_i386_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   struct elf_i386_link_hash_table *htab;
   bfd *dynobj;
   asection *s;
   boolean relocs;
-  boolean reltext;
   bfd *i;
 
   htab = elf_i386_hash_table (info);
@@ -1315,7 +1317,6 @@ elf_i386_size_dynamic_sections (output_bfd, info)
   /* We now have determined the sizes of the various dynamic sections.
      Allocate memory for them.  */
   relocs = false;
-  reltext = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
       if ((s->flags & SEC_LINKER_CREATED) == 0)
@@ -1344,29 +1345,8 @@ elf_i386_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             asection *target;
-
-             /* Remember whether there are any reloc sections other
-                than .rel.plt.  */
              if (s != htab->srelplt)
-               {
-                 const char *outname;
-
-                 relocs = true;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL
-                    entry.  The entries in the .rel.plt section
-                    really apply to the .got section, which we
-                    created ourselves and so know is not readonly.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 s->output_section);
-                 target = bfd_get_section_by_name (output_bfd, outname + 4);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-               }
+               relocs = true;
 
              /* We use the reloc_count field as a counter if we need
                 to copy relocs into the output file.  */
@@ -1426,11 +1406,10 @@ elf_i386_size_dynamic_sections (output_bfd, info)
            return false;
        }
 
-      if (reltext)
+      if ((info->flags & DF_TEXTREL) != 0)
        {
          if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
            return false;
-         info->flags |= DF_TEXTREL;
        }
     }
 
@@ -2215,6 +2194,22 @@ elf_i386_fake_sections (abfd, hdr, sec)
   return true;
 }
 
+static enum elf_reloc_type_class
+elf_i386_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_386_RELATIVE:
+      return reloc_class_relative;
+    case R_386_JUMP_SLOT:
+      return reloc_class_plt;
+    case R_386_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 
 #define TARGET_LITTLE_SYM              bfd_elf32_i386_vec
 #define TARGET_LITTLE_NAME             "elf32-i386"
@@ -2246,5 +2241,6 @@ elf_i386_fake_sections (abfd, hdr, sec)
 #define elf_backend_relocate_section         elf_i386_relocate_section
 #define elf_backend_size_dynamic_sections     elf_i386_size_dynamic_sections
 #define elf_backend_fake_sections            elf_i386_fake_sections
+#define elf_backend_reloc_type_class         elf_i386_reloc_type_class
 
 #include "elf32-target.h"
index 76d0324ee5fd2ba10d950d8ccd40128fb79ed0d3..3129dd713c505e480277e000f1076f1f91a2f260 100644 (file)
@@ -52,6 +52,8 @@ static boolean elf32_sparc_object_p
   PARAMS ((bfd *));
 static void elf32_sparc_final_write_processing
   PARAMS ((bfd *, boolean));
+static enum elf_reloc_type_class elf32_sparc_reloc_type_class
+  PARAMS ((int));
 \f
 /* The relocation "howto" table.  */
 
@@ -592,6 +594,8 @@ elf32_sparc_check_relocs (abfd, info, sec, relocs)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 2))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf32_External_Rela);
@@ -909,12 +913,11 @@ elf32_sparc_adjust_dynamic_symbol (info, h)
 
 static boolean
 elf32_sparc_size_dynamic_sections (output_bfd, info)
-     bfd *output_bfd;
+     bfd *output_bfd ATTRIBUTE_UNUSED;
      struct bfd_link_info *info;
 {
   bfd *dynobj;
   asection *s;
-  boolean reltext;
   boolean relplt;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -952,7 +955,6 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
-  reltext = false;
   relplt = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
@@ -985,19 +987,6 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             const char *outname;
-             asection *target;
-
-             /* If this relocation section applies to a read only
-                section, then we probably need a DT_TEXTREL entry.  */
-             outname = bfd_get_section_name (output_bfd,
-                                             s->output_section);
-             target = bfd_get_section_by_name (output_bfd, outname + 5);
-             if (target != NULL
-                 && (target->flags & SEC_READONLY) != 0
-                 && (target->flags & SEC_ALLOC) != 0)
-               reltext = true;
-
              if (strcmp (name, ".rela.plt") == 0)
                relplt = true;
 
@@ -1058,11 +1047,10 @@ elf32_sparc_size_dynamic_sections (output_bfd, info)
                                            sizeof (Elf32_External_Rela)))
        return false;
 
-      if (reltext)
+      if (info->flags & DF_TEXTREL)
        {
          if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0))
            return false;
-         info->flags |= DF_TEXTREL;
        }
     }
 
@@ -2081,6 +2069,23 @@ elf32_sparc_final_write_processing (abfd, linker)
       break;
     }
 }
+
+static enum elf_reloc_type_class
+elf32_sparc_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_SPARC_RELATIVE:
+      return reloc_class_relative;
+    case R_SPARC_JMP_SLOT:
+      return reloc_class_plt;
+    case R_SPARC_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 \f
 #define TARGET_BIG_SYM bfd_elf32_sparc_vec
 #define TARGET_BIG_NAME        "elf32-sparc"
@@ -2111,6 +2116,7 @@ elf32_sparc_final_write_processing (abfd, linker)
                                        elf32_sparc_final_write_processing
 #define elf_backend_gc_mark_hook        elf32_sparc_gc_mark_hook
 #define elf_backend_gc_sweep_hook       elf32_sparc_gc_sweep_hook
+#define elf_backend_reloc_type_class   elf32_sparc_reloc_type_class
 
 #define elf_backend_can_gc_sections 1
 #define elf_backend_want_got_plt 0
index c4248f713ee0bfd6fe489f597ec668d1dfffe4fa..e121126bc91472e133f1bc1e40740e18528e6f20 100644 (file)
@@ -96,6 +96,7 @@ static boolean sparc64_elf_slurp_reloc_table
 static long sparc64_elf_canonicalize_dynamic_reloc
   PARAMS ((bfd *, arelent **, asymbol **));
 static void sparc64_elf_write_relocs PARAMS ((bfd *, asection *, PTR));
+static enum elf_reloc_type_class sparc64_elf_reloc_type_class PARAMS ((int));
 \f
 /* The relocation "howto" table.  */
 
@@ -1248,6 +1249,8 @@ sparc64_elf_check_relocs (abfd, info, sec, relocs)
                          || ! bfd_set_section_alignment (dynobj, sreloc, 3))
                        return false;
                    }
+                 if (sec->flags & SEC_READONLY)
+                   info->flags |= DF_TEXTREL;
                }
 
              sreloc->_raw_size += sizeof (Elf64_External_Rela);
@@ -1666,7 +1669,6 @@ sparc64_elf_size_dynamic_sections (output_bfd, info)
 {
   bfd *dynobj;
   asection *s;
-  boolean reltext;
   boolean relplt;
 
   dynobj = elf_hash_table (info)->dynobj;
@@ -1698,7 +1700,6 @@ sparc64_elf_size_dynamic_sections (output_bfd, info)
   /* The check_relocs and adjust_dynamic_symbol entry points have
      determined the sizes of the various dynamic sections.  Allocate
      memory for them.  */
-  reltext = false;
   relplt = false;
   for (s = dynobj->sections; s != NULL; s = s->next)
     {
@@ -1731,18 +1732,6 @@ sparc64_elf_size_dynamic_sections (output_bfd, info)
            }
          else
            {
-             const char *outname;
-             asection *target;
-
-             /* If this relocation section applies to a read only
-                section, then we probably need a DT_TEXTREL entry.  */
-             outname = bfd_get_section_name (output_bfd,
-                                             s->output_section);
-             target = bfd_get_section_by_name (output_bfd, outname + 5);
-             if (target != NULL
-                 && (target->flags & SEC_READONLY) != 0)
-               reltext = true;
-
              if (strcmp (name, ".rela.plt") == 0)
                relplt = true;
 
@@ -1805,11 +1794,10 @@ sparc64_elf_size_dynamic_sections (output_bfd, info)
                                            sizeof (Elf64_External_Rela)))
        return false;
 
-      if (reltext)
+      if (info->flags & DF_TEXTREL)
        {
          if (! bfd_elf64_add_dynamic_entry (info, DT_TEXTREL, 0))
            return false;
-         info->flags |= DF_TEXTREL;
        }
 
       /* Add dynamic STT_REGISTER symbols and corresponding DT_SPARC_REGISTER
@@ -2909,6 +2897,23 @@ sparc64_elf_finish_dynamic_sections (output_bfd, info)
 
   return true;
 }
+
+static enum elf_reloc_type_class
+sparc64_elf_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_SPARC_RELATIVE:
+      return reloc_class_relative;
+    case R_SPARC_JMP_SLOT:
+      return reloc_class_plt;
+    case R_SPARC_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 \f
 /* Functions for dealing with the e_flags field.  */
 
@@ -3160,6 +3165,8 @@ const struct elf_size_info sparc64_elf_size_info =
   sparc64_elf_size_info
 #define elf_backend_object_p \
   sparc64_elf_object_p
+#define elf_backend_reloc_type_class \
+  sparc64_elf_reloc_type_class
 
 #define elf_backend_want_got_plt 0
 #define elf_backend_plt_readonly 0
index 1a6399bf6b7268b8c997d1f0cd99827365eb68dc..4428767a0ea7a33524b56d66c28b46e8a49ac2eb 100644 (file)
@@ -67,6 +67,12 @@ static boolean elf_link_size_reloc_section
 static void elf_link_adjust_relocs
   PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
           struct elf_link_hash_entry **));
+static int elf_link_sort_cmp1
+  PARAMS ((const void *, const void *));
+static int elf_link_sort_cmp2
+  PARAMS ((const void *, const void *));
+static size_t elf_link_sort_relocs
+  PARAMS ((bfd *, struct bfd_link_info *, asection **));
 
 /* Given an ELF BFD, add symbols to the global hash table as
    appropriate.  */
@@ -3065,6 +3071,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       asection *s;
       size_t bucketcount = 0;
       size_t hash_entry_size;
+      unsigned int dtagcount;
 
       /* Set up the version definition section.  */
       s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -3439,8 +3446,9 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
       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;
+      for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount)
+       if (! elf_add_dynamic_entry (info, DT_NULL, 0))
+         return false;
     }
 
   return true;
@@ -4270,6 +4278,210 @@ elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
   free (irela);
 }
 
+struct elf_link_sort_rela {
+  bfd_vma offset;
+  enum elf_reloc_type_class type;
+  union {
+    Elf_Internal_Rel rel;
+    Elf_Internal_Rela rela;
+  } u;
+};
+
+static int
+elf_link_sort_cmp1 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *)A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *)B;
+  int relativea, relativeb;
+
+  relativea = a->type == reloc_class_relative;
+  relativeb = b->type == reloc_class_relative;
+
+  if (relativea < relativeb)
+    return -1;
+  if (relativea > relativeb)
+    return 1;
+  if (ELF_R_SYM (a->u.rel.r_info) < ELF_R_SYM (b->u.rel.r_info))
+    return -1;
+  if (ELF_R_SYM (a->u.rel.r_info) > ELF_R_SYM (b->u.rel.r_info))
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static int
+elf_link_sort_cmp2 (A, B)
+     const PTR A;
+     const PTR B;
+{
+  struct elf_link_sort_rela *a = (struct elf_link_sort_rela *)A;
+  struct elf_link_sort_rela *b = (struct elf_link_sort_rela *)B;
+  int copya, copyb;
+
+  if (a->offset < b->offset)
+    return -1;
+  if (a->offset > b->offset)
+    return 1;
+  copya = a->type == reloc_class_copy;
+  copyb = b->type == reloc_class_copy;
+  if (copya < copyb)
+    return -1;
+  if (copya > copyb)
+    return 1;
+  if (a->u.rel.r_offset < b->u.rel.r_offset)
+    return -1;
+  if (a->u.rel.r_offset > b->u.rel.r_offset)
+    return 1;
+  return 0;
+}
+
+static size_t
+elf_link_sort_relocs (abfd, info, psec)
+     bfd *abfd;
+     struct bfd_link_info *info;
+     asection **psec;
+{
+  bfd *dynobj = elf_hash_table (info)->dynobj;
+  asection *reldyn, *o;
+  boolean rel = false;
+  size_t count, size, i, j, ret;
+  struct elf_link_sort_rela *rela;
+  struct elf_backend_data *bed = get_elf_backend_data (abfd);
+
+  reldyn = bfd_get_section_by_name (abfd, ".rela.dyn");
+  if (reldyn == NULL || reldyn->_raw_size == 0)
+    {
+      reldyn = bfd_get_section_by_name (abfd, ".rel.dyn");
+      if (reldyn == NULL || reldyn->_raw_size == 0)
+       return 0;
+      rel = true;
+      count = reldyn->_raw_size / sizeof (Elf_External_Rel);
+    }
+  else
+    count = reldyn->_raw_size / sizeof (Elf_External_Rela);
+
+  size = 0;
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+       == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+       && o->output_section == reldyn)
+      size += o->_raw_size;
+
+  if (size != reldyn->_raw_size)
+    return 0;
+
+  rela = (struct elf_link_sort_rela *) calloc (sizeof (*rela), count);
+  if (rela == NULL)
+    {
+      (*info->callbacks->warning)
+       (info, _("Not enough memory to sort relocations"), 0, abfd, 0, 0);
+      return 0;
+    }
+
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+       == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+       && o->output_section == reldyn)
+      {
+       if (rel)
+         {
+           Elf_External_Rel *erel, *erelend;
+           struct elf_link_sort_rela *s;
+
+           erel = (Elf_External_Rel *) o->contents;
+           erelend = (Elf_External_Rel *) ((PTR) o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rel);
+           for (; erel < erelend; erel++, s++)
+             {
+               if (bed->s->swap_reloc_in)
+                 (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, &s->u.rel);
+               else
+                 elf_swap_reloc_in (abfd, erel, &s->u.rel);
+
+               s->type = (*bed->elf_backend_reloc_type_class)
+                           (ELF_R_TYPE (s->u.rel.r_info));
+             }     
+         }
+       else
+         {
+           Elf_External_Rela *erela, *erelaend;
+           struct elf_link_sort_rela *s;
+
+           erela = (Elf_External_Rela *) o->contents;
+           erelaend = (Elf_External_Rela *) ((PTR) o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rela);
+           for (; erela < erelaend; erela++, s++)
+             {
+               if (bed->s->swap_reloca_in)
+                 (*bed->s->swap_reloca_in) (dynobj, (bfd_byte *) erela, &s->u.rela);
+               else
+                 elf_swap_reloca_in (dynobj, erela, &s->u.rela);
+
+               s->type = (*bed->elf_backend_reloc_type_class)
+                           (ELF_R_TYPE (s->u.rel.r_info));
+             }     
+         }
+      }
+
+  qsort (rela, count, sizeof (*rela), elf_link_sort_cmp1);
+  for (i = 0, j = 0; i < count && rela[i].type != reloc_class_relative; i++)
+    {
+      if (ELF_R_SYM (rela[i].u.rel.r_info) != ELF_R_SYM (rela[j].u.rel.r_info))
+       j = i;
+      rela[i].offset = rela[j].u.rel.r_offset;
+    }
+  ret = count - i;
+  qsort (rela, i, sizeof (*rela), elf_link_sort_cmp2);
+  
+  for (o = dynobj->sections; o != NULL; o = o->next)
+    if ((o->flags & (SEC_HAS_CONTENTS|SEC_LINKER_CREATED))
+       == (SEC_HAS_CONTENTS|SEC_LINKER_CREATED)
+       && o->output_section == reldyn)
+      {
+       if (rel)
+         {
+           Elf_External_Rel *erel, *erelend;
+           struct elf_link_sort_rela *s;
+
+           erel = (Elf_External_Rel *) o->contents;
+           erelend = (Elf_External_Rel *) ((PTR) o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rel);
+           for (; erel < erelend; erel++, s++)
+             {
+               if (bed->s->swap_reloc_out)
+                 (*bed->s->swap_reloc_out) (abfd, &s->u.rel, (bfd_byte *) erel);
+               else
+                 elf_swap_reloc_out (abfd, &s->u.rel, erel);
+             }
+         }
+       else
+         {
+           Elf_External_Rela *erela, *erelaend;
+           struct elf_link_sort_rela *s;
+
+           erela = (Elf_External_Rela *) o->contents;
+           erelaend = (Elf_External_Rela *) ((PTR) o->contents + o->_raw_size);
+           s = rela + o->output_offset / sizeof (Elf_External_Rela);
+           for (; erela < erelaend; erela++, s++)
+             {
+               if (bed->s->swap_reloca_out)
+                 (*bed->s->swap_reloca_out) (dynobj, &s->u.rela, (bfd_byte *) erela);
+               else
+                 elf_swap_reloca_out (dynobj, &s->u.rela, erela);
+             }     
+         }
+      }
+
+  free (rela);
+  *psec = reldyn;
+  return ret;
+}
+
 /* Do the final step of an ELF link.  */
 
 boolean
@@ -4296,6 +4508,8 @@ elf_bfd_final_link (abfd, info)
   struct elf_backend_data *bed = get_elf_backend_data (abfd);
   struct elf_outext_info eoinfo;
   boolean merged;
+  size_t relativecount = 0;
+  asection *reldyn = 0;
 
   if (info->shared)
     abfd->flags |= DYNAMIC;
@@ -4866,6 +5080,9 @@ elf_bfd_final_link (abfd, info)
       o->reloc_count = 0;
     }
 
+  if (dynamic && info->combreloc && dynobj != NULL)
+    relativecount = elf_link_sort_relocs (abfd, info, &reldyn);
+
   /* If we are linking against a dynamic object, or generating a
      shared library, finish up the dynamic linking information.  */
   if (dynamic)
@@ -4890,6 +5107,23 @@ elf_bfd_final_link (abfd, info)
            {
            default:
              break;
+           case DT_NULL:
+             if (relativecount > 0 && dyncon + 1 < dynconend)
+               {
+                 switch (elf_section_data (reldyn)->this_hdr.sh_type)
+                   {
+                   case SHT_REL: dyn.d_tag = DT_RELCOUNT; break;
+                   case SHT_RELA: dyn.d_tag = DT_RELACOUNT; break;
+                   default: break;
+                   }
+                 if (dyn.d_tag != DT_NULL)
+                   {
+                     dyn.d_un.d_val = relativecount;
+                     elf_swap_dyn_out (dynobj, &dyn, dyncon);
+                     relativecount = 0;
+                   }
+               }
+             break;
            case DT_INIT:
              name = info->init_function;
              goto get_sym;
index 8fdb9a07c91036667166dfe175eeb826a177c2ee..027361071693fcbc359cac5493e0eb852957382b 100644 (file)
@@ -138,6 +138,7 @@ struct elfNN_ia64_link_hash_table
   asection *rel_pltoff_sec;    /* dynamic relocation section for same */
 
   bfd_size_type minplt_entries;        /* number of minplt entries */
+  unsigned reltext : 1;                /* are there relocs against readonly sections? */
 
   struct elfNN_ia64_local_hash_table loc_hash_table;
 };
@@ -299,6 +300,8 @@ static boolean elfNN_ia64_merge_private_bfd_data
   PARAMS ((bfd *ibfd, bfd *obfd));
 static boolean elfNN_ia64_print_private_bfd_data
   PARAMS ((bfd *abfd, PTR ptr));
+static enum elf_reloc_type_class elfNN_ia64_reloc_type_class
+  PARAMS ((int));
 \f
 /* ia64-specific relocation */
 
@@ -1571,7 +1574,7 @@ elfNN_ia64_hash_table_create (abfd)
 {
   struct elfNN_ia64_link_hash_table *ret;
 
-  ret = bfd_alloc (abfd, sizeof (*ret));
+  ret = bfd_zalloc (abfd, sizeof (*ret));
   if (!ret)
     return 0;
   if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
@@ -1916,6 +1919,9 @@ get_reloc_section (abfd, ia64_info, sec, create)
        return NULL;
     }
 
+  if (sec->flags & SEC_READONLY)
+    ia64_info->reltext = 1;
+
   return srel;
 }
 
@@ -2535,7 +2541,6 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
   struct elfNN_ia64_link_hash_table *ia64_info;
   asection *sec;
   bfd *dynobj;
-  boolean reltext = false;
   boolean relplt = false;
 
   dynobj = elf_hash_table(info)->dynobj;
@@ -2692,24 +2697,6 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
            {
              if (!strip)
                {
-                 const char *outname;
-                 asection *target;
-
-                 /* If this relocation section applies to a read only
-                    section, then we probably need a DT_TEXTREL entry.  */
-                 outname = bfd_get_section_name (output_bfd,
-                                                 sec->output_section);
-                 if (outname[4] == 'a')
-                   outname += 5;
-                 else
-                   outname += 4;
-
-                 target = bfd_get_section_by_name (output_bfd, outname);
-                 if (target != NULL
-                     && (target->flags & SEC_READONLY) != 0
-                     && (target->flags & SEC_ALLOC) != 0)
-                   reltext = true;
-
                  /* We use the reloc_count field as a counter if we need to
                     copy relocs into the output file.  */
                  sec->reloc_count = 0;
@@ -2763,7 +2750,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info)
                                            sizeof (ElfNN_External_Rela)))
        return false;
 
-      if (reltext)
+      if (ia64_info->reltext)
        {
          if (! bfd_elfNN_add_dynamic_entry (info, DT_TEXTREL, 0))
            return false;
@@ -4324,6 +4311,27 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
   _bfd_elf_print_private_bfd_data (abfd, ptr);
   return true;
 }
+
+static enum elf_reloc_type_class
+elfNN_ia64_reloc_type_class (type)
+     int type;
+{
+  switch (type)
+    {
+    case R_IA64_REL32MSB:
+    case R_IA64_REL32LSB:
+    case R_IA64_REL64MSB:
+    case R_IA64_REL64LSB:
+      return reloc_class_relative;
+    case R_IA64_IPLTMSB:
+    case R_IA64_IPLTLSB:
+      return reloc_class_plt;
+    case R_IA64_COPY:
+      return reloc_class_copy;
+    default:
+      return reloc_class_normal;
+    }
+}
 \f
 #define TARGET_LITTLE_SYM              bfd_elfNN_ia64_little_vec
 #define TARGET_LITTLE_NAME             "elfNN-ia64-little"
@@ -4400,6 +4408,7 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr)
 #define elf_backend_want_dynbss                0
 #define elf_backend_copy_indirect_symbol elfNN_ia64_hash_copy_indirect
 #define elf_backend_hide_symbol                elfNN_ia64_hash_hide_symbol
+#define elf_backend_reloc_type_class   elfNN_ia64_reloc_type_class
 
 #include "elfNN-target.h"
 
index 6ba5b6e43f22d7af7425606319b0da97428d073c..a4c5e1d94bf66628e62b39b0c832fdda73460943 100644 (file)
@@ -339,6 +339,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #ifndef elf_backend_fprintf_vma
 #define elf_backend_fprintf_vma                        _bfd_elf_fprintf_vma
 #endif
+#ifndef elf_backend_reloc_type_class
+#define elf_backend_reloc_type_class           _bfd_elf_reloc_type_class
+#endif
 
 /* Previously, backends could only use SHT_REL or SHT_RELA relocation
    sections, but not both.  They defined USE_REL to indicate SHT_REL
@@ -426,6 +429,7 @@ static CONST struct elf_backend_data elfNN_bed =
   elf_backend_grok_psinfo,
   elf_backend_sprintf_vma,
   elf_backend_fprintf_vma,
+  elf_backend_reloc_type_class,
   elf_backend_ecoff_debug_swap,
   ELF_MACHINE_ALT1,
   ELF_MACHINE_ALT2,
index 8025966067bd16c90f32c8c0567ac52ca31044f5..55f85ad061ae451e652bbb38054a3f0056352cc4 100644 (file)
@@ -1,3 +1,8 @@
+2001-08-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * bfdlink.h (struct bfd_link_info): Add combreloc and
+       spare_dynamic_tags fields.
+
 2001-08-23  Lars Brinkhoff  <lars@nocrew.org>
 
        * dyn-string.h, fibheap.h, partition.h, sort.h, splay-tree.h:
index 56b1fe4586f7b3770377f0ffb0c5cb20a7471393..1dd2842382d15718836b5603bc41dba97233d068 100644 (file)
@@ -275,9 +275,16 @@ struct bfd_link_info
   /* May be used to set DT_FLAGS_1 for ELF. */
   bfd_vma flags_1;
 
-  /* true if auto-import thunks for DATA items in pei386 DLLs 
+  /* True if auto-import thunks for DATA items in pei386 DLLs 
      should be generated/linked against.  */
   boolean pei386_auto_import;
+
+  /* True if non-PLT relocs should be merged into one reloc section
+     and sorted so that relocs against the same symbol come together.  */
+  boolean combreloc;
+
+  /* How many spare .dynamic DT_NULL entries should be added?  */
+  int spare_dynamic_tags;
 };
 
 /* This structures holds a set of callback functions.  These are
index b4a130241917807191ed691850563f4332db2fb8..c29a986074e783019c10611374359df6c5e93394 100644 (file)
@@ -1,3 +1,27 @@
+2001-08-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * emultempl/elf32.em (place_orphan): Place orphan .rel* sections
+       into .rel.dyn resp. .rela.dyn if combreloc.
+       (get_script): If .x linker script is equal to .xn, only put it
+       once into the binary.
+       Add .xc and .xsc scripts.
+       (parse_args): Handle -z combreloc and -z nocombreloc.
+       * scripttempl/elf.sc (.rela.sbss): Fix a typo.
+       For .xc and .xsc scripts put all .rel* or .rela* input sections
+       but .rel*.plt and PLT-like sections into .rel.dyn resp. .rela.dyn.
+       * genscripts.sh (GENERATE_COMBRELOC_SCRIPT): Set if SCRIPT_NAME
+       is elf.
+       Strip trailing whitespace from script.
+       Generate .xc and .xsc scripts if requested.
+       * ldmain.c (main): Initialize link_info.combreloc and
+       link_info.spare_dynamic_tags.
+       * lexsup.c (OPTION_SPARE_DYNAMIC_TAGS): Define.
+       (ld_options): Add --spare-dynamic-tags option.
+       (parse_args): Likewise.
+       * ld.texinfo: Document -z combreloc and -z nocombreloc.
+       * ldint.texinfo: Document .xc and .xsc linker scripts.
+       * NEWS: Add notes about -z combreloc and SHF_MERGE.
+
 2001-08-22  H.J. Lu  <hjl@gnu.org>
 
        * emulparams/elf32fr30.sh: Add a newline.
diff --git a/ld/NEWS b/ld/NEWS
index f1e7ece2883363899d7ff1b2a4234a579a356c10..27dc89105fd5e356252fac215612a193607b77c3 100644 (file)
--- a/ld/NEWS
+++ b/ld/NEWS
@@ -1,5 +1,11 @@
 -*- text -*-
 
+* Support for -z combreloc in the ELF linker, which puts dynamic
+  relocations against the same symbol together, so that dynamic linker
+  can use an one-entry symbol lookup cache.
+
+* Support for ELF SHF_MERGE section merging, by Jakub Jelinek.
+
 * Support for AMD x86-64 architecture, by Jan Hubicka, SuSE Labs.
 
 * Support added for eliminating duplicate DWARF2 debug information by
index 93dc739535d2dfc55c528356858f506056dcbec3..0e5cd99676cba79a12f85e654604d4746773b87b 100644 (file)
@@ -1135,7 +1135,25 @@ gld${EMULATION_NAME}_place_orphan (file, s)
   else if (strncmp (secname, ".rel", 4) == 0
           && (hold_rel.os != NULL
               || (hold_rel.os = output_rel_find ()) != NULL))
-    place = &hold_rel;
+    {
+      if (! link_info.relocateable && link_info.combreloc)
+       {
+         if (strncmp (secname, ".rela", 5) == 0)
+           os = lang_output_section_find (".rela.dyn");
+         else
+           os = lang_output_section_find (".rel.dyn");
+
+         if (os != NULL
+             && os->bfd_section != NULL
+             && ((s->flags ^ os->bfd_section->flags)
+                 & (SEC_LOAD | SEC_ALLOC)) == 0)
+           {
+             lang_add_section (&os->children, s, os, file);
+             return true;
+           }
+       }
+      place = &hold_rel;
+    }
   else if ((s->flags & (SEC_CODE | SEC_READONLY)) == SEC_READONLY
           && HAVE_SECTION (hold_rodata, ".rodata"))
     place = &hold_rodata;
@@ -1332,14 +1350,18 @@ echo '  ; else if (link_info.relocateable == true) return' >> e${EMULATION_NAME}
 sed $sc ldscripts/${EMULATION_NAME}.xr                     >> e${EMULATION_NAME}.c
 echo '  ; else if (!config.text_read_only) return'         >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xbn                    >> e${EMULATION_NAME}.c
+if ! cmp -s ldscripts/${EMULATION_NAME}.x ldscripts/${EMULATION_NAME}.xn; then
 echo '  ; else if (!config.magic_demand_paged) return'     >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xn                     >> e${EMULATION_NAME}.c
-
+fi
 if test -n "$GENERATE_SHLIB_SCRIPT" ; then
+echo '  ; else if (link_info.shared && link_info.combreloc) return' >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xsc                    >> e${EMULATION_NAME}.c
 echo '  ; else if (link_info.shared) return'              >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.xs                     >> e${EMULATION_NAME}.c
 fi
-
+echo '  ; else if (link_info.combreloc) return'            >> e${EMULATION_NAME}.c
+sed $sc ldscripts/${EMULATION_NAME}.xc                     >> e${EMULATION_NAME}.c
 echo '  ; else return'                                     >> e${EMULATION_NAME}.c
 sed $sc ldscripts/${EMULATION_NAME}.x                      >> e${EMULATION_NAME}.c
 echo '; }'                                                 >> e${EMULATION_NAME}.c
@@ -1492,6 +1514,10 @@ cat >>e${EMULATION_NAME}.c <<EOF
        }
       else if (strcmp (optarg, "defs") == 0)
        link_info.no_undefined = true;
+      else if (strcmp (optarg, "combreloc") == 0)
+       link_info.combreloc = true;
+      else if (strcmp (optarg, "nocombreloc") == 0)
+       link_info.combreloc = false;
       /* What about the other Solaris -z options? FIXME.  */
       break;
 EOF
index d3ab768ae8f6d2bbe5a64ae30dfa0e46a4bc2a92..f1691328ad4c257227fbad22b469df1c64051107 100755 (executable)
@@ -84,6 +84,17 @@ LIB_SEARCH_DIRS=`echo ${LIB_PATH} | tr ':' ' ' | sed -e 's/\([^ ][^ ]*\)/SEARCH_
 # A .xs script is for generating a shared library with the --shared
 #   flag; it is only generated if $GENERATE_SHLIB_SCRIPT is set by the
 #   emulation parameters.
+# A .xc script is for linking with -z combreloc; it is only generated if
+#   $GENERATE_COMBRELOC_SCRIPT is set by the emulation parameters or
+#   $SCRIPT_NAME is "elf".
+# A .xsc script is for linking with --shared -z combreloc; it is generated
+#   if $GENERATE_COMBRELOC_SCRIPT is set by the emulation parameters or
+#   $SCRIPT_NAME is "elf" and $GENERATE_SHLIB_SCRIPT is set by the emulation
+#   parameters too.
+
+if [ "x$SCRIPT_NAME" = "xelf" ]; then
+  GENERATE_COMBRELOC_SCRIPT=yes
+fi
 
 SEGMENT_SIZE=${SEGMENT_SIZE-${TARGET_PAGE_SIZE}}
 
@@ -101,34 +112,45 @@ DATA_ALIGNMENT=${DATA_ALIGNMENT_r}
 DEFAULT_DATA_ALIGNMENT="ALIGN(${SEGMENT_SIZE})"
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xr
+) | sed -e '/^ *$/d;s/[        ]*$//' > ldscripts/${EMULATION_NAME}.xr
 
 LD_FLAG=u
 DATA_ALIGNMENT=${DATA_ALIGNMENT_u}
 CONSTRUCTING=" "
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xu
+) | sed -e '/^ *$/d;s/[        ]*$//' > ldscripts/${EMULATION_NAME}.xu
 
 LD_FLAG=
 DATA_ALIGNMENT=${DATA_ALIGNMENT_}
 RELOCATING=" "
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.x
+) | sed -e '/^ *$/d;s/[        ]*$//' > ldscripts/${EMULATION_NAME}.x
 
 LD_FLAG=n
 DATA_ALIGNMENT=${DATA_ALIGNMENT_n}
 TEXT_START_ADDR=${NONPAGED_TEXT_START_ADDR-${TEXT_START_ADDR}}
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xn
+) | sed -e '/^ *$/d;s/[        ]*$//' > ldscripts/${EMULATION_NAME}.xn
 
 LD_FLAG=N
 DATA_ALIGNMENT=${DATA_ALIGNMENT_N}
 ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
   . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xbn
+) | sed -e '/^ *$/d;s/[        ]*$//' > ldscripts/${EMULATION_NAME}.xbn
+
+if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
+  DATA_ALIGNMENT=${DATA_ALIGNMENT_c-${DATA_ALIGNMENT_}}
+  LD_FLAG=c
+  COMBRELOC=ldscripts/${EMULATION_NAME}.xc.tmp
+  ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
+    . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+  ) | sed -e '/^ *$/d;s/[      ]*$//' > ldscripts/${EMULATION_NAME}.xc
+  rm -f ${COMBRELOC}
+  COMBRELOC=
+fi
 
 if test -n "$GENERATE_SHLIB_SCRIPT"; then
   LD_FLAG=shared
@@ -137,7 +159,17 @@ if test -n "$GENERATE_SHLIB_SCRIPT"; then
   # Note that TEXT_START_ADDR is set to NONPAGED_TEXT_START_ADDR.
   ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
     . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
-  ) | sed -e '/^ *$/d' > ldscripts/${EMULATION_NAME}.xs
+  ) | sed -e '/^ *$/d;s/[      ]*$//' > ldscripts/${EMULATION_NAME}.xs
+  if test -n "$GENERATE_COMBRELOC_SCRIPT"; then
+    LD_FLAG=cshared
+    DATA_ALIGNMENT=${DATA_ALIGNMENT_sc-${DATA_ALIGNMENT}}
+    COMBRELOC=ldscripts/${EMULATION_NAME}.xc.tmp
+    ( . ${srcdir}/emulparams/${EMULATION_NAME}.sh
+      . ${srcdir}/scripttempl/${SCRIPT_NAME}.sc
+    ) | sed -e '/^ *$/d;s/[    ]*$//' > ldscripts/${EMULATION_NAME}.xsc
+    rm -f ${COMBRELOC}
+    COMBRELOC=
+  fi
 fi
 
 for i in $EMULATION_LIBPATH ; do
index 95785e036e9f17840aadf22ced420de347e23ba1..5bc0a30896f6ec4d796cd47d8723b11f6bd26353 100644 (file)
@@ -840,7 +840,8 @@ for Solaris compatibility.
 @item -z @var{keyword}
 The recognized keywords are @code{initfirst}, @code{interpose},
 @code{loadfltr}, @code{nodefaultlib}, @code{nodelete}, @code{nodlopen},
-@code{nodump}, @code{now} and @code{origin}. The other keywords are
+@code{nodump}, @code{now}, @code{origin}, @code{combreloc} and
+@code{nocombreloc}. The other keywords are
 ignored for Solaris compatibility. @code{initfirst} marks the object
 to be initialized first at runtime before any other objects.
 @code{interpose} marks the object that its symbol table interposes
@@ -854,6 +855,9 @@ of this object will ignore any default library search paths.
 @code{now} marks the object with the non-lazy runtime binding.
 @code{origin} marks the object may contain $ORIGIN.
 @code{defs} disallows undefined symbols.
+@code{combreloc} combines multiple reloc sections and sorts them
+to make dynamic symbol lookup caching possible.
+@code{nocombreloc} disables multiple reloc sections combining.
 
 @kindex -(
 @cindex groups of archives
index 47a98172137bd6686b11380c6c4c77965d6e4960..489750ac7f6a315abb4a51e2f50d09714953bc0e 100644 (file)
@@ -239,7 +239,7 @@ If @code{SCRIPT_NAME} is set to @var{script}, @code{genscripts.sh} will
 invoke @file{scripttempl/@var{script}.sc}.
 
 The @file{genscripts.sh} script will invoke the @file{scripttempl}
-script 5 or 6 times.  Each time it will set the shell variable
+script 5 to 8 times.  Each time it will set the shell variable
 @code{LD_FLAG} to a different value.  When the linker is run, the
 options used will direct it to select a particular script.  (Script
 selection is controlled by the @code{get_script} emulation entry point;
@@ -278,6 +278,22 @@ this value if @code{GENERATE_SHLIB_SCRIPT} is defined in the
 this script at the appropriate time, normally when the linker is invoked
 with the @code{-shared} option.  The output has an extension of
 @file{.xs}.
+@item c
+The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
+this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
+@file{emulparams} file or if @code{SCRIPT_NAME} is @code{elf}. The
+@file{emultempl} script must arrange to use this script at the appropriate
+time, normally when the linker is invoked with the @code{-z combreloc}
+option.  The output has an extension of
+@file{.xc}.
+@item cshared
+The @file{scripttempl} script is only invoked with @code{LD_FLAG} set to
+this value if @code{GENERATE_COMBRELOC_SCRIPT} is defined in the
+@file{emulparams} file or if @code{SCRIPT_NAME} is @code{elf} and
+@code{GENERATE_SHLIB_SCRIPT} is defined in the @file{emulparms} file.
+The @file{emultempl} script must arrange to use this script at the
+appropriate time, normally when the linker is invoked with the @code{-shared
+-z combreloc} option.  The output has an extension of @file{.xsc}.
 @end table
 
 Besides the shell variables set by the @file{emulparams} script, and the
@@ -301,6 +317,10 @@ page aligned, or to @samp{.} when generating the @code{-N} script.
 @item CREATE_SHLIB
 This will be set to a non-empty string when generating a @code{-shared}
 script.
+
+@item COMBRELOC
+This will be set to a non-empty string when generating @code{-z combreloc}
+scripts to a temporary file name which can be used during script generation.
 @end table
 
 The conventional way to write a @file{scripttempl} script is to first
index 0ec7891891c412e32b0c20da1d60590ef7346a37..b7114f9e63dcd0c3ee62a058ad8597c2d85aed75 100644 (file)
@@ -244,6 +244,8 @@ main (argc, argv)
   link_info.flags = (bfd_vma) 0;
   link_info.flags_1 = (bfd_vma) 0;
   link_info.pei386_auto_import = false;
+  link_info.combreloc = false;
+  link_info.spare_dynamic_tags = 5;
 
   ldfile_add_arch ("");
 
index 7e23a7d07b6ddf9106cff1185c8bac7708528157..5183b86e71d8e4be52e944589e4dae64d6cadfa2 100644 (file)
@@ -131,6 +131,7 @@ int parsing_defsym = 0;
 #define OPTION_TARGET_HELP              (OPTION_UNIQUE + 1)
 #define OPTION_ALLOW_SHLIB_UNDEFINED   (OPTION_TARGET_HELP + 1)
 #define OPTION_DISCARD_NONE            (OPTION_ALLOW_SHLIB_UNDEFINED + 1)
+#define OPTION_SPARE_DYNAMIC_TAGS      (OPTION_DISCARD_NONE + 1)
 
 /* The long options.  This structure is used for both the option
    parsing and the help text.  */
@@ -347,6 +348,8 @@ static const struct ld_option ld_options[] =
       '\0', NULL, N_("Sort common symbols by size"), TWO_DASHES },
   { {"sort_common", no_argument, NULL, OPTION_SORT_COMMON},
       '\0', NULL, NULL, NO_HELP },
+  { {"spare-dynamic-tags", required_argument, NULL, OPTION_SPARE_DYNAMIC_TAGS},
+      '\0', N_("COUNT"), N_("How many tags to reserve in .dynamic section"), TWO_DASHES },
   { {"split-by-file", optional_argument, NULL, OPTION_SPLIT_BY_FILE},
       '\0', N_("[=SIZE]"), N_("Split output sections every SIZE octets"), TWO_DASHES },
   { {"split-by-reloc", optional_argument, NULL, OPTION_SPLIT_BY_RELOC},
@@ -1073,6 +1076,9 @@ the GNU General Public License.  This program has absolutely no warranty.\n"));
        case 'y':
          add_ysym (optarg);
          break;
+       case OPTION_SPARE_DYNAMIC_TAGS:
+         link_info.spare_dynamic_tags = strtoul (optarg, NULL, 0);
+         break;
        case OPTION_SPLIT_BY_RELOC:
          if (optarg != NULL)
            config.split_by_reloc = strtoul (optarg, NULL, 0);
index 84630bd21f5c2c559f7d683a3ed1d0dfe6c2cdec..8ccf8038655b3345e3639a8604c04cb60c3493b1 100644 (file)
@@ -145,6 +145,13 @@ SECTIONS
   .gnu.version_d ${RELOCATING-0} : { *(.gnu.version_d) }
   .gnu.version_r ${RELOCATING-0} : { *(.gnu.version_r) }
 
+EOF
+if [ "x$COMBRELOC" = x ]; then
+  COMBRELOCCAT=cat
+else
+  COMBRELOCCAT="cat > $COMBRELOC"
+fi
+eval $COMBRELOCCAT <<EOF
   .rel.init    ${RELOCATING-0} : { *(.rel.init)        }
   .rela.init   ${RELOCATING-0} : { *(.rela.init)       }
   .rel.text    ${RELOCATING-0} :
@@ -215,7 +222,7 @@ SECTIONS
     {
       *(.rela.sbss)
       ${RELOCATING+*(.rela.sbss.*)}
-      ${RELOCATING+*(.rel.gnu.linkonce.sb.*)}
+      ${RELOCATING+*(.rela.gnu.linkonce.sb.*)}
     }
   .rel.sdata2  ${RELOCATING-0} : 
     { 
@@ -253,6 +260,24 @@ SECTIONS
       ${RELOCATING+*(.rela.bss.*)}
       ${RELOCATING+*(.rela.gnu.linkonce.b.*)}
     }
+EOF
+if [ -n "$COMBRELOC" ]; then
+cat <<EOF
+  .rel.dyn      :
+    {
+EOF
+sed -e '/^[    ]*[{}][         ]*$/d;/:[       ]*$/d;/\.rela\./d;s/^.*: { *\(.*\)}$/      \1/' $COMBRELOC
+cat <<EOF
+    }
+  .rela.dyn     :
+    {
+EOF
+sed -e '/^[    ]*[{}][         ]*$/d;/:[       ]*$/d;/\.rel\./d;s/^.*: { *\(.*\)}/      \1/' $COMBRELOC
+cat <<EOF
+    }
+EOF
+fi
+cat <<EOF
   .rel.plt     ${RELOCATING-0} : { *(.rel.plt)         }
   .rela.plt    ${RELOCATING-0} : { *(.rela.plt)                }
   ${OTHER_PLT_RELOC_SECTIONS}