mirror of
https://github.com/golang/go
synced 2024-11-23 04:30:03 -07:00
cmd/link: recognize ARM64 PE files and relocations
For now, this only add a single relocation type, which is sufficient for Windows resources. Later we'll see if we need more for cgo. In order to ensure these code paths are actually tested, this expands the rsrc tests to include all the architectures of PE objects that we need to be recognizing, and splits things more clearly between binutils and llvm objects, which have a slightly different layout, so that we test both. This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. Change-Id: Ia1ee840265e9d12c0b12dd1c5d0810f8b300e557 Reviewed-on: https://go-review.googlesource.com/c/go/+/289429 Trust: Jason A. Donenfeld <Jason@zx2c4.com> Run-TryBot: Jason A. Donenfeld <Jason@zx2c4.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
a655208c9e
commit
f41460145e
@ -1827,7 +1827,11 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
|
||||
return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
|
||||
}
|
||||
|
||||
if /* x86 */ c1 == 0x4c && c2 == 0x01 || /* x86_64 */ c1 == 0x64 && c2 == 0x86 || /* armv7 */ c1 == 0xc4 && c2 == 0x01 {
|
||||
switch c1<<8 | c2 {
|
||||
case 0x4c01, // 386
|
||||
0x6486, // amd64
|
||||
0xc401, // arm
|
||||
0x64aa: // arm64
|
||||
ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
|
||||
textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
|
||||
if err != nil {
|
||||
|
@ -115,6 +115,24 @@ const (
|
||||
IMAGE_REL_THUMB_BRANCH24 = 0x0014
|
||||
IMAGE_REL_THUMB_BLX23 = 0x0015
|
||||
IMAGE_REL_ARM_PAIR = 0x0016
|
||||
IMAGE_REL_ARM64_ABSOLUTE = 0x0000
|
||||
IMAGE_REL_ARM64_ADDR32 = 0x0001
|
||||
IMAGE_REL_ARM64_ADDR32NB = 0x0002
|
||||
IMAGE_REL_ARM64_BRANCH26 = 0x0003
|
||||
IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004
|
||||
IMAGE_REL_ARM64_REL21 = 0x0005
|
||||
IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006
|
||||
IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007
|
||||
IMAGE_REL_ARM64_SECREL = 0x0008
|
||||
IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009
|
||||
IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A
|
||||
IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B
|
||||
IMAGE_REL_ARM64_TOKEN = 0x000C
|
||||
IMAGE_REL_ARM64_SECTION = 0x000D
|
||||
IMAGE_REL_ARM64_ADDR64 = 0x000E
|
||||
IMAGE_REL_ARM64_BRANCH19 = 0x000F
|
||||
IMAGE_REL_ARM64_BRANCH14 = 0x0010
|
||||
IMAGE_REL_ARM64_REL32 = 0x0011
|
||||
)
|
||||
|
||||
// TODO(crawshaw): de-duplicate these symbols with cmd/internal/ld, ideally in debug/pe.
|
||||
@ -319,6 +337,17 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
|
||||
case IMAGE_REL_ARM_BRANCH24:
|
||||
rType = objabi.R_CALLARM
|
||||
|
||||
rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:])))
|
||||
}
|
||||
|
||||
case sys.ARM64:
|
||||
switch r.Type {
|
||||
default:
|
||||
return nil, nil, fmt.Errorf("%s: %v: unknown ARM64 relocation type %v", pn, sectsyms[rsect], r.Type)
|
||||
|
||||
case IMAGE_REL_ARM64_ADDR32, IMAGE_REL_ARM64_ADDR32NB:
|
||||
rType = objabi.R_ADDR
|
||||
|
||||
rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:])))
|
||||
}
|
||||
}
|
||||
|
@ -753,23 +753,24 @@ func TestIndexMismatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPErsrc(t *testing.T) {
|
||||
func TestPErsrcBinutils(t *testing.T) {
|
||||
// Test that PE rsrc section is handled correctly (issue 39658).
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" {
|
||||
t.Skipf("this is a windows/amd64-only test")
|
||||
if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" {
|
||||
// This test is limited to amd64 and 386, because binutils is limited as such
|
||||
t.Skipf("this is only for windows/amd64 and windows/386")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestPErsrc")
|
||||
tmpdir, err := ioutil.TempDir("", "TestPErsrcBinutils")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
pkgdir := filepath.Join("testdata", "testPErsrc")
|
||||
pkgdir := filepath.Join("testdata", "pe-binutils")
|
||||
exe := filepath.Join(tmpdir, "a.exe")
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
|
||||
cmd.Dir = pkgdir
|
||||
@ -787,19 +788,36 @@ func TestPErsrc(t *testing.T) {
|
||||
if !bytes.Contains(b, []byte("Hello Gophers!")) {
|
||||
t.Fatalf("binary does not contain expected content")
|
||||
}
|
||||
}
|
||||
|
||||
pkgdir = filepath.Join("testdata", "testPErsrc-complex")
|
||||
exe = filepath.Join(tmpdir, "a.exe")
|
||||
cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
|
||||
func TestPErsrcLLVM(t *testing.T) {
|
||||
// Test that PE rsrc section is handled correctly (issue 39658).
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Skipf("this is a windows-only test")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tmpdir, err := ioutil.TempDir("", "TestPErsrcLLVM")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
pkgdir := filepath.Join("testdata", "pe-llvm")
|
||||
exe := filepath.Join(tmpdir, "a.exe")
|
||||
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
|
||||
cmd.Dir = pkgdir
|
||||
// cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
|
||||
out, err = cmd.CombinedOutput()
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("building failed: %v, output:\n%s", err, out)
|
||||
}
|
||||
|
||||
// Check that the binary contains the rsrc data
|
||||
b, err = ioutil.ReadFile(exe)
|
||||
b, err := ioutil.ReadFile(exe)
|
||||
if err != nil {
|
||||
t.Fatalf("reading output failed: %v", err)
|
||||
}
|
||||
|
@ -4,10 +4,9 @@
|
||||
|
||||
// Test that a PE rsrc section is handled correctly (issue 39658).
|
||||
//
|
||||
// rsrc.syso is created with:
|
||||
// windres -i a.rc -o rsrc.syso -O coff
|
||||
// on windows-amd64-2016 builder, where a.rc is a text file with
|
||||
// the following content:
|
||||
// rsrc.syso is created using binutils with:
|
||||
// {x86_64,i686}-w64-mingw32-windres -i a.rc -o rsrc_$GOARCH.syso -O coff
|
||||
// where a.rc is a text file with the following content:
|
||||
//
|
||||
// resname RCDATA {
|
||||
// "Hello Gophers!\0",
|
BIN
src/cmd/link/testdata/pe-binutils/rsrc_386.syso
vendored
Normal file
BIN
src/cmd/link/testdata/pe-binutils/rsrc_386.syso
vendored
Normal file
Binary file not shown.
@ -6,8 +6,8 @@
|
||||
// have been created by llvm-rc or msvc's rc.exe, which means there's the
|
||||
// @feat.00 symbol as well as split .rsrc$00 and .rsrc$01 section to deal with.
|
||||
//
|
||||
// rsrc.syso is created with:
|
||||
// windres -i a.rc -o rsrc.syso -O coff
|
||||
// rsrc.syso is created using llvm with:
|
||||
// {i686,x86_64,armv7,arm64}-w64-mingw32-windres -i a.rc -o rsrc_$GOARCH.syso -O coff
|
||||
// where this windres calls into llvm-rc and llvm-cvtres. The source file,
|
||||
// a.rc, simply contains a reference to its own bytes:
|
||||
//
|
BIN
src/cmd/link/testdata/pe-llvm/rsrc_386.syso
vendored
Normal file
BIN
src/cmd/link/testdata/pe-llvm/rsrc_386.syso
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/cmd/link/testdata/pe-llvm/rsrc_arm.syso
vendored
Normal file
BIN
src/cmd/link/testdata/pe-llvm/rsrc_arm.syso
vendored
Normal file
Binary file not shown.
BIN
src/cmd/link/testdata/pe-llvm/rsrc_arm64.syso
vendored
Normal file
BIN
src/cmd/link/testdata/pe-llvm/rsrc_arm64.syso
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user