rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/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 "strings"
    34  
    35  // Symbol table.
    36  
    37  func putelfstr(s string) int {
    38  	if len(Elfstrdat) == 0 && s != "" {
    39  		// first entry must be empty string
    40  		putelfstr("")
    41  	}
    42  
    43  	// When dynamically linking, we create LSym's by reading the names from
    44  	// the symbol tables of the shared libraries and so the names need to
    45  	// match exactly.  Tools like DTrace will have to wait for now.
    46  	if !DynlinkingGo() {
    47  		// Rewrite · to . for ASCII-only tools like DTrace (sigh)
    48  		s = strings.Replace(s, "·", ".", -1)
    49  	}
    50  
    51  	n := len(s) + 1
    52  	for len(Elfstrdat)+n > cap(Elfstrdat) {
    53  		Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
    54  	}
    55  
    56  	off := len(Elfstrdat)
    57  	Elfstrdat = Elfstrdat[:off+n]
    58  	copy(Elfstrdat[off:], s)
    59  
    60  	return off
    61  }
    62  
    63  func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
    64  	switch Thearch.Thechar {
    65  	case '6', '7', '9':
    66  		Thearch.Lput(uint32(off))
    67  		Cput(uint8(info))
    68  		Cput(uint8(other))
    69  		Thearch.Wput(uint16(shndx))
    70  		Thearch.Vput(uint64(addr))
    71  		Thearch.Vput(uint64(size))
    72  		Symsize += ELF64SYMSIZE
    73  
    74  	default:
    75  		Thearch.Lput(uint32(off))
    76  		Thearch.Lput(uint32(addr))
    77  		Thearch.Lput(uint32(size))
    78  		Cput(uint8(info))
    79  		Cput(uint8(other))
    80  		Thearch.Wput(uint16(shndx))
    81  		Symsize += ELF32SYMSIZE
    82  	}
    83  }
    84  
    85  var numelfsym int = 1 // 0 is reserved
    86  
    87  var elfbind int
    88  
    89  func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
    90  	var type_ int
    91  
    92  	switch t {
    93  	default:
    94  		return
    95  
    96  	case 'T':
    97  		type_ = STT_FUNC
    98  
    99  	case 'D':
   100  		type_ = STT_OBJECT
   101  
   102  	case 'B':
   103  		type_ = STT_OBJECT
   104  
   105  	case 'U':
   106  		type_ = STT_NOTYPE
   107  		if x == Ctxt.Tlsg {
   108  			type_ = STT_TLS
   109  		}
   110  
   111  	case 't':
   112  		type_ = STT_TLS
   113  	}
   114  
   115  	xo := x
   116  	for xo.Outer != nil {
   117  		xo = xo.Outer
   118  	}
   119  
   120  	var elfshnum int
   121  	if xo.Type == SDYNIMPORT || xo.Type == SHOSTOBJ {
   122  		elfshnum = SHN_UNDEF
   123  	} else {
   124  		if xo.Sect == nil {
   125  			Ctxt.Cursym = x
   126  			Diag("missing section in putelfsym")
   127  			return
   128  		}
   129  		if xo.Sect.(*Section).Elfsect == nil {
   130  			Ctxt.Cursym = x
   131  			Diag("missing ELF section in putelfsym")
   132  			return
   133  		}
   134  		elfshnum = xo.Sect.(*Section).Elfsect.(*ElfShdr).shnum
   135  	}
   136  
   137  	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
   138  	// maybe one day STB_WEAK.
   139  	bind := STB_GLOBAL
   140  
   141  	if ver != 0 || (x.Type&SHIDDEN != 0) || x.Local {
   142  		bind = STB_LOCAL
   143  	}
   144  
   145  	// In external linking mode, we have to invoke gcc with -rdynamic
   146  	// to get the exported symbols put into the dynamic symbol table.
   147  	// To avoid filling the dynamic table with lots of unnecessary symbols,
   148  	// mark all Go symbols local (not global) in the final executable.
   149  	// But when we're dynamically linking, we need all those global symbols.
   150  	if !DynlinkingGo() && Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
   151  		bind = STB_LOCAL
   152  	}
   153  
   154  	if bind != elfbind {
   155  		return
   156  	}
   157  
   158  	off := putelfstr(s)
   159  	if Linkmode == LinkExternal && elfshnum != SHN_UNDEF {
   160  		addr -= int64(xo.Sect.(*Section).Vaddr)
   161  	}
   162  	other := STV_DEFAULT
   163  	if x.Type&SHIDDEN != 0 {
   164  		other = STV_HIDDEN
   165  	}
   166  	putelfsyment(off, addr, size, bind<<4|type_&0xf, elfshnum, other)
   167  	x.Elfsym = int32(numelfsym)
   168  	numelfsym++
   169  }
   170  
   171  func putelfsectionsym(s *LSym, shndx int) {
   172  	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
   173  	s.Elfsym = int32(numelfsym)
   174  	numelfsym++
   175  }
   176  
   177  func putelfsymshndx(sympos int64, shndx int) {
   178  	here := Cpos()
   179  	if elf64 {
   180  		Cseek(sympos + 6)
   181  	} else {
   182  		Cseek(sympos + 14)
   183  	}
   184  
   185  	Thearch.Wput(uint16(shndx))
   186  	Cseek(here)
   187  }
   188  
   189  func Asmelfsym() {
   190  	// the first symbol entry is reserved
   191  	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
   192  
   193  	dwarfaddelfsectionsyms()
   194  
   195  	elfbind = STB_LOCAL
   196  	genasmsym(putelfsym)
   197  
   198  	elfbind = STB_GLOBAL
   199  	elfglobalsymndx = numelfsym
   200  	genasmsym(putelfsym)
   201  }
   202  
   203  func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
   204  	switch t {
   205  	case 'T', 'L', 'D', 'B':
   206  		if ver != 0 {
   207  			t += 'a' - 'A'
   208  		}
   209  		fallthrough
   210  
   211  	case 'a',
   212  		'p',
   213  		'f',
   214  		'z',
   215  		'Z',
   216  		'm':
   217  		l := 4
   218  		if HEADTYPE == Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
   219  			Lputb(uint32(addr >> 32))
   220  			l = 8
   221  		}
   222  
   223  		Lputb(uint32(addr))
   224  		Cput(uint8(t + 0x80)) /* 0x80 is variable length */
   225  
   226  		var i int
   227  		if t == 'z' || t == 'Z' {
   228  			Cput(uint8(s[0]))
   229  			for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 {
   230  				Cput(uint8(s[i]))
   231  				Cput(uint8(s[i+1]))
   232  			}
   233  
   234  			Cput(0)
   235  			Cput(0)
   236  			i++
   237  		} else {
   238  			/* skip the '<' in filenames */
   239  			if t == 'f' {
   240  				s = s[1:]
   241  			}
   242  			for i = 0; i < len(s); i++ {
   243  				Cput(uint8(s[i]))
   244  			}
   245  			Cput(0)
   246  		}
   247  
   248  		Symsize += int32(l) + 1 + int32(i) + 1
   249  
   250  	default:
   251  		return
   252  	}
   253  }
   254  
   255  func Asmplan9sym() {
   256  	genasmsym(putplan9sym)
   257  }
   258  
   259  var symt *LSym
   260  
   261  func Wputl(w uint16) {
   262  	Cput(uint8(w))
   263  	Cput(uint8(w >> 8))
   264  }
   265  
   266  func Wputb(w uint16) {
   267  	Cput(uint8(w >> 8))
   268  	Cput(uint8(w))
   269  }
   270  
   271  func Lputb(l uint32) {
   272  	Cput(uint8(l >> 24))
   273  	Cput(uint8(l >> 16))
   274  	Cput(uint8(l >> 8))
   275  	Cput(uint8(l))
   276  }
   277  
   278  func Lputl(l uint32) {
   279  	Cput(uint8(l))
   280  	Cput(uint8(l >> 8))
   281  	Cput(uint8(l >> 16))
   282  	Cput(uint8(l >> 24))
   283  }
   284  
   285  func Vputb(v uint64) {
   286  	Lputb(uint32(v >> 32))
   287  	Lputb(uint32(v))
   288  }
   289  
   290  func Vputl(v uint64) {
   291  	Lputl(uint32(v))
   292  	Lputl(uint32(v >> 32))
   293  }
   294  
   295  func symtab() {
   296  	dosymtype()
   297  
   298  	// Define these so that they'll get put into the symbol table.
   299  	// data.c:/^address will provide the actual values.
   300  	xdefine("runtime.text", STEXT, 0)
   301  
   302  	xdefine("runtime.etext", STEXT, 0)
   303  	xdefine("runtime.typelink", SRODATA, 0)
   304  	xdefine("runtime.etypelink", SRODATA, 0)
   305  	xdefine("runtime.rodata", SRODATA, 0)
   306  	xdefine("runtime.erodata", SRODATA, 0)
   307  	xdefine("runtime.noptrdata", SNOPTRDATA, 0)
   308  	xdefine("runtime.enoptrdata", SNOPTRDATA, 0)
   309  	xdefine("runtime.data", SDATA, 0)
   310  	xdefine("runtime.edata", SDATA, 0)
   311  	xdefine("runtime.bss", SBSS, 0)
   312  	xdefine("runtime.ebss", SBSS, 0)
   313  	xdefine("runtime.noptrbss", SNOPTRBSS, 0)
   314  	xdefine("runtime.enoptrbss", SNOPTRBSS, 0)
   315  	xdefine("runtime.end", SBSS, 0)
   316  	xdefine("runtime.epclntab", SRODATA, 0)
   317  	xdefine("runtime.esymtab", SRODATA, 0)
   318  
   319  	// garbage collection symbols
   320  	s := Linklookup(Ctxt, "runtime.gcdata", 0)
   321  
   322  	s.Type = SRODATA
   323  	s.Size = 0
   324  	s.Reachable = true
   325  	xdefine("runtime.egcdata", SRODATA, 0)
   326  
   327  	s = Linklookup(Ctxt, "runtime.gcbss", 0)
   328  	s.Type = SRODATA
   329  	s.Size = 0
   330  	s.Reachable = true
   331  	xdefine("runtime.egcbss", SRODATA, 0)
   332  
   333  	// pseudo-symbols to mark locations of type, string, and go string data.
   334  	var symtype *LSym
   335  	if !DynlinkingGo() {
   336  		s = Linklookup(Ctxt, "type.*", 0)
   337  
   338  		s.Type = STYPE
   339  		s.Size = 0
   340  		s.Reachable = true
   341  		symtype = s
   342  	}
   343  
   344  	s = Linklookup(Ctxt, "go.string.*", 0)
   345  	s.Type = SGOSTRING
   346  	s.Local = true
   347  	s.Size = 0
   348  	s.Reachable = true
   349  	symgostring := s
   350  
   351  	s = Linklookup(Ctxt, "go.func.*", 0)
   352  	s.Type = SGOFUNC
   353  	s.Local = true
   354  	s.Size = 0
   355  	s.Reachable = true
   356  	symgofunc := s
   357  
   358  	symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
   359  
   360  	symt = Linklookup(Ctxt, "runtime.symtab", 0)
   361  	symt.Local = true
   362  	symt.Type = SSYMTAB
   363  	symt.Size = 0
   364  	symt.Reachable = true
   365  
   366  	ntypelinks := 0
   367  
   368  	// assign specific types so that they sort together.
   369  	// within a type they sort by size, so the .* symbols
   370  	// just defined above will be first.
   371  	// hide the specific symbols.
   372  	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
   373  		if !s.Reachable || s.Special != 0 {
   374  			continue
   375  		}
   376  
   377  		if strings.Contains(s.Name, "..gostring.") || strings.Contains(s.Name, "..gobytes.") {
   378  			s.Local = true
   379  		}
   380  
   381  		if s.Type != SRODATA {
   382  			continue
   383  		}
   384  
   385  		if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() {
   386  			s.Type = STYPE
   387  			s.Hide = 1
   388  			s.Outer = symtype
   389  		}
   390  
   391  		if strings.HasPrefix(s.Name, "go.typelink.") {
   392  			ntypelinks++
   393  			s.Type = STYPELINK
   394  			s.Hide = 1
   395  			s.Outer = symtypelink
   396  		}
   397  
   398  		if strings.HasPrefix(s.Name, "go.string.") {
   399  			s.Type = SGOSTRING
   400  			s.Hide = 1
   401  			s.Outer = symgostring
   402  		}
   403  
   404  		if strings.HasPrefix(s.Name, "go.func.") {
   405  			s.Type = SGOFUNC
   406  			s.Hide = 1
   407  			s.Outer = symgofunc
   408  		}
   409  
   410  		if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
   411  			s.Type = SGOFUNC
   412  			s.Hide = 1
   413  			s.Outer = symgofunc
   414  			s.Align = 4
   415  			liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
   416  		}
   417  	}
   418  
   419  	// Information about the layout of the executable image for the
   420  	// runtime to use. Any changes here must be matched by changes to
   421  	// the definition of moduledata in runtime/symtab.go.
   422  	// This code uses several global variables that are set by pcln.go:pclntab.
   423  	moduledata := Linklookup(Ctxt, "runtime.firstmoduledata", 0)
   424  	moduledata.Type = SNOPTRDATA
   425  	moduledatasize := moduledata.Size
   426  	moduledata.Size = 0 // truncate symbol back to 0 bytes to reinitialize
   427  	moduledata.Reachable = true
   428  	moduledata.Local = true
   429  	// The pclntab slice
   430  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0))
   431  	adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
   432  	adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
   433  	// The ftab slice
   434  	Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabPclntabOffset))
   435  	adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
   436  	adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
   437  	// The filetab slice
   438  	Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset))
   439  	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile))
   440  	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile))
   441  	// findfunctab
   442  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
   443  	// minpc, maxpc
   444  	Addaddr(Ctxt, moduledata, pclntabFirstFunc)
   445  	Addaddrplus(Ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size)
   446  	// pointers to specific parts of the module
   447  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.text", 0))
   448  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etext", 0))
   449  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrdata", 0))
   450  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrdata", 0))
   451  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.data", 0))
   452  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.edata", 0))
   453  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.bss", 0))
   454  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.ebss", 0))
   455  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrbss", 0))
   456  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrbss", 0))
   457  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0))
   458  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0))
   459  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0))
   460  	// The typelinks slice
   461  	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
   462  	adduint(Ctxt, moduledata, uint64(ntypelinks))
   463  	adduint(Ctxt, moduledata, uint64(ntypelinks))
   464  	// The rest of moduledata is zero initialized.
   465  	moduledata.Size = moduledatasize
   466  	Symgrow(Ctxt, moduledata, moduledatasize)
   467  
   468  	lastmoduledatap := Linklookup(Ctxt, "runtime.lastmoduledatap", 0)
   469  	if lastmoduledatap.Type != SDYNIMPORT {
   470  		lastmoduledatap.Type = SNOPTRDATA
   471  		lastmoduledatap.Size = 0 // overwrite existing value
   472  		Addaddr(Ctxt, lastmoduledatap, moduledata)
   473  	}
   474  }