@@ -10,13 +10,15 @@ import (
10
10
"debug/elf"
11
11
"flag"
12
12
"fmt"
13
+ "io"
13
14
"io/fs"
14
15
"log"
15
16
"os"
16
17
"os/exec"
17
18
"path/filepath"
18
19
"regexp"
19
20
"runtime"
21
+ "strconv"
20
22
"strings"
21
23
"syscall"
22
24
"testing"
@@ -287,6 +289,173 @@ func checkLineComments(t *testing.T, hdrname string) {
287
289
}
288
290
}
289
291
292
+ // checkArchive verifies that the created library looks OK.
293
+ // We just check a couple of things now, we can add more checks as needed.
294
+ func checkArchive (t * testing.T , arname string ) {
295
+ t .Helper ()
296
+
297
+ switch GOOS {
298
+ case "aix" , "darwin" , "ios" , "windows" :
299
+ // We don't have any checks for non-ELF libraries yet.
300
+ if _ , err := os .Stat (arname ); err != nil {
301
+ t .Errorf ("archive %s does not exist: %v" , arname , err )
302
+ }
303
+ default :
304
+ checkELFArchive (t , arname )
305
+ }
306
+ }
307
+
308
+ // checkELFArchive checks an ELF archive.
309
+ func checkELFArchive (t * testing.T , arname string ) {
310
+ t .Helper ()
311
+
312
+ f , err := os .Open (arname )
313
+ if err != nil {
314
+ t .Errorf ("archive %s does not exist: %v" , arname , err )
315
+ return
316
+ }
317
+ defer f .Close ()
318
+
319
+ // TODO(iant): put these in a shared package? But where?
320
+ const (
321
+ magic = "!<arch>\n "
322
+ fmag = "`\n "
323
+
324
+ namelen = 16
325
+ datelen = 12
326
+ uidlen = 6
327
+ gidlen = 6
328
+ modelen = 8
329
+ sizelen = 10
330
+ fmaglen = 2
331
+ hdrlen = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
332
+ )
333
+
334
+ type arhdr struct {
335
+ name string
336
+ date string
337
+ uid string
338
+ gid string
339
+ mode string
340
+ size string
341
+ fmag string
342
+ }
343
+
344
+ var magbuf [len (magic )]byte
345
+ if _ , err := io .ReadFull (f , magbuf [:]); err != nil {
346
+ t .Errorf ("%s: archive too short" , arname )
347
+ return
348
+ }
349
+ if string (magbuf [:]) != magic {
350
+ t .Errorf ("%s: incorrect archive magic string %q" , arname , magbuf )
351
+ }
352
+
353
+ off := int64 (len (magic ))
354
+ for {
355
+ if off & 1 != 0 {
356
+ var b [1 ]byte
357
+ if _ , err := f .Read (b [:]); err != nil {
358
+ if err == io .EOF {
359
+ break
360
+ }
361
+ t .Errorf ("%s: error skipping alignment byte at %d: %v" , arname , off , err )
362
+ }
363
+ off ++
364
+ }
365
+
366
+ var hdrbuf [hdrlen ]byte
367
+ if _ , err := io .ReadFull (f , hdrbuf [:]); err != nil {
368
+ if err == io .EOF {
369
+ break
370
+ }
371
+ t .Errorf ("%s: error reading archive header at %d: %v" , arname , off , err )
372
+ return
373
+ }
374
+
375
+ var hdr arhdr
376
+ hdrslice := hdrbuf [:]
377
+ set := func (len int , ps * string ) {
378
+ * ps = string (bytes .TrimSpace (hdrslice [:len ]))
379
+ hdrslice = hdrslice [len :]
380
+ }
381
+ set (namelen , & hdr .name )
382
+ set (datelen , & hdr .date )
383
+ set (uidlen , & hdr .uid )
384
+ set (gidlen , & hdr .gid )
385
+ set (modelen , & hdr .mode )
386
+ set (sizelen , & hdr .size )
387
+ hdr .fmag = string (hdrslice [:fmaglen ])
388
+ hdrslice = hdrslice [fmaglen :]
389
+ if len (hdrslice ) != 0 {
390
+ t .Fatalf ("internal error: len(hdrslice) == %d" , len (hdrslice ))
391
+ }
392
+
393
+ if hdr .fmag != fmag {
394
+ t .Errorf ("%s: invalid fmagic value %q at %d" , arname , hdr .fmag , off )
395
+ return
396
+ }
397
+
398
+ size , err := strconv .ParseInt (hdr .size , 10 , 64 )
399
+ if err != nil {
400
+ t .Errorf ("%s: error parsing size %q at %d: %v" , arname , hdr .size , off , err )
401
+ return
402
+ }
403
+
404
+ off += hdrlen
405
+
406
+ switch hdr .name {
407
+ case "__.SYMDEF" , "/" , "/SYM64/" :
408
+ // The archive symbol map.
409
+ case "//" , "ARFILENAMES/" :
410
+ // The extended name table.
411
+ default :
412
+ // This should be an ELF object.
413
+ checkELFArchiveObject (t , arname , off , io .NewSectionReader (f , off , size ))
414
+ }
415
+
416
+ off += size
417
+ if _ , err := f .Seek (off , os .SEEK_SET ); err != nil {
418
+ t .Errorf ("%s: failed to seek to %d: %v" , arname , off , err )
419
+ }
420
+ }
421
+ }
422
+
423
+ // checkELFArchiveObject checks an object in an ELF archive.
424
+ func checkELFArchiveObject (t * testing.T , arname string , off int64 , obj io.ReaderAt ) {
425
+ t .Helper ()
426
+
427
+ ef , err := elf .NewFile (obj )
428
+ if err != nil {
429
+ t .Errorf ("%s: failed to open ELF file at %d: %v" , arname , off , err )
430
+ return
431
+ }
432
+ defer ef .Close ()
433
+
434
+ // Verify section types.
435
+ for _ , sec := range ef .Sections {
436
+ want := elf .SHT_NULL
437
+ switch sec .Name {
438
+ case ".text" , ".data" :
439
+ want = elf .SHT_PROGBITS
440
+ case ".bss" :
441
+ want = elf .SHT_NOBITS
442
+ case ".symtab" :
443
+ want = elf .SHT_SYMTAB
444
+ case ".strtab" :
445
+ want = elf .SHT_STRTAB
446
+ case ".init_array" :
447
+ want = elf .SHT_INIT_ARRAY
448
+ case ".fini_array" :
449
+ want = elf .SHT_FINI_ARRAY
450
+ case ".preinit_array" :
451
+ want = elf .SHT_PREINIT_ARRAY
452
+ }
453
+ if want != elf .SHT_NULL && sec .Type != want {
454
+ t .Errorf ("%s: incorrect section type in elf file at %d for section %q: got %v want %v" , arname , off , sec .Name , sec .Type , want )
455
+ }
456
+ }
457
+ }
458
+
290
459
func TestInstall (t * testing.T ) {
291
460
if ! testWork {
292
461
defer os .RemoveAll (filepath .Join (GOPATH , "pkg" ))
@@ -345,6 +514,7 @@ func TestEarlySignalHandler(t *testing.T) {
345
514
t .Fatal (err )
346
515
}
347
516
checkLineComments (t , "libgo2.h" )
517
+ checkArchive (t , "libgo2.a" )
348
518
349
519
ccArgs := append (cc , "-o" , "testp" + exeSuffix , "main2.c" , "libgo2.a" )
350
520
if runtime .Compiler == "gccgo" {
@@ -385,6 +555,7 @@ func TestSignalForwarding(t *testing.T) {
385
555
t .Fatal (err )
386
556
}
387
557
checkLineComments (t , "libgo2.h" )
558
+ checkArchive (t , "libgo2.a" )
388
559
389
560
ccArgs := append (cc , "-o" , "testp" + exeSuffix , "main5.c" , "libgo2.a" )
390
561
if runtime .Compiler == "gccgo" {
@@ -437,6 +608,7 @@ func TestSignalForwardingExternal(t *testing.T) {
437
608
t .Fatal (err )
438
609
}
439
610
checkLineComments (t , "libgo2.h" )
611
+ checkArchive (t , "libgo2.a" )
440
612
441
613
ccArgs := append (cc , "-o" , "testp" + exeSuffix , "main5.c" , "libgo2.a" )
442
614
if runtime .Compiler == "gccgo" {
@@ -554,6 +726,7 @@ func TestOsSignal(t *testing.T) {
554
726
t .Fatal (err )
555
727
}
556
728
checkLineComments (t , "libgo3.h" )
729
+ checkArchive (t , "libgo3.a" )
557
730
558
731
ccArgs := append (cc , "-o" , "testp" + exeSuffix , "main3.c" , "libgo3.a" )
559
732
if runtime .Compiler == "gccgo" {
@@ -591,6 +764,7 @@ func TestSigaltstack(t *testing.T) {
591
764
t .Fatal (err )
592
765
}
593
766
checkLineComments (t , "libgo4.h" )
767
+ checkArchive (t , "libgo4.a" )
594
768
595
769
ccArgs := append (cc , "-o" , "testp" + exeSuffix , "main4.c" , "libgo4.a" )
596
770
if runtime .Compiler == "gccgo" {
@@ -779,6 +953,7 @@ func TestSIGPROF(t *testing.T) {
779
953
t .Fatal (err )
780
954
}
781
955
checkLineComments (t , "libgo6.h" )
956
+ checkArchive (t , "libgo6.a" )
782
957
783
958
ccArgs := append (cc , "-o" , "testp6" + exeSuffix , "main6.c" , "libgo6.a" )
784
959
if runtime .Compiler == "gccgo" {
@@ -824,6 +999,7 @@ func TestCompileWithoutShared(t *testing.T) {
824
999
t .Fatal (err )
825
1000
}
826
1001
checkLineComments (t , "libgo2.h" )
1002
+ checkArchive (t , "libgo2.a" )
827
1003
828
1004
exe := "./testnoshared" + exeSuffix
829
1005
@@ -926,6 +1102,7 @@ func TestManyCalls(t *testing.T) {
926
1102
t .Fatal (err )
927
1103
}
928
1104
checkLineComments (t , "libgo7.h" )
1105
+ checkArchive (t , "libgo7.a" )
929
1106
930
1107
ccArgs := append (cc , "-o" , "testp7" + exeSuffix , "main7.c" , "libgo7.a" )
931
1108
if runtime .Compiler == "gccgo" {
@@ -985,6 +1162,7 @@ func TestPreemption(t *testing.T) {
985
1162
t .Fatal (err )
986
1163
}
987
1164
checkLineComments (t , "libgo8.h" )
1165
+ checkArchive (t , "libgo8.a" )
988
1166
989
1167
ccArgs := append (cc , "-o" , "testp8" + exeSuffix , "main8.c" , "libgo8.a" )
990
1168
out , err = exec .Command (ccArgs [0 ], ccArgs [1 :]... ).CombinedOutput ()
0 commit comments