From 095256e47b391b5e8e784b719581c0d65875aaff Mon Sep 17 00:00:00 2001 From: Andrey Bondrov Date: Thu, 30 Mar 2017 21:19:28 +1000 Subject: [PATCH] Restore fixed dso_deps patch (as it greatly improves performance of dynamic loader for deeply nested DSO dependencies) --- glibc-dso_deps.patch | 430 ++++++++++++++++++++++++++++++------------- glibc.spec | 5 +- 2 files changed, 304 insertions(+), 131 deletions(-) diff --git a/glibc-dso_deps.patch b/glibc-dso_deps.patch index d90a750..bb0bb26 100644 --- a/glibc-dso_deps.patch +++ b/glibc-dso_deps.patch @@ -1,63 +1,118 @@ ---- glibc-2.21/elf/dl-deps.c.dsodeps~ 2015-02-06 07:40:18.000000000 +0100 -+++ glibc-2.21/elf/dl-deps.c 2015-02-07 14:32:43.667285775 +0100 -@@ -152,6 +152,56 @@ preload (struct list *known, unsigned in - map->l_reserved = 1; - } +@@ -, +, @@ + 17645) +--- + elf/Makefile | 1 + + elf/dl-deps.c | 143 +++++++++++++++++++++++++++++------------------ + elf/dl-fini.c | 176 +++++++++++++++++++++++++++++++--------------------------- + elf/dl-open.c | 74 ++++++++++++++++++++++++ + 4 files changed, 256 insertions(+), 138 deletions(-) +--- a/elf/Makefile ++++ a/elf/Makefile +@@ -513,6 +513,7 @@ $(objpfx)unload8mod1.so: $(objpfx)unload8mod2.so + $(objpfx)unload8mod2.so: $(objpfx)unload8mod3.so + $(objpfx)unload8mod3.so: $(libdl) + $(objpfx)tst-initordera2.so: $(objpfx)tst-initordera1.so ++$(objpfx)tst-initorderb1.so: $(objpfx)tst-initordera2.so + $(objpfx)tst-initorderb2.so: $(objpfx)tst-initorderb1.so $(objpfx)tst-initordera2.so + $(objpfx)tst-initordera3.so: $(objpfx)tst-initorderb2.so $(objpfx)tst-initorderb1.so + $(objpfx)tst-initordera4.so: $(objpfx)tst-initordera3.so +--- a/elf/dl-deps.c ++++ a/elf/dl-deps.c +@@ -139,6 +139,93 @@ cannot load auxiliary `%s' because of empty dynamic string token " \ + __result; }) -+static int compare (struct link_map *a, struct link_map *b) + static void ++weight (struct link_map **maps, size_t nmaps, char *seen, unsigned int *w) +{ -+ struct link_map **r, **s; -+ /* Check if must swap */ -+ if ((r = b->l_initfini)) -+ { -+ while (*r) -+ if (*r++ == a) -+ return 1; -+ } -+ /* Check if must *not* swap */ -+ if ((r = a->l_initfini)) -+ { -+ while (*r) -+ if (*r++ == b) -+ return -1; -+ } -+ /* No direct dependency information */ -+ return 0; -+} ++ int i, c; ++ struct link_map *m, **r; + ++ /* Start at 1 because the first entry is the binary itself. */ ++ for (i = 1; i < nmaps; ++i) ++ { ++ m = maps[i]; ++ if ((r = m->l_initfini)) ++ { ++ c = 0; ++ while (*r) ++ { ++ ++ /* If not a self reference, not being unloaded, and not ++ already removed from the list, increment the reference ++ counter. */ ++ if (*r != m && (*r)->l_idx >= 0 && !seen[(*r)->l_idx]) ++ ++c; ++ ++r; ++ } ++ ++ /* Update the {w}eight vector with {c}ount map(s) dependency */ ++ w[i] = c; ++ } ++ else ++ w[i] = 0; ++ } ++} + +static void +sort (struct link_map **maps, size_t nmaps) +{ -+ unsigned int i, k; ++ int c, i, k; ++ unsigned int w[nmaps]; ++ char seen[nmaps]; + struct link_map *t; ++ memset(seen, 0, nmaps); ++ ++ /* Use the l_idx field as an unique identifier. */ ++ for (i = 0; i < nmaps; ++i) ++ { ++ /* Ensure to not touch a link_map with l_idx < 0 as it is ++ used to flag a dso is being unloaded. */ ++ if (maps[i]->l_idx >= 0) ++ maps[i]->l_idx = i; ++ } + + /* We can skip looking for the binary itself which is at the front -+ of the search list for the main namespace. */ -+ for (i = 1; i < nmaps; ++i) ++ of the search list. */ ++ w[0] = 0; ++ seen[0] = 1; ++ ++ /* The list is sorted in place, with entries added from end to start. */ ++ weight(maps, k = nmaps, seen, w); ++ c = 0; ++ while (c < k) + { -+ /* Find the last object in the list for which the current one is -+ a dependency and move the current object behind the object -+ with the dependency. */ -+ for (k = i + 1; k < nmaps; ++k) ++ for (i = k - 1; i >= 1; --i) + { -+ if (compare(maps[i], maps[k]) > 0) ++ if (w[i] == c && maps[i]->l_idx >= 0) + { -+ /* Move the current object to the back past the last -+ object with it as the dependency. */ -+ t = maps[i]; -+ maps[i] = maps[k]; -+ maps[k] = t; ++ seen[maps[i]->l_idx] = 1; ++ ++ /* Reducing the number of entries or swaping entries ++ require remaking the {w}eight map. */ ++ if (--k != i) ++ { ++ t = maps[k]; ++ maps[k] = maps[i]; ++ maps[i] = t; ++ } ++ weight(maps, k, seen, w); ++ c = -1; ++ break; + } + } ++ ++ /* If c != 0, there are cycles, and the first entry in the map, ++ with the lowest reference {c}ount is removed attempting to ++ to break the cycle. */ ++ ++c; + } +} + -+ - void - internal_function - _dl_map_object_deps (struct link_map *map, -@@ -611,61 +661,7 @@ Filters not supported with LD_TRACE_PREL ++static void + preload (struct list *known, unsigned int *nlist, struct link_map *map) + { + known[*nlist].done = 0; +@@ -611,61 +698,7 @@ Filters not supported with LD_TRACE_PRELINKING")); memcpy (l_initfini, map->l_searchlist.r_list, nlist * sizeof (struct link_map *)); if (__glibc_likely (nlist > 1)) @@ -120,87 +175,88 @@ /* Terminate the list of dependencies. */ l_initfini[nlist] = NULL; ---- glibc-2.21/elf/dl-fini.c.dsodeps~ 2015-02-06 07:40:18.000000000 +0100 -+++ glibc-2.21/elf/dl-fini.c 2015-02-07 14:31:26.369897612 +0100 -@@ -26,101 +26,83 @@ +--- a/elf/dl-fini.c ++++ a/elf/dl-fini.c +@@ -26,102 +26,112 @@ typedef void (*fini_t) (void); -+static int compare (struct link_map *a, struct link_map *b) -+{ -+ struct link_map **r; -+ /* Check if must swap */ -+ if ((r = b->l_initfini)) -+ { -+ while (*r) -+ if (*r++ == a) -+ return 1; -+ } -+ /* Check if must *not* swap */ -+ if ((r = a->l_initfini)) -+ { -+ while (*r) -+ if (*r++ == b) -+ return -1; -+ } -+ if (b->l_reldeps && a->l_initfini) -+ { -+ unsigned int m = b->l_reldeps->act; -+ struct link_map **relmaps = &b->l_reldeps->list[0]; -+ -+ /* Look through the relocation dependencies of the object. */ -+ while (m--) -+ if (relmaps[m] == a) -+ { -+ /* If a cycle exists with a link time dependency, -+ preserve the latter. */ -+ for (r = a->l_initfini; *r; ++r) -+ if (*r == b) -+ return -1; -+ return 1; -+ } -+ } -+ /* No direct dependency information */ -+ return 0; -+} -+ -+ - void - internal_function - _dl_sort_fini (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns) +-void +-internal_function +-_dl_sort_fini (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns) ++static void ++weight (struct link_map **maps, size_t nmaps, char *seen, unsigned int *w, int from) { - /* A list of one element need not be sorted. */ - if (nmaps == 1) - return; -- -- /* We can skip looking for the binary itself which is at the front -- of the search list for the main namespace. */ ++ int i, c; ++ struct link_map *m, **r; ++ for (i = from; i < nmaps; ++i) ++ { ++ m = maps[i]; ++ if ((r = m->l_initfini)) ++ { ++ c = 0; ++ while (*r) ++ { ++ /* If not a self reference, not being unloaded, and not ++ already removed from the list, increment the reference ++ counter. */ ++ if (*r != m && (*r)->l_idx >= 0 && !seen[(*r)->l_idx]) ++ ++c; ++ ++r; ++ } ++ /* Update the {w}eight vector with {c}ount map(s) dependency */ ++ w[i] = c; ++ } ++ else ++ w[i] = 0; ++ } ++} ++ ++ ++static void ++sort (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns) ++{ ++ int from; ++ int c, i, k; ++ unsigned int w[nmaps]; ++ char seen[nmaps]; ++ struct link_map *t; ++ ++ memset(seen, 0, nmaps); ++ ++ /* Use the l_idx field as an unique identifier. */ ++ for (i = 0; i < nmaps; ++i) ++ { ++ /* Ensure to not touch a link_map with l_idx < 0 as it is ++ used to flag a dso is being unloaded. */ ++ if (maps[i]->l_idx >= 0) ++ maps[i]->l_idx = i; ++ } + + /* We can skip looking for the binary itself which is at the front + of the search list for the main namespace. */ - unsigned int i = ns == LM_ID_BASE; - uint16_t seen[nmaps]; - memset (seen, 0, nmaps * sizeof (seen[0])); - while (1) -+ unsigned int i, k; -+ struct link_map *t; -+ -+ /* We can skip looking for the binary itself which is at the front -+ of the search list for the main namespace. */ -+ for (i = ns == LM_ID_BASE; i < nmaps; ++i) ++ from = ns == LM_ID_BASE; ++ if (from) { - /* Keep track of which object we looked at this round. */ - ++seen[i]; - struct link_map *thisp = maps[i]; -+ t = maps[i]; - - /* Do not handle ld.so in secondary namespaces and object which - are not removed. */ +- +- /* Do not handle ld.so in secondary namespaces and object which +- are not removed. */ - if (thisp != thisp->l_real || thisp->l_idx == -1) - goto skip; -+ if (t != t->l_real || t->l_idx == -1) -+ continue; - - /* Find the last object in the list for which the current one is - a dependency and move the current object behind the object - with the dependency. */ +- +- /* Find the last object in the list for which the current one is +- a dependency and move the current object behind the object +- with the dependency. */ - unsigned int k = nmaps - 1; - while (k > i) - { @@ -224,25 +280,48 @@ - (k - i) * sizeof (used[0])); - used[k] = here_used; - } -- ++ w[0] = 0; ++ seen[0] = 1; ++ } + - if (seen[i + 1] > nmaps - i) -- { ++ /* The list is sorted in place, with entries added from end to start. */ ++ weight(maps, k = nmaps, seen, w, from); ++ c = 0; ++ while (c < k) ++ { ++ for (i = k - 1; i >= from; --i) ++ { ++ t = maps[i]; ++ /* Do not handle ld.so in secondary namespaces and object which ++ are not removed. */ ++ if (w[i] == c && maps[i]->l_idx >= 0 && t->l_real == t) ++ { ++ seen[maps[i]->l_idx] = 1; ++ /* Reducing the number of entries or swaping entries ++ require remaking the {w}eight map. */ ++ if (--k != i) ++ { ++ maps[i] = maps[k]; ++ maps[k] = t; ++ if (used) + { - ++i; - goto next_clear; -- } ++ char c = used[i]; ++ used[i] = used[k]; ++ used[k] = c; + } - - uint16_t this_seen = seen[i]; - memmove (&seen[i], &seen[i + 1], (k - i) * sizeof (seen[0])); - seen[k] = this_seen; - - goto next; -- } + } - - if (__glibc_unlikely (maps[k]->l_reldeps != NULL)) -+ for (k = i + 1; k < nmaps; ++k) -+ { -+ if (compare(maps[i], maps[k]) > 0) - { +- { - unsigned int m = maps[k]->l_reldeps->act; - struct link_map **relmaps = &maps[k]->l_reldeps->list[0]; - @@ -260,30 +339,121 @@ - goto move; - } - ignore:; -- } ++ weight(maps, k, seen, w, from); ++ c = -1; ++ break; + } - - --k; -+ /* Move the current object to the back past the last -+ object with it as the dependency. */ -+ t = maps[i]; -+ maps[i] = maps[k]; -+ maps[k] = t; -+ if (used) -+ { -+ char c = used[i]; -+ used[i] = used[k]; -+ used[k] = c; -+ } -+ } } -- ++ /* If c != 0, there are cycles, and the first entry in the map, ++ with the lowest reference {c}ount is removed attempting to ++ to break the cycle. */ ++ ++c; ++ } ++} + - skip: - if (++i == nmaps) - break; - next_clear: - memset (&seen[i], 0, (nmaps - i) * sizeof (seen[0])); -- + - next:; - } +- } ++void ++internal_function ++_dl_sort_fini (struct link_map **maps, size_t nmaps, char *used, Lmid_t ns) ++{ ++ /* A list of one element need not be sorted. */ ++ if (nmaps == 1) ++ return; ++ ++ sort (maps, nmaps, used, ns); } + +--- a/elf/dl-open.c ++++ a/elf/dl-open.c +@@ -182,6 +182,80 @@ _dl_find_dso_for_object (const ElfW(Addr) addr) + rtld_hidden_def (_dl_find_dso_for_object); + + static void ++weight (struct link_map **maps, size_t nmaps, char *seen, unsigned int *w) ++{ ++ int i, c; ++ struct link_map *m, **r; ++ for (i = 0; i < nmaps; ++i) ++ { ++ m = maps[i]; ++ if ((r = m->l_initfini)) ++ { ++ c = 0; ++ while (*r) ++ { ++ /* If not a self reference, not being unloaded, and not ++ already removed from the list, increment the reference ++ counter. */ ++ if (*r != m && (*r)->l_idx >= 0 && !seen[(*r)->l_idx]) ++ ++c; ++ ++r; ++ } ++ /* Update the {w}eight vector with {c}ount map(s) dependency */ ++ w[i] = c; ++ } ++ else ++ w[i] = 0; ++ } ++} ++ ++static void ++sort (struct link_map **maps, size_t nmaps) ++{ ++ int c, i, k; ++ unsigned int w[nmaps]; ++ char seen[nmaps]; ++ struct link_map *t; ++ memset(seen, 0, nmaps); ++ /* Use the l_idx field as an unique identifier. */ ++ for (i = 0; i < nmaps; ++i) ++ { ++ /* Ensure to not touch a link_map with l_idx < 0 as it is ++ used to flag a dso is being unloaded. */ ++ if (maps[i]->l_idx >= 0) ++ maps[i]->l_idx = i; ++ } ++ /* The list is sorted in place, with entries added from end to start. */ ++ weight(maps, k = nmaps, seen, w); ++ c = 0; ++ while (c < k) ++ { ++ for (i = k - 1; i >= 0; --i) ++ { ++ if (w[i] == c && maps[i]->l_idx >= 0) ++ { ++ seen[maps[i]->l_idx] = 1; ++ /* Reducing the number of entries or swaping entries ++ require remaking the {w}eight map. */ ++ if (--k != i) ++ { ++ t = maps[k]; ++ maps[k] = maps[i]; ++ maps[i] = t; ++ } ++ weight(maps, k, seen, w); ++ c = -1; ++ break; ++ } ++ } ++ /* If c != 0, there are cycles, and the first entry in the map, ++ with the lowest reference {c}ount is removed attempting to ++ to break the cycle. */ ++ ++c; ++ } ++} ++ ++static void + dl_open_worker (void *a) + { + struct dl_open_args *args = a; +-- diff --git a/glibc.spec b/glibc.spec index 8e007c5..ebee6b0 100644 --- a/glibc.spec +++ b/glibc.spec @@ -57,7 +57,7 @@ Summary: The GNU libc libraries Name: glibc Epoch: 6 Version: 2.24 -Release: 7 +Release: 8 License: LGPLv2+ and LGPLv2+ with exceptions and GPLv2+ Group: System/Libraries Url: http://www.eglibc.org/ @@ -130,6 +130,8 @@ Patch27: glibc-2.22-blacklist-CPUs-from-lock-elision.patch Patch28: glibc-bug-regex-gcc5.patch Patch29: glibc-c-utf8-locale.patch Patch30: glibc-dns-host-gcc5.patch +# https://sourceware.org/bugzilla/show_bug.cgi?id=17645 +Patch31: glibc-dso_deps.patch Patch32: glibc-gcc-PR69537.patch Patch33: glibc-gethnamaddr-gcc5.patch Patch34: glibc-ld-ctype-gcc5.patch @@ -823,6 +825,7 @@ their ~/.profile configuration file. %patch28 -p1 %patch29 -p1 %patch30 -p1 +%patch31 -p1 %patch32 -p1 %patch33 -p1 %patch34 -p1