Beispiel #1
0
func getc() int {
	c := curio.peekc
	if c != 0 {
		curio.peekc = curio.peekc1
		curio.peekc1 = 0
		goto check
	}

	if curio.bin == nil {
		if len(curio.cp) == 0 {
			c = 0
		} else {
			c = int(curio.cp[0])
			curio.cp = curio.cp[1:]
		}
	} else {
		var c1 int
		var c2 int
	loop:
		c = obj.Bgetc(curio.bin)
		if c == 0xef {
			c1 = obj.Bgetc(curio.bin)
			c2 = obj.Bgetc(curio.bin)
			if c1 == 0xbb && c2 == 0xbf {
				yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
				goto loop
			}

			obj.Bungetc(curio.bin)
			obj.Bungetc(curio.bin)
		}
	}

check:
	switch c {
	case 0:
		if curio.bin != nil {
			Yyerror("illegal NUL byte")
			break
		}
		fallthrough

		// insert \n at EOF
	case EOF:
		if curio.eofnl != 0 || curio.last == '\n' {
			return EOF
		}
		curio.eofnl = 1
		c = '\n'
		fallthrough

	case '\n':
		if pushedio.bin == nil {
			lexlineno++
		}
	}

	curio.last = c
	return c
}
Beispiel #2
0
func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
	start := obj.Boffset(f)
	ctxt.IncVersion()
	var buf [8]uint8
	obj.Bread(f, buf[:])
	if string(buf[:]) != startmagic {
		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
	}
	c := obj.Bgetc(f)
	if c != 1 {
		log.Fatalf("%s: invalid file version number %d", pn, c)
	}

	var lib string
	for {
		lib = rdstring(f)
		if lib == "" {
			break
		}
		addlib(ctxt, pkg, pn, lib)
	}

	ctxt.CurRefs = []*LSym{nil} // zeroth ref is nil
	for {
		c, err := f.Peek(1)
		if err != nil {
			log.Fatalf("%s: peeking: %v", pn, err)
		}
		if c[0] == 0xff {
			obj.Bgetc(f)
			break
		}
		readref(ctxt, f, pkg, pn)
	}

	dataLength := rdint64(f)
	data := make([]byte, dataLength)
	obj.Bread(f, data)

	for {
		c, err := f.Peek(1)
		if err != nil {
			log.Fatalf("%s: peeking: %v", pn, err)
		}
		if c[0] == 0xff {
			break
		}
		readsym(ctxt, f, &data, pkg, pn)
	}

	buf = [8]uint8{}
	obj.Bread(f, buf[:])
	if string(buf[:]) != endmagic {
		log.Fatalf("%s: invalid file end", pn)
	}

	if obj.Boffset(f) != start+length {
		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
	}
}
Beispiel #3
0
Datei: lex.go Projekt: vsayer/go
func (l *lexer) getr() rune {
	// unread rune != 0 available
	if r := l.peekr1; r != 0 {
		l.peekr1 = l.peekr2
		l.peekr2 = 0
		if r == '\n' && importpkg == nil {
			lexlineno++
		}
		return r
	}

redo:
	// common case: 7bit ASCII
	c := obj.Bgetc(l.bin)
	if c < utf8.RuneSelf {
		if c == 0 {
			yyerrorl(int(lexlineno), "illegal NUL byte")
			return 0
		}
		if c == '\n' && importpkg == nil {
			lexlineno++
		}
		return rune(c)
	}
	// c >= utf8.RuneSelf

	// uncommon case: non-ASCII
	var buf [utf8.UTFMax]byte
	buf[0] = byte(c)
	buf[1] = byte(obj.Bgetc(l.bin))
	i := 2
	for ; i < len(buf) && !utf8.FullRune(buf[:i]); i++ {
		buf[i] = byte(obj.Bgetc(l.bin))
	}

	r, w := utf8.DecodeRune(buf[:i])
	if r == utf8.RuneError && w == 1 {
		// The string conversion here makes a copy for passing
		// to fmt.Printf, so that buf itself does not escape and
		// can be allocated on the stack.
		yyerrorl(int(lexlineno), "illegal UTF-8 sequence % x", string(buf[:i]))
	}

	if r == BOM {
		yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
		goto redo
	}

	return r
}
Beispiel #4
0
func (p *importer) byte() byte {
	if c := obj.Bgetc(p.in); c >= 0 {
		p.read++
		return byte(c)
	}
	Fatalf("read error")
	return 0
}
Beispiel #5
0
// byte is the bottleneck interface for reading from p.in.
// It unescapes '|' 'S' to '$' and '|' '|' to '|'.
func (p *importer) byte() byte {
	c := obj.Bgetc(p.in)
	p.read++
	if c < 0 {
		Fatalf("read error")
	}
	if c == '|' {
		c = obj.Bgetc(p.in)
		p.read++
		if c < 0 {
			Fatalf("read error")
		}
		switch c {
		case 'S':
			c = '$'
		case '|':
			// nothing to do
		default:
			Fatalf("unexpected escape sequence in export data")
		}
	}
	return byte(c)
}
Beispiel #6
0
func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
	if obj.Bgetc(f) != 0xfe {
		log.Fatalf("readsym out of sync")
	}
	name := rdsymName(f, pkg)
	v := rdint(f)
	if v != 0 && v != 1 {
		log.Fatalf("invalid symbol version %d", v)
	}
	if v == 1 {
		v = ctxt.Version
	}
	lsym := Linklookup(ctxt, name, v)
	ctxt.CurRefs = append(ctxt.CurRefs, lsym)
}
Beispiel #7
0
func rdint(f *obj.Biobuf) int64 {
	var c int

	uv := uint64(0)
	for shift := 0; ; shift += 7 {
		if shift >= 64 {
			log.Fatalf("corrupt input")
		}
		c = obj.Bgetc(f)
		uv |= uint64(c&0x7F) << uint(shift)
		if c&0x80 == 0 {
			break
		}
	}

	return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
}
Beispiel #8
0
func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
	start := obj.Boffset(f)
	ctxt.Version++
	var buf [8]uint8
	obj.Bread(f, buf[:])
	if string(buf[:]) != startmagic {
		log.Fatalf("%s: invalid file start %x %x %x %x %x %x %x %x", pn, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7])
	}
	c := obj.Bgetc(f)
	if c != 1 {
		log.Fatalf("%s: invalid file version number %d", pn, c)
	}

	var lib string
	for {
		lib = rdstring(f)
		if lib == "" {
			break
		}
		addlib(ctxt, pkg, pn, lib)
	}

	for {
		c, err := f.Peek(1)
		if err != nil {
			log.Fatalf("%s: peeking: %v", pn, err)
		}
		if c[0] == 0xff {
			break
		}
		readsym(ctxt, f, pkg, pn)
	}

	buf = [8]uint8{}
	obj.Bread(f, buf[:])
	if string(buf[:]) != endmagic {
		log.Fatalf("%s: invalid file end", pn)
	}

	if obj.Boffset(f) != start+length {
		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
	}
}
Beispiel #9
0
func readref(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
	if obj.Bgetc(f) != 0xfe {
		log.Fatalf("readsym out of sync")
	}
	name := rdsymName(f, pkg)
	v := rdint(f)
	if v != 0 && v != 1 {
		log.Fatalf("invalid symbol version %d", v)
	}
	if v == 1 {
		v = ctxt.Version
	}
	s := Linklookup(ctxt, name, v)
	ctxt.CurRefs = append(ctxt.CurRefs, s)

	if s == nil || v != 0 {
		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)
		}
		s.Type = obj.SRODATA
		s.Attr |= AttrLocal
		switch s.Name[:5] {
		case "$f32.":
			if uint64(uint32(x)) != x {
				log.Panicf("$-symbol %s too large: %d", s.Name, x)
			}
			Adduint32(ctxt, s, uint32(x))
		case "$f64.", "$i64.":
			Adduint64(ctxt, s, x)
		default:
			log.Panicf("unrecognized $-symbol: %s", s.Name)
		}
		s.Attr.Set(AttrReachable, false)
	}
	if strings.HasPrefix(s.Name, "runtime.gcbits.") {
		s.Attr |= AttrLocal
	}
}
Beispiel #10
0
// TODO(gri) line argument doesn't appear to be used
func importfile(f *Val, line int) {
	if _, ok := f.U.(string); !ok {
		Yyerror("import statement not a string")
		fakeimport()
		return
	}

	if len(f.U.(string)) == 0 {
		Yyerror("import path is empty")
		fakeimport()
		return
	}

	if isbadimport(f.U.(string)) {
		fakeimport()
		return
	}

	// The package name main is no longer reserved,
	// but we reserve the import path "main" to identify
	// the main package, just as we reserve the import
	// path "math" to identify the standard math package.
	if f.U.(string) == "main" {
		Yyerror("cannot import \"main\"")
		errorexit()
	}

	if myimportpath != "" && f.U.(string) == myimportpath {
		Yyerror("import %q while compiling that package (import cycle)", f.U.(string))
		errorexit()
	}

	path_ := f.U.(string)

	if mapped, ok := importMap[path_]; ok {
		path_ = mapped
	}

	if path_ == "unsafe" {
		if safemode != 0 {
			Yyerror("cannot import package unsafe")
			errorexit()
		}

		importpkg = mkpkg(f.U.(string))
		cannedimports("unsafe.o", unsafeimport)
		imported_unsafe = true
		return
	}

	if islocalname(path_) {
		if path_[0] == '/' {
			Yyerror("import path cannot be absolute path")
			fakeimport()
			return
		}

		prefix := Ctxt.Pathname
		if localimport != "" {
			prefix = localimport
		}
		cleanbuf := prefix
		cleanbuf += "/"
		cleanbuf += path_
		cleanbuf = path.Clean(cleanbuf)
		path_ = cleanbuf

		if isbadimport(path_) {
			fakeimport()
			return
		}
	}

	file, found := findpkg(path_)
	if !found {
		Yyerror("can't find import: %q", f.U.(string))
		errorexit()
	}

	importpkg = mkpkg(path_)

	// If we already saw that package, feed a dummy statement
	// to the lexer to avoid parsing export data twice.
	if importpkg.Imported {
		tag := ""
		if importpkg.Safe {
			tag = "safe"
		}

		p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
		cannedimports(file, p)
		return
	}

	importpkg.Imported = true

	var err error
	var imp *obj.Biobuf
	imp, err = obj.Bopenr(file)
	if err != nil {
		Yyerror("can't open import: %q: %v", f.U.(string), err)
		errorexit()
	}

	if strings.HasSuffix(file, ".a") {
		if !skiptopkgdef(imp) {
			Yyerror("import %s: not a package file", file)
			errorexit()
		}
	}

	// check object header
	p := obj.Brdstr(imp, '\n', 1)

	if p != "empty archive" {
		if !strings.HasPrefix(p, "go object ") {
			Yyerror("import %s: not a go object file", file)
			errorexit()
		}

		q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
		if p[10:] != q {
			Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
			errorexit()
		}
	}

	// assume files move (get installed)
	// so don't record the full path.
	linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib

	// In the importfile, if we find:
	// $$\n  (old format): position the input right after $$\n and return
	// $$B\n (new format): import directly, then feed the lexer a dummy statement

	// look for $$
	var c int
	for {
		c = obj.Bgetc(imp)
		if c < 0 {
			break
		}
		if c == '$' {
			c = obj.Bgetc(imp)
			if c == '$' || c < 0 {
				break
			}
		}
	}

	// get character after $$
	if c >= 0 {
		c = obj.Bgetc(imp)
	}

	switch c {
	case '\n':
		// old export format
		pushedio = curio

		curio.bin = imp
		curio.peekc = 0
		curio.peekc1 = 0
		curio.infile = file
		curio.nlsemi = false
		typecheckok = true

		push_parser()

	case 'B':
		// new export format
		obj.Bgetc(imp) // skip \n after $$B
		Import(imp)

		// continue as if the package was imported before (see above)
		tag := ""
		if importpkg.Safe {
			tag = "safe"
		}
		p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
		cannedimports(file, p)
		// Reset incannedimport flag (we are not truly in a
		// canned import) - this will cause importpkg.Direct to
		// be set via parser.import_package (was issue #13977).
		//
		// TODO(gri) Remove this global variable and convoluted
		// code in the process of streamlining the import code.
		incannedimport = 0

	default:
		Yyerror("no import in %q", f.U.(string))
	}
}
Beispiel #11
0
func getc() int {
	c := curio.peekc
	if c != 0 {
		curio.peekc = curio.peekc1
		curio.peekc1 = 0
		goto check
	}

	if curio.bin == nil {
		if len(curio.cp) == 0 {
			c = 0
		} else {
			c = int(curio.cp[0])
			curio.cp = curio.cp[1:]
		}
	} else {
	loop:
		c = obj.Bgetc(curio.bin)
		// recognize BOM (U+FEFF): UTF-8 encoding is 0xef 0xbb 0xbf
		if c == 0xef {
			buf, err := curio.bin.Peek(2)
			if err != nil {
				yyerrorl(int(lexlineno), "illegal UTF-8 sequence ef % x followed by read error (%v)", string(buf), err)
				errorexit()
			}
			if buf[0] == 0xbb && buf[1] == 0xbf {
				yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")

				// consume BOM bytes
				obj.Bgetc(curio.bin)
				obj.Bgetc(curio.bin)
				goto loop
			}
		}
	}

check:
	switch c {
	case 0:
		if curio.bin != nil {
			Yyerror("illegal NUL byte")
			break
		}
		fallthrough

		// insert \n at EOF
	case EOF:
		if curio.eofnl || curio.last == '\n' {
			return EOF
		}
		curio.eofnl = true
		c = '\n'
		fallthrough

	case '\n':
		if pushedio.bin == nil {
			lexlineno++
		}
	}

	curio.last = c
	return c
}
Beispiel #12
0
Datei: lex.go Projekt: vsayer/go
func importfile(f *Val, indent []byte) {
	if importpkg != nil {
		Fatalf("importpkg not nil")
	}

	path_, ok := f.U.(string)
	if !ok {
		Yyerror("import statement not a string")
		return
	}

	if len(path_) == 0 {
		Yyerror("import path is empty")
		return
	}

	if isbadimport(path_) {
		return
	}

	// The package name main is no longer reserved,
	// but we reserve the import path "main" to identify
	// the main package, just as we reserve the import
	// path "math" to identify the standard math package.
	if path_ == "main" {
		Yyerror("cannot import \"main\"")
		errorexit()
	}

	if myimportpath != "" && path_ == myimportpath {
		Yyerror("import %q while compiling that package (import cycle)", path_)
		errorexit()
	}

	if mapped, ok := importMap[path_]; ok {
		path_ = mapped
	}

	if path_ == "unsafe" {
		if safemode != 0 {
			Yyerror("cannot import package unsafe")
			errorexit()
		}

		importpkg = unsafepkg
		imported_unsafe = true
		return
	}

	if islocalname(path_) {
		if path_[0] == '/' {
			Yyerror("import path cannot be absolute path")
			return
		}

		prefix := Ctxt.Pathname
		if localimport != "" {
			prefix = localimport
		}
		path_ = path.Join(prefix, path_)

		if isbadimport(path_) {
			return
		}
	}

	file, found := findpkg(path_)
	if !found {
		Yyerror("can't find import: %q", path_)
		errorexit()
	}

	importpkg = mkpkg(path_)

	if importpkg.Imported {
		return
	}

	importpkg.Imported = true

	imp, err := obj.Bopenr(file)
	if err != nil {
		Yyerror("can't open import: %q: %v", path_, err)
		errorexit()
	}
	defer obj.Bterm(imp)

	if strings.HasSuffix(file, ".a") {
		if !skiptopkgdef(imp) {
			Yyerror("import %s: not a package file", file)
			errorexit()
		}
	}

	// check object header
	p := obj.Brdstr(imp, '\n', 1)

	if p != "empty archive" {
		if !strings.HasPrefix(p, "go object ") {
			Yyerror("import %s: not a go object file", file)
			errorexit()
		}

		q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
		if p[10:] != q {
			Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
			errorexit()
		}
	}

	// assume files move (get installed)
	// so don't record the full path.
	linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib

	// In the importfile, if we find:
	// $$\n  (old format): position the input right after $$\n and return
	// $$B\n (new format): import directly, then feed the lexer a dummy statement

	// look for $$
	var c int
	for {
		c = obj.Bgetc(imp)
		if c < 0 {
			break
		}
		if c == '$' {
			c = obj.Bgetc(imp)
			if c == '$' || c < 0 {
				break
			}
		}
	}

	// get character after $$
	if c >= 0 {
		c = obj.Bgetc(imp)
	}

	switch c {
	case '\n':
		// old export format
		parse_import(imp, indent)

	case 'B':
		// new export format
		obj.Bgetc(imp) // skip \n after $$B
		Import(imp)

	default:
		Yyerror("no import in %q", path_)
		errorexit()
	}

	if safemode != 0 && !importpkg.Safe {
		Yyerror("cannot import unsafe package %q", importpkg.Path)
	}
}
Beispiel #13
0
func getc() int {
	c := curio.peekc
	if c != 0 {
		curio.peekc = curio.peekc1
		curio.peekc1 = 0
		goto check
	}

	if curio.bin == nil {
		if len(curio.cp) == 0 {
			c = 0
		} else {
			c = int(curio.cp[0])
			curio.cp = curio.cp[1:]
		}
	} else {
	loop:
		c = obj.Bgetc(curio.bin)
		if c == 0xef {
			buf, err := curio.bin.Peek(2)
			if err != nil {
				log.Fatalf("getc: peeking: %v", err)
			}
			if buf[0] == 0xbb && buf[1] == 0xbf {
				yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")

				// consume BOM bytes
				obj.Bgetc(curio.bin)
				obj.Bgetc(curio.bin)
				goto loop
			}
		}
	}

check:
	switch c {
	case 0:
		if curio.bin != nil {
			Yyerror("illegal NUL byte")
			break
		}
		fallthrough

		// insert \n at EOF
	case EOF:
		if curio.eofnl || curio.last == '\n' {
			return EOF
		}
		curio.eofnl = true
		c = '\n'
		fallthrough

	case '\n':
		if pushedio.bin == nil {
			lexlineno++
		}
	}

	curio.last = c
	return c
}
Beispiel #14
0
func readsym(ctxt *Link, f *obj.Biobuf, buf *[]byte, pkg string, pn string) {
	if obj.Bgetc(f) != 0xfe {
		log.Fatalf("readsym out of sync")
	}
	t := rdint(f)
	s := rdsym(ctxt, f, pkg)
	flags := rdint(f)
	dupok := flags&1 != 0
	local := flags&2 != 0
	size := rdint(f)
	typ := rdsym(ctxt, f, pkg)
	data := rddata(f, buf)
	nreloc := rdint(f)

	var dup *LSym
	if s.Type != 0 && s.Type != obj.SXREF {
		if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
			if s.Size < int64(size) {
				s.Size = int64(size)
			}
			if typ != nil && s.Gotype == nil {
				s.Gotype = typ
			}
			return
		}

		if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
			goto overwrite
		}
		if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
		}
		if len(s.P) > 0 {
			dup = s
			s = dupSym
		}
	}

overwrite:
	s.File = pkg
	if dupok {
		s.Attr |= AttrDuplicateOK
	}
	if t == obj.SXREF {
		log.Fatalf("bad sxref")
	}
	if t == 0 {
		log.Fatalf("missing type for %s in %s", s.Name, pn)
	}
	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
		t = int(s.Type)
	}
	s.Type = int16(t)
	if s.Size < int64(size) {
		s.Size = int64(size)
	}
	s.Attr.Set(AttrLocal, local)
	if typ != nil {
		s.Gotype = typ
	}
	if dup != nil && typ != nil { // if bss sym defined multiple times, take type from any one def
		dup.Gotype = typ
	}
	s.P = data
	if nreloc > 0 {
		s.R = make([]Reloc, nreloc)
		var r *Reloc
		for i := 0; i < nreloc; i++ {
			r = &s.R[i]
			r.Off = rdint32(f)
			r.Siz = rduint8(f)
			r.Type = rdint32(f)
			r.Add = rdint64(f)
			r.Sym = rdsym(ctxt, f, pkg)
		}
	}

	if s.Type == obj.STEXT {
		s.Args = rdint32(f)
		s.Locals = rdint32(f)
		if rduint8(f) != 0 {
			s.Attr |= AttrNoSplit
		}
		flags := rdint(f)
		if flags&(1<<2) != 0 {
			s.Attr |= AttrReflectMethod
		}
		n := rdint(f)
		s.Autom = make([]Auto, n)
		for i := 0; i < n; i++ {
			s.Autom[i] = Auto{
				Asym:    rdsym(ctxt, f, pkg),
				Aoffset: rdint32(f),
				Name:    rdint16(f),
				Gotype:  rdsym(ctxt, f, pkg),
			}
		}

		s.Pcln = new(Pcln)
		pc := s.Pcln
		pc.Pcsp.P = rddata(f, buf)
		pc.Pcfile.P = rddata(f, buf)
		pc.Pcline.P = rddata(f, buf)
		n = rdint(f)
		pc.Pcdata = make([]Pcdata, n)
		for i := 0; i < n; i++ {
			pc.Pcdata[i].P = rddata(f, buf)
		}
		n = rdint(f)
		pc.Funcdata = make([]*LSym, n)
		pc.Funcdataoff = make([]int64, n)
		for i := 0; i < n; i++ {
			pc.Funcdata[i] = rdsym(ctxt, f, pkg)
		}
		for i := 0; i < n; i++ {
			pc.Funcdataoff[i] = rdint64(f)
		}
		n = rdint(f)
		pc.File = make([]*LSym, n)
		for i := 0; i < n; i++ {
			pc.File[i] = rdsym(ctxt, f, pkg)
		}

		if dup == nil {
			if s.Attr.OnList() {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Attr |= AttrOnList
			if ctxt.Etextp != nil {
				ctxt.Etextp.Next = s
			} else {
				ctxt.Textp = s
			}
			ctxt.Etextp = s
		}
	}
}
Beispiel #15
0
func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
	if obj.Bgetc(f) != 0xfe {
		log.Fatalf("readsym out of sync")
	}
	t := rdint(f)
	s := rdsym(ctxt, f, pkg)
	flags := rdint(f)
	dupok := flags&1 != 0
	local := flags&2 != 0
	size := rdint(f)
	typ := rdsym(ctxt, f, pkg)
	data := rddata(f)
	nreloc := rdint(f)

	var dup *LSym
	if s.Type != 0 && s.Type != obj.SXREF {
		if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
			if s.Size < int64(size) {
				s.Size = int64(size)
			}
			if typ != nil && s.Gotype == nil {
				s.Gotype = typ
			}
			return
		}

		if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
			goto overwrite
		}
		if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && !dupok && !s.Attr.DuplicateOK() {
			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
		}
		if len(s.P) > 0 {
			dup = s
			s = linknewsym(ctxt, ".dup", -1)
		}
	}

overwrite:
	s.File = pkg
	if dupok {
		s.Attr |= AttrDuplicateOK
	}
	if t == obj.SXREF {
		log.Fatalf("bad sxref")
	}
	if t == 0 {
		log.Fatalf("missing type for %s in %s", s.Name, pn)
	}
	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
		t = int(s.Type)
	}
	s.Type = int16(t)
	if s.Size < int64(size) {
		s.Size = int64(size)
	}
	s.Attr.Set(AttrLocal, local)
	if typ != nil { // if bss sym defined multiple times, take type from any one def
		s.Gotype = typ
	}
	if dup != nil && typ != nil {
		dup.Gotype = typ
	}
	s.P = data
	s.P = s.P[:len(data)]
	if nreloc > 0 {
		s.R = make([]Reloc, nreloc)
		s.R = s.R[:nreloc]
		var r *Reloc
		for i := 0; i < nreloc; i++ {
			r = &s.R[i]
			r.Off = rdint32(f)
			r.Siz = rduint8(f)
			r.Type = rdint32(f)
			r.Add = rdint64(f)
			rdint64(f) // Xadd, ignored
			r.Sym = rdsym(ctxt, f, pkg)
			rdsym(ctxt, f, pkg) // Xsym, ignored
		}
	}

	if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
		// content-addressed garbage collection liveness bitmap symbol.
		// double check for hash collisions.
		if !bytes.Equal(s.P, dup.P) {
			log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
		}
	}

	if s.Type == obj.STEXT {
		s.Args = rdint32(f)
		s.Locals = rdint32(f)
		if rduint8(f) != 0 {
			s.Attr |= AttrNoSplit
		}
		flags := rdint(f)
		if flags&(1<<2) != 0 {
			s.Attr |= AttrReflectMethod
		}
		n := rdint(f)
		s.Autom = make([]Auto, n)
		for i := 0; i < n; i++ {
			s.Autom[i] = Auto{
				Asym:    rdsym(ctxt, f, pkg),
				Aoffset: rdint32(f),
				Name:    rdint16(f),
				Gotype:  rdsym(ctxt, f, pkg),
			}
		}

		s.Pcln = new(Pcln)
		pc := s.Pcln
		pc.Pcsp.P = rddata(f)
		pc.Pcfile.P = rddata(f)
		pc.Pcline.P = rddata(f)
		n = rdint(f)
		pc.Pcdata = make([]Pcdata, n)
		pc.Npcdata = n
		for i := 0; i < n; i++ {
			pc.Pcdata[i].P = rddata(f)
		}
		n = rdint(f)
		pc.Funcdata = make([]*LSym, n)
		pc.Funcdataoff = make([]int64, n)
		pc.Nfuncdata = n
		for i := 0; i < n; i++ {
			pc.Funcdata[i] = rdsym(ctxt, f, pkg)
		}
		for i := 0; i < n; i++ {
			pc.Funcdataoff[i] = rdint64(f)
		}
		n = rdint(f)
		pc.File = make([]*LSym, n)
		pc.Nfile = n
		for i := 0; i < n; i++ {
			pc.File[i] = rdsym(ctxt, f, pkg)
		}

		if dup == nil {
			if s.Attr.OnList() {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Attr |= AttrOnList
			if ctxt.Etextp != nil {
				ctxt.Etextp.Next = s
			} else {
				ctxt.Textp = s
			}
			ctxt.Etextp = s
		}
	}

	if ctxt.Debugasm != 0 {
		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
		if s.Version != 0 {
			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
		}
		if s.Type != 0 {
			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
		}
		if s.Attr.DuplicateOK() {
			fmt.Fprintf(ctxt.Bso, "dupok ")
		}
		if s.Attr.NoSplit() {
			fmt.Fprintf(ctxt.Bso, "nosplit ")
		}
		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
		if s.Type == obj.STEXT {
			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
		}
		fmt.Fprintf(ctxt.Bso, "\n")
		var c int
		var j int
		for i := 0; i < len(s.P); {
			fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
			for j = i; j < i+16 && j < len(s.P); j++ {
				fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
			}
			for ; j < i+16; j++ {
				fmt.Fprintf(ctxt.Bso, "   ")
			}
			fmt.Fprintf(ctxt.Bso, "  ")
			for j = i; j < i+16 && j < len(s.P); j++ {
				c = int(s.P[j])
				if ' ' <= c && c <= 0x7e {
					fmt.Fprintf(ctxt.Bso, "%c", c)
				} else {
					fmt.Fprintf(ctxt.Bso, ".")
				}
			}

			fmt.Fprintf(ctxt.Bso, "\n")
			i += 16
		}

		var r *Reloc
		for i := 0; i < len(s.R); i++ {
			r = &s.R[i]
			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add))
		}
	}
}
Beispiel #16
0
func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) {
	eof := obj.Boffset(f) + length

	start := obj.Boffset(f)
	c1 := obj.Bgetc(f)
	c2 := obj.Bgetc(f)
	c3 := obj.Bgetc(f)
	c4 := obj.Bgetc(f)
	obj.Bseek(f, start, 0)

	magic := uint32(c1)<<24 | uint32(c2)<<16 | uint32(c3)<<8 | uint32(c4)
	if magic == 0x7f454c46 { // \x7F E L F
		ldhostobj(ldelf, f, pkg, length, pn, file)
		return
	}

	if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
		ldhostobj(ldmacho, f, pkg, length, pn, file)
		return
	}

	if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
		ldhostobj(ldpe, f, pkg, length, pn, file)
		return
	}

	/* check the header */
	line := obj.Brdline(f, '\n')
	if line == "" {
		if obj.Blinelen(f) > 0 {
			Diag("%s: not an object file", pn)
			return
		}
		Diag("truncated object file: %s", pn)
		return
	}

	if !strings.HasPrefix(line, "go object ") {
		if strings.HasSuffix(pn, ".go") {
			Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
		}

		if line == Thestring {
			// old header format: just $GOOS
			Diag("%s: stale object file", pn)
			return
		}

		Diag("%s: not an object file", pn)
		return
	}

	// First, check that the basic goos, goarch, and version match.
	t := fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())

	line = strings.TrimRight(line, "\n")
	if !strings.HasPrefix(line[10:]+" ", t) && Debug['f'] == 0 {
		Diag("%s: object is [%s] expected [%s]", pn, line[10:], t)
		return
	}

	// Second, check that longer lines match each other exactly,
	// so that the Go compiler and write additional information
	// that must be the same from run to run.
	if len(line) >= len(t)+10 {
		if theline == "" {
			theline = line[10:]
		} else if theline != line[10:] {
			Diag("%s: object is [%s] expected [%s]", pn, line[10:], theline)
			return
		}
	}

	/* skip over exports and other info -- ends with \n!\n */
	import0 := obj.Boffset(f)

	c1 = '\n' // the last line ended in \n
	c2 = obj.Bgetc(f)
	c3 = obj.Bgetc(f)
	for c1 != '\n' || c2 != '!' || c3 != '\n' {
		c1 = c2
		c2 = c3
		c3 = obj.Bgetc(f)
		if c3 == obj.Beof {
			Diag("truncated object file: %s", pn)
			return
		}
	}

	import1 := obj.Boffset(f)

	obj.Bseek(f, import0, 0)
	ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
	obj.Bseek(f, import1, 0)

	ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
}
Beispiel #17
0
func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
	if obj.Bgetc(f) != 0xfe {
		log.Fatalf("readsym out of sync")
	}
	t := int(rdint(f))
	name := expandpkg(rdstring(f), pkg)
	v := int(rdint(f))
	if v != 0 && v != 1 {
		log.Fatalf("invalid symbol version %d", v)
	}
	flags := int(rdint(f))
	dupok := flags & 1
	local := false
	if flags&2 != 0 {
		local = true
	}
	size := int(rdint(f))
	typ := rdsym(ctxt, f, pkg)
	data := rddata(f)
	nreloc := int(rdint(f))

	if v != 0 {
		v = ctxt.Version
	}
	s := Linklookup(ctxt, name, v)
	var dup *LSym
	if s.Type != 0 && s.Type != obj.SXREF {
		if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
			if s.Size < int64(size) {
				s.Size = int64(size)
			}
			if typ != nil && s.Gotype == nil {
				s.Gotype = typ
			}
			return
		}

		if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
			goto overwrite
		}
		if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
		}
		if len(s.P) > 0 {
			dup = s
			s = linknewsym(ctxt, ".dup", readsym_ndup)
			readsym_ndup++ // scratch
		}
	}

overwrite:
	s.File = pkg
	s.Dupok = uint8(dupok)
	if t == obj.SXREF {
		log.Fatalf("bad sxref")
	}
	if t == 0 {
		log.Fatalf("missing type for %s in %s", name, pn)
	}
	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
		t = int(s.Type)
	}
	s.Type = int16(t)
	if s.Size < int64(size) {
		s.Size = int64(size)
	}
	s.Local = local
	if typ != nil { // if bss sym defined multiple times, take type from any one def
		s.Gotype = typ
	}
	if dup != nil && typ != nil {
		dup.Gotype = typ
	}
	s.P = data
	s.P = s.P[:len(data)]
	if nreloc > 0 {
		s.R = make([]Reloc, nreloc)
		s.R = s.R[:nreloc]
		var r *Reloc
		for i := 0; i < nreloc; i++ {
			r = &s.R[i]
			r.Off = int32(rdint(f))
			r.Siz = uint8(rdint(f))
			r.Type = int32(rdint(f))
			r.Add = rdint(f)
			rdint(f) // Xadd, ignored
			r.Sym = rdsym(ctxt, f, pkg)
			rdsym(ctxt, f, pkg) // Xsym, ignored
		}
	}

	if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
		// content-addressed garbage collection liveness bitmap symbol.
		// double check for hash collisions.
		if !bytes.Equal(s.P, dup.P) {
			log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
		}
	}

	if s.Type == obj.STEXT {
		s.Args = int32(rdint(f))
		s.Locals = int32(rdint(f))
		s.Nosplit = uint8(rdint(f))
		v := int(rdint(f))
		s.Leaf = uint8(v & 1)
		s.Cfunc = uint8(v & 2)
		n := int(rdint(f))
		var a *Auto
		for i := 0; i < n; i++ {
			a = new(Auto)
			a.Asym = rdsym(ctxt, f, pkg)
			a.Aoffset = int32(rdint(f))
			a.Name = int16(rdint(f))
			a.Gotype = rdsym(ctxt, f, pkg)
			a.Link = s.Autom
			s.Autom = a
		}

		s.Pcln = new(Pcln)
		pc := s.Pcln
		pc.Pcsp.P = rddata(f)
		pc.Pcfile.P = rddata(f)
		pc.Pcline.P = rddata(f)
		n = int(rdint(f))
		pc.Pcdata = make([]Pcdata, n)
		pc.Npcdata = n
		for i := 0; i < n; i++ {
			pc.Pcdata[i].P = rddata(f)
		}
		n = int(rdint(f))
		pc.Funcdata = make([]*LSym, n)
		pc.Funcdataoff = make([]int64, n)
		pc.Nfuncdata = n
		for i := 0; i < n; i++ {
			pc.Funcdata[i] = rdsym(ctxt, f, pkg)
		}
		for i := 0; i < n; i++ {
			pc.Funcdataoff[i] = rdint(f)
		}
		n = int(rdint(f))
		pc.File = make([]*LSym, n)
		pc.Nfile = n
		for i := 0; i < n; i++ {
			pc.File[i] = rdsym(ctxt, f, pkg)
		}

		if dup == nil {
			if s.Onlist != 0 {
				log.Fatalf("symbol %s listed multiple times", s.Name)
			}
			s.Onlist = 1
			if ctxt.Etextp != nil {
				ctxt.Etextp.Next = s
			} else {
				ctxt.Textp = s
			}
			ctxt.Etextp = s
		}
	}

	if ctxt.Debugasm != 0 {
		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
		if s.Version != 0 {
			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
		}
		if s.Type != 0 {
			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
		}
		if s.Dupok != 0 {
			fmt.Fprintf(ctxt.Bso, "dupok ")
		}
		if s.Cfunc != 0 {
			fmt.Fprintf(ctxt.Bso, "cfunc ")
		}
		if s.Nosplit != 0 {
			fmt.Fprintf(ctxt.Bso, "nosplit ")
		}
		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
		if s.Type == obj.STEXT {
			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
		}
		fmt.Fprintf(ctxt.Bso, "\n")
		var c int
		var j int
		for i := 0; i < len(s.P); {
			fmt.Fprintf(ctxt.Bso, "\t%#04x", uint(i))
			for j = i; j < i+16 && j < len(s.P); j++ {
				fmt.Fprintf(ctxt.Bso, " %02x", s.P[j])
			}
			for ; j < i+16; j++ {
				fmt.Fprintf(ctxt.Bso, "   ")
			}
			fmt.Fprintf(ctxt.Bso, "  ")
			for j = i; j < i+16 && j < len(s.P); j++ {
				c = int(s.P[j])
				if ' ' <= c && c <= 0x7e {
					fmt.Fprintf(ctxt.Bso, "%c", c)
				} else {
					fmt.Fprintf(ctxt.Bso, ".")
				}
			}

			fmt.Fprintf(ctxt.Bso, "\n")
			i += 16
		}

		var r *Reloc
		for i := 0; i < len(s.R); i++ {
			r = &s.R[i]
			fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, r.Sym.Name, int64(r.Add))
		}
	}
}