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