Skip to content

Commit cfb0cc3

Browse files
cmd/link: use SHT_INIT_ARRAY for .init_array section
Fixes #50295 Change-Id: If55ebcd5f2af724da7c9c744458a56d21a7ddde7 Reviewed-on: https://go-review.googlesource.com/c/go/+/373734 Trust: Ian Lance Taylor <[email protected]> Reviewed-by: Cherry Mui <[email protected]>
1 parent 2d1d548 commit cfb0cc3

File tree

2 files changed

+184
-1
lines changed

2 files changed

+184
-1
lines changed

misc/cgo/testcarchive/carchive_test.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import (
1010
"debug/elf"
1111
"flag"
1212
"fmt"
13+
"io"
1314
"io/fs"
1415
"log"
1516
"os"
1617
"os/exec"
1718
"path/filepath"
1819
"regexp"
1920
"runtime"
21+
"strconv"
2022
"strings"
2123
"syscall"
2224
"testing"
@@ -287,6 +289,173 @@ func checkLineComments(t *testing.T, hdrname string) {
287289
}
288290
}
289291

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+
290459
func TestInstall(t *testing.T) {
291460
if !testWork {
292461
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
@@ -345,6 +514,7 @@ func TestEarlySignalHandler(t *testing.T) {
345514
t.Fatal(err)
346515
}
347516
checkLineComments(t, "libgo2.h")
517+
checkArchive(t, "libgo2.a")
348518

349519
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
350520
if runtime.Compiler == "gccgo" {
@@ -385,6 +555,7 @@ func TestSignalForwarding(t *testing.T) {
385555
t.Fatal(err)
386556
}
387557
checkLineComments(t, "libgo2.h")
558+
checkArchive(t, "libgo2.a")
388559

389560
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
390561
if runtime.Compiler == "gccgo" {
@@ -437,6 +608,7 @@ func TestSignalForwardingExternal(t *testing.T) {
437608
t.Fatal(err)
438609
}
439610
checkLineComments(t, "libgo2.h")
611+
checkArchive(t, "libgo2.a")
440612

441613
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
442614
if runtime.Compiler == "gccgo" {
@@ -554,6 +726,7 @@ func TestOsSignal(t *testing.T) {
554726
t.Fatal(err)
555727
}
556728
checkLineComments(t, "libgo3.h")
729+
checkArchive(t, "libgo3.a")
557730

558731
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
559732
if runtime.Compiler == "gccgo" {
@@ -591,6 +764,7 @@ func TestSigaltstack(t *testing.T) {
591764
t.Fatal(err)
592765
}
593766
checkLineComments(t, "libgo4.h")
767+
checkArchive(t, "libgo4.a")
594768

595769
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
596770
if runtime.Compiler == "gccgo" {
@@ -779,6 +953,7 @@ func TestSIGPROF(t *testing.T) {
779953
t.Fatal(err)
780954
}
781955
checkLineComments(t, "libgo6.h")
956+
checkArchive(t, "libgo6.a")
782957

783958
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
784959
if runtime.Compiler == "gccgo" {
@@ -824,6 +999,7 @@ func TestCompileWithoutShared(t *testing.T) {
824999
t.Fatal(err)
8251000
}
8261001
checkLineComments(t, "libgo2.h")
1002+
checkArchive(t, "libgo2.a")
8271003

8281004
exe := "./testnoshared" + exeSuffix
8291005

@@ -926,6 +1102,7 @@ func TestManyCalls(t *testing.T) {
9261102
t.Fatal(err)
9271103
}
9281104
checkLineComments(t, "libgo7.h")
1105+
checkArchive(t, "libgo7.a")
9291106

9301107
ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
9311108
if runtime.Compiler == "gccgo" {
@@ -985,6 +1162,7 @@ func TestPreemption(t *testing.T) {
9851162
t.Fatal(err)
9861163
}
9871164
checkLineComments(t, "libgo8.h")
1165+
checkArchive(t, "libgo8.a")
9881166

9891167
ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
9901168
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()

src/cmd/link/internal/ld/elf.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1080,7 +1080,12 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
10801080
}
10811081

10821082
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
1083-
sh.Type = uint32(elf.SHT_PROGBITS)
1083+
switch sect.Name {
1084+
case ".init_array":
1085+
sh.Type = uint32(elf.SHT_INIT_ARRAY)
1086+
default:
1087+
sh.Type = uint32(elf.SHT_PROGBITS)
1088+
}
10841089
} else {
10851090
sh.Type = uint32(elf.SHT_NOBITS)
10861091
}

0 commit comments

Comments
 (0)