unofficial mirror of guix-patches@gnu.org 
 help / color / mirror / code / Atom feed
* [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin)
@ 2018-04-18 16:38 Ludovic Courtès
  2018-04-18 16:40 ` [bug#31208] [PATCH 1/3] gremlin: Preserve offset info for dynamic entries Ludovic Courtès
  2018-05-04 20:52 ` [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin) Ludovic Courtès
  0 siblings, 2 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-04-18 16:38 UTC (permalink / raw)
  To: 31208

Hello!

As discussed before, this patch set is a first stab at getting rid of
PatchELF (which has portability issues) in particular in the Meson build
system.  (The patches are for the next ‘core-updates’.)

The second patch adds ‘strip-runpath’.  It doesn’t add ‘augment-rpath’
though, because that’s a bit more involved (it needs to grow the string
table and the section it’s in), and so I wanted to make sure we really
need it first.  :-)

In the discussion of ‘meson-build-system’ in
<https://debbugs.gnu.org/cgi/bugreport.cgi?bug=28444>, we didn’t discuss
this specific part.  Peter & Marius: can you explain whether/why this is
needed?

Thanks,
Ludo’.

Ludovic Courtès (3):
  gremlin: Preserve offset info for dynamic entries.
  gremlin: Add 'strip-runpath'.
  build-system/meson: Use 'strip-runpath' instead of PatchELF.

 guix/build/gremlin.scm            | 130 +++++++++++++++++++++---------
 guix/build/meson-build-system.scm |   2 +-
 tests/gremlin.scm                 |  35 +++++++-
 3 files changed, 129 insertions(+), 38 deletions(-)

-- 
2.17.0

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [bug#31208] [PATCH 1/3] gremlin: Preserve offset info for dynamic entries.
  2018-04-18 16:38 [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin) Ludovic Courtès
@ 2018-04-18 16:40 ` Ludovic Courtès
  2018-04-18 16:40   ` [bug#31208] [PATCH 2/3] gremlin: Add 'strip-runpath' Ludovic Courtès
  2018-04-18 16:40   ` [bug#31208] [PATCH 3/3] build-system/meson: Use 'strip-runpath' instead of PatchELF Ludovic Courtès
  2018-05-04 20:52 ` [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin) Ludovic Courtès
  1 sibling, 2 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-04-18 16:40 UTC (permalink / raw)
  To: 31208

* guix/build/gremlin.scm (<dynamic-entry>): New record type.
(raw-dynamic-entries): Return a list of <dynamic-entry>.
(dynamic-entries): Adjust accordingly and return a list of <dynamic-entry>.
(elf-dynamic-info)[matching-entry]: New procedure.
Use it.
---
 guix/build/gremlin.scm | 84 ++++++++++++++++++++++++------------------
 1 file changed, 49 insertions(+), 35 deletions(-)

diff --git a/guix/build/gremlin.scm b/guix/build/gremlin.scm
index bb019967e..78d133311 100644
--- a/guix/build/gremlin.scm
+++ b/guix/build/gremlin.scm
@@ -99,10 +99,16 @@ dynamic linking information."
 ;;     } d_un;
 ;; } Elf64_Dyn;
 
+(define-record-type <dynamic-entry>
+  (dynamic-entry type value offset)
+  dynamic-entry?
+  (type   dynamic-entry-type)                     ;DT_*
+  (value  dynamic-entry-value)                    ;string | number | ...
+  (offset dynamic-entry-offset))                  ;integer
+
 (define (raw-dynamic-entries elf segment)
-  "Return as a list of type/value pairs all the dynamic entries found in
-SEGMENT, the 'PT_DYNAMIC' segment of ELF.  In the result, each car is a DT_
-value, and the interpretation of the cdr depends on the type."
+  "Return as a list of <dynamic-entry> for the dynamic entries found in
+SEGMENT, the 'PT_DYNAMIC' segment of ELF."
   (define start
     (elf-segment-offset segment))
   (define bytes
@@ -123,7 +129,9 @@ value, and the interpretation of the cdr depends on the type."
           (if (= type DT_NULL)                    ;finished?
               (reverse result)
               (loop (+ offset (* 2 word-size))
-                    (alist-cons type value result)))))))
+                    (cons (dynamic-entry type value
+                                         (+ start offset word-size))
+                          result)))))))
 
 (define (vma->offset elf vma)
   "Convert VMA, a virtual memory address, to an offset within ELF.
@@ -148,35 +156,33 @@ offset."
 
 (define (dynamic-entries elf segment)
   "Return all the dynamic entries found in SEGMENT, the 'PT_DYNAMIC' segment
-of ELF, as a list of type/value pairs.  The type is a DT_ value, and the value
-may be a string or an integer depending on the entry type (for instance, the
-value of DT_NEEDED entries is a string.)"
+of ELF, as a list of <dynamic-entry>.  The value of each entry may be a string
+or an integer depending on the entry type (for instance, the value of
+DT_NEEDED entries is a string.)  Likewise the offset is the offset within the
+string table if the type is a string."
   (define entries
     (raw-dynamic-entries elf segment))
 
   (define string-table-offset
-    (any (match-lambda
-            ((type . value)
-             (and (= type DT_STRTAB) value))
-            (_ #f))
+    (any (lambda (entry)
+           (and (= (dynamic-entry-type entry) DT_STRTAB)
+                (dynamic-entry-value entry)))
          entries))
 
-  (define (interpret-dynamic-entry type value)
-    (cond ((memv type (list DT_NEEDED DT_SONAME DT_RPATH DT_RUNPATH))
-           (if string-table-offset
-               (pointer->string
-                (bytevector->pointer (elf-bytes elf)
-                                     (vma->offset
-                                      elf
-                                      (+ string-table-offset value))))
-               value))
-          (else
-           value)))
+  (define (interpret-dynamic-entry entry)
+    (let ((type  (dynamic-entry-type entry))
+          (value (dynamic-entry-value entry)))
+      (cond ((memv type (list DT_NEEDED DT_SONAME DT_RPATH DT_RUNPATH))
+             (if string-table-offset
+                 (let* ((offset (vma->offset elf (+ string-table-offset value)))
+                        (value  (pointer->string
+                                 (bytevector->pointer (elf-bytes elf) offset))))
+                   (dynamic-entry type value offset))
+                 (dynamic-entry type value (dynamic-entry-offset entry))))
+            (else
+             (dynamic-entry type value (dynamic-entry-offset entry))))))
 
-  (map (match-lambda
-         ((type . value)
-          (cons type (interpret-dynamic-entry type value))))
-       entries))
+  (map interpret-dynamic-entry entries))
 
 \f
 ;;;
@@ -200,21 +206,29 @@ value of DT_NEEDED entries is a string.)"
 (define (elf-dynamic-info elf)
   "Return dynamic-link information for ELF as an <elf-dynamic-info> object, or
 #f if ELF lacks dynamic-link information."
+  (define (matching-entry type)
+    (lambda (entry)
+      (= type (dynamic-entry-type entry))))
+
   (match (dynamic-link-segment elf)
     (#f #f)
     ((? elf-segment? dynamic)
      (let ((entries (dynamic-entries elf dynamic)))
-       (%elf-dynamic-info (assv-ref entries DT_SONAME)
-                          (filter-map (match-lambda
-                                        ((type . value)
-                                         (and (= type DT_NEEDED) value))
-                                        (_ #f))
+       (%elf-dynamic-info (find (matching-entry DT_SONAME) entries)
+                          (filter-map (lambda (entry)
+                                        (and (= (dynamic-entry-type entry)
+                                                DT_NEEDED)
+                                             (dynamic-entry-value entry)))
                                       entries)
-                          (or (and=> (assv-ref entries DT_RPATH)
-                                     search-path->list)
+                          (or (and=> (find (matching-entry DT_RPATH)
+                                           entries)
+                                     (compose search-path->list
+                                              dynamic-entry-value))
                               '())
-                          (or (and=> (assv-ref entries DT_RUNPATH)
-                                     search-path->list)
+                          (or (and=> (find (matching-entry DT_RUNPATH)
+                                           entries)
+                                     (compose search-path->list
+                                              dynamic-entry-value))
                               '()))))))
 
 (define %libc-libraries
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [bug#31208] [PATCH 2/3] gremlin: Add 'strip-runpath'.
  2018-04-18 16:40 ` [bug#31208] [PATCH 1/3] gremlin: Preserve offset info for dynamic entries Ludovic Courtès
@ 2018-04-18 16:40   ` Ludovic Courtès
  2018-04-18 16:40   ` [bug#31208] [PATCH 3/3] build-system/meson: Use 'strip-runpath' instead of PatchELF Ludovic Courtès
  1 sibling, 0 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-04-18 16:40 UTC (permalink / raw)
  To: 31208

* guix/build/gremlin.scm (strip-runpath): New procedure.
* tests/gremlin.scm (c-compiler): New variable.
("strip-runpath"): New test.
---
 guix/build/gremlin.scm | 46 +++++++++++++++++++++++++++++++++++++++++-
 tests/gremlin.scm      | 35 +++++++++++++++++++++++++++++++-
 2 files changed, 79 insertions(+), 2 deletions(-)

diff --git a/guix/build/gremlin.scm b/guix/build/gremlin.scm
index 78d133311..e8ea66dfb 100644
--- a/guix/build/gremlin.scm
+++ b/guix/build/gremlin.scm
@@ -41,7 +41,8 @@
             elf-dynamic-info-runpath
             expand-origin
 
-            validate-needed-in-runpath))
+            validate-needed-in-runpath
+            strip-runpath))
 
 ;;; Commentary:
 ;;;
@@ -320,4 +321,47 @@ be found in RUNPATH ~s~%"
           ;;   (format (current-error-port) "~a is OK~%" file))
           (null? not-found))))))
 
+(define (strip-runpath file)
+  "Remove from the DT_RUNPATH of FILE any entries that are not necessary
+according to DT_NEEDED."
+  (define (minimal-runpath needed runpath)
+    (filter (lambda (directory)
+              (and (string-prefix? "/" directory)
+                   (any (lambda (lib)
+                          (file-exists? (string-append directory "/" lib)))
+                        needed)))
+            runpath))
+
+  (define port
+    (open-file file "r+b"))
+
+  (catch #t
+    (lambda ()
+      (let* ((elf      (parse-elf (get-bytevector-all port)))
+             (entries  (dynamic-entries elf (dynamic-link-segment elf)))
+             (needed   (filter-map (lambda (entry)
+                                     (and (= (dynamic-entry-type entry)
+                                             DT_NEEDED)
+                                          (dynamic-entry-value entry)))
+                                   entries))
+             (runpath  (find (lambda (entry)
+                               (= DT_RUNPATH (dynamic-entry-type entry)))
+                             entries))
+             (old      (search-path->list
+                        (dynamic-entry-value runpath)))
+             (new      (minimal-runpath needed old)))
+        (unless (equal? old new)
+          (format (current-error-port)
+                  "~a: stripping RUNPATH to ~s (removed ~s)~%"
+                  file new
+                  (lset-difference string=? old new))
+          (seek port (dynamic-entry-offset runpath) SEEK_SET)
+          (put-bytevector port (string->utf8 (string-join new ":")))
+          (put-u8 port 0))
+        (close-port port)
+        new))
+    (lambda (key . args)
+      (false-if-exception (close-port port))
+      (apply throw key args))))
+
 ;;; gremlin.scm ends here
diff --git a/tests/gremlin.scm b/tests/gremlin.scm
index 288555496..1b47d5c38 100644
--- a/tests/gremlin.scm
+++ b/tests/gremlin.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2015 Ludovic Courtès <ludo@gnu.org>
+;;; Copyright © 2015, 2018 Ludovic Courtès <ludo@gnu.org>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -18,12 +18,14 @@
 
 (define-module (test-gremlin)
   #:use-module (guix elf)
+  #:use-module ((guix utils) #:select (call-with-temporary-directory))
   #:use-module (guix build utils)
   #:use-module (guix build gremlin)
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-26)
   #:use-module (srfi srfi-64)
   #:use-module (rnrs io ports)
+  #:use-module (ice-9 popen)
   #:use-module (ice-9 match))
 
 (define %guile-executable
@@ -37,6 +39,9 @@
 (define read-elf
   (compose parse-elf get-bytevector-all))
 
+(define c-compiler
+  (or (which "gcc") (which "cc") (which "g++")))
+
 \f
 (test-begin "gremlin")
 
@@ -63,4 +68,32 @@
          "../${ORIGIN}/bar/$ORIGIN/baz"
          "ORIGIN/foo")))
 
+(unless c-compiler
+  (test-skip 1))
+(test-equal "strip-runpath"
+  "hello\n"
+  (call-with-temporary-directory
+   (lambda (directory)
+     (with-directory-excursion directory
+       (call-with-output-file "t.c"
+         (lambda (port)
+           (display "int main () { puts(\"hello\"); }" port)))
+       (invoke c-compiler "t.c"
+               "-Wl,-rpath=/foo" "-Wl,-rpath=/bar")
+       (let* ((dyninfo (elf-dynamic-info
+                        (parse-elf (call-with-input-file "a.out"
+                                     get-bytevector-all))))
+              (old     (elf-dynamic-info-runpath dyninfo))
+              (new     (strip-runpath "a.out"))
+              (new*    (strip-runpath "a.out")))
+         (validate-needed-in-runpath "a.out")
+         (and (member "/foo" old) (member "/bar" old)
+              (not (member "/foo" new))
+              (not (member "/bar" new))
+              (equal? new* new)
+              (let* ((pipe (open-input-pipe "./a.out"))
+                     (str  (get-string-all pipe)))
+                (close-pipe pipe)
+                str)))))))
+
 (test-end "gremlin")
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [bug#31208] [PATCH 3/3] build-system/meson: Use 'strip-runpath' instead of PatchELF.
  2018-04-18 16:40 ` [bug#31208] [PATCH 1/3] gremlin: Preserve offset info for dynamic entries Ludovic Courtès
  2018-04-18 16:40   ` [bug#31208] [PATCH 2/3] gremlin: Add 'strip-runpath' Ludovic Courtès
@ 2018-04-18 16:40   ` Ludovic Courtès
  1 sibling, 0 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-04-18 16:40 UTC (permalink / raw)
  To: 31208

* guix/build/meson-build-system.scm (fix-runpath): Call 'strip-runpath'
instead of invoking 'patchelf'.
---
 guix/build/meson-build-system.scm | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/guix/build/meson-build-system.scm b/guix/build/meson-build-system.scm
index e8cb5440e..793cc32e7 100644
--- a/guix/build/meson-build-system.scm
+++ b/guix/build/meson-build-system.scm
@@ -134,7 +134,7 @@ for example libraries only needed for the tests."
                                             (find-files dir elf-pred))
                                           existing-elf-dirs))))
          (for-each (lambda (elf-file)
-                     (system* "patchelf" "--shrink-rpath" elf-file)
+                     (strip-runpath elf-file)
                      (handle-file elf-file elf-list))
                    elf-list)))))
   (for-each handle-output outputs)
-- 
2.17.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin)
  2018-04-18 16:38 [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin) Ludovic Courtès
  2018-04-18 16:40 ` [bug#31208] [PATCH 1/3] gremlin: Preserve offset info for dynamic entries Ludovic Courtès
@ 2018-05-04 20:52 ` Ludovic Courtès
       [not found]   ` <CADh9keX7zyDOoNFstawVKdinxNOMKfff3jQuZUOvxFDawZP9Hw@mail.gmail.com>
  1 sibling, 1 reply; 8+ messages in thread
From: Ludovic Courtès @ 2018-05-04 20:52 UTC (permalink / raw)
  To: 31208

Ping!  :-)

Ludovic Courtès <ludo@gnu.org> skribis:

> Hello!
>
> As discussed before, this patch set is a first stab at getting rid of
> PatchELF (which has portability issues) in particular in the Meson build
> system.  (The patches are for the next ‘core-updates’.)
>
> The second patch adds ‘strip-runpath’.  It doesn’t add ‘augment-rpath’
> though, because that’s a bit more involved (it needs to grow the string
> table and the section it’s in), and so I wanted to make sure we really
> need it first.  :-)
>
> In the discussion of ‘meson-build-system’ in
> <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=28444>, we didn’t discuss
> this specific part.  Peter & Marius: can you explain whether/why this is
> needed?
>
> Thanks,
> Ludo’.
>
> Ludovic Courtès (3):
>   gremlin: Preserve offset info for dynamic entries.
>   gremlin: Add 'strip-runpath'.
>   build-system/meson: Use 'strip-runpath' instead of PatchELF.
>
>  guix/build/gremlin.scm            | 130 +++++++++++++++++++++---------
>  guix/build/meson-build-system.scm |   2 +-
>  tests/gremlin.scm                 |  35 +++++++-
>  3 files changed, 129 insertions(+), 38 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin)
       [not found]   ` <CADh9keX7zyDOoNFstawVKdinxNOMKfff3jQuZUOvxFDawZP9Hw@mail.gmail.com>
@ 2018-05-05 20:02     ` Ludovic Courtès
  2018-05-07  9:24       ` bug#31208: " Ludovic Courtès
  2018-05-07  9:32       ` [bug#31208] " Ludovic Courtès
  0 siblings, 2 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-05-05 20:02 UTC (permalink / raw)
  To: Peter Mikkelsen; +Cc: 31208

Hello Peter,

(I’m re-adding Cc, hope you don’t mind.)

Peter Mikkelsen <petermikkelsen10@gmail.com> skribis:

> Since I am not really that much into meson, I am not sure my answer
> will be enough, but I will give it a go:
> The augment-rpath is needed because in some software projects such as
> nautilus, there is both a library and an executable.
> When building the software, the library is built first, and then the
> executable which depends on it, but then the runpath of the executable
> is 'fixed' so
> that libnautilus is no longer in the runpath of the nautilus binary.
> This is a problem since libnautilus is needed at runtime, so it is
> added using augment-rpath.

Oh, I see.

Back to this patch series, it means we still need ‘augment-rpath’.  :-/
I suppose we can still apply these patches to ‘core-updates-next’
though, it’s a step in the right direction.

> I think I remember something about the meson developers saying that it
> is no problem, since libnautilus will be installed in a standard
> location or something,
> but I really don't remember, sorry..

What Libtool does is that it “relinks” executables upon “make install”
so that they have the correct RUNPATH.

> Sorry for the not so good reply, but I hope it makes a little bit sense :)

It makes a lot of sense yes, thank you!

Ludo’.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* bug#31208: [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin)
  2018-05-05 20:02     ` Ludovic Courtès
@ 2018-05-07  9:24       ` Ludovic Courtès
  2018-05-07  9:32       ` [bug#31208] " Ludovic Courtès
  1 sibling, 0 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-05-07  9:24 UTC (permalink / raw)
  To: Peter Mikkelsen; +Cc: 31208-done

ludo@gnu.org (Ludovic Courtès) skribis:

> Back to this patch series, it means we still need ‘augment-rpath’.  :-/
> I suppose we can still apply these patches to ‘core-updates-next’
> though, it’s a step in the right direction.

Done!

Ludo’.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin)
  2018-05-05 20:02     ` Ludovic Courtès
  2018-05-07  9:24       ` bug#31208: " Ludovic Courtès
@ 2018-05-07  9:32       ` Ludovic Courtès
  1 sibling, 0 replies; 8+ messages in thread
From: Ludovic Courtès @ 2018-05-07  9:32 UTC (permalink / raw)
  To: Peter Mikkelsen; +Cc: 31208

ludo@gnu.org (Ludovic Courtès) skribis:

> Peter Mikkelsen <petermikkelsen10@gmail.com> skribis:

[...]

>> I think I remember something about the meson developers saying that it
>> is no problem, since libnautilus will be installed in a standard
>> location or something,
>> but I really don't remember, sorry..
>
> What Libtool does is that it “relinks” executables upon “make install”
> so that they have the correct RUNPATH.

I found this issue, which mentions the problem:

  https://github.com/mesonbuild/meson/issues/2121#issuecomment-377971590

It’s a pity this isn’t properly solved.  :-/

Ludo’.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2018-05-07  9:33 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-04-18 16:38 [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin) Ludovic Courtès
2018-04-18 16:40 ` [bug#31208] [PATCH 1/3] gremlin: Preserve offset info for dynamic entries Ludovic Courtès
2018-04-18 16:40   ` [bug#31208] [PATCH 2/3] gremlin: Add 'strip-runpath' Ludovic Courtès
2018-04-18 16:40   ` [bug#31208] [PATCH 3/3] build-system/meson: Use 'strip-runpath' instead of PatchELF Ludovic Courtès
2018-05-04 20:52 ` [bug#31208] [PATCH 0/3] Add 'strip-runpath' in (guix build gremlin) Ludovic Courtès
     [not found]   ` <CADh9keX7zyDOoNFstawVKdinxNOMKfff3jQuZUOvxFDawZP9Hw@mail.gmail.com>
2018-05-05 20:02     ` Ludovic Courtès
2018-05-07  9:24       ` bug#31208: " Ludovic Courtès
2018-05-07  9:32       ` [bug#31208] " Ludovic Courtès

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).