objfile.go (23541B)
1 // Copyright 2019 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 // This package defines the Go object file format, and provide "low-level" functions 6 // for reading and writing object files. 7 8 // The object file is understood by the compiler, assembler, linker, and tools. They 9 // have "high level" code that operates on object files, handling application-specific 10 // logics, and use this package for the actual reading and writing. Specifically, the 11 // code below: 12 // 13 // - cmd/internal/obj/objfile.go (used by cmd/asm and cmd/compile) 14 // - cmd/internal/objfile/goobj.go (used cmd/nm, cmd/objdump) 15 // - cmd/link/internal/loader package (used by cmd/link) 16 // 17 // If the object file format changes, they may (or may not) need to change. 18 19 package goobj 20 21 import ( 22 "bytes" 23 "github.com/twitchyliquid64/golang-asm/bio" 24 "crypto/sha1" 25 "encoding/binary" 26 "errors" 27 "fmt" 28 "github.com/twitchyliquid64/golang-asm/unsafeheader" 29 "io" 30 "unsafe" 31 ) 32 33 // New object file format. 34 // 35 // Header struct { 36 // Magic [...]byte // "\x00go116ld" 37 // Fingerprint [8]byte 38 // Flags uint32 39 // Offsets [...]uint32 // byte offset of each block below 40 // } 41 // 42 // Strings [...]struct { 43 // Data [...]byte 44 // } 45 // 46 // Autolib [...]struct { // imported packages (for file loading) 47 // Pkg string 48 // Fingerprint [8]byte 49 // } 50 // 51 // PkgIndex [...]string // referenced packages by index 52 // 53 // Files [...]string 54 // 55 // SymbolDefs [...]struct { 56 // Name string 57 // ABI uint16 58 // Type uint8 59 // Flag uint8 60 // Flag2 uint8 61 // Size uint32 62 // } 63 // Hashed64Defs [...]struct { // short hashed (content-addressable) symbol definitions 64 // ... // same as SymbolDefs 65 // } 66 // HashedDefs [...]struct { // hashed (content-addressable) symbol definitions 67 // ... // same as SymbolDefs 68 // } 69 // NonPkgDefs [...]struct { // non-pkg symbol definitions 70 // ... // same as SymbolDefs 71 // } 72 // NonPkgRefs [...]struct { // non-pkg symbol references 73 // ... // same as SymbolDefs 74 // } 75 // 76 // RefFlags [...]struct { // referenced symbol flags 77 // Sym symRef 78 // Flag uint8 79 // Flag2 uint8 80 // } 81 // 82 // Hash64 [...][8]byte 83 // Hash [...][N]byte 84 // 85 // RelocIndex [...]uint32 // index to Relocs 86 // AuxIndex [...]uint32 // index to Aux 87 // DataIndex [...]uint32 // offset to Data 88 // 89 // Relocs [...]struct { 90 // Off int32 91 // Size uint8 92 // Type uint8 93 // Add int64 94 // Sym symRef 95 // } 96 // 97 // Aux [...]struct { 98 // Type uint8 99 // Sym symRef 100 // } 101 // 102 // Data [...]byte 103 // Pcdata [...]byte 104 // 105 // // blocks only used by tools (objdump, nm) 106 // 107 // RefNames [...]struct { // referenced symbol names 108 // Sym symRef 109 // Name string 110 // // TODO: include ABI version as well? 111 // } 112 // 113 // string is encoded as is a uint32 length followed by a uint32 offset 114 // that points to the corresponding string bytes. 115 // 116 // symRef is struct { PkgIdx, SymIdx uint32 }. 117 // 118 // Slice type (e.g. []symRef) is encoded as a length prefix (uint32) 119 // followed by that number of elements. 120 // 121 // The types below correspond to the encoded data structure in the 122 // object file. 123 124 // Symbol indexing. 125 // 126 // Each symbol is referenced with a pair of indices, { PkgIdx, SymIdx }, 127 // as the symRef struct above. 128 // 129 // PkgIdx is either a predeclared index (see PkgIdxNone below) or 130 // an index of an imported package. For the latter case, PkgIdx is the 131 // index of the package in the PkgIndex array. 0 is an invalid index. 132 // 133 // SymIdx is the index of the symbol in the given package. 134 // - If PkgIdx is PkgIdxSelf, SymIdx is the index of the symbol in the 135 // SymbolDefs array. 136 // - If PkgIdx is PkgIdxHashed64, SymIdx is the index of the symbol in the 137 // Hashed64Defs array. 138 // - If PkgIdx is PkgIdxHashed, SymIdx is the index of the symbol in the 139 // HashedDefs array. 140 // - If PkgIdx is PkgIdxNone, SymIdx is the index of the symbol in the 141 // NonPkgDefs array (could natually overflow to NonPkgRefs array). 142 // - Otherwise, SymIdx is the index of the symbol in some other package's 143 // SymbolDefs array. 144 // 145 // {0, 0} represents a nil symbol. Otherwise PkgIdx should not be 0. 146 // 147 // Hash contains the content hashes of content-addressable symbols, of 148 // which PkgIdx is PkgIdxHashed, in the same order of HashedDefs array. 149 // Hash64 is similar, for PkgIdxHashed64 symbols. 150 // 151 // RelocIndex, AuxIndex, and DataIndex contains indices/offsets to 152 // Relocs/Aux/Data blocks, one element per symbol, first for all the 153 // defined symbols, then all the defined hashed and non-package symbols, 154 // in the same order of SymbolDefs/Hashed64Defs/HashedDefs/NonPkgDefs 155 // arrays. For N total defined symbols, the array is of length N+1. The 156 // last element is the total number of relocations (aux symbols, data 157 // blocks, etc.). 158 // 159 // They can be accessed by index. For the i-th symbol, its relocations 160 // are the RelocIndex[i]-th (inclusive) to RelocIndex[i+1]-th (exclusive) 161 // elements in the Relocs array. Aux/Data are likewise. (The index is 162 // 0-based.) 163 164 // Auxiliary symbols. 165 // 166 // Each symbol may (or may not) be associated with a number of auxiliary 167 // symbols. They are described in the Aux block. See Aux struct below. 168 // Currently a symbol's Gotype, FuncInfo, and associated DWARF symbols 169 // are auxiliary symbols. 170 171 const stringRefSize = 8 // two uint32s 172 173 type FingerprintType [8]byte 174 175 func (fp FingerprintType) IsZero() bool { return fp == FingerprintType{} } 176 177 // Package Index. 178 const ( 179 PkgIdxNone = (1<<31 - 1) - iota // Non-package symbols 180 PkgIdxHashed64 // Short hashed (content-addressable) symbols 181 PkgIdxHashed // Hashed (content-addressable) symbols 182 PkgIdxBuiltin // Predefined runtime symbols (ex: runtime.newobject) 183 PkgIdxSelf // Symbols defined in the current package 184 PkgIdxInvalid = 0 185 // The index of other referenced packages starts from 1. 186 ) 187 188 // Blocks 189 const ( 190 BlkAutolib = iota 191 BlkPkgIdx 192 BlkFile 193 BlkSymdef 194 BlkHashed64def 195 BlkHasheddef 196 BlkNonpkgdef 197 BlkNonpkgref 198 BlkRefFlags 199 BlkHash64 200 BlkHash 201 BlkRelocIdx 202 BlkAuxIdx 203 BlkDataIdx 204 BlkReloc 205 BlkAux 206 BlkData 207 BlkPcdata 208 BlkRefName 209 BlkEnd 210 NBlk 211 ) 212 213 // File header. 214 // TODO: probably no need to export this. 215 type Header struct { 216 Magic string 217 Fingerprint FingerprintType 218 Flags uint32 219 Offsets [NBlk]uint32 220 } 221 222 const Magic = "\x00go116ld" 223 224 func (h *Header) Write(w *Writer) { 225 w.RawString(h.Magic) 226 w.Bytes(h.Fingerprint[:]) 227 w.Uint32(h.Flags) 228 for _, x := range h.Offsets { 229 w.Uint32(x) 230 } 231 } 232 233 func (h *Header) Read(r *Reader) error { 234 b := r.BytesAt(0, len(Magic)) 235 h.Magic = string(b) 236 if h.Magic != Magic { 237 return errors.New("wrong magic, not a Go object file") 238 } 239 off := uint32(len(h.Magic)) 240 copy(h.Fingerprint[:], r.BytesAt(off, len(h.Fingerprint))) 241 off += 8 242 h.Flags = r.uint32At(off) 243 off += 4 244 for i := range h.Offsets { 245 h.Offsets[i] = r.uint32At(off) 246 off += 4 247 } 248 return nil 249 } 250 251 func (h *Header) Size() int { 252 return len(h.Magic) + 4 + 4*len(h.Offsets) 253 } 254 255 // Autolib 256 type ImportedPkg struct { 257 Pkg string 258 Fingerprint FingerprintType 259 } 260 261 const importedPkgSize = stringRefSize + 8 262 263 func (p *ImportedPkg) Write(w *Writer) { 264 w.StringRef(p.Pkg) 265 w.Bytes(p.Fingerprint[:]) 266 } 267 268 // Symbol definition. 269 // 270 // Serialized format: 271 // Sym struct { 272 // Name string 273 // ABI uint16 274 // Type uint8 275 // Flag uint8 276 // Flag2 uint8 277 // Siz uint32 278 // Align uint32 279 // } 280 type Sym [SymSize]byte 281 282 const SymSize = stringRefSize + 2 + 1 + 1 + 1 + 4 + 4 283 284 const SymABIstatic = ^uint16(0) 285 286 const ( 287 ObjFlagShared = 1 << iota // this object is built with -shared 288 ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names 289 ObjFlagFromAssembly // object is from asm src, not go 290 ) 291 292 // Sym.Flag 293 const ( 294 SymFlagDupok = 1 << iota 295 SymFlagLocal 296 SymFlagTypelink 297 SymFlagLeaf 298 SymFlagNoSplit 299 SymFlagReflectMethod 300 SymFlagGoType 301 SymFlagTopFrame 302 ) 303 304 // Sym.Flag2 305 const ( 306 SymFlagUsedInIface = 1 << iota 307 SymFlagItab 308 ) 309 310 // Returns the length of the name of the symbol. 311 func (s *Sym) NameLen(r *Reader) int { 312 return int(binary.LittleEndian.Uint32(s[:])) 313 } 314 315 func (s *Sym) Name(r *Reader) string { 316 len := binary.LittleEndian.Uint32(s[:]) 317 off := binary.LittleEndian.Uint32(s[4:]) 318 return r.StringAt(off, len) 319 } 320 321 func (s *Sym) ABI() uint16 { return binary.LittleEndian.Uint16(s[8:]) } 322 func (s *Sym) Type() uint8 { return s[10] } 323 func (s *Sym) Flag() uint8 { return s[11] } 324 func (s *Sym) Flag2() uint8 { return s[12] } 325 func (s *Sym) Siz() uint32 { return binary.LittleEndian.Uint32(s[13:]) } 326 func (s *Sym) Align() uint32 { return binary.LittleEndian.Uint32(s[17:]) } 327 328 func (s *Sym) Dupok() bool { return s.Flag()&SymFlagDupok != 0 } 329 func (s *Sym) Local() bool { return s.Flag()&SymFlagLocal != 0 } 330 func (s *Sym) Typelink() bool { return s.Flag()&SymFlagTypelink != 0 } 331 func (s *Sym) Leaf() bool { return s.Flag()&SymFlagLeaf != 0 } 332 func (s *Sym) NoSplit() bool { return s.Flag()&SymFlagNoSplit != 0 } 333 func (s *Sym) ReflectMethod() bool { return s.Flag()&SymFlagReflectMethod != 0 } 334 func (s *Sym) IsGoType() bool { return s.Flag()&SymFlagGoType != 0 } 335 func (s *Sym) TopFrame() bool { return s.Flag()&SymFlagTopFrame != 0 } 336 func (s *Sym) UsedInIface() bool { return s.Flag2()&SymFlagUsedInIface != 0 } 337 func (s *Sym) IsItab() bool { return s.Flag2()&SymFlagItab != 0 } 338 339 func (s *Sym) SetName(x string, w *Writer) { 340 binary.LittleEndian.PutUint32(s[:], uint32(len(x))) 341 binary.LittleEndian.PutUint32(s[4:], w.stringOff(x)) 342 } 343 344 func (s *Sym) SetABI(x uint16) { binary.LittleEndian.PutUint16(s[8:], x) } 345 func (s *Sym) SetType(x uint8) { s[10] = x } 346 func (s *Sym) SetFlag(x uint8) { s[11] = x } 347 func (s *Sym) SetFlag2(x uint8) { s[12] = x } 348 func (s *Sym) SetSiz(x uint32) { binary.LittleEndian.PutUint32(s[13:], x) } 349 func (s *Sym) SetAlign(x uint32) { binary.LittleEndian.PutUint32(s[17:], x) } 350 351 func (s *Sym) Write(w *Writer) { w.Bytes(s[:]) } 352 353 // for testing 354 func (s *Sym) fromBytes(b []byte) { copy(s[:], b) } 355 356 // Symbol reference. 357 type SymRef struct { 358 PkgIdx uint32 359 SymIdx uint32 360 } 361 362 // Hash64 363 type Hash64Type [Hash64Size]byte 364 365 const Hash64Size = 8 366 367 // Hash 368 type HashType [HashSize]byte 369 370 const HashSize = sha1.Size 371 372 // Relocation. 373 // 374 // Serialized format: 375 // Reloc struct { 376 // Off int32 377 // Siz uint8 378 // Type uint8 379 // Add int64 380 // Sym SymRef 381 // } 382 type Reloc [RelocSize]byte 383 384 const RelocSize = 4 + 1 + 1 + 8 + 8 385 386 func (r *Reloc) Off() int32 { return int32(binary.LittleEndian.Uint32(r[:])) } 387 func (r *Reloc) Siz() uint8 { return r[4] } 388 func (r *Reloc) Type() uint8 { return r[5] } 389 func (r *Reloc) Add() int64 { return int64(binary.LittleEndian.Uint64(r[6:])) } 390 func (r *Reloc) Sym() SymRef { 391 return SymRef{binary.LittleEndian.Uint32(r[14:]), binary.LittleEndian.Uint32(r[18:])} 392 } 393 394 func (r *Reloc) SetOff(x int32) { binary.LittleEndian.PutUint32(r[:], uint32(x)) } 395 func (r *Reloc) SetSiz(x uint8) { r[4] = x } 396 func (r *Reloc) SetType(x uint8) { r[5] = x } 397 func (r *Reloc) SetAdd(x int64) { binary.LittleEndian.PutUint64(r[6:], uint64(x)) } 398 func (r *Reloc) SetSym(x SymRef) { 399 binary.LittleEndian.PutUint32(r[14:], x.PkgIdx) 400 binary.LittleEndian.PutUint32(r[18:], x.SymIdx) 401 } 402 403 func (r *Reloc) Set(off int32, size uint8, typ uint8, add int64, sym SymRef) { 404 r.SetOff(off) 405 r.SetSiz(size) 406 r.SetType(typ) 407 r.SetAdd(add) 408 r.SetSym(sym) 409 } 410 411 func (r *Reloc) Write(w *Writer) { w.Bytes(r[:]) } 412 413 // for testing 414 func (r *Reloc) fromBytes(b []byte) { copy(r[:], b) } 415 416 // Aux symbol info. 417 // 418 // Serialized format: 419 // Aux struct { 420 // Type uint8 421 // Sym SymRef 422 // } 423 type Aux [AuxSize]byte 424 425 const AuxSize = 1 + 8 426 427 // Aux Type 428 const ( 429 AuxGotype = iota 430 AuxFuncInfo 431 AuxFuncdata 432 AuxDwarfInfo 433 AuxDwarfLoc 434 AuxDwarfRanges 435 AuxDwarfLines 436 437 // TODO: more. Pcdata? 438 ) 439 440 func (a *Aux) Type() uint8 { return a[0] } 441 func (a *Aux) Sym() SymRef { 442 return SymRef{binary.LittleEndian.Uint32(a[1:]), binary.LittleEndian.Uint32(a[5:])} 443 } 444 445 func (a *Aux) SetType(x uint8) { a[0] = x } 446 func (a *Aux) SetSym(x SymRef) { 447 binary.LittleEndian.PutUint32(a[1:], x.PkgIdx) 448 binary.LittleEndian.PutUint32(a[5:], x.SymIdx) 449 } 450 451 func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) } 452 453 // for testing 454 func (a *Aux) fromBytes(b []byte) { copy(a[:], b) } 455 456 // Referenced symbol flags. 457 // 458 // Serialized format: 459 // RefFlags struct { 460 // Sym symRef 461 // Flag uint8 462 // Flag2 uint8 463 // } 464 type RefFlags [RefFlagsSize]byte 465 466 const RefFlagsSize = 8 + 1 + 1 467 468 func (r *RefFlags) Sym() SymRef { 469 return SymRef{binary.LittleEndian.Uint32(r[:]), binary.LittleEndian.Uint32(r[4:])} 470 } 471 func (r *RefFlags) Flag() uint8 { return r[8] } 472 func (r *RefFlags) Flag2() uint8 { return r[9] } 473 474 func (r *RefFlags) SetSym(x SymRef) { 475 binary.LittleEndian.PutUint32(r[:], x.PkgIdx) 476 binary.LittleEndian.PutUint32(r[4:], x.SymIdx) 477 } 478 func (r *RefFlags) SetFlag(x uint8) { r[8] = x } 479 func (r *RefFlags) SetFlag2(x uint8) { r[9] = x } 480 481 func (r *RefFlags) Write(w *Writer) { w.Bytes(r[:]) } 482 483 // Referenced symbol name. 484 // 485 // Serialized format: 486 // RefName struct { 487 // Sym symRef 488 // Name string 489 // } 490 type RefName [RefNameSize]byte 491 492 const RefNameSize = 8 + stringRefSize 493 494 func (n *RefName) Sym() SymRef { 495 return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])} 496 } 497 func (n *RefName) Name(r *Reader) string { 498 len := binary.LittleEndian.Uint32(n[8:]) 499 off := binary.LittleEndian.Uint32(n[12:]) 500 return r.StringAt(off, len) 501 } 502 503 func (n *RefName) SetSym(x SymRef) { 504 binary.LittleEndian.PutUint32(n[:], x.PkgIdx) 505 binary.LittleEndian.PutUint32(n[4:], x.SymIdx) 506 } 507 func (n *RefName) SetName(x string, w *Writer) { 508 binary.LittleEndian.PutUint32(n[8:], uint32(len(x))) 509 binary.LittleEndian.PutUint32(n[12:], w.stringOff(x)) 510 } 511 512 func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) } 513 514 type Writer struct { 515 wr *bio.Writer 516 stringMap map[string]uint32 517 off uint32 // running offset 518 } 519 520 func NewWriter(wr *bio.Writer) *Writer { 521 return &Writer{wr: wr, stringMap: make(map[string]uint32)} 522 } 523 524 func (w *Writer) AddString(s string) { 525 if _, ok := w.stringMap[s]; ok { 526 return 527 } 528 w.stringMap[s] = w.off 529 w.RawString(s) 530 } 531 532 func (w *Writer) stringOff(s string) uint32 { 533 off, ok := w.stringMap[s] 534 if !ok { 535 panic(fmt.Sprintf("writeStringRef: string not added: %q", s)) 536 } 537 return off 538 } 539 540 func (w *Writer) StringRef(s string) { 541 w.Uint32(uint32(len(s))) 542 w.Uint32(w.stringOff(s)) 543 } 544 545 func (w *Writer) RawString(s string) { 546 w.wr.WriteString(s) 547 w.off += uint32(len(s)) 548 } 549 550 func (w *Writer) Bytes(s []byte) { 551 w.wr.Write(s) 552 w.off += uint32(len(s)) 553 } 554 555 func (w *Writer) Uint64(x uint64) { 556 var b [8]byte 557 binary.LittleEndian.PutUint64(b[:], x) 558 w.wr.Write(b[:]) 559 w.off += 8 560 } 561 562 func (w *Writer) Uint32(x uint32) { 563 var b [4]byte 564 binary.LittleEndian.PutUint32(b[:], x) 565 w.wr.Write(b[:]) 566 w.off += 4 567 } 568 569 func (w *Writer) Uint16(x uint16) { 570 var b [2]byte 571 binary.LittleEndian.PutUint16(b[:], x) 572 w.wr.Write(b[:]) 573 w.off += 2 574 } 575 576 func (w *Writer) Uint8(x uint8) { 577 w.wr.WriteByte(x) 578 w.off++ 579 } 580 581 func (w *Writer) Offset() uint32 { 582 return w.off 583 } 584 585 type Reader struct { 586 b []byte // mmapped bytes, if not nil 587 readonly bool // whether b is backed with read-only memory 588 589 rd io.ReaderAt 590 start uint32 591 h Header // keep block offsets 592 } 593 594 func NewReaderFromBytes(b []byte, readonly bool) *Reader { 595 r := &Reader{b: b, readonly: readonly, rd: bytes.NewReader(b), start: 0} 596 err := r.h.Read(r) 597 if err != nil { 598 return nil 599 } 600 return r 601 } 602 603 func (r *Reader) BytesAt(off uint32, len int) []byte { 604 if len == 0 { 605 return nil 606 } 607 end := int(off) + len 608 return r.b[int(off):end:end] 609 } 610 611 func (r *Reader) uint64At(off uint32) uint64 { 612 b := r.BytesAt(off, 8) 613 return binary.LittleEndian.Uint64(b) 614 } 615 616 func (r *Reader) int64At(off uint32) int64 { 617 return int64(r.uint64At(off)) 618 } 619 620 func (r *Reader) uint32At(off uint32) uint32 { 621 b := r.BytesAt(off, 4) 622 return binary.LittleEndian.Uint32(b) 623 } 624 625 func (r *Reader) int32At(off uint32) int32 { 626 return int32(r.uint32At(off)) 627 } 628 629 func (r *Reader) uint16At(off uint32) uint16 { 630 b := r.BytesAt(off, 2) 631 return binary.LittleEndian.Uint16(b) 632 } 633 634 func (r *Reader) uint8At(off uint32) uint8 { 635 b := r.BytesAt(off, 1) 636 return b[0] 637 } 638 639 func (r *Reader) StringAt(off uint32, len uint32) string { 640 b := r.b[off : off+len] 641 if r.readonly { 642 return toString(b) // backed by RO memory, ok to make unsafe string 643 } 644 return string(b) 645 } 646 647 func toString(b []byte) string { 648 if len(b) == 0 { 649 return "" 650 } 651 652 var s string 653 hdr := (*unsafeheader.String)(unsafe.Pointer(&s)) 654 hdr.Data = unsafe.Pointer(&b[0]) 655 hdr.Len = len(b) 656 657 return s 658 } 659 660 func (r *Reader) StringRef(off uint32) string { 661 l := r.uint32At(off) 662 return r.StringAt(r.uint32At(off+4), l) 663 } 664 665 func (r *Reader) Fingerprint() FingerprintType { 666 return r.h.Fingerprint 667 } 668 669 func (r *Reader) Autolib() []ImportedPkg { 670 n := (r.h.Offsets[BlkAutolib+1] - r.h.Offsets[BlkAutolib]) / importedPkgSize 671 s := make([]ImportedPkg, n) 672 off := r.h.Offsets[BlkAutolib] 673 for i := range s { 674 s[i].Pkg = r.StringRef(off) 675 copy(s[i].Fingerprint[:], r.BytesAt(off+stringRefSize, len(s[i].Fingerprint))) 676 off += importedPkgSize 677 } 678 return s 679 } 680 681 func (r *Reader) Pkglist() []string { 682 n := (r.h.Offsets[BlkPkgIdx+1] - r.h.Offsets[BlkPkgIdx]) / stringRefSize 683 s := make([]string, n) 684 off := r.h.Offsets[BlkPkgIdx] 685 for i := range s { 686 s[i] = r.StringRef(off) 687 off += stringRefSize 688 } 689 return s 690 } 691 692 func (r *Reader) NPkg() int { 693 return int(r.h.Offsets[BlkPkgIdx+1]-r.h.Offsets[BlkPkgIdx]) / stringRefSize 694 } 695 696 func (r *Reader) Pkg(i int) string { 697 off := r.h.Offsets[BlkPkgIdx] + uint32(i)*stringRefSize 698 return r.StringRef(off) 699 } 700 701 func (r *Reader) NFile() int { 702 return int(r.h.Offsets[BlkFile+1]-r.h.Offsets[BlkFile]) / stringRefSize 703 } 704 705 func (r *Reader) File(i int) string { 706 off := r.h.Offsets[BlkFile] + uint32(i)*stringRefSize 707 return r.StringRef(off) 708 } 709 710 func (r *Reader) NSym() int { 711 return int(r.h.Offsets[BlkSymdef+1]-r.h.Offsets[BlkSymdef]) / SymSize 712 } 713 714 func (r *Reader) NHashed64def() int { 715 return int(r.h.Offsets[BlkHashed64def+1]-r.h.Offsets[BlkHashed64def]) / SymSize 716 } 717 718 func (r *Reader) NHasheddef() int { 719 return int(r.h.Offsets[BlkHasheddef+1]-r.h.Offsets[BlkHasheddef]) / SymSize 720 } 721 722 func (r *Reader) NNonpkgdef() int { 723 return int(r.h.Offsets[BlkNonpkgdef+1]-r.h.Offsets[BlkNonpkgdef]) / SymSize 724 } 725 726 func (r *Reader) NNonpkgref() int { 727 return int(r.h.Offsets[BlkNonpkgref+1]-r.h.Offsets[BlkNonpkgref]) / SymSize 728 } 729 730 // SymOff returns the offset of the i-th symbol. 731 func (r *Reader) SymOff(i uint32) uint32 { 732 return r.h.Offsets[BlkSymdef] + uint32(i*SymSize) 733 } 734 735 // Sym returns a pointer to the i-th symbol. 736 func (r *Reader) Sym(i uint32) *Sym { 737 off := r.SymOff(i) 738 return (*Sym)(unsafe.Pointer(&r.b[off])) 739 } 740 741 // NRefFlags returns the number of referenced symbol flags. 742 func (r *Reader) NRefFlags() int { 743 return int(r.h.Offsets[BlkRefFlags+1]-r.h.Offsets[BlkRefFlags]) / RefFlagsSize 744 } 745 746 // RefFlags returns a pointer to the i-th referenced symbol flags. 747 // Note: here i is not a local symbol index, just a counter. 748 func (r *Reader) RefFlags(i int) *RefFlags { 749 off := r.h.Offsets[BlkRefFlags] + uint32(i*RefFlagsSize) 750 return (*RefFlags)(unsafe.Pointer(&r.b[off])) 751 } 752 753 // Hash64 returns the i-th short hashed symbol's hash. 754 // Note: here i is the index of short hashed symbols, not all symbols 755 // (unlike other accessors). 756 func (r *Reader) Hash64(i uint32) uint64 { 757 off := r.h.Offsets[BlkHash64] + uint32(i*Hash64Size) 758 return r.uint64At(off) 759 } 760 761 // Hash returns a pointer to the i-th hashed symbol's hash. 762 // Note: here i is the index of hashed symbols, not all symbols 763 // (unlike other accessors). 764 func (r *Reader) Hash(i uint32) *HashType { 765 off := r.h.Offsets[BlkHash] + uint32(i*HashSize) 766 return (*HashType)(unsafe.Pointer(&r.b[off])) 767 } 768 769 // NReloc returns the number of relocations of the i-th symbol. 770 func (r *Reader) NReloc(i uint32) int { 771 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) 772 return int(r.uint32At(relocIdxOff+4) - r.uint32At(relocIdxOff)) 773 } 774 775 // RelocOff returns the offset of the j-th relocation of the i-th symbol. 776 func (r *Reader) RelocOff(i uint32, j int) uint32 { 777 relocIdxOff := r.h.Offsets[BlkRelocIdx] + uint32(i*4) 778 relocIdx := r.uint32At(relocIdxOff) 779 return r.h.Offsets[BlkReloc] + (relocIdx+uint32(j))*uint32(RelocSize) 780 } 781 782 // Reloc returns a pointer to the j-th relocation of the i-th symbol. 783 func (r *Reader) Reloc(i uint32, j int) *Reloc { 784 off := r.RelocOff(i, j) 785 return (*Reloc)(unsafe.Pointer(&r.b[off])) 786 } 787 788 // Relocs returns a pointer to the relocations of the i-th symbol. 789 func (r *Reader) Relocs(i uint32) []Reloc { 790 off := r.RelocOff(i, 0) 791 n := r.NReloc(i) 792 return (*[1 << 20]Reloc)(unsafe.Pointer(&r.b[off]))[:n:n] 793 } 794 795 // NAux returns the number of aux symbols of the i-th symbol. 796 func (r *Reader) NAux(i uint32) int { 797 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 798 return int(r.uint32At(auxIdxOff+4) - r.uint32At(auxIdxOff)) 799 } 800 801 // AuxOff returns the offset of the j-th aux symbol of the i-th symbol. 802 func (r *Reader) AuxOff(i uint32, j int) uint32 { 803 auxIdxOff := r.h.Offsets[BlkAuxIdx] + i*4 804 auxIdx := r.uint32At(auxIdxOff) 805 return r.h.Offsets[BlkAux] + (auxIdx+uint32(j))*uint32(AuxSize) 806 } 807 808 // Aux returns a pointer to the j-th aux symbol of the i-th symbol. 809 func (r *Reader) Aux(i uint32, j int) *Aux { 810 off := r.AuxOff(i, j) 811 return (*Aux)(unsafe.Pointer(&r.b[off])) 812 } 813 814 // Auxs returns the aux symbols of the i-th symbol. 815 func (r *Reader) Auxs(i uint32) []Aux { 816 off := r.AuxOff(i, 0) 817 n := r.NAux(i) 818 return (*[1 << 20]Aux)(unsafe.Pointer(&r.b[off]))[:n:n] 819 } 820 821 // DataOff returns the offset of the i-th symbol's data. 822 func (r *Reader) DataOff(i uint32) uint32 { 823 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 824 return r.h.Offsets[BlkData] + r.uint32At(dataIdxOff) 825 } 826 827 // DataSize returns the size of the i-th symbol's data. 828 func (r *Reader) DataSize(i uint32) int { 829 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 830 return int(r.uint32At(dataIdxOff+4) - r.uint32At(dataIdxOff)) 831 } 832 833 // Data returns the i-th symbol's data. 834 func (r *Reader) Data(i uint32) []byte { 835 dataIdxOff := r.h.Offsets[BlkDataIdx] + i*4 836 base := r.h.Offsets[BlkData] 837 off := r.uint32At(dataIdxOff) 838 end := r.uint32At(dataIdxOff + 4) 839 return r.BytesAt(base+off, int(end-off)) 840 } 841 842 // AuxDataBase returns the base offset of the aux data block. 843 func (r *Reader) PcdataBase() uint32 { 844 return r.h.Offsets[BlkPcdata] 845 } 846 847 // NRefName returns the number of referenced symbol names. 848 func (r *Reader) NRefName() int { 849 return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize 850 } 851 852 // RefName returns a pointer to the i-th referenced symbol name. 853 // Note: here i is not a local symbol index, just a counter. 854 func (r *Reader) RefName(i int) *RefName { 855 off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize) 856 return (*RefName)(unsafe.Pointer(&r.b[off])) 857 } 858 859 // ReadOnly returns whether r.BytesAt returns read-only bytes. 860 func (r *Reader) ReadOnly() bool { 861 return r.readonly 862 } 863 864 // Flags returns the flag bits read from the object file header. 865 func (r *Reader) Flags() uint32 { 866 return r.h.Flags 867 } 868 869 func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 } 870 func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 } 871 func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 }