rsc.io/go@v0.0.0-20150416155037-e040fd465409/src/cmd/internal/asm/asm.go (about)

     1  // Inferno utils/6a/a.h and lex.c.
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
     3  // http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
     4  //
     5  //	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
     6  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     7  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     8  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
     9  //	Portions Copyright © 2004,2006 Bruce Ellis
    10  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    11  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    12  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    13  //
    14  // Permission is hereby granted, free of charge, to any person obtaining a copy
    15  // of this software and associated documentation files (the "Software"), to deal
    16  // in the Software without restriction, including without limitation the rights
    17  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    18  // copies of the Software, and to permit persons to whom the Software is
    19  // furnished to do so, subject to the following conditions:
    20  //
    21  // The above copyright notice and this permission notice shall be included in
    22  // all copies or substantial portions of the Software.
    23  //
    24  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    25  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    26  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    27  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    28  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    29  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    30  // THE SOFTWARE.
    31  
    32  // Package asm holds code shared among the assemblers.
    33  package asm
    34  
    35  import (
    36  	"flag"
    37  	"fmt"
    38  	"log"
    39  	"os"
    40  	"path/filepath"
    41  	"strconv"
    42  	"strings"
    43  
    44  	"cmd/internal/obj"
    45  )
    46  
    47  // Initialized by client.
    48  var (
    49  	LSCONST int
    50  	LCONST  int
    51  	LFCONST int
    52  	LNAME   int
    53  	LVAR    int
    54  	LLAB    int
    55  
    56  	Thechar     rune
    57  	Thestring   string
    58  	Thelinkarch *obj.LinkArch
    59  
    60  	Arches map[string]*obj.LinkArch
    61  
    62  	Cclean  func()
    63  	Yyparse func()
    64  	Syminit func(*Sym)
    65  
    66  	Lexinit []Lextab
    67  )
    68  
    69  type Lextab struct {
    70  	Name  string
    71  	Type  int
    72  	Value int64
    73  }
    74  
    75  const (
    76  	MAXALIGN = 7
    77  	FPCHIP   = 1
    78  	NSYMB    = 500
    79  	BUFSIZ   = 8192
    80  	HISTSZ   = 20
    81  	EOF      = -1
    82  	IGN      = -2
    83  	NHASH    = 503
    84  	NMACRO   = 10
    85  )
    86  
    87  const (
    88  	CLAST = iota
    89  	CMACARG
    90  	CMACRO
    91  	CPREPROC
    92  )
    93  
    94  type Macro struct {
    95  	Text string
    96  	Narg int
    97  	Dots bool
    98  }
    99  
   100  type Sym struct {
   101  	Link      *Sym
   102  	Ref       *Ref
   103  	Macro     *Macro
   104  	Value     int64
   105  	Type      int
   106  	Name      string
   107  	Labelname string
   108  	Sym       int8
   109  }
   110  
   111  type Ref struct {
   112  	Class int
   113  }
   114  
   115  type Io struct {
   116  	Link *Io
   117  	P    []byte
   118  	F    *os.File
   119  	B    [1024]byte
   120  }
   121  
   122  var fi struct {
   123  	P []byte
   124  }
   125  
   126  var (
   127  	debug    [256]int
   128  	hash     = map[string]*Sym{}
   129  	Dlist    []string
   130  	newflag  int
   131  	hunk     string
   132  	include  []string
   133  	iofree   *Io
   134  	ionext   *Io
   135  	iostack  *Io
   136  	Lineno   int32
   137  	nerrors  int
   138  	nhunk    int32
   139  	ninclude int
   140  	nsymb    int32
   141  	nullgen  obj.Addr
   142  	outfile  string
   143  	Pass     int
   144  	PC       int32
   145  	peekc    int = IGN
   146  	sym      int
   147  	symb     string
   148  	thunk    int32
   149  	obuf     obj.Biobuf
   150  	Ctxt     *obj.Link
   151  	bstdout  obj.Biobuf
   152  )
   153  
   154  func dodef(p string) {
   155  	Dlist = append(Dlist, p)
   156  }
   157  
   158  func usage() {
   159  	fmt.Printf("usage: %ca [options] file.c...\n", Thechar)
   160  	flag.PrintDefaults()
   161  	errorexit()
   162  }
   163  
   164  func Main() {
   165  	// Allow GOARCH=Thestring or GOARCH=Thestringsuffix,
   166  	// but not other values.
   167  	p := obj.Getgoarch()
   168  
   169  	if !strings.HasPrefix(p, Thestring) {
   170  		log.Fatalf("cannot use %cc with GOARCH=%s", Thechar, p)
   171  	}
   172  	if p != Thestring {
   173  		Thelinkarch = Arches[p]
   174  		if Thelinkarch == nil {
   175  			log.Fatalf("unknown arch %s", p)
   176  		}
   177  	}
   178  
   179  	Ctxt = obj.Linknew(Thelinkarch)
   180  	Ctxt.Diag = Yyerror
   181  	Ctxt.Bso = &bstdout
   182  	Ctxt.Enforce_data_order = 1
   183  	bstdout = *obj.Binitw(os.Stdout)
   184  
   185  	debug = [256]int{}
   186  	cinit()
   187  	outfile = ""
   188  	setinclude(".")
   189  
   190  	flag.Var(flagFn(dodef), "D", "name[=value]: add #define")
   191  	flag.Var(flagFn(setinclude), "I", "dir: add dir to include path")
   192  	flag.Var((*count)(&debug['S']), "S", "print assembly and machine code")
   193  	flag.Var((*count)(&debug['m']), "m", "debug preprocessor macros")
   194  	flag.StringVar(&outfile, "o", "", "file: set output file")
   195  	flag.StringVar(&Ctxt.Trimpath, "trimpath", "", "prefix: remove prefix from recorded source file paths")
   196  
   197  	flag.Parse()
   198  
   199  	Ctxt.Debugasm = int32(debug['S'])
   200  
   201  	if flag.NArg() < 1 {
   202  		usage()
   203  	}
   204  	if flag.NArg() > 1 {
   205  		fmt.Printf("can't assemble multiple files\n")
   206  		errorexit()
   207  	}
   208  
   209  	if assemble(flag.Arg(0)) != 0 {
   210  		errorexit()
   211  	}
   212  	obj.Bflush(&bstdout)
   213  	if nerrors > 0 {
   214  		errorexit()
   215  	}
   216  }
   217  
   218  func assemble(file string) int {
   219  	if outfile == "" {
   220  		outfile = strings.TrimSuffix(filepath.Base(file), ".s") + "." + string(Thechar)
   221  	}
   222  
   223  	of, err := os.Create(outfile)
   224  	if err != nil {
   225  		Yyerror("%ca: cannot create %s", Thechar, outfile)
   226  		errorexit()
   227  	}
   228  
   229  	obuf = *obj.Binitw(of)
   230  	fmt.Fprintf(&obuf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
   231  	fmt.Fprintf(&obuf, "!\n")
   232  
   233  	var i int
   234  	for Pass = 1; Pass <= 2; Pass++ {
   235  		pinit(file)
   236  		for i = 0; i < len(Dlist); i++ {
   237  			dodefine(Dlist[i])
   238  		}
   239  		Yyparse()
   240  		Cclean()
   241  		if nerrors != 0 {
   242  			return nerrors
   243  		}
   244  	}
   245  
   246  	obj.Writeobjdirect(Ctxt, &obuf)
   247  	obj.Bflush(&obuf)
   248  	return 0
   249  }
   250  
   251  func cinit() {
   252  	for i := 0; i < len(Lexinit); i++ {
   253  		s := Lookup(Lexinit[i].Name)
   254  		if s.Type != LNAME {
   255  			Yyerror("double initialization %s", Lexinit[i].Name)
   256  		}
   257  		s.Type = Lexinit[i].Type
   258  		s.Value = Lexinit[i].Value
   259  	}
   260  }
   261  
   262  func syminit(s *Sym) {
   263  	s.Type = LNAME
   264  	s.Value = 0
   265  }
   266  
   267  type flagFn func(string)
   268  
   269  func (flagFn) String() string {
   270  	return "<arg>"
   271  }
   272  
   273  func (f flagFn) Set(s string) error {
   274  	f(s)
   275  	return nil
   276  }
   277  
   278  type yyImpl struct{}
   279  
   280  // count is a flag.Value that is like a flag.Bool and a flag.Int.
   281  // If used as -name, it increments the count, but -name=x sets the count.
   282  // Used for verbose flag -v.
   283  type count int
   284  
   285  func (c *count) String() string {
   286  	return fmt.Sprint(int(*c))
   287  }
   288  
   289  func (c *count) Set(s string) error {
   290  	switch s {
   291  	case "true":
   292  		*c++
   293  	case "false":
   294  		*c = 0
   295  	default:
   296  		n, err := strconv.Atoi(s)
   297  		if err != nil {
   298  			return fmt.Errorf("invalid count %q", s)
   299  		}
   300  		*c = count(n)
   301  	}
   302  	return nil
   303  }
   304  
   305  func (c *count) IsBoolFlag() bool {
   306  	return true
   307  }