| // Copyright 2014 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package main |
| |
| import ( |
| "bufio" |
| "flag" |
| "fmt" |
| "internal/buildcfg" |
| "log" |
| "os" |
| |
| "cmd/asm/internal/arch" |
| "cmd/asm/internal/asm" |
| "cmd/asm/internal/flags" |
| "cmd/asm/internal/lex" |
| |
| "cmd/internal/bio" |
| "cmd/internal/obj" |
| "cmd/internal/objabi" |
| "cmd/internal/telemetry/counter" |
| ) |
| |
| func main() { |
| log.SetFlags(0) |
| log.SetPrefix("asm: ") |
| counter.Open() |
| |
| buildcfg.Check() |
| GOARCH := buildcfg.GOARCH |
| |
| flags.Parse() |
| counter.Inc("asm/invocations") |
| counter.CountFlags("asm/flag:", *flag.CommandLine) |
| |
| architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink) |
| if architecture == nil { |
| log.Fatalf("unrecognized architecture %s", GOARCH) |
| } |
| ctxt := obj.Linknew(architecture.LinkArch) |
| ctxt.Debugasm = flags.PrintOut |
| ctxt.Debugvlog = flags.DebugV |
| ctxt.Flag_dynlink = *flags.Dynlink |
| ctxt.Flag_linkshared = *flags.Linkshared |
| ctxt.Flag_shared = *flags.Shared || *flags.Dynlink |
| ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack |
| ctxt.Debugpcln = flags.DebugFlags.PCTab |
| ctxt.IsAsm = true |
| ctxt.Pkgpath = *flags.Importpath |
| switch *flags.Spectre { |
| default: |
| log.Printf("unknown setting -spectre=%s", *flags.Spectre) |
| os.Exit(2) |
| case "": |
| // nothing |
| case "index": |
| // known to compiler; ignore here so people can use |
| // the same list with -gcflags=-spectre=LIST and -asmflags=-spectrre=LIST |
| case "all", "ret": |
| ctxt.Retpoline = true |
| } |
| |
| ctxt.Bso = bufio.NewWriter(os.Stdout) |
| defer ctxt.Bso.Flush() |
| |
| architecture.Init(ctxt) |
| |
| // Create object file, write header. |
| buf, err := bio.Create(*flags.OutputFile) |
| if err != nil { |
| log.Fatal(err) |
| } |
| defer buf.Close() |
| |
| if !*flags.SymABIs { |
| buf.WriteString(objabi.HeaderString()) |
| fmt.Fprintf(buf, "!\n") |
| } |
| |
| // Set macros for GOEXPERIMENTs so we can easily switch |
| // runtime assembly code based on them. |
| if objabi.LookupPkgSpecial(ctxt.Pkgpath).AllowAsmABI { |
| for _, exp := range buildcfg.Experiment.Enabled() { |
| flags.D = append(flags.D, "GOEXPERIMENT_"+exp) |
| } |
| } |
| |
| var ok, diag bool |
| var failedFile string |
| for _, f := range flag.Args() { |
| lexer := lex.NewLexer(f) |
| parser := asm.NewParser(ctxt, architecture, lexer) |
| ctxt.DiagFunc = func(format string, args ...interface{}) { |
| diag = true |
| log.Printf(format, args...) |
| } |
| if *flags.SymABIs { |
| ok = parser.ParseSymABIs(buf) |
| } else { |
| pList := new(obj.Plist) |
| pList.Firstpc, ok = parser.Parse() |
| // reports errors to parser.Errorf |
| if ok { |
| obj.Flushplist(ctxt, pList, nil) |
| } |
| } |
| if !ok { |
| failedFile = f |
| break |
| } |
| } |
| if ok && !*flags.SymABIs { |
| ctxt.NumberSyms() |
| obj.WriteObjFile(ctxt, buf) |
| } |
| if !ok || diag { |
| if failedFile != "" { |
| log.Printf("assembly of %s failed", failedFile) |
| } else { |
| log.Print("assembly failed") |
| } |
| buf.Close() |
| os.Remove(*flags.OutputFile) |
| os.Exit(1) |
| } |
| } |