aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2021-12-21 10:00:23 -0800
committerCarlos Amedee <carlos@golang.org>2022-01-05 18:14:31 +0000
commita845a562a0f2abd96c448a1ab3effe65d154353a (patch)
treef17ae77e7f5d491183662368c55d5a0be092af0a
parent169be8e5b123007a02adf3f742b2a200bd8f9e67 (diff)
downloadgo-a845a562a0f2abd96c448a1ab3effe65d154353a.tar.gz
go-a845a562a0f2abd96c448a1ab3effe65d154353a.zip
[release-branch.go1.16] cmd/link: use SHT_INIT_ARRAY for .init_array section
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>
-rw-r--r--misc/cgo/testcarchive/carchive_test.go177
-rw-r--r--src/cmd/link/internal/ld/elf.go7
2 files changed, 183 insertions, 1 deletions
diff --git a/misc/cgo/testcarchive/carchive_test.go b/misc/cgo/testcarchive/carchive_test.go
index 6a5adf79ca..e81eefafdf 100644
--- a/misc/cgo/testcarchive/carchive_test.go
+++ b/misc/cgo/testcarchive/carchive_test.go
@@ -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" {
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index f5823a8fbf..0f2ef0df43 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -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)
}