github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/internal/obj/objfile.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Writing of Go object files. 6 // 7 // Originally, Go object files were Plan 9 object files, but no longer. 8 // Now they are more like standard object files, in that each symbol is defined 9 // by an associated memory image (bytes) and a list of relocations to apply 10 // during linking. We do not (yet?) use a standard file format, however. 11 // For now, the format is chosen to be as simple as possible to read and write. 12 // It may change for reasons of efficiency, or we may even switch to a 13 // standard file format if there are compelling benefits to doing so. 14 // See golang.org/s/go13linker for more background. 15 // 16 // The file format is: 17 // 18 // - magic header: "\x00\x00go13ld" 19 // - byte 1 - version number 20 // - sequence of strings giving dependencies (imported packages) 21 // - empty string (marks end of sequence) 22 // - sequence of symbol references used by the defined symbols 23 // - byte 0xff (marks end of sequence) 24 // - sequence of integer lengths: 25 // - total data length 26 // - total number of relocations 27 // - total number of pcdata 28 // - total number of automatics 29 // - total number of funcdata 30 // - total number of files 31 // - data, the content of the defined symbols 32 // - sequence of defined symbols 33 // - byte 0xff (marks end of sequence) 34 // - magic footer: "\xff\xffgo13ld" 35 // 36 // All integers are stored in a zigzag varint format. 37 // See golang.org/s/go12symtab for a definition. 38 // 39 // Data blocks and strings are both stored as an integer 40 // followed by that many bytes. 41 // 42 // A symbol reference is a string name followed by a version. 43 // 44 // A symbol points to other symbols using an index into the symbol 45 // reference sequence. Index 0 corresponds to a nil LSym* pointer. 46 // In the symbol layout described below "symref index" stands for this 47 // index. 48 // 49 // Each symbol is laid out as the following fields (taken from LSym*): 50 // 51 // - byte 0xfe (sanity check for synchronization) 52 // - type [int] 53 // - name & version [symref index] 54 // - flags [int] 55 // 1 dupok 56 // - size [int] 57 // - gotype [symref index] 58 // - p [data block] 59 // - nr [int] 60 // - r [nr relocations, sorted by off] 61 // 62 // If type == STEXT, there are a few more fields: 63 // 64 // - args [int] 65 // - locals [int] 66 // - nosplit [int] 67 // - flags [int] 68 // 1<<0 leaf 69 // 1<<1 C function 70 // 1<<2 function may call reflect.Type.Method 71 // - nlocal [int] 72 // - local [nlocal automatics] 73 // - pcln [pcln table] 74 // 75 // Each relocation has the encoding: 76 // 77 // - off [int] 78 // - siz [int] 79 // - type [int] 80 // - add [int] 81 // - sym [symref index] 82 // 83 // Each local has the encoding: 84 // 85 // - asym [symref index] 86 // - offset [int] 87 // - type [int] 88 // - gotype [symref index] 89 // 90 // The pcln table has the encoding: 91 // 92 // - pcsp [data block] 93 // - pcfile [data block] 94 // - pcline [data block] 95 // - npcdata [int] 96 // - pcdata [npcdata data blocks] 97 // - nfuncdata [int] 98 // - funcdata [nfuncdata symref index] 99 // - funcdatasym [nfuncdata ints] 100 // - nfile [int] 101 // - file [nfile symref index] 102 // 103 // The file layout and meaning of type integers are architecture-independent. 104 // 105 // TODO(rsc): The file format is good for a first pass but needs work. 106 // - There are SymID in the object file that should really just be strings. 107 108 package obj 109 110 import ( 111 "bufio" 112 "fmt" 113 "log" 114 "path/filepath" 115 "sort" 116 "strings" 117 ) 118 119 // The Go and C compilers, and the assembler, call writeobj to write 120 // out a Go object file. The linker does not call this; the linker 121 // does not write out object files. 122 func Writeobjdirect(ctxt *Link, b *Biobuf) { 123 Flushplist(ctxt) 124 WriteObjFile(ctxt, b) 125 } 126 127 func Flushplist(ctxt *Link) { 128 flushplist(ctxt, ctxt.Debugasm == 0) 129 } 130 func FlushplistNoFree(ctxt *Link) { 131 flushplist(ctxt, false) 132 } 133 func flushplist(ctxt *Link, freeProgs bool) { 134 // Build list of symbols, and assign instructions to lists. 135 // Ignore ctxt->plist boundaries. There are no guarantees there, 136 // and the assemblers just use one big list. 137 var curtext *LSym 138 var etext *Prog 139 var text []*LSym 140 141 for pl := ctxt.Plist; pl != nil; pl = pl.Link { 142 var plink *Prog 143 for p := pl.Firstpc; p != nil; p = plink { 144 if ctxt.Debugasm != 0 && ctxt.Debugvlog != 0 { 145 fmt.Printf("obj: %v\n", p) 146 } 147 plink = p.Link 148 p.Link = nil 149 150 switch p.As { 151 case AEND: 152 continue 153 154 case ATYPE: 155 // Assume each TYPE instruction describes 156 // a different local variable or parameter, 157 // so no dedup. 158 // Using only the TYPE instructions means 159 // that we discard location information about local variables 160 // in C and assembly functions; that information is inferred 161 // from ordinary references, because there are no TYPE 162 // instructions there. Without the type information, gdb can't 163 // use the locations, so we don't bother to save them. 164 // If something else could use them, we could arrange to 165 // preserve them. 166 if curtext == nil { 167 continue 168 } 169 a := new(Auto) 170 a.Asym = p.From.Sym 171 a.Aoffset = int32(p.From.Offset) 172 a.Name = int16(p.From.Name) 173 a.Gotype = p.From.Gotype 174 a.Link = curtext.Autom 175 curtext.Autom = a 176 continue 177 178 case AGLOBL: 179 s := p.From.Sym 180 if s.Seenglobl { 181 fmt.Printf("duplicate %v\n", p) 182 } 183 s.Seenglobl = true 184 if s.Onlist { 185 log.Fatalf("symbol %s listed multiple times", s.Name) 186 } 187 s.Onlist = true 188 ctxt.Data = append(ctxt.Data, s) 189 s.Size = p.To.Offset 190 if s.Type == 0 || s.Type == SXREF { 191 s.Type = SBSS 192 } 193 flag := int(p.From3.Offset) 194 if flag&DUPOK != 0 { 195 s.Dupok = true 196 } 197 if flag&RODATA != 0 { 198 s.Type = SRODATA 199 } else if flag&NOPTR != 0 { 200 s.Type = SNOPTRBSS 201 } else if flag&TLSBSS != 0 { 202 s.Type = STLSBSS 203 } 204 continue 205 206 case ATEXT: 207 s := p.From.Sym 208 if s == nil { 209 // func _() { } 210 curtext = nil 211 212 continue 213 } 214 215 if s.Text != nil { 216 log.Fatalf("duplicate TEXT for %s", s.Name) 217 } 218 if s.Onlist { 219 log.Fatalf("symbol %s listed multiple times", s.Name) 220 } 221 s.Onlist = true 222 text = append(text, s) 223 flag := int(p.From3Offset()) 224 if flag&DUPOK != 0 { 225 s.Dupok = true 226 } 227 if flag&NOSPLIT != 0 { 228 s.Nosplit = true 229 } 230 if flag&REFLECTMETHOD != 0 { 231 s.ReflectMethod = true 232 } 233 s.Type = STEXT 234 s.Text = p 235 etext = p 236 curtext = s 237 continue 238 239 case AFUNCDATA: 240 // Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information. 241 if curtext == nil { // func _() {} 242 continue 243 } 244 if p.To.Sym.Name == "go_args_stackmap" { 245 if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps { 246 ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps") 247 } 248 p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version)) 249 } 250 251 } 252 253 if curtext == nil { 254 etext = nil 255 continue 256 } 257 etext.Link = p 258 etext = p 259 } 260 } 261 262 // Add reference to Go arguments for C or assembly functions without them. 263 for _, s := range text { 264 if !strings.HasPrefix(s.Name, "\"\".") { 265 continue 266 } 267 found := false 268 var p *Prog 269 for p = s.Text; p != nil; p = p.Link { 270 if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps { 271 found = true 272 break 273 } 274 } 275 276 if !found { 277 p = Appendp(ctxt, s.Text) 278 p.As = AFUNCDATA 279 p.From.Type = TYPE_CONST 280 p.From.Offset = FUNCDATA_ArgsPointerMaps 281 p.To.Type = TYPE_MEM 282 p.To.Name = NAME_EXTERN 283 p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version)) 284 } 285 } 286 287 // Turn functions into machine code images. 288 for _, s := range text { 289 mkfwd(s) 290 linkpatch(ctxt, s) 291 if ctxt.Flag_optimize { 292 ctxt.Arch.Follow(ctxt, s) 293 } 294 ctxt.Arch.Preprocess(ctxt, s) 295 ctxt.Arch.Assemble(ctxt, s) 296 fieldtrack(ctxt, s) 297 linkpcln(ctxt, s) 298 if freeProgs { 299 s.Text = nil 300 } 301 } 302 303 // Add to running list in ctxt. 304 ctxt.Text = append(ctxt.Text, text...) 305 ctxt.Plist = nil 306 ctxt.Plast = nil 307 ctxt.Curp = nil 308 if freeProgs { 309 ctxt.freeProgs() 310 } 311 } 312 313 // objWriter writes Go object files. 314 type objWriter struct { 315 wr *bufio.Writer 316 ctxt *Link 317 // Temporary buffer for zigzag int writing. 318 varintbuf [10]uint8 319 320 // Provide the the index of a symbol reference by symbol name. 321 // One map for versioned symbols and one for unversioned symbols. 322 // Used for deduplicating the symbol reference list. 323 refIdx map[string]int 324 vrefIdx map[string]int 325 326 // Number of objects written of each type. 327 nRefs int 328 nData int 329 nReloc int 330 nPcdata int 331 nAutom int 332 nFuncdata int 333 nFile int 334 } 335 336 func (w *objWriter) addLengths(s *LSym) { 337 w.nData += len(s.P) 338 w.nReloc += len(s.R) 339 340 if s.Type != STEXT { 341 return 342 } 343 344 pc := s.Pcln 345 346 data := 0 347 data += len(pc.Pcsp.P) 348 data += len(pc.Pcfile.P) 349 data += len(pc.Pcline.P) 350 for i := 0; i < len(pc.Pcdata); i++ { 351 data += len(pc.Pcdata[i].P) 352 } 353 354 w.nData += data 355 w.nPcdata += len(pc.Pcdata) 356 357 autom := 0 358 for a := s.Autom; a != nil; a = a.Link { 359 autom++ 360 } 361 w.nAutom += autom 362 w.nFuncdata += len(pc.Funcdataoff) 363 w.nFile += len(pc.File) 364 } 365 366 func (w *objWriter) writeLengths() { 367 w.writeInt(int64(w.nData)) 368 w.writeInt(int64(w.nReloc)) 369 w.writeInt(int64(w.nPcdata)) 370 w.writeInt(int64(w.nAutom)) 371 w.writeInt(int64(w.nFuncdata)) 372 w.writeInt(int64(w.nFile)) 373 } 374 375 func newObjWriter(ctxt *Link, b *Biobuf) *objWriter { 376 return &objWriter{ 377 ctxt: ctxt, 378 wr: b.w, 379 vrefIdx: make(map[string]int), 380 refIdx: make(map[string]int), 381 } 382 } 383 384 func WriteObjFile(ctxt *Link, b *Biobuf) { 385 w := newObjWriter(ctxt, b) 386 387 // Magic header 388 w.wr.WriteString("\x00\x00go13ld") 389 390 // Version 391 w.wr.WriteByte(1) 392 393 // Autolib 394 for _, pkg := range ctxt.Imports { 395 w.writeString(pkg) 396 } 397 w.writeString("") 398 399 // Symbol references 400 for _, s := range ctxt.Text { 401 w.writeRefs(s) 402 w.addLengths(s) 403 } 404 for _, s := range ctxt.Data { 405 w.writeRefs(s) 406 w.addLengths(s) 407 } 408 // End symbol references 409 w.wr.WriteByte(0xff) 410 411 // Lengths 412 w.writeLengths() 413 414 // Data block 415 for _, s := range ctxt.Text { 416 w.wr.Write(s.P) 417 pc := s.Pcln 418 w.wr.Write(pc.Pcsp.P) 419 w.wr.Write(pc.Pcfile.P) 420 w.wr.Write(pc.Pcline.P) 421 for i := 0; i < len(pc.Pcdata); i++ { 422 w.wr.Write(pc.Pcdata[i].P) 423 } 424 } 425 for _, s := range ctxt.Data { 426 w.wr.Write(s.P) 427 } 428 429 // Symbols 430 for _, s := range ctxt.Text { 431 w.writeSym(s) 432 } 433 for _, s := range ctxt.Data { 434 w.writeSym(s) 435 } 436 437 // Magic footer 438 w.wr.WriteString("\xff\xffgo13ld") 439 } 440 441 // Symbols are prefixed so their content doesn't get confused with the magic footer. 442 const symPrefix = 0xfe 443 444 func (w *objWriter) writeRef(s *LSym, isPath bool) { 445 if s == nil || s.RefIdx != 0 { 446 return 447 } 448 var m map[string]int 449 switch s.Version { 450 case 0: 451 m = w.refIdx 452 case 1: 453 m = w.vrefIdx 454 default: 455 log.Fatalf("%s: invalid version number %d", s.Name, s.Version) 456 } 457 458 idx := m[s.Name] 459 if idx != 0 { 460 s.RefIdx = idx 461 return 462 } 463 w.wr.WriteByte(symPrefix) 464 if isPath { 465 w.writeString(filepath.ToSlash(s.Name)) 466 } else { 467 w.writeString(s.Name) 468 } 469 w.writeInt(int64(s.Version)) 470 w.nRefs++ 471 s.RefIdx = w.nRefs 472 m[s.Name] = w.nRefs 473 } 474 475 func (w *objWriter) writeRefs(s *LSym) { 476 w.writeRef(s, false) 477 w.writeRef(s.Gotype, false) 478 for i := range s.R { 479 w.writeRef(s.R[i].Sym, false) 480 } 481 482 if s.Type == STEXT { 483 for a := s.Autom; a != nil; a = a.Link { 484 w.writeRef(a.Asym, false) 485 w.writeRef(a.Gotype, false) 486 } 487 pc := s.Pcln 488 for _, d := range pc.Funcdata { 489 w.writeRef(d, false) 490 } 491 for _, f := range pc.File { 492 w.writeRef(f, true) 493 } 494 } 495 } 496 497 func (w *objWriter) writeSymDebug(s *LSym) { 498 ctxt := w.ctxt 499 fmt.Fprintf(ctxt.Bso, "%s ", s.Name) 500 if s.Version != 0 { 501 fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version) 502 } 503 if s.Type != 0 { 504 fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type) 505 } 506 if s.Dupok { 507 fmt.Fprintf(ctxt.Bso, "dupok ") 508 } 509 if s.Cfunc { 510 fmt.Fprintf(ctxt.Bso, "cfunc ") 511 } 512 if s.Nosplit { 513 fmt.Fprintf(ctxt.Bso, "nosplit ") 514 } 515 fmt.Fprintf(ctxt.Bso, "size=%d", s.Size) 516 if s.Type == STEXT { 517 fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals)) 518 if s.Leaf { 519 fmt.Fprintf(ctxt.Bso, " leaf") 520 } 521 } 522 523 fmt.Fprintf(ctxt.Bso, "\n") 524 for p := s.Text; p != nil; p = p.Link { 525 fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), p) 526 } 527 var c int 528 var j int 529 for i := 0; i < len(s.P); { 530 fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i)) 531 for j = i; j < i+16 && j < len(s.P); j++ { 532 fmt.Fprintf(ctxt.Bso, " %02x", s.P[j]) 533 } 534 for ; j < i+16; j++ { 535 fmt.Fprintf(ctxt.Bso, " ") 536 } 537 fmt.Fprintf(ctxt.Bso, " ") 538 for j = i; j < i+16 && j < len(s.P); j++ { 539 c = int(s.P[j]) 540 if ' ' <= c && c <= 0x7e { 541 fmt.Fprintf(ctxt.Bso, "%c", c) 542 } else { 543 fmt.Fprintf(ctxt.Bso, ".") 544 } 545 } 546 547 fmt.Fprintf(ctxt.Bso, "\n") 548 i += 16 549 } 550 551 sort.Sort(relocByOff(s.R)) // generate stable output 552 for _, r := range s.R { 553 name := "" 554 if r.Sym != nil { 555 name = r.Sym.Name 556 } 557 if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' { 558 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add))) 559 } else { 560 fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add)) 561 } 562 } 563 } 564 565 func (w *objWriter) writeSym(s *LSym) { 566 ctxt := w.ctxt 567 if ctxt.Debugasm != 0 { 568 w.writeSymDebug(s) 569 } 570 571 w.wr.WriteByte(symPrefix) 572 w.writeInt(int64(s.Type)) 573 w.writeRefIndex(s) 574 flags := int64(0) 575 if s.Dupok { 576 flags |= 1 577 } 578 if s.Local { 579 flags |= 1 << 1 580 } 581 w.writeInt(flags) 582 w.writeInt(s.Size) 583 w.writeRefIndex(s.Gotype) 584 w.writeInt(int64(len(s.P))) 585 586 w.writeInt(int64(len(s.R))) 587 var r *Reloc 588 for i := 0; i < len(s.R); i++ { 589 r = &s.R[i] 590 w.writeInt(int64(r.Off)) 591 w.writeInt(int64(r.Siz)) 592 w.writeInt(int64(r.Type)) 593 w.writeInt(r.Add) 594 w.writeRefIndex(r.Sym) 595 } 596 597 if s.Type != STEXT { 598 return 599 } 600 601 w.writeInt(int64(s.Args)) 602 w.writeInt(int64(s.Locals)) 603 if s.Nosplit { 604 w.writeInt(1) 605 } else { 606 w.writeInt(0) 607 } 608 flags = int64(0) 609 if s.Leaf { 610 flags |= 1 611 } 612 if s.Cfunc { 613 flags |= 1 << 1 614 } 615 if s.ReflectMethod { 616 flags |= 1 << 2 617 } 618 w.writeInt(flags) 619 n := 0 620 for a := s.Autom; a != nil; a = a.Link { 621 n++ 622 } 623 w.writeInt(int64(n)) 624 for a := s.Autom; a != nil; a = a.Link { 625 w.writeRefIndex(a.Asym) 626 w.writeInt(int64(a.Aoffset)) 627 if a.Name == NAME_AUTO { 628 w.writeInt(A_AUTO) 629 } else if a.Name == NAME_PARAM { 630 w.writeInt(A_PARAM) 631 } else { 632 log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name) 633 } 634 w.writeRefIndex(a.Gotype) 635 } 636 637 pc := s.Pcln 638 w.writeInt(int64(len(pc.Pcsp.P))) 639 w.writeInt(int64(len(pc.Pcfile.P))) 640 w.writeInt(int64(len(pc.Pcline.P))) 641 w.writeInt(int64(len(pc.Pcdata))) 642 for i := 0; i < len(pc.Pcdata); i++ { 643 w.writeInt(int64(len(pc.Pcdata[i].P))) 644 } 645 w.writeInt(int64(len(pc.Funcdataoff))) 646 for i := 0; i < len(pc.Funcdataoff); i++ { 647 w.writeRefIndex(pc.Funcdata[i]) 648 } 649 for i := 0; i < len(pc.Funcdataoff); i++ { 650 w.writeInt(pc.Funcdataoff[i]) 651 } 652 w.writeInt(int64(len(pc.File))) 653 for _, f := range pc.File { 654 w.writeRefIndex(f) 655 } 656 } 657 658 func (w *objWriter) writeInt(sval int64) { 659 var v uint64 660 uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63)) 661 p := w.varintbuf[:] 662 for v = uv; v >= 0x80; v >>= 7 { 663 p[0] = uint8(v | 0x80) 664 p = p[1:] 665 } 666 p[0] = uint8(v) 667 p = p[1:] 668 w.wr.Write(w.varintbuf[:len(w.varintbuf)-len(p)]) 669 } 670 671 func (w *objWriter) writeString(s string) { 672 w.writeInt(int64(len(s))) 673 w.wr.WriteString(s) 674 } 675 676 func (w *objWriter) writeRefIndex(s *LSym) { 677 if s == nil { 678 w.writeInt(0) 679 return 680 } 681 if s.RefIdx == 0 { 682 log.Fatalln("writing an unreferenced symbol", s.Name) 683 } 684 w.writeInt(int64(s.RefIdx)) 685 } 686 687 // relocByOff sorts relocations by their offsets. 688 type relocByOff []Reloc 689 690 func (x relocByOff) Len() int { return len(x) } 691 func (x relocByOff) Less(i, j int) bool { return x[i].Off < x[j].Off } 692 func (x relocByOff) Swap(i, j int) { x[i], x[j] = x[j], x[i] }