@@ -8,6 +8,7 @@ package ld
8
8
9
9
import (
10
10
"debug/elf"
11
+ "fmt"
11
12
"internal/testenv"
12
13
"os"
13
14
"path/filepath"
@@ -182,3 +183,108 @@ func main() {
182
183
}
183
184
}
184
185
}
186
+
187
+ func TestElfBindNow (t * testing.T ) {
188
+ t .Parallel ()
189
+ testenv .MustHaveGoBuild (t )
190
+ testenv .MustInternalLink (t , false )
191
+
192
+ const prog = `package main; import _ "net"; func main() {}`
193
+
194
+ tests := []struct {
195
+ name string
196
+ args []string
197
+ wantDf1Now bool
198
+ wantDf1Pie bool
199
+ wantDfBindNow bool
200
+ }{
201
+ {name : "default" },
202
+ {
203
+ name : "pie" ,
204
+ args : []string {"-buildmode=pie" },
205
+ wantDf1Pie : true ,
206
+ },
207
+ {
208
+ name : "bindnow" ,
209
+ args : []string {"-ldflags" , "-bindnow" },
210
+ wantDf1Now : true ,
211
+ wantDfBindNow : true ,
212
+ },
213
+ {
214
+ name : "bindnow-pie" ,
215
+ args : []string {"-buildmode=pie" , "-ldflags" , "-bindnow" },
216
+ wantDf1Now : true ,
217
+ wantDf1Pie : true ,
218
+ wantDfBindNow : true ,
219
+ },
220
+ }
221
+
222
+ gotDynFlag := func (flags []uint64 , dynFlag uint64 ) bool {
223
+ for _ , flag := range flags {
224
+ if gotFlag := dynFlag & flag != 0 ; gotFlag {
225
+ return true
226
+ }
227
+ }
228
+
229
+ return false
230
+ }
231
+
232
+ for _ , test := range tests {
233
+ t .Run (
234
+ test .name , func (t * testing.T ) {
235
+ var (
236
+ gotDfBindNow , gotDf1Now , gotDf1Pie bool
237
+
238
+ dir = t .TempDir ()
239
+ src = filepath .Join (dir , fmt .Sprintf ("elf_%s.go" , test .name ))
240
+ binFile = filepath .Join (dir , test .name )
241
+ )
242
+
243
+ if err := os .WriteFile (src , []byte (prog ), 0666 ); err != nil {
244
+ t .Fatal (err )
245
+ }
246
+
247
+ cmdArgs := append ([]string {"build" , "-o" , binFile }, append (test .args , src )... )
248
+ cmd := testenv .Command (t , testenv .GoToolPath (t ), cmdArgs ... )
249
+
250
+ if out , err := cmd .CombinedOutput (); err != nil {
251
+ t .Fatalf ("%v: %v:\n %s" , cmd .Args , err , out )
252
+ }
253
+
254
+ fi , err := os .Open (binFile )
255
+ if err != nil {
256
+ t .Fatalf ("failed to open built file: %v" , err )
257
+ }
258
+ defer fi .Close ()
259
+
260
+ elfFile , err := elf .NewFile (fi )
261
+ if err != nil {
262
+ t .Skip ("The system may not support ELF, skipped." )
263
+ }
264
+ defer elfFile .Close ()
265
+
266
+ flags , err := elfFile .DynValue (elf .DT_FLAGS )
267
+ if err != nil {
268
+ t .Fatalf ("failed to get DT_FLAGS: %v" , err )
269
+ }
270
+
271
+ flags1 , err := elfFile .DynValue (elf .DT_FLAGS_1 )
272
+ if err != nil {
273
+ t .Fatalf ("failed to get DT_FLAGS_1: %v" , err )
274
+ }
275
+
276
+ if gotDfBindNow = gotDynFlag (flags , uint64 (elf .DF_BIND_NOW )); gotDfBindNow != test .wantDfBindNow {
277
+ t .Fatalf ("DT_FLAGS BIND_NOW flag is %v, want: %v" , gotDfBindNow , test .wantDfBindNow )
278
+ }
279
+
280
+ if gotDf1Now = gotDynFlag (flags1 , uint64 (elf .DF_1_NOW )); gotDf1Now != test .wantDf1Now {
281
+ t .Fatalf ("DT_FLAGS_1 DF_1_NOW flag is %v, want: %v" , gotDf1Now , test .wantDf1Now )
282
+ }
283
+
284
+ if gotDf1Pie = gotDynFlag (flags1 , uint64 (elf .DF_1_PIE )); gotDf1Pie != test .wantDf1Pie {
285
+ t .Fatalf ("DT_FLAGS_1 DF_1_PIE flag is %v, want: %v" , gotDf1Pie , test .wantDf1Pie )
286
+ }
287
+ },
288
+ )
289
+ }
290
+ }
0 commit comments