From 985d0877829bf13f51120c4743c08ac82c0c8d62 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 27 Jan 2021 12:35:16 -0500 Subject: [PATCH] cmd/link: add windows/arm64 support This CL is part of a stack adding windows/arm64 support (#36439), intended to land in the Go 1.17 cycle. Change-Id: I397c1d238bb18cbe78b3fca00910660cf1d66b8d Reviewed-on: https://go-review.googlesource.com/c/go/+/288822 Trust: Russ Cox Trust: Jason A. Donenfeld Reviewed-by: Cherry Zhang Reviewed-by: Alex Brainman Reviewed-by: Jason A. Donenfeld --- src/cmd/link/internal/arm64/asm.go | 34 ++++++++++++++++++++++++++++++ src/cmd/link/internal/arm64/obj.go | 5 +++++ src/cmd/link/internal/ld/config.go | 6 +++--- src/cmd/link/internal/ld/pe.go | 28 +++++++++++++++++++++++- 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index 14a20a17d5..72093268c2 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -568,6 +568,40 @@ func machoreloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sy return true } +func pereloc1(arch *sys.Arch, out *ld.OutBuf, ldr *loader.Loader, s loader.Sym, r loader.ExtReloc, sectoff int64) bool { + var v uint32 + + rs := r.Xsym + rt := r.Type + + if ldr.SymDynid(rs) < 0 { + ldr.Errorf(s, "reloc %d (%s) to non-coff symbol %s type=%d (%s)", rt, sym.RelocName(arch, rt), ldr.SymName(rs), ldr.SymType(rs), ldr.SymType(rs)) + return false + } + + out.Write32(uint32(sectoff)) + out.Write32(uint32(ldr.SymDynid(rs))) + + switch rt { + default: + return false + + case objabi.R_DWARFSECREF: + v = ld.IMAGE_REL_ARM64_SECREL + + case objabi.R_ADDR: + if r.Size == 8 { + v = ld.IMAGE_REL_ARM64_ADDR64 + } else { + v = ld.IMAGE_REL_ARM64_ADDR32 + } + } + + out.Write16(uint16(v)) + + return true +} + func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loader.Reloc, s loader.Sym, val int64) (int64, int, bool) { const noExtReloc = 0 const isOk = true diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go index bd13295e61..18a32531e9 100644 --- a/src/cmd/link/internal/arm64/obj.go +++ b/src/cmd/link/internal/arm64/obj.go @@ -58,6 +58,7 @@ func Init() (*sys.Arch, ld.Arch) { GenSymsLate: gensymlate, Machoreloc1: machoreloc1, MachorelocSize: 8, + PEreloc1: pereloc1, Androiddynld: "/system/bin/linker64", Linuxdynld: "/lib/ld-linux-aarch64.so.1", @@ -108,5 +109,9 @@ func archinit(ctxt *ld.Link) { if *ld.FlagRound == -1 { *ld.FlagRound = 16384 // 16K page alignment } + + case objabi.Hwindows: /* PE executable */ + // ld.HEADR, ld.FlagTextAddr, ld.FlagRound are set in ld.Peinit + return } } diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go index d1e06239a5..481dc67475 100644 --- a/src/cmd/link/internal/ld/config.go +++ b/src/cmd/link/internal/ld/config.go @@ -36,7 +36,7 @@ func (mode *BuildMode) Set(s string) error { return fmt.Errorf("invalid buildmode: %q", s) case "exe": switch objabi.GOOS + "/" + objabi.GOARCH { - case "darwin/arm64", "windows/arm": // On these platforms, everything is PIE + case "darwin/arm64", "windows/arm", "windows/arm64": // On these platforms, everything is PIE *mode = BuildModePIE default: *mode = BuildModeExe @@ -65,7 +65,7 @@ func (mode *BuildMode) Set(s string) error { } case "windows": switch objabi.GOARCH { - case "amd64", "386", "arm": + case "amd64", "386", "arm", "arm64": default: return badmode() } @@ -220,7 +220,7 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) { case BuildModePIE: switch objabi.GOOS + "/" + objabi.GOARCH { case "linux/amd64", "linux/arm64", "android/arm64": - case "windows/386", "windows/amd64", "windows/arm": + case "windows/386", "windows/amd64", "windows/arm", "windows/arm64": case "darwin/amd64", "darwin/arm64": default: // Internal linking does not support TLS_IE. diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go index c46036c7ea..36c8e0da9a 100644 --- a/src/cmd/link/internal/ld/pe.go +++ b/src/cmd/link/internal/ld/pe.go @@ -69,6 +69,7 @@ const ( IMAGE_SCN_ALIGN_32BYTES = 0x600000 ) +// See https://docs.microsoft.com/en-us/windows/win32/debug/pe-format. // TODO(crawshaw): add these constants to debug/pe. const ( // TODO: the Microsoft doco says IMAGE_SYM_DTYPE_ARRAY is 3 and IMAGE_SYM_DTYPE_FUNCTION is 2 @@ -95,6 +96,25 @@ const ( IMAGE_REL_ARM_BRANCH11 = 0x0004 IMAGE_REL_ARM_SECREL = 0x000F + 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 + IMAGE_REL_BASED_HIGHLOW = 3 IMAGE_REL_BASED_DIR64 = 10 ) @@ -465,6 +485,8 @@ func (f *peFile) addInitArray(ctxt *Link) *peSection { size = 8 case "arm": size = 4 + case "arm64": + size = 8 } sect := f.addSection(".ctors", size, size) sect.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ @@ -477,7 +499,7 @@ func (f *peFile) addInitArray(ctxt *Link) *peSection { switch objabi.GOARCH { case "386", "arm": ctxt.Out.Write32(uint32(addr)) - case "amd64": + case "amd64", "arm64": ctxt.Out.Write64(addr) } return sect @@ -594,6 +616,8 @@ dwarfLoop: ctxt.Out.Write16(IMAGE_REL_AMD64_ADDR64) case "arm": ctxt.Out.Write16(IMAGE_REL_ARM_ADDR32) + case "arm64": + ctxt.Out.Write16(IMAGE_REL_ARM64_ADDR64) } return 1 }) @@ -788,6 +812,8 @@ func (f *peFile) writeFileHeader(ctxt *Link) { fh.Machine = pe.IMAGE_FILE_MACHINE_I386 case sys.ARM: fh.Machine = pe.IMAGE_FILE_MACHINE_ARMNT + case sys.ARM64: + fh.Machine = pe.IMAGE_FILE_MACHINE_ARM64 } fh.NumberOfSections = uint16(len(f.sections)) -- 2.50.0