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