mirror of
https://github.com/golang/go.git
synced 2025-05-05 23:53:05 +00:00
These assemblers produce byte-for-byte identical output to the ones written in C. They are primarily a proof that cmd/internal/obj can be used standalone to produce working object files. (The use via objwriter starts by deserializing an already-constructed internal representation, so objwriter does not exercise the code in cmd/internal/obj that creates such a representation from scratch.) Change-Id: I1793d8d010046cfb9d8b4d2d4469e7f47a3d3ac7 Reviewed-on: https://go-review.googlesource.com/3143 Reviewed-by: Rob Pike <r@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
312 lines
6.2 KiB
Go
312 lines
6.2 KiB
Go
// Inferno utils/6a/a.h and lex.c.
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
|
|
//
|
|
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
|
|
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
|
|
// Portions Copyright © 1997-1999 Vita Nuova Limited
|
|
// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
|
|
// Portions Copyright © 2004,2006 Bruce Ellis
|
|
// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
|
|
// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
|
|
// Portions Copyright © 2009 The Go Authors. All rights reserved.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
// of this software and associated documentation files (the "Software"), to deal
|
|
// in the Software without restriction, including without limitation the rights
|
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
// copies of the Software, and to permit persons to whom the Software is
|
|
// furnished to do so, subject to the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included in
|
|
// all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
// THE SOFTWARE.
|
|
|
|
// Package asm holds code shared among the assemblers.
|
|
package asm
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"cmd/internal/obj"
|
|
)
|
|
|
|
// Initialized by client.
|
|
var (
|
|
LSCONST int
|
|
LCONST int
|
|
LFCONST int
|
|
LNAME int
|
|
LVAR int
|
|
LLAB int
|
|
|
|
Thechar rune
|
|
Thestring string
|
|
Thelinkarch *obj.LinkArch
|
|
|
|
Arches map[string]*obj.LinkArch
|
|
|
|
Cclean func()
|
|
Yyparse func()
|
|
Syminit func(*Sym)
|
|
|
|
Lexinit []Lextab
|
|
)
|
|
|
|
type Lextab struct {
|
|
Name string
|
|
Type int
|
|
Value int64
|
|
}
|
|
|
|
const (
|
|
MAXALIGN = 7
|
|
FPCHIP = 1
|
|
NSYMB = 500
|
|
BUFSIZ = 8192
|
|
HISTSZ = 20
|
|
EOF = -1
|
|
IGN = -2
|
|
NHASH = 503
|
|
STRINGSZ = 200
|
|
NMACRO = 10
|
|
)
|
|
|
|
const (
|
|
CLAST = iota
|
|
CMACARG
|
|
CMACRO
|
|
CPREPROC
|
|
)
|
|
|
|
type Macro struct {
|
|
Text string
|
|
Narg int
|
|
Dots bool
|
|
}
|
|
|
|
type Sym struct {
|
|
Link *Sym
|
|
Ref *Ref
|
|
Macro *Macro
|
|
Value int64
|
|
Type int
|
|
Name string
|
|
Labelname string
|
|
Sym int8
|
|
}
|
|
|
|
type Ref struct {
|
|
Class int
|
|
}
|
|
|
|
type Io struct {
|
|
Link *Io
|
|
P []byte
|
|
F *os.File
|
|
B [1024]byte
|
|
}
|
|
|
|
var fi struct {
|
|
P []byte
|
|
}
|
|
|
|
var (
|
|
debug [256]int
|
|
hash = map[string]*Sym{}
|
|
Dlist []string
|
|
newflag int
|
|
hunk string
|
|
include []string
|
|
iofree *Io
|
|
ionext *Io
|
|
iostack *Io
|
|
Lineno int32
|
|
nerrors int
|
|
nhunk int32
|
|
ninclude int
|
|
nsymb int32
|
|
nullgen obj.Addr
|
|
outfile string
|
|
Pass int
|
|
PC int32
|
|
peekc int = IGN
|
|
sym int
|
|
symb string
|
|
thunk int32
|
|
obuf obj.Biobuf
|
|
Ctxt *obj.Link
|
|
bstdout obj.Biobuf
|
|
)
|
|
|
|
func dodef(p string) {
|
|
Dlist = append(Dlist, p)
|
|
}
|
|
|
|
func usage() {
|
|
fmt.Printf("usage: %ca [options] file.c...\n", Thechar)
|
|
flag.PrintDefaults()
|
|
errorexit()
|
|
}
|
|
|
|
func Main() {
|
|
var p string
|
|
|
|
// Allow GOARCH=Thestring or GOARCH=Thestringsuffix,
|
|
// but not other values.
|
|
p = obj.Getgoarch()
|
|
|
|
if !strings.HasPrefix(p, Thestring) {
|
|
log.Fatalf("cannot use %cc with GOARCH=%s", Thechar, p)
|
|
}
|
|
if p != Thestring {
|
|
Thelinkarch = Arches[p]
|
|
if Thelinkarch == nil {
|
|
log.Fatalf("unknown arch %s", p)
|
|
}
|
|
}
|
|
|
|
Ctxt = obj.Linknew(Thelinkarch)
|
|
Ctxt.Diag = Yyerror
|
|
Ctxt.Bso = &bstdout
|
|
Ctxt.Enforce_data_order = 1
|
|
bstdout = *obj.Binitw(os.Stdout)
|
|
|
|
debug = [256]int{}
|
|
cinit()
|
|
outfile = ""
|
|
setinclude(".")
|
|
|
|
flag.Var(flagFn(dodef), "D", "name[=value]: add #define")
|
|
flag.Var(flagFn(setinclude), "I", "dir: add dir to include path")
|
|
flag.Var((*count)(&debug['S']), "S", "print assembly and machine code")
|
|
flag.Var((*count)(&debug['m']), "m", "debug preprocessor macros")
|
|
flag.StringVar(&outfile, "o", "", "file: set output file")
|
|
flag.StringVar(&Ctxt.Trimpath, "trimpath", "", "prefix: remove prefix from recorded source file paths")
|
|
|
|
flag.Parse()
|
|
|
|
Ctxt.Debugasm = int32(debug['S'])
|
|
|
|
if flag.NArg() < 1 {
|
|
usage()
|
|
}
|
|
if flag.NArg() > 1 {
|
|
fmt.Printf("can't assemble multiple files\n")
|
|
errorexit()
|
|
}
|
|
|
|
if assemble(flag.Arg(0)) != 0 {
|
|
errorexit()
|
|
}
|
|
obj.Bflush(&bstdout)
|
|
if nerrors > 0 {
|
|
errorexit()
|
|
}
|
|
}
|
|
|
|
func assemble(file string) int {
|
|
var i int
|
|
|
|
if outfile == "" {
|
|
outfile = strings.TrimSuffix(filepath.Base(file), ".s") + "." + string(Thechar)
|
|
}
|
|
|
|
of, err := os.Create(outfile)
|
|
if err != nil {
|
|
Yyerror("%ca: cannot create %s", Thechar, outfile)
|
|
errorexit()
|
|
}
|
|
|
|
obuf = *obj.Binitw(of)
|
|
fmt.Fprintf(&obuf, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
|
|
fmt.Fprintf(&obuf, "!\n")
|
|
|
|
for Pass = 1; Pass <= 2; Pass++ {
|
|
pinit(file)
|
|
for i = 0; i < len(Dlist); i++ {
|
|
dodefine(Dlist[i])
|
|
}
|
|
Yyparse()
|
|
Cclean()
|
|
if nerrors != 0 {
|
|
return nerrors
|
|
}
|
|
}
|
|
|
|
obj.Writeobjdirect(Ctxt, &obuf)
|
|
obj.Bflush(&obuf)
|
|
return 0
|
|
}
|
|
|
|
func cinit() {
|
|
for i := 0; i < len(Lexinit); i++ {
|
|
s := Lookup(Lexinit[i].Name)
|
|
if s.Type != LNAME {
|
|
Yyerror("double initialization %s", Lexinit[i].Name)
|
|
}
|
|
s.Type = Lexinit[i].Type
|
|
s.Value = Lexinit[i].Value
|
|
}
|
|
}
|
|
|
|
func syminit(s *Sym) {
|
|
s.Type = LNAME
|
|
s.Value = 0
|
|
}
|
|
|
|
type flagFn func(string)
|
|
|
|
func (flagFn) String() string {
|
|
return "<arg>"
|
|
}
|
|
|
|
func (f flagFn) Set(s string) error {
|
|
f(s)
|
|
return nil
|
|
}
|
|
|
|
type yyImpl struct{}
|
|
|
|
// count is a flag.Value that is like a flag.Bool and a flag.Int.
|
|
// If used as -name, it increments the count, but -name=x sets the count.
|
|
// Used for verbose flag -v.
|
|
type count int
|
|
|
|
func (c *count) String() string {
|
|
return fmt.Sprint(int(*c))
|
|
}
|
|
|
|
func (c *count) Set(s string) error {
|
|
switch s {
|
|
case "true":
|
|
*c++
|
|
case "false":
|
|
*c = 0
|
|
default:
|
|
n, err := strconv.Atoi(s)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid count %q", s)
|
|
}
|
|
*c = count(n)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *count) IsBoolFlag() bool {
|
|
return true
|
|
}
|