Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 78191 Details for
Bug 114008
-Wl,-Bdirect speed-up ...
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
binutils-gentoo-dynsort.diff
binutils-gentoo-dynsort.diff (text/plain), 32.20 KB, created by
Alexey Maximov
on 2006-01-26 10:00:03 UTC
(
hide
)
Description:
binutils-gentoo-dynsort.diff
Filename:
MIME Type:
Creator:
Alexey Maximov
Created:
2006-01-26 10:00:03 UTC
Size:
32.20 KB
patch
obsolete
>diff -ruN binutils-2.16.91.0.5.orig/bfd/bfdsort.c binutils-2.16.91.0.5/bfd/bfdsort.c >--- binutils-2.16.91.0.5.orig/bfd/bfdsort.c 1970-01-01 07:00:00.000000000 +0700 >+++ binutils-2.16.91.0.5/bfd/bfdsort.c 2006-01-26 23:33:48.055803597 +0600 >@@ -0,0 +1,252 @@ >+/* >+ * This module copied from glibc/stdlib/qsort.c & adapted, >+ * in order to add support for a closure argument. >+ */ >+ >+/* Copyright (C) 1991,1992,1996,1997,1999,2004 Free Software Foundation, Inc. >+ This file is part of the GNU C Library. >+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu). >+ >+ The GNU C Library is free software; you can redistribute it and/or >+ modify it under the terms of the GNU Lesser General Public >+ License as published by the Free Software Foundation; either >+ version 2.1 of the License, or (at your option) any later version. >+ >+ The GNU C Library is distributed in the hope that it will be useful, >+ but WITHOUT ANY WARRANTY; without even the implied warranty of >+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU >+ Lesser General Public License for more details. >+ >+ You should have received a copy of the GNU Lesser General Public >+ License along with the GNU C Library; if not, write to the Free >+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA >+ 02111-1307 USA. */ >+ >+/* If you consider tuning this algorithm, you should consult first: >+ Engineering a sort function; Jon Bentley and M. Douglas McIlroy; >+ Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */ >+ >+#include "sysdep.h" >+ >+/* Byte-wise swap two items of size SIZE. */ >+#define SWAP(a, b, size) \ >+ do \ >+ { \ >+ register bfd_size_type __size = (size); \ >+ register char *__a = (a), *__b = (b); \ >+ do \ >+ { \ >+ char __tmp = *__a; \ >+ *__a++ = *__b; \ >+ *__b++ = __tmp; \ >+ } while (--__size > 0); \ >+ } while (0) >+ >+/* Discontinue quicksort algorithm when partition gets below this size. >+ This particular magic number was chosen to work best on a Sun 4/260. */ >+#define MAX_THRESH 4 >+ >+/* Stack node declarations used to store unfulfilled partition obligations. */ >+typedef struct >+ { >+ char *lo; >+ char *hi; >+ } stack_node; >+ >+/* The next 4 #defines implement a very fast in-line stack abstraction. */ >+/* The stack needs log (total_elements) entries (we could even subtract >+ log(MAX_THRESH)). Since total_elements has type size_t, we get as >+ upper bound for log (total_elements): >+ bits per byte (CHAR_BIT) * sizeof(size_t). */ >+#define STACK_SIZE (8 * sizeof(bfd_size_type)) >+#define PUSH(low, high) do { top->lo = (low); top->hi = (high); ++top; } while (0) >+#define POP(low, high) do { --top; low = top->lo; high = top->hi; } while (0) >+#define STACK_NOT_EMPTY (stack < top) >+ >+ >+/* Order size using quicksort. This implementation incorporates >+ four optimizations discussed in Sedgewick: >+ >+ 1. Non-recursive, using an explicit stack of pointer that store the >+ next array partition to sort. To save time, this maximum amount >+ of space required to store an array of SIZE_MAX is allocated on the >+ stack. Assuming a 32-bit (64 bit) integer for size_t, this needs >+ only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes). >+ Pretty cheap, actually. >+ >+ 2. Chose the pivot element using a median-of-three decision tree. >+ This reduces the probability of selecting a bad pivot value and >+ eliminates certain extraneous comparisons. >+ >+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving >+ insertion sort to order the MAX_THRESH items within each partition. >+ This is a big win, since insertion sort is faster for small, mostly >+ sorted array segments. >+ >+ 4. The larger of the two sub-partitions is always pushed onto the >+ stack first, with the algorithm then concentrating on the >+ smaller partition. This *guarantees* no more than log (total_elems) >+ stack size is needed (actually O(1) in this case)! */ >+ >+void >+bfd_qsort (void *pbase, bfd_size_type total_elems, bfd_size_type size, >+ bfd_qsort_closure_func cmp, void *closure) >+{ >+ register char *base_ptr = (char *) pbase; >+ >+ const bfd_size_type max_thresh = MAX_THRESH * size; >+ >+ if (total_elems == 0) >+ /* Avoid lossage with unsigned arithmetic below. */ >+ return; >+ >+ if (total_elems > MAX_THRESH) >+ { >+ char *lo = base_ptr; >+ char *hi = &lo[size * (total_elems - 1)]; >+ stack_node stack[STACK_SIZE]; >+ stack_node *top = stack; >+ >+ PUSH (NULL, NULL); >+ >+ while (STACK_NOT_EMPTY) >+ { >+ char *left_ptr; >+ char *right_ptr; >+ >+ /* Select median value from among LO, MID, and HI. Rearrange >+ LO and HI so the three values are sorted. This lowers the >+ probability of picking a pathological pivot value and >+ skips a comparison for both the LEFT_PTR and RIGHT_PTR in >+ the while loops. */ >+ >+ char *mid = lo + size * ((hi - lo) / size >> 1); >+ >+ if ((*cmp) ((void *) mid, (void *) lo, closure) < 0) >+ SWAP (mid, lo, size); >+ if ((*cmp) ((void *) hi, (void *) mid, closure) < 0) >+ SWAP (mid, hi, size); >+ else >+ goto jump_over; >+ if ((*cmp) ((void *) mid, (void *) lo, closure) < 0) >+ SWAP (mid, lo, size); >+ jump_over:; >+ >+ left_ptr = lo + size; >+ right_ptr = hi - size; >+ >+ /* Here's the famous ``collapse the walls'' section of quicksort. >+ Gotta like those tight inner loops! They are the main reason >+ that this algorithm runs much faster than others. */ >+ do >+ { >+ while ((*cmp) ((void *) left_ptr, (void *) mid, closure) < 0) >+ left_ptr += size; >+ >+ while ((*cmp) ((void *) mid, (void *) right_ptr, closure) < 0) >+ right_ptr -= size; >+ >+ if (left_ptr < right_ptr) >+ { >+ SWAP (left_ptr, right_ptr, size); >+ if (mid == left_ptr) >+ mid = right_ptr; >+ else if (mid == right_ptr) >+ mid = left_ptr; >+ left_ptr += size; >+ right_ptr -= size; >+ } >+ else if (left_ptr == right_ptr) >+ { >+ left_ptr += size; >+ right_ptr -= size; >+ break; >+ } >+ } >+ while (left_ptr <= right_ptr); >+ >+ /* Set up pointers for next iteration. First determine whether >+ left and right partitions are below the threshold size. If so, >+ ignore one or both. Otherwise, push the larger partition's >+ bounds on the stack and continue sorting the smaller one. */ >+ >+ if ((bfd_size_type) (right_ptr - lo) <= max_thresh) >+ { >+ if ((bfd_size_type) (hi - left_ptr) <= max_thresh) >+ /* Ignore both small partitions. */ >+ POP (lo, hi); >+ else >+ /* Ignore small left partition. */ >+ lo = left_ptr; >+ } >+ else if ((bfd_size_type) (hi - left_ptr) <= max_thresh) >+ /* Ignore small right partition. */ >+ hi = right_ptr; >+ else if ((right_ptr - lo) > (hi - left_ptr)) >+ { >+ /* Push larger left partition indices. */ >+ PUSH (lo, right_ptr); >+ lo = left_ptr; >+ } >+ else >+ { >+ /* Push larger right partition indices. */ >+ PUSH (left_ptr, hi); >+ hi = right_ptr; >+ } >+ } >+ } >+ >+ /* Once the BASE_PTR array is partially sorted by quicksort the rest >+ is completely sorted using insertion sort, since this is efficient >+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning >+ of the array to sort, and END_PTR points at the very last element in >+ the array (*not* one beyond it!). */ >+ >+#define min(x, y) ((x) < (y) ? (x) : (y)) >+ >+ { >+ char *const end_ptr = &base_ptr[size * (total_elems - 1)]; >+ char *tmp_ptr = base_ptr; >+ char *thresh = min(end_ptr, base_ptr + max_thresh); >+ register char *run_ptr; >+ >+ /* Find smallest element in first threshold and place it at the >+ array's beginning. This is the smallest array element, >+ and the operation speeds up insertion sort's inner loop. */ >+ >+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size) >+ if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, closure) < 0) >+ tmp_ptr = run_ptr; >+ >+ if (tmp_ptr != base_ptr) >+ SWAP (tmp_ptr, base_ptr, size); >+ >+ /* Insertion sort, running from left-hand-side up to right-hand-side. */ >+ >+ run_ptr = base_ptr + size; >+ while ((run_ptr += size) <= end_ptr) >+ { >+ tmp_ptr = run_ptr - size; >+ while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, closure) < 0) >+ tmp_ptr -= size; >+ >+ tmp_ptr += size; >+ if (tmp_ptr != run_ptr) >+ { >+ char *trav; >+ >+ trav = run_ptr + size; >+ while (--trav >= run_ptr) >+ { >+ char c = *trav; >+ char *hi, *lo; >+ >+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo) >+ *hi = *lo; >+ *hi = c; >+ } >+ } >+ } >+ } >+} >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf32-hppa.c binutils-2.16.91.0.5/bfd/elf32-hppa.c >--- binutils-2.16.91.0.5.orig/bfd/elf32-hppa.c 2005-11-13 23:16:34.000000000 +0600 >+++ binutils-2.16.91.0.5/bfd/elf32-hppa.c 2006-01-26 23:33:47.784868762 +0600 >@@ -435,7 +435,7 @@ > = (struct elf32_hppa_link_hash_table *) btab; > > bfd_hash_table_free (&htab->bstab); >- _bfd_generic_link_hash_table_free (btab); >+ _bfd_elf_link_hash_table_free (hash); > } > > /* Build a name for an entry in the stub hash table. */ >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf32-m68hc1x.c binutils-2.16.91.0.5/bfd/elf32-m68hc1x.c >--- binutils-2.16.91.0.5.orig/bfd/elf32-m68hc1x.c 2005-06-23 03:53:34.000000000 +0700 >+++ binutils-2.16.91.0.5/bfd/elf32-m68hc1x.c 2006-01-26 23:33:47.802864434 +0600 >@@ -106,7 +106,7 @@ > > bfd_hash_table_free (ret->stub_hash_table); > free (ret->stub_hash_table); >- _bfd_generic_link_hash_table_free (hash); >+ _bfd_elf_link_hash_table_free (hash); > } > > /* Assorted hash table functions. */ >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf64-ppc.c binutils-2.16.91.0.5/bfd/elf64-ppc.c >--- binutils-2.16.91.0.5.orig/bfd/elf64-ppc.c 2006-01-26 23:29:41.000000000 +0600 >+++ binutils-2.16.91.0.5/bfd/elf64-ppc.c 2006-01-26 23:33:47.833856979 +0600 >@@ -3502,7 +3502,7 @@ > > bfd_hash_table_free (&ret->stub_hash_table); > bfd_hash_table_free (&ret->branch_hash_table); >- _bfd_generic_link_hash_table_free (hash); >+ _bfd_elf_link_hash_table_free (hash); > } > > /* Satisfy the ELF linker by filling in some fields in our fake bfd. */ >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf-bfd.h binutils-2.16.91.0.5/bfd/elf-bfd.h >--- binutils-2.16.91.0.5.orig/bfd/elf-bfd.h 2006-01-26 23:29:42.000000000 +0600 >+++ binutils-2.16.91.0.5/bfd/elf-bfd.h 2006-01-26 23:33:47.836856258 +0600 >@@ -346,6 +346,10 @@ > { > struct bfd_link_hash_table root; > >+ /* Symbol sort order for final traversal at output */ >+ unsigned int sorted_size; >+ struct elf_link_hash_entry **sorted; >+ > /* Whether we have created the special dynamic sections required > when linking against or generating a shared object. */ > bfd_boolean dynamic_sections_created; >@@ -427,11 +431,16 @@ > /* Traverse an ELF linker hash table. */ > > #define elf_link_hash_traverse(table, func, info) \ >- (bfd_link_hash_traverse \ >- (&(table)->root, \ >- (bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ >+ (_bfd_elf_link_hash_traverse \ >+ ((table), \ >+ (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func), \ > (info))) > >+void _bfd_elf_link_hash_traverse >+ (struct elf_link_hash_table *table, >+ bfd_boolean (*func) (struct elf_link_hash_entry *, void *), >+ void *info); >+ > /* Get the ELF linker hash table from a link_info structure. */ > > #define elf_hash_table(p) ((struct elf_link_hash_table *) ((p)->hash)) >@@ -1460,6 +1469,8 @@ > > extern unsigned long bfd_elf_hash > (const char *); >+extern unsigned long _bfd_elf_ver_hash >+ (const char *); > > extern bfd_reloc_status_type bfd_elf_generic_reloc > (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); >@@ -1477,6 +1488,7 @@ > (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); > extern struct bfd_link_hash_table *_bfd_elf_link_hash_table_create > (bfd *); >+extern void _bfd_elf_link_hash_table_free (struct bfd_link_hash_table *); > extern void _bfd_elf_link_hash_copy_indirect > (struct bfd_link_info *, struct elf_link_hash_entry *, > struct elf_link_hash_entry *); >@@ -1605,7 +1617,7 @@ > extern bfd_boolean _bfd_elf_strtab_emit > (bfd *, struct elf_strtab_hash *); > extern void _bfd_elf_strtab_finalize >- (struct elf_strtab_hash *); >+ (struct elf_strtab_hash *, size_t); > > extern bfd_boolean _bfd_elf_discard_section_eh_frame > (bfd *, struct bfd_link_info *, asection *, >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf.c binutils-2.16.91.0.5/bfd/elf.c >--- binutils-2.16.91.0.5.orig/bfd/elf.c 2006-01-26 23:29:42.000000000 +0600 >+++ binutils-2.16.91.0.5/bfd/elf.c 2006-01-26 23:33:47.890843273 +0600 >@@ -1579,6 +1579,8 @@ > table->direct_sec = NULL; > table->loaded = NULL; > table->is_relocatable_executable = FALSE; >+ table->sorted = NULL; >+ table->sorted_size = 0; > > ret = _bfd_link_hash_table_init (&table->root, abfd, newfunc); > table->root.type = bfd_link_elf_hash_table; >@@ -1607,6 +1609,15 @@ > return &ret->root; > } > >+void >+_bfd_elf_link_hash_table_free (struct bfd_link_hash_table *hash) >+{ >+ struct elf_link_hash_table *table = (struct elf_link_hash_table *) hash; >+ if (table->sorted) >+ free (table->sorted); >+ _bfd_generic_link_hash_table_free (hash); >+} >+ > /* This is a hook for the ELF emulation code in the generic linker to > tell the backend linker what file name to use for the DT_NEEDED > entry for a dynamic object. */ >@@ -3005,7 +3016,7 @@ > _bfd_elf_strtab_addref (elf_shstrtab (abfd), t->strtab_hdr.sh_name); > } > >- _bfd_elf_strtab_finalize (elf_shstrtab (abfd)); >+ _bfd_elf_strtab_finalize (elf_shstrtab (abfd), 0); > t->shstrtab_hdr.sh_size = _bfd_elf_strtab_size (elf_shstrtab (abfd)); > > elf_numsections (abfd) = section_number; >diff -ruN binutils-2.16.91.0.5.orig/bfd/elflink.c binutils-2.16.91.0.5/bfd/elflink.c >--- binutils-2.16.91.0.5.orig/bfd/elflink.c 2006-01-26 23:29:43.000000000 +0600 >+++ binutils-2.16.91.0.5/bfd/elflink.c 2006-01-26 23:33:47.957827162 +0600 >@@ -3021,7 +3021,8 @@ > const struct elf_backend_data *bed; > bfd_byte *extdyn; > >- _bfd_elf_strtab_finalize (dynstr); >+ _bfd_elf_strtab_finalize (dynstr, info->dynsort ? >+ elf_hash_table (info)->bucketcount : 0); > size = _bfd_elf_strtab_size (dynstr); > > bed = get_elf_backend_data (dynobj); >@@ -4777,27 +4778,17 @@ > return FALSE; > } > } >- >-/* This function will be called though elf_link_hash_traverse to store >- all hash value of the exported symbols in an array. */ > >-static bfd_boolean >-elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data) >+/* >+ * Compute the elf hash value of the name ignoring the version. >+ */ >+unsigned long >+_bfd_elf_ver_hash (const char *name) > { >- unsigned long **valuep = data; >- const char *name; > char *p; > unsigned long ha; > char *alc = NULL; > >- if (h->root.type == bfd_link_hash_warning) >- h = (struct elf_link_hash_entry *) h->root.u.i.link; >- >- /* Ignore indirect symbols. These are added by the versioning code. */ >- if (h->dynindx == -1) >- return TRUE; >- >- name = h->root.root.string; > p = strchr (name, ELF_VER_CHR); > if (p != NULL) > { >@@ -4810,6 +4801,31 @@ > /* Compute the hash value. */ > ha = bfd_elf_hash (name); > >+ if (alc != NULL) >+ free (alc); >+ >+ return ha; >+} >+ >+ >+/* This function will be called though elf_link_hash_traverse to store >+ all hash value of the exported symbols in an array. */ >+ >+static bfd_boolean >+elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data) >+{ >+ unsigned long **valuep = data; >+ unsigned long ha; >+ >+ if (h->root.type == bfd_link_hash_warning) >+ h = (struct elf_link_hash_entry *) h->root.u.i.link; >+ >+ /* Ignore indirect symbols. These are added by the versioning code. */ >+ if (h->dynindx == -1) >+ return TRUE; >+ >+ ha = _bfd_elf_ver_hash (h->root.root.string); >+ > /* Store the found hash value in the array given as the argument. */ > *(*valuep)++ = ha; > >@@ -4817,9 +4833,6 @@ > later. */ > h->u.elf_hash_value = ha; > >- if (alc != NULL) >- free (alc); >- > return TRUE; > } > >@@ -4982,6 +4995,131 @@ > return best_size; > } > >+void _bfd_elf_link_hash_traverse >+ (struct elf_link_hash_table *table, >+ bfd_boolean (*func) (struct elf_link_hash_entry *, void *), >+ void *info) >+{ >+ if (!table->sorted) >+ bfd_link_hash_traverse \ >+ (&(table)->root, \ >+ (bfd_boolean (*) (struct bfd_link_hash_entry *, void *)) (func), \ >+ (info)); >+ else >+ { >+ unsigned int i; >+ for (i = 0; i < table->sorted_size; i++) >+ { >+ if (! func (table->sorted[i], info)) >+ return; >+ } >+ } >+} >+ >+/* Sort by elf hash value % buckets */ >+static int >+elf_sort_dynsym_hash (const void *arg1, const void *arg2, const void *closure) >+{ >+ size_t h1_bucket, h2_bucket; >+ const struct elf_link_hash_entry *h1; >+ const struct elf_link_hash_entry *h2; >+ const bfd_size_type *bucketcount; >+ >+ h1 = *(const struct elf_link_hash_entry **) arg1; >+ h2 = *(const struct elf_link_hash_entry **) arg2; >+ bucketcount = closure; >+ >+ h1_bucket = h1->u.elf_hash_value % *bucketcount; >+ h2_bucket = h2->u.elf_hash_value % *bucketcount; >+ >+ if (h1_bucket > h2_bucket) >+ return 1; >+ if (h1_bucket < h2_bucket) >+ return -1; >+ >+ return 0; >+} >+ >+struct elf_dynsym_sort_info >+{ >+ bfd_boolean do_dynsym; >+ unsigned int alloc_size; >+ unsigned int sorted_size; >+ struct elf_link_hash_entry **sorted_syms; >+}; >+ >+/* collect sym entries into an array for later sorting */ >+static bfd_boolean >+elf_sort_collect_dynsyms (struct elf_link_hash_entry *h, void *data) >+{ >+ struct elf_dynsym_sort_info *sinfo = data; >+ >+ if ((sinfo->do_dynsym && h->dynindx < 0) || >+ (!sinfo->do_dynsym && h->dynindx >= 0)) >+ return TRUE; >+ >+ if (sinfo->sorted_size >= sinfo->alloc_size) >+ { >+ sinfo->alloc_size *= 2; >+ /* FIXME: need to free this data too ... */ >+ sinfo->sorted_syms = bfd_realloc (sinfo->sorted_syms, >+ sizeof (struct elf_link_hash_entry *) * >+ sinfo->alloc_size); >+ } >+ sinfo->sorted_syms [sinfo->sorted_size++] = h; >+ >+ return TRUE; >+} >+ >+ /* Nasty hack to avoid re-running autoconf / touching generated headers */ >+ >+typedef int(*bfd_qsort_closure_func)(const void *, const void *, const void *); >+extern void bfd_qsort (void *base, bfd_size_type nmemb, bfd_size_type size, >+ bfd_qsort_closure_func cmp, void *closure); >+ >+#include "bfdsort.c" >+ >+/* >+ * Sort the exported elf symbols by elf_hash % bucketcount to >+ * improve run-time linker cache behavior. Subsequent >+ * elf_link_hash_traverse calls will reflect this new order. >+ */ >+static bfd_boolean >+_bfd_elf_sort_dynsyms (struct bfd_link_info *info) >+{ >+ bfd_size_type bucketcount; >+ struct elf_dynsym_sort_info sinfo; >+ >+ sinfo.alloc_size = 8; >+ sinfo.sorted_syms = bfd_malloc (sizeof (struct elf_link_hash_entry *) * >+ sinfo.alloc_size); >+ if (!sinfo.sorted_syms) >+ return FALSE; >+ >+ sinfo.sorted_size = 0; >+ >+ /* append dynsyms for sorting */ >+ sinfo.do_dynsym = TRUE; >+ elf_link_hash_traverse (elf_hash_table (info), elf_sort_collect_dynsyms, &sinfo); >+ >+ /* sort them ... */ >+ bucketcount = elf_hash_table (info)->bucketcount; >+ bfd_qsort (sinfo.sorted_syms, sinfo.sorted_size, >+ sizeof (struct elf_link_hash_entry *), >+ elf_sort_dynsym_hash, >+ &bucketcount); >+ >+ /* append everything else */ >+ sinfo.do_dynsym = FALSE; >+ elf_link_hash_traverse (elf_hash_table (info), elf_sort_collect_dynsyms, &sinfo); >+ >+ /* freed in _bfd_elf_link_hash_table_free */ >+ elf_hash_table (info)->sorted = sinfo.sorted_syms; >+ elf_hash_table (info)->sorted_size = sinfo.sorted_size; >+ >+ return TRUE; >+} >+ > /* Set up the sizes and contents of the ELF dynamic sections. This is > called by the ELF linker emulation before_allocation routine. We > must set the sizes of the sections before the linker sets the >@@ -5766,6 +5904,7 @@ > section symbol for each output section, which come first. > Next come all of the back-end allocated local dynamic syms, > followed by the rest of the global symbols. */ >+ /* To sort these optimally we need the correct bucketcount */ > > dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info, > §ion_sym_count); >@@ -5872,6 +6011,17 @@ > for (dtagcount = 0; dtagcount <= info->spare_dynamic_tags; ++dtagcount) > if (!_bfd_elf_add_dynamic_entry (info, DT_NULL, 0)) > return FALSE; >+ >+ /* Sort .dynsym to accelerate runtime linking */ >+ if (info->dynsort) >+ { >+ if (!_bfd_elf_sort_dynsyms (info)) >+ return FALSE; >+ >+ /* renumber to reflect the new sorting order */ >+ _bfd_elf_link_renumber_dynsyms (output_bfd, info, >+ §ion_sym_count); >+ } > } > > return TRUE; >@@ -6012,6 +6162,7 @@ > bfd_vma sym_mask; > } u; > enum elf_reloc_type_class type; >+ unsigned long elf_bucket; > /* We use this as an array of size int_rels_per_ext_rel. */ > Elf_Internal_Rela rela[1]; > }; >@@ -6048,6 +6199,10 @@ > const struct elf_link_sort_rela *b = B; > int copya, copyb; > >+ if (a->elf_bucket < b->elf_bucket) >+ return -1; >+ if (a->elf_bucket > b->elf_bucket) >+ return 1; > if (a->u.offset < b->u.offset) > return -1; > if (a->u.offset > b->u.offset) >@@ -6066,8 +6221,9 @@ > } > > static size_t >-elf_link_sort_relocs (bfd *abfd, struct bfd_link_info *info, asection **psec) >+elf_link_sort_relocs (bfd *abfd, struct elf_final_link_info *finfo, asection **psec) > { >+ struct bfd_link_info *info = finfo->info; > asection *reldyn; > bfd_size_type count, size; > size_t i, ret, sort_elt, ext_size; >@@ -6079,6 +6235,7 @@ > void (*swap_out) (bfd *, const Elf_Internal_Rela *, bfd_byte *); > struct bfd_link_order *lo; > bfd_vma r_sym_mask; >+ int r_sym_shift; > > reldyn = bfd_get_section_by_name (abfd, ".rela.dyn"); > if (reldyn == NULL || reldyn->size == 0) >@@ -6120,15 +6277,29 @@ > } > > if (bed->s->arch_size == 32) >- r_sym_mask = ~(bfd_vma) 0xff; >+ { >+ r_sym_mask = ~(bfd_vma) 0xff; >+ r_sym_shift = 8; >+ } > else >- r_sym_mask = ~(bfd_vma) 0xffffffff; >+ { >+ r_sym_mask = ~(bfd_vma) 0xffffffff; >+ r_sym_shift = 32; >+ } > > for (lo = reldyn->map_head.link_order; lo != NULL; lo = lo->next) > if (lo->type == bfd_indirect_link_order) > { > bfd_byte *erel, *erelend; > asection *o = lo->u.indirect.section; >+ int base_offset = -1; >+ int base_max = 0; >+ >+ if (elf_hash_table (info)->sorted_size > 0) >+ { >+ base_offset = elf_hash_table (info)->sorted[0]->dynindx; >+ base_max = base_offset + elf_hash_table (info)->sorted_size; >+ } > > if (o->contents == NULL && o->size != 0) > { >@@ -6143,10 +6314,24 @@ > p = sort + o->output_offset / ext_size * sort_elt; > while (erel < erelend) > { >+ long dyn_idx; >+ size_t bucketcount = elf_hash_table (info)->bucketcount; > struct elf_link_sort_rela *s = (struct elf_link_sort_rela *) p; > (*swap_in) (abfd, erel, s->rela); > s->type = (*bed->elf_backend_reloc_type_class) (s->rela); > s->u.sym_mask = r_sym_mask; >+ >+ if (s->type != reloc_class_relative) >+ dyn_idx = s->rela->r_info >> r_sym_shift; >+ else >+ dyn_idx = -1; >+ >+ if (info->dynsort && base_offset >= 0 && >+ dyn_idx < base_max && dyn_idx >= base_offset) >+ s->elf_bucket = elf_hash_table (info)->sorted [dyn_idx - base_offset]->u.elf_hash_value % bucketcount; >+ else >+ s->elf_bucket = 0; >+ > p += sort_elt; > erel += ext_size; > } >@@ -8612,7 +8797,7 @@ > } > > if (dynamic && info->combreloc && dynobj != NULL) >- relativecount = elf_link_sort_relocs (abfd, info, &reldyn); >+ relativecount = elf_link_sort_relocs (abfd, &finfo, &reldyn); > > /* If we are linking against a dynamic object, or generating a > shared library, finish up the dynamic linking information. */ >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf-m10300.c binutils-2.16.91.0.5/bfd/elf-m10300.c >--- binutils-2.16.91.0.5.orig/bfd/elf-m10300.c 2005-11-13 23:16:34.000000000 +0600 >+++ binutils-2.16.91.0.5/bfd/elf-m10300.c 2006-01-26 23:33:47.976822593 +0600 >@@ -3729,8 +3729,7 @@ > > _bfd_generic_link_hash_table_free > ((struct bfd_link_hash_table *) ret->static_hash_table); >- _bfd_generic_link_hash_table_free >- ((struct bfd_link_hash_table *) ret); >+ _bfd_elf_link_hash_table_free (hash); > } > > static unsigned long >diff -ruN binutils-2.16.91.0.5.orig/bfd/elf-strtab.c binutils-2.16.91.0.5/bfd/elf-strtab.c >--- binutils-2.16.91.0.5.orig/bfd/elf-strtab.c 2005-05-11 05:46:41.000000000 +0700 >+++ binutils-2.16.91.0.5/bfd/elf-strtab.c 2006-01-26 23:33:47.977822353 +0600 >@@ -39,6 +39,7 @@ > /* Entry this is a suffix of (if len < 0). */ > struct elf_strtab_hash_entry *suffix; > } u; >+ long hash_bucket; > }; > > /* The strtab hash table. */ >@@ -54,6 +55,8 @@ > bfd_size_type sec_size; > /* Array of pointers to strtab entries. */ > struct elf_strtab_hash_entry **array; >+ /* Array of pointers to strtab entries. */ >+ struct elf_strtab_hash_entry **array_sorted; > }; > > /* Routine to create an entry in a section merge hashtab. */ >@@ -117,6 +120,7 @@ > } > > table->array[0] = NULL; >+ table->array_sorted = NULL; > > return table; > } >@@ -128,6 +132,8 @@ > { > bfd_hash_table_free (&tab->table); > free (tab->array); >+ if (tab->array_sorted) >+ free (tab->array_sorted); > free (tab); > } > >@@ -229,6 +235,12 @@ > _bfd_elf_strtab_emit (register bfd *abfd, struct elf_strtab_hash *tab) > { > bfd_size_type off = 1, i; >+ struct elf_strtab_hash_entry **array; >+ >+ if (tab->array_sorted != NULL) >+ array = tab->array_sorted; >+ else >+ array = tab->array; > > if (bfd_bwrite ("", 1, abfd) != 1) > return FALSE; >@@ -238,12 +250,12 @@ > register const char *str; > register unsigned int len; > >- BFD_ASSERT (tab->array[i]->refcount == 0); >- len = tab->array[i]->len; >+ BFD_ASSERT (array[i]->refcount == 0); >+ len = array[i]->len; > if ((int) len < 0) > continue; > >- str = tab->array[i]->root.string; >+ str = array[i]->root.string; > if (bfd_bwrite (str, len, abfd) != len) > return FALSE; > >@@ -278,6 +290,26 @@ > return lenA - lenB; > } > >+/* sort by hash bucket position */ >+static int >+hash_compare (const void *a, const void *b) >+{ >+ struct elf_strtab_hash_entry *A = *(struct elf_strtab_hash_entry **) a; >+ struct elf_strtab_hash_entry *B = *(struct elf_strtab_hash_entry **) b; >+ >+ if (A->hash_bucket > B->hash_bucket) >+ return 1; >+ if (A->hash_bucket < B->hash_bucket) >+ return -1; >+ >+ /* Make qsort faster for lots of identical empty symbols */ >+ if (a > b) >+ return 1; >+ if (a < b) >+ return -1; >+ return 0; >+} >+ > static inline int > is_suffix (const struct elf_strtab_hash_entry *A, > const struct elf_strtab_hash_entry *B) >@@ -293,9 +325,8 @@ > > /* This function assigns final string table offsets for used strings, > merging strings matching suffixes of longer strings if possible. */ >- > void >-_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab) >+_bfd_elf_strtab_finalize (struct elf_strtab_hash *tab, size_t bucket_count) > { > struct elf_strtab_hash_entry **array, **a, *e; > bfd_size_type size, amt; >@@ -361,15 +392,37 @@ > } > } > >-alloc_failure: >- if (array) >- free (array); >+ if (bucket_count != 0) >+ { >+ array[0] = NULL; >+ for (i = 1; i < tab->size; ++i) >+ { >+ e = tab->array[i]; >+ array[i] = e; >+ >+ if (e->len > 0) >+ { >+ e->hash_bucket = _bfd_elf_ver_hash (e->root.string); >+ e->hash_bucket %= bucket_count; >+ } >+ else >+ e->hash_bucket = 0; >+ } >+ qsort (array + 1, tab->size - 1, sizeof (struct elf_strtab_hash_entry *), hash_compare); >+ tab->array_sorted = array; >+ } >+ else >+ { >+ free (array); >+ alloc_failure: >+ array = tab->array; >+ } > > /* Assign positions to the strings we want to keep. */ > size = 1; > for (i = 1; i < tab->size; ++i) > { >- e = tab->array[i]; >+ e = array[i]; > if (e->refcount && e->len > 0) > { > e->u.index = size; >@@ -382,7 +435,7 @@ > /* Adjust the rest. */ > for (i = 1; i < tab->size; ++i) > { >- e = tab->array[i]; >+ e = array[i]; > if (e->refcount && e->len < 0) > e->u.index = e->u.suffix->u.index + (e->u.suffix->len + e->len); > } >diff -ruN binutils-2.16.91.0.5.orig/bfd/elfxx-target.h binutils-2.16.91.0.5/bfd/elfxx-target.h >--- binutils-2.16.91.0.5.orig/bfd/elfxx-target.h 2005-08-23 02:27:41.000000000 +0700 >+++ binutils-2.16.91.0.5/bfd/elfxx-target.h 2006-01-26 23:33:47.992818746 +0600 >@@ -205,7 +205,7 @@ > #endif > > #ifndef bfd_elfNN_bfd_link_hash_table_free >-#define bfd_elfNN_bfd_link_hash_table_free _bfd_generic_link_hash_table_free >+#define bfd_elfNN_bfd_link_hash_table_free _bfd_elf_link_hash_table_free > #endif > > #ifdef elf_backend_relocate_section >diff -ruN binutils-2.16.91.0.5.orig/include/bfdlink.h binutils-2.16.91.0.5/include/bfdlink.h >--- binutils-2.16.91.0.5.orig/include/bfdlink.h 2006-01-26 23:29:42.000000000 +0600 >+++ binutils-2.16.91.0.5/include/bfdlink.h 2006-01-26 23:33:47.993818506 +0600 >@@ -342,6 +342,9 @@ > /* TRUE if unreferenced sections should be removed. */ > unsigned int gc_sections: 1; > >+ /* TRUE if dynsym/dynstr/relocs should be sorted */ >+ unsigned int dynsort : 1; >+ > /* What to do with unresolved symbols in an object file. > When producing executables the default is GENERATE_ERROR. > When producing shared libraries the default is IGNORE. The >diff -ruN binutils-2.16.91.0.5.orig/ld/emultempl/elf32.em binutils-2.16.91.0.5/ld/emultempl/elf32.em >--- binutils-2.16.91.0.5.orig/ld/emultempl/elf32.em 2006-01-26 23:29:42.000000000 +0600 >+++ binutils-2.16.91.0.5/ld/emultempl/elf32.em 2006-01-26 23:33:48.008814899 +0600 >@@ -1782,6 +1782,10 @@ > link_info.relro = TRUE; > else if (strcmp (optarg, "norelro") == 0) > link_info.relro = FALSE; >+ else if (strcmp (optarg, "dynsort") == 0) >+ link_info.dynsort = TRUE; >+ else if (strcmp (optarg, "nodynsort") == 0) >+ link_info.dynsort = FALSE; > /* What about the other Solaris -z options? FIXME. */ > break; > EOF >@@ -1817,6 +1821,7 @@ > fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n")); > fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n")); > fprintf (file, _(" -z defs\t\tReport unresolved symbols in object files.\n")); >+ fprintf (file, _(" -z dynsort\t\tSort dynamic link sections\n")); > fprintf (file, _(" -z execstack\t\tMark executable as requiring executable stack\n")); > fprintf (file, _(" -z execheap\t\tMark executable as requiring executable heap\n")); > fprintf (file, _(" -z initfirst\t\tMark DSO to be initialized first at runtime\n")); >@@ -1829,6 +1834,7 @@ > fprintf (file, _(" -z nodelete\t\tMark DSO non-deletable at runtime\n")); > fprintf (file, _(" -z nodlopen\t\tMark DSO not available to dlopen\n")); > fprintf (file, _(" -z nodump\t\tMark DSO not available to dldump\n")); >+ fprintf (file, _(" -z nodynsort\t\tDon't sort dynamic link sections\n")); > fprintf (file, _(" -z noexecstack\tMark executable as not requiring executable stack\n")); > fprintf (file, _(" -z noexecheap\tMark executable as not requiring executable heap\n")); > fprintf (file, _(" -z norelro\t\tDon't create RELRO program header\n")); >diff -ruN binutils-2.16.91.0.5.orig/ld/ldmain.c binutils-2.16.91.0.5/ld/ldmain.c >--- binutils-2.16.91.0.5.orig/ld/ldmain.c 2006-01-26 23:29:43.000000000 +0600 >+++ binutils-2.16.91.0.5/ld/ldmain.c 2006-01-26 23:33:48.024811051 +0600 >@@ -316,6 +316,7 @@ > link_info.need_relax_finalize = FALSE; > link_info.warn_shared_textrel = TRUE; > link_info.gc_sections = FALSE; >+ link_info.dynsort = FALSE; > > ldfile_add_arch (""); > >diff -ruN binutils-2.16.91.0.5.orig/ld/ld.texinfo binutils-2.16.91.0.5/ld/ld.texinfo >--- binutils-2.16.91.0.5.orig/ld/ld.texinfo 2005-12-21 04:43:57.000000000 +0600 >+++ binutils-2.16.91.0.5/ld/ld.texinfo 2006-01-26 23:33:48.054803837 +0600 >@@ -933,6 +933,9 @@ > Disallows undefined symbols in object files. Undefined symbols in > shared libraries are still allowed. > >+@item dynsort >+Sorts dynamic link sections, to reduce cache misses during linking. >+ > @item execstack > Marks the object as requiring executable stack. > >@@ -974,6 +977,9 @@ > @item nodump > Marks the object can not be dumped by @code{dldump}. > >+@item nodynsort >+Disables dynamic link section sorting. >+ > @item noexecstack > Marks the object as not requiring executable stack. >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 114008
:
74762
|
75104
|
77828
|
77830
|
77840
|
78188
|
78189
|
78190
| 78191 |
78192
|
78193
|
78194
|
78195
|
78196
|
78213
|
80806
|
80807
|
80808
|
80809
|
84585
|
84615
|
84616
|
84617
|
86630
|
89027
|
451452
|
451454