func addinitarray() (c *IMAGE_SECTION_HEADER) { // The size below was determined by the specification for array relocations, // and by observing what GCC writes here. If the initarray section grows to // contain more than one constructor entry, the size will need to be 8 * constructor_count. // However, the entire Go runtime is initialized from just one function, so it is unlikely // that this will need to grow in the future. var size int switch obj.Getgoarch() { default: fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch()) os.Exit(2) case "386": size = 4 case "amd64": size = 8 } c = addpesection(".ctors", size, size) c.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ c.SizeOfRawData = uint32(size) Cseek(int64(c.PointerToRawData)) chksectoff(c, Cpos()) init_entry := Linklookup(Ctxt, INITENTRY, 0) addr := uint64(init_entry.Value) - init_entry.Sect.Vaddr switch obj.Getgoarch() { case "386": Lputl(uint32(addr)) case "amd64": Vputl(addr) } return c }
func main() { // disable timestamps for reproducible output log.SetFlags(0) log.SetPrefix("compile: ") switch obj.Getgoarch() { default: fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.Getgoarch()) os.Exit(2) case "386": x86.Main() case "amd64", "amd64p32": amd64.Main() case "arm": arm.Main() case "arm64": arm64.Main() case "mips64", "mips64le": mips64.Main() case "ppc64", "ppc64le": ppc64.Main() case "s390x": s390x.Main() } }
func Main() { gc.Thearch.LinkArch = &x86.Linkamd64 if obj.Getgoarch() == "amd64p32" { gc.Thearch.LinkArch = &x86.Linkamd64p32 } gc.Thearch.REGSP = x86.REGSP gc.Thearch.REGCTXT = x86.REGCTXT gc.Thearch.REGCALLX = x86.REG_BX gc.Thearch.REGCALLX2 = x86.REG_AX gc.Thearch.REGRETURN = x86.REG_AX gc.Thearch.REGMIN = x86.REG_AX gc.Thearch.REGMAX = x86.REG_R15 gc.Thearch.FREGMIN = x86.REG_X0 gc.Thearch.FREGMAX = x86.REG_X15 gc.Thearch.MAXWIDTH = 1 << 50 gc.Thearch.AddIndex = addindex gc.Thearch.Betypeinit = betypeinit gc.Thearch.Cgen_bmul = cgen_bmul gc.Thearch.Cgen_hmul = cgen_hmul gc.Thearch.Cgen_shift = cgen_shift gc.Thearch.Clearfat = clearfat gc.Thearch.Defframe = defframe gc.Thearch.Dodiv = dodiv gc.Thearch.Excise = excise gc.Thearch.Expandchecks = expandchecks gc.Thearch.Getg = getg gc.Thearch.Gins = gins gc.Thearch.Ginsboolval = ginsboolval gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove gc.Thearch.Peep = peep gc.Thearch.Proginfo = proginfo gc.Thearch.Regtyp = regtyp gc.Thearch.Sameaddr = sameaddr gc.Thearch.Smallindir = smallindir gc.Thearch.Stackaddr = stackaddr gc.Thearch.Blockcopy = blockcopy gc.Thearch.Sudoaddable = sudoaddable gc.Thearch.Sudoclean = sudoclean gc.Thearch.Excludedregs = excludedregs gc.Thearch.RtoB = RtoB gc.Thearch.FtoB = FtoB gc.Thearch.BtoR = BtoR gc.Thearch.BtoF = BtoF gc.Thearch.Optoas = optoas gc.Thearch.Doregbits = doregbits gc.Thearch.Regnames = regnames gc.Thearch.SSARegToReg = ssaRegToReg gc.Thearch.SSAMarkMoves = ssaMarkMoves gc.Thearch.SSAGenValue = ssaGenValue gc.Thearch.SSAGenBlock = ssaGenBlock gc.Main() gc.Exit(0) }
func Main() { gc.Thearch.LinkArch = &ppc64.Linkppc64 if obj.Getgoarch() == "ppc64le" { gc.Thearch.LinkArch = &ppc64.Linkppc64le } gc.Thearch.REGSP = ppc64.REGSP gc.Thearch.REGCTXT = ppc64.REGCTXT gc.Thearch.REGCALLX = ppc64.REG_R3 gc.Thearch.REGCALLX2 = ppc64.REG_R4 gc.Thearch.REGRETURN = ppc64.REG_R3 gc.Thearch.REGMIN = ppc64.REG_R0 gc.Thearch.REGMAX = ppc64.REG_R31 gc.Thearch.FREGMIN = ppc64.REG_F0 gc.Thearch.FREGMAX = ppc64.REG_F31 gc.Thearch.MAXWIDTH = 1 << 50 gc.Thearch.ReservedRegs = resvd gc.Thearch.Betypeinit = betypeinit gc.Thearch.Cgen_hmul = cgen_hmul gc.Thearch.Cgen_shift = cgen_shift gc.Thearch.Clearfat = clearfat gc.Thearch.Defframe = defframe gc.Thearch.Dodiv = dodiv gc.Thearch.Excise = excise gc.Thearch.Expandchecks = expandchecks gc.Thearch.Getg = getg gc.Thearch.Gins = gins gc.Thearch.Ginscmp = ginscmp gc.Thearch.Ginscon = ginscon gc.Thearch.Ginsnop = ginsnop gc.Thearch.Gmove = gmove gc.Thearch.Peep = peep gc.Thearch.Proginfo = proginfo gc.Thearch.Regtyp = regtyp gc.Thearch.Sameaddr = sameaddr gc.Thearch.Smallindir = smallindir gc.Thearch.Stackaddr = stackaddr gc.Thearch.Blockcopy = blockcopy gc.Thearch.Sudoaddable = sudoaddable gc.Thearch.Sudoclean = sudoclean gc.Thearch.Excludedregs = excludedregs gc.Thearch.RtoB = RtoB gc.Thearch.FtoB = RtoB gc.Thearch.BtoR = BtoR gc.Thearch.BtoF = BtoF gc.Thearch.Optoas = optoas gc.Thearch.Doregbits = doregbits gc.Thearch.Regnames = regnames initvariants() initproginfo() gc.Main() gc.Exit(0) }
func main() { switch obj.Getgoarch() { default: fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.Getgoarch()) os.Exit(2) case "386": x86.Main() case "amd64", "amd64p32": amd64.Main() case "arm": arm.Main() case "arm64": arm64.Main() case "mips64", "mips64le": mips64.Main() case "ppc64", "ppc64le": ppc64.Main() case "s390x": s390x.Main() } }
func betypeinit() { if obj.Getgoarch() == "amd64p32" { addptr = x86.AADDL movptr = x86.AMOVL leaptr = x86.ALEAL cmpptr = x86.ACMPL } if gc.Ctxt.Flag_dynlink || obj.Getgoos() == "nacl" { resvd = append(resvd, x86.REG_R15) } if gc.Ctxt.Framepointer_enabled || obj.Getgoos() == "nacl" { resvd = append(resvd, x86.REG_BP) } gc.Thearch.ReservedRegs = resvd }
func linkarchinit() { if obj.Getgoarch() == "ppc64le" { ld.SysArch = sys.ArchPPC64LE } else { ld.SysArch = sys.ArchPPC64 } ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant ld.Thearch.Asmb = asmb ld.Thearch.Elfreloc1 = elfreloc1 ld.Thearch.Elfsetupplt = elfsetupplt ld.Thearch.Gentext = gentext ld.Thearch.Machoreloc1 = machoreloc1 if ld.SysArch == sys.ArchPPC64LE { ld.Thearch.Lput = ld.Lputl ld.Thearch.Wput = ld.Wputl ld.Thearch.Vput = ld.Vputl ld.Thearch.Append16 = ld.Append16l ld.Thearch.Append32 = ld.Append32l ld.Thearch.Append64 = ld.Append64l } else { ld.Thearch.Lput = ld.Lputb ld.Thearch.Wput = ld.Wputb ld.Thearch.Vput = ld.Vputb ld.Thearch.Append16 = ld.Append16b ld.Thearch.Append32 = ld.Append32b ld.Thearch.Append64 = ld.Append64b } // TODO(austin): ABI v1 uses /usr/lib/ld.so.1 ld.Thearch.Linuxdynld = "/lib64/ld64.so.1" ld.Thearch.Freebsddynld = "XXX" ld.Thearch.Openbsddynld = "XXX" ld.Thearch.Netbsddynld = "XXX" ld.Thearch.Dragonflydynld = "XXX" ld.Thearch.Solarisdynld = "XXX" }
func linkarchinit() { ld.SysArch = sys.ArchAMD64 if obj.Getgoarch() == "amd64p32" { ld.SysArch = sys.ArchAMD64P32 } ld.Thearch.Funcalign = FuncAlign ld.Thearch.Maxalign = MaxAlign ld.Thearch.Minalign = MinAlign ld.Thearch.Dwarfregsp = DWARFREGSP ld.Thearch.Dwarfreglr = DWARFREGLR ld.Thearch.Adddynrel = adddynrel ld.Thearch.Archinit = archinit ld.Thearch.Archreloc = archreloc ld.Thearch.Archrelocvariant = archrelocvariant ld.Thearch.Asmb = asmb ld.Thearch.Elfreloc1 = elfreloc1 ld.Thearch.Elfsetupplt = elfsetupplt ld.Thearch.Gentext = gentext ld.Thearch.Machoreloc1 = machoreloc1 ld.Thearch.PEreloc1 = pereloc1 ld.Thearch.Lput = ld.Lputl ld.Thearch.Wput = ld.Wputl ld.Thearch.Vput = ld.Vputl ld.Thearch.Append16 = ld.Append16l ld.Thearch.Append32 = ld.Append32l ld.Thearch.Append64 = ld.Append64l ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2" ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1" ld.Thearch.Openbsddynld = "/usr/libexec/ld.so" ld.Thearch.Netbsddynld = "/libexec/ld.elf_so" ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2" ld.Thearch.Solarisdynld = "/lib/amd64/ld.so.1" }
func linknew(arch *sys.Arch) *Link { ctxt := &Link{ Hash: []map[string]*LSym{ // preallocate about 2mb for hash of // non static symbols make(map[string]*LSym, 100000), }, Allsym: make([]*LSym, 0, 100000), Arch: arch, Goroot: obj.Getgoroot(), } p := obj.Getgoarch() if p != arch.Name { log.Fatalf("invalid goarch %s (want %s)", p, arch.Name) } ctxt.Headtype = headtype(obj.Getgoos()) if ctxt.Headtype < 0 { log.Fatalf("unknown goos %s", obj.Getgoos()) } // Record thread-local storage offset. // TODO(rsc): Move tlsoffset back into the linker. switch ctxt.Headtype { default: log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype)) case obj.Hplan9, obj.Hwindows: break /* * ELF uses TLS offset negative from FS. * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS). * Known to low-level assembly in package runtime and runtime/cgo. */ case obj.Hlinux, obj.Hfreebsd, obj.Hnetbsd, obj.Hopenbsd, obj.Hdragonfly, obj.Hsolaris: if obj.Getgoos() == "android" { switch ctxt.Arch.Family { case sys.AMD64: // Android/amd64 constant - offset from 0(FS) to our TLS slot. // Explained in src/runtime/cgo/gcc_android_*.c ctxt.Tlsoffset = 0x1d0 case sys.I386: // Android/386 constant - offset from 0(GS) to our TLS slot. ctxt.Tlsoffset = 0xf8 default: ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize } } else { ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize } case obj.Hnacl: switch ctxt.Arch.Family { default: log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name) case sys.ARM: ctxt.Tlsoffset = 0 case sys.AMD64: ctxt.Tlsoffset = 0 case sys.I386: ctxt.Tlsoffset = -8 } /* * OS X system constants - offset from 0(GS) to our TLS. * Explained in src/runtime/cgo/gcc_darwin_*.c. */ case obj.Hdarwin: switch ctxt.Arch.Family { default: log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name) case sys.ARM: ctxt.Tlsoffset = 0 // dummy value, not needed case sys.AMD64: ctxt.Tlsoffset = 0x8a0 case sys.ARM64: ctxt.Tlsoffset = 0 // dummy value, not needed case sys.I386: ctxt.Tlsoffset = 0x468 } } // On arm, record goarm. if ctxt.Arch.Family == sys.ARM { ctxt.Goarm = obj.Getgoarm() } return ctxt }
// peemitreloc emits relocation entries for go.o in external linking. func peemitreloc(text, data, ctors *IMAGE_SECTION_HEADER) { for Cpos()&7 != 0 { Cput(0) } text.PointerToRelocations = uint32(Cpos()) // first entry: extended relocs Lputl(0) // placeholder for number of relocation + 1 Lputl(0) Wputl(0) n := perelocsect(Segtext.Sect, Ctxt.Textp) + 1 for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next { n += perelocsect(sect, datap) } cpos := Cpos() Cseek(int64(text.PointerToRelocations)) Lputl(uint32(n)) Cseek(cpos) if n > 0x10000 { n = 0x10000 text.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL } else { text.PointerToRelocations += 10 // skip the extend reloc entry } text.NumberOfRelocations = uint16(n - 1) data.PointerToRelocations = uint32(cpos) // first entry: extended relocs Lputl(0) // placeholder for number of relocation + 1 Lputl(0) Wputl(0) n = 1 for sect := Segdata.Sect; sect != nil; sect = sect.Next { n += perelocsect(sect, datap) } cpos = Cpos() Cseek(int64(data.PointerToRelocations)) Lputl(uint32(n)) Cseek(cpos) if n > 0x10000 { n = 0x10000 data.Characteristics |= IMAGE_SCN_LNK_NRELOC_OVFL } else { data.PointerToRelocations += 10 // skip the extend reloc entry } data.NumberOfRelocations = uint16(n - 1) dottext := Linklookup(Ctxt, ".text", 0) ctors.NumberOfRelocations = 1 ctors.PointerToRelocations = uint32(Cpos()) sectoff := ctors.VirtualAddress Lputl(sectoff) Lputl(uint32(dottext.Dynid)) switch obj.Getgoarch() { default: fmt.Fprintf(os.Stderr, "link: unknown architecture for PE: %q\n", obj.Getgoarch()) os.Exit(2) case "386": Wputl(IMAGE_REL_I386_DIR32) case "amd64": Wputl(IMAGE_REL_AMD64_ADDR64) } }
func Main() { defer hidePanic() goarch = obj.Getgoarch() Ctxt = obj.Linknew(Thearch.LinkArch) Ctxt.DiagFunc = Yyerror bstdout = bufio.NewWriter(os.Stdout) Ctxt.Bso = bstdout localpkg = mkpkg("") localpkg.Prefix = "\"\"" autopkg = mkpkg("") autopkg.Prefix = "\"\"" // pseudo-package, for scoping builtinpkg = mkpkg("go.builtin") builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin // pseudo-package, accessed by import "unsafe" unsafepkg = mkpkg("unsafe") unsafepkg.Name = "unsafe" // real package, referred to by generated runtime calls Runtimepkg = mkpkg("runtime") Runtimepkg.Name = "runtime" // pseudo-packages used in symbol tables itabpkg = mkpkg("go.itab") itabpkg.Name = "go.itab" itabpkg.Prefix = "go.itab" // not go%2eitab itablinkpkg = mkpkg("go.itablink") itablinkpkg.Name = "go.itablink" itablinkpkg.Prefix = "go.itablink" // not go%2eitablink trackpkg = mkpkg("go.track") trackpkg.Name = "go.track" trackpkg.Prefix = "go.track" // not go%2etrack typepkg = mkpkg("type") typepkg.Name = "type" // pseudo-package used for map zero values mappkg = mkpkg("go.map") mappkg.Name = "go.map" mappkg.Prefix = "go.map" goroot = obj.Getgoroot() goos = obj.Getgoos() Nacl = goos == "nacl" if Nacl { flag_largemodel = true } flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime") obj.Flagcount("%", "debug non-static initializers", &Debug['%']) obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A']) obj.Flagcount("B", "disable bounds checking", &Debug['B']) flag.StringVar(&localimport, "D", "", "set relative `path` for local imports") obj.Flagcount("E", "debug symbol export", &Debug['E']) obj.Flagfn1("I", "add `directory` to import search path", addidir) obj.Flagcount("K", "debug missing line numbers", &Debug['K']) obj.Flagcount("M", "debug move generation", &Debug['M']) obj.Flagcount("N", "disable optimizations", &Debug['N']) obj.Flagcount("P", "debug peephole optimizer", &Debug['P']) obj.Flagcount("R", "debug register optimizer", &Debug['R']) obj.Flagcount("S", "print assembly listing", &Debug['S']) obj.Flagfn0("V", "print compiler version", doversion) obj.Flagcount("W", "debug parse tree after type checking", &Debug['W']) flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`") flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata") flag.BoolVar(&pure_go, "complete", false, "compiling complete package (no C or assembly)") flag.StringVar(&debugstr, "d", "", "print debug information about items in `list`") obj.Flagcount("e", "no limit on number of errors reported", &Debug['e']) obj.Flagcount("f", "debug stack frames", &Debug['f']) obj.Flagcount("g", "debug code generation", &Debug['g']) obj.Flagcount("h", "halt on error", &Debug['h']) obj.Flagcount("i", "debug line number stack", &Debug['i']) obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap) flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`") obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j']) obj.Flagcount("l", "disable inlining", &Debug['l']) flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") obj.Flagcount("live", "debug liveness analysis", &debuglive) obj.Flagcount("m", "print optimization decisions", &Debug['m']) flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") flag.BoolVar(&newexport, "newexport", true, "use new export format") // TODO(gri) remove eventually (issue 15323) flag.BoolVar(&nolocalimports, "nolocalimports", false, "reject local (relative) imports") flag.StringVar(&outfile, "o", "", "write output to `file`") flag.StringVar(&myimportpath, "p", "", "set expected package import `path`") flag.BoolVar(&writearchive, "pack", false, "write package file instead of object file") obj.Flagcount("r", "debug generated wrappers", &Debug['r']) flag.BoolVar(&flag_race, "race", false, "enable race detector") obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s']) flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths") flag.BoolVar(&safemode, "u", false, "reject unsafe code") obj.Flagcount("v", "increase debug verbosity", &Debug['v']) obj.Flagcount("w", "debug type checking", &Debug['w']) flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier") obj.Flagcount("x", "debug lexer", &Debug['x']) var flag_shared bool var flag_dynlink bool if supportsDynlink(Thearch.LinkArch.Arch) { flag.BoolVar(&flag_shared, "shared", false, "generate code that can be linked into a shared library") flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries") } if Thearch.LinkArch.Family == sys.AMD64 { flag.BoolVar(&flag_largemodel, "largemodel", false, "generate code that assumes a large memory model") } flag.StringVar(&cpuprofile, "cpuprofile", "", "write cpu profile to `file`") flag.StringVar(&memprofile, "memprofile", "", "write memory profile to `file`") flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`") flag.BoolVar(&ssaEnabled, "ssa", true, "use SSA backend to generate code") obj.Flagparse(usage) Ctxt.Flag_shared = flag_dynlink || flag_shared Ctxt.Flag_dynlink = flag_dynlink Ctxt.Flag_optimize = Debug['N'] == 0 Ctxt.Debugasm = int32(Debug['S']) Ctxt.Debugvlog = int32(Debug['v']) if flag.NArg() < 1 { usage() } startProfile() if flag_race { racepkg = mkpkg("runtime/race") racepkg.Name = "race" } if flag_msan { msanpkg = mkpkg("runtime/msan") msanpkg.Name = "msan" } if flag_race && flag_msan { log.Fatal("cannot use both -race and -msan") } else if flag_race || flag_msan { instrumenting = true } // parse -d argument if debugstr != "" { Split: for _, name := range strings.Split(debugstr, ",") { if name == "" { continue } val := 1 if i := strings.Index(name, "="); i >= 0 { var err error val, err = strconv.Atoi(name[i+1:]) if err != nil { log.Fatalf("invalid debug value %v", name) } name = name[:i] } for _, t := range debugtab { if t.name == name { if t.val != nil { *t.val = val continue Split } } } // special case for ssa for now if strings.HasPrefix(name, "ssa/") { // expect form ssa/phase/flag // e.g. -d=ssa/generic_cse/time // _ in phase name also matches space phase := name[4:] flag := "debug" // default flag is debug if i := strings.Index(phase, "/"); i >= 0 { flag = phase[i+1:] phase = phase[:i] } err := ssa.PhaseOption(phase, flag, val) if err != "" { log.Fatalf(err) } continue Split } log.Fatalf("unknown debug key -d %s\n", name) } } // enable inlining. for now: // default: inlining on. (debug['l'] == 1) // -l: inlining off (debug['l'] == 0) // -ll, -lll: inlining on again, with extra debugging (debug['l'] > 1) if Debug['l'] <= 1 { Debug['l'] = 1 - Debug['l'] } Thearch.Betypeinit() Widthint = Thearch.LinkArch.IntSize Widthptr = Thearch.LinkArch.PtrSize Widthreg = Thearch.LinkArch.RegSize initUniverse() blockgen = 1 dclcontext = PEXTERN nerrors = 0 lexlineno = 1 loadsys() for _, infile = range flag.Args() { if trace && Debug['x'] != 0 { fmt.Printf("--- %s ---\n", infile) } linehistpush(infile) f, err := os.Open(infile) if err != nil { fmt.Printf("open %s: %v\n", infile, err) errorexit() } bin := bufio.NewReader(f) // Skip initial BOM if present. if r, _, _ := bin.ReadRune(); r != BOM { bin.UnreadRune() } block = 1 iota_ = -1000000 imported_unsafe = false parse_file(bin) if nsyntaxerrors != 0 { errorexit() } // Instead of converting EOF into '\n' in getc and count it as an extra line // for the line history to work, and which then has to be corrected elsewhere, // just add a line here. lexlineno++ linehistpop() f.Close() } testdclstack() mkpackage(localpkg.Name) // final import not used checks finishUniverse() typecheckok = true if Debug['f'] != 0 { frame(1) } // Process top-level declarations in phases. // Phase 1: const, type, and names and types of funcs. // This will gather all the information about types // and methods but doesn't depend on any of it. defercheckwidth() // Don't use range--typecheck can add closures to xtop. for i := 0; i < len(xtop); i++ { if xtop[i].Op != ODCL && xtop[i].Op != OAS && xtop[i].Op != OAS2 { xtop[i] = typecheck(xtop[i], Etop) } } // Phase 2: Variable assignments. // To check interface assignments, depends on phase 1. // Don't use range--typecheck can add closures to xtop. for i := 0; i < len(xtop); i++ { if xtop[i].Op == ODCL || xtop[i].Op == OAS || xtop[i].Op == OAS2 { xtop[i] = typecheck(xtop[i], Etop) } } resumecheckwidth() // Phase 3: Type check function bodies. // Don't use range--typecheck can add closures to xtop. for i := 0; i < len(xtop); i++ { if xtop[i].Op == ODCLFUNC || xtop[i].Op == OCLOSURE { Curfn = xtop[i] decldepth = 1 saveerrors() typecheckslice(Curfn.Nbody.Slice(), Etop) checkreturn(Curfn) if nerrors != 0 { Curfn.Nbody.Set(nil) // type errors; do not compile } } } // Phase 4: Decide how to capture closed variables. // This needs to run before escape analysis, // because variables captured by value do not escape. for _, n := range xtop { if n.Op == ODCLFUNC && n.Func.Closure != nil { Curfn = n capturevars(n) } } Curfn = nil if nsavederrors+nerrors != 0 { errorexit() } // Phase 5: Inlining if Debug['l'] > 1 { // Typecheck imported function bodies if debug['l'] > 1, // otherwise lazily when used or re-exported. for _, n := range importlist { if n.Func.Inl.Len() != 0 { saveerrors() typecheckinl(n) } } if nsavederrors+nerrors != 0 { errorexit() } } if Debug['l'] != 0 { // Find functions that can be inlined and clone them before walk expands them. visitBottomUp(xtop, func(list []*Node, recursive bool) { for _, n := range list { if n.Op == ODCLFUNC { caninl(n) inlcalls(n) } } }) } // Phase 6: Escape analysis. // Required for moving heap allocations onto stack, // which in turn is required by the closure implementation, // which stores the addresses of stack variables into the closure. // If the closure does not escape, it needs to be on the stack // or else the stack copier will not update it. // Large values are also moved off stack in escape analysis; // because large values may contain pointers, it must happen early. escapes(xtop) // Phase 7: Transform closure bodies to properly reference captured variables. // This needs to happen before walk, because closures must be transformed // before walk reaches a call of a closure. for _, n := range xtop { if n.Op == ODCLFUNC && n.Func.Closure != nil { Curfn = n transformclosure(n) } } Curfn = nil // Phase 8: Compile top level functions. // Don't use range--walk can add functions to xtop. for i := 0; i < len(xtop); i++ { if xtop[i].Op == ODCLFUNC { funccompile(xtop[i]) } } if nsavederrors+nerrors == 0 { fninit(xtop) } if compiling_runtime { checknowritebarrierrec() } // Phase 9: Check external declarations. for i, n := range externdcl { if n.Op == ONAME { externdcl[i] = typecheck(externdcl[i], Erv) } } if nerrors+nsavederrors != 0 { errorexit() } dumpobj() if asmhdr != "" { dumpasmhdr() } if nerrors+nsavederrors != 0 { errorexit() } Flusherrors() }
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 (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 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': // old export format parse_import(imp, indent) case 'B': // new export format 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) } }