Package: guix-patches;
Reported by: Ludovic Courtès <ludo <at> gnu.org>
Date: Fri, 27 Nov 2020 08:34:02 UTC
Severity: normal
Tags: patch
Done: Ludovic Courtès <ludo <at> gnu.org>
Bug is archived. No further changes may be made.
To add a comment to this bug, you must first unarchive it, by sending
a message to control AT debbugs.gnu.org, with unarchive 44899 in the body.
You can then email your comments to 44899 AT debbugs.gnu.org in the normal way.
Toggle the display of automated, internal messages from the tracker.
View this report as an mbox folder, status mbox, maintainer mbox
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Fri, 27 Nov 2020 08:34:02 GMT) Full text and rfc822 format available.Ludovic Courtès <ludo <at> gnu.org>
:guix-patches <at> gnu.org
.
(Fri, 27 Nov 2020 08:34:02 GMT) Full text and rfc822 format available.Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: guix-patches <at> gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 0/3] Using 'ld.so.cache' to speed up application startup Date: Fri, 27 Nov 2020 09:33:02 +0100
Hello Guix! The other day on IRC Ricardo had the brilliant idea of using the ld.so cache to avoid the “stat storm” stemming from our long RUNPATHs, and thus to speed up application startup. As an example, Guile has 9 entries in its RUNPATH and Inkscape has 44 entries. The first patch changes the loader (1) to look for the cache in $ORIGIN/../etc/ld.so.cache, and (2) to look for the cache before looking at RUNPATH entries. The second patch adds a build phase that creates ‘etc/ld.so.cache’. It passes ‘ldconfig’ a config file that contains the union of all the RUNPATH entries of all the executables found in the output at hand. (It cannot be done in a profile hook because $ORIGIN is determined by looking at /proc/self/exe, which is the canonical file name in the store.) You can see it in action with LD_DEBUG=libs: --8<---------------cut here---------------start------------->8--- $ LD_DEBUG=libs /gnu/store/3dfv892jq8081xnsl9gfylbgv1fdicvd-guile-3.0.4/bin/guile --version 11150: find library=libguile-3.0.so.1 [0]; searching 11150: search cache=/gnu/store/3dfv892jq8081xnsl9gfylbgv1fdicvd-guile-3.0.4/bin/../etc/ld.so.cache 11150: trying file=/gnu/store/3dfv892jq8081xnsl9gfylbgv1fdicvd-guile-3.0.4/lib/libguile-3.0.so.1 11150: 11150: find library=libgc.so.1 [0]; searching 11150: search cache=/gnu/store/3dfv892jq8081xnsl9gfylbgv1fdicvd-guile-3.0.4/bin/../etc/ld.so.cache 11150: trying file=/gnu/store/hy88vf2ynlica0wj0ppi0d3b11gi2b2h-libgc-8.0.4/lib/libgc.so.1 [...] --8<---------------cut here---------------end--------------->8--- Here’s the after/before for Guile: --8<---------------cut here---------------start------------->8--- $ strace -c /gnu/store/3dfv892jq8081xnsl9gfylbgv1fdicvd-guile-3.0.4/bin/guile --version [...] 2.70 0.000259 5 46 6 openat 1.87 0.000180 1 130 88 stat 1.66 0.000159 4 36 rt_sigprocmask 0.74 0.000071 1 40 close 0.64 0.000061 3 18 fstat [...] 100.00 0.009604 600 105 total $ strace -c guile --version [...] 13.82 0.000723 4 165 114 openat 13.46 0.000704 3 190 144 stat [...] 1.43 0.000075 2 29 fstat [...] 100.00 0.005232 773 268 total --8<---------------cut here---------------end--------------->8--- Erroneous syscalls are divided by 2.5; total syscalls reduced by 22%. For Bash: --8<---------------cut here---------------start------------->8--- $ strace -c /gnu/store/qs33sf58502v1wx77va092y14sbspv4f-bash-minimal-5.0.16/bin/bash --version GNU bash, version 5.0.16(1)-release (x86_64-unknown-linux-gnu) Copyright (C) 2019 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 0.00 0.000000 0 4 read 0.00 0.000000 0 6 write 0.00 0.000000 0 5 close 0.00 0.000000 0 5 fstat 0.00 0.000000 0 12 mmap 0.00 0.000000 0 5 mprotect 0.00 0.000000 0 1 munmap 0.00 0.000000 0 3 brk 0.00 0.000000 0 1 rt_sigprocmask 0.00 0.000000 0 1 1 access 0.00 0.000000 0 1 execve 0.00 0.000000 0 1 readlink 0.00 0.000000 0 1 getuid 0.00 0.000000 0 1 getgid 0.00 0.000000 0 1 geteuid 0.00 0.000000 0 1 getegid 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 9 4 openat ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000000 59 5 total $ strace -c /gnu/store/fvhj74pghapbjvsvj27skvkra1by1965-bash-minimal-5.0.16/bin/bash --version GNU bash, version 5.0.16(1)-release (x86_64-unknown-linux-gnu) Copyright (C) 2019 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 34.15 0.000420 12 35 16 openat 18.29 0.000225 8 27 mmap 8.13 0.000100 25 4 brk 7.72 0.000095 6 14 14 stat 7.24 0.000089 89 1 1 access 6.18 0.000076 4 19 fstat 5.45 0.000067 3 19 close 4.47 0.000055 2 20 read 3.82 0.000047 9 5 mprotect 2.36 0.000029 4 6 write 0.65 0.000008 8 1 execve 0.41 0.000005 5 1 arch_prctl 0.33 0.000004 4 1 getuid 0.24 0.000003 3 1 rt_sigprocmask 0.24 0.000003 3 1 getegid 0.16 0.000002 2 1 getgid 0.16 0.000002 2 1 geteuid ------ ----------- ----------- --------- --------- ---------------- 100.00 0.001230 157 31 total --8<---------------cut here---------------end--------------->8--- Erroneous syscalls are divided by 6; total syscalls divided by 2.7. As always, this is probably not that big a deal on warm-cache SSD, but it probably makes a difference on a cold cache, on spinning disks, and on network file systems. * Possible improvements The hard-coded ‘../etc/ld.so.cache’ means that it can only be used with first-level sub-directories like bin/ and sbin/; it won’t be used for libexec/guix/guile, for instance, which is a bummer. Perhaps we should compute the ‘ld.so.cache’ file name “lexically” instead. We should also think hard about ways users could be tricked into loading a malicious ‘ld.so.cache’. That’s also another reason why “lexical dot-dot” would be safer: we could ensure that only pre-computed ‘ld.so.cache’ that live in the store are ever loaded. The ‘ld.so.conf’ file passed to ‘ldconfig’ should ideally contains the RUNPATH entries _recursively_, such that even indirect dependencies can be found in cache. Thoughts? Ludo’. Ludovic Courtès (3): gnu: glibc: Load ${ORIGIN}/../etc/ld.so.cache when available. gremlin: Fix typo in docstring. build-system/gnu: Add 'make-dynamic-linker-cache' phase. gnu/local.mk | 1 + gnu/packages/base.scm | 11 +- gnu/packages/patches/glibc-dl-cache.patch | 122 ++++++++++++++++++++++ guix/build-system/gnu.scm | 4 + guix/build/gnu-build-system.scm | 73 +++++++++++++ guix/build/gremlin.scm | 2 +- 6 files changed, 202 insertions(+), 11 deletions(-) create mode 100644 gnu/packages/patches/glibc-dl-cache.patch -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Fri, 27 Nov 2020 09:06:01 GMT) Full text and rfc822 format available.Message #8 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 1/3] gnu: glibc: Load ${ORIGIN}/../etc/ld.so.cache when available. Date: Fri, 27 Nov 2020 10:05:21 +0100
* gnu/packages/patches/glibc-dl-cache.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/base.scm (glibc)[source]: Remove 'snippet' and 'modules'. --- gnu/local.mk | 1 + gnu/packages/base.scm | 11 +- gnu/packages/patches/glibc-dl-cache.patch | 122 ++++++++++++++++++++++ 3 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 gnu/packages/patches/glibc-dl-cache.patch diff --git a/gnu/local.mk b/gnu/local.mk index f9fed30a3f..82c3c608c6 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1051,6 +1051,7 @@ dist_patch_DATA = \ %D%/packages/patches/glibc-bootstrap-system-2.2.5.patch \ %D%/packages/patches/glibc-bootstrap-system-2.16.0.patch \ %D%/packages/patches/glibc-bootstrap-system.patch \ + %D%/packages/patches/glibc-dl-cache.patch \ %D%/packages/patches/glibc-hidden-visibility-ldconfig.patch \ %D%/packages/patches/glibc-hurd-clock_gettime_monotonic.patch \ %D%/packages/patches/glibc-hurd-clock_t_centiseconds.patch \ diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm index bd352319a1..f8f4ae37fd 100644 --- a/gnu/packages/base.scm +++ b/gnu/packages/base.scm @@ -675,17 +675,8 @@ the store.") (sha256 (base32 "0di848ibffrnwq7g2dvgqrnn4xqhj3h96csn69q4da51ymafl9qn")) - (snippet - ;; Disable 'ldconfig' and /etc/ld.so.cache. The latter is - ;; required on LFS distros to avoid loading the distro's libc.so - ;; instead of ours. - '(begin - (substitute* "sysdeps/unix/sysv/linux/configure" - (("use_ldconfig=yes") - "use_ldconfig=no")) - #t)) - (modules '((guix build utils))) (patches (search-patches "glibc-ldd-x86_64.patch" + "glibc-dl-cache.patch" "glibc-hidden-visibility-ldconfig.patch" "glibc-versioned-locpath.patch" "glibc-allow-kernel-2.6.32.patch" diff --git a/gnu/packages/patches/glibc-dl-cache.patch b/gnu/packages/patches/glibc-dl-cache.patch new file mode 100644 index 0000000000..9d578bb3d9 --- /dev/null +++ b/gnu/packages/patches/glibc-dl-cache.patch @@ -0,0 +1,122 @@ +Read the shared library cache relative to $ORIGIN instead of reading +from /etc/ld.so.cache. Also arrange so that this cache takes +precedence over RUNPATH. + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 93d185e788..6a2989bd4c 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -171,6 +171,33 @@ _dl_cache_libcmp (const char *p1, const char *p2) + return *p1 - *p2; + } + ++/* Special value representing the lack of an ld.so cache. */ ++static const char ld_so_cache_lacking[] = "/ld.so cache is lacking"; ++ ++/* Return the per-application ld.so cache, relative to $ORIGIN, or NULL if ++ that fails for some reason. Do not return the system-wide LD_SO_CACHE ++ since on a foreign distro it would contain invalid information. */ ++static const char * ++ld_so_cache (void) ++{ ++ static const char *loader_cache; ++ ++ if (loader_cache == NULL) ++ { ++ const char suffix[] = "/../etc/ld.so.cache"; ++ const char *origin = _dl_get_origin (); ++ ++ /* Note: We can't use 'malloc' because it can be interposed. */ ++ char *cache = alloca (strlen (origin) + sizeof suffix); ++ ++ strcpy (cache, origin); ++ strcat (cache, suffix); ++ ++ loader_cache = __strdup (cache) ?: ld_so_cache_lacking; ++ } ++ ++ return loader_cache; ++} + + /* Look up NAME in ld.so.cache and return the file name stored there, or null + if none is found. The cache is loaded if it was not already. If loading +@@ -190,12 +217,15 @@ _dl_load_cache_lookup (const char *name) + + /* Print a message if the loading of libs is traced. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) +- _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE); ++ _dl_debug_printf (" search cache=%s\n", ld_so_cache ()); ++ ++ if (__glibc_unlikely (ld_so_cache () == ld_so_cache_lacking)) ++ return NULL; + + if (cache == NULL) + { + /* Read the contents of the file. */ +- void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize, ++ void *file = _dl_sysdep_read_whole_file (ld_so_cache (), &cachesize, + PROT_READ); + + /* We can handle three different cache file formats here: +diff --git a/elf/dl-load.c b/elf/dl-load.c +index f3201e7c14..a69aec3428 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -2152,28 +2152,6 @@ _dl_map_object (struct link_map *loader, const char *name, + loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, + LA_SER_LIBPATH, &found_other_class); + +- /* Look at the RUNPATH information for this binary. */ +- if (fd == -1 && loader != NULL +- && cache_rpath (loader, &loader->l_runpath_dirs, +- DT_RUNPATH, "RUNPATH")) +- fd = open_path (name, namelen, mode, +- &loader->l_runpath_dirs, &realname, &fb, loader, +- LA_SER_RUNPATH, &found_other_class); +- +- if (fd == -1) +- { +- realname = _dl_sysdep_open_object (name, namelen, &fd); +- if (realname != NULL) +- { +- fd = open_verify (realname, fd, +- &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, +- LA_SER_CONFIG, mode, &found_other_class, +- false); +- if (fd == -1) +- free (realname); +- } +- } +- + #ifdef USE_LDCONFIG + if (fd == -1 + && (__glibc_likely ((mode & __RTLD_SECURE) == 0) +@@ -2232,6 +2210,28 @@ _dl_map_object (struct link_map *loader, const char *name, + } + #endif + ++ /* Look at the RUNPATH information for this binary. */ ++ if (fd == -1 && loader != NULL ++ && cache_rpath (loader, &loader->l_runpath_dirs, ++ DT_RUNPATH, "RUNPATH")) ++ fd = open_path (name, namelen, mode, ++ &loader->l_runpath_dirs, &realname, &fb, loader, ++ LA_SER_RUNPATH, &found_other_class); ++ ++ if (fd == -1) ++ { ++ realname = _dl_sysdep_open_object (name, namelen, &fd); ++ if (realname != NULL) ++ { ++ fd = open_verify (realname, fd, ++ &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, ++ LA_SER_CONFIG, mode, &found_other_class, ++ false); ++ if (fd == -1) ++ free (realname); ++ } ++ } ++ + /* Finally, try the default path. */ + if (fd == -1 + && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Fri, 27 Nov 2020 09:06:02 GMT) Full text and rfc822 format available.Message #11 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 2/3] gremlin: Fix typo in docstring. Date: Fri, 27 Nov 2020 10:05:22 +0100
* guix/build/gremlin.scm (file-runpath): Fix typo. --- guix/build/gremlin.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guix/build/gremlin.scm b/guix/build/gremlin.scm index 6857e47b99..44604827a9 100644 --- a/guix/build/gremlin.scm +++ b/guix/build/gremlin.scm @@ -250,7 +250,7 @@ info." (elf-dynamic-info (parse-elf (get-bytevector-all port)))))) (define (file-runpath file) - "Return the DT_RUNPATH dynamic entry of FILE as a list of string, or #f if + "Return the DT_RUNPATH dynamic entry of FILE as a list of strings, or #f if FILE lacks dynamic info." (and=> (file-dynamic-info file) elf-dynamic-info-runpath)) -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Fri, 27 Nov 2020 09:06:02 GMT) Full text and rfc822 format available.Message #14 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH 3/3] build-system/gnu: Add 'make-dynamic-linker-cache' phase. Date: Fri, 27 Nov 2020 10:05:23 +0100
* guix/build/gnu-build-system.scm (make-dynamic-linker-cache): New procedure. (%standard-phases): Add it. * guix/build-system/gnu.scm (gnu-build, gnu-cross-build): Add #:make-dynamic-linker-cache? and honor it. --- guix/build-system/gnu.scm | 4 ++ guix/build/gnu-build-system.scm | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/guix/build-system/gnu.scm b/guix/build-system/gnu.scm index 2c23197e77..d6c4dc9bbc 100644 --- a/guix/build-system/gnu.scm +++ b/guix/build-system/gnu.scm @@ -342,6 +342,7 @@ standard packages used as implicit inputs of the GNU build system." (strip-directories ''("lib" "lib64" "libexec" "bin" "sbin")) (validate-runpath? #t) + (make-dynamic-linker-cache? #t) (license-file-regexp %license-file-regexp) (phases '%standard-phases) (locale "en_US.utf8") @@ -410,6 +411,7 @@ packages that must not be referenced." #:patch-shebangs? ,patch-shebangs? #:strip-binaries? ,strip-binaries? #:validate-runpath? ,validate-runpath? + #:make-dynamic-linker-cache? ,make-dynamic-linker-cache? #:license-file-regexp ,license-file-regexp #:strip-flags ,strip-flags #:strip-directories ,strip-directories))) @@ -497,6 +499,7 @@ is one of `host' or `target'." (strip-directories ''("lib" "lib64" "libexec" "bin" "sbin")) (validate-runpath? #t) + (make-dynamic-linker-cache? #t) (license-file-regexp %license-file-regexp) (phases '%standard-phases) (locale "en_US.utf8") @@ -577,6 +580,7 @@ platform." #:patch-shebangs? ,patch-shebangs? #:strip-binaries? ,strip-binaries? #:validate-runpath? ,validate-runpath? + #:make-dynamic-linker-cache? ,make-dynamic-linker-cache? #:license-file-regexp ,license-file-regexp #:strip-flags ,strip-flags #:strip-directories ,strip-directories)))) diff --git a/guix/build/gnu-build-system.scm b/guix/build/gnu-build-system.scm index 8fa11f4ea9..194cddc047 100644 --- a/guix/build/gnu-build-system.scm +++ b/guix/build/gnu-build-system.scm @@ -712,6 +712,78 @@ which cannot be found~%" (which binary) rest))))))))) outputs)) +(define* (make-dynamic-linker-cache #:key outputs + (make-dynamic-linker-cache? #t) + #:allow-other-keys) + "Create a dynamic linker cache under 'etc/ld.so.cache' in each of the +OUTPUTS. This reduces application startup time by avoiding the 'stat' storm +that traversing all the RUNPATH entries entails." + (define (make-cache-for-output directory) + (define bin-directories + (filter-map (lambda (sub-directory) + (let ((directory (string-append directory "/" + sub-directory))) + (and (directory-exists? directory) + directory))) + '("bin" "sbin"))) + + (define programs + ;; Programs that can benefit from the ld.so cache. These programs must + ;; be in a directory such that: + ;; + ;; (string-append (dirname PROGRAM) "../etc/ld.so.cache") + ;; + ;; potentially exists since that's what ld.so will look for. Thus, + ;; something like 'libexec/foo/PROGRAM' is not a valid candidate. + (append-map (lambda (directory) + (if (directory-exists? directory) + (filter-map (lambda (file) + (let ((file (string-append + directory "/" file))) + (and (executable-file? file) + (not (file-is-directory? file)) + (elf-file? file) + file))) + (scandir directory)) + '())) + bin-directories)) + + (define runpaths + ;; The union of RUNPATH entries. + (delete-duplicates + (append-map (lambda (program) + (or (file-runpath program) '())) + programs))) + + (define cache-file + (string-append directory "/etc/ld.so.cache")) + + (unless (null? runpaths) + (mkdir-p (dirname cache-file)) + (guard (c ((invoke-error? c) + ;; Do not treat 'ldconfig' failure as an error. + (format (current-error-port) + "warning: 'ldconfig' failed:~%") + (report-invoke-error c (current-error-port)))) + ;; Create a config file to tell 'ldconfig' where to look for the + ;; libraries that PROGRAMS need. + (call-with-output-file "/tmp/ld.so.conf" + (lambda (port) + (for-each (lambda (directory) + (display directory port) + (newline port)) + runpaths))) + + (invoke "ldconfig" "-f" "/tmp/ld.so.conf" "-C" cache-file) + (format #t "created '~a' from ~a library search path entries~%" + cache-file (length runpaths))))) + + (if make-dynamic-linker-cache? + (match outputs + (((_ . directories) ...) + (for-each make-cache-for-output directories))) + (format #t "ld.so cache not built~%"))) + (define %license-file-regexp ;; Regexp matching license files. "^(COPYING.*|LICEN[CS]E.*|[Ll]icen[cs]e.*|Copy[Rr]ight(\\.(txt|md))?)$") @@ -791,6 +863,7 @@ which cannot be found~%" validate-documentation-location delete-info-dir-file patch-dot-desktop-files + make-dynamic-linker-cache install-license-files reset-gzip-timestamps compress-documentation))) -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Sat, 28 Nov 2020 10:25:02 GMT) Full text and rfc822 format available.Message #17 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH v2 1/4] gremlin: Fix typo in docstring. Date: Sat, 28 Nov 2020 11:24:05 +0100
* guix/build/gremlin.scm (file-runpath): Fix typo. --- guix/build/gremlin.scm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guix/build/gremlin.scm b/guix/build/gremlin.scm index 6857e47b99..44604827a9 100644 --- a/guix/build/gremlin.scm +++ b/guix/build/gremlin.scm @@ -250,7 +250,7 @@ info." (elf-dynamic-info (parse-elf (get-bytevector-all port)))))) (define (file-runpath file) - "Return the DT_RUNPATH dynamic entry of FILE as a list of string, or #f if + "Return the DT_RUNPATH dynamic entry of FILE as a list of strings, or #f if FILE lacks dynamic info." (and=> (file-dynamic-info file) elf-dynamic-info-runpath)) -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Sat, 28 Nov 2020 10:25:02 GMT) Full text and rfc822 format available.Message #20 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH v2 2/4] gremlin: Add 'file-needed/recursive'. Date: Sat, 28 Nov 2020 11:24:06 +0100
* guix/build/gremlin.scm (file-needed/recursive): New procedure. * tests/gremlin.scm ("file-needed/recursive"): New test. --- guix/build/gremlin.scm | 41 +++++++++++++++++++++++++++++++++++++++++ tests/gremlin.scm | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/guix/build/gremlin.scm b/guix/build/gremlin.scm index 44604827a9..d56984b85e 100644 --- a/guix/build/gremlin.scm +++ b/guix/build/gremlin.scm @@ -44,6 +44,7 @@ file-dynamic-info file-runpath file-needed + file-needed/recursive missing-runpath-error? missing-runpath-error-file @@ -259,6 +260,46 @@ FILE lacks dynamic info." dynamic info." (and=> (file-dynamic-info file) elf-dynamic-info-needed)) +(define (file-needed/recursive file) + "Return two values: the list of absolute .so file names FILE depends on, +recursively, and the list of .so file names that could not be found. File +names are resolved by searching the RUNPATH of the file that NEEDs them. + +This is similar to the info returned by the 'ldd' command." + (let loop ((files (list file)) + (result '()) + (not-found '())) + (match files + (() + (values (reverse result) + (reverse (delete-duplicates not-found)))) + ((file . rest) + (match (file-dynamic-info (pk 'file file)) + (#f + (loop rest result not-found)) + (info + (let ((runpath (elf-dynamic-info-runpath info)) + (needed (elf-dynamic-info-needed info))) + (if (and runpath needed) + (let* ((runpath (map (cute expand-origin <> (dirname file)) + runpath)) + (resolved (map (cut search-path runpath <>) + needed)) + (failed (filter-map (lambda (needed resolved) + (and (not resolved) + (not (libc-library? needed)) + needed)) + needed resolved)) + (needed (remove (lambda (value) + (or (not value) + ;; XXX: quadratic + (member value result))) + resolved))) + (loop (append rest needed) + (append needed result) + (append failed not-found))) + (loop rest result not-found))))))))) + (define %libc-libraries ;; List of libraries as of glibc 2.21 (there are more but those are ;; typically mean to be LD_PRELOADed and thus do not appear as NEEDED.) diff --git a/tests/gremlin.scm b/tests/gremlin.scm index f191adb8b3..9ddac14265 100644 --- a/tests/gremlin.scm +++ b/tests/gremlin.scm @@ -27,6 +27,8 @@ #:use-module (srfi srfi-64) #:use-module (rnrs io ports) #:use-module (ice-9 popen) + #:use-module (ice-9 rdelim) + #:use-module (ice-9 regex) #:use-module (ice-9 match)) (define %guile-executable @@ -58,6 +60,40 @@ (string-take lib (string-contains lib ".so"))) (elf-dynamic-info-needed dyninfo)))))) +(unless (and %guile-executable (not (getenv "LD_LIBRARY_PATH")) + (file-needed %guile-executable)) ;statically linked? + (test-skip 1)) +(test-assert "file-needed/recursive" + (let* ((needed (file-needed/recursive %guile-executable)) + (pipe (dynamic-wind + (lambda () + ;; Tell ld.so to list loaded objects, like 'ldd' does. + (setenv "LD_TRACE_LOADED_OBJECTS" "yup")) + (lambda () + (open-pipe* OPEN_READ %guile-executable)) + (lambda () + (unsetenv "LD_TRACE_LOADED_OBJECTS"))))) + (define ldd-rx + (make-regexp "^[[:blank:]]+([[:graph:]]+ => )?([[:graph:]]+) .*$")) + + (define (read-ldd-output port) + ;; Read from PORT output in GNU ldd format. + (let loop ((result '())) + (match (read-line port) + ((? eof-object?) + (reverse result)) + ((= (cut regexp-exec ldd-rx <>) m) + (if m + (loop (cons (match:substring m 2) result)) + (loop result)))))) + + (define ground-truth + (remove (cut string-prefix? "linux-vdso.so" <>) + (read-ldd-output pipe))) + + (and (zero? (close-pipe pipe)) + (lset= string=? (pk 'truth ground-truth) (pk 'needed needed))))) + (test-equal "expand-origin" '("OOO/../lib" "OOO" -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Sat, 28 Nov 2020 10:25:03 GMT) Full text and rfc822 format available.Message #23 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH v2 4/4] build-system/gnu: Add 'make-dynamic-linker-cache' phase. Date: Sat, 28 Nov 2020 11:24:09 +0100
* guix/build/gnu-build-system.scm (make-dynamic-linker-cache): New procedure. (%standard-phases): Add it. * guix/build-system/gnu.scm (gnu-build, gnu-cross-build): Add #:make-dynamic-linker-cache? and honor it. --- guix/build-system/gnu.scm | 4 ++ guix/build/gnu-build-system.scm | 68 +++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/guix/build-system/gnu.scm b/guix/build-system/gnu.scm index 2c23197e77..d6c4dc9bbc 100644 --- a/guix/build-system/gnu.scm +++ b/guix/build-system/gnu.scm @@ -342,6 +342,7 @@ standard packages used as implicit inputs of the GNU build system." (strip-directories ''("lib" "lib64" "libexec" "bin" "sbin")) (validate-runpath? #t) + (make-dynamic-linker-cache? #t) (license-file-regexp %license-file-regexp) (phases '%standard-phases) (locale "en_US.utf8") @@ -410,6 +411,7 @@ packages that must not be referenced." #:patch-shebangs? ,patch-shebangs? #:strip-binaries? ,strip-binaries? #:validate-runpath? ,validate-runpath? + #:make-dynamic-linker-cache? ,make-dynamic-linker-cache? #:license-file-regexp ,license-file-regexp #:strip-flags ,strip-flags #:strip-directories ,strip-directories))) @@ -497,6 +499,7 @@ is one of `host' or `target'." (strip-directories ''("lib" "lib64" "libexec" "bin" "sbin")) (validate-runpath? #t) + (make-dynamic-linker-cache? #t) (license-file-regexp %license-file-regexp) (phases '%standard-phases) (locale "en_US.utf8") @@ -577,6 +580,7 @@ platform." #:patch-shebangs? ,patch-shebangs? #:strip-binaries? ,strip-binaries? #:validate-runpath? ,validate-runpath? + #:make-dynamic-linker-cache? ,make-dynamic-linker-cache? #:license-file-regexp ,license-file-regexp #:strip-flags ,strip-flags #:strip-directories ,strip-directories)))) diff --git a/guix/build/gnu-build-system.scm b/guix/build/gnu-build-system.scm index 8fa11f4ea9..5f08b9d6ac 100644 --- a/guix/build/gnu-build-system.scm +++ b/guix/build/gnu-build-system.scm @@ -712,6 +712,73 @@ which cannot be found~%" (which binary) rest))))))))) outputs)) +(define* (make-dynamic-linker-cache #:key outputs + (make-dynamic-linker-cache? #t) + #:allow-other-keys) + "Create a dynamic linker cache under 'etc/ld.so.cache' in each of the +OUTPUTS. This reduces application startup time by avoiding the 'stat' storm +that traversing all the RUNPATH entries entails." + (define (make-cache-for-output directory) + (define bin-directories + (filter-map (lambda (sub-directory) + (let ((directory (string-append directory "/" + sub-directory))) + (and (directory-exists? directory) + directory))) + '("bin" "sbin" "libexec"))) + + (define programs + ;; Programs that can benefit from the ld.so cache. + (append-map (lambda (directory) + (if (directory-exists? directory) + (find-files directory + (lambda (file stat) + (and (executable-file? file) + (elf-file? file)))) + '())) + bin-directories)) + + (define library-path + ;; Directories containing libraries that PROGRAMS depend on, + ;; recursively. + (delete-duplicates + (append-map (lambda (program) + (map dirname (file-needed/recursive program))) + programs))) + + (define cache-file + (string-append directory "/etc/ld.so.cache")) + + (define ld.so.conf + (string-append (or (getenv "TMPDIR") "/tmp") + "/ld.so.conf")) + + (unless (null? library-path) + (mkdir-p (dirname cache-file)) + (guard (c ((invoke-error? c) + ;; Do not treat 'ldconfig' failure as an error. + (format (current-error-port) + "warning: 'ldconfig' failed:~%") + (report-invoke-error c (current-error-port)))) + ;; Create a config file to tell 'ldconfig' where to look for the + ;; libraries that PROGRAMS need. + (call-with-output-file ld.so.conf + (lambda (port) + (for-each (lambda (directory) + (display directory port) + (newline port)) + library-path))) + + (invoke "ldconfig" "-f" ld.so.conf "-C" cache-file) + (format #t "created '~a' from ~a library search path entries~%" + cache-file (length library-path))))) + + (if make-dynamic-linker-cache? + (match outputs + (((_ . directories) ...) + (for-each make-cache-for-output directories))) + (format #t "ld.so cache not built~%"))) + (define %license-file-regexp ;; Regexp matching license files. "^(COPYING.*|LICEN[CS]E.*|[Ll]icen[cs]e.*|Copy[Rr]ight(\\.(txt|md))?)$") @@ -791,6 +858,7 @@ which cannot be found~%" validate-documentation-location delete-info-dir-file patch-dot-desktop-files + make-dynamic-linker-cache install-license-files reset-gzip-timestamps compress-documentation))) -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Sat, 28 Nov 2020 10:25:03 GMT) Full text and rfc822 format available.Message #26 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH v2 0/4] Using 'ld.so.cache' to speed up application startup Date: Sat, 28 Nov 2020 11:24:04 +0100
Hi! This new version addresses the shortcomings I mentioned earlier and other issues reported on IRC: • ld.so no longer uses “../etc/ld.so.cache”. Instead, it (1) ensures $ORIGIN is in the store, (2) extracts the store file name, and (3) appends “/etc/ld.so.cache”. IOW, the ‘ld.so.cache’ is always resolved relative to the store directory $ORIGIN belongs to, not relative to $ORIGIN itself. Thinking about it, it’s a direct translation of the ld.so.cache model from FHS to the functional model where a system-wide /etc/ld.so.cache makes no sense. • ‘make-dynamic-linker-cache’ now creates an ‘ld.so.conf’ that contains all the dependencies, recursively, as would be returned by ‘ldd’. The new ‘file-needed/recursive’ procedure returns the list of shared objects depended on like ‘ldd’. • ‘make-dynamic-linker-cache’ creates ‘ld.so.conf’ in $TMPDIR rather than hard-code /tmp, so as to be friendlier to ‘--disable-chroot’ builds (as is currently used on GNU/Hurd). I’m rather happy and confident with that version. :-) Feedback welcome! Ludo’. Ludovic Courtès (4): gremlin: Fix typo in docstring. gremlin: Add 'file-needed/recursive'. gnu: glibc: Load 'etc/ld.so.cache' in $ORIGIN's store item when available. build-system/gnu: Add 'make-dynamic-linker-cache' phase. gnu/local.mk | 1 + gnu/packages/base.scm | 16 +-- gnu/packages/patches/glibc-dl-cache.patch | 140 ++++++++++++++++++++++ guix/build-system/gnu.scm | 4 + guix/build/gnu-build-system.scm | 68 +++++++++++ guix/build/gremlin.scm | 43 ++++++- tests/gremlin.scm | 36 ++++++ 7 files changed, 297 insertions(+), 11 deletions(-) create mode 100644 gnu/packages/patches/glibc-dl-cache.patch -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Sat, 28 Nov 2020 10:25:03 GMT) Full text and rfc822 format available.Message #29 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH v2 3/4] gnu: glibc: Load 'etc/ld.so.cache' in $ORIGIN's store item when available. Date: Sat, 28 Nov 2020 11:24:07 +0100
* gnu/packages/patches/glibc-dl-cache.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/base.scm (glibc)[source]: Remove 'snippet' and 'modules'. [arguments]: In 'pre-configure' phase, substitute @STORE_DIRECTORY@ in 'elf/dl-cache.c'. --- gnu/local.mk | 1 + gnu/packages/base.scm | 16 +-- gnu/packages/patches/glibc-dl-cache.patch | 140 ++++++++++++++++++++++ 3 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 gnu/packages/patches/glibc-dl-cache.patch diff --git a/gnu/local.mk b/gnu/local.mk index f9fed30a3f..82c3c608c6 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1051,6 +1051,7 @@ dist_patch_DATA = \ %D%/packages/patches/glibc-bootstrap-system-2.2.5.patch \ %D%/packages/patches/glibc-bootstrap-system-2.16.0.patch \ %D%/packages/patches/glibc-bootstrap-system.patch \ + %D%/packages/patches/glibc-dl-cache.patch \ %D%/packages/patches/glibc-hidden-visibility-ldconfig.patch \ %D%/packages/patches/glibc-hurd-clock_gettime_monotonic.patch \ %D%/packages/patches/glibc-hurd-clock_t_centiseconds.patch \ diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm index bd352319a1..ad4415f226 100644 --- a/gnu/packages/base.scm +++ b/gnu/packages/base.scm @@ -675,17 +675,8 @@ the store.") (sha256 (base32 "0di848ibffrnwq7g2dvgqrnn4xqhj3h96csn69q4da51ymafl9qn")) - (snippet - ;; Disable 'ldconfig' and /etc/ld.so.cache. The latter is - ;; required on LFS distros to avoid loading the distro's libc.so - ;; instead of ours. - '(begin - (substitute* "sysdeps/unix/sysv/linux/configure" - (("use_ldconfig=yes") - "use_ldconfig=no")) - #t)) - (modules '((guix build utils))) (patches (search-patches "glibc-ldd-x86_64.patch" + "glibc-dl-cache.patch" "glibc-hidden-visibility-ldconfig.patch" "glibc-versioned-locpath.patch" "glibc-allow-kernel-2.6.32.patch" @@ -800,6 +791,11 @@ the store.") ;; 4.7.1. ((" -lgcc_s") "")) + ;; Tell the ld.so cache code where the store is. + (substitute* "elf/dl-cache.c" + (("@STORE_DIRECTORY@") + (string-append "\"" (%store-directory) "\""))) + ;; Have `system' use that Bash. (substitute* "sysdeps/posix/system.c" (("#define[[:blank:]]+SHELL_PATH.*$") diff --git a/gnu/packages/patches/glibc-dl-cache.patch b/gnu/packages/patches/glibc-dl-cache.patch new file mode 100644 index 0000000000..0f23b12add --- /dev/null +++ b/gnu/packages/patches/glibc-dl-cache.patch @@ -0,0 +1,140 @@ +Read the shared library cache relative to $ORIGIN instead of reading +from /etc/ld.so.cache. Also arrange so that this cache takes +precedence over RUNPATH. + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 93d185e788..e0760a1f40 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -171,6 +171,51 @@ _dl_cache_libcmp (const char *p1, const char *p2) + return *p1 - *p2; + } + ++/* Special value representing the lack of an ld.so cache. */ ++static const char ld_so_cache_lacking[] = "/ld.so cache is lacking"; ++ ++/* Return the per-application ld.so cache, relative to $ORIGIN, or NULL if ++ that fails for some reason. Do not return the system-wide LD_SO_CACHE ++ since on a foreign distro it would contain invalid information. */ ++static const char * ++ld_so_cache (void) ++{ ++ static const char *loader_cache; ++ ++ if (loader_cache == NULL) ++ { ++ static const char store[] = "/gnu/store"; ++ const char *origin = _dl_get_origin (); ++ ++ /* Check whether ORIGIN is something like "/gnu/store/…-foo/bin". */ ++ if (strncmp (store, origin, strlen (store)) == 0 ++ && origin[sizeof store - 1] == '/') ++ { ++ char *store_item_end = strchr (origin + sizeof store, '/'); ++ ++ if (store_item_end != NULL) ++ { ++ static const char suffix[] = "/etc/ld.so.cache"; ++ size_t store_item_len = store_item_end - origin; ++ ++ /* Note: We can't use 'malloc' because it can be interposed. ++ Likewise, 'strncpy' is not available. */ ++ char *cache = alloca (strlen (origin) + sizeof suffix); ++ ++ strcpy (cache, origin); ++ strcpy (cache + store_item_len, suffix); ++ ++ loader_cache = __strdup (cache) ?: ld_so_cache_lacking; ++ } ++ else ++ loader_cache = ld_so_cache_lacking; ++ } ++ else ++ loader_cache = ld_so_cache_lacking; ++ } ++ ++ return loader_cache; ++} + + /* Look up NAME in ld.so.cache and return the file name stored there, or null + if none is found. The cache is loaded if it was not already. If loading +@@ -190,12 +235,15 @@ _dl_load_cache_lookup (const char *name) + + /* Print a message if the loading of libs is traced. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) +- _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE); ++ _dl_debug_printf (" search cache=%s\n", ld_so_cache ()); ++ ++ if (__glibc_unlikely (ld_so_cache () == ld_so_cache_lacking)) ++ return NULL; + + if (cache == NULL) + { + /* Read the contents of the file. */ +- void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize, ++ void *file = _dl_sysdep_read_whole_file (ld_so_cache (), &cachesize, + PROT_READ); + + /* We can handle three different cache file formats here: +diff --git a/elf/dl-load.c b/elf/dl-load.c +index f3201e7c14..a69aec3428 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -2152,28 +2152,6 @@ _dl_map_object (struct link_map *loader, const char *name, + loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, + LA_SER_LIBPATH, &found_other_class); + +- /* Look at the RUNPATH information for this binary. */ +- if (fd == -1 && loader != NULL +- && cache_rpath (loader, &loader->l_runpath_dirs, +- DT_RUNPATH, "RUNPATH")) +- fd = open_path (name, namelen, mode, +- &loader->l_runpath_dirs, &realname, &fb, loader, +- LA_SER_RUNPATH, &found_other_class); +- +- if (fd == -1) +- { +- realname = _dl_sysdep_open_object (name, namelen, &fd); +- if (realname != NULL) +- { +- fd = open_verify (realname, fd, +- &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, +- LA_SER_CONFIG, mode, &found_other_class, +- false); +- if (fd == -1) +- free (realname); +- } +- } +- + #ifdef USE_LDCONFIG + if (fd == -1 + && (__glibc_likely ((mode & __RTLD_SECURE) == 0) +@@ -2232,6 +2210,28 @@ _dl_map_object (struct link_map *loader, const char *name, + } + #endif + ++ /* Look at the RUNPATH information for this binary. */ ++ if (fd == -1 && loader != NULL ++ && cache_rpath (loader, &loader->l_runpath_dirs, ++ DT_RUNPATH, "RUNPATH")) ++ fd = open_path (name, namelen, mode, ++ &loader->l_runpath_dirs, &realname, &fb, loader, ++ LA_SER_RUNPATH, &found_other_class); ++ ++ if (fd == -1) ++ { ++ realname = _dl_sysdep_open_object (name, namelen, &fd); ++ if (realname != NULL) ++ { ++ fd = open_verify (realname, fd, ++ &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, ++ LA_SER_CONFIG, mode, &found_other_class, ++ false); ++ if (fd == -1) ++ free (realname); ++ } ++ } ++ + /* Finally, try the default path. */ + if (fd == -1 + && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL -- 2.29.2
guix-patches <at> gnu.org
:bug#44899
; Package guix-patches
.
(Sat, 28 Nov 2020 10:25:04 GMT) Full text and rfc822 format available.Message #32 received at 44899 <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899 <at> debbugs.gnu.org Cc: Ludovic Courtès <ludo <at> gnu.org> Subject: [PATCH v2 3/4] gnu: glibc: Load ${ORIGIN}/../etc/ld.so.cache when available. Date: Sat, 28 Nov 2020 11:24:08 +0100
* gnu/packages/patches/glibc-dl-cache.patch: New file. * gnu/local.mk (dist_patch_DATA): Add it. * gnu/packages/base.scm (glibc)[source]: Remove 'snippet' and 'modules'. [arguments]: In 'pre-configure' phase, substitute @STORE_DIRECTORY@ in 'elf/dl-cache.c'. --- gnu/local.mk | 1 + gnu/packages/base.scm | 16 +-- gnu/packages/patches/glibc-dl-cache.patch | 140 ++++++++++++++++++++++ 3 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 gnu/packages/patches/glibc-dl-cache.patch diff --git a/gnu/local.mk b/gnu/local.mk index f9fed30a3f..82c3c608c6 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1051,6 +1051,7 @@ dist_patch_DATA = \ %D%/packages/patches/glibc-bootstrap-system-2.2.5.patch \ %D%/packages/patches/glibc-bootstrap-system-2.16.0.patch \ %D%/packages/patches/glibc-bootstrap-system.patch \ + %D%/packages/patches/glibc-dl-cache.patch \ %D%/packages/patches/glibc-hidden-visibility-ldconfig.patch \ %D%/packages/patches/glibc-hurd-clock_gettime_monotonic.patch \ %D%/packages/patches/glibc-hurd-clock_t_centiseconds.patch \ diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm index bd352319a1..ad4415f226 100644 --- a/gnu/packages/base.scm +++ b/gnu/packages/base.scm @@ -675,17 +675,8 @@ the store.") (sha256 (base32 "0di848ibffrnwq7g2dvgqrnn4xqhj3h96csn69q4da51ymafl9qn")) - (snippet - ;; Disable 'ldconfig' and /etc/ld.so.cache. The latter is - ;; required on LFS distros to avoid loading the distro's libc.so - ;; instead of ours. - '(begin - (substitute* "sysdeps/unix/sysv/linux/configure" - (("use_ldconfig=yes") - "use_ldconfig=no")) - #t)) - (modules '((guix build utils))) (patches (search-patches "glibc-ldd-x86_64.patch" + "glibc-dl-cache.patch" "glibc-hidden-visibility-ldconfig.patch" "glibc-versioned-locpath.patch" "glibc-allow-kernel-2.6.32.patch" @@ -800,6 +791,11 @@ the store.") ;; 4.7.1. ((" -lgcc_s") "")) + ;; Tell the ld.so cache code where the store is. + (substitute* "elf/dl-cache.c" + (("@STORE_DIRECTORY@") + (string-append "\"" (%store-directory) "\""))) + ;; Have `system' use that Bash. (substitute* "sysdeps/posix/system.c" (("#define[[:blank:]]+SHELL_PATH.*$") diff --git a/gnu/packages/patches/glibc-dl-cache.patch b/gnu/packages/patches/glibc-dl-cache.patch new file mode 100644 index 0000000000..0f23b12add --- /dev/null +++ b/gnu/packages/patches/glibc-dl-cache.patch @@ -0,0 +1,140 @@ +Read the shared library cache relative to $ORIGIN instead of reading +from /etc/ld.so.cache. Also arrange so that this cache takes +precedence over RUNPATH. + +diff --git a/elf/dl-cache.c b/elf/dl-cache.c +index 93d185e788..e0760a1f40 100644 +--- a/elf/dl-cache.c ++++ b/elf/dl-cache.c +@@ -171,6 +171,51 @@ _dl_cache_libcmp (const char *p1, const char *p2) + return *p1 - *p2; + } + ++/* Special value representing the lack of an ld.so cache. */ ++static const char ld_so_cache_lacking[] = "/ld.so cache is lacking"; ++ ++/* Return the per-application ld.so cache, relative to $ORIGIN, or NULL if ++ that fails for some reason. Do not return the system-wide LD_SO_CACHE ++ since on a foreign distro it would contain invalid information. */ ++static const char * ++ld_so_cache (void) ++{ ++ static const char *loader_cache; ++ ++ if (loader_cache == NULL) ++ { ++ static const char store[] = "/gnu/store"; ++ const char *origin = _dl_get_origin (); ++ ++ /* Check whether ORIGIN is something like "/gnu/store/…-foo/bin". */ ++ if (strncmp (store, origin, strlen (store)) == 0 ++ && origin[sizeof store - 1] == '/') ++ { ++ char *store_item_end = strchr (origin + sizeof store, '/'); ++ ++ if (store_item_end != NULL) ++ { ++ static const char suffix[] = "/etc/ld.so.cache"; ++ size_t store_item_len = store_item_end - origin; ++ ++ /* Note: We can't use 'malloc' because it can be interposed. ++ Likewise, 'strncpy' is not available. */ ++ char *cache = alloca (strlen (origin) + sizeof suffix); ++ ++ strcpy (cache, origin); ++ strcpy (cache + store_item_len, suffix); ++ ++ loader_cache = __strdup (cache) ?: ld_so_cache_lacking; ++ } ++ else ++ loader_cache = ld_so_cache_lacking; ++ } ++ else ++ loader_cache = ld_so_cache_lacking; ++ } ++ ++ return loader_cache; ++} + + /* Look up NAME in ld.so.cache and return the file name stored there, or null + if none is found. The cache is loaded if it was not already. If loading +@@ -190,12 +235,15 @@ _dl_load_cache_lookup (const char *name) + + /* Print a message if the loading of libs is traced. */ + if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)) +- _dl_debug_printf (" search cache=%s\n", LD_SO_CACHE); ++ _dl_debug_printf (" search cache=%s\n", ld_so_cache ()); ++ ++ if (__glibc_unlikely (ld_so_cache () == ld_so_cache_lacking)) ++ return NULL; + + if (cache == NULL) + { + /* Read the contents of the file. */ +- void *file = _dl_sysdep_read_whole_file (LD_SO_CACHE, &cachesize, ++ void *file = _dl_sysdep_read_whole_file (ld_so_cache (), &cachesize, + PROT_READ); + + /* We can handle three different cache file formats here: +diff --git a/elf/dl-load.c b/elf/dl-load.c +index f3201e7c14..a69aec3428 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -2152,28 +2152,6 @@ _dl_map_object (struct link_map *loader, const char *name, + loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded, + LA_SER_LIBPATH, &found_other_class); + +- /* Look at the RUNPATH information for this binary. */ +- if (fd == -1 && loader != NULL +- && cache_rpath (loader, &loader->l_runpath_dirs, +- DT_RUNPATH, "RUNPATH")) +- fd = open_path (name, namelen, mode, +- &loader->l_runpath_dirs, &realname, &fb, loader, +- LA_SER_RUNPATH, &found_other_class); +- +- if (fd == -1) +- { +- realname = _dl_sysdep_open_object (name, namelen, &fd); +- if (realname != NULL) +- { +- fd = open_verify (realname, fd, +- &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, +- LA_SER_CONFIG, mode, &found_other_class, +- false); +- if (fd == -1) +- free (realname); +- } +- } +- + #ifdef USE_LDCONFIG + if (fd == -1 + && (__glibc_likely ((mode & __RTLD_SECURE) == 0) +@@ -2232,6 +2210,28 @@ _dl_map_object (struct link_map *loader, const char *name, + } + #endif + ++ /* Look at the RUNPATH information for this binary. */ ++ if (fd == -1 && loader != NULL ++ && cache_rpath (loader, &loader->l_runpath_dirs, ++ DT_RUNPATH, "RUNPATH")) ++ fd = open_path (name, namelen, mode, ++ &loader->l_runpath_dirs, &realname, &fb, loader, ++ LA_SER_RUNPATH, &found_other_class); ++ ++ if (fd == -1) ++ { ++ realname = _dl_sysdep_open_object (name, namelen, &fd); ++ if (realname != NULL) ++ { ++ fd = open_verify (realname, fd, ++ &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded, ++ LA_SER_CONFIG, mode, &found_other_class, ++ false); ++ if (fd == -1) ++ free (realname); ++ } ++ } ++ + /* Finally, try the default path. */ + if (fd == -1 + && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL -- 2.29.2
Ludovic Courtès <ludo <at> gnu.org>
:Ludovic Courtès <ludo <at> gnu.org>
:Message #37 received at 44899-done <at> debbugs.gnu.org (full text, mbox):
From: Ludovic Courtès <ludo <at> gnu.org> To: 44899-done <at> debbugs.gnu.org Subject: Re: [bug#44899] [PATCH v2 0/4] Using 'ld.so.cache' to speed up application startup Date: Tue, 01 Dec 2020 21:45:24 +0100
Ludovic Courtès <ludo <at> gnu.org> skribis: > gremlin: Fix typo in docstring. > gremlin: Add 'file-needed/recursive'. > gnu: glibc: Load 'etc/ld.so.cache' in $ORIGIN's store item when > available. > build-system/gnu: Add 'make-dynamic-linker-cache' phase. Pushed as f85efa86e7690d9181946351631e02b1c20958c9, sans hard-coded /gnu/store in the patch as reported by Ricardo on IRC and debugging leftover in gremlin.scm. Enjoy… and report any issues you may find! :-) Ludo’.
Debbugs Internal Request <help-debbugs <at> gnu.org>
to internal_control <at> debbugs.gnu.org
.
(Wed, 30 Dec 2020 12:24:08 GMT) Full text and rfc822 format available.
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.