objfile.go 15.6 KB
Newer Older
1
// Copyright 2013 The Go Authors. All rights reserved.
Russ Cox's avatar
Russ Cox committed
2 3 4
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

5 6 7 8 9
// Package objfile reads Go object files for the Go linker, cmd/link.
//
// This package is similar to cmd/internal/objfile which also reads
// Go object files.
package objfile
10

Russ Cox's avatar
Russ Cox committed
11
import (
12
	"bufio"
Russ Cox's avatar
Russ Cox committed
13
	"bytes"
14
	"cmd/internal/bio"
15
	"cmd/internal/dwarf"
16
	"cmd/internal/obj"
17
	"cmd/internal/objabi"
18
	"cmd/internal/sys"
19
	"cmd/link/internal/sym"
20
	"fmt"
21
	"io"
Russ Cox's avatar
Russ Cox committed
22
	"log"
23
	"os"
Russ Cox's avatar
Russ Cox committed
24 25
	"strconv"
	"strings"
26
	"unsafe"
Russ Cox's avatar
Russ Cox committed
27 28
)

29
const (
30 31
	startmagic = "\x00go114ld"
	endmagic   = "\xffgo114ld"
32
)
Russ Cox's avatar
Russ Cox committed
33

34 35 36 37
var emptyPkg = []byte(`"".`)

// objReader reads Go object files.
type objReader struct {
Cherry Zhang's avatar
Cherry Zhang committed
38
	rd              *bio.Reader
39
	arch            *sys.Arch
40
	syms            *sym.Symbols
41
	lib             *sym.Library
42
	unit            *sym.CompilationUnit
43
	pn              string
44
	dupSym          *sym.Symbol
45
	localSymVersion int
46
	flags           int
47
	strictDupMsgs   int
Cherry Zhang's avatar
Cherry Zhang committed
48
	dataSize        int
49 50 51 52

	// rdBuf is used by readString and readSymName as scratch for reading strings.
	rdBuf []byte

53
	// List of symbol references for the file being read.
54
	refs        []*sym.Symbol
55
	data        []byte
56 57 58
	reloc       []sym.Reloc
	pcdata      []sym.Pcdata
	funcdata    []*sym.Symbol
59
	funcdataoff []int64
60
	file        []*sym.Symbol
61
	pkgpref     string // objabi.PathToPrefix(r.lib.Pkg) + "."
Cherry Zhang's avatar
Cherry Zhang committed
62

63 64
	roObject []byte // from read-only mmap of object file (may be nil)
	roOffset int64  // offset into readonly object data examined so far
65

Cherry Zhang's avatar
Cherry Zhang committed
66
	dataReadOnly bool // whether data is backed by read-only memory
67 68
}

69 70 71 72 73 74 75 76 77 78 79 80 81
// Flags to enable optional behavior during object loading/reading.

const (
	NoFlag int = iota

	// Sanity-check duplicate symbol contents, issuing warning
	// when duplicates have different lengths or contents.
	StrictDupsWarnFlag

	// Similar to StrictDupsWarnFlag, but issue fatal error.
	StrictDupsErrFlag
)

82 83
// Load loads an object file f into library lib.
// The symbols loaded are added to syms.
84
func Load(arch *sys.Arch, syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64, pn string, flags int) int {
85
	start := f.Offset()
86 87
	roObject := f.SliceRO(uint64(length))
	if roObject != nil {
88
		f.MustSeek(int64(-length), os.SEEK_CUR)
89
	}
90
	r := &objReader{
Cherry Zhang's avatar
Cherry Zhang committed
91
		rd:              f,
92
		lib:             lib,
93
		unit:            unit,
94 95
		arch:            arch,
		syms:            syms,
96
		pn:              pn,
97
		dupSym:          &sym.Symbol{Name: ".dup"},
98
		localSymVersion: syms.IncVersion(),
99
		flags:           flags,
100
		roObject:        roObject,
101
		pkgpref:         objabi.PathToPrefix(lib.Pkg) + ".",
102 103
	}
	r.loadObjFile()
104 105 106 107
	if roObject != nil {
		if r.roOffset != length {
			log.Fatalf("%s: unexpected end at %d, want %d", pn, r.roOffset, start+length)
		}
108
		r.rd.MustSeek(int64(length), os.SEEK_CUR)
109
	} else if f.Offset() != start+length {
110
		log.Fatalf("%s: unexpected end at %d, want %d", pn, f.Offset(), start+length)
111
	}
112
	return r.strictDupMsgs
113 114 115 116
}

func (r *objReader) loadObjFile() {
	// Magic header
Russ Cox's avatar
Russ Cox committed
117
	var buf [8]uint8
118
	r.readFull(buf[:])
Russ Cox's avatar
Russ Cox committed
119
	if string(buf[:]) != startmagic {
120
		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", r.pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
Russ Cox's avatar
Russ Cox committed
121
	}
122 123

	// Version
124
	c, err := r.readByte()
125 126
	if err != nil || c != 1 {
		log.Fatalf("%s: invalid file version number %d", r.pn, c)
Russ Cox's avatar
Russ Cox committed
127 128
	}

129
	// Autolib
Russ Cox's avatar
Russ Cox committed
130
	for {
131
		lib := r.readString()
Russ Cox's avatar
Russ Cox committed
132 133 134
		if lib == "" {
			break
		}
135
		r.lib.ImportStrings = append(r.lib.ImportStrings, lib)
Russ Cox's avatar
Russ Cox committed
136 137
	}

138 139 140 141 142 143 144 145
	// DWARF strings
	count := r.readInt()
	r.unit.DWARFFileTable = make([]string, count)
	for i := 0; i < count; i++ {
		// TODO: This should probably be a call to mkROString.
		r.unit.DWARFFileTable[i] = r.readString()
	}

146
	// Symbol references
147
	r.refs = []*sym.Symbol{nil} // zeroth ref is nil
148
	for {
149
		c, err := r.peek(1)
150
		if err != nil {
151
			log.Fatalf("%s: peeking: %v", r.pn, err)
152 153
		}
		if c[0] == 0xff {
154
			r.readByte()
155 156
			break
		}
157
		r.readRef()
158 159
	}

160 161
	// Lengths
	r.readSlices()
162

163
	// Data section
164
	err = r.readDataSection()
Cherry Zhang's avatar
Cherry Zhang committed
165 166 167
	if err != nil {
		log.Fatalf("%s: error reading %s", r.pn, err)
	}
168

169
	// Defined symbols
Russ Cox's avatar
Russ Cox committed
170
	for {
171
		c, err := r.peek(1)
172
		if err != nil {
173
			log.Fatalf("%s: peeking: %v", r.pn, err)
174 175
		}
		if c[0] == 0xff {
Russ Cox's avatar
Russ Cox committed
176 177
			break
		}
178
		r.readSym()
Russ Cox's avatar
Russ Cox committed
179 180
	}

181
	// Magic footer
Russ Cox's avatar
Russ Cox committed
182
	buf = [8]uint8{}
183
	r.readFull(buf[:])
Russ Cox's avatar
Russ Cox committed
184
	if string(buf[:]) != endmagic {
185
		log.Fatalf("%s: invalid file end", r.pn)
Russ Cox's avatar
Russ Cox committed
186 187 188
	}
}

189
func (r *objReader) readSlices() {
Cherry Zhang's avatar
Cherry Zhang committed
190
	r.dataSize = r.readInt()
191
	n := r.readInt()
192
	r.reloc = make([]sym.Reloc, n)
193
	n = r.readInt()
194
	r.pcdata = make([]sym.Pcdata, n)
195
	_ = r.readInt() // TODO: remove on next object file rev (autom count)
196
	n = r.readInt()
197
	r.funcdata = make([]*sym.Symbol, n)
198 199
	r.funcdataoff = make([]int64, n)
	n = r.readInt()
200
	r.file = make([]*sym.Symbol, n)
201 202
}

203 204 205
func (r *objReader) readDataSection() (err error) {
	if r.roObject != nil {
		r.data, r.dataReadOnly, err =
206 207
			r.roObject[r.roOffset:r.roOffset+int64(r.dataSize)], true, nil
		r.roOffset += int64(r.dataSize)
208 209 210 211 212 213
		return
	}
	r.data, r.dataReadOnly, err = r.rd.Slice(uint64(r.dataSize))
	return
}

214 215
// Symbols are prefixed so their content doesn't get confused with the magic footer.
const symPrefix = 0xfe
216

217
func (r *objReader) readSym() {
218 219
	var c byte
	var err error
220
	if c, err = r.readByte(); c != symPrefix || err != nil {
221
		log.Fatalln("readSym out of sync")
Russ Cox's avatar
Russ Cox committed
222
	}
223
	if c, err = r.readByte(); err != nil {
224 225
		log.Fatalln("error reading input: ", err)
	}
226
	t := sym.AbiSymKindToSymKind[c]
227 228
	s := r.readSymIndex()
	flags := r.readInt()
229 230
	dupok := flags&1 != 0
	local := flags&2 != 0
231
	makeTypelink := flags&4 != 0
232 233 234 235
	size := r.readInt()
	typ := r.readSymIndex()
	data := r.readData()
	nreloc := r.readInt()
236
	isdup := false
Russ Cox's avatar
Russ Cox committed
237

238 239 240
	var dup *sym.Symbol
	if s.Type != 0 && s.Type != sym.SXREF {
		if (t == sym.SDATA || t == sym.SBSS || t == sym.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
Russ Cox's avatar
Russ Cox committed
241 242 243 244 245 246 247 248 249
			if s.Size < int64(size) {
				s.Size = int64(size)
			}
			if typ != nil && s.Gotype == nil {
				s.Gotype = typ
			}
			return
		}

250
		if (s.Type == sym.SDATA || s.Type == sym.SBSS || s.Type == sym.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
Russ Cox's avatar
Russ Cox committed
251 252
			goto overwrite
		}
253
		if s.Type != sym.SBSS && s.Type != sym.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
254
			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, r.pn)
Russ Cox's avatar
Russ Cox committed
255 256 257
		}
		if len(s.P) > 0 {
			dup = s
258
			s = r.dupSym
259
			isdup = true
Russ Cox's avatar
Russ Cox committed
260 261 262 263
		}
	}

overwrite:
264
	s.File = r.pkgpref[:len(r.pkgpref)-1]
265
	s.Unit = r.unit
266
	if dupok {
267
		s.Attr |= sym.AttrDuplicateOK
268
	}
269
	if t == sym.SXREF {
Russ Cox's avatar
Russ Cox committed
270 271 272
		log.Fatalf("bad sxref")
	}
	if t == 0 {
273
		log.Fatalf("missing type for %s in %s", s.Name, r.pn)
Russ Cox's avatar
Russ Cox committed
274
	}
275
	if t == sym.SBSS && (s.Type == sym.SRODATA || s.Type == sym.SNOPTRBSS) {
276
		t = s.Type
Russ Cox's avatar
Russ Cox committed
277
	}
278
	s.Type = t
Russ Cox's avatar
Russ Cox committed
279 280 281
	if s.Size < int64(size) {
		s.Size = int64(size)
	}
282 283
	s.Attr.Set(sym.AttrLocal, local)
	s.Attr.Set(sym.AttrMakeTypelink, makeTypelink)
284
	if typ != nil {
Russ Cox's avatar
Russ Cox committed
285 286
		s.Gotype = typ
	}
287
	if isdup && typ != nil { // if bss sym defined multiple times, take type from any one def
Russ Cox's avatar
Russ Cox committed
288 289 290
		dup.Gotype = typ
	}
	s.P = data
Cherry Zhang's avatar
Cherry Zhang committed
291
	s.Attr.Set(sym.AttrReadOnly, r.dataReadOnly)
Russ Cox's avatar
Russ Cox committed
292
	if nreloc > 0 {
293
		s.R = r.reloc[:nreloc:nreloc]
294
		if !isdup {
295
			r.reloc = r.reloc[nreloc:]
296 297
		}

Russ Cox's avatar
Russ Cox committed
298
		for i := 0; i < nreloc; i++ {
299
			s.R[i] = sym.Reloc{
300 301
				Off:  r.readInt32(),
				Siz:  r.readUint8(),
302
				Type: objabi.RelocType(r.readInt32()),
303 304 305
				Add:  r.readInt64(),
				Sym:  r.readSymIndex(),
			}
Russ Cox's avatar
Russ Cox committed
306 307 308
		}
	}

309 310
	if s.Type == sym.STEXT {
		s.FuncInfo = new(sym.FuncInfo)
311
		pc := s.FuncInfo
312 313 314

		pc.Args = r.readInt32()
		pc.Locals = r.readInt32()
315
		if r.readUint8() != 0 {
316
			s.Attr |= sym.AttrNoSplit
317
		}
318
		flags := r.readInt()
319
		if flags&(1<<2) != 0 {
320
			s.Attr |= sym.AttrReflectMethod
321
		}
322
		if flags&(1<<3) != 0 {
323
			s.Attr |= sym.AttrShared
324
		}
325 326 327
		if flags&(1<<4) != 0 {
			s.Attr |= sym.AttrTopFrame
		}
328
		n := r.readInt()
329 330
		if n != 0 {
			log.Fatalf("stale object file: autom count nonzero")
331 332
		}

333 334 335
		pc.Pcsp.P = r.readData()
		pc.Pcfile.P = r.readData()
		pc.Pcline.P = r.readData()
336
		pc.Pcinline.P = r.readData()
337 338
		n = r.readInt()
		pc.Pcdata = r.pcdata[:n:n]
339
		if !isdup {
340
			r.pcdata = r.pcdata[n:]
341
		}
Russ Cox's avatar
Russ Cox committed
342
		for i := 0; i < n; i++ {
343
			pc.Pcdata[i].P = r.readData()
Russ Cox's avatar
Russ Cox committed
344
		}
345 346 347
		n = r.readInt()
		pc.Funcdata = r.funcdata[:n:n]
		pc.Funcdataoff = r.funcdataoff[:n:n]
348
		if !isdup {
349 350
			r.funcdata = r.funcdata[n:]
			r.funcdataoff = r.funcdataoff[n:]
351
		}
Russ Cox's avatar
Russ Cox committed
352
		for i := 0; i < n; i++ {
353
			pc.Funcdata[i] = r.readSymIndex()
Russ Cox's avatar
Russ Cox committed
354
		}
Russ Cox's avatar
Russ Cox committed
355
		for i := 0; i < n; i++ {
356
			pc.Funcdataoff[i] = r.readInt64()
Russ Cox's avatar
Russ Cox committed
357
		}
358 359
		n = r.readInt()
		pc.File = r.file[:n:n]
360
		if !isdup {
361
			r.file = r.file[n:]
362
		}
Russ Cox's avatar
Russ Cox committed
363
		for i := 0; i < n; i++ {
364
			pc.File[i] = r.readSymIndex()
Russ Cox's avatar
Russ Cox committed
365
		}
366
		n = r.readInt()
367
		pc.InlTree = make([]sym.InlinedCall, n)
368 369 370 371 372
		for i := 0; i < n; i++ {
			pc.InlTree[i].Parent = r.readInt32()
			pc.InlTree[i].File = r.readSymIndex()
			pc.InlTree[i].Line = r.readInt32()
			pc.InlTree[i].Func = r.readSymIndex()
373
			pc.InlTree[i].ParentPC = r.readInt32()
374
		}
Russ Cox's avatar
Russ Cox committed
375

376
		if !dupok {
377
			if s.Attr.OnList() {
Russ Cox's avatar
Russ Cox committed
378 379
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
380
			s.Attr |= sym.AttrOnList
381
			r.lib.Textp = append(r.lib.Textp, s)
382 383 384 385
		} else {
			// there may ba a dup in another package
			// put into a temp list and add to text later
			if !isdup {
386
				r.lib.DupTextSyms = append(r.lib.DupTextSyms, s)
387
			} else {
388
				r.lib.DupTextSyms = append(r.lib.DupTextSyms, dup)
389
			}
Russ Cox's avatar
Russ Cox committed
390 391
		}
	}
392
	if s.Type == sym.SDWARFINFO {
393 394
		r.patchDWARFName(s)
	}
395 396 397 398 399 400 401 402 403 404 405

	if isdup && r.flags&(StrictDupsWarnFlag|StrictDupsErrFlag) != 0 {
		// Compare the just-read symbol with the previously read
		// symbol of the same name, verifying that they have the same
		// payload. If not, issue a warning and possibly an error.
		if !bytes.Equal(s.P, dup.P) {
			reason := "same length but different contents"
			if len(s.P) != len(dup.P) {
				reason = fmt.Sprintf("new length %d != old length %d",
					len(data), len(dup.P))
			}
406
			fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason)
407 408 409 410 411 412

			// For the moment, whitelist DWARF subprogram DIEs for
			// auto-generated wrapper functions. What seems to happen
			// here is that we get different line numbers on formal
			// params; I am guessing that the pos is being inherited
			// from the spot where the wrapper is needed.
413 414
			whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
				strings.HasPrefix(dup.Name, "go.info.go.builtin") ||
415 416
				strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") ||
				strings.HasPrefix(dup.Name, "go.debuglines"))
417 418
			if !whitelist {
				r.strictDupMsgs++
419 420 421
			}
		}
	}
422 423
}

424
func (r *objReader) patchDWARFName(s *sym.Symbol) {
425 426 427 428 429 430 431 432 433 434 435 436 437
	// This is kind of ugly. Really the package name should not
	// even be included here.
	if s.Size < 1 || s.P[0] != dwarf.DW_ABRV_FUNCTION {
		return
	}
	e := bytes.IndexByte(s.P, 0)
	if e == -1 {
		return
	}
	p := bytes.Index(s.P[:e], emptyPkg)
	if p == -1 {
		return
	}
438
	pkgprefix := []byte(r.pkgpref)
439 440 441 442 443 444 445 446 447 448 449
	patched := bytes.Replace(s.P[:e], emptyPkg, pkgprefix, -1)

	s.P = append(patched, s.P[e:]...)
	delta := int64(len(s.P)) - s.Size
	s.Size = int64(len(s.P))
	for i := range s.R {
		r := &s.R[i]
		if r.Off > int32(e) {
			r.Off += int32(delta)
		}
	}
Russ Cox's avatar
Russ Cox committed
450 451
}

452
func (r *objReader) readFull(b []byte) {
453 454 455 456 457
	if r.roObject != nil {
		copy(b, r.roObject[r.roOffset:])
		r.roOffset += int64(len(b))
		return
	}
458 459 460 461 462 463
	_, err := io.ReadFull(r.rd, b)
	if err != nil {
		log.Fatalf("%s: error reading %s", r.pn, err)
	}
}

464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
func (r *objReader) readByte() (byte, error) {
	if r.roObject != nil {
		b := r.roObject[r.roOffset]
		r.roOffset++
		return b, nil
	}
	return r.rd.ReadByte()
}

func (r *objReader) peek(n int) ([]byte, error) {
	if r.roObject != nil {
		return r.roObject[r.roOffset : r.roOffset+int64(n)], nil
	}
	return r.rd.Peek(n)
}

480
func (r *objReader) readRef() {
481
	if c, err := r.readByte(); c != symPrefix || err != nil {
482
		log.Fatalf("readSym out of sync")
483
	}
484
	name := r.readSymName()
485 486 487
	var v int
	if abi := r.readInt(); abi == -1 {
		// Static
488
		v = r.localSymVersion
489 490 491 492 493
	} else if abiver := sym.ABIToVersion(obj.ABI(abi)); abiver != -1 {
		// Note that data symbols are "ABI0", which maps to version 0.
		v = abiver
	} else {
		log.Fatalf("invalid symbol ABI for %q: %d", name, abi)
494
	}
495
	s := r.syms.Lookup(name, v)
496
	r.refs = append(r.refs, s)
497

498
	if s == nil || v == r.localSymVersion {
499 500 501 502 503 504 505
		return
	}
	if s.Name[0] == '$' && len(s.Name) > 5 && s.Type == 0 && len(s.P) == 0 {
		x, err := strconv.ParseUint(s.Name[5:], 16, 64)
		if err != nil {
			log.Panicf("failed to parse $-symbol %s: %v", s.Name, err)
		}
506 507
		s.Type = sym.SRODATA
		s.Attr |= sym.AttrLocal
508 509 510 511 512
		switch s.Name[:5] {
		case "$f32.":
			if uint64(uint32(x)) != x {
				log.Panicf("$-symbol %s too large: %d", s.Name, x)
			}
513
			s.AddUint32(r.arch, uint32(x))
514
		case "$f64.", "$i64.":
515
			s.AddUint64(r.arch, x)
516 517 518
		default:
			log.Panicf("unrecognized $-symbol: %s", s.Name)
		}
519
		s.Attr.Set(sym.AttrReachable, false)
520 521
	}
	if strings.HasPrefix(s.Name, "runtime.gcbits.") {
522
		s.Attr |= sym.AttrLocal
523
	}
524 525
}

526
func (r *objReader) readInt64() int64 {
Russ Cox's avatar
Russ Cox committed
527
	uv := uint64(0)
528
	for shift := uint(0); ; shift += 7 {
Russ Cox's avatar
Russ Cox committed
529 530 531
		if shift >= 64 {
			log.Fatalf("corrupt input")
		}
532
		c, err := r.readByte()
533 534 535 536
		if err != nil {
			log.Fatalln("error reading input: ", err)
		}
		uv |= uint64(c&0x7F) << shift
Russ Cox's avatar
Russ Cox committed
537 538 539 540 541
		if c&0x80 == 0 {
			break
		}
	}

542
	return int64(uv>>1) ^ (int64(uv<<63) >> 63)
Russ Cox's avatar
Russ Cox committed
543 544
}

545 546
func (r *objReader) readInt() int {
	n := r.readInt64()
547 548 549 550 551 552
	if int64(int(n)) != n {
		log.Panicf("%v out of range for int", n)
	}
	return int(n)
}

553 554
func (r *objReader) readInt32() int32 {
	n := r.readInt64()
555 556 557 558 559 560
	if int64(int32(n)) != n {
		log.Panicf("%v out of range for int32", n)
	}
	return int32(n)
}

561 562
func (r *objReader) readInt16() int16 {
	n := r.readInt64()
563 564 565 566 567 568
	if int64(int16(n)) != n {
		log.Panicf("%v out of range for int16", n)
	}
	return int16(n)
}

569 570
func (r *objReader) readUint8() uint8 {
	n := r.readInt64()
571 572 573 574 575 576
	if int64(uint8(n)) != n {
		log.Panicf("%v out of range for uint8", n)
	}
	return uint8(n)
}

577 578
func (r *objReader) readString() string {
	n := r.readInt()
Shahar Kohanim's avatar
Shahar Kohanim committed
579 580
	if cap(r.rdBuf) < n {
		r.rdBuf = make([]byte, 2*n)
581
	}
582 583
	r.readFull(r.rdBuf[:n])
	return string(r.rdBuf[:n])
Russ Cox's avatar
Russ Cox committed
584 585
}

586 587 588 589
func (r *objReader) readData() []byte {
	n := r.readInt()
	p := r.data[:n:n]
	r.data = r.data[n:]
590
	return p
Russ Cox's avatar
Russ Cox committed
591 592
}

593 594 595 596 597 598 599 600 601 602 603 604 605 606
type stringHeader struct {
	str unsafe.Pointer
	len int
}

func mkROString(rodata []byte) string {
	if len(rodata) == 0 {
		return ""
	}
	ss := stringHeader{str: unsafe.Pointer(&rodata[0]), len: len(rodata)}
	s := *(*string)(unsafe.Pointer(&ss))
	return s
}

607 608 609
// readSymName reads a symbol name, replacing all "". with pkg.
func (r *objReader) readSymName() string {
	n := r.readInt()
Russ Cox's avatar
Russ Cox committed
610
	if n == 0 {
611
		r.readInt64()
612
		return ""
Russ Cox's avatar
Russ Cox committed
613
	}
Shahar Kohanim's avatar
Shahar Kohanim committed
614 615
	if cap(r.rdBuf) < n {
		r.rdBuf = make([]byte, 2*n)
616
	}
617 618
	sOffset := r.roOffset
	origName, err := r.peek(n)
619 620 621 622 623 624
	if err == bufio.ErrBufferFull {
		// Long symbol names are rare but exist. One source is type
		// symbols for types with long string forms. See #15104.
		origName = make([]byte, n)
		r.readFull(origName)
	} else if err != nil {
625
		log.Fatalf("%s: error reading symbol: %v", r.pn, err)
626
	}
627
	adjName := r.rdBuf[:0]
628
	nPkgRefs := 0
629 630 631
	for {
		i := bytes.Index(origName, emptyPkg)
		if i == -1 {
632 633 634 635 636 637
			var s string
			if r.roObject != nil && nPkgRefs == 0 {
				s = mkROString(r.roObject[sOffset : sOffset+int64(n)])
			} else {
				s = string(append(adjName, origName...))
			}
638 639 640
			// Read past the peeked origName, now that we're done with it,
			// using the rfBuf (also no longer used) as the scratch space.
			// TODO: use bufio.Reader.Discard if available instead?
641 642 643
			if err == nil {
				r.readFull(r.rdBuf[:n])
			}
Shahar Kohanim's avatar
Shahar Kohanim committed
644
			r.rdBuf = adjName[:0] // in case 2*n wasn't enough
645
			return s
646
		}
647
		nPkgRefs++
648
		adjName = append(adjName, origName[:i]...)
649
		adjName = append(adjName, r.pkgpref[:len(r.pkgpref)-1]...)
650 651 652 653 654
		adjName = append(adjName, '.')
		origName = origName[i+len(emptyPkg):]
	}
}

655
// Reads the index of a symbol reference and resolves it to a symbol
656
func (r *objReader) readSymIndex() *sym.Symbol {
657 658
	i := r.readInt()
	return r.refs[i]
Russ Cox's avatar
Russ Cox committed
659
}