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 }