mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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>
This commit is contained in:
parent
ff2ebf69c4
commit
9e25c2f6de
7 changed files with 80 additions and 21 deletions
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
## Linker {#linker}
|
||||
|
||||
On 64-bit ARM-based Windows (the `windows/arm64` port), the linker now supports internal
|
||||
linking mode of cgo programs, which can be requested with the
|
||||
`-ldflags=-linkmode=internal` flag.
|
||||
|
||||
## Bootstrap {#bootstrap}
|
||||
|
||||
<!-- go.dev/issue/69315 -->
|
||||
|
|
|
|||
5
src/cmd/dist/build.go
vendored
5
src/cmd/dist/build.go
vendored
|
|
@ -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" {
|
||||
|
|
|
|||
5
src/cmd/dist/test.go
vendored
5
src/cmd/dist/test.go
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -89,11 +89,6 @@ func MustLinkExternal(goos, goarch string, withCgo bool) bool {
|
|||
// Internally linking cgo is incomplete on some architectures.
|
||||
// https://go.dev/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.
|
||||
// https://go.dev/issue/8912
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue