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