func assemble(file string) int { if outfile == "" { outfile = strings.TrimSuffix(filepath.Base(file), ".s") + "." + string(Thechar) } of, err := os.Create(outfile) if err != nil { Yyerror("%ca: cannot create %s", Thechar, outfile) errorexit() } obuf = *obj.Binitw(of) fmt.Fprintf(&obuf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion()) fmt.Fprintf(&obuf, "!\n") var i int for Pass = 1; Pass <= 2; Pass++ { pinit(file) for i = 0; i < len(Dlist); i++ { dodefine(Dlist[i]) } Yyparse() Cclean() if nerrors != 0 { return nerrors } } obj.Writeobjdirect(Ctxt, &obuf) obuf.Flush() return 0 }
func main() { log.SetFlags(0) log.SetPrefix("asm: ") GOARCH := obj.Getgoarch() architecture := arch.Set(GOARCH) if architecture == nil { log.Fatalf("unrecognized architecture %s", GOARCH) } flags.Parse() ctxt := obj.Linknew(architecture.LinkArch) if *flags.PrintOut { ctxt.Debugasm = 1 } ctxt.LineHist.TrimPathPrefix = *flags.TrimPath ctxt.Flag_dynlink = *flags.Dynlink ctxt.Flag_shared = *flags.Shared || *flags.Dynlink ctxt.Bso = bufio.NewWriter(os.Stdout) defer ctxt.Bso.Flush() // Create object file, write header. out, err := os.Create(*flags.OutputFile) if err != nil { log.Fatal(err) } defer bio.MustClose(out) buf := bufio.NewWriter(bio.MustWriter(out)) fmt.Fprintf(buf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion()) fmt.Fprintf(buf, "!\n") lexer := lex.NewLexer(flag.Arg(0), ctxt) parser := asm.NewParser(ctxt, architecture, lexer) diag := false ctxt.DiagFunc = func(format string, args ...interface{}) { diag = true log.Printf(format, args...) } pList := obj.Linknewplist(ctxt) var ok bool pList.Firstpc, ok = parser.Parse() if ok { // reports errors to parser.Errorf obj.Writeobjdirect(ctxt, buf) } if !ok || diag { log.Printf("assembly of %s failed", flag.Arg(0)) os.Remove(*flags.OutputFile) os.Exit(1) } buf.Flush() }
func doversion() { p := obj.Expstring() if p == "X:none" { p = "" } sep := "" if p != "" { sep = " " } fmt.Printf("%cg version %s%s%s\n", Thearch.Thechar, obj.Getgoversion(), sep, p) os.Exit(0) }
func doversion() { p := obj.Expstring() if p == "X:none" { p = "" } sep := "" if p != "" { sep = " " } fmt.Printf("compile version %s%s%s\n", obj.Getgoversion(), sep, p) os.Exit(0) }
func main() { log.SetFlags(0) log.SetPrefix("asm: ") GOARCH := obj.Getgoarch() architecture := arch.Set(GOARCH) if architecture == nil { log.Fatalf("asm: unrecognized architecture %s", GOARCH) } flags.Parse(architecture.Thechar) // Create object file, write header. fd, err := os.Create(*flags.OutputFile) if err != nil { log.Fatal(err) } ctxt := obj.Linknew(architecture.LinkArch) if *flags.PrintOut { ctxt.Debugasm = 1 } ctxt.LineHist.TrimPathPrefix = *flags.TrimPath ctxt.Flag_dynlink = *flags.Dynlink if *flags.Shared || *flags.Dynlink { ctxt.Flag_shared = 1 } ctxt.Bso = obj.Binitw(os.Stdout) defer ctxt.Bso.Flush() ctxt.Diag = log.Fatalf output := obj.Binitw(fd) fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion()) fmt.Fprintf(output, "!\n") lexer := lex.NewLexer(flag.Arg(0), ctxt) parser := asm.NewParser(ctxt, architecture, lexer) pList := obj.Linknewplist(ctxt) var ok bool pList.Firstpc, ok = parser.Parse() if !ok { log.Printf("asm: assembly of %s failed", flag.Arg(0)) os.Remove(*flags.OutputFile) os.Exit(1) } obj.Writeobjdirect(ctxt, output) output.Flush() }
func Fatalf(fmt_ string, args ...interface{}) { Flusherrors() fmt.Printf("%v: internal compiler error: ", linestr(lineno)) fmt.Printf(fmt_, args...) fmt.Printf("\n") // If this is a released compiler version, ask for a bug report. if strings.HasPrefix(obj.Getgoversion(), "release") { fmt.Printf("\n") fmt.Printf("Please file a bug report including a short program that triggers the error.\n") fmt.Printf("https://golang.org/issue/new\n") } hcrash() errorexit() }
func writebench(filename string) error { f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666) if err != nil { return err } var buf bytes.Buffer fmt.Fprintln(&buf, "commit:", obj.Getgoversion()) fmt.Fprintln(&buf, "goos:", runtime.GOOS) fmt.Fprintln(&buf, "goarch:", runtime.GOARCH) timings.Write(&buf, "BenchmarkCompile:"+myimportpath+":") n, err := f.Write(buf.Bytes()) if err != nil { return err } if n != buf.Len() { panic("bad writer") } return f.Close() }
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 doversion() { fmt.Printf("%cl version %s\n", Thearch.Thechar, obj.Getgoversion()) Errorexit() }
func importfile(f *Val, line int) { if f.Ctype != CTSTR { Yyerror("import statement not a string") fakeimport() return } if len(f.U.Sval) == 0 { Yyerror("import path is empty") fakeimport() return } if isbadimport(f.U.Sval) { 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.Sval == "main" { Yyerror("cannot import \"main\"") errorexit() } if myimportpath != "" && f.U.Sval == myimportpath { Yyerror("import %q while compiling that package (import cycle)", f.U.Sval) errorexit() } if f.U.Sval == "unsafe" { if safemode != 0 { Yyerror("cannot import package unsafe") errorexit() } importpkg = mkpkg(f.U.Sval) cannedimports("unsafe.6", unsafeimport) imported_unsafe = 1 return } path_ := f.U.Sval 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.Sval) 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 != 0 { tag := "" if importpkg.Safe { tag = "safe" } p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag) cannedimports(file, p) return } importpkg.Imported = 1 var err error var imp *obj.Biobuf imp, err = obj.Bopenr(file) if err != nil { Yyerror("can't open import: %q: %v", f.U.Sval, 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. linehist(file[len(file)-len(path_)-2:], -1, 1) // acts as #pragma lib /* * position the input right * after $$ and return */ pushedio = curio curio.bin = imp curio.peekc = 0 curio.peekc1 = 0 curio.infile = file curio.nlsemi = 0 typecheckok = 1 var c int32 for { c = int32(getc()) if c == EOF { break } if c != '$' { continue } c = int32(getc()) if c == EOF { break } if c != '$' { continue } return } Yyerror("no import in %q", f.U.Sval) unimportfile() }
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 { 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 impf, err := os.Open(file) if err != nil { Yyerror("can't open import: %q: %v", path_, err) errorexit() } defer impf.Close() imp := bufio.NewReader(impf) if strings.HasSuffix(file, ".a") { if !skiptopkgdef(imp) { Yyerror("import %s: not a package file", file) errorexit() } } // check object header p, err := imp.ReadString('\n') if err != nil { log.Fatalf("reading input: %v", err) } if len(p) > 0 { p = p[:len(p)-1] } if p != "empty archive" { if !strings.HasPrefix(p, "go object ") { Yyerror("import %s: not a go object file: %s", file, p) 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() } } // process header lines for { p, err = imp.ReadString('\n') if err != nil { log.Fatalf("reading input: %v", err) } if p == "\n" { break // header ends with blank line } if strings.HasPrefix(p, "safe") { importpkg.Safe = true break // ok to ignore rest } } // 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 (textual format): not supported anymore // $$B\n (binary format) : import directly, then feed the lexer a dummy statement // look for $$ var c byte for { c, err = imp.ReadByte() if err != nil { break } if c == '$' { c, err = imp.ReadByte() if c == '$' || err != nil { break } } } // get character after $$ if err == nil { c, _ = imp.ReadByte() } switch c { case '\n': Yyerror("cannot import %s: old export format no longer supported (recompile library)", path_) case 'B': if Debug_export != 0 { fmt.Printf("importing %s (%s)\n", path_, file) } imp.ReadByte() // skip \n after $$B Import(imp) default: Yyerror("no import in %q", path_) errorexit() } if safemode && !importpkg.Safe { Yyerror("cannot import unsafe package %q", importpkg.Path) } }
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 dumpobj1(outfile string, mode int) { var err error bout, err = bio.Create(outfile) if err != nil { Flusherrors() fmt.Printf("can't create %s: %v\n", outfile, err) errorexit() } startobj := int64(0) var arhdr [ArhdrSize]byte if writearchive { bout.WriteString("!<arch>\n") arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) startobj = bout.Offset() } printheader := func() { fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) if buildid != "" { fmt.Fprintf(bout, "build id %q\n", buildid) } if localpkg.Name == "main" { fmt.Fprintf(bout, "main\n") } if safemode { fmt.Fprintf(bout, "safe\n") } else { fmt.Fprintf(bout, "----\n") // room for some other tool to write "safe" } fmt.Fprintf(bout, "\n") // header ends with blank line } printheader() if mode&modeCompilerObj != 0 { dumpexport() } if writearchive { bout.Flush() size := bout.Offset() - startobj if size&1 != 0 { bout.WriteByte(0) } bout.Seek(startobj-ArhdrSize, 0) formathdr(arhdr[:], "__.PKGDEF", size) bout.Write(arhdr[:]) bout.Flush() bout.Seek(startobj+size+(size&1), 0) } if mode&modeLinkerObj == 0 { bout.Close() return } if writearchive { // start object file arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) startobj = bout.Offset() printheader() } if pragcgobuf != "" { if writearchive { // write empty export section; must be before cgo section fmt.Fprintf(bout, "\n$$\n\n$$\n\n") } fmt.Fprintf(bout, "\n$$ // cgo\n") fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf) } fmt.Fprintf(bout, "\n!\n") externs := len(externdcl) dumpglobls() dumptypestructs() // Dump extra globals. tmp := externdcl if externdcl != nil { externdcl = externdcl[externs:] } dumpglobls() externdcl = tmp if zerosize > 0 { zero := Pkglookup("zero", mappkg) ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA) } dumpdata() obj.Writeobjdirect(Ctxt, bout.Writer) if writearchive { bout.Flush() size := bout.Offset() - startobj if size&1 != 0 { bout.WriteByte(0) } bout.Seek(startobj-ArhdrSize, 0) formathdr(arhdr[:], "_go_.o", size) bout.Write(arhdr[:]) } bout.Close() }
func dumpobj() { var err error bout, err = obj.Bopenw(outfile) if err != nil { Flusherrors() fmt.Printf("can't create %s: %v\n", outfile, err) errorexit() } startobj := int64(0) var arhdr [ArhdrSize]byte if writearchive != 0 { obj.Bwritestring(bout, "!<arch>\n") arhdr = [ArhdrSize]byte{} obj.Bwrite(bout, arhdr[:]) startobj = obj.Boffset(bout) } fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) dumpexport() if writearchive != 0 { obj.Bflush(bout) size := obj.Boffset(bout) - startobj if size&1 != 0 { obj.Bputc(bout, 0) } obj.Bseek(bout, startobj-ArhdrSize, 0) formathdr(arhdr[:], "__.PKGDEF", size) obj.Bwrite(bout, arhdr[:]) obj.Bflush(bout) obj.Bseek(bout, startobj+size+(size&1), 0) arhdr = [ArhdrSize]byte{} obj.Bwrite(bout, arhdr[:]) startobj = obj.Boffset(bout) fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) } if pragcgobuf != "" { if writearchive != 0 { // write empty export section; must be before cgo section fmt.Fprintf(bout, "\n$$\n\n$$\n\n") } fmt.Fprintf(bout, "\n$$ // cgo\n") fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf) } fmt.Fprintf(bout, "\n!\n") var externs *NodeList if externdcl != nil { externs = externdcl.End } dumpglobls() dumptypestructs() // Dump extra globals. tmp := externdcl if externs != nil { externdcl = externs.Next } dumpglobls() externdcl = tmp zero := Pkglookup("zerovalue", Runtimepkg) ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA) dumpdata() obj.Writeobjdirect(Ctxt, bout) if writearchive != 0 { obj.Bflush(bout) size := obj.Boffset(bout) - startobj if size&1 != 0 { obj.Bputc(bout, 0) } obj.Bseek(bout, startobj-ArhdrSize, 0) name := fmt.Sprintf("_go_.%c", Thearch.Thechar) formathdr(arhdr[:], name, size) obj.Bwrite(bout, arhdr[:]) } obj.Bterm(bout) }
func doversion() { Exitf("version %s", obj.Getgoversion()) }
func dumpobj() { var err error bout, err = obj.Bopenw(outfile) if err != nil { Flusherrors() fmt.Printf("can't create %s: %v\n", outfile, err) errorexit() } startobj := int64(0) var arhdr [ArhdrSize]byte if writearchive != 0 { obj.Bwritestring(bout, "!<arch>\n") arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) startobj = obj.Boffset(bout) } fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) dumpexport() if writearchive != 0 { bout.Flush() size := obj.Boffset(bout) - startobj if size&1 != 0 { obj.Bputc(bout, 0) } obj.Bseek(bout, startobj-ArhdrSize, 0) formathdr(arhdr[:], "__.PKGDEF", size) bout.Write(arhdr[:]) bout.Flush() obj.Bseek(bout, startobj+size+(size&1), 0) arhdr = [ArhdrSize]byte{} bout.Write(arhdr[:]) startobj = obj.Boffset(bout) fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring()) } if pragcgobuf != "" { if writearchive != 0 { // write empty export section; must be before cgo section fmt.Fprintf(bout, "\n$$\n\n$$\n\n") } fmt.Fprintf(bout, "\n$$ // cgo\n") fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf) } fmt.Fprintf(bout, "\n!\n") externs := len(externdcl) dumpglobls() dumptypestructs() // Dump extra globals. tmp := externdcl if externdcl != nil { externdcl = externdcl[externs:] } dumpglobls() externdcl = tmp dumpdata() obj.Writeobjdirect(Ctxt, bout) if writearchive != 0 { bout.Flush() size := obj.Boffset(bout) - startobj if size&1 != 0 { obj.Bputc(bout, 0) } obj.Bseek(bout, startobj-ArhdrSize, 0) formathdr(arhdr[:], "_go_.o", size) bout.Write(arhdr[:]) } obj.Bterm(bout) }
// 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)) } }