]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.16] cmd/link: use SHT_INIT_ARRAY for .init_array section
authorIan Lance Taylor <iant@golang.org>
Tue, 21 Dec 2021 18:00:23 +0000 (10:00 -0800)
committerCarlos Amedee <carlos@golang.org>
Wed, 5 Jan 2022 18:14:31 +0000 (18:14 +0000)
For #50295
Fixes #50296

Change-Id: If55ebcd5f2af724da7c9c744458a56d21a7ddde7
Reviewed-on: https://go-review.googlesource.com/c/go/+/373734
Trust: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
(cherry picked from commit cfb0cc355233d4367b188b23a3bc143985a28b8c)
Reviewed-on: https://go-review.googlesource.com/c/go/+/374234
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Austin Clements <austin@google.com>
misc/cgo/testcarchive/carchive_test.go
src/cmd/link/internal/ld/elf.go

index 6a5adf79ca05bb72cdbb048fade45c15d13f499b..e81eefafdf9655b574040daf13257a805e1f2cb7 100644 (file)
@@ -10,6 +10,7 @@ import (
        "debug/elf"
        "flag"
        "fmt"
+       "io"
        "io/ioutil"
        "log"
        "os"
@@ -17,6 +18,7 @@ import (
        "path/filepath"
        "regexp"
        "runtime"
+       "strconv"
        "strings"
        "syscall"
        "testing"
@@ -264,6 +266,173 @@ func checkLineComments(t *testing.T, hdrname string) {
        }
 }
 
+// checkArchive verifies that the created library looks OK.
+// We just check a couple of things now, we can add more checks as needed.
+func checkArchive(t *testing.T, arname string) {
+       t.Helper()
+
+       switch GOOS {
+       case "aix", "darwin", "ios", "windows":
+               // We don't have any checks for non-ELF libraries yet.
+               if _, err := os.Stat(arname); err != nil {
+                       t.Errorf("archive %s does not exist: %v", arname, err)
+               }
+       default:
+               checkELFArchive(t, arname)
+       }
+}
+
+// checkELFArchive checks an ELF archive.
+func checkELFArchive(t *testing.T, arname string) {
+       t.Helper()
+
+       f, err := os.Open(arname)
+       if err != nil {
+               t.Errorf("archive %s does not exist: %v", arname, err)
+               return
+       }
+       defer f.Close()
+
+       // TODO(iant): put these in a shared package?  But where?
+       const (
+               magic = "!<arch>\n"
+               fmag  = "`\n"
+
+               namelen = 16
+               datelen = 12
+               uidlen  = 6
+               gidlen  = 6
+               modelen = 8
+               sizelen = 10
+               fmaglen = 2
+               hdrlen  = namelen + datelen + uidlen + gidlen + modelen + sizelen + fmaglen
+       )
+
+       type arhdr struct {
+               name string
+               date string
+               uid  string
+               gid  string
+               mode string
+               size string
+               fmag string
+       }
+
+       var magbuf [len(magic)]byte
+       if _, err := io.ReadFull(f, magbuf[:]); err != nil {
+               t.Errorf("%s: archive too short", arname)
+               return
+       }
+       if string(magbuf[:]) != magic {
+               t.Errorf("%s: incorrect archive magic string %q", arname, magbuf)
+       }
+
+       off := int64(len(magic))
+       for {
+               if off&1 != 0 {
+                       var b [1]byte
+                       if _, err := f.Read(b[:]); err != nil {
+                               if err == io.EOF {
+                                       break
+                               }
+                               t.Errorf("%s: error skipping alignment byte at %d: %v", arname, off, err)
+                       }
+                       off++
+               }
+
+               var hdrbuf [hdrlen]byte
+               if _, err := io.ReadFull(f, hdrbuf[:]); err != nil {
+                       if err == io.EOF {
+                               break
+                       }
+                       t.Errorf("%s: error reading archive header at %d: %v", arname, off, err)
+                       return
+               }
+
+               var hdr arhdr
+               hdrslice := hdrbuf[:]
+               set := func(len int, ps *string) {
+                       *ps = string(bytes.TrimSpace(hdrslice[:len]))
+                       hdrslice = hdrslice[len:]
+               }
+               set(namelen, &hdr.name)
+               set(datelen, &hdr.date)
+               set(uidlen, &hdr.uid)
+               set(gidlen, &hdr.gid)
+               set(modelen, &hdr.mode)
+               set(sizelen, &hdr.size)
+               hdr.fmag = string(hdrslice[:fmaglen])
+               hdrslice = hdrslice[fmaglen:]
+               if len(hdrslice) != 0 {
+                       t.Fatalf("internal error: len(hdrslice) == %d", len(hdrslice))
+               }
+
+               if hdr.fmag != fmag {
+                       t.Errorf("%s: invalid fmagic value %q at %d", arname, hdr.fmag, off)
+                       return
+               }
+
+               size, err := strconv.ParseInt(hdr.size, 10, 64)
+               if err != nil {
+                       t.Errorf("%s: error parsing size %q at %d: %v", arname, hdr.size, off, err)
+                       return
+               }
+
+               off += hdrlen
+
+               switch hdr.name {
+               case "__.SYMDEF", "/", "/SYM64/":
+                       // The archive symbol map.
+               case "//", "ARFILENAMES/":
+                       // The extended name table.
+               default:
+                       // This should be an ELF object.
+                       checkELFArchiveObject(t, arname, off, io.NewSectionReader(f, off, size))
+               }
+
+               off += size
+               if _, err := f.Seek(off, os.SEEK_SET); err != nil {
+                       t.Errorf("%s: failed to seek to %d: %v", arname, off, err)
+               }
+       }
+}
+
+// checkELFArchiveObject checks an object in an ELF archive.
+func checkELFArchiveObject(t *testing.T, arname string, off int64, obj io.ReaderAt) {
+       t.Helper()
+
+       ef, err := elf.NewFile(obj)
+       if err != nil {
+               t.Errorf("%s: failed to open ELF file at %d: %v", arname, off, err)
+               return
+       }
+       defer ef.Close()
+
+       // Verify section types.
+       for _, sec := range ef.Sections {
+               want := elf.SHT_NULL
+               switch sec.Name {
+               case ".text", ".data":
+                       want = elf.SHT_PROGBITS
+               case ".bss":
+                       want = elf.SHT_NOBITS
+               case ".symtab":
+                       want = elf.SHT_SYMTAB
+               case ".strtab":
+                       want = elf.SHT_STRTAB
+               case ".init_array":
+                       want = elf.SHT_INIT_ARRAY
+               case ".fini_array":
+                       want = elf.SHT_FINI_ARRAY
+               case ".preinit_array":
+                       want = elf.SHT_PREINIT_ARRAY
+               }
+               if want != elf.SHT_NULL && sec.Type != want {
+                       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)
+               }
+       }
+}
+
 func TestInstall(t *testing.T) {
        if !testWork {
                defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
@@ -322,6 +491,7 @@ func TestEarlySignalHandler(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo2.h")
+       checkArchive(t, "libgo2.a")
 
        ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
        if runtime.Compiler == "gccgo" {
@@ -362,6 +532,7 @@ func TestSignalForwarding(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo2.h")
+       checkArchive(t, "libgo2.a")
 
        ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
        if runtime.Compiler == "gccgo" {
@@ -412,6 +583,7 @@ func TestSignalForwardingExternal(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo2.h")
+       checkArchive(t, "libgo2.a")
 
        ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
        if runtime.Compiler == "gccgo" {
@@ -529,6 +701,7 @@ func TestOsSignal(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo3.h")
+       checkArchive(t, "libgo3.a")
 
        ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
        if runtime.Compiler == "gccgo" {
@@ -566,6 +739,7 @@ func TestSigaltstack(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo4.h")
+       checkArchive(t, "libgo4.a")
 
        ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
        if runtime.Compiler == "gccgo" {
@@ -753,6 +927,7 @@ func TestSIGPROF(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo6.h")
+       checkArchive(t, "libgo6.a")
 
        ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
        if runtime.Compiler == "gccgo" {
@@ -796,6 +971,7 @@ func TestCompileWithoutShared(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo2.h")
+       checkArchive(t, "libgo2.a")
 
        exe := "./testnoshared" + exeSuffix
 
@@ -900,6 +1076,7 @@ func TestManyCalls(t *testing.T) {
                t.Fatal(err)
        }
        checkLineComments(t, "libgo7.h")
+       checkArchive(t, "libgo7.a")
 
        ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
        if runtime.Compiler == "gccgo" {
index f5823a8fbfb73ed9ed1756738f2e7ae49d4f4b5a..0f2ef0df43562f99f24b697bf1d66f2126669910 100644 (file)
@@ -993,7 +993,12 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
        }
 
        if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
-               sh.Type = uint32(elf.SHT_PROGBITS)
+               switch sect.Name {
+               case ".init_array":
+                       sh.Type = uint32(elf.SHT_INIT_ARRAY)
+               default:
+                       sh.Type = uint32(elf.SHT_PROGBITS)
+               }
        } else {
                sh.Type = uint32(elf.SHT_NOBITS)
        }