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