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)
24
25func main() {
26	log.SetFlags(0)
27	log.SetPrefix("asm: ")
28
29	buildcfg.Check()
30	GOARCH := buildcfg.GOARCH
31
32	flags.Parse()
33
34	architecture := arch.Set(GOARCH, *flags.Shared || *flags.Dynlink)
35	if architecture == nil {
36		log.Fatalf("unrecognized architecture %s", GOARCH)
37	}
38
39	ctxt := obj.Linknew(architecture.LinkArch)
40	ctxt.Debugasm = flags.PrintOut
41	ctxt.Debugvlog = flags.DebugV
42	ctxt.Flag_dynlink = *flags.Dynlink
43	ctxt.Flag_linkshared = *flags.Linkshared
44	ctxt.Flag_shared = *flags.Shared || *flags.Dynlink
45	ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack
46	ctxt.IsAsm = true
47	ctxt.Pkgpath = *flags.Importpath
48	switch *flags.Spectre {
49	default:
50		log.Printf("unknown setting -spectre=%s", *flags.Spectre)
51		os.Exit(2)
52	case "":
53		// nothing
54	case "index":
55		// known to compiler; ignore here so people can use
56		// the same list with -gcflags=-spectre=LIST and -asmflags=-spectrre=LIST
57	case "all", "ret":
58		ctxt.Retpoline = true
59	}
60
61	ctxt.Bso = bufio.NewWriter(os.Stdout)
62	defer ctxt.Bso.Flush()
63
64	architecture.Init(ctxt)
65
66	// Create object file, write header.
67	buf, err := bio.Create(*flags.OutputFile)
68	if err != nil {
69		log.Fatal(err)
70	}
71	defer buf.Close()
72
73	if !*flags.SymABIs {
74		buf.WriteString(objabi.HeaderString())
75		fmt.Fprintf(buf, "!\n")
76	}
77
78	var ok, diag bool
79	var failedFile string
80	for _, f := range flag.Args() {
81		lexer := lex.NewLexer(f)
82		parser := asm.NewParser(ctxt, architecture, lexer,
83			*flags.CompilingRuntime)
84		ctxt.DiagFunc = func(format string, args ...interface{}) {
85			diag = true
86			log.Printf(format, args...)
87		}
88		if *flags.SymABIs {
89			ok = parser.ParseSymABIs(buf)
90		} else {
91			pList := new(obj.Plist)
92			pList.Firstpc, ok = parser.Parse()
93			// reports errors to parser.Errorf
94			if ok {
95				obj.Flushplist(ctxt, pList, nil, *flags.Importpath)
96			}
97		}
98		if !ok {
99			failedFile = f
100			break
101		}
102	}
103	if ok && !*flags.SymABIs {
104		ctxt.NumberSyms()
105		obj.WriteObjFile(ctxt, buf)
106	}
107	if !ok || diag {
108		if failedFile != "" {
109			log.Printf("assembly of %s failed", failedFile)
110		} else {
111			log.Print("assembly failed")
112		}
113		buf.Close()
114		os.Remove(*flags.OutputFile)
115		os.Exit(1)
116	}
117}
118