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