aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
authorqmuntal <quimmuntal@gmail.com>2025-09-16 18:00:10 +0200
committerQuim Muntal <quimmuntal@gmail.com>2025-10-27 22:57:10 -0700
commit9e25c2f6dee50f9ce0fcfe1807befad9e54dfe4b (patch)
treeede452f8948510084cdfa307759580399ba6df00 /src/cmd
parentff2ebf69c4f099adf90d6c6284f2b3fd2ff789f0 (diff)
downloadgo-9e25c2f6dee50f9ce0fcfe1807befad9e54dfe4b.tar.xz
cmd/link: internal linking support for windows/arm64
The internal linker was missing some pieces to support windows/arm64. Closes #75485 Cq-Include-Trybots: luci.golang.try:gotip-windows-arm64 Change-Id: I5c18a47e63e09b8ae22c9b24832249b54f544b7e Reviewed-on: https://go-review.googlesource.com/c/go/+/704295 Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/dist/build.go5
-rw-r--r--src/cmd/dist/test.go5
-rw-r--r--src/cmd/link/internal/arm64/asm.go21
-rw-r--r--src/cmd/link/internal/ld/data.go17
-rw-r--r--src/cmd/link/internal/loadpe/ldpe.go44
5 files changed, 76 insertions, 16 deletions
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index 2fcdb2d391..2b382a1c02 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -624,11 +624,6 @@ func mustLinkExternal(goos, goarch string, cgoEnabled bool) bool {
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/14449
return true
- case "arm64":
- if goos == "windows" {
- // windows/arm64 internal linking is not implemented.
- return true
- }
case "ppc64":
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
if goos == "aix" || goos == "linux" {
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 1e74438f48..9c9e1b85f0 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -1183,9 +1183,6 @@ func (t *tester) internalLink() bool {
if goos == "ios" {
return false
}
- if goos == "windows" && goarch == "arm64" {
- return false
- }
// Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373
// https://golang.org/issue/14449
@@ -1212,7 +1209,7 @@ func (t *tester) internalLinkPIE() bool {
case "darwin-amd64", "darwin-arm64",
"linux-amd64", "linux-arm64", "linux-loong64", "linux-ppc64le",
"android-arm64",
- "windows-amd64", "windows-386":
+ "windows-amd64", "windows-386", "windows-arm64":
return true
}
return false
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 1f4282adec..7c4546fb17 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -1027,25 +1027,35 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
}
case objabi.R_ARM64_PCREL:
+ // When targetting Windows, the instruction immediate field is cleared
+ // before applying relocations, as it contains the offset as bytes
+ // instead of pages. It has already been accounted for in loadpe.Load
+ // by adjusting r.Add().
if (val>>24)&0x9f == 0x90 {
- // R_AARCH64_ADR_PREL_PG_HI21
+ // ELF R_AARCH64_ADR_PREL_PG_HI21, or Mach-O ARM64_RELOC_PAGE21, or PE IMAGE_REL_ARM64_PAGEBASE_REL21
// patch instruction: adrp
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
if t >= 1<<32 || t < -1<<32 {
ldr.Errorf(s, "program too large, address relocation distance = %d", t)
}
o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
+ if target.IsWindows() {
+ val &^= 3<<29 | 0x7ffff<<5
+ }
return val | int64(o0), noExtReloc, isOk
} else if (val>>24)&0x9f == 0x91 {
- // ELF R_AARCH64_ADD_ABS_LO12_NC or Mach-O ARM64_RELOC_PAGEOFF12
+ // ELF R_AARCH64_ADD_ABS_LO12_NC, or Mach-O ARM64_RELOC_PAGEOFF12, or PE IMAGE_REL_ARM64_PAGEOFFSET_12A
// patch instruction: add
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
o1 := uint32(t&0xfff) << 10
+ if target.IsWindows() {
+ val &^= 0xfff << 10
+ }
return val | int64(o1), noExtReloc, isOk
} else if (val>>24)&0x3b == 0x39 {
- // Mach-O ARM64_RELOC_PAGEOFF12
+ // Mach-O ARM64_RELOC_PAGEOFF12 or PE IMAGE_REL_ARM64_PAGEOFFSET_12L
// patch ldr/str(b/h/w/d/q) (integer or vector) instructions, which have different scaling factors.
- // Mach-O uses same relocation type for them.
+ // Mach-O and PE use same relocation type for them.
shift := uint32(val) >> 30
if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
shift = 4
@@ -1055,6 +1065,9 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
}
o1 := (uint32(t&0xfff) >> shift) << 10
+ if target.IsWindows() {
+ val &^= 0xfff << 10
+ }
return val | int64(o1), noExtReloc, isOk
} else {
ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index dfb1d7bafb..b70d050c99 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -913,6 +913,23 @@ func windynrelocsym(ctxt *Link, rel *loader.SymbolBuilder, s loader.Sym) error {
rel.AddPCRelPlus(ctxt.Arch, targ, 0)
rel.AddUint8(0x90)
rel.AddUint8(0x90)
+ case sys.ARM64:
+ // adrp x16, addr
+ rel.AddUint32(ctxt.Arch, 0x90000010)
+ r, _ := rel.AddRel(objabi.R_ARM64_PCREL)
+ r.SetOff(int32(rel.Size() - 4))
+ r.SetSiz(4)
+ r.SetSym(targ)
+
+ // ldr x17, [x16, <offset>]
+ rel.AddUint32(ctxt.Arch, 0xf9400211)
+ r, _ = rel.AddRel(objabi.R_ARM64_PCREL)
+ r.SetOff(int32(rel.Size() - 4))
+ r.SetSiz(4)
+ r.SetSym(targ)
+
+ // br x17
+ rel.AddUint32(ctxt.Arch, 0xd61f0220)
}
} else if tplt >= 0 {
if su == nil {
diff --git a/src/cmd/link/internal/loadpe/ldpe.go b/src/cmd/link/internal/loadpe/ldpe.go
index d3a050135c..2073045c47 100644
--- a/src/cmd/link/internal/loadpe/ldpe.go
+++ b/src/cmd/link/internal/loadpe/ldpe.go
@@ -392,21 +392,59 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
switch r.Type {
case IMAGE_REL_ARM64_ADDR32:
rType = objabi.R_ADDR
+ case IMAGE_REL_ARM64_ADDR64:
+ rType = objabi.R_ADDR
+ rSize = 8
case IMAGE_REL_ARM64_ADDR32NB:
rType = objabi.R_PEIMAGEOFF
+ case IMAGE_REL_ARM64_BRANCH26:
+ rType = objabi.R_CALLARM64
+ case IMAGE_REL_ARM64_PAGEBASE_REL21,
+ IMAGE_REL_ARM64_PAGEOFFSET_12A,
+ IMAGE_REL_ARM64_PAGEOFFSET_12L:
+ rType = objabi.R_ARM64_PCREL
}
}
if rType == 0 {
return nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, state.sectsyms[rsect], r.Type)
}
- var rAdd int64
+ var val int64
switch rSize {
default:
panic("unexpected relocation size " + strconv.Itoa(int(rSize)))
case 4:
- rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:])))
+ val = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:])))
case 8:
- rAdd = int64(binary.LittleEndian.Uint64(state.sectdata[rsect][rOff:]))
+ val = int64(binary.LittleEndian.Uint64(state.sectdata[rsect][rOff:]))
+ }
+ var rAdd int64
+ if arch.Family == sys.ARM64 {
+ switch r.Type {
+ case IMAGE_REL_ARM64_BRANCH26:
+ // This instruction doesn't support an addend.
+ case IMAGE_REL_ARM64_PAGEOFFSET_12A:
+ // The addend is stored in the immediate field of the instruction.
+ // Get the addend from the instruction.
+ rAdd = (val >> 10) & 0xfff
+ case IMAGE_REL_ARM64_PAGEOFFSET_12L:
+ // Same as IMAGE_REL_ARM64_PAGEOFFSET_12A, but taking into account the shift.
+ shift := uint32(val) >> 30
+ if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
+ shift = 4
+ }
+ rAdd = ((val >> 10) & 0xfff) << shift
+ case IMAGE_REL_ARM64_PAGEBASE_REL21:
+ // The addend is stored in the immediate field of the instruction
+ // as a byte offset. Get the addend from the instruction and clear
+ // the immediate bits.
+ immlo := (val >> 29) & 3
+ immhi := (val >> 5) & 0x7ffff
+ rAdd = (immhi << 2) | immlo
+ default:
+ rAdd = val
+ }
+ } else {
+ rAdd = val
}
// ld -r could generate multiple section symbols for the
// same section but with different values, we have to take