Skip to content

Commit f414601

Browse files
committed
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 <[email protected]> Run-TryBot: Jason A. Donenfeld <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent a655208 commit f414601

File tree

11 files changed

+67
-17
lines changed

11 files changed

+67
-17
lines changed

src/cmd/link/internal/ld/lib.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1827,7 +1827,11 @@ func ldobj(ctxt *Link, f *bio.Reader, lib *sym.Library, length int64, pn string,
18271827
return ldhostobj(ldmacho, ctxt.HeadType, f, pkg, length, pn, file)
18281828
}
18291829

1830-
if /* x86 */ c1 == 0x4c && c2 == 0x01 || /* x86_64 */ c1 == 0x64 && c2 == 0x86 || /* armv7 */ c1 == 0xc4 && c2 == 0x01 {
1830+
switch c1<<8 | c2 {
1831+
case 0x4c01, // 386
1832+
0x6486, // amd64
1833+
0xc401, // arm
1834+
0x64aa: // arm64
18311835
ldpe := func(ctxt *Link, f *bio.Reader, pkg string, length int64, pn string) {
18321836
textp, rsrc, err := loadpe.Load(ctxt.loader, ctxt.Arch, ctxt.IncVersion(), f, pkg, length, pn)
18331837
if err != nil {

src/cmd/link/internal/loadpe/ldpe.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,24 @@ const (
115115
IMAGE_REL_THUMB_BRANCH24 = 0x0014
116116
IMAGE_REL_THUMB_BLX23 = 0x0015
117117
IMAGE_REL_ARM_PAIR = 0x0016
118+
IMAGE_REL_ARM64_ABSOLUTE = 0x0000
119+
IMAGE_REL_ARM64_ADDR32 = 0x0001
120+
IMAGE_REL_ARM64_ADDR32NB = 0x0002
121+
IMAGE_REL_ARM64_BRANCH26 = 0x0003
122+
IMAGE_REL_ARM64_PAGEBASE_REL21 = 0x0004
123+
IMAGE_REL_ARM64_REL21 = 0x0005
124+
IMAGE_REL_ARM64_PAGEOFFSET_12A = 0x0006
125+
IMAGE_REL_ARM64_PAGEOFFSET_12L = 0x0007
126+
IMAGE_REL_ARM64_SECREL = 0x0008
127+
IMAGE_REL_ARM64_SECREL_LOW12A = 0x0009
128+
IMAGE_REL_ARM64_SECREL_HIGH12A = 0x000A
129+
IMAGE_REL_ARM64_SECREL_LOW12L = 0x000B
130+
IMAGE_REL_ARM64_TOKEN = 0x000C
131+
IMAGE_REL_ARM64_SECTION = 0x000D
132+
IMAGE_REL_ARM64_ADDR64 = 0x000E
133+
IMAGE_REL_ARM64_BRANCH19 = 0x000F
134+
IMAGE_REL_ARM64_BRANCH14 = 0x0010
135+
IMAGE_REL_ARM64_REL32 = 0x0011
118136
)
119137

120138
// 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
319337
case IMAGE_REL_ARM_BRANCH24:
320338
rType = objabi.R_CALLARM
321339

340+
rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:])))
341+
}
342+
343+
case sys.ARM64:
344+
switch r.Type {
345+
default:
346+
return nil, nil, fmt.Errorf("%s: %v: unknown ARM64 relocation type %v", pn, sectsyms[rsect], r.Type)
347+
348+
case IMAGE_REL_ARM64_ADDR32, IMAGE_REL_ARM64_ADDR32NB:
349+
rType = objabi.R_ADDR
350+
322351
rAdd = int64(int32(binary.LittleEndian.Uint32(sectdata[rsect][rOff:])))
323352
}
324353
}

src/cmd/link/link_test.go

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -753,23 +753,24 @@ func TestIndexMismatch(t *testing.T) {
753753
}
754754
}
755755

756-
func TestPErsrc(t *testing.T) {
756+
func TestPErsrcBinutils(t *testing.T) {
757757
// Test that PE rsrc section is handled correctly (issue 39658).
758758
testenv.MustHaveGoBuild(t)
759759

760-
if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" {
761-
t.Skipf("this is a windows/amd64-only test")
760+
if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" {
761+
// This test is limited to amd64 and 386, because binutils is limited as such
762+
t.Skipf("this is only for windows/amd64 and windows/386")
762763
}
763764

764765
t.Parallel()
765766

766-
tmpdir, err := ioutil.TempDir("", "TestPErsrc")
767+
tmpdir, err := ioutil.TempDir("", "TestPErsrcBinutils")
767768
if err != nil {
768769
t.Fatal(err)
769770
}
770771
defer os.RemoveAll(tmpdir)
771772

772-
pkgdir := filepath.Join("testdata", "testPErsrc")
773+
pkgdir := filepath.Join("testdata", "pe-binutils")
773774
exe := filepath.Join(tmpdir, "a.exe")
774775
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
775776
cmd.Dir = pkgdir
@@ -787,19 +788,36 @@ func TestPErsrc(t *testing.T) {
787788
if !bytes.Contains(b, []byte("Hello Gophers!")) {
788789
t.Fatalf("binary does not contain expected content")
789790
}
791+
}
792+
793+
func TestPErsrcLLVM(t *testing.T) {
794+
// Test that PE rsrc section is handled correctly (issue 39658).
795+
testenv.MustHaveGoBuild(t)
796+
797+
if runtime.GOOS != "windows" {
798+
t.Skipf("this is a windows-only test")
799+
}
800+
801+
t.Parallel()
802+
803+
tmpdir, err := ioutil.TempDir("", "TestPErsrcLLVM")
804+
if err != nil {
805+
t.Fatal(err)
806+
}
807+
defer os.RemoveAll(tmpdir)
790808

791-
pkgdir = filepath.Join("testdata", "testPErsrc-complex")
792-
exe = filepath.Join(tmpdir, "a.exe")
793-
cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
809+
pkgdir := filepath.Join("testdata", "pe-llvm")
810+
exe := filepath.Join(tmpdir, "a.exe")
811+
cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
794812
cmd.Dir = pkgdir
795813
// cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
796-
out, err = cmd.CombinedOutput()
814+
out, err := cmd.CombinedOutput()
797815
if err != nil {
798816
t.Fatalf("building failed: %v, output:\n%s", err, out)
799817
}
800818

801819
// Check that the binary contains the rsrc data
802-
b, err = ioutil.ReadFile(exe)
820+
b, err := ioutil.ReadFile(exe)
803821
if err != nil {
804822
t.Fatalf("reading output failed: %v", err)
805823
}

src/cmd/link/testdata/testPErsrc/main.go renamed to src/cmd/link/testdata/pe-binutils/main.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,9 @@
44

55
// Test that a PE rsrc section is handled correctly (issue 39658).
66
//
7-
// rsrc.syso is created with:
8-
// windres -i a.rc -o rsrc.syso -O coff
9-
// on windows-amd64-2016 builder, where a.rc is a text file with
10-
// the following content:
7+
// rsrc.syso is created using binutils with:
8+
// {x86_64,i686}-w64-mingw32-windres -i a.rc -o rsrc_$GOARCH.syso -O coff
9+
// where a.rc is a text file with the following content:
1110
//
1211
// resname RCDATA {
1312
// "Hello Gophers!\0",
228 Bytes
Binary file not shown.

src/cmd/link/testdata/testPErsrc-complex/main.go renamed to src/cmd/link/testdata/pe-llvm/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
// have been created by llvm-rc or msvc's rc.exe, which means there's the
77
// @feat.00 symbol as well as split .rsrc$00 and .rsrc$01 section to deal with.
88
//
9-
// rsrc.syso is created with:
10-
// windres -i a.rc -o rsrc.syso -O coff
9+
// rsrc.syso is created using llvm with:
10+
// {i686,x86_64,armv7,arm64}-w64-mingw32-windres -i a.rc -o rsrc_$GOARCH.syso -O coff
1111
// where this windres calls into llvm-rc and llvm-cvtres. The source file,
1212
// a.rc, simply contains a reference to its own bytes:
1313
//
352 Bytes
Binary file not shown.
352 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)