reflect, runtime: adjust user-created GCData on AIX

On AIX the runtime adjusts the GCData field in getGCMaskOnDemand
to account for the AIX dynamic loader moving the data section.
That works fine for statically generated types,
but it breaks user generated types. The user generated type
will have a normal, correct, pointer, and adjusting the pointer
will make it point elsewhere.

This all happens to work OK when doing an external link,
because in that case we do have dynamic relocs and there is no adjustment.
But it fails with an internal link.

This CL fixes the problem by applying a reverse adjustment to
user generated types, so that the adjustment winds up with the
original pointer value.

Change-Id: Ibf3199b9ffb36e79af134fbed41db2853297de74
Reviewed-on: https://go-review.googlesource.com/c/go/+/740800
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
Ian Lance Taylor 2026-01-30 18:42:27 -08:00 committed by Gopher Robot
parent 01299a31c2
commit bd1b41eb81
2 changed files with 43 additions and 0 deletions

View file

@ -2580,6 +2580,9 @@ func StructOf(fields []StructField) Type {
// space to store it.
typ.TFlag |= abi.TFlagGCMaskOnDemand
typ.GCData = (*byte)(unsafe.Pointer(new(uintptr)))
if runtime.GOOS == "aix" {
typ.GCData = adjustAIXGCData(typ.GCData)
}
}
typ.Equal = nil
@ -2745,6 +2748,9 @@ func ArrayOf(length int, elem Type) Type {
// space to store it.
array.TFlag |= abi.TFlagGCMaskOnDemand
array.GCData = (*byte)(unsafe.Pointer(new(uintptr)))
if runtime.GOOS == "aix" {
array.GCData = adjustAIXGCData(array.GCData)
}
}
etyp := typ
@ -2776,6 +2782,34 @@ func ArrayOf(length int, elem Type) Type {
return ti.(Type)
}
// adjustAIXGCData adjusts the GCData field pointer for AIX.
// See runtime.getGCMaskOnDemand.
func adjustAIXGCData(addr *byte) *byte {
adjusted := adjustAIXGCDataForRuntime(addr)
if adjusted != addr {
pinAIXGCDataMu.Lock()
pinAIXGCData = append(pinAIXGCData, addr)
pinAIXGCDataMu.Unlock()
}
return adjusted
}
// adjustAIXGCDataForRuntime adjusts the GCData field pointer
// as the runtime requires for AIX. See runtime.getGCMaskOnDemand.
//
//go:linkname adjustAIXGCDataForRuntime
//go:noescape
func adjustAIXGCDataForRuntime(*byte) *byte
// pinAIXGCDataMu proects pinAIXGCData.
var pinAIXGCDataMu sync.Mutex
// pinAIXGCData keeps the actual GCData pointer alive on AIX.
// On AIX we need to use adjustAIXGCData to convert the GC pointer
// to the value that the runtime expects. That means that the rtype
// no longer refers to the original pointer. This slice keeps it alive.
var pinAIXGCData []*byte
func appendVarint(x []byte, v uintptr) []byte {
for ; v >= 0x80; v >>= 7 {
x = append(x, byte(v|0x80))

View file

@ -732,6 +732,15 @@ func reflect_addReflectOff(ptr unsafe.Pointer) int32 {
return id
}
// reflect_adjustAIXGCDataForRuntime takes a type.GCData address and returns
// the new address to use. This is only called on AIX.
// See getGCMaskOnDemand.
//
//go:linkname reflect_adjustAIXGCDataForRuntime reflect.adjustAIXGCDataForRuntime
func reflect_adjustAIXGCDataForRuntime(addr *byte) *byte {
return (*byte)(add(unsafe.Pointer(addr), aixStaticDataBase-firstmoduledata.data))
}
//go:linkname fips_getIndicator crypto/internal/fips140.getIndicator
func fips_getIndicator() uint8 {
return getg().fipsIndicator