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 <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
Cherry Mui 2024-12-20 22:33:15 -05:00
parent eef35e3bd9
commit b9955f0ad9
4 changed files with 30 additions and 0 deletions

View file

@ -424,6 +424,9 @@ func (st *relocSymState) relocsym(s loader.Sym, P []byte) {
// FIXME: It should be forbidden to have R_ADDR from a // FIXME: It should be forbidden to have R_ADDR from a
// symbol which isn't in .data. However, as .text has the // symbol which isn't in .data. However, as .text has the
// same address once loaded, this is possible. // 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 { if ldr.SymSect(s).Seg == &Segdata {
Xcoffadddynrel(target, ldr, syms, s, r, ri) Xcoffadddynrel(target, ldr, syms, s, r, ri)
} }

View file

@ -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. // except go:buildid which is generated late and not used by the program.
addRef("go:buildid") 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 // text section information
slice(textsectionmapSym, uint64(nsections)) slice(textsectionmapSym, uint64(nsections))

View file

@ -468,6 +468,18 @@ type modulehash struct {
// To make sure the map isn't collected, we keep a second reference here. // To make sure the map isn't collected, we keep a second reference here.
var pinnedTypemaps []map[typeOff]*_type 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 firstmoduledata moduledata // linker symbol
var lastmoduledatap *moduledata // linker symbol var lastmoduledatap *moduledata // linker symbol

View file

@ -104,6 +104,10 @@ func getGCMaskOnDemand(t *_type) *byte {
// in read-only memory currently. // in read-only memory currently.
addr := unsafe.Pointer(t.GCData) addr := unsafe.Pointer(t.GCData)
if GOOS == "aix" {
addr = add(addr, firstmoduledata.data-aixStaticDataBase)
}
for { for {
p := (*byte)(atomic.Loadp(addr)) p := (*byte)(atomic.Loadp(addr))
switch p { switch p {