]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Skip libdw reloc sorting when superfluous.
authorRoland McGrath <roland@redhat.com>
Wed, 30 Jun 2010 23:02:23 +0000 (16:02 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 30 Jun 2010 23:21:32 +0000 (16:21 -0700)
libdw/ChangeLog
libdw/relocate.c

index 113ba7a84387fbc2928e3219aef8967a4984aba5..21dd1c6dd55d59a6a4407b4ad3dd3e433d8bed9c 100644 (file)
@@ -1,5 +1,8 @@
 2010-06-30  Roland McGrath  <roland@redhat.com>
 
+       * relocate.c (digest_one_reloc, digest_relocs): Track r_offset values
+       and don't bother sorting if they were already sorted.
+
        * relocate.c (digest_relocs, compare_digested_reloc): Use qsort on an
        array of pointers, not structs.
 
index ae4211a5e90df65cf468a591aafce6c5efcceaf7..a29797e8632407534330b02b5c13b639e8687f9a 100644 (file)
@@ -124,7 +124,7 @@ match_r_type (const int *types, int r_type)
 static inline int
 digest_one_reloc (const int *rel8_types, const int *rel4_types,
                  struct dwarf_section_reloc *r, Elf_Data *data,
-                 struct digested_reloc **digest,
+                 GElf_Addr *sorted, struct digested_reloc **digest,
                  GElf_Addr r_offset, GElf_Xword r_info, GElf_Sxword r_addend)
 {
   const int r_type = GELF_R_TYPE (r_info);
@@ -208,6 +208,12 @@ digest_one_reloc (const int *rel8_types, const int *rel4_types,
       (*digest)->addend = r_addend;
       ++*digest;
       ++*nrel;
+
+      /* Record the largest offset yet seen, or -1 if we moved backwards.  */
+      if (r_offset < *sorted)
+       *sorted = -1;
+      else
+       *sorted = r_offset;
     }
 
   return 0;
@@ -266,6 +272,8 @@ digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
 
   r->rel4.n = r->rel8.n = 0;
 
+  GElf_Addr sorted = 0;
+
   int ret = 0;
   if (shdr.sh_type == SHT_RELA)
     for (size_t i = 0; i < nrel && !ret; ++i)
@@ -273,7 +281,7 @@ digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
        GElf_Rela rela;
        if (unlikely (gelf_getrela (reldata, i, &rela) == NULL))
          assert (!"impossible gelf_getrela failure");
-       ret = digest_one_reloc (rel8_types, rel4_types, r, data, &d,
+       ret = digest_one_reloc (rel8_types, rel4_types, r, data, &sorted, &d,
                                rela.r_offset, rela.r_info, rela.r_addend);
       }
   else
@@ -282,7 +290,7 @@ digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
        GElf_Rel rel;
        if (unlikely (gelf_getrel (reldata, i, &rel) == NULL))
          assert (!"impossible gelf_getrel failure");
-       ret = digest_one_reloc (rel8_types, rel4_types, r, data, &d,
+       ret = digest_one_reloc (rel8_types, rel4_types, r, data, &sorted, &d,
                                rel.r_offset, rel.r_info, 0);
       }
 
@@ -291,17 +299,6 @@ digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
   if (ret)
     return ret;
 
-  /* qsort is much faster when it only copies pointers.
-     So make another array of pointers for the sorting.  */
-
-  struct digested_reloc *sort_digest[d - digest];
-  for (size_t i = 0; i < (size_t) (d - digest); ++i)
-    sort_digest[i] = &digest[i];
-
-  /* Sort by datum address.  */
-  qsort (sort_digest, d - digest, sizeof sort_digest[0],
-        &compare_digested_reloc);
-
   if (r->rel8.n > 0)
     {
       r->rel8.datum = libdw_alloc (dbg, const unsigned char *,
@@ -331,26 +328,49 @@ digest_relocs (Dwarf *dbg, Elf_Data *data, struct dwarf_section_reloc *r)
   size_t n8 = 0;
   size_t n4 = 0;
 
-  for (size_t i = 0; i < (size_t) (d - digest); ++i)
+  inline void reify_reloc (struct digested_reloc *dr)
+  {
+    if (dr->rel8)
+      {
+       r->rel8.datum[n8] = dr->datum;
+       r->rel8.symndx[n8] = dr->symndx;
+       if (shdr.sh_type == SHT_RELA)
+         r->rela8[n8] = dr->addend;
+       ++n8;
+      }
+    else
+      {
+       r->rel4.datum[n4] = dr->datum;
+       r->rel4.symndx[n4] = dr->symndx;
+       if (shdr.sh_type == SHT_RELA)
+         r->rela4[n4] = dr->addend;
+       ++n4;
+      }
+  }
+
+  if (sorted != (GElf_Addr) -1)
     {
-      struct digested_reloc *dr = sort_digest[i];
-      if (dr->rel8)
-       {
-         r->rel8.datum[n8] = dr->datum;
-         r->rel8.symndx[n8] = dr->symndx;
-         if (shdr.sh_type == SHT_RELA)
-           r->rela8[n8] = dr->addend;
-         ++n8;
-       }
-      else
-       {
-         r->rel4.datum[n4] = dr->datum;
-         r->rel4.symndx[n4] = dr->symndx;
-         if (shdr.sh_type == SHT_RELA)
-           r->rela4[n4] = dr->addend;
-         ++n4;
-       }
+      /* The records were already sorted in the file.  */
+      for (struct digested_reloc *dr = digest; dr < d; ++dr)
+       reify_reloc (dr);
     }
+  else
+    {
+      /* qsort is much faster when it only copies pointers.
+        So make another array of pointers for the sorting.  */
+
+      struct digested_reloc *sort_digest[d - digest];
+      for (size_t i = 0; i < (size_t) (d - digest); ++i)
+       sort_digest[i] = &digest[i];
+
+      /* Sort by datum address.  */
+      qsort (sort_digest, d - digest, sizeof sort_digest[0],
+            &compare_digested_reloc);
+
+      for (size_t i = 0; i < (size_t) (d - digest); ++i)
+       reify_reloc (sort_digest[i]);
+    }
+
   assert (n8 == r->rel8.n);
   assert (n4 == r->rel4.n);