From 661e7c99376b69cd2d6c41e3fb5de92112deb7fb Mon Sep 17 00:00:00 2001
From: Clement <clement.chigot@atos.net>
Date: Mon, 4 Feb 2019 11:08:24 -0600
Subject: [PATCH 14/24] cmd/link: fix trampoline generation for aix/ppc64

---
 src/cmd/link/internal/ld/data.go   | 44 ++++++++++++++++++----
 src/cmd/link/internal/ld/lib.go    |  3 +-
 src/cmd/link/internal/ld/xcoff.go  |  8 +++-
 src/cmd/link/internal/ppc64/asm.go | 75 ++++++++++++++++++++++++++------------
 4 files changed, 96 insertions(+), 34 deletions(-)

diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index df35f4d128..3baec20a0a 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1991,6 +1991,10 @@ func (ctxt *Link) textaddress() {
 		// lay down trampolines after each function
 		for ; ntramps < len(ctxt.tramps); ntramps++ {
 			tramp := ctxt.tramps[ntramps]
+			if ctxt.HeadType == objabi.Haix && strings.HasPrefix(tramp.Name, "runtime.text") {
+				// Already set in assignAddress
+				continue
+			}
 			sect, n, va = assignAddress(ctxt, sect, n, tramp, va, true)
 		}
 	}
@@ -2031,10 +2035,6 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
 	} else {
 		va = uint64(Rnd(int64(va), int64(Funcalign)))
 	}
-	s.Value = 0
-	for sub := s; sub != nil; sub = sub.Sub {
-		sub.Value += int64(va)
-	}
 
 	funcsize := uint64(MINFUNC) // spacing required for findfunctab
 	if s.Size > MINFUNC {
@@ -2050,7 +2050,7 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
 
 	// Only break at outermost syms.
 
-	if ctxt.Arch.InFamily(sys.PPC64) && s.Outer == nil && ctxt.IsELF && ctxt.LinkMode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(s, isTramp) > 0x1c00000 {
+	if ctxt.Arch.InFamily(sys.PPC64) && s.Outer == nil && ctxt.LinkMode == LinkExternal && va-sect.Vaddr+funcsize+maxSizeTrampolinesPPC64(s, isTramp) > 0x1c00000 {
 		// Set the length for the previous text section
 		sect.Length = va - sect.Vaddr
 
@@ -2060,9 +2060,35 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
 		s.Sect = sect
 
 		// Create a symbol for the start of the secondary text sections
-		ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0).Sect = sect
+		ntext := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
+		ntext.Sect = sect
+		if ctxt.HeadType == objabi.Haix {
+			// runtime.text.X must be a real symbol on AIX.
+			// Assign its address directly in order to be the
+			// first symbol of this new section.
+			ntext.Type = sym.STEXT
+			ntext.Size = int64(MINFUNC)
+			ntext.Attr |= sym.AttrReachable
+			ntext.Attr |= sym.AttrOnList
+			ctxt.tramps = append(ctxt.tramps, ntext)
+
+			ntext.Value = int64(va)
+			va += uint64(ntext.Size)
+
+			if s.Align != 0 {
+				va = uint64(Rnd(int64(va), int64(s.Align)))
+			} else {
+				va = uint64(Rnd(int64(va), int64(Funcalign)))
+			}
+		}
 		n++
 	}
+
+	s.Value = 0
+	for sub := s; sub != nil; sub = sub.Sub {
+		sub.Value += int64(va)
+	}
+
 	va += funcsize
 
 	return sect, n, va
@@ -2248,7 +2274,11 @@ func (ctxt *Link) address() []*sym.Segment {
 			break
 		}
 		symname := fmt.Sprintf("runtime.text.%d", n)
-		ctxt.xdefine(symname, sym.STEXT, int64(sect.Vaddr))
+		if ctxt.HeadType != objabi.Haix || ctxt.LinkMode != LinkExternal {
+			// Addresses are already set on AIX with external linker
+			// because these symbols are part of their sections.
+			ctxt.xdefine(symname, sym.STEXT, int64(sect.Vaddr))
+		}
 		n++
 	}
 
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 3d18482379..19d04461c3 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -2174,7 +2174,8 @@ func genasmsym(ctxt *Link, put func(*Link, *sym.Symbol, string, SymbolType, int6
 			n++
 			continue
 		}
-		if sect.Name != ".text" {
+		if sect.Name != ".text" || (ctxt.HeadType == objabi.Haix && ctxt.LinkMode == LinkExternal) {
+			// On AIX, runtime.text.X are symbols already in the symtab.
 			break
 		}
 		s = ctxt.Syms.ROLookup(fmt.Sprintf("runtime.text.%d", n), 0)
diff --git a/src/cmd/link/internal/ld/xcoff.go b/src/cmd/link/internal/ld/xcoff.go
index e33f53b7e3..ca95d5945e 100644
--- a/src/cmd/link/internal/ld/xcoff.go
+++ b/src/cmd/link/internal/ld/xcoff.go
@@ -783,7 +783,11 @@ func (f *xcoffFile) writeSymbolFunc(ctxt *Link, x *sym.Symbol) []xcoffSym {
 	syms := []xcoffSym{}
 
 	// Check if a new file is detected.
-	if x.File == "" { // Undefined global symbol
+	if strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
+		// Trampoline don't have a FILE so there are considered
+		// in the current file.
+		// Same goes for runtime.text.X symbols.
+	} else if x.File == "" { // Undefined global symbol
 		// If this happens, the algorithme must be redone.
 		if currSymSrcFile.name != "" {
 			Exitf("undefined global symbol found inside another file")
@@ -866,7 +870,7 @@ func putaixsym(ctxt *Link, x *sym.Symbol, str string, t SymbolType, addr int64,
 		return
 
 	case TextSym:
-		if x.FuncInfo != nil {
+		if x.FuncInfo != nil || strings.Contains(x.Name, "-tramp") || strings.HasPrefix(x.Name, "runtime.text.") {
 			// Function within a file
 			syms = xfile.writeSymbolFunc(ctxt, x)
 		} else {
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 70b3d2bd6d..fc4892b1d6 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -684,7 +684,7 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
 
 				// With internal linking, the trampoline can be used if it is not too far.
 				// With external linking, the trampoline must be in this section for it to be reused.
-				if (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ctxt.LinkMode == ld.LinkExternal && s.Sect == tramp.Sect) {
+				if ((ctxt.LinkMode == ld.LinkInternal) && int64(int32((t)<<6)>>6) == t) || (ctxt.LinkMode == ld.LinkExternal && s.Sect == tramp.Sect) {
 					break
 				}
 			}
@@ -694,7 +694,7 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
 					ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
 				} else {
 					ctxt.AddTramp(tramp)
-					gentramp(ctxt.Arch, ctxt.LinkMode, tramp, r.Sym, r.Add)
+					gentramp(ctxt, tramp, r.Sym, r.Add)
 				}
 			}
 			r.Sym = tramp
@@ -706,40 +706,67 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
 	}
 }
 
-func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, offset int64) {
-	// Used for default build mode for an executable
-	// Address of the call target is generated using
-	// relocation and doesn't depend on r2 (TOC).
+func gentramp(ctxt *ld.Link, tramp, target *sym.Symbol, offset int64) {
 	tramp.Size = 16 // 4 instructions
 	tramp.P = make([]byte, tramp.Size)
 	t := ld.Symaddr(target) + offset
-	o1 := uint32(0x3fe00000) // lis r31,targetaddr hi
-	o2 := uint32(0x3bff0000) // addi r31,targetaddr lo
-	// With external linking, the target address must be
-	// relocated using LO and HA
-	if linkmode == ld.LinkExternal {
+	var o1, o2 uint32
+
+	if ctxt.HeadType == objabi.Haix {
+		// On AIX, the address is retrieved with a TOC symbol.
+		// For internal linking, the "Linux" way might still be used.
+		// However, all text symbols are accessed with a TOC symbol as
+		// text relocations aren't supposed to be possible.
+		// So, keep using the external linking way to be more AIX friendly.
+		o1 = uint32(0x3fe20000) // lis r2, toctargetaddr hi
+		o2 = uint32(0xebff0000) // ld r31, toctargetaddr lo
+
+		toctramp := ctxt.Syms.Lookup("TOC."+tramp.Name, 0)
+		toctramp.Type = sym.SXCOFFTOC
+		toctramp.Attr |= sym.AttrReachable
+		toctramp.AddAddr(ctxt.Arch, target)
+
 		tr := tramp.AddRel()
 		tr.Off = 0
-		tr.Type = objabi.R_ADDRPOWER
+		tr.Type = objabi.R_ADDRPOWER_TOCREL_DS
 		tr.Siz = 8 // generates 2 relocations:  HA + LO
-		tr.Sym = target
+		tr.Sym = toctramp
 		tr.Add = offset
 	} else {
-		// adjustment needed if lo has sign bit set
-		// when using addi to compute address
-		val := uint32((t & 0xffff0000) >> 16)
-		if t&0x8000 != 0 {
-			val += 1
+		// Used for default build mode for an executable
+		// Address of the call target is generated using
+		// relocation and doesn't depend on r2 (TOC).
+		o1 = uint32(0x3fe00000) // lis r31,targetaddr hi
+		o2 = uint32(0x3bff0000) // addi r31,targetaddr lo
+
+		// With external linking, the target address must be
+		// relocated using LO and HA
+		if ctxt.LinkMode == ld.LinkExternal {
+			tr := tramp.AddRel()
+			tr.Off = 0
+			tr.Type = objabi.R_ADDRPOWER
+			tr.Siz = 8 // generates 2 relocations:  HA + LO
+			tr.Sym = target
+			tr.Add = offset
+
+		} else {
+			// adjustment needed if lo has sign bit set
+			// when using addi to compute address
+			val := uint32((t & 0xffff0000) >> 16)
+			if t&0x8000 != 0 {
+				val += 1
+			}
+			o1 |= val                // hi part of addr
+			o2 |= uint32(t & 0xffff) // lo part of addr
 		}
-		o1 |= val                // hi part of addr
-		o2 |= uint32(t & 0xffff) // lo part of addr
 	}
+
 	o3 := uint32(0x7fe903a6) // mtctr r31
 	o4 := uint32(0x4e800420) // bctr
-	arch.ByteOrder.PutUint32(tramp.P, o1)
-	arch.ByteOrder.PutUint32(tramp.P[4:], o2)
-	arch.ByteOrder.PutUint32(tramp.P[8:], o3)
-	arch.ByteOrder.PutUint32(tramp.P[12:], o4)
+	ctxt.Arch.ByteOrder.PutUint32(tramp.P, o1)
+	ctxt.Arch.ByteOrder.PutUint32(tramp.P[4:], o2)
+	ctxt.Arch.ByteOrder.PutUint32(tramp.P[8:], o3)
+	ctxt.Arch.ByteOrder.PutUint32(tramp.P[12:], o4)
 }
 
 func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val int64) (int64, bool) {
-- 
2.15.1

