github.com/d4l3k/go@v0.0.0-20151015000803-65fc379daeda/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 bind != elfbind { 159 return 160 } 161 162 off := putelfstr(s) 163 if Linkmode == LinkExternal && elfshnum != SHN_UNDEF { 164 addr -= int64(xo.Sect.Vaddr) 165 } 166 other := STV_DEFAULT 167 if x.Type&obj.SHIDDEN != 0 { 168 other = STV_HIDDEN 169 } 170 putelfsyment(off, addr, size, bind<<4|type_&0xf, elfshnum, other) 171 x.Elfsym = int32(numelfsym) 172 numelfsym++ 173 } 174 175 func putelfsectionsym(s *LSym, shndx int) { 176 putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0) 177 s.Elfsym = int32(numelfsym) 178 numelfsym++ 179 } 180 181 func putelfsymshndx(sympos int64, shndx int) { 182 here := Cpos() 183 if elf64 { 184 Cseek(sympos + 6) 185 } else { 186 Cseek(sympos + 14) 187 } 188 189 Thearch.Wput(uint16(shndx)) 190 Cseek(here) 191 } 192 193 func Asmelfsym() { 194 // the first symbol entry is reserved 195 putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0) 196 197 dwarfaddelfsectionsyms() 198 199 elfbind = STB_LOCAL 200 genasmsym(putelfsym) 201 202 elfbind = STB_GLOBAL 203 elfglobalsymndx = numelfsym 204 genasmsym(putelfsym) 205 } 206 207 func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) { 208 switch t { 209 case 'T', 'L', 'D', 'B': 210 if ver != 0 { 211 t += 'a' - 'A' 212 } 213 fallthrough 214 215 case 'a', 216 'p', 217 'f', 218 'z', 219 'Z', 220 'm': 221 l := 4 222 if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 { 223 Lputb(uint32(addr >> 32)) 224 l = 8 225 } 226 227 Lputb(uint32(addr)) 228 Cput(uint8(t + 0x80)) /* 0x80 is variable length */ 229 230 var i int 231 if t == 'z' || t == 'Z' { 232 Cput(uint8(s[0])) 233 for i = 1; s[i] != 0 || s[i+1] != 0; i += 2 { 234 Cput(uint8(s[i])) 235 Cput(uint8(s[i+1])) 236 } 237 238 Cput(0) 239 Cput(0) 240 i++ 241 } else { 242 /* skip the '<' in filenames */ 243 if t == 'f' { 244 s = s[1:] 245 } 246 for i = 0; i < len(s); i++ { 247 Cput(uint8(s[i])) 248 } 249 Cput(0) 250 } 251 252 Symsize += int32(l) + 1 + int32(i) + 1 253 254 default: 255 return 256 } 257 } 258 259 func Asmplan9sym() { 260 genasmsym(putplan9sym) 261 } 262 263 var symt *LSym 264 265 func Wputl(w uint16) { 266 Cput(uint8(w)) 267 Cput(uint8(w >> 8)) 268 } 269 270 func Wputb(w uint16) { 271 Cput(uint8(w >> 8)) 272 Cput(uint8(w)) 273 } 274 275 func Lputb(l uint32) { 276 Cput(uint8(l >> 24)) 277 Cput(uint8(l >> 16)) 278 Cput(uint8(l >> 8)) 279 Cput(uint8(l)) 280 } 281 282 func Lputl(l uint32) { 283 Cput(uint8(l)) 284 Cput(uint8(l >> 8)) 285 Cput(uint8(l >> 16)) 286 Cput(uint8(l >> 24)) 287 } 288 289 func Vputb(v uint64) { 290 Lputb(uint32(v >> 32)) 291 Lputb(uint32(v)) 292 } 293 294 func Vputl(v uint64) { 295 Lputl(uint32(v)) 296 Lputl(uint32(v >> 32)) 297 } 298 299 type byPkg []*Library 300 301 func (libs byPkg) Len() int { 302 return len(libs) 303 } 304 305 func (libs byPkg) Less(a, b int) bool { 306 return libs[a].Pkg < libs[b].Pkg 307 } 308 309 func (libs byPkg) Swap(a, b int) { 310 libs[a], libs[b] = libs[b], libs[a] 311 } 312 313 func symtab() { 314 dosymtype() 315 316 // Define these so that they'll get put into the symbol table. 317 // data.c:/^address will provide the actual values. 318 xdefine("runtime.text", obj.STEXT, 0) 319 320 xdefine("runtime.etext", obj.STEXT, 0) 321 xdefine("runtime.typelink", obj.SRODATA, 0) 322 xdefine("runtime.etypelink", obj.SRODATA, 0) 323 xdefine("runtime.rodata", obj.SRODATA, 0) 324 xdefine("runtime.erodata", obj.SRODATA, 0) 325 xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0) 326 xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0) 327 xdefine("runtime.data", obj.SDATA, 0) 328 xdefine("runtime.edata", obj.SDATA, 0) 329 xdefine("runtime.bss", obj.SBSS, 0) 330 xdefine("runtime.ebss", obj.SBSS, 0) 331 xdefine("runtime.noptrbss", obj.SNOPTRBSS, 0) 332 xdefine("runtime.enoptrbss", obj.SNOPTRBSS, 0) 333 xdefine("runtime.end", obj.SBSS, 0) 334 xdefine("runtime.epclntab", obj.SRODATA, 0) 335 xdefine("runtime.esymtab", obj.SRODATA, 0) 336 337 // garbage collection symbols 338 s := Linklookup(Ctxt, "runtime.gcdata", 0) 339 340 s.Type = obj.SRODATA 341 s.Size = 0 342 s.Reachable = true 343 xdefine("runtime.egcdata", obj.SRODATA, 0) 344 345 s = Linklookup(Ctxt, "runtime.gcbss", 0) 346 s.Type = obj.SRODATA 347 s.Size = 0 348 s.Reachable = true 349 xdefine("runtime.egcbss", obj.SRODATA, 0) 350 351 // pseudo-symbols to mark locations of type, string, and go string data. 352 var symtype *LSym 353 var symtyperel *LSym 354 if UseRelro() && Buildmode == BuildmodeCShared { 355 s = Linklookup(Ctxt, "type.*", 0) 356 357 s.Type = obj.STYPE 358 s.Size = 0 359 s.Reachable = true 360 symtype = s 361 362 s = Linklookup(Ctxt, "typerel.*", 0) 363 364 s.Type = obj.STYPERELRO 365 s.Size = 0 366 s.Reachable = true 367 symtyperel = s 368 } else if !DynlinkingGo() { 369 s = Linklookup(Ctxt, "type.*", 0) 370 371 s.Type = obj.STYPE 372 s.Size = 0 373 s.Reachable = true 374 symtype = s 375 symtyperel = s 376 } 377 378 s = Linklookup(Ctxt, "go.string.*", 0) 379 s.Type = obj.SGOSTRING 380 s.Local = true 381 s.Size = 0 382 s.Reachable = true 383 symgostring := s 384 385 s = Linklookup(Ctxt, "go.func.*", 0) 386 s.Type = obj.SGOFUNC 387 s.Local = true 388 s.Size = 0 389 s.Reachable = true 390 symgofunc := s 391 392 s = Linklookup(Ctxt, "runtime.gcbits.*", 0) 393 s.Type = obj.SGCBITS 394 s.Local = true 395 s.Size = 0 396 s.Reachable = true 397 symgcbits := s 398 399 symtypelink := Linklookup(Ctxt, "runtime.typelink", 0) 400 symtypelink.Type = obj.STYPELINK 401 402 symt = Linklookup(Ctxt, "runtime.symtab", 0) 403 symt.Local = true 404 symt.Type = obj.SSYMTAB 405 symt.Size = 0 406 symt.Reachable = true 407 408 ntypelinks := 0 409 410 // assign specific types so that they sort together. 411 // within a type they sort by size, so the .* symbols 412 // just defined above will be first. 413 // hide the specific symbols. 414 for s := Ctxt.Allsym; s != nil; s = s.Allsym { 415 if !s.Reachable || s.Special != 0 || s.Type != obj.SRODATA { 416 continue 417 } 418 419 if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() { 420 s.Hide = 1 421 if UseRelro() && len(s.R) > 0 { 422 s.Type = obj.STYPERELRO 423 s.Outer = symtyperel 424 } else { 425 s.Type = obj.STYPE 426 s.Outer = symtype 427 } 428 } 429 430 if strings.HasPrefix(s.Name, "go.typelink.") { 431 ntypelinks++ 432 s.Type = obj.STYPELINK 433 s.Hide = 1 434 s.Outer = symtypelink 435 } 436 437 if strings.HasPrefix(s.Name, "go.string.") { 438 s.Type = obj.SGOSTRING 439 s.Hide = 1 440 s.Outer = symgostring 441 } 442 443 if strings.HasPrefix(s.Name, "runtime.gcbits.") { 444 s.Type = obj.SGCBITS 445 s.Hide = 1 446 s.Outer = symgcbits 447 } 448 449 if strings.HasPrefix(s.Name, "go.func.") { 450 s.Type = obj.SGOFUNC 451 s.Hide = 1 452 s.Outer = symgofunc 453 } 454 455 if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") { 456 s.Type = obj.SGOFUNC 457 s.Hide = 1 458 s.Outer = symgofunc 459 s.Align = 4 460 liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1) 461 } 462 } 463 464 if Buildmode == BuildmodeShared { 465 abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0) 466 abihashgostr.Reachable = true 467 abihashgostr.Type = obj.SRODATA 468 hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0) 469 Addaddr(Ctxt, abihashgostr, hashsym) 470 adduint(Ctxt, abihashgostr, uint64(hashsym.Size)) 471 } 472 473 // Information about the layout of the executable image for the 474 // runtime to use. Any changes here must be matched by changes to 475 // the definition of moduledata in runtime/symtab.go. 476 // This code uses several global variables that are set by pcln.go:pclntab. 477 moduledata := Ctxt.Moduledata 478 // The pclntab slice 479 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0)) 480 adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size)) 481 adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size)) 482 // The ftab slice 483 Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabPclntabOffset)) 484 adduint(Ctxt, moduledata, uint64(pclntabNfunc+1)) 485 adduint(Ctxt, moduledata, uint64(pclntabNfunc+1)) 486 // The filetab slice 487 Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset)) 488 adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)) 489 adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile)) 490 // findfunctab 491 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0)) 492 // minpc, maxpc 493 Addaddr(Ctxt, moduledata, pclntabFirstFunc) 494 Addaddrplus(Ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size) 495 // pointers to specific parts of the module 496 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.text", 0)) 497 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.etext", 0)) 498 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrdata", 0)) 499 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrdata", 0)) 500 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.data", 0)) 501 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.edata", 0)) 502 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.bss", 0)) 503 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.ebss", 0)) 504 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.noptrbss", 0)) 505 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.enoptrbss", 0)) 506 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.end", 0)) 507 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcdata", 0)) 508 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.gcbss", 0)) 509 // The typelinks slice 510 Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0)) 511 adduint(Ctxt, moduledata, uint64(ntypelinks)) 512 adduint(Ctxt, moduledata, uint64(ntypelinks)) 513 if len(Ctxt.Shlibs) > 0 { 514 thismodulename := filepath.Base(outfile) 515 if Buildmode == BuildmodeExe { 516 // When linking an executable, outfile is just "a.out". Make 517 // it something slightly more comprehensible. 518 thismodulename = "the executable" 519 } 520 addgostring(moduledata, "go.link.thismodulename", thismodulename) 521 522 modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0) 523 modulehashes.Reachable = true 524 modulehashes.Local = true 525 modulehashes.Type = obj.SRODATA 526 527 for i, shlib := range Ctxt.Shlibs { 528 // modulehashes[i].modulename 529 modulename := filepath.Base(shlib.Path) 530 addgostring(modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename) 531 532 // modulehashes[i].linktimehash 533 addgostring(modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash)) 534 535 // modulehashes[i].runtimehash 536 abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0) 537 abihash.Reachable = true 538 Addaddr(Ctxt, modulehashes, abihash) 539 } 540 541 Addaddr(Ctxt, moduledata, modulehashes) 542 adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs))) 543 adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs))) 544 } 545 // The rest of moduledata is zero initialized. 546 // When linking an object that does not contain the runtime we are 547 // creating the moduledata from scratch and it does not have a 548 // compiler-provided size, so read it from the type data. 549 moduledatatype := Linkrlookup(Ctxt, "type.runtime.moduledata", 0) 550 moduledata.Size = decodetype_size(moduledatatype) 551 Symgrow(Ctxt, moduledata, moduledata.Size) 552 553 lastmoduledatap := Linklookup(Ctxt, "runtime.lastmoduledatap", 0) 554 if lastmoduledatap.Type != obj.SDYNIMPORT { 555 lastmoduledatap.Type = obj.SNOPTRDATA 556 lastmoduledatap.Size = 0 // overwrite existing value 557 Addaddr(Ctxt, lastmoduledatap, moduledata) 558 } 559 }