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 }
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)) } }
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 }
func (p *importer) byte() byte { if c := obj.Bgetc(p.in); c >= 0 { p.read++ return byte(c) } Fatalf("read error") return 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) }
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) }
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) }
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)) } }
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 } }
// 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)) } }
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 }
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) } }
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 }
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 } } }
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)) } } }
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) }
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)) } } }