1// Copyright 2014 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package main 6 7import ( 8 "bufio" 9 "flag" 10 "fmt" 11 "internal/buildcfg" 12 "log" 13 "os" 14 15 "cmd/asm/internal/arch" 16 "cmd/asm/internal/asm" 17 "cmd/asm/internal/flags" 18 "cmd/asm/internal/lex" 19 20 "cmd/internal/bio" 21 "cmd/internal/obj" 22 "cmd/internal/objabi" 23 "cmd/internal/telemetry/counter" 24) 25 26func main() { 27 log.SetFlags(0) 28 log.SetPrefix("asm: ") 29 counter.Open() 30 31 buildcfg.Check() 32 GOARCH := buildcfg.GOARCH 33 34 flags.Parse() 35 counter.Inc("asm/invocations") 36 counter.CountFlags("asm/flag:", *flag.CommandLine) 37 38 architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink) 39 if architecture == nil { 40 log.Fatalf("unrecognized architecture %s", GOARCH) 41 } 42 ctxt := obj.Linknew(architecture.LinkArch) 43 ctxt.Debugasm = flags.PrintOut 44 ctxt.Debugvlog = flags.DebugV 45 ctxt.Flag_dynlink = *flags.Dynlink 46 ctxt.Flag_linkshared = *flags.Linkshared 47 ctxt.Flag_shared = *flags.Shared || *flags.Dynlink 48 ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack 49 ctxt.Debugpcln = flags.DebugFlags.PCTab 50 ctxt.IsAsm = true 51 ctxt.Pkgpath = *flags.Importpath 52 switch *flags.Spectre { 53 default: 54 log.Printf("unknown setting -spectre=%s", *flags.Spectre) 55 os.Exit(2) 56 case "": 57 // nothing 58 case "index": 59 // known to compiler; ignore here so people can use 60 // the same list with -gcflags=-spectre=LIST and -asmflags=-spectrre=LIST 61 case "all", "ret": 62 ctxt.Retpoline = true 63 } 64 65 ctxt.Bso = bufio.NewWriter(os.Stdout) 66 defer ctxt.Bso.Flush() 67 68 architecture.Init(ctxt) 69 70 // Create object file, write header. 71 buf, err := bio.Create(*flags.OutputFile) 72 if err != nil { 73 log.Fatal(err) 74 } 75 defer buf.Close() 76 77 if !*flags.SymABIs { 78 buf.WriteString(objabi.HeaderString()) 79 fmt.Fprintf(buf, "!\n") 80 } 81 82 // Set macros for GOEXPERIMENTs so we can easily switch 83 // runtime assembly code based on them. 84 if objabi.LookupPkgSpecial(ctxt.Pkgpath).AllowAsmABI { 85 for _, exp := range buildcfg.Experiment.Enabled() { 86 flags.D = append(flags.D, "GOEXPERIMENT_"+exp) 87 } 88 } 89 90 var ok, diag bool 91 var failedFile string 92 for _, f := range flag.Args() { 93 lexer := lex.NewLexer(f) 94 parser := asm.NewParser(ctxt, architecture, lexer) 95 ctxt.DiagFunc = func(format string, args ...interface{}) { 96 diag = true 97 log.Printf(format, args...) 98 } 99 if *flags.SymABIs { 100 ok = parser.ParseSymABIs(buf) 101 } else { 102 pList := new(obj.Plist) 103 pList.Firstpc, ok = parser.Parse() 104 // reports errors to parser.Errorf 105 if ok { 106 obj.Flushplist(ctxt, pList, nil) 107 } 108 } 109 if !ok { 110 failedFile = f 111 break 112 } 113 } 114 if ok && !*flags.SymABIs { 115 ctxt.NumberSyms() 116 obj.WriteObjFile(ctxt, buf) 117 } 118 if !ok || diag { 119 if failedFile != "" { 120 log.Printf("assembly of %s failed", failedFile) 121 } else { 122 log.Print("assembly failed") 123 } 124 buf.Close() 125 os.Remove(*flags.OutputFile) 126 os.Exit(1) 127 } 128} 129