[dev.link] cmd/link: fix data race on AIX

On AIX, in relocsym we call Xcoffadddynrel, which adds a
relocation record to a global array. relocsym already runs in
parallel. In the past we only parallelize over segments, and
we call Xcoffadddynrel only for symbols in data segment, so it is
effectively called sequentially. In CL 239197 we started to do
more fine-grained parallelism, so we need to make sure it is safe
to call Xcoffadddynrel in parallel.

Fix AIX build.

Change-Id: I3128193995a5a99d9fa04c8e728e590f17298da3
Reviewed-on: https://go-review.googlesource.com/c/go/+/239561
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index e5ed847..9e3b8e2 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -16,6 +16,7 @@
 	"path/filepath"
 	"sort"
 	"strings"
+	"sync"
 )
 
 // This file handles all algorithms related to XCOFF files generation.
@@ -417,6 +418,7 @@
 	dynLibraries    map[string]int       // Dynamic libraries in .loader section. The integer represents its import file number (- 1)
 	loaderSymbols   []*xcoffLoaderSymbol // symbols inside .loader symbol table
 	loaderReloc     []*xcoffLoaderReloc  // Reloc that must be made inside loader
+	sync.Mutex                           // currently protect loaderReloc
 }
 
 // Var used by XCOFF Generation algorithms
@@ -1265,7 +1267,9 @@
 		xldr.rtype = 0x3F<<8 + XCOFF_R_POS
 	}
 
+	xfile.Lock()
 	xfile.loaderReloc = append(xfile.loaderReloc, xldr)
+	xfile.Unlock()
 	return true
 }
 
@@ -1398,6 +1402,21 @@
 	off := hdr.Lrldoff                                // current offset is the same of reloc offset
 
 	/* Reloc */
+	// Ensure deterministic order
+	sort.Slice(f.loaderReloc, func(i, j int) bool {
+		r1, r2 := f.loaderReloc[i], f.loaderReloc[j]
+		if r1.sym != r2.sym {
+			return r1.sym < r2.sym
+		}
+		if r1.roff != r2.roff {
+			return r1.roff < r2.roff
+		}
+		if r1.rtype != r2.rtype {
+			return r1.rtype < r2.rtype
+		}
+		return r1.symndx < r2.symndx
+	})
+
 	ep := ldr.Lookup(*flagEntrySymbol, 0)
 	xldr := &XcoffLdRel64{
 		Lvaddr:  uint64(ldr.SymValue(ep)),