From 231012650beab5f157cae54735e359a12c159755 Mon Sep 17 00:00:00 2001
From: Clement <clement.chigot@atos.net>
Date: Wed, 23 Jan 2019 09:13:49 -0600
Subject: [PATCH 09/24] cmd/link: fix moduledata symbols for aix/ppc64 and
 external linker

Moduledata symbols like runtime.data or runtime.text must have the exact
same position in the final executable (as some symbols access are made
by offset from them).
Ld on AIX might move them randomly if there aren't real symbols.
---
 src/cmd/internal/objabi/reloctype.go |  5 +++
 src/cmd/link/internal/ld/data.go     | 78 ++++++++++++++++++++++++++++++++----
 src/cmd/link/internal/ld/lib.go      | 10 +++--
 src/cmd/link/internal/ld/symtab.go   | 14 +++++++
 src/cmd/link/internal/ld/xcoff.go    |  4 +-
 src/cmd/link/internal/ppc64/asm.go   |  3 ++
 6 files changed, 101 insertions(+), 13 deletions(-)

diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go
index 355882c638..f619e017d8 100644
--- a/src/cmd/internal/objabi/reloctype.go
+++ b/src/cmd/internal/objabi/reloctype.go
@@ -196,6 +196,11 @@ const (
 
 	// R_WASMIMPORT resolves to the index of the WebAssembly function import.
 	R_WASMIMPORT
+
+	// R_XCOFFREF (only used on aix/ppc64) prevents garbage collection by ld
+	// of a symbol. This isn't a real relocation, it can be placed in anywhere
+	// in a symbol and target any symbols.
+	R_XCOFFREF
 )
 
 // IsDirectJump reports whether r is a relocation for a direct jump.
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 92b3a35329..00f9ca65f9 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -478,6 +478,21 @@ func relocsym(ctxt *Link, s *sym.Symbol) {
 			o += r.Add - (s.Value + int64(r.Off) + int64(r.Siz))
 		case objabi.R_SIZE:
 			o = r.Sym.Size + r.Add
+
+		case objabi.R_XCOFFREF:
+			if ctxt.HeadType != objabi.Haix {
+				Errorf(s, "find XCOFF R_REF on non-XCOFF files")
+			}
+			if ctxt.LinkMode != LinkExternal {
+				Errorf(s, "find XCOFF R_REF with internal linking")
+			}
+			r.Xsym = r.Sym
+			r.Xadd = r.Add
+			r.Done = false
+
+			// This isn't a real relocation so it must not update
+			// its offset value.
+			continue
 		}
 
 		if r.Variant != sym.RV_NONE {
@@ -1116,7 +1131,7 @@ func (ctxt *Link) dodata() {
 		ctxt.Logf("%5.2f dodata\n", Cputime())
 	}
 
-	if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin {
+	if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
 		// The values in moduledata are filled out by relocations
 		// pointing to the addresses of these special symbols.
 		// Typically these symbols have no size and are not laid
@@ -1134,6 +1149,12 @@ func (ctxt *Link) dodata() {
 		// To work around this we lay out the symbls whose
 		// addresses are vital for multi-module programs to work
 		// as normal symbols, and give them a little size.
+		//
+		// On AIX, as all DATA sections are merged together, ld might not put
+		// these symbols at the beginning of their respective section if there
+		// aren't real symbols, their alignment might not match the
+		// first symbol alignment. Therefore, there are explicitly put at the
+		// beginning of their section with the same alignment.
 		bss := ctxt.Syms.Lookup("runtime.bss", 0)
 		bss.Size = 8
 		bss.Attr.Set(sym.AttrSpecial, false)
@@ -1144,7 +1165,12 @@ func (ctxt *Link) dodata() {
 		data.Size = 8
 		data.Attr.Set(sym.AttrSpecial, false)
 
-		ctxt.Syms.Lookup("runtime.edata", 0).Attr.Set(sym.AttrSpecial, false)
+		edata := ctxt.Syms.Lookup("runtime.edata", 0)
+		edata.Attr.Set(sym.AttrSpecial, false)
+		if ctxt.HeadType == objabi.Haix {
+			// XCOFFTOC symbols are part of .data section.
+			edata.Type = sym.SXCOFFTOC
+		}
 
 		types := ctxt.Syms.Lookup("runtime.types", 0)
 		types.Type = sym.STYPE
@@ -1154,6 +1180,16 @@ func (ctxt *Link) dodata() {
 		etypes := ctxt.Syms.Lookup("runtime.etypes", 0)
 		etypes.Type = sym.SFUNCTAB
 		etypes.Attr.Set(sym.AttrSpecial, false)
+
+		if ctxt.HeadType == objabi.Haix {
+			rodata := ctxt.Syms.Lookup("runtime.rodata", 0)
+			rodata.Type = sym.SSTRING
+			rodata.Size = 8
+			rodata.Attr.Set(sym.AttrSpecial, false)
+
+			ctxt.Syms.Lookup("runtime.erodata", 0).Attr.Set(sym.AttrSpecial, false)
+
+		}
 	}
 
 	// Collect data symbols by type into data.
@@ -1197,6 +1233,12 @@ func (ctxt *Link) dodata() {
 					// that an Outer symbol has been changed to a
 					// relro Type before it reaches here.
 					isRelro = true
+				case sym.SFUNCTAB:
+					if ctxt.HeadType == objabi.Haix && s.Name == "runtime.etypes" {
+						// runtime.etypes must be at the end of
+						// the relro datas.
+						isRelro = true
+					}
 				}
 				if isRelro {
 					s.Type = symnrelro
@@ -1238,6 +1280,13 @@ func (ctxt *Link) dodata() {
 	}
 	wg.Wait()
 
+	if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
+		// These symbols must have the same alignment as their section.
+		// Otherwize, ld might change the layout of Go sections.
+		ctxt.Syms.ROLookup("runtime.data", 0).Align = dataMaxAlign[sym.SDATA]
+		ctxt.Syms.ROLookup("runtime.bss", 0).Align = dataMaxAlign[sym.SBSS]
+	}
+
 	// Allocate sections.
 	// Data is processed before segtext, because we need
 	// to see all symbols in the .data and .bss sections in order
@@ -1351,7 +1400,9 @@ func (ctxt *Link) dodata() {
 		gc.AddSym(s)
 		datsize += s.Size
 	}
+	gc.End(datsize - int64(sect.Vaddr))
 	// On AIX, TOC entries must be the last of .data
+	// These aren't part of gc as they won't change during the runtime.
 	for _, s := range data[sym.SXCOFFTOC] {
 		s.Sect = sect
 		s.Type = sym.SDATA
@@ -1361,7 +1412,6 @@ func (ctxt *Link) dodata() {
 	}
 	checkdatsize(ctxt, datsize, sym.SDATA)
 	sect.Length = uint64(datsize) - sect.Vaddr
-	gc.End(int64(sect.Length))
 
 	/* bss */
 	sect = addsection(ctxt.Arch, &Segdata, ".bss", 06)
@@ -1556,8 +1606,15 @@ func (ctxt *Link) dodata() {
 		sect = addrelrosection("")
 
 		sect.Vaddr = 0
+		if ctxt.HeadType == objabi.Haix {
+			// datsize must be reset because relro datas will end up
+			// in data segment.
+			datsize = 0
+		}
+
 		ctxt.Syms.Lookup("runtime.types", 0).Sect = sect
 		ctxt.Syms.Lookup("runtime.etypes", 0).Sect = sect
+
 		for _, symnro := range sym.ReadOnly {
 			symn := sym.RelROMap[symnro]
 			align := dataMaxAlign[symn]
@@ -1779,12 +1836,12 @@ func dodataSect(ctxt *Link, symn sym.SymKind, syms []*sym.Symbol) (result []*sym
 		// If the usually-special section-marker symbols are being laid
 		// out as regular symbols, put them either at the beginning or
 		// end of their section.
-		if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin {
+		if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
 			switch s.Name {
-			case "runtime.text", "runtime.bss", "runtime.data", "runtime.types":
+			case "runtime.text", "runtime.bss", "runtime.data", "runtime.types", "runtime.rodata":
 				head = s
 				continue
-			case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes":
+			case "runtime.etext", "runtime.ebss", "runtime.edata", "runtime.etypes", "runtime.erodata":
 				tail = s
 				continue
 			}
@@ -1899,8 +1956,15 @@ func (ctxt *Link) textaddress() {
 
 	text := ctxt.Syms.Lookup("runtime.text", 0)
 	text.Sect = sect
+	if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
+		// Setting runtime.text has a real symbol prevents ld to
+		// change its base address resulting in wrong offsets for
+		// reflect methods.
+		text.Align = sect.Align
+		text.Size = 0x8
+	}
 
-	if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin {
+	if (ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
 		etext := ctxt.Syms.Lookup("runtime.etext", 0)
 		etext.Sect = sect
 
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 06fa071101..e99c81aeb7 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -2137,9 +2137,10 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
 	s := ctxt.Syms.Lookup("runtime.text", 0)
 	if s.Type == sym.STEXT {
 		// We've already included this symbol in ctxt.Textp
-		// if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin.
+		// if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin or
+		// on AIX with external linker.
 		// See data.go:/textaddress
-		if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) {
+		if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
 			put(ctxt, s, s.Name, TextSym, s.Value, nil)
 		}
 	}
@@ -2168,9 +2169,10 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
 	s = ctxt.Syms.Lookup("runtime.etext", 0)
 	if s.Type == sym.STEXT {
 		// We've already included this symbol in ctxt.Textp
-		// if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin.
+		// if ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin or
+		// on AIX with external linker.
 		// See data.go:/textaddress
-		if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) {
+		if !(ctxt.DynlinkingGo() && ctxt.HeadType == objabi.Hdarwin) && !(ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
 			put(ctxt, s, s.Name, TextSym, s.Value, nil)
 		}
 	}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index 7c296d766c..b968e0eff5 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -562,6 +562,20 @@ func (ctxt *Link) symtab() {
 	moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.types", 0))
 	moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.etypes", 0))
 
+	if ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal {
+		// Add R_REF relocation to prevent garbage collection of
+		// runtime.rodata, runtime.erodata and runtime.epclntab.
+		addRef := func(name string) {
+			r := moduledata.AddRel()
+			r.Sym = ctxt.Syms.Lookup(name, 0)
+			r.Type = objabi.R_XCOFFREF
+			r.Siz = uint8(ctxt.Arch.PtrSize)
+		}
+		addRef("runtime.rodata")
+		addRef("runtime.erodata")
+		addRef("runtime.epclntab")
+	}
+
 	// text section information
 	moduledata.AddAddr(ctxt.Arch, ctxt.Syms.Lookup("runtime.textsectionmap", 0))
 	moduledata.AddUint(ctxt.Arch, uint64(nsections))
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index 1b6ceba21f..2e6cce2925 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -586,7 +586,8 @@ func xcoffUpdateOuterSize(ctxt *Link, size int64, stype sym.SymKind) {
 		fallthrough
 	case sym.STYPE:
 		if !ctxt.DynlinkingGo() {
-			outerSymSize["type.*"] = size
+			// runtime.types size must be removed.
+			outerSymSize["type.*"] = size - 8
 		}
 	case sym.SGOSTRING:
 		outerSymSize["go.string.*"] = size
@@ -1566,7 +1567,6 @@ func (f *xcoffFile) emitRelocations(ctxt *Link, fileoff int64) {
 
 				r := &s.R[ri]
 
-				// ctxt.Logf("%s reloc %d(%s)/%d to %s\n", s, r.Type, r.Type.String(), r.Siz, r.Sym.Name)
 				if r.Done {
 					continue
 				}
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 000a838e1b..70b3d2bd6d 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -414,6 +414,9 @@ func xcoffreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, se
 			return false
 		}
 		emitReloc(ld.XCOFF_R_RBR|0x19<<8, 0)
+	case objabi.R_XCOFFREF:
+		emitReloc(ld.XCOFF_R_REF|0x3F<<8, 0)
+
 	}
 	return true
 
-- 
2.15.1

