@@ -12,56 +12,80 @@ import (
12
12
"strings"
13
13
)
14
14
15
- // glibcPatcher patches ELF binaries to use an alternative version of glibc.
16
- type glibcPatcher struct {
15
+ // libPatcher patches ELF binaries to use an alternative version of glibc.
16
+ type libPatcher struct {
17
17
// ld is the absolute path to the new dynamic linker (ld.so).
18
18
ld string
19
19
20
20
// rpath is the new RPATH with the directories containing the new libc
21
21
// shared objects (libc.so) and other libraries.
22
22
rpath []string
23
- }
24
23
25
- // newGlibcPatcher creates a new glibcPatcher and verifies that it can find the
26
- // shared object files in glibc.
27
- func newGlibcPatcher (glibc * packageFS ) (* glibcPatcher , error ) {
28
- patcher := & glibcPatcher {}
24
+ // needed are shared libraries to add as dependencies (DT_NEEDED).
25
+ needed []string
26
+ }
29
27
28
+ // setGlibc configures the patcher to use the dynamic linker and libc libraries
29
+ // in pkg.
30
+ func (p * libPatcher ) setGlibc (pkg * packageFS ) error {
30
31
// Verify that we can find a directory with libc in it.
31
32
glob := "lib*/libc.so*"
32
- matches , _ := fs .Glob (glibc , glob )
33
+ matches , _ := fs .Glob (pkg , glob )
33
34
if len (matches ) == 0 {
34
- return nil , fmt .Errorf ("cannot find libc.so file matching %q" , glob )
35
+ return fmt .Errorf ("cannot find libc.so file matching %q" , glob )
35
36
}
36
37
for i := range matches {
37
38
matches [i ] = path .Dir (matches [i ])
38
39
}
39
40
slices .Sort (matches ) // pick the shortest name: lib < lib32 < lib64 < libx32
40
41
41
- lib , err := glibc .OSPath (matches [0 ])
42
+ lib , err := pkg .OSPath (matches [0 ])
42
43
if err != nil {
43
- return nil , err
44
+ return err
44
45
}
45
- patcher .rpath = append (patcher .rpath , lib )
46
+ p .rpath = append (p .rpath , lib )
46
47
slog .Debug ("found new libc directory" , "path" , lib )
47
48
48
49
// Verify that we can find the new dynamic linker.
49
50
glob = "lib*/ld-linux*.so*"
50
- matches , _ = fs .Glob (glibc , glob )
51
+ matches , _ = fs .Glob (pkg , glob )
51
52
if len (matches ) == 0 {
52
- return nil , fmt .Errorf ("cannot find ld.so file matching %q" , glob )
53
+ return fmt .Errorf ("cannot find ld.so file matching %q" , glob )
53
54
}
54
55
slices .Sort (matches )
55
- patcher .ld , err = glibc .OSPath (matches [0 ])
56
+ p .ld , err = pkg .OSPath (matches [0 ])
56
57
if err != nil {
57
- return nil , err
58
+ return err
58
59
}
59
- slog .Debug ("found new dynamic linker" , "path" , patcher .ld )
60
+ slog .Debug ("found new dynamic linker" , "path" , p .ld )
61
+ return nil
62
+ }
60
63
61
- return patcher , nil
64
+ // setGlibc configures the patcher to use the standard C++ and gcc libraries in
65
+ // pkg.
66
+ func (p * libPatcher ) setGcc (pkg * packageFS ) error {
67
+ // Verify that we can find a directory with libstdc++.so in it.
68
+ glob := "lib*/libstdc++.so*"
69
+ matches , _ := fs .Glob (pkg , glob )
70
+ if len (matches ) == 0 {
71
+ return fmt .Errorf ("cannot find libstdc++.so file matching %q" , glob )
72
+ }
73
+ for i := range matches {
74
+ matches [i ] = path .Dir (matches [i ])
75
+ }
76
+ slices .Sort (matches ) // pick the shortest name: lib < lib32 < lib64 < libx32
77
+
78
+ lib , err := pkg .OSPath (matches [0 ])
79
+ if err != nil {
80
+ return err
81
+ }
82
+ p .rpath = append (p .rpath , lib )
83
+ p .needed = append (p .needed , "libstdc++.so" )
84
+ slog .Debug ("found new libstdc++ directory" , "path" , lib )
85
+ return nil
62
86
}
63
87
64
- func (g * glibcPatcher ) prependRPATH (libPkg * packageFS ) {
88
+ func (p * libPatcher ) prependRPATH (libPkg * packageFS ) {
65
89
glob := "lib*/*.so*"
66
90
matches , _ := fs .Glob (libPkg , glob )
67
91
if len (matches ) == 0 {
@@ -80,13 +104,13 @@ func (g *glibcPatcher) prependRPATH(libPkg *packageFS) {
80
104
continue
81
105
}
82
106
}
83
- g .rpath = append (matches , g .rpath ... )
107
+ p .rpath = append (p .rpath , matches ... )
84
108
slog .Debug ("prepended package lib dirs to RPATH" , "pkg" , libPkg .storePath , "dirs" , matches )
85
109
}
86
110
87
111
// patch applies glibc patches to a binary and writes the patched result to
88
112
// outPath. It does not modify the original binary in-place.
89
- func (g * glibcPatcher ) patch (ctx context.Context , path , outPath string ) error {
113
+ func (p * libPatcher ) patch (ctx context.Context , path , outPath string ) error {
90
114
cmd := & patchelf {PrintInterpreter : true }
91
115
out , err := cmd .run (ctx , path )
92
116
if err != nil {
@@ -102,8 +126,9 @@ func (g *glibcPatcher) patch(ctx context.Context, path, outPath string) error {
102
126
oldRpath := strings .Split (string (out ), ":" )
103
127
104
128
cmd = & patchelf {
105
- SetInterpreter : g .ld ,
106
- SetRPATH : append (g .rpath , oldRpath ... ),
129
+ SetInterpreter : p .ld ,
130
+ SetRPATH : append (p .rpath , oldRpath ... ),
131
+ AddNeeded : p .needed ,
107
132
Output : outPath ,
108
133
}
109
134
slog .Debug ("patching glibc on binary" ,
@@ -123,6 +148,8 @@ type patchelf struct {
123
148
SetInterpreter string
124
149
PrintInterpreter bool
125
150
151
+ AddNeeded []string
152
+
126
153
Output string
127
154
}
128
155
@@ -141,6 +168,9 @@ func (p *patchelf) run(ctx context.Context, elf string) ([]byte, error) {
141
168
if p .PrintInterpreter {
142
169
cmd .Args = append (cmd .Args , "--print-interpreter" )
143
170
}
171
+ for _ , needed := range p .AddNeeded {
172
+ cmd .Args = append (cmd .Args , "--add-needed" , needed )
173
+ }
144
174
if p .Output != "" {
145
175
cmd .Args = append (cmd .Args , "--output" , p .Output )
146
176
}
0 commit comments