github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/src/cmd/link/internal/ppc64/asm.go (about)

     1  // Inferno utils/5l/asm.c
     2  // http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.c
     3  //
     4  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     5  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     6  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     7  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     8  //	Portions Copyright © 2004,2006 Bruce Ellis
     9  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    10  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    11  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    12  //
    13  // Permission is hereby granted, free of charge, to any person obtaining a copy
    14  // of this software and associated documentation files (the "Software"), to deal
    15  // in the Software without restriction, including without limitation the rights
    16  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    17  // copies of the Software, and to permit persons to whom the Software is
    18  // furnished to do so, subject to the following conditions:
    19  //
    20  // The above copyright notice and this permission notice shall be included in
    21  // all copies or substantial portions of the Software.
    22  //
    23  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    24  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    25  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    26  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    27  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    28  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    29  // THE SOFTWARE.
    30  
    31  package ppc64
    32  
    33  import (
    34  	"cmd/internal/obj"
    35  	"cmd/link/internal/ld"
    36  	"encoding/binary"
    37  	"fmt"
    38  	"log"
    39  )
    40  
    41  func gentext() {
    42  	var s *ld.LSym
    43  	var stub *ld.LSym
    44  	var pprevtextp **ld.LSym
    45  	var r *ld.Reloc
    46  	var n string
    47  	var o1 uint32
    48  	var i int
    49  
    50  	// The ppc64 ABI PLT has similar concepts to other
    51  	// architectures, but is laid out quite differently.  When we
    52  	// see an R_PPC64_REL24 relocation to a dynamic symbol
    53  	// (indicating that the call needs to go through the PLT), we
    54  	// generate up to three stubs and reserve a PLT slot.
    55  	//
    56  	// 1) The call site will be bl x; nop (where the relocation
    57  	//    applies to the bl).  We rewrite this to bl x_stub; ld
    58  	//    r2,24(r1).  The ld is necessary because x_stub will save
    59  	//    r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
    60  	//
    61  	// 2) We reserve space for a pointer in the .plt section (once
    62  	//    per referenced dynamic function).  .plt is a data
    63  	//    section filled solely by the dynamic linker (more like
    64  	//    .plt.got on other architectures).  Initially, the
    65  	//    dynamic linker will fill each slot with a pointer to the
    66  	//    corresponding x@plt entry point.
    67  	//
    68  	// 3) We generate the "call stub" x_stub (once per dynamic
    69  	//    function/object file pair).  This saves the TOC in the
    70  	//    TOC save slot, reads the function pointer from x's .plt
    71  	//    slot and calls it like any other global entry point
    72  	//    (including setting r12 to the function address).
    73  	//
    74  	// 4) We generate the "symbol resolver stub" x@plt (once per
    75  	//    dynamic function).  This is solely a branch to the glink
    76  	//    resolver stub.
    77  	//
    78  	// 5) We generate the glink resolver stub (only once).  This
    79  	//    computes which symbol resolver stub we came through and
    80  	//    invokes the dynamic resolver via a pointer provided by
    81  	//    the dynamic linker.  This will patch up the .plt slot to
    82  	//    point directly at the function so future calls go
    83  	//    straight from the call stub to the real function, and
    84  	//    then call the function.
    85  
    86  	// NOTE: It's possible we could make ppc64 closer to other
    87  	// architectures: ppc64's .plt is like .plt.got on other
    88  	// platforms and ppc64's .glink is like .plt on other
    89  	// platforms.
    90  
    91  	// Find all R_PPC64_REL24 relocations that reference dynamic
    92  	// imports.  Reserve PLT entries for these symbols and
    93  	// generate call stubs.  The call stubs need to live in .text,
    94  	// which is why we need to do this pass this early.
    95  	//
    96  	// This assumes "case 1" from the ABI, where the caller needs
    97  	// us to save and restore the TOC pointer.
    98  	pprevtextp = &ld.Ctxt.Textp
    99  
   100  	for s = *pprevtextp; s != nil; pprevtextp, s = &s.Next, s.Next {
   101  		for i = range s.R {
   102  			r = &s.R[i]
   103  			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != obj.SDYNIMPORT {
   104  				continue
   105  			}
   106  
   107  			// Reserve PLT entry and generate symbol
   108  			// resolver
   109  			addpltsym(ld.Ctxt, r.Sym)
   110  
   111  			// Generate call stub
   112  			n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
   113  
   114  			stub = ld.Linklookup(ld.Ctxt, n, 0)
   115  			stub.Reachable = stub.Reachable || s.Reachable
   116  			if stub.Size == 0 {
   117  				// Need outer to resolve .TOC.
   118  				stub.Outer = s
   119  
   120  				// Link in to textp before s (we could
   121  				// do it after, but would have to skip
   122  				// the subsymbols)
   123  				*pprevtextp = stub
   124  
   125  				stub.Next = s
   126  				pprevtextp = &stub.Next
   127  
   128  				gencallstub(1, stub, r.Sym)
   129  			}
   130  
   131  			// Update the relocation to use the call stub
   132  			r.Sym = stub
   133  
   134  			// Restore TOC after bl.  The compiler put a
   135  			// nop here for us to overwrite.
   136  			o1 = 0xe8410018 // ld r2,24(r1)
   137  			ld.Ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
   138  		}
   139  	}
   140  }
   141  
   142  // Construct a call stub in stub that calls symbol targ via its PLT
   143  // entry.
   144  func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
   145  	if abicase != 1 {
   146  		// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
   147  		// relocations, we'll need to implement cases 2 and 3.
   148  		log.Fatalf("gencallstub only implements case 1 calls")
   149  	}
   150  
   151  	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
   152  
   153  	stub.Type = obj.STEXT
   154  
   155  	// Save TOC pointer in TOC save slot
   156  	ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
   157  
   158  	// Load the function pointer from the PLT.
   159  	r := ld.Addrel(stub)
   160  
   161  	r.Off = int32(stub.Size)
   162  	r.Sym = plt
   163  	r.Add = int64(targ.Plt)
   164  	r.Siz = 2
   165  	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   166  		r.Off += int32(r.Siz)
   167  	}
   168  	r.Type = obj.R_POWER_TOC
   169  	r.Variant = ld.RV_POWER_HA
   170  	ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
   171  	r = ld.Addrel(stub)
   172  	r.Off = int32(stub.Size)
   173  	r.Sym = plt
   174  	r.Add = int64(targ.Plt)
   175  	r.Siz = 2
   176  	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   177  		r.Off += int32(r.Siz)
   178  	}
   179  	r.Type = obj.R_POWER_TOC
   180  	r.Variant = ld.RV_POWER_LO
   181  	ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
   182  
   183  	// Jump to the loaded pointer
   184  	ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
   185  	ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
   186  }
   187  
   188  func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
   189  	log.Fatalf("adddynrela not implemented")
   190  }
   191  
   192  func adddynrel(s *ld.LSym, r *ld.Reloc) {
   193  	targ := r.Sym
   194  	ld.Ctxt.Cursym = s
   195  
   196  	switch r.Type {
   197  	default:
   198  		if r.Type >= 256 {
   199  			ld.Diag("unexpected relocation type %d", r.Type)
   200  			return
   201  		}
   202  
   203  		// Handle relocations found in ELF object files.
   204  	case 256 + ld.R_PPC64_REL24:
   205  		r.Type = obj.R_CALLPOWER
   206  
   207  		// This is a local call, so the caller isn't setting
   208  		// up r12 and r2 is the same for the caller and
   209  		// callee.  Hence, we need to go to the local entry
   210  		// point.  (If we don't do this, the callee will try
   211  		// to use r12 to compute r2.)
   212  		r.Add += int64(r.Sym.Localentry) * 4
   213  
   214  		if targ.Type == obj.SDYNIMPORT {
   215  			// Should have been handled in elfsetupplt
   216  			ld.Diag("unexpected R_PPC64_REL24 for dyn import")
   217  		}
   218  
   219  		return
   220  
   221  	case 256 + ld.R_PPC64_ADDR64:
   222  		r.Type = obj.R_ADDR
   223  		if targ.Type == obj.SDYNIMPORT {
   224  			// These happen in .toc sections
   225  			ld.Adddynsym(ld.Ctxt, targ)
   226  
   227  			rela := ld.Linklookup(ld.Ctxt, ".rela", 0)
   228  			ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
   229  			ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
   230  			ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
   231  			r.Type = 256 // ignore during relocsym
   232  		}
   233  
   234  		return
   235  
   236  	case 256 + ld.R_PPC64_TOC16:
   237  		r.Type = obj.R_POWER_TOC
   238  		r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
   239  		return
   240  
   241  	case 256 + ld.R_PPC64_TOC16_LO:
   242  		r.Type = obj.R_POWER_TOC
   243  		r.Variant = ld.RV_POWER_LO
   244  		return
   245  
   246  	case 256 + ld.R_PPC64_TOC16_HA:
   247  		r.Type = obj.R_POWER_TOC
   248  		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
   249  		return
   250  
   251  	case 256 + ld.R_PPC64_TOC16_HI:
   252  		r.Type = obj.R_POWER_TOC
   253  		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
   254  		return
   255  
   256  	case 256 + ld.R_PPC64_TOC16_DS:
   257  		r.Type = obj.R_POWER_TOC
   258  		r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
   259  		return
   260  
   261  	case 256 + ld.R_PPC64_TOC16_LO_DS:
   262  		r.Type = obj.R_POWER_TOC
   263  		r.Variant = ld.RV_POWER_DS
   264  		return
   265  
   266  	case 256 + ld.R_PPC64_REL16_LO:
   267  		r.Type = obj.R_PCREL
   268  		r.Variant = ld.RV_POWER_LO
   269  		r.Add += 2 // Compensate for relocation size of 2
   270  		return
   271  
   272  	case 256 + ld.R_PPC64_REL16_HI:
   273  		r.Type = obj.R_PCREL
   274  		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
   275  		r.Add += 2
   276  		return
   277  
   278  	case 256 + ld.R_PPC64_REL16_HA:
   279  		r.Type = obj.R_PCREL
   280  		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
   281  		r.Add += 2
   282  		return
   283  	}
   284  
   285  	// Handle references to ELF symbols from our own object files.
   286  	if targ.Type != obj.SDYNIMPORT {
   287  		return
   288  	}
   289  
   290  	// TODO(austin): Translate our relocations to ELF
   291  
   292  	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
   293  }
   294  
   295  func elfreloc1(r *ld.Reloc, sectoff int64) int {
   296  	// TODO(minux)
   297  	return -1
   298  }
   299  
   300  func elfsetupplt() {
   301  	plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
   302  	if plt.Size == 0 {
   303  		// The dynamic linker stores the address of the
   304  		// dynamic resolver and the DSO identifier in the two
   305  		// doublewords at the beginning of the .plt section
   306  		// before the PLT array.  Reserve space for these.
   307  		plt.Size = 16
   308  	}
   309  }
   310  
   311  func machoreloc1(r *ld.Reloc, sectoff int64) int {
   312  	return -1
   313  }
   314  
   315  // Return the value of .TOC. for symbol s
   316  func symtoc(s *ld.LSym) int64 {
   317  	var toc *ld.LSym
   318  
   319  	if s.Outer != nil {
   320  		toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
   321  	} else {
   322  		toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
   323  	}
   324  
   325  	if toc == nil {
   326  		ld.Diag("TOC-relative relocation in object without .TOC.")
   327  		return 0
   328  	}
   329  
   330  	return toc.Value
   331  }
   332  
   333  func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
   334  	if ld.Linkmode == ld.LinkExternal {
   335  		// TODO(minux): translate R_ADDRPOWER and R_CALLPOWER into standard ELF relocations.
   336  		// R_ADDRPOWER corresponds to R_PPC_ADDR16_HA and R_PPC_ADDR16_LO.
   337  		// R_CALLPOWER corresponds to R_PPC_REL24.
   338  		return -1
   339  	}
   340  
   341  	switch r.Type {
   342  	case obj.R_CONST:
   343  		*val = r.Add
   344  		return 0
   345  
   346  	case obj.R_GOTOFF:
   347  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
   348  		return 0
   349  
   350  	case obj.R_ADDRPOWER:
   351  		// r->add is two ppc64 instructions holding an immediate 32-bit constant.
   352  		// We want to add r->sym's address to that constant.
   353  		// The encoding of the immediate x<<16 + y,
   354  		// where x is the low 16 bits of the first instruction and y is the low 16
   355  		// bits of the second. Both x and y are signed (int16, not uint16).
   356  		o1 := uint32(r.Add >> 32)
   357  		o2 := uint32(r.Add)
   358  		t := ld.Symaddr(r.Sym)
   359  		if t < 0 {
   360  			ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
   361  		}
   362  
   363  		t += int64((o1&0xffff)<<16 + uint32(int32(o2)<<16>>16))
   364  		if t&0x8000 != 0 {
   365  			t += 0x10000
   366  		}
   367  		o1 = o1&0xffff0000 | (uint32(t)>>16)&0xffff
   368  		o2 = o2&0xffff0000 | uint32(t)&0xffff
   369  
   370  		// when laid out, the instruction order must always be o1, o2.
   371  		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   372  			*val = int64(o1)<<32 | int64(o2)
   373  		} else {
   374  			*val = int64(o2)<<32 | int64(o1)
   375  		}
   376  		return 0
   377  
   378  	case obj.R_CALLPOWER:
   379  		// Bits 6 through 29 = (S + A - P) >> 2
   380  		var o1 uint32
   381  		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   382  			o1 = ld.Be32(s.P[r.Off:])
   383  		} else {
   384  			o1 = ld.Le32(s.P[r.Off:])
   385  		}
   386  
   387  		t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
   388  		if t&3 != 0 {
   389  			ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
   390  		}
   391  		if int64(int32(t<<6)>>6) != t {
   392  			// TODO(austin) This can happen if text > 32M.
   393  			// Add a call trampoline to .text in that case.
   394  			ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
   395  		}
   396  
   397  		*val = int64(o1&0xfc000003 | uint32(t)&^0xfc000003)
   398  		return 0
   399  
   400  	case obj.R_POWER_TOC: // S + A - .TOC.
   401  		*val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
   402  
   403  		return 0
   404  	}
   405  
   406  	return -1
   407  }
   408  
   409  func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
   410  	switch r.Variant & ld.RV_TYPE_MASK {
   411  	default:
   412  		ld.Diag("unexpected relocation variant %d", r.Variant)
   413  		fallthrough
   414  
   415  	case ld.RV_NONE:
   416  		return t
   417  
   418  	case ld.RV_POWER_LO:
   419  		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
   420  			// Whether to check for signed or unsigned
   421  			// overflow depends on the instruction
   422  			var o1 uint32
   423  			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   424  				o1 = ld.Be32(s.P[r.Off-2:])
   425  			} else {
   426  				o1 = ld.Le32(s.P[r.Off:])
   427  			}
   428  			switch o1 >> 26 {
   429  			case 24, // ori
   430  				26, // xori
   431  				28: // andi
   432  				if t>>16 != 0 {
   433  					goto overflow
   434  				}
   435  
   436  			default:
   437  				if int64(int16(t)) != t {
   438  					goto overflow
   439  				}
   440  			}
   441  		}
   442  
   443  		return int64(int16(t))
   444  
   445  	case ld.RV_POWER_HA:
   446  		t += 0x8000
   447  		fallthrough
   448  
   449  		// Fallthrough
   450  	case ld.RV_POWER_HI:
   451  		t >>= 16
   452  
   453  		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
   454  			// Whether to check for signed or unsigned
   455  			// overflow depends on the instruction
   456  			var o1 uint32
   457  			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   458  				o1 = ld.Be32(s.P[r.Off-2:])
   459  			} else {
   460  				o1 = ld.Le32(s.P[r.Off:])
   461  			}
   462  			switch o1 >> 26 {
   463  			case 25, // oris
   464  				27, // xoris
   465  				29: // andis
   466  				if t>>16 != 0 {
   467  					goto overflow
   468  				}
   469  
   470  			default:
   471  				if int64(int16(t)) != t {
   472  					goto overflow
   473  				}
   474  			}
   475  		}
   476  
   477  		return int64(int16(t))
   478  
   479  	case ld.RV_POWER_DS:
   480  		var o1 uint32
   481  		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
   482  			o1 = uint32(ld.Be16(s.P[r.Off:]))
   483  		} else {
   484  			o1 = uint32(ld.Le16(s.P[r.Off:]))
   485  		}
   486  		if t&3 != 0 {
   487  			ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
   488  		}
   489  		if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
   490  			goto overflow
   491  		}
   492  		return int64(o1)&0x3 | int64(int16(t))
   493  	}
   494  
   495  overflow:
   496  	ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
   497  	return t
   498  }
   499  
   500  func addpltsym(ctxt *ld.Link, s *ld.LSym) {
   501  	if s.Plt >= 0 {
   502  		return
   503  	}
   504  
   505  	ld.Adddynsym(ctxt, s)
   506  
   507  	if ld.Iself {
   508  		plt := ld.Linklookup(ctxt, ".plt", 0)
   509  		rela := ld.Linklookup(ctxt, ".rela.plt", 0)
   510  		if plt.Size == 0 {
   511  			elfsetupplt()
   512  		}
   513  
   514  		// Create the glink resolver if necessary
   515  		glink := ensureglinkresolver()
   516  
   517  		// Write symbol resolver stub (just a branch to the
   518  		// glink resolver stub)
   519  		r := ld.Addrel(glink)
   520  
   521  		r.Sym = glink
   522  		r.Off = int32(glink.Size)
   523  		r.Siz = 4
   524  		r.Type = obj.R_CALLPOWER
   525  		ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
   526  
   527  		// In the ppc64 ABI, the dynamic linker is responsible
   528  		// for writing the entire PLT.  We just need to
   529  		// reserve 8 bytes for each PLT entry and generate a
   530  		// JMP_SLOT dynamic relocation for it.
   531  		//
   532  		// TODO(austin): ABI v1 is different
   533  		s.Plt = int32(plt.Size)
   534  
   535  		plt.Size += 8
   536  
   537  		ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
   538  		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
   539  		ld.Adduint64(ctxt, rela, 0)
   540  	} else {
   541  		ld.Diag("addpltsym: unsupported binary format")
   542  	}
   543  }
   544  
   545  // Generate the glink resolver stub if necessary and return the .glink section
   546  func ensureglinkresolver() *ld.LSym {
   547  	glink := ld.Linklookup(ld.Ctxt, ".glink", 0)
   548  	if glink.Size != 0 {
   549  		return glink
   550  	}
   551  
   552  	// This is essentially the resolver from the ppc64 ELF ABI.
   553  	// At entry, r12 holds the address of the symbol resolver stub
   554  	// for the target routine and the argument registers hold the
   555  	// arguments for the target routine.
   556  	//
   557  	// This stub is PIC, so first get the PC of label 1 into r11.
   558  	// Other things will be relative to this.
   559  	ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
   560  	ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
   561  	ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
   562  	ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
   563  
   564  	// Compute the .plt array index from the entry point address.
   565  	// Because this is PIC, everything is relative to label 1b (in
   566  	// r11):
   567  	//   r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
   568  	ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
   569  	ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
   570  	ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
   571  	ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
   572  
   573  	// r11 = address of the first byte of the PLT
   574  	r := ld.Addrel(glink)
   575  
   576  	r.Off = int32(glink.Size)
   577  	r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
   578  	r.Siz = 8
   579  	r.Type = obj.R_ADDRPOWER
   580  
   581  	// addis r11,0,.plt@ha; addi r11,r11,.plt@l
   582  	r.Add = 0x3d600000<<32 | 0x396b0000
   583  
   584  	glink.Size += 8
   585  
   586  	// Load r12 = dynamic resolver address and r11 = DSO
   587  	// identifier from the first two doublewords of the PLT.
   588  	ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
   589  	ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
   590  
   591  	// Jump to the dynamic resolver
   592  	ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
   593  	ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
   594  
   595  	// The symbol resolvers must immediately follow.
   596  	//   res_0:
   597  
   598  	// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
   599  	// before the first symbol resolver stub.
   600  	s := ld.Linklookup(ld.Ctxt, ".dynamic", 0)
   601  
   602  	ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
   603  
   604  	return glink
   605  }
   606  
   607  func asmb() {
   608  	if ld.Debug['v'] != 0 {
   609  		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
   610  	}
   611  	ld.Bso.Flush()
   612  
   613  	if ld.Iself {
   614  		ld.Asmbelfsetup()
   615  	}
   616  
   617  	sect := ld.Segtext.Sect
   618  	ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   619  	ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
   620  	for sect = sect.Next; sect != nil; sect = sect.Next {
   621  		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   622  		ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
   623  	}
   624  
   625  	if ld.Segrodata.Filelen > 0 {
   626  		if ld.Debug['v'] != 0 {
   627  			fmt.Fprintf(&ld.Bso, "%5.2f rodatblk\n", obj.Cputime())
   628  		}
   629  		ld.Bso.Flush()
   630  
   631  		ld.Cseek(int64(ld.Segrodata.Fileoff))
   632  		ld.Datblk(int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   633  	}
   634  
   635  	if ld.Debug['v'] != 0 {
   636  		fmt.Fprintf(&ld.Bso, "%5.2f datblk\n", obj.Cputime())
   637  	}
   638  	ld.Bso.Flush()
   639  
   640  	ld.Cseek(int64(ld.Segdata.Fileoff))
   641  	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   642  
   643  	/* output symbol table */
   644  	ld.Symsize = 0
   645  
   646  	ld.Lcsize = 0
   647  	symo := uint32(0)
   648  	if ld.Debug['s'] == 0 {
   649  		// TODO: rationalize
   650  		if ld.Debug['v'] != 0 {
   651  			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
   652  		}
   653  		ld.Bso.Flush()
   654  		switch ld.HEADTYPE {
   655  		default:
   656  			if ld.Iself {
   657  				symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   658  				symo = uint32(ld.Rnd(int64(symo), int64(ld.INITRND)))
   659  			}
   660  
   661  		case obj.Hplan9:
   662  			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   663  		}
   664  
   665  		ld.Cseek(int64(symo))
   666  		switch ld.HEADTYPE {
   667  		default:
   668  			if ld.Iself {
   669  				if ld.Debug['v'] != 0 {
   670  					fmt.Fprintf(&ld.Bso, "%5.2f elfsym\n", obj.Cputime())
   671  				}
   672  				ld.Asmelfsym()
   673  				ld.Cflush()
   674  				ld.Cwrite(ld.Elfstrdat)
   675  
   676  				if ld.Debug['v'] != 0 {
   677  					fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
   678  				}
   679  				ld.Dwarfemitdebugsections()
   680  
   681  				if ld.Linkmode == ld.LinkExternal {
   682  					ld.Elfemitreloc()
   683  				}
   684  			}
   685  
   686  		case obj.Hplan9:
   687  			ld.Asmplan9sym()
   688  			ld.Cflush()
   689  
   690  			sym := ld.Linklookup(ld.Ctxt, "pclntab", 0)
   691  			if sym != nil {
   692  				ld.Lcsize = int32(len(sym.P))
   693  				for i := 0; int32(i) < ld.Lcsize; i++ {
   694  					ld.Cput(uint8(sym.P[i]))
   695  				}
   696  
   697  				ld.Cflush()
   698  			}
   699  		}
   700  	}
   701  
   702  	ld.Ctxt.Cursym = nil
   703  	if ld.Debug['v'] != 0 {
   704  		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
   705  	}
   706  	ld.Bso.Flush()
   707  	ld.Cseek(0)
   708  	switch ld.HEADTYPE {
   709  	default:
   710  	case obj.Hplan9: /* plan 9 */
   711  		ld.Thearch.Lput(0x647)                      /* magic */
   712  		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
   713  		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
   714  		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
   715  		ld.Thearch.Lput(uint32(ld.Symsize))      /* nsyms */
   716  		ld.Thearch.Lput(uint32(ld.Entryvalue())) /* va of entry */
   717  		ld.Thearch.Lput(0)
   718  		ld.Thearch.Lput(uint32(ld.Lcsize))
   719  
   720  	case obj.Hlinux,
   721  		obj.Hfreebsd,
   722  		obj.Hnetbsd,
   723  		obj.Hopenbsd,
   724  		obj.Hnacl:
   725  		ld.Asmbelf(int64(symo))
   726  	}
   727  
   728  	ld.Cflush()
   729  	if ld.Debug['c'] != 0 {
   730  		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
   731  		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
   732  		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
   733  		fmt.Printf("symsize=%d\n", ld.Symsize)
   734  		fmt.Printf("lcsize=%d\n", ld.Lcsize)
   735  		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
   736  	}
   737  }