...
Run Format

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

Documentation: cmd/link/internal/ppc64

     1  // Inferno utils/5l/asm.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/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/objabi"
    35  	"cmd/internal/sys"
    36  	"cmd/link/internal/ld"
    37  	"cmd/link/internal/sym"
    38  	"debug/elf"
    39  	"encoding/binary"
    40  	"fmt"
    41  	"log"
    42  )
    43  
    44  func genplt(ctxt *ld.Link) {
    45  	// The ppc64 ABI PLT has similar concepts to other
    46  	// architectures, but is laid out quite differently. When we
    47  	// see an R_PPC64_REL24 relocation to a dynamic symbol
    48  	// (indicating that the call needs to go through the PLT), we
    49  	// generate up to three stubs and reserve a PLT slot.
    50  	//
    51  	// 1) The call site will be bl x; nop (where the relocation
    52  	//    applies to the bl).  We rewrite this to bl x_stub; ld
    53  	//    r2,24(r1).  The ld is necessary because x_stub will save
    54  	//    r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
    55  	//
    56  	// 2) We reserve space for a pointer in the .plt section (once
    57  	//    per referenced dynamic function).  .plt is a data
    58  	//    section filled solely by the dynamic linker (more like
    59  	//    .plt.got on other architectures).  Initially, the
    60  	//    dynamic linker will fill each slot with a pointer to the
    61  	//    corresponding x@plt entry point.
    62  	//
    63  	// 3) We generate the "call stub" x_stub (once per dynamic
    64  	//    function/object file pair).  This saves the TOC in the
    65  	//    TOC save slot, reads the function pointer from x's .plt
    66  	//    slot and calls it like any other global entry point
    67  	//    (including setting r12 to the function address).
    68  	//
    69  	// 4) We generate the "symbol resolver stub" x@plt (once per
    70  	//    dynamic function).  This is solely a branch to the glink
    71  	//    resolver stub.
    72  	//
    73  	// 5) We generate the glink resolver stub (only once).  This
    74  	//    computes which symbol resolver stub we came through and
    75  	//    invokes the dynamic resolver via a pointer provided by
    76  	//    the dynamic linker. This will patch up the .plt slot to
    77  	//    point directly at the function so future calls go
    78  	//    straight from the call stub to the real function, and
    79  	//    then call the function.
    80  
    81  	// NOTE: It's possible we could make ppc64 closer to other
    82  	// architectures: ppc64's .plt is like .plt.got on other
    83  	// platforms and ppc64's .glink is like .plt on other
    84  	// platforms.
    85  
    86  	// Find all R_PPC64_REL24 relocations that reference dynamic
    87  	// imports. Reserve PLT entries for these symbols and
    88  	// generate call stubs. The call stubs need to live in .text,
    89  	// which is why we need to do this pass this early.
    90  	//
    91  	// This assumes "case 1" from the ABI, where the caller needs
    92  	// us to save and restore the TOC pointer.
    93  	var stubs []*sym.Symbol
    94  	for _, s := range ctxt.Textp {
    95  		for i := range s.R {
    96  			r := &s.R[i]
    97  			if r.Type != 256+objabi.RelocType(elf.R_PPC64_REL24) || r.Sym.Type != sym.SDYNIMPORT {
    98  				continue
    99  			}
   100  
   101  			// Reserve PLT entry and generate symbol
   102  			// resolver
   103  			addpltsym(ctxt, r.Sym)
   104  
   105  			// Generate call stub
   106  			n := fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
   107  
   108  			stub := ctxt.Syms.Lookup(n, 0)
   109  			if s.Attr.Reachable() {
   110  				stub.Attr |= sym.AttrReachable
   111  			}
   112  			if stub.Size == 0 {
   113  				// Need outer to resolve .TOC.
   114  				stub.Outer = s
   115  				stubs = append(stubs, stub)
   116  				gencallstub(ctxt, 1, stub, r.Sym)
   117  			}
   118  
   119  			// Update the relocation to use the call stub
   120  			r.Sym = stub
   121  
   122  			// Restore TOC after bl. The compiler put a
   123  			// nop here for us to overwrite.
   124  			const o1 = 0xe8410018 // ld r2,24(r1)
   125  			ctxt.Arch.ByteOrder.PutUint32(s.P[r.Off+4:], o1)
   126  		}
   127  	}
   128  	// Put call stubs at the beginning (instead of the end).
   129  	// So when resolving the relocations to calls to the stubs,
   130  	// the addresses are known and trampolines can be inserted
   131  	// when necessary.
   132  	ctxt.Textp = append(stubs, ctxt.Textp...)
   133  }
   134  
   135  func genaddmoduledata(ctxt *ld.Link) {
   136  	addmoduledata := ctxt.Syms.ROLookup("runtime.addmoduledata", 0)
   137  	if addmoduledata.Type == sym.STEXT && ctxt.BuildMode != ld.BuildModePlugin {
   138  		return
   139  	}
   140  	addmoduledata.Attr |= sym.AttrReachable
   141  	initfunc := ctxt.Syms.Lookup("go.link.addmoduledata", 0)
   142  	initfunc.Type = sym.STEXT
   143  	initfunc.Attr |= sym.AttrLocal
   144  	initfunc.Attr |= sym.AttrReachable
   145  	o := func(op uint32) {
   146  		initfunc.AddUint32(ctxt.Arch, op)
   147  	}
   148  	// addis r2, r12, .TOC.-func@ha
   149  	rel := initfunc.AddRel()
   150  	rel.Off = int32(initfunc.Size)
   151  	rel.Siz = 8
   152  	rel.Sym = ctxt.Syms.Lookup(".TOC.", 0)
   153  	rel.Sym.Attr |= sym.AttrReachable
   154  	rel.Type = objabi.R_ADDRPOWER_PCREL
   155  	o(0x3c4c0000)
   156  	// addi r2, r2, .TOC.-func@l
   157  	o(0x38420000)
   158  	// mflr r31
   159  	o(0x7c0802a6)
   160  	// stdu r31, -32(r1)
   161  	o(0xf801ffe1)
   162  	// addis r3, r2, local.moduledata@got@ha
   163  	rel = initfunc.AddRel()
   164  	rel.Off = int32(initfunc.Size)
   165  	rel.Siz = 8
   166  	if s := ctxt.Syms.ROLookup("local.moduledata", 0); s != nil {
   167  		rel.Sym = s
   168  	} else if s := ctxt.Syms.ROLookup("local.pluginmoduledata", 0); s != nil {
   169  		rel.Sym = s
   170  	} else {
   171  		rel.Sym = ctxt.Syms.Lookup("runtime.firstmoduledata", 0)
   172  	}
   173  	rel.Sym.Attr |= sym.AttrReachable
   174  	rel.Sym.Attr |= sym.AttrLocal
   175  	rel.Type = objabi.R_ADDRPOWER_GOT
   176  	o(0x3c620000)
   177  	// ld r3, local.moduledata@got@l(r3)
   178  	o(0xe8630000)
   179  	// bl runtime.addmoduledata
   180  	rel = initfunc.AddRel()
   181  	rel.Off = int32(initfunc.Size)
   182  	rel.Siz = 4
   183  	rel.Sym = addmoduledata
   184  	rel.Type = objabi.R_CALLPOWER
   185  	o(0x48000001)
   186  	// nop
   187  	o(0x60000000)
   188  	// ld r31, 0(r1)
   189  	o(0xe8010000)
   190  	// mtlr r31
   191  	o(0x7c0803a6)
   192  	// addi r1,r1,32
   193  	o(0x38210020)
   194  	// blr
   195  	o(0x4e800020)
   196  
   197  	if ctxt.BuildMode == ld.BuildModePlugin {
   198  		ctxt.Textp = append(ctxt.Textp, addmoduledata)
   199  	}
   200  	initarray_entry := ctxt.Syms.Lookup("go.link.addmoduledatainit", 0)
   201  	ctxt.Textp = append(ctxt.Textp, initfunc)
   202  	initarray_entry.Attr |= sym.AttrReachable
   203  	initarray_entry.Attr |= sym.AttrLocal
   204  	initarray_entry.Type = sym.SINITARR
   205  	initarray_entry.AddAddr(ctxt.Arch, initfunc)
   206  }
   207  
   208  func gentext(ctxt *ld.Link) {
   209  	if ctxt.DynlinkingGo() {
   210  		genaddmoduledata(ctxt)
   211  	}
   212  
   213  	if ctxt.LinkMode == ld.LinkInternal {
   214  		genplt(ctxt)
   215  	}
   216  }
   217  
   218  // Construct a call stub in stub that calls symbol targ via its PLT
   219  // entry.
   220  func gencallstub(ctxt *ld.Link, abicase int, stub *sym.Symbol, targ *sym.Symbol) {
   221  	if abicase != 1 {
   222  		// If we see R_PPC64_TOCSAVE or R_PPC64_REL24_NOTOC
   223  		// relocations, we'll need to implement cases 2 and 3.
   224  		log.Fatalf("gencallstub only implements case 1 calls")
   225  	}
   226  
   227  	plt := ctxt.Syms.Lookup(".plt", 0)
   228  
   229  	stub.Type = sym.STEXT
   230  
   231  	// Save TOC pointer in TOC save slot
   232  	stub.AddUint32(ctxt.Arch, 0xf8410018) // std r2,24(r1)
   233  
   234  	// Load the function pointer from the PLT.
   235  	r := stub.AddRel()
   236  
   237  	r.Off = int32(stub.Size)
   238  	r.Sym = plt
   239  	r.Add = int64(targ.Plt)
   240  	r.Siz = 2
   241  	if ctxt.Arch.ByteOrder == binary.BigEndian {
   242  		r.Off += int32(r.Siz)
   243  	}
   244  	r.Type = objabi.R_POWER_TOC
   245  	r.Variant = sym.RV_POWER_HA
   246  	stub.AddUint32(ctxt.Arch, 0x3d820000) // addis r12,r2,targ@plt@toc@ha
   247  	r = stub.AddRel()
   248  	r.Off = int32(stub.Size)
   249  	r.Sym = plt
   250  	r.Add = int64(targ.Plt)
   251  	r.Siz = 2
   252  	if ctxt.Arch.ByteOrder == binary.BigEndian {
   253  		r.Off += int32(r.Siz)
   254  	}
   255  	r.Type = objabi.R_POWER_TOC
   256  	r.Variant = sym.RV_POWER_LO
   257  	stub.AddUint32(ctxt.Arch, 0xe98c0000) // ld r12,targ@plt@toc@l(r12)
   258  
   259  	// Jump to the loaded pointer
   260  	stub.AddUint32(ctxt.Arch, 0x7d8903a6) // mtctr r12
   261  	stub.AddUint32(ctxt.Arch, 0x4e800420) // bctr
   262  }
   263  
   264  func adddynrel(ctxt *ld.Link, s *sym.Symbol, r *sym.Reloc) bool {
   265  	targ := r.Sym
   266  
   267  	switch r.Type {
   268  	default:
   269  		if r.Type >= 256 {
   270  			ld.Errorf(s, "unexpected relocation type %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
   271  			return false
   272  		}
   273  
   274  		// Handle relocations found in ELF object files.
   275  	case 256 + objabi.RelocType(elf.R_PPC64_REL24):
   276  		r.Type = objabi.R_CALLPOWER
   277  
   278  		// This is a local call, so the caller isn't setting
   279  		// up r12 and r2 is the same for the caller and
   280  		// callee. Hence, we need to go to the local entry
   281  		// point.  (If we don't do this, the callee will try
   282  		// to use r12 to compute r2.)
   283  		r.Add += int64(r.Sym.Localentry) * 4
   284  
   285  		if targ.Type == sym.SDYNIMPORT {
   286  			// Should have been handled in elfsetupplt
   287  			ld.Errorf(s, "unexpected R_PPC64_REL24 for dyn import")
   288  		}
   289  
   290  		return true
   291  
   292  	case 256 + objabi.RelocType(elf.R_PPC_REL32):
   293  		r.Type = objabi.R_PCREL
   294  		r.Add += 4
   295  
   296  		if targ.Type == sym.SDYNIMPORT {
   297  			ld.Errorf(s, "unexpected R_PPC_REL32 for dyn import")
   298  		}
   299  
   300  		return true
   301  
   302  	case 256 + objabi.RelocType(elf.R_PPC64_ADDR64):
   303  		r.Type = objabi.R_ADDR
   304  		if targ.Type == sym.SDYNIMPORT {
   305  			// These happen in .toc sections
   306  			ld.Adddynsym(ctxt, targ)
   307  
   308  			rela := ctxt.Syms.Lookup(".rela", 0)
   309  			rela.AddAddrPlus(ctxt.Arch, s, int64(r.Off))
   310  			rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(targ.Dynid), uint32(elf.R_PPC64_ADDR64)))
   311  			rela.AddUint64(ctxt.Arch, uint64(r.Add))
   312  			r.Type = 256 // ignore during relocsym
   313  		}
   314  
   315  		return true
   316  
   317  	case 256 + objabi.RelocType(elf.R_PPC64_TOC16):
   318  		r.Type = objabi.R_POWER_TOC
   319  		r.Variant = sym.RV_POWER_LO | sym.RV_CHECK_OVERFLOW
   320  		return true
   321  
   322  	case 256 + objabi.RelocType(elf.R_PPC64_TOC16_LO):
   323  		r.Type = objabi.R_POWER_TOC
   324  		r.Variant = sym.RV_POWER_LO
   325  		return true
   326  
   327  	case 256 + objabi.RelocType(elf.R_PPC64_TOC16_HA):
   328  		r.Type = objabi.R_POWER_TOC
   329  		r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
   330  		return true
   331  
   332  	case 256 + objabi.RelocType(elf.R_PPC64_TOC16_HI):
   333  		r.Type = objabi.R_POWER_TOC
   334  		r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
   335  		return true
   336  
   337  	case 256 + objabi.RelocType(elf.R_PPC64_TOC16_DS):
   338  		r.Type = objabi.R_POWER_TOC
   339  		r.Variant = sym.RV_POWER_DS | sym.RV_CHECK_OVERFLOW
   340  		return true
   341  
   342  	case 256 + objabi.RelocType(elf.R_PPC64_TOC16_LO_DS):
   343  		r.Type = objabi.R_POWER_TOC
   344  		r.Variant = sym.RV_POWER_DS
   345  		return true
   346  
   347  	case 256 + objabi.RelocType(elf.R_PPC64_REL16_LO):
   348  		r.Type = objabi.R_PCREL
   349  		r.Variant = sym.RV_POWER_LO
   350  		r.Add += 2 // Compensate for relocation size of 2
   351  		return true
   352  
   353  	case 256 + objabi.RelocType(elf.R_PPC64_REL16_HI):
   354  		r.Type = objabi.R_PCREL
   355  		r.Variant = sym.RV_POWER_HI | sym.RV_CHECK_OVERFLOW
   356  		r.Add += 2
   357  		return true
   358  
   359  	case 256 + objabi.RelocType(elf.R_PPC64_REL16_HA):
   360  		r.Type = objabi.R_PCREL
   361  		r.Variant = sym.RV_POWER_HA | sym.RV_CHECK_OVERFLOW
   362  		r.Add += 2
   363  		return true
   364  	}
   365  
   366  	// Handle references to ELF symbols from our own object files.
   367  	if targ.Type != sym.SDYNIMPORT {
   368  		return true
   369  	}
   370  
   371  	// TODO(austin): Translate our relocations to ELF
   372  
   373  	return false
   374  }
   375  
   376  func elfreloc1(ctxt *ld.Link, r *sym.Reloc, sectoff int64) bool {
   377  	ctxt.Out.Write64(uint64(sectoff))
   378  
   379  	elfsym := r.Xsym.ElfsymForReloc()
   380  	switch r.Type {
   381  	default:
   382  		return false
   383  	case objabi.R_ADDR:
   384  		switch r.Siz {
   385  		case 4:
   386  			ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR32) | uint64(elfsym)<<32)
   387  		case 8:
   388  			ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR64) | uint64(elfsym)<<32)
   389  		default:
   390  			return false
   391  		}
   392  	case objabi.R_POWER_TLS:
   393  		ctxt.Out.Write64(uint64(elf.R_PPC64_TLS) | uint64(elfsym)<<32)
   394  	case objabi.R_POWER_TLS_LE:
   395  		ctxt.Out.Write64(uint64(elf.R_PPC64_TPREL16) | uint64(elfsym)<<32)
   396  	case objabi.R_POWER_TLS_IE:
   397  		ctxt.Out.Write64(uint64(elf.R_PPC64_GOT_TPREL16_HA) | uint64(elfsym)<<32)
   398  		ctxt.Out.Write64(uint64(r.Xadd))
   399  		ctxt.Out.Write64(uint64(sectoff + 4))
   400  		ctxt.Out.Write64(uint64(elf.R_PPC64_GOT_TPREL16_LO_DS) | uint64(elfsym)<<32)
   401  	case objabi.R_ADDRPOWER:
   402  		ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_HA) | uint64(elfsym)<<32)
   403  		ctxt.Out.Write64(uint64(r.Xadd))
   404  		ctxt.Out.Write64(uint64(sectoff + 4))
   405  		ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_LO) | uint64(elfsym)<<32)
   406  	case objabi.R_ADDRPOWER_DS:
   407  		ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_HA) | uint64(elfsym)<<32)
   408  		ctxt.Out.Write64(uint64(r.Xadd))
   409  		ctxt.Out.Write64(uint64(sectoff + 4))
   410  		ctxt.Out.Write64(uint64(elf.R_PPC64_ADDR16_LO_DS) | uint64(elfsym)<<32)
   411  	case objabi.R_ADDRPOWER_GOT:
   412  		ctxt.Out.Write64(uint64(elf.R_PPC64_GOT16_HA) | uint64(elfsym)<<32)
   413  		ctxt.Out.Write64(uint64(r.Xadd))
   414  		ctxt.Out.Write64(uint64(sectoff + 4))
   415  		ctxt.Out.Write64(uint64(elf.R_PPC64_GOT16_LO_DS) | uint64(elfsym)<<32)
   416  	case objabi.R_ADDRPOWER_PCREL:
   417  		ctxt.Out.Write64(uint64(elf.R_PPC64_REL16_HA) | uint64(elfsym)<<32)
   418  		ctxt.Out.Write64(uint64(r.Xadd))
   419  		ctxt.Out.Write64(uint64(sectoff + 4))
   420  		ctxt.Out.Write64(uint64(elf.R_PPC64_REL16_LO) | uint64(elfsym)<<32)
   421  		r.Xadd += 4
   422  	case objabi.R_ADDRPOWER_TOCREL:
   423  		ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_HA) | uint64(elfsym)<<32)
   424  		ctxt.Out.Write64(uint64(r.Xadd))
   425  		ctxt.Out.Write64(uint64(sectoff + 4))
   426  		ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_LO) | uint64(elfsym)<<32)
   427  	case objabi.R_ADDRPOWER_TOCREL_DS:
   428  		ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_HA) | uint64(elfsym)<<32)
   429  		ctxt.Out.Write64(uint64(r.Xadd))
   430  		ctxt.Out.Write64(uint64(sectoff + 4))
   431  		ctxt.Out.Write64(uint64(elf.R_PPC64_TOC16_LO_DS) | uint64(elfsym)<<32)
   432  	case objabi.R_CALLPOWER:
   433  		if r.Siz != 4 {
   434  			return false
   435  		}
   436  		ctxt.Out.Write64(uint64(elf.R_PPC64_REL24) | uint64(elfsym)<<32)
   437  
   438  	}
   439  	ctxt.Out.Write64(uint64(r.Xadd))
   440  
   441  	return true
   442  }
   443  
   444  func elfsetupplt(ctxt *ld.Link) {
   445  	plt := ctxt.Syms.Lookup(".plt", 0)
   446  	if plt.Size == 0 {
   447  		// The dynamic linker stores the address of the
   448  		// dynamic resolver and the DSO identifier in the two
   449  		// doublewords at the beginning of the .plt section
   450  		// before the PLT array. Reserve space for these.
   451  		plt.Size = 16
   452  	}
   453  }
   454  
   455  func machoreloc1(arch *sys.Arch, out *ld.OutBuf, s *sym.Symbol, r *sym.Reloc, sectoff int64) bool {
   456  	return false
   457  }
   458  
   459  // Return the value of .TOC. for symbol s
   460  func symtoc(ctxt *ld.Link, s *sym.Symbol) int64 {
   461  	var toc *sym.Symbol
   462  
   463  	if s.Outer != nil {
   464  		toc = ctxt.Syms.ROLookup(".TOC.", int(s.Outer.Version))
   465  	} else {
   466  		toc = ctxt.Syms.ROLookup(".TOC.", int(s.Version))
   467  	}
   468  
   469  	if toc == nil {
   470  		ld.Errorf(s, "TOC-relative relocation in object without .TOC.")
   471  		return 0
   472  	}
   473  
   474  	return toc.Value
   475  }
   476  
   477  func archrelocaddr(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool {
   478  	var o1, o2 uint32
   479  	if ctxt.Arch.ByteOrder == binary.BigEndian {
   480  		o1 = uint32(*val >> 32)
   481  		o2 = uint32(*val)
   482  	} else {
   483  		o1 = uint32(*val)
   484  		o2 = uint32(*val >> 32)
   485  	}
   486  
   487  	// We are spreading a 31-bit address across two instructions, putting the
   488  	// high (adjusted) part in the low 16 bits of the first instruction and the
   489  	// low part in the low 16 bits of the second instruction, or, in the DS case,
   490  	// bits 15-2 (inclusive) of the address into bits 15-2 of the second
   491  	// instruction (it is an error in this case if the low 2 bits of the address
   492  	// are non-zero).
   493  
   494  	t := ld.Symaddr(r.Sym) + r.Add
   495  	if t < 0 || t >= 1<<31 {
   496  		ld.Errorf(s, "relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
   497  	}
   498  	if t&0x8000 != 0 {
   499  		t += 0x10000
   500  	}
   501  
   502  	switch r.Type {
   503  	case objabi.R_ADDRPOWER:
   504  		o1 |= (uint32(t) >> 16) & 0xffff
   505  		o2 |= uint32(t) & 0xffff
   506  	case objabi.R_ADDRPOWER_DS:
   507  		o1 |= (uint32(t) >> 16) & 0xffff
   508  		if t&3 != 0 {
   509  			ld.Errorf(s, "bad DS reloc for %s: %d", s.Name, ld.Symaddr(r.Sym))
   510  		}
   511  		o2 |= uint32(t) & 0xfffc
   512  	default:
   513  		return false
   514  	}
   515  
   516  	if ctxt.Arch.ByteOrder == binary.BigEndian {
   517  		*val = int64(o1)<<32 | int64(o2)
   518  	} else {
   519  		*val = int64(o2)<<32 | int64(o1)
   520  	}
   521  	return true
   522  }
   523  
   524  // resolve direct jump relocation r in s, and add trampoline if necessary
   525  func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
   526  
   527  	// Trampolines are created if the branch offset is too large and the linker cannot insert a call stub to handle it.
   528  	// For internal linking, trampolines are always created for long calls.
   529  	// For external linking, the linker can insert a call stub to handle a long call, but depends on having the TOC address in
   530  	// r2.  For those build modes with external linking where the TOC address is not maintained in r2, trampolines must be created.
   531  	if ctxt.LinkMode == ld.LinkExternal && (ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE) {
   532  		// No trampolines needed since r2 contains the TOC
   533  		return
   534  	}
   535  
   536  	t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
   537  	switch r.Type {
   538  	case objabi.R_CALLPOWER:
   539  
   540  		// If branch offset is too far then create a trampoline.
   541  
   542  		if (ctxt.LinkMode == ld.LinkExternal && s.Sect != r.Sym.Sect) || (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) != t) || (*ld.FlagDebugTramp > 1 && s.File != r.Sym.File) {
   543  			var tramp *sym.Symbol
   544  			for i := 0; ; i++ {
   545  
   546  				// Using r.Add as part of the name is significant in functions like duffzero where the call
   547  				// target is at some offset within the function.  Calls to duff+8 and duff+256 must appear as
   548  				// distinct trampolines.
   549  
   550  				name := r.Sym.Name
   551  				if r.Add == 0 {
   552  					name = name + fmt.Sprintf("-tramp%d", i)
   553  				} else {
   554  					name = name + fmt.Sprintf("%+x-tramp%d", r.Add, i)
   555  				}
   556  
   557  				// Look up the trampoline in case it already exists
   558  
   559  				tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
   560  				if tramp.Value == 0 {
   561  					break
   562  				}
   563  
   564  				t = ld.Symaddr(tramp) + r.Add - (s.Value + int64(r.Off))
   565  
   566  				// With internal linking, the trampoline can be used if it is not too far.
   567  				// With external linking, the trampoline must be in this section for it to be reused.
   568  				if (ctxt.LinkMode == ld.LinkInternal && int64(int32(t<<6)>>6) == t) || (ctxt.LinkMode == ld.LinkExternal && s.Sect == tramp.Sect) {
   569  					break
   570  				}
   571  			}
   572  			if tramp.Type == 0 {
   573  				if ctxt.DynlinkingGo() || ctxt.BuildMode == ld.BuildModeCArchive || ctxt.BuildMode == ld.BuildModeCShared || ctxt.BuildMode == ld.BuildModePIE {
   574  					// Should have returned for above cases
   575  					ld.Errorf(s, "unexpected trampoline for shared or dynamic linking\n")
   576  				} else {
   577  					ctxt.AddTramp(tramp)
   578  					gentramp(ctxt.Arch, ctxt.LinkMode, tramp, r.Sym, r.Add)
   579  				}
   580  			}
   581  			r.Sym = tramp
   582  			r.Add = 0 // This was folded into the trampoline target address
   583  			r.Done = false
   584  		}
   585  	default:
   586  		ld.Errorf(s, "trampoline called with non-jump reloc: %d (%s)", r.Type, sym.RelocName(ctxt.Arch, r.Type))
   587  	}
   588  }
   589  
   590  func gentramp(arch *sys.Arch, linkmode ld.LinkMode, tramp, target *sym.Symbol, offset int64) {
   591  	// Used for default build mode for an executable
   592  	// Address of the call target is generated using
   593  	// relocation and doesn't depend on r2 (TOC).
   594  	tramp.Size = 16 // 4 instructions
   595  	tramp.P = make([]byte, tramp.Size)
   596  	t := ld.Symaddr(target) + offset
   597  	o1 := uint32(0x3fe00000) // lis r31,targetaddr hi
   598  	o2 := uint32(0x3bff0000) // addi r31,targetaddr lo
   599  	// With external linking, the target address must be
   600  	// relocated using LO and HA
   601  	if linkmode == ld.LinkExternal {
   602  		tr := tramp.AddRel()
   603  		tr.Off = 0
   604  		tr.Type = objabi.R_ADDRPOWER
   605  		tr.Siz = 8 // generates 2 relocations:  HA + LO
   606  		tr.Sym = target
   607  		tr.Add = offset
   608  	} else {
   609  		// adjustment needed if lo has sign bit set
   610  		// when using addi to compute address
   611  		val := uint32((t & 0xffff0000) >> 16)
   612  		if t&0x8000 != 0 {
   613  			val += 1
   614  		}
   615  		o1 |= val                // hi part of addr
   616  		o2 |= uint32(t & 0xffff) // lo part of addr
   617  	}
   618  	o3 := uint32(0x7fe903a6) // mtctr r31
   619  	o4 := uint32(0x4e800420) // bctr
   620  	arch.ByteOrder.PutUint32(tramp.P, o1)
   621  	arch.ByteOrder.PutUint32(tramp.P[4:], o2)
   622  	arch.ByteOrder.PutUint32(tramp.P[8:], o3)
   623  	arch.ByteOrder.PutUint32(tramp.P[12:], o4)
   624  }
   625  
   626  func archreloc(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, val *int64) bool {
   627  	if ctxt.LinkMode == ld.LinkExternal {
   628  		switch r.Type {
   629  		default:
   630  			return false
   631  		case objabi.R_POWER_TLS, objabi.R_POWER_TLS_LE, objabi.R_POWER_TLS_IE:
   632  			r.Done = false
   633  			// check Outer is nil, Type is TLSBSS?
   634  			r.Xadd = r.Add
   635  			r.Xsym = r.Sym
   636  			return true
   637  		case objabi.R_ADDRPOWER,
   638  			objabi.R_ADDRPOWER_DS,
   639  			objabi.R_ADDRPOWER_TOCREL,
   640  			objabi.R_ADDRPOWER_TOCREL_DS,
   641  			objabi.R_ADDRPOWER_GOT,
   642  			objabi.R_ADDRPOWER_PCREL:
   643  			r.Done = false
   644  
   645  			// set up addend for eventual relocation via outer symbol.
   646  			rs := r.Sym
   647  			r.Xadd = r.Add
   648  			for rs.Outer != nil {
   649  				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
   650  				rs = rs.Outer
   651  			}
   652  
   653  			if rs.Type != sym.SHOSTOBJ && rs.Type != sym.SDYNIMPORT && rs.Sect == nil {
   654  				ld.Errorf(s, "missing section for %s", rs.Name)
   655  			}
   656  			r.Xsym = rs
   657  
   658  			return true
   659  		case objabi.R_CALLPOWER:
   660  			r.Done = false
   661  			r.Xsym = r.Sym
   662  			r.Xadd = r.Add
   663  			return true
   664  		}
   665  	}
   666  
   667  	switch r.Type {
   668  	case objabi.R_CONST:
   669  		*val = r.Add
   670  		return true
   671  	case objabi.R_GOTOFF:
   672  		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ctxt.Syms.Lookup(".got", 0))
   673  		return true
   674  	case objabi.R_ADDRPOWER, objabi.R_ADDRPOWER_DS:
   675  		return archrelocaddr(ctxt, r, s, val)
   676  	case objabi.R_CALLPOWER:
   677  		// Bits 6 through 29 = (S + A - P) >> 2
   678  
   679  		t := ld.Symaddr(r.Sym) + r.Add - (s.Value + int64(r.Off))
   680  
   681  		if t&3 != 0 {
   682  			ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
   683  		}
   684  		// If branch offset is too far then create a trampoline.
   685  
   686  		if int64(int32(t<<6)>>6) != t {
   687  			ld.Errorf(s, "direct call too far: %s %x", r.Sym.Name, t)
   688  		}
   689  		*val |= int64(uint32(t) &^ 0xfc000003)
   690  		return true
   691  	case objabi.R_POWER_TOC: // S + A - .TOC.
   692  		*val = ld.Symaddr(r.Sym) + r.Add - symtoc(ctxt, s)
   693  
   694  		return true
   695  	case objabi.R_POWER_TLS_LE:
   696  		// The thread pointer points 0x7000 bytes after the start of the
   697  		// thread local storage area as documented in section "3.7.2 TLS
   698  		// Runtime Handling" of "Power Architecture 64-Bit ELF V2 ABI
   699  		// Specification".
   700  		v := r.Sym.Value - 0x7000
   701  		if int64(int16(v)) != v {
   702  			ld.Errorf(s, "TLS offset out of range %d", v)
   703  		}
   704  		*val = (*val &^ 0xffff) | (v & 0xffff)
   705  		return true
   706  	}
   707  
   708  	return false
   709  }
   710  
   711  func archrelocvariant(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol, t int64) int64 {
   712  	switch r.Variant & sym.RV_TYPE_MASK {
   713  	default:
   714  		ld.Errorf(s, "unexpected relocation variant %d", r.Variant)
   715  		fallthrough
   716  
   717  	case sym.RV_NONE:
   718  		return t
   719  
   720  	case sym.RV_POWER_LO:
   721  		if r.Variant&sym.RV_CHECK_OVERFLOW != 0 {
   722  			// Whether to check for signed or unsigned
   723  			// overflow depends on the instruction
   724  			var o1 uint32
   725  			if ctxt.Arch.ByteOrder == binary.BigEndian {
   726  				o1 = ld.Be32(s.P[r.Off-2:])
   727  			} else {
   728  				o1 = ld.Le32(s.P[r.Off:])
   729  			}
   730  			switch o1 >> 26 {
   731  			case 24, // ori
   732  				26, // xori
   733  				28: // andi
   734  				if t>>16 != 0 {
   735  					goto overflow
   736  				}
   737  
   738  			default:
   739  				if int64(int16(t)) != t {
   740  					goto overflow
   741  				}
   742  			}
   743  		}
   744  
   745  		return int64(int16(t))
   746  
   747  	case sym.RV_POWER_HA:
   748  		t += 0x8000
   749  		fallthrough
   750  
   751  		// Fallthrough
   752  	case sym.RV_POWER_HI:
   753  		t >>= 16
   754  
   755  		if r.Variant&sym.RV_CHECK_OVERFLOW != 0 {
   756  			// Whether to check for signed or unsigned
   757  			// overflow depends on the instruction
   758  			var o1 uint32
   759  			if ctxt.Arch.ByteOrder == binary.BigEndian {
   760  				o1 = ld.Be32(s.P[r.Off-2:])
   761  			} else {
   762  				o1 = ld.Le32(s.P[r.Off:])
   763  			}
   764  			switch o1 >> 26 {
   765  			case 25, // oris
   766  				27, // xoris
   767  				29: // andis
   768  				if t>>16 != 0 {
   769  					goto overflow
   770  				}
   771  
   772  			default:
   773  				if int64(int16(t)) != t {
   774  					goto overflow
   775  				}
   776  			}
   777  		}
   778  
   779  		return int64(int16(t))
   780  
   781  	case sym.RV_POWER_DS:
   782  		var o1 uint32
   783  		if ctxt.Arch.ByteOrder == binary.BigEndian {
   784  			o1 = uint32(ld.Be16(s.P[r.Off:]))
   785  		} else {
   786  			o1 = uint32(ld.Le16(s.P[r.Off:]))
   787  		}
   788  		if t&3 != 0 {
   789  			ld.Errorf(s, "relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
   790  		}
   791  		if (r.Variant&sym.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
   792  			goto overflow
   793  		}
   794  		return int64(o1)&0x3 | int64(int16(t))
   795  	}
   796  
   797  overflow:
   798  	ld.Errorf(s, "relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
   799  	return t
   800  }
   801  
   802  func addpltsym(ctxt *ld.Link, s *sym.Symbol) {
   803  	if s.Plt >= 0 {
   804  		return
   805  	}
   806  
   807  	ld.Adddynsym(ctxt, s)
   808  
   809  	if ctxt.IsELF {
   810  		plt := ctxt.Syms.Lookup(".plt", 0)
   811  		rela := ctxt.Syms.Lookup(".rela.plt", 0)
   812  		if plt.Size == 0 {
   813  			elfsetupplt(ctxt)
   814  		}
   815  
   816  		// Create the glink resolver if necessary
   817  		glink := ensureglinkresolver(ctxt)
   818  
   819  		// Write symbol resolver stub (just a branch to the
   820  		// glink resolver stub)
   821  		r := glink.AddRel()
   822  
   823  		r.Sym = glink
   824  		r.Off = int32(glink.Size)
   825  		r.Siz = 4
   826  		r.Type = objabi.R_CALLPOWER
   827  		glink.AddUint32(ctxt.Arch, 0x48000000) // b .glink
   828  
   829  		// In the ppc64 ABI, the dynamic linker is responsible
   830  		// for writing the entire PLT.  We just need to
   831  		// reserve 8 bytes for each PLT entry and generate a
   832  		// JMP_SLOT dynamic relocation for it.
   833  		//
   834  		// TODO(austin): ABI v1 is different
   835  		s.Plt = int32(plt.Size)
   836  
   837  		plt.Size += 8
   838  
   839  		rela.AddAddrPlus(ctxt.Arch, plt, int64(s.Plt))
   840  		rela.AddUint64(ctxt.Arch, ld.ELF64_R_INFO(uint32(s.Dynid), uint32(elf.R_PPC64_JMP_SLOT)))
   841  		rela.AddUint64(ctxt.Arch, 0)
   842  	} else {
   843  		ld.Errorf(s, "addpltsym: unsupported binary format")
   844  	}
   845  }
   846  
   847  // Generate the glink resolver stub if necessary and return the .glink section
   848  func ensureglinkresolver(ctxt *ld.Link) *sym.Symbol {
   849  	glink := ctxt.Syms.Lookup(".glink", 0)
   850  	if glink.Size != 0 {
   851  		return glink
   852  	}
   853  
   854  	// This is essentially the resolver from the ppc64 ELF ABI.
   855  	// At entry, r12 holds the address of the symbol resolver stub
   856  	// for the target routine and the argument registers hold the
   857  	// arguments for the target routine.
   858  	//
   859  	// This stub is PIC, so first get the PC of label 1 into r11.
   860  	// Other things will be relative to this.
   861  	glink.AddUint32(ctxt.Arch, 0x7c0802a6) // mflr r0
   862  	glink.AddUint32(ctxt.Arch, 0x429f0005) // bcl 20,31,1f
   863  	glink.AddUint32(ctxt.Arch, 0x7d6802a6) // 1: mflr r11
   864  	glink.AddUint32(ctxt.Arch, 0x7c0803a6) // mtlf r0
   865  
   866  	// Compute the .plt array index from the entry point address.
   867  	// Because this is PIC, everything is relative to label 1b (in
   868  	// r11):
   869  	//   r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
   870  	glink.AddUint32(ctxt.Arch, 0x3800ffd0) // li r0,-(res_0-1b)=-48
   871  	glink.AddUint32(ctxt.Arch, 0x7c006214) // add r0,r0,r12
   872  	glink.AddUint32(ctxt.Arch, 0x7c0b0050) // sub r0,r0,r11
   873  	glink.AddUint32(ctxt.Arch, 0x7800f082) // srdi r0,r0,2
   874  
   875  	// r11 = address of the first byte of the PLT
   876  	r := glink.AddRel()
   877  
   878  	r.Off = int32(glink.Size)
   879  	r.Sym = ctxt.Syms.Lookup(".plt", 0)
   880  	r.Siz = 8
   881  	r.Type = objabi.R_ADDRPOWER
   882  
   883  	glink.AddUint32(ctxt.Arch, 0x3d600000) // addis r11,0,.plt@ha
   884  	glink.AddUint32(ctxt.Arch, 0x396b0000) // addi r11,r11,.plt@l
   885  
   886  	// Load r12 = dynamic resolver address and r11 = DSO
   887  	// identifier from the first two doublewords of the PLT.
   888  	glink.AddUint32(ctxt.Arch, 0xe98b0000) // ld r12,0(r11)
   889  	glink.AddUint32(ctxt.Arch, 0xe96b0008) // ld r11,8(r11)
   890  
   891  	// Jump to the dynamic resolver
   892  	glink.AddUint32(ctxt.Arch, 0x7d8903a6) // mtctr r12
   893  	glink.AddUint32(ctxt.Arch, 0x4e800420) // bctr
   894  
   895  	// The symbol resolvers must immediately follow.
   896  	//   res_0:
   897  
   898  	// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
   899  	// before the first symbol resolver stub.
   900  	s := ctxt.Syms.Lookup(".dynamic", 0)
   901  
   902  	ld.Elfwritedynentsymplus(ctxt, s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
   903  
   904  	return glink
   905  }
   906  
   907  func asmb(ctxt *ld.Link) {
   908  	if ctxt.Debugvlog != 0 {
   909  		ctxt.Logf("%5.2f asmb\n", ld.Cputime())
   910  	}
   911  
   912  	if ctxt.IsELF {
   913  		ld.Asmbelfsetup()
   914  	}
   915  
   916  	for _, sect := range ld.Segtext.Sections {
   917  		ctxt.Out.SeekSet(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
   918  		// Handle additional text sections with Codeblk
   919  		if sect.Name == ".text" {
   920  			ld.Codeblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   921  		} else {
   922  			ld.Datblk(ctxt, int64(sect.Vaddr), int64(sect.Length))
   923  		}
   924  	}
   925  
   926  	if ld.Segrodata.Filelen > 0 {
   927  		if ctxt.Debugvlog != 0 {
   928  			ctxt.Logf("%5.2f rodatblk\n", ld.Cputime())
   929  		}
   930  		ctxt.Out.SeekSet(int64(ld.Segrodata.Fileoff))
   931  		ld.Datblk(ctxt, int64(ld.Segrodata.Vaddr), int64(ld.Segrodata.Filelen))
   932  	}
   933  	if ld.Segrelrodata.Filelen > 0 {
   934  		if ctxt.Debugvlog != 0 {
   935  			ctxt.Logf("%5.2f relrodatblk\n", ld.Cputime())
   936  		}
   937  		ctxt.Out.SeekSet(int64(ld.Segrelrodata.Fileoff))
   938  		ld.Datblk(ctxt, int64(ld.Segrelrodata.Vaddr), int64(ld.Segrelrodata.Filelen))
   939  	}
   940  
   941  	if ctxt.Debugvlog != 0 {
   942  		ctxt.Logf("%5.2f datblk\n", ld.Cputime())
   943  	}
   944  
   945  	ctxt.Out.SeekSet(int64(ld.Segdata.Fileoff))
   946  	ld.Datblk(ctxt, int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
   947  
   948  	ctxt.Out.SeekSet(int64(ld.Segdwarf.Fileoff))
   949  	ld.Dwarfblk(ctxt, int64(ld.Segdwarf.Vaddr), int64(ld.Segdwarf.Filelen))
   950  
   951  	/* output symbol table */
   952  	ld.Symsize = 0
   953  
   954  	ld.Lcsize = 0
   955  	symo := uint32(0)
   956  	if !*ld.FlagS {
   957  		// TODO: rationalize
   958  		if ctxt.Debugvlog != 0 {
   959  			ctxt.Logf("%5.2f sym\n", ld.Cputime())
   960  		}
   961  		switch ctxt.HeadType {
   962  		default:
   963  			if ctxt.IsELF {
   964  				symo = uint32(ld.Segdwarf.Fileoff + ld.Segdwarf.Filelen)
   965  				symo = uint32(ld.Rnd(int64(symo), int64(*ld.FlagRound)))
   966  			}
   967  
   968  		case objabi.Hplan9:
   969  			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
   970  		}
   971  
   972  		ctxt.Out.SeekSet(int64(symo))
   973  		switch ctxt.HeadType {
   974  		default:
   975  			if ctxt.IsELF {
   976  				if ctxt.Debugvlog != 0 {
   977  					ctxt.Logf("%5.2f elfsym\n", ld.Cputime())
   978  				}
   979  				ld.Asmelfsym(ctxt)
   980  				ctxt.Out.Flush()
   981  				ctxt.Out.Write(ld.Elfstrdat)
   982  
   983  				if ctxt.LinkMode == ld.LinkExternal {
   984  					ld.Elfemitreloc(ctxt)
   985  				}
   986  			}
   987  
   988  		case objabi.Hplan9:
   989  			ld.Asmplan9sym(ctxt)
   990  			ctxt.Out.Flush()
   991  
   992  			sym := ctxt.Syms.Lookup("pclntab", 0)
   993  			if sym != nil {
   994  				ld.Lcsize = int32(len(sym.P))
   995  				ctxt.Out.Write(sym.P)
   996  				ctxt.Out.Flush()
   997  			}
   998  		}
   999  	}
  1000  
  1001  	if ctxt.Debugvlog != 0 {
  1002  		ctxt.Logf("%5.2f header\n", ld.Cputime())
  1003  	}
  1004  	ctxt.Out.SeekSet(0)
  1005  	switch ctxt.HeadType {
  1006  	default:
  1007  	case objabi.Hplan9: /* plan 9 */
  1008  		ctxt.Out.Write32(0x647)                      /* magic */
  1009  		ctxt.Out.Write32(uint32(ld.Segtext.Filelen)) /* sizes */
  1010  		ctxt.Out.Write32(uint32(ld.Segdata.Filelen))
  1011  		ctxt.Out.Write32(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
  1012  		ctxt.Out.Write32(uint32(ld.Symsize))          /* nsyms */
  1013  		ctxt.Out.Write32(uint32(ld.Entryvalue(ctxt))) /* va of entry */
  1014  		ctxt.Out.Write32(0)
  1015  		ctxt.Out.Write32(uint32(ld.Lcsize))
  1016  
  1017  	case objabi.Hlinux,
  1018  		objabi.Hfreebsd,
  1019  		objabi.Hnetbsd,
  1020  		objabi.Hopenbsd,
  1021  		objabi.Hnacl:
  1022  		ld.Asmbelf(ctxt, int64(symo))
  1023  	}
  1024  
  1025  	ctxt.Out.Flush()
  1026  	if *ld.FlagC {
  1027  		fmt.Printf("textsize=%d\n", ld.Segtext.Filelen)
  1028  		fmt.Printf("datsize=%d\n", ld.Segdata.Filelen)
  1029  		fmt.Printf("bsssize=%d\n", ld.Segdata.Length-ld.Segdata.Filelen)
  1030  		fmt.Printf("symsize=%d\n", ld.Symsize)
  1031  		fmt.Printf("lcsize=%d\n", ld.Lcsize)
  1032  		fmt.Printf("total=%d\n", ld.Segtext.Filelen+ld.Segdata.Length+uint64(ld.Symsize)+uint64(ld.Lcsize))
  1033  	}
  1034  }
  1035  

View as plain text