github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/asm/asm.go (about)

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