...
Run Format

Source file src/cmd/link/internal/ppc64/asm.go

Documentation: cmd/link/internal/ppc64

  // Inferno utils/5l/asm.c
  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
  //
  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
  //	Portions Copyright © 1997-1999 Vita Nuova Limited
  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
  //	Portions Copyright © 2004,2006 Bruce Ellis
  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
  //	Portions Copyright © 2009 The Go Authors. All rights reserved.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
  
  package ppc64
  
  import (
  	"cmd/internal/objabi"
  	"cmd/link/internal/ld"
  	"encoding/binary"
  	"fmt"
  	"log"
  )
  
  func genplt(ctxt *ld.Link) {
  	// The ppc64 ABI PLT has similar concepts to other
  	// architectures, but is laid out quite differently. When we
  	// see an R_PPC64_REL24 relocation to a dynamic symbol
  	// (indicating that the call needs to go through the PLT), we
  	// generate up to three stubs and reserve a PLT slot.
  	//
  	// 1) The call site will be bl x; nop (where the relocation
  	//    applies to the bl).  We rewrite this to bl x_stub; ld
  	//    r2,24(r1).  The ld is necessary because x_stub will save
  	//    r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
  	//
  	// 2) We reserve space for a pointer in the .plt section (once
  	//    per referenced dynamic function).  .plt is a data
  	//    section filled solely by the dynamic linker (more like
  	//    .plt.got on other architectures).  Initially, the
  	//    dynamic linker will fill each slot with a pointer to the
  	//    corresponding x@plt entry point.
  	//
  	// 3) We generate the "call stub" x_stub (once per dynamic
  	//    function/object file pair).  This saves the TOC in the
  	//    TOC save slot, reads the function pointer from x's .plt
  	//    slot and calls it like any other global entry point
  	//    (including setting r12 to the function address).
  	//
  	// 4) We generate the "symbol resolver stub" x@plt (once per
  	//    dynamic function).  This is solely a branch to the glink
  	//    resolver stub.
  	//
  	// 5) We generate the glink resolver stub (only once).  This
  	//    computes which symbol resolver stub we came through and
  	//    invokes the dynamic resolver via a pointer provided by
  	//    the dynamic linker. This will patch up the .plt slot to
  	//    point directly at the function so future calls go
  	//    straight from the call stub to the real function, and
  	//    then call the function.
  
  	// NOTE: It's possible we could make ppc64 closer to other
  	// architectures: ppc64's .plt is like .plt.got on other
  	// platforms and ppc64's .glink is like .plt on other
  	// platforms.
  
  	// Find all R_PPC64_REL24 relocations that reference dynamic
  	// imports. Reserve PLT entries for these symbols and
  	// generate call stubs. The call stubs need to live in .text,
  	// which is why we need to do this pass this early.
  	//
  	// This assumes "case 1" from the ABI, where the caller needs
  	// us to save and restore the TOC pointer.
  	var stubs []*ld.Symbol
  	for _, s := range ctxt.Textp {
  		for i := range s.R {
  			r := &s.R[i]
  			if r.Type != 256+ld.R_PPC64_REL24 || r.Sym.Type != ld.SDYNIMPORT {
  				continue
  			}
  
  			// Reserve PLT entry and generate symbol
  			// resolver
  			addpltsym(ctxt, r.Sym)
  
  			// Generate call stub
  			n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
  
  			stub := ctxt.Syms.Lookup(n, 0)
  			if s.Attr.Reachable() {
  				stub.Attr |= ld.AttrReachable
  			}
  			if stub.Size == 0 {
  				// Need outer to resolve .TOC.
  				stub.Outer = s
  				stubs = append(stubs, stub)
  				gencallstub(ctxt, 1, stub, r.Sym)
  			}
  
  			// Update the relocation to use the call stub
  			r.Sym = stub
  
  			// Restore TOC after bl. The compiler put a
  			// nop here for us to overwrite.
  			const o1 = 0xe8410018 // ld r2,24(r1)
  			ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
  		}
  	}
  	// Put call stubs at the beginning (instead of the end).
  	// So when resolving the relocations to calls to the stubs,
  	// the addresses are known and trampolines can be inserted
  	// when necessary.
  	ctxt.Textp = append(stubs, ctxt.Textp...)
  }
  
  func genaddmoduledata(ctxt *ld.Link) {
  	addmoduledata := ctxt.Syms.ROLookup("runtime.addmoduledata", 0)
  	if addmoduledata.Type == ld.STEXT {
  		return
  	}
  	addmoduledata.Attr |= ld.AttrReachable
  	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
  	initfunc.Type = ld.STEXT
  	initfunc.Attr |= ld.AttrLocal
  	initfunc.Attr |= ld.AttrReachable
  	o := func(op uint32) {
  		ld.Adduint32(ctxt, initfunc, op)
  	}
  	// addis r2, r12, .TOC.-func@ha
  	rel := ld.Addrel(initfunc)
  	rel.Off = int32(initfunc.Size)
  	rel.Siz = 8
  	rel.Sym = ctxt.Syms.Lookup(".TOC.", 0)
  	rel.Type = objabi.R_ADDRPOWER_PCREL
  	o(0x3c4c0000)
  	// addi r2, r2, .TOC.-func@l
  	o(0x38420000)
  	// mflr r31
  	o(0x7c0802a6)
  	// stdu r31, -32(r1)
  	o(0xf801ffe1)
  	// addis r3, r2, local.moduledata@got@ha
  	rel = ld.Addrel(initfunc)
  	rel.Off = int32(initfunc.Size)
  	rel.Siz = 8
  	rel.Sym = ctxt.Syms.Lookup("local.moduledata", 0)
  	rel.Type = objabi.R_ADDRPOWER_GOT
  	o(0x3c620000)
  	// ld r3, local.moduledata@got@l(r3)
  	o(0xe8630000)
  	// bl runtime.addmoduledata
  	rel = ld.Addrel(initfunc)
  	rel.Off = int32(initfunc.Size)
  	rel.Siz = 4
  	rel.Sym = addmoduledata
  	rel.Type = objabi.R_CALLPOWER
  	o(0x48000001)
  	// nop
  	o(0x60000000)
  	// ld r31, 0(r1)
  	o(0xe8010000)
  	// mtlr r31
  	o(0x7c0803a6)
  	// addi r1,r1,32
  	o(0x38210020)
  	// blr
  	o(0x4e800020)
  
  	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
  	ctxt.Textp = append(ctxt.Textp, initfunc)
  	initarray_entry.Attr |= ld.AttrReachable
  	initarray_entry.Attr |= ld.AttrLocal
  	initarray_entry.Type = ld.SINITARR
  	ld.Addaddr(ctxt, initarray_entry, initfunc)
  }
  
  func gentext(ctxt *ld.Link) {
  	if ctxt.DynlinkingGo() {
  		genaddmoduledata(ctxt)
  	}
  
  	if ld.Linkmode == ld.LinkInternal {
  		genplt(ctxt)
  	}
  }
  
  // Construct a call stub in stub that calls symbol targ via its PLT
  // entry.
  func gencallstub(ctxt *ld.Link, abicase int, stub *ld.Symbol, targ *ld.Symbol) {
  	if abicase != 1 {
  		// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
  		// relocations, we'll need to implement cases 2 and 3.
  		log.Fatalf("gencallstub only implements case 1 calls")
  	}
  
  	plt := ctxt.Syms.Lookup(".plt", 0)
  
  	stub.Type = ld.STEXT
  
  	// Save TOC pointer in TOC save slot
  	ld.Adduint32(ctxt, stub, 0xf8410018) // std r2,24(r1)
  
  	// Load the function pointer from the PLT.
  	r := ld.Addrel(stub)
  
  	r.Off = int32(stub.Size)
  	r.Sym = plt
  	r.Add = int64(targ.Plt)
  	r.Siz = 2
  	if ctxt.Arch.ByteOrder == binary.BigEndian {
  		r.Off += int32(r.Siz)
  	}
  	r.Type = objabi.R_POWER_TOC
  	r.Variant = ld.RV_POWER_HA
  	ld.Adduint32(ctxt, stub, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
  	r = ld.Addrel(stub)
  	r.Off = int32(stub.Size)
  	r.Sym = plt
  	r.Add = int64(targ.Plt)
  	r.Siz = 2
  	if ctxt.Arch.ByteOrder == binary.BigEndian {
  		r.Off += int32(r.Siz)
  	}
  	r.Type = objabi.R_POWER_TOC
  	r.Variant = ld.RV_POWER_LO
  	ld.Adduint32(ctxt, stub, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
  
  	// Jump to the loaded pointer
  	ld.Adduint32(ctxt, stub, 0x7d8903a6) // mtctr r12
  	ld.Adduint32(ctxt, stub, 0x4e800420) // bctr
  }
  
  func adddynrel(ctxt *ld.Link, s *ld.Symbol, r *ld.Reloc) bool {
  	targ := r.Sym
  
  	switch r.Type {
  	default:
  		if r.Type >= 256 {
  			ld.Errorf(s, "unexpected relocation type %d", r.Type)
  			return false
  		}
  
  		// Handle relocations found in ELF object files.
  	case 256 + ld.R_PPC64_REL24:
  		r.Type = objabi.R_CALLPOWER
  
  		// This is a local call, so the caller isn't setting
  		// up r12 and r2 is the same for the caller and
  		// callee. Hence, we need to go to the local entry
  		// point.  (If we don't do this, the callee will try
  		// to use r12 to compute r2.)
  		r.Add += int64(r.Sym.Localentry) * 4
  
  		if targ.Type == ld.SDYNIMPORT {
  			// Should have been handled in elfsetupplt
  			ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
  		}
  
  		return true
  
  	case 256 + ld.R_PPC_REL32:
  		r.Type = objabi.R_PCREL
  		r.Add += 4
  
  		if targ.Type == ld.SDYNIMPORT {
  			ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
  		}
  
  		return true
  
  	case 256 + ld.R_PPC64_ADDR64:
  		r.Type = objabi.R_ADDR
  		if targ.Type == ld.SDYNIMPORT {
  			// These happen in .toc sections
  			ld.Adddynsym(ctxt, targ)
  
  			rela := ctxt.Syms.Lookup(".rela", 0)
  			ld.Addaddrplus(ctxt, rela, s, int64(r.Off))
  			ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_PPC64_ADDR64))
  			ld.Adduint64(ctxt, rela, uint64(r.Add))
  			r.Type = 256 // ignore during relocsym
  		}
  
  		return true
  
  	case 256 + ld.R_PPC64_TOC16:
  		r.Type = objabi.R_POWER_TOC
  		r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
  		return true
  
  	case 256 + ld.R_PPC64_TOC16_LO:
  		r.Type = objabi.R_POWER_TOC
  		r.Variant = ld.RV_POWER_LO
  		return true
  
  	case 256 + ld.R_PPC64_TOC16_HA:
  		r.Type = objabi.R_POWER_TOC
  		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
  		return true
  
  	case 256 + ld.R_PPC64_TOC16_HI:
  		r.Type = objabi.R_POWER_TOC
  		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
  		return true
  
  	case 256 + ld.R_PPC64_TOC16_DS:
  		r.Type = objabi.R_POWER_TOC
  		r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
  		return true
  
  	case 256 + ld.R_PPC64_TOC16_LO_DS:
  		r.Type = objabi.R_POWER_TOC
  		r.Variant = ld.RV_POWER_DS
  		return true
  
  	case 256 + ld.R_PPC64_REL16_LO:
  		r.Type = objabi.R_PCREL
  		r.Variant = ld.RV_POWER_LO
  		r.Add += 2 // Compensate for relocation size of 2
  		return true
  
  	case 256 + ld.R_PPC64_REL16_HI:
  		r.Type = objabi.R_PCREL
  		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
  		r.Add += 2
  		return true
  
  	case 256 + ld.R_PPC64_REL16_HA:
  		r.Type = objabi.R_PCREL
  		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
  		r.Add += 2
  		return true
  	}
  
  	// Handle references to ELF symbols from our own object files.
  	if targ.Type != ld.SDYNIMPORT {
  		return true
  	}
  
  	// TODO(austin): Translate our relocations to ELF
  
  	return false
  }
  
  func elfreloc1(ctxt *ld.Link, r *ld.Reloc, sectoff int64) int {
  	ld.Thearch.Vput(uint64(sectoff))
  
  	elfsym := r.Xsym.ElfsymForReloc()
  	switch r.Type {
  	default:
  		return -1
  
  	case objabi.R_ADDR:
  		switch r.Siz {
  		case 4:
  			ld.Thearch.Vput(ld.R_PPC64_ADDR32 | uint64(elfsym)<<32)
  		case 8:
  			ld.Thearch.Vput(ld.R_PPC64_ADDR64 | uint64(elfsym)<<32)
  		default:
  			return -1
  		}
  
  	case objabi.R_POWER_TLS:
  		ld.Thearch.Vput(ld.R_PPC64_TLS | uint64(elfsym)<<32)
  
  	case objabi.R_POWER_TLS_LE:
  		ld.Thearch.Vput(ld.R_PPC64_TPREL16 | uint64(elfsym)<<32)
  
  	case objabi.R_POWER_TLS_IE:
  		ld.Thearch.Vput(ld.R_PPC64_GOT_TPREL16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_GOT_TPREL16_LO_DS | uint64(elfsym)<<32)
  
  	case objabi.R_ADDRPOWER:
  		ld.Thearch.Vput(ld.R_PPC64_ADDR16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_ADDR16_LO | uint64(elfsym)<<32)
  
  	case objabi.R_ADDRPOWER_DS:
  		ld.Thearch.Vput(ld.R_PPC64_ADDR16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_ADDR16_LO_DS | uint64(elfsym)<<32)
  
  	case objabi.R_ADDRPOWER_GOT:
  		ld.Thearch.Vput(ld.R_PPC64_GOT16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_GOT16_LO_DS | uint64(elfsym)<<32)
  
  	case objabi.R_ADDRPOWER_PCREL:
  		ld.Thearch.Vput(ld.R_PPC64_REL16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_REL16_LO | uint64(elfsym)<<32)
  		r.Xadd += 4
  
  	case objabi.R_ADDRPOWER_TOCREL:
  		ld.Thearch.Vput(ld.R_PPC64_TOC16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_TOC16_LO | uint64(elfsym)<<32)
  
  	case objabi.R_ADDRPOWER_TOCREL_DS:
  		ld.Thearch.Vput(ld.R_PPC64_TOC16_HA | uint64(elfsym)<<32)
  		ld.Thearch.Vput(uint64(r.Xadd))
  		ld.Thearch.Vput(uint64(sectoff + 4))
  		ld.Thearch.Vput(ld.R_PPC64_TOC16_LO_DS | uint64(elfsym)<<32)
  
  	case objabi.R_CALLPOWER:
  		if r.Siz != 4 {
  			return -1
  		}
  		ld.Thearch.Vput(ld.R_PPC64_REL24 | uint64(elfsym)<<32)
  
  	}
  	ld.Thearch.Vput(uint64(r.Xadd))
  
  	return 0
  }
  
  func elfsetupplt(ctxt *ld.Link) {
  	plt := ctxt.Syms.Lookup(".plt", 0)
  	if plt.Size == 0 {
  		// The dynamic linker stores the address of the
  		// dynamic resolver and the DSO identifier in the two
  		// doublewords at the beginning of the .plt section
  		// before the PLT array. Reserve space for these.
  		plt.Size = 16
  	}
  }
  
  func machoreloc1(s *ld.Symbol, r *ld.Reloc, sectoff int64) int {
  	return -1
  }
  
  // Return the value of .TOC. for symbol s
  func symtoc(ctxt *ld.Link, s *ld.Symbol) int64 {
  	var toc *ld.Symbol
  
  	if s.Outer != nil {
  		toc = ctxt.Syms.ROLookup(".TOC.", int(s.Outer.Version))
  	} else {
  		toc = ctxt.Syms.ROLookup(".TOC.", int(s.Version))
  	}
  
  	if toc == nil {
  		ld.Errorf(s, "TOC-relative relocation in object without .TOC.")
  		return 0
  	}
  
  	return toc.Value
  }
  
  func archrelocaddr(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
  	var o1, o2 uint32
  	if ctxt.Arch.ByteOrder == binary.BigEndian {
  		o1 = uint32(*val >> 32)
  		o2 = uint32(*val)
  	} else {
  		o1 = uint32(*val)
  		o2 = uint32(*val >> 32)
  	}
  
  	// We are spreading a 31-bit address across two instructions, putting the
  	// high (adjusted) part in the low 16 bits of the first instruction and the
  	// low part in the low 16 bits of the second instruction, or, in the DS case,
  	// bits 15-2 (inclusive) of the address into bits 15-2 of the second
  	// instruction (it is an error in this case if the low 2 bits of the address
  	// are non-zero).
  
  	t := ld.Symaddr(r.Sym) + r.Add
  	if t < 0 || t >= 1<<31 {
  		ld.Errorf(s, "relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
  	}
  	if t&0x8000 != 0 {
  		t += 0x10000
  	}
  
  	switch r.Type {
  	case objabi.R_ADDRPOWER:
  		o1 |= (uint32(t) >> 16) & 0xffff
  		o2 |= uint32(t) & 0xffff
  
  	case objabi.R_ADDRPOWER_DS:
  		o1 |= (uint32(t) >> 16) & 0xffff
  		if t&3 != 0 {
  			ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
  		}
  		o2 |= uint32(t) & 0xfffc
  
  	default:
  		return -1
  	}
  
  	if ctxt.Arch.ByteOrder == binary.BigEndian {
  		*val = int64(o1)<<32 | int64(o2)
  	} else {
  		*val = int64(o2)<<32 | int64(o1)
  	}
  	return 0
  }
  
  // resolve direct jump relocation r in s, and add trampoline if necessary
  func trampoline(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol) {
  
  	// Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
  	// For internal linking, trampolines are always created for long calls.
  	// For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
  	// r2.  For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
  	if ld.Linkmode == ld.LinkExternal && (ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE) {
  		// No trampolines needed since r2 contains the TOC
  		return
  	}
  
  	t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
  	switch r.Type {
  	case objabi.R_CALLPOWER:
  
  		// If branch offset is too far then create a trampoline.
  
  		if (ld.Linkmode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
  			var tramp *ld.Symbol
  			for i := 0; ; i++ {
  
  				// Using r.Add as part of the name is significant in functions like duffzero where the call
  				// target is at some offset within the function.  Calls to duff+8 and duff+256 must appear as
  				// distinct trampolines.
  
  				name := r.Sym.Name
  				if r.Add == 0 {
  					name = name + fmt.Sprintf("-tramp%d", i)
  				} else {
  					name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i)
  				}
  
  				// Look up the trampoline in case it already exists
  
  				tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
  				if tramp.Value == 0 {
  					break
  				}
  
  				t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
  
  				// 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 (ld.Linkmode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ld.Linkmode == ld.LinkExternal && s.Sect == tramp.Sect) {
  					break
  				}
  			}
  			if tramp.Type == 0 {
  				if ctxt.DynlinkingGo() || ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.Buildmode == ld.BuildmodePIE {
  					// Should have returned for above cases
  					ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
  				} else {
  					ctxt.AddTramp(tramp)
  					gentramp(tramp, r.Sym, int64(r.Add))
  				}
  			}
  			r.Sym = tramp
  			r.Add = 0 // This was folded into the trampoline target address
  			r.Done = 0
  		}
  	default:
  		ld.Errorf(s, "trampoline called with non-jump reloc: %v", r.Type)
  	}
  }
  
  func gentramp(tramp, target *ld.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).
  	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 ld.Linkmode == ld.LinkExternal {
  		tr := ld.Addrel(tramp)
  		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
  	}
  	o3 := uint32(0x7fe903a6) // mtctr r31
  	o4 := uint32(0x4e800420) // bctr
  	ld.SysArch.ByteOrder.PutUint32(tramp.P, o1)
  	ld.SysArch.ByteOrder.PutUint32(tramp.P[4:], o2)
  	ld.SysArch.ByteOrder.PutUint32(tramp.P[8:], o3)
  	ld.SysArch.ByteOrder.PutUint32(tramp.P[12:], o4)
  }
  
  func archreloc(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, val *int64) int {
  	if ld.Linkmode == ld.LinkExternal {
  		switch r.Type {
  		default:
  			return -1
  
  		case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
  			r.Done = 0
  			// check Outer is nil, Type is TLSBSS?
  			r.Xadd = r.Add
  			r.Xsym = r.Sym
  			return 0
  
  		case objabi.R_ADDRPOWER,
  			objabi.R_ADDRPOWER_DS,
  			objabi.R_ADDRPOWER_TOCREL,
  			objabi.R_ADDRPOWER_TOCREL_DS,
  			objabi.R_ADDRPOWER_GOT,
  			objabi.R_ADDRPOWER_PCREL:
  			r.Done = 0
  
  			// set up addend for eventual relocation via outer symbol.
  			rs := r.Sym
  			r.Xadd = r.Add
  			for rs.Outer != nil {
  				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
  				rs = rs.Outer
  			}
  
  			if rs.Type != ld.SHOSTOBJ && rs.Type != ld.SDYNIMPORT && rs.Sect == nil {
  				ld.Errorf(s, "missing section for %s", rs.Name)
  			}
  			r.Xsym = rs
  
  			return 0
  
  		case objabi.R_CALLPOWER:
  			r.Done = 0
  			r.Xsym = r.Sym
  			r.Xadd = r.Add
  			return 0
  		}
  	}
  
  	switch r.Type {
  	case objabi.R_CONST:
  		*val = r.Add
  		return 0
  
  	case objabi.R_GOTOFF:
  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
  		return 0
  
  	case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
  		return archrelocaddr(ctxt, r, s, val)
  
  	case objabi.R_CALLPOWER:
  		// Bits 6 through 29 = (S + A - P) >> 2
  
  		t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
  
  		if t&3 != 0 {
  			ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
  		}
  		// If branch offset is too far then create a trampoline.
  
  		if int64(int32(t<<6)>>6) != t {
  			ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
  		}
  		*val |= int64(uint32(t) &^ 0xfc000003)
  		return 0
  
  	case objabi.R_POWER_TOC: // S + A - .TOC.
  		*val = ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s)
  
  		return 0
  
  	case objabi.R_POWER_TLS_LE:
  		// The thread pointer points 0x7000 bytes after the start of the the
  		// thread local storage area as documented in section "3.7.2 TLS
  		// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
  		// Specification".
  		v := r.Sym.Value - 0x7000
  		if int64(int16(v)) != v {
  			ld.Errorf(s, "TLS offset out of range %d", v)
  		}
  		*val = (*val &^ 0xffff) | (v & 0xffff)
  		return 0
  	}
  
  	return -1
  }
  
  func archrelocvariant(ctxt *ld.Link, r *ld.Reloc, s *ld.Symbol, t int64) int64 {
  	switch r.Variant & ld.RV_TYPE_MASK {
  	default:
  		ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
  		fallthrough
  
  	case ld.RV_NONE:
  		return t
  
  	case ld.RV_POWER_LO:
  		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
  			// Whether to check for signed or unsigned
  			// overflow depends on the instruction
  			var o1 uint32
  			if ctxt.Arch.ByteOrder == binary.BigEndian {
  				o1 = ld.Be32(s.P[r.Off-2:])
  			} else {
  				o1 = ld.Le32(s.P[r.Off:])
  			}
  			switch o1 >> 26 {
  			case 24, // ori
  				26, // xori
  				28: // andi
  				if t>>16 != 0 {
  					goto overflow
  				}
  
  			default:
  				if int64(int16(t)) != t {
  					goto overflow
  				}
  			}
  		}
  
  		return int64(int16(t))
  
  	case ld.RV_POWER_HA:
  		t += 0x8000
  		fallthrough
  
  		// Fallthrough
  	case ld.RV_POWER_HI:
  		t >>= 16
  
  		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
  			// Whether to check for signed or unsigned
  			// overflow depends on the instruction
  			var o1 uint32
  			if ctxt.Arch.ByteOrder == binary.BigEndian {
  				o1 = ld.Be32(s.P[r.Off-2:])
  			} else {
  				o1 = ld.Le32(s.P[r.Off:])
  			}
  			switch o1 >> 26 {
  			case 25, // oris
  				27, // xoris
  				29: // andis
  				if t>>16 != 0 {
  					goto overflow
  				}
  
  			default:
  				if int64(int16(t)) != t {
  					goto overflow
  				}
  			}
  		}
  
  		return int64(int16(t))
  
  	case ld.RV_POWER_DS:
  		var o1 uint32
  		if ctxt.Arch.ByteOrder == binary.BigEndian {
  			o1 = uint32(ld.Be16(s.P[r.Off:]))
  		} else {
  			o1 = uint32(ld.Le16(s.P[r.Off:]))
  		}
  		if t&3 != 0 {
  			ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
  		}
  		if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
  			goto overflow
  		}
  		return int64(o1)&0x3 | int64(int16(t))
  	}
  
  overflow:
  	ld.Errorf(s, "relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
  	return t
  }
  
  func addpltsym(ctxt *ld.Link, s *ld.Symbol) {
  	if s.Plt >= 0 {
  		return
  	}
  
  	ld.Adddynsym(ctxt, s)
  
  	if ld.Iself {
  		plt := ctxt.Syms.Lookup(".plt", 0)
  		rela := ctxt.Syms.Lookup(".rela.plt", 0)
  		if plt.Size == 0 {
  			elfsetupplt(ctxt)
  		}
  
  		// Create the glink resolver if necessary
  		glink := ensureglinkresolver(ctxt)
  
  		// Write symbol resolver stub (just a branch to the
  		// glink resolver stub)
  		r := ld.Addrel(glink)
  
  		r.Sym = glink
  		r.Off = int32(glink.Size)
  		r.Siz = 4
  		r.Type = objabi.R_CALLPOWER
  		ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
  
  		// In the ppc64 ABI, the dynamic linker is responsible
  		// for writing the entire PLT.  We just need to
  		// reserve 8 bytes for each PLT entry and generate a
  		// JMP_SLOT dynamic relocation for it.
  		//
  		// TODO(austin): ABI v1 is different
  		s.Plt = int32(plt.Size)
  
  		plt.Size += 8
  
  		ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
  		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
  		ld.Adduint64(ctxt, rela, 0)
  	} else {
  		ld.Errorf(s, "addpltsym: unsupported binary format")
  	}
  }
  
  // Generate the glink resolver stub if necessary and return the .glink section
  func ensureglinkresolver(ctxt *ld.Link) *ld.Symbol {
  	glink := ctxt.Syms.Lookup(".glink", 0)
  	if glink.Size != 0 {
  		return glink
  	}
  
  	// This is essentially the resolver from the ppc64 ELF ABI.
  	// At entry, r12 holds the address of the symbol resolver stub
  	// for the target routine and the argument registers hold the
  	// arguments for the target routine.
  	//
  	// This stub is PIC, so first get the PC of label 1 into r11.
  	// Other things will be relative to this.
  	ld.Adduint32(ctxt, glink, 0x7c0802a6) // mflr r0
  	ld.Adduint32(ctxt, glink, 0x429f0005) // bcl 20,31,1f
  	ld.Adduint32(ctxt, glink, 0x7d6802a6) // 1: mflr r11
  	ld.Adduint32(ctxt, glink, 0x7c0803a6) // mtlf r0
  
  	// Compute the .plt array index from the entry point address.
  	// Because this is PIC, everything is relative to label 1b (in
  	// r11):
  	//   r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
  	ld.Adduint32(ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
  	ld.Adduint32(ctxt, glink, 0x7c006214) // add r0,r0,r12
  	ld.Adduint32(ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
  	ld.Adduint32(ctxt, glink, 0x7800f082) // srdi r0,r0,2
  
  	// r11 = address of the first byte of the PLT
  	r := ld.Addrel(glink)
  
  	r.Off = int32(glink.Size)
  	r.Sym = ctxt.Syms.Lookup(".plt", 0)
  	r.Siz = 8
  	r.Type = objabi.R_ADDRPOWER
  
  	ld.Adduint32(ctxt, glink, 0x3d600000) // addis r11,0,.plt@ha
  	ld.Adduint32(ctxt, glink, 0x396b0000) // addi r11,r11,.plt@l
  
  	// Load r12 = dynamic resolver address and r11 = DSO
  	// identifier from the first two doublewords of the PLT.
  	ld.Adduint32(ctxt, glink, 0xe98b0000) // ld r12,0(r11)
  	ld.Adduint32(ctxt, glink, 0xe96b0008) // ld r11,8(r11)
  
  	// Jump to the dynamic resolver
  	ld.Adduint32(ctxt, glink, 0x7d8903a6) // mtctr r12
  	ld.Adduint32(ctxt, glink, 0x4e800420) // bctr
  
  	// The symbol resolvers must immediately follow.
  	//   res_0:
  
  	// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
  	// before the first symbol resolver stub.
  	s := ctxt.Syms.Lookup(".dynamic", 0)
  
  	ld.Elfwritedynentsymplus(ctxt, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
  
  	return glink
  }
  
  func asmb(ctxt *ld.Link) {
  	if ctxt.Debugvlog != 0 {
  		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
  	}
  
  	if ld.Iself {
  		ld.Asmbelfsetup()
  	}
  
  	for _, sect := range ld.Segtext.Sections {
  		ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
  		// Handle additional text sections with Codeblk
  		if sect.Name == ".text" {
  			ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
  		} else {
  			ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
  		}
  	}
  
  	if ld.Segrodata.Filelen > 0 {
  		if ctxt.Debugvlog != 0 {
  			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
  		}
  		ld.Cseek(int64(ld.Segrodata.Fileoff))
  		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
  	}
  	if ld.Segrelrodata.Filelen > 0 {
  		if ctxt.Debugvlog != 0 {
  			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
  		}
  		ld.Cseek(int64(ld.Segrelrodata.Fileoff))
  		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
  	}
  
  	if ctxt.Debugvlog != 0 {
  		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
  	}
  
  	ld.Cseek(int64(ld.Segdata.Fileoff))
  	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
  
  	ld.Cseek(int64(ld.Segdwarf.Fileoff))
  	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
  
  	/* output symbol table */
  	ld.Symsize = 0
  
  	ld.Lcsize = 0
  	symo := uint32(0)
  	if !*ld.FlagS {
  		// TODO: rationalize
  		if ctxt.Debugvlog != 0 {
  			ctxt.Logf("%5.2f sym\n", ld.Cputime())
  		}
  		switch ld.Headtype {
  		default:
  			if ld.Iself {
  				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
  				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
  			}
  
  		case objabi.Hplan9:
  			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
  		}
  
  		ld.Cseek(int64(symo))
  		switch ld.Headtype {
  		default:
  			if ld.Iself {
  				if ctxt.Debugvlog != 0 {
  					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
  				}
  				ld.Asmelfsym(ctxt)
  				ld.Cflush()
  				ld.Cwrite(ld.Elfstrdat)
  
  				if ld.Linkmode == ld.LinkExternal {
  					ld.Elfemitreloc(ctxt)
  				}
  			}
  
  		case objabi.Hplan9:
  			ld.Asmplan9sym(ctxt)
  			ld.Cflush()
  
  			sym := ctxt.Syms.Lookup("pclntab", 0)
  			if sym != nil {
  				ld.Lcsize = int32(len(sym.P))
  				for i := 0; int32(i) < ld.Lcsize; i++ {
  					ld.Cput(sym.P[i])
  				}
  
  				ld.Cflush()
  			}
  		}
  	}
  
  	if ctxt.Debugvlog != 0 {
  		ctxt.Logf("%5.2f header\n", ld.Cputime())
  	}
  	ld.Cseek(0)
  	switch ld.Headtype {
  	default:
  	case objabi.Hplan9: /* plan 9 */
  		ld.Thearch.Lput(0x647)                      /* magic */
  		ld.Thearch.Lput(uint32(ld.Segtext.Filelen)) /* sizes */
  		ld.Thearch.Lput(uint32(ld.Segdata.Filelen))
  		ld.Thearch.Lput(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
  		ld.Thearch.Lput(uint32(ld.Symsize))          /* nsyms */
  		ld.Thearch.Lput(uint32(ld.Entryvalue(ctxt))) /* va of entry */
  		ld.Thearch.Lput(0)
  		ld.Thearch.Lput(uint32(ld.Lcsize))
  
  	case objabi.Hlinux,
  		objabi.Hfreebsd,
  		objabi.Hnetbsd,
  		objabi.Hopenbsd,
  		objabi.Hnacl:
  		ld.Asmbelf(ctxt, int64(symo))
  	}
  
  	ld.Cflush()
  	if *ld.FlagC {
  		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
  		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
  		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
  		fmt.Printf("symsize=%d\n", ld.Symsize)
  		fmt.Printf("lcsize=%d\n", ld.Lcsize)
  		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
  	}
  }
  

View as plain text