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}
|
## 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}
|
## Bootstrap {#bootstrap}
|
||||||
|
|
||||||
<!-- go.dev/issue/69315 -->
|
<!-- 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.
|
// Internally linking cgo is incomplete on some architectures.
|
||||||
// https://golang.org/issue/14449
|
// https://golang.org/issue/14449
|
||||||
return true
|
return true
|
||||||
case "arm64":
|
|
||||||
if goos == "windows" {
|
|
||||||
// windows/arm64 internal linking is not implemented.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case "ppc64":
|
case "ppc64":
|
||||||
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
||||||
if goos == "aix" || goos == "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" {
|
if goos == "ios" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if goos == "windows" && goarch == "arm64" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// Internally linking cgo is incomplete on some architectures.
|
// Internally linking cgo is incomplete on some architectures.
|
||||||
// https://golang.org/issue/10373
|
// https://golang.org/issue/10373
|
||||||
// https://golang.org/issue/14449
|
// https://golang.org/issue/14449
|
||||||
|
|
@ -1212,7 +1209,7 @@ func (t *tester) internalLinkPIE() bool {
|
||||||
case "darwin-amd64", "darwin-arm64",
|
case "darwin-amd64", "darwin-arm64",
|
||||||
"linux-amd64", "linux-arm64", "linux-loong64", "linux-ppc64le",
|
"linux-amd64", "linux-arm64", "linux-loong64", "linux-ppc64le",
|
||||||
"android-arm64",
|
"android-arm64",
|
||||||
"windows-amd64", "windows-386":
|
"windows-amd64", "windows-386", "windows-arm64":
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
|
||||||
|
|
@ -1027,25 +1027,35 @@ func archreloc(target *ld.Target, ldr *loader.Loader, syms *ld.ArchSyms, r loade
|
||||||
}
|
}
|
||||||
|
|
||||||
case objabi.R_ARM64_PCREL:
|
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 {
|
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
|
// patch instruction: adrp
|
||||||
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
|
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
|
||||||
if t >= 1<<32 || t < -1<<32 {
|
if t >= 1<<32 || t < -1<<32 {
|
||||||
ldr.Errorf(s, "program too large, address relocation distance = %d", t)
|
ldr.Errorf(s, "program too large, address relocation distance = %d", t)
|
||||||
}
|
}
|
||||||
o0 := (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
|
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
|
return val | int64(o0), noExtReloc, isOk
|
||||||
} else if (val>>24)&0x9f == 0x91 {
|
} 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
|
// patch instruction: add
|
||||||
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
|
t := ldr.SymAddr(rs) + r.Add() - ((ldr.SymValue(s) + int64(r.Off())) &^ 0xfff)
|
||||||
o1 := uint32(t&0xfff) << 10
|
o1 := uint32(t&0xfff) << 10
|
||||||
|
if target.IsWindows() {
|
||||||
|
val &^= 0xfff << 10
|
||||||
|
}
|
||||||
return val | int64(o1), noExtReloc, isOk
|
return val | int64(o1), noExtReloc, isOk
|
||||||
} else if (val>>24)&0x3b == 0x39 {
|
} 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.
|
// 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
|
shift := uint32(val) >> 30
|
||||||
if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
|
if shift == 0 && (val>>20)&0x048 == 0x048 { // 128-bit vector load
|
||||||
shift = 4
|
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)
|
ldr.Errorf(s, "invalid address: %x for relocation type: ARM64_RELOC_PAGEOFF12", t)
|
||||||
}
|
}
|
||||||
o1 := (uint32(t&0xfff) >> shift) << 10
|
o1 := (uint32(t&0xfff) >> shift) << 10
|
||||||
|
if target.IsWindows() {
|
||||||
|
val &^= 0xfff << 10
|
||||||
|
}
|
||||||
return val | int64(o1), noExtReloc, isOk
|
return val | int64(o1), noExtReloc, isOk
|
||||||
} else {
|
} else {
|
||||||
ldr.Errorf(s, "unsupported instruction for %x R_ARM64_PCREL", val)
|
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.AddPCRelPlus(ctxt.Arch, targ, 0)
|
||||||
rel.AddUint8(0x90)
|
rel.AddUint8(0x90)
|
||||||
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 {
|
} else if tplt >= 0 {
|
||||||
if su == nil {
|
if su == nil {
|
||||||
|
|
|
||||||
|
|
@ -392,21 +392,59 @@ func Load(l *loader.Loader, arch *sys.Arch, localSymVersion int, input *bio.Read
|
||||||
switch r.Type {
|
switch r.Type {
|
||||||
case IMAGE_REL_ARM64_ADDR32:
|
case IMAGE_REL_ARM64_ADDR32:
|
||||||
rType = objabi.R_ADDR
|
rType = objabi.R_ADDR
|
||||||
|
case IMAGE_REL_ARM64_ADDR64:
|
||||||
|
rType = objabi.R_ADDR
|
||||||
|
rSize = 8
|
||||||
case IMAGE_REL_ARM64_ADDR32NB:
|
case IMAGE_REL_ARM64_ADDR32NB:
|
||||||
rType = objabi.R_PEIMAGEOFF
|
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 {
|
if rType == 0 {
|
||||||
return nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, state.sectsyms[rsect], r.Type)
|
return nil, fmt.Errorf("%s: %v: unknown relocation type %v", pn, state.sectsyms[rsect], r.Type)
|
||||||
}
|
}
|
||||||
var rAdd int64
|
var val int64
|
||||||
switch rSize {
|
switch rSize {
|
||||||
default:
|
default:
|
||||||
panic("unexpected relocation size " + strconv.Itoa(int(rSize)))
|
panic("unexpected relocation size " + strconv.Itoa(int(rSize)))
|
||||||
case 4:
|
case 4:
|
||||||
rAdd = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:])))
|
val = int64(int32(binary.LittleEndian.Uint32(state.sectdata[rsect][rOff:])))
|
||||||
case 8:
|
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
|
// ld -r could generate multiple section symbols for the
|
||||||
// same section but with different values, we have to take
|
// 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.
|
// Internally linking cgo is incomplete on some architectures.
|
||||||
// https://go.dev/issue/14449
|
// https://go.dev/issue/14449
|
||||||
return true
|
return true
|
||||||
case "arm64":
|
|
||||||
if goos == "windows" {
|
|
||||||
// windows/arm64 internal linking is not implemented.
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
case "ppc64":
|
case "ppc64":
|
||||||
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
// Big Endian PPC64 cgo internal linking is not implemented for aix or linux.
|
||||||
// https://go.dev/issue/8912
|
// https://go.dev/issue/8912
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue