github.com/4ad/go@v0.0.0-20161219182952-69a12818b605/src/cmd/link/internal/ld/symtab.go (about)

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