github.com/Filosottile/go@v0.0.0-20170906193555-dbed9972d994/src/cmd/link/internal/ld/symtab.go (about)

     1  // Inferno utils/6l/span.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.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 ld
    32  
    33  import (
    34  	"cmd/internal/objabi"
    35  	"cmd/internal/sys"
    36  	"fmt"
    37  	"path/filepath"
    38  	"strings"
    39  )
    40  
    41  // Symbol table.
    42  
    43  func putelfstr(s string) int {
    44  	if len(Elfstrdat) == 0 && s != "" {
    45  		// first entry must be empty string
    46  		putelfstr("")
    47  	}
    48  
    49  	off := len(Elfstrdat)
    50  	Elfstrdat = append(Elfstrdat, s...)
    51  	Elfstrdat = append(Elfstrdat, 0)
    52  	return off
    53  }
    54  
    55  func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
    56  	if elf64 {
    57  		Thearch.Lput(uint32(off))
    58  		Cput(uint8(info))
    59  		Cput(uint8(other))
    60  		Thearch.Wput(uint16(shndx))
    61  		Thearch.Vput(uint64(addr))
    62  		Thearch.Vput(uint64(size))
    63  		Symsize += ELF64SYMSIZE
    64  	} else {
    65  		Thearch.Lput(uint32(off))
    66  		Thearch.Lput(uint32(addr))
    67  		Thearch.Lput(uint32(size))
    68  		Cput(uint8(info))
    69  		Cput(uint8(other))
    70  		Thearch.Wput(uint16(shndx))
    71  		Symsize += ELF32SYMSIZE
    72  	}
    73  }
    74  
    75  var numelfsym int = 1 // 0 is reserved
    76  
    77  var elfbind int
    78  
    79  func putelfsym(ctxt *Link, x *Symbol, s string, t SymbolType, addr int64, go_ *Symbol) {
    80  	var typ int
    81  
    82  	switch t {
    83  	default:
    84  		return
    85  
    86  	case TextSym:
    87  		typ = STT_FUNC
    88  
    89  	case DataSym, BSSSym:
    90  		typ = STT_OBJECT
    91  
    92  	case UndefinedSym:
    93  		// ElfType is only set for symbols read from Go shared libraries, but
    94  		// for other symbols it is left as STT_NOTYPE which is fine.
    95  		typ = int(x.ElfType)
    96  
    97  	case TLSSym:
    98  		typ = STT_TLS
    99  	}
   100  
   101  	size := x.Size
   102  	if t == UndefinedSym {
   103  		size = 0
   104  	}
   105  
   106  	xo := x
   107  	for xo.Outer != nil {
   108  		xo = xo.Outer
   109  	}
   110  
   111  	var elfshnum int
   112  	if xo.Type == SDYNIMPORT || xo.Type == SHOSTOBJ {
   113  		elfshnum = SHN_UNDEF
   114  	} else {
   115  		if xo.Sect == nil {
   116  			Errorf(x, "missing section in putelfsym")
   117  			return
   118  		}
   119  		if xo.Sect.Elfsect == nil {
   120  			Errorf(x, "missing ELF section in putelfsym")
   121  			return
   122  		}
   123  		elfshnum = xo.Sect.Elfsect.shnum
   124  	}
   125  
   126  	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
   127  	// maybe one day STB_WEAK.
   128  	bind := STB_GLOBAL
   129  
   130  	if x.Version != 0 || (x.Type&SHIDDEN != 0) || x.Attr.Local() {
   131  		bind = STB_LOCAL
   132  	}
   133  
   134  	// In external linking mode, we have to invoke gcc with -rdynamic
   135  	// to get the exported symbols put into the dynamic symbol table.
   136  	// To avoid filling the dynamic table with lots of unnecessary symbols,
   137  	// mark all Go symbols local (not global) in the final executable.
   138  	// But when we're dynamically linking, we need all those global symbols.
   139  	if !ctxt.DynlinkingGo() && Linkmode == LinkExternal && !x.Attr.CgoExportStatic() && elfshnum != SHN_UNDEF {
   140  		bind = STB_LOCAL
   141  	}
   142  
   143  	if Linkmode == LinkExternal && elfshnum != SHN_UNDEF {
   144  		addr -= int64(xo.Sect.Vaddr)
   145  	}
   146  	other := STV_DEFAULT
   147  	if x.Type&SHIDDEN != 0 {
   148  		other = STV_HIDDEN
   149  	}
   150  	if SysArch.Family == sys.PPC64 && typ == STT_FUNC && x.Attr.Shared() && x.Name != "runtime.duffzero" && x.Name != "runtime.duffcopy" {
   151  		// On ppc64 the top three bits of the st_other field indicate how
   152  		// many instructions separate the global and local entry points. In
   153  		// our case it is two instructions, indicated by the value 3.
   154  		// The conditions here match those in preprocess in
   155  		// cmd/internal/obj/ppc64/obj9.go, which is where the
   156  		// instructions are inserted.
   157  		other |= 3 << 5
   158  	}
   159  
   160  	// When dynamically linking, we create Symbols by reading the names from
   161  	// the symbol tables of the shared libraries and so the names need to
   162  	// match exactly. Tools like DTrace will have to wait for now.
   163  	if !ctxt.DynlinkingGo() {
   164  		// Rewrite · to . for ASCII-only tools like DTrace (sigh)
   165  		s = strings.Replace(s, "·", ".", -1)
   166  	}
   167  
   168  	if ctxt.DynlinkingGo() && bind == STB_GLOBAL && elfbind == STB_LOCAL && x.Type == STEXT {
   169  		// When dynamically linking, we want references to functions defined
   170  		// in this module to always be to the function object, not to the
   171  		// PLT. We force this by writing an additional local symbol for every
   172  		// global function symbol and making all relocations against the
   173  		// global symbol refer to this local symbol instead (see
   174  		// (*Symbol).ElfsymForReloc). This is approximately equivalent to the
   175  		// ELF linker -Bsymbolic-functions option, but that is buggy on
   176  		// several platforms.
   177  		putelfsyment(putelfstr("local."+s), addr, size, STB_LOCAL<<4|typ&0xf, elfshnum, other)
   178  		x.LocalElfsym = int32(numelfsym)
   179  		numelfsym++
   180  		return
   181  	} else if bind != elfbind {
   182  		return
   183  	}
   184  
   185  	putelfsyment(putelfstr(s), addr, size, bind<<4|typ&0xf, elfshnum, other)
   186  	x.Elfsym = int32(numelfsym)
   187  	numelfsym++
   188  }
   189  
   190  func putelfsectionsym(s *Symbol, shndx int) {
   191  	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
   192  	s.Elfsym = int32(numelfsym)
   193  	numelfsym++
   194  }
   195  
   196  func Asmelfsym(ctxt *Link) {
   197  	// the first symbol entry is reserved
   198  	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
   199  
   200  	dwarfaddelfsectionsyms(ctxt)
   201  
   202  	// Some linkers will add a FILE sym if one is not present.
   203  	// Avoid having the working directory inserted into the symbol table.
   204  	// It is added with a name to avoid problems with external linking
   205  	// encountered on some versions of Solaris. See issue #14957.
   206  	putelfsyment(putelfstr("go.go"), 0, 0, STB_LOCAL<<4|STT_FILE, SHN_ABS, 0)
   207  	numelfsym++
   208  
   209  	elfbind = STB_LOCAL
   210  	genasmsym(ctxt, putelfsym)
   211  
   212  	elfbind = STB_GLOBAL
   213  	elfglobalsymndx = numelfsym
   214  	genasmsym(ctxt, putelfsym)
   215  }
   216  
   217  func putplan9sym(ctxt *Link, x *Symbol, s string, typ SymbolType, addr int64, go_ *Symbol) {
   218  	t := int(typ)
   219  	switch typ {
   220  	case TextSym, DataSym, BSSSym:
   221  		if x.Version != 0 {
   222  			t += 'a' - 'A'
   223  		}
   224  		fallthrough
   225  
   226  	case AutoSym, ParamSym, FrameSym:
   227  		l := 4
   228  		if Headtype == objabi.Hplan9 && SysArch.Family == sys.AMD64 && !Flag8 {
   229  			Lputb(uint32(addr >> 32))
   230  			l = 8
   231  		}
   232  
   233  		Lputb(uint32(addr))
   234  		Cput(uint8(t + 0x80)) /* 0x80 is variable length */
   235  
   236  		var i int
   237  		for i = 0; i < len(s); i++ {
   238  			Cput(s[i])
   239  		}
   240  		Cput(0)
   241  
   242  		Symsize += int32(l) + 1 + int32(i) + 1
   243  
   244  	default:
   245  		return
   246  	}
   247  }
   248  
   249  func Asmplan9sym(ctxt *Link) {
   250  	genasmsym(ctxt, putplan9sym)
   251  }
   252  
   253  var symt *Symbol
   254  
   255  var encbuf [10]byte
   256  
   257  func Wputb(w uint16) { Cwrite(Append16b(encbuf[:0], w)) }
   258  func Lputb(l uint32) { Cwrite(Append32b(encbuf[:0], l)) }
   259  func Vputb(v uint64) { Cwrite(Append64b(encbuf[:0], v)) }
   260  
   261  func Wputl(w uint16) { Cwrite(Append16l(encbuf[:0], w)) }
   262  func Lputl(l uint32) { Cwrite(Append32l(encbuf[:0], l)) }
   263  func Vputl(v uint64) { Cwrite(Append64l(encbuf[:0], v)) }
   264  
   265  func Append16b(b []byte, v uint16) []byte {
   266  	return append(b, uint8(v>>8), uint8(v))
   267  }
   268  func Append16l(b []byte, v uint16) []byte {
   269  	return append(b, uint8(v), uint8(v>>8))
   270  }
   271  
   272  func Append32b(b []byte, v uint32) []byte {
   273  	return append(b, uint8(v>>24), uint8(v>>16), uint8(v>>8), uint8(v))
   274  }
   275  func Append32l(b []byte, v uint32) []byte {
   276  	return append(b, uint8(v), uint8(v>>8), uint8(v>>16), uint8(v>>24))
   277  }
   278  
   279  func Append64b(b []byte, v uint64) []byte {
   280  	return append(b, uint8(v>>56), uint8(v>>48), uint8(v>>40), uint8(v>>32),
   281  		uint8(v>>24), uint8(v>>16), uint8(v>>8), uint8(v))
   282  }
   283  
   284  func Append64l(b []byte, v uint64) []byte {
   285  	return append(b, uint8(v), uint8(v>>8), uint8(v>>16), uint8(v>>24),
   286  		uint8(v>>32), uint8(v>>40), uint8(v>>48), uint8(v>>56))
   287  }
   288  
   289  type byPkg []*Library
   290  
   291  func (libs byPkg) Len() int {
   292  	return len(libs)
   293  }
   294  
   295  func (libs byPkg) Less(a, b int) bool {
   296  	return libs[a].Pkg < libs[b].Pkg
   297  }
   298  
   299  func (libs byPkg) Swap(a, b int) {
   300  	libs[a], libs[b] = libs[b], libs[a]
   301  }
   302  
   303  // Create a table with information on the text sections.
   304  
   305  func textsectionmap(ctxt *Link) uint32 {
   306  
   307  	t := ctxt.Syms.Lookup("runtime.textsectionmap", 0)
   308  	t.Type = SRODATA
   309  	t.Attr |= AttrReachable
   310  	nsections := int64(0)
   311  
   312  	for _, sect := range Segtext.Sections {
   313  		if sect.Name == ".text" {
   314  			nsections++
   315  		} else {
   316  			break
   317  		}
   318  	}
   319  	Symgrow(t, 3*nsections*int64(SysArch.PtrSize))
   320  
   321  	off := int64(0)
   322  	n := 0
   323  
   324  	// The vaddr for each text section is the difference between the section's
   325  	// Vaddr and the Vaddr for the first text section as determined at compile
   326  	// time.
   327  
   328  	// The symbol for the first text section is named runtime.text as before.
   329  	// Additional text sections are named runtime.text.n where n is the
   330  	// order of creation starting with 1. These symbols provide the section's
   331  	// address after relocation by the linker.
   332  
   333  	textbase := Segtext.Sections[0].Vaddr
   334  	for _, sect := range Segtext.Sections {
   335  		if sect.Name != ".text" {
   336  			break
   337  		}
   338  		off = setuint(ctxt, t, off, sect.Vaddr-textbase)
   339  		off = setuint(ctxt, t, off, sect.Length)
   340  		if n == 0 {
   341  			s := ctxt.Syms.ROLookup("runtime.text", 0)
   342  			if s == nil {
   343  				Errorf(nil, "Unable to find symbol runtime.text\n")
   344  			}
   345  			off = setaddr(ctxt, t, off, s)
   346  
   347  		} else {
   348  			s := ctxt.Syms.Lookup(fmt.Sprintf("runtime.text.%d", n), 0)
   349  			if s == nil {
   350  				Errorf(nil, "Unable to find symbol runtime.text.%d\n", n)
   351  			}
   352  			off = setaddr(ctxt, t, off, s)
   353  		}
   354  		n++
   355  	}
   356  	return uint32(n)
   357  }
   358  
   359  func (ctxt *Link) symtab() {
   360  	dosymtype(ctxt)
   361  
   362  	// Define these so that they'll get put into the symbol table.
   363  	// data.c:/^address will provide the actual values.
   364  	ctxt.xdefine("runtime.text", STEXT, 0)
   365  
   366  	ctxt.xdefine("runtime.etext", STEXT, 0)
   367  	ctxt.xdefine("runtime.itablink", SRODATA, 0)
   368  	ctxt.xdefine("runtime.eitablink", SRODATA, 0)
   369  	ctxt.xdefine("runtime.rodata", SRODATA, 0)
   370  	ctxt.xdefine("runtime.erodata", SRODATA, 0)
   371  	ctxt.xdefine("runtime.types", SRODATA, 0)
   372  	ctxt.xdefine("runtime.etypes", SRODATA, 0)
   373  	ctxt.xdefine("runtime.noptrdata", SNOPTRDATA, 0)
   374  	ctxt.xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
   375  	ctxt.xdefine("runtime.data", SDATA, 0)
   376  	ctxt.xdefine("runtime.edata", SDATA, 0)
   377  	ctxt.xdefine("runtime.bss", SBSS, 0)
   378  	ctxt.xdefine("runtime.ebss", SBSS, 0)
   379  	ctxt.xdefine("runtime.noptrbss", SNOPTRBSS, 0)
   380  	ctxt.xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
   381  	ctxt.xdefine("runtime.end", SBSS, 0)
   382  	ctxt.xdefine("runtime.epclntab", SRODATA, 0)
   383  	ctxt.xdefine("runtime.esymtab", SRODATA, 0)
   384  
   385  	// garbage collection symbols
   386  	s := ctxt.Syms.Lookup("runtime.gcdata", 0)
   387  
   388  	s.Type = SRODATA
   389  	s.Size = 0
   390  	s.Attr |= AttrReachable
   391  	ctxt.xdefine("runtime.egcdata", SRODATA, 0)
   392  
   393  	s = ctxt.Syms.Lookup("runtime.gcbss", 0)
   394  	s.Type = SRODATA
   395  	s.Size = 0
   396  	s.Attr |= AttrReachable
   397  	ctxt.xdefine("runtime.egcbss", SRODATA, 0)
   398  
   399  	// pseudo-symbols to mark locations of type, string, and go string data.
   400  	var symtype *Symbol
   401  	var symtyperel *Symbol
   402  	if UseRelro() && (Buildmode == BuildmodeCArchive || Buildmode == BuildmodeCShared || Buildmode == BuildmodePIE) {
   403  		s = ctxt.Syms.Lookup("type.*", 0)
   404  
   405  		s.Type = STYPE
   406  		s.Size = 0
   407  		s.Attr |= AttrReachable
   408  		symtype = s
   409  
   410  		s = ctxt.Syms.Lookup("typerel.*", 0)
   411  
   412  		s.Type = STYPERELRO
   413  		s.Size = 0
   414  		s.Attr |= AttrReachable
   415  		symtyperel = s
   416  	} else if !ctxt.DynlinkingGo() {
   417  		s = ctxt.Syms.Lookup("type.*", 0)
   418  
   419  		s.Type = STYPE
   420  		s.Size = 0
   421  		s.Attr |= AttrReachable
   422  		symtype = s
   423  		symtyperel = s
   424  	}
   425  
   426  	groupSym := func(name string, t SymKind) *Symbol {
   427  		s := ctxt.Syms.Lookup(name, 0)
   428  		s.Type = t
   429  		s.Size = 0
   430  		s.Attr |= AttrLocal | AttrReachable
   431  		return s
   432  	}
   433  	var (
   434  		symgostring = groupSym("go.string.*", SGOSTRING)
   435  		symgofunc   = groupSym("go.func.*", SGOFUNC)
   436  		symgcbits   = groupSym("runtime.gcbits.*", SGCBITS)
   437  	)
   438  
   439  	var symgofuncrel *Symbol
   440  	if !ctxt.DynlinkingGo() {
   441  		if UseRelro() {
   442  			symgofuncrel = groupSym("go.funcrel.*", SGOFUNCRELRO)
   443  		} else {
   444  			symgofuncrel = symgofunc
   445  		}
   446  	}
   447  
   448  	symitablink := ctxt.Syms.Lookup("runtime.itablink", 0)
   449  	symitablink.Type = SITABLINK
   450  
   451  	symt = ctxt.Syms.Lookup("runtime.symtab", 0)
   452  	symt.Attr |= AttrLocal
   453  	symt.Type = SSYMTAB
   454  	symt.Size = 0
   455  	symt.Attr |= AttrReachable
   456  
   457  	nitablinks := 0
   458  
   459  	// assign specific types so that they sort together.
   460  	// within a type they sort by size, so the .* symbols
   461  	// just defined above will be first.
   462  	// hide the specific symbols.
   463  	for _, s := range ctxt.Syms.Allsym {
   464  		if !s.Attr.Reachable() || s.Attr.Special() || s.Type != SRODATA {
   465  			continue
   466  		}
   467  
   468  		switch {
   469  		case strings.HasPrefix(s.Name, "type."):
   470  			if !ctxt.DynlinkingGo() {
   471  				s.Attr |= AttrNotInSymbolTable
   472  			}
   473  			if UseRelro() {
   474  				s.Type = STYPERELRO
   475  				s.Outer = symtyperel
   476  			} else {
   477  				s.Type = STYPE
   478  				s.Outer = symtype
   479  			}
   480  
   481  		case strings.HasPrefix(s.Name, "go.importpath.") && UseRelro():
   482  			// Keep go.importpath symbols in the same section as types and
   483  			// names, as they can be referred to by a section offset.
   484  			s.Type = STYPERELRO
   485  
   486  		case strings.HasPrefix(s.Name, "go.itablink."):
   487  			nitablinks++
   488  			s.Type = SITABLINK
   489  			s.Attr |= AttrNotInSymbolTable
   490  			s.Outer = symitablink
   491  
   492  		case strings.HasPrefix(s.Name, "go.string."):
   493  			s.Type = SGOSTRING
   494  			s.Attr |= AttrNotInSymbolTable
   495  			s.Outer = symgostring
   496  
   497  		case strings.HasPrefix(s.Name, "runtime.gcbits."):
   498  			s.Type = SGCBITS
   499  			s.Attr |= AttrNotInSymbolTable
   500  			s.Outer = symgcbits
   501  
   502  		case strings.HasSuffix(s.Name, "·f"):
   503  			if !ctxt.DynlinkingGo() {
   504  				s.Attr |= AttrNotInSymbolTable
   505  			}
   506  			if UseRelro() {
   507  				s.Type = SGOFUNCRELRO
   508  				s.Outer = symgofuncrel
   509  			} else {
   510  				s.Type = SGOFUNC
   511  				s.Outer = symgofunc
   512  			}
   513  
   514  		case strings.HasPrefix(s.Name, "gcargs."),
   515  			strings.HasPrefix(s.Name, "gclocals."),
   516  			strings.HasPrefix(s.Name, "gclocals·"),
   517  			strings.HasPrefix(s.Name, "inltree."):
   518  			s.Type = SGOFUNC
   519  			s.Attr |= AttrNotInSymbolTable
   520  			s.Outer = symgofunc
   521  			s.Align = 4
   522  			liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
   523  		}
   524  	}
   525  
   526  	if Buildmode == BuildmodeShared {
   527  		abihashgostr := ctxt.Syms.Lookup("go.link.abihash."+filepath.Base(*flagOutfile), 0)
   528  		abihashgostr.Attr |= AttrReachable
   529  		abihashgostr.Type = SRODATA
   530  		hashsym := ctxt.Syms.Lookup("go.link.abihashbytes", 0)
   531  		Addaddr(ctxt, abihashgostr, hashsym)
   532  		adduint(ctxt, abihashgostr, uint64(hashsym.Size))
   533  	}
   534  	if Buildmode == BuildmodePlugin || ctxt.Syms.ROLookup("plugin.Open", 0) != nil {
   535  		for _, l := range ctxt.Library {
   536  			s := ctxt.Syms.Lookup("go.link.pkghashbytes."+l.Pkg, 0)
   537  			s.Attr |= AttrReachable
   538  			s.Type = SRODATA
   539  			s.Size = int64(len(l.hash))
   540  			s.P = []byte(l.hash)
   541  			str := ctxt.Syms.Lookup("go.link.pkghash."+l.Pkg, 0)
   542  			str.Attr |= AttrReachable
   543  			str.Type = SRODATA
   544  			Addaddr(ctxt, str, s)
   545  			adduint(ctxt, str, uint64(len(l.hash)))
   546  		}
   547  	}
   548  
   549  	nsections := textsectionmap(ctxt)
   550  
   551  	// Information about the layout of the executable image for the
   552  	// runtime to use. Any changes here must be matched by changes to
   553  	// the definition of moduledata in runtime/symtab.go.
   554  	// This code uses several global variables that are set by pcln.go:pclntab.
   555  	moduledata := ctxt.Moduledata
   556  	// The pclntab slice
   557  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.pclntab", 0))
   558  	adduint(ctxt, moduledata, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size))
   559  	adduint(ctxt, moduledata, uint64(ctxt.Syms.Lookup("runtime.pclntab", 0).Size))
   560  	// The ftab slice
   561  	Addaddrplus(ctxt, moduledata, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabPclntabOffset))
   562  	adduint(ctxt, moduledata, uint64(pclntabNfunc+1))
   563  	adduint(ctxt, moduledata, uint64(pclntabNfunc+1))
   564  	// The filetab slice
   565  	Addaddrplus(ctxt, moduledata, ctxt.Syms.Lookup("runtime.pclntab", 0), int64(pclntabFiletabOffset))
   566  	adduint(ctxt, moduledata, uint64(len(ctxt.Filesyms))+1)
   567  	adduint(ctxt, moduledata, uint64(len(ctxt.Filesyms))+1)
   568  	// findfunctab
   569  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.findfunctab", 0))
   570  	// minpc, maxpc
   571  	Addaddr(ctxt, moduledata, pclntabFirstFunc)
   572  	Addaddrplus(ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size)
   573  	// pointers to specific parts of the module
   574  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.text", 0))
   575  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.etext", 0))
   576  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.noptrdata", 0))
   577  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.enoptrdata", 0))
   578  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.data", 0))
   579  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.edata", 0))
   580  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.bss", 0))
   581  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.ebss", 0))
   582  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.noptrbss", 0))
   583  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.enoptrbss", 0))
   584  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.end", 0))
   585  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.gcdata", 0))
   586  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.gcbss", 0))
   587  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.types", 0))
   588  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.etypes", 0))
   589  
   590  	// text section information
   591  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.textsectionmap", 0))
   592  	adduint(ctxt, moduledata, uint64(nsections))
   593  	adduint(ctxt, moduledata, uint64(nsections))
   594  
   595  	// The typelinks slice
   596  	typelinkSym := ctxt.Syms.Lookup("runtime.typelink", 0)
   597  	ntypelinks := uint64(typelinkSym.Size) / 4
   598  	Addaddr(ctxt, moduledata, typelinkSym)
   599  	adduint(ctxt, moduledata, ntypelinks)
   600  	adduint(ctxt, moduledata, ntypelinks)
   601  	// The itablinks slice
   602  	Addaddr(ctxt, moduledata, ctxt.Syms.Lookup("runtime.itablink", 0))
   603  	adduint(ctxt, moduledata, uint64(nitablinks))
   604  	adduint(ctxt, moduledata, uint64(nitablinks))
   605  	// The ptab slice
   606  	if ptab := ctxt.Syms.ROLookup("go.plugin.tabs", 0); ptab != nil && ptab.Attr.Reachable() {
   607  		ptab.Attr |= AttrLocal
   608  		ptab.Type = SRODATA
   609  
   610  		nentries := uint64(len(ptab.P) / 8) // sizeof(nameOff) + sizeof(typeOff)
   611  		Addaddr(ctxt, moduledata, ptab)
   612  		adduint(ctxt, moduledata, nentries)
   613  		adduint(ctxt, moduledata, nentries)
   614  	} else {
   615  		adduint(ctxt, moduledata, 0)
   616  		adduint(ctxt, moduledata, 0)
   617  		adduint(ctxt, moduledata, 0)
   618  	}
   619  	if Buildmode == BuildmodePlugin {
   620  		addgostring(ctxt, moduledata, "go.link.thispluginpath", *flagPluginPath)
   621  
   622  		pkghashes := ctxt.Syms.Lookup("go.link.pkghashes", 0)
   623  		pkghashes.Attr |= AttrReachable
   624  		pkghashes.Attr |= AttrLocal
   625  		pkghashes.Type = SRODATA
   626  
   627  		for i, l := range ctxt.Library {
   628  			// pkghashes[i].name
   629  			addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkgname.%d", i), l.Pkg)
   630  			// pkghashes[i].linktimehash
   631  			addgostring(ctxt, pkghashes, fmt.Sprintf("go.link.pkglinkhash.%d", i), string(l.hash))
   632  			// pkghashes[i].runtimehash
   633  			hash := ctxt.Syms.ROLookup("go.link.pkghash."+l.Pkg, 0)
   634  			Addaddr(ctxt, pkghashes, hash)
   635  		}
   636  		Addaddr(ctxt, moduledata, pkghashes)
   637  		adduint(ctxt, moduledata, uint64(len(ctxt.Library)))
   638  		adduint(ctxt, moduledata, uint64(len(ctxt.Library)))
   639  	} else {
   640  		adduint(ctxt, moduledata, 0) // pluginpath
   641  		adduint(ctxt, moduledata, 0)
   642  		adduint(ctxt, moduledata, 0) // pkghashes slice
   643  		adduint(ctxt, moduledata, 0)
   644  		adduint(ctxt, moduledata, 0)
   645  	}
   646  	if len(ctxt.Shlibs) > 0 {
   647  		thismodulename := filepath.Base(*flagOutfile)
   648  		switch Buildmode {
   649  		case BuildmodeExe, BuildmodePIE:
   650  			// When linking an executable, outfile is just "a.out". Make
   651  			// it something slightly more comprehensible.
   652  			thismodulename = "the executable"
   653  		}
   654  		addgostring(ctxt, moduledata, "go.link.thismodulename", thismodulename)
   655  
   656  		modulehashes := ctxt.Syms.Lookup("go.link.abihashes", 0)
   657  		modulehashes.Attr |= AttrReachable
   658  		modulehashes.Attr |= AttrLocal
   659  		modulehashes.Type = SRODATA
   660  
   661  		for i, shlib := range ctxt.Shlibs {
   662  			// modulehashes[i].modulename
   663  			modulename := filepath.Base(shlib.Path)
   664  			addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
   665  
   666  			// modulehashes[i].linktimehash
   667  			addgostring(ctxt, modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
   668  
   669  			// modulehashes[i].runtimehash
   670  			abihash := ctxt.Syms.Lookup("go.link.abihash."+modulename, 0)
   671  			abihash.Attr |= AttrReachable
   672  			Addaddr(ctxt, modulehashes, abihash)
   673  		}
   674  
   675  		Addaddr(ctxt, moduledata, modulehashes)
   676  		adduint(ctxt, moduledata, uint64(len(ctxt.Shlibs)))
   677  		adduint(ctxt, moduledata, uint64(len(ctxt.Shlibs)))
   678  	}
   679  
   680  	// The rest of moduledata is zero initialized.
   681  	// When linking an object that does not contain the runtime we are
   682  	// creating the moduledata from scratch and it does not have a
   683  	// compiler-provided size, so read it from the type data.
   684  	moduledatatype := ctxt.Syms.ROLookup("type.runtime.moduledata", 0)
   685  	moduledata.Size = decodetypeSize(ctxt.Arch, moduledatatype)
   686  	Symgrow(moduledata, moduledata.Size)
   687  
   688  	lastmoduledatap := ctxt.Syms.Lookup("runtime.lastmoduledatap", 0)
   689  	if lastmoduledatap.Type != SDYNIMPORT {
   690  		lastmoduledatap.Type = SNOPTRDATA
   691  		lastmoduledatap.Size = 0 // overwrite existing value
   692  		Addaddr(ctxt, lastmoduledatap, moduledata)
   693  	}
   694  }