1
0
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:
Jason A. Donenfeld 2021-02-04 00:11:12 +01:00
parent a655208c9e
commit f41460145e
11 changed files with 67 additions and 17 deletions

View File

@ -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 {

View File

@ -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:])))
}
}

View File

@ -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)
}

View File

@ -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",

Binary file not shown.

View File

@ -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:
//

Binary file not shown.

Binary file not shown.

Binary file not shown.