From b9955f0ad952a22388eead15e3d15610a29e03a0 Mon Sep 17 00:00:00 2001 From: Cherry Mui Date: Fri, 20 Dec 2024 22:33:15 -0500 Subject: [PATCH] cmd/link, runtime: apply a delta to RODATA->DATA relocations On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol does not work, as the dynamic loader can change the address of the data section, and it is not possible to apply a dynamic relocation to RODATA. In order to get the correct address, we apply the delta between unrelocated and relocated data section addresses at run time. The linker saves both the unrelocated and the relocated addresses, so we can compute the delta. This is possible because RODATA symbols are generated by the compiler and so we have full control of. On AIX, the only case is the on-demand GC pointer masks from the type descriptors, for very large types. Perhaps there is a better way. Fixes #70483. Change-Id: I2664c0a813b38f7b146794cb1e73ccf5e238ca65 Reviewed-on: https://go-review.googlesource.com/c/go/+/638016 Reviewed-by: Keith Randall Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI --- src/cmd/link/internal/ld/data.go | 3 +++ src/cmd/link/internal/ld/symtab.go | 11 +++++++++++ src/runtime/symtab.go | 12 ++++++++++++ src/runtime/type.go | 4 ++++ 4 files changed, 30 insertions(+) diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 5c4497cdd75b0f..a6b94a829f1442 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -424,6 +424,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) { // FIXME: It should be forbidden to have R_ADDR from a // symbol which isn't in .data. However, as .text has the // same address once loaded, this is possible. + // TODO: .text (including rodata) to .data relocation + // doesn't work correctly, so we should really disallow it. + // See also aixStaticDataBase in symtab.go and in runtime. if ldr.SymSect(s).Seg == &Segdata { Xcoffadddynrel(target, ldr, syms, s, r, ri) } diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go index 8156f83a7a3267..b89a7802a2c62a 100644 --- a/src/cmd/link/internal/ld/symtab.go +++ b/src/cmd/link/internal/ld/symtab.go @@ -707,6 +707,17 @@ func (ctxt *Link) symtab(pcln *pclntab) []sym.SymKind { // except go:buildid which is generated late and not used by the program. addRef("go:buildid") } + if ctxt.IsAIX() { + // On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol + // does not work. See data.go:relocsym, case R_ADDR. + // Here we record the unrelocated address in aixStaticDataBase (it is + // unrelocated as it is in RODATA) so we can compute the delta at + // run time. + sb := ldr.CreateSymForUpdate("runtime.aixStaticDataBase", 0) + sb.SetSize(0) + sb.AddAddr(ctxt.Arch, ldr.Lookup("runtime.data", 0)) + sb.SetType(sym.SRODATA) + } // text section information slice(textsectionmapSym, uint64(nsections)) diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go index c78b044264742d..c3bd5103205cf6 100644 --- a/src/runtime/symtab.go +++ b/src/runtime/symtab.go @@ -468,6 +468,18 @@ type modulehash struct { // To make sure the map isn't collected, we keep a second reference here. var pinnedTypemaps []map[typeOff]*_type +// aixStaticDataBase (used only on AIX) holds the unrelocated address +// of the data section, set by the linker. +// +// On AIX, an R_ADDR relocation from an RODATA symbol to a DATA symbol +// does not work, as the dynamic loader can change the address of the +// data section, and it is not possible to apply a dynamic relocation +// to RODATA. In order to get the correct address, we need to apply +// the delta between unrelocated and relocated data section addresses. +// aixStaticDataBase is the unrelocated address, and moduledata.data is +// the relocated one. +var aixStaticDataBase uintptr // linker symbol + var firstmoduledata moduledata // linker symbol var lastmoduledatap *moduledata // linker symbol diff --git a/src/runtime/type.go b/src/runtime/type.go index 9702164b1a261a..1edf9c9dd6d85c 100644 --- a/src/runtime/type.go +++ b/src/runtime/type.go @@ -104,6 +104,10 @@ func getGCMaskOnDemand(t *_type) *byte { // in read-only memory currently. addr := unsafe.Pointer(t.GCData) + if GOOS == "aix" { + addr = add(addr, firstmoduledata.data-aixStaticDataBase) + } + for { p := (*byte)(atomic.Loadp(addr)) switch p {