mirror of https://github.com/golang/go.git
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 <iant@golang.org> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
2d1d548081
commit
cfb0cc3552
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -17,6 +18,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -287,6 +289,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) {
|
func TestInstall(t *testing.T) {
|
||||||
if !testWork {
|
if !testWork {
|
||||||
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
defer os.RemoveAll(filepath.Join(GOPATH, "pkg"))
|
||||||
|
|
@ -345,6 +514,7 @@ func TestEarlySignalHandler(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo2.h")
|
checkLineComments(t, "libgo2.h")
|
||||||
|
checkArchive(t, "libgo2.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main2.c", "libgo2.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -385,6 +555,7 @@ func TestSignalForwarding(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo2.h")
|
checkLineComments(t, "libgo2.h")
|
||||||
|
checkArchive(t, "libgo2.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -437,6 +608,7 @@ func TestSignalForwardingExternal(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo2.h")
|
checkLineComments(t, "libgo2.h")
|
||||||
|
checkArchive(t, "libgo2.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main5.c", "libgo2.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -554,6 +726,7 @@ func TestOsSignal(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo3.h")
|
checkLineComments(t, "libgo3.h")
|
||||||
|
checkArchive(t, "libgo3.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main3.c", "libgo3.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -591,6 +764,7 @@ func TestSigaltstack(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo4.h")
|
checkLineComments(t, "libgo4.h")
|
||||||
|
checkArchive(t, "libgo4.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
|
ccArgs := append(cc, "-o", "testp"+exeSuffix, "main4.c", "libgo4.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -779,6 +953,7 @@ func TestSIGPROF(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo6.h")
|
checkLineComments(t, "libgo6.h")
|
||||||
|
checkArchive(t, "libgo6.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
|
ccArgs := append(cc, "-o", "testp6"+exeSuffix, "main6.c", "libgo6.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -824,6 +999,7 @@ func TestCompileWithoutShared(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo2.h")
|
checkLineComments(t, "libgo2.h")
|
||||||
|
checkArchive(t, "libgo2.a")
|
||||||
|
|
||||||
exe := "./testnoshared" + exeSuffix
|
exe := "./testnoshared" + exeSuffix
|
||||||
|
|
||||||
|
|
@ -926,6 +1102,7 @@ func TestManyCalls(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo7.h")
|
checkLineComments(t, "libgo7.h")
|
||||||
|
checkArchive(t, "libgo7.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
|
ccArgs := append(cc, "-o", "testp7"+exeSuffix, "main7.c", "libgo7.a")
|
||||||
if runtime.Compiler == "gccgo" {
|
if runtime.Compiler == "gccgo" {
|
||||||
|
|
@ -985,6 +1162,7 @@ func TestPreemption(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
checkLineComments(t, "libgo8.h")
|
checkLineComments(t, "libgo8.h")
|
||||||
|
checkArchive(t, "libgo8.a")
|
||||||
|
|
||||||
ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
|
ccArgs := append(cc, "-o", "testp8"+exeSuffix, "main8.c", "libgo8.a")
|
||||||
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
||||||
|
|
|
||||||
|
|
@ -1080,7 +1080,12 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
|
||||||
}
|
}
|
||||||
|
|
||||||
if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
|
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 {
|
} else {
|
||||||
sh.Type = uint32(elf.SHT_NOBITS)
|
sh.Type = uint32(elf.SHT_NOBITS)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue