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 {