From 97e4010fd4b8094aa0b4498ad751e4c07ea8a1aa Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Mon, 22 Oct 2018 10:10:23 -0400 Subject: [PATCH] cmd/compile: accept and parse symabis This doesn't yet do anything with this information. For #27539. Change-Id: Ia12c905812aa1ed425eedd6ab2f55ec75d81c0ce Reviewed-on: https://go-review.googlesource.com/c/147099 Run-TryBot: Austin Clements TryBot-Result: Gobot Gobot Reviewed-by: David Chase Reviewed-by: Cherry Zhang --- src/cmd/compile/internal/gc/main.go | 82 +++++++++++++++++++++++++++++ src/cmd/internal/obj/abi_string.go | 16 ++++++ src/cmd/internal/obj/link.go | 22 ++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/cmd/internal/obj/abi_string.go diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 78142d3bf8..55d6d55e6d 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -247,6 +247,9 @@ func Main(archInit func(*Arch)) { flag.Int64Var(&memprofilerate, "memprofilerate", 0, "set runtime.MemProfileRate to `rate`") var goversion string flag.StringVar(&goversion, "goversion", "", "required version of the runtime") + var symabisPath string + flag.StringVar(&symabisPath, "symabis", "", "read symbol ABIs from `file`") + flag.BoolVar(&allABIs, "allabis", false, "generate ABI wrappers for all symbols (for bootstrap)") flag.StringVar(&traceprofile, "traceprofile", "", "write an execution trace to `file`") flag.StringVar(&blockprofile, "blockprofile", "", "write block profile to `file`") flag.StringVar(&mutexprofile, "mutexprofile", "", "write mutex profile to `file`") @@ -285,6 +288,10 @@ func Main(archInit func(*Arch)) { checkLang() + if symabisPath != "" { + readSymABIs(symabisPath, myimportpath) + } + thearch.LinkArch.Init(Ctxt) if outfile == "" { @@ -810,6 +817,81 @@ func readImportCfg(file string) { } } +// symabiDefs and symabiRefs record the defined and referenced ABIs of +// symbols required by non-Go code. These are keyed by link symbol +// name, where the local package prefix is always `"".` +var symabiDefs, symabiRefs map[string]obj.ABI + +// allABIs indicates that all symbol definitions should have ABI +// wrappers. This is used during toolchain bootstrapping to avoid +// having to find cross-package references. +var allABIs bool + +// readSymABIs reads a symabis file that specifies definitions and +// references of text symbols by ABI. +// +// The symabis format is a set of lines, where each line is a sequence +// of whitespace-separated fields. The first field is a verb and is +// either "def" for defining a symbol ABI or "ref" for referencing a +// symbol using an ABI. For both "def" and "ref", the second field is +// the symbol name and the third field is the ABI name, as one of the +// named cmd/internal/obj.ABI constants. +func readSymABIs(file, myimportpath string) { + data, err := ioutil.ReadFile(file) + if err != nil { + log.Fatalf("-symabis: %v", err) + } + + symabiDefs = make(map[string]obj.ABI) + symabiRefs = make(map[string]obj.ABI) + + localPrefix := "" + if myimportpath != "" { + // Symbols in this package may be written either as + // "".X or with the package's import path already in + // the symbol. + localPrefix = objabi.PathToPrefix(myimportpath) + "." + } + + for lineNum, line := range strings.Split(string(data), "\n") { + lineNum++ // 1-based + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + parts := strings.Fields(line) + switch parts[0] { + case "def", "ref": + // Parse line. + if len(parts) != 3 { + log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0]) + } + sym, abi := parts[1], parts[2] + if abi != "ABI0" { // Only supported external ABI right now + log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi) + } + + // If the symbol is already prefixed with + // myimportpath, rewrite it to start with "" + // so it matches the compiler's internal + // symbol names. + if localPrefix != "" && strings.HasPrefix(sym, localPrefix) { + sym = `"".` + sym[len(localPrefix):] + } + + // Record for later. + if parts[0] == "def" { + symabiDefs[sym] = obj.ABI0 + } else { + symabiRefs[sym] = obj.ABI0 + } + default: + log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0]) + } + } +} + func saveerrors() { nsavederrors += nerrors nerrors = 0 diff --git a/src/cmd/internal/obj/abi_string.go b/src/cmd/internal/obj/abi_string.go new file mode 100644 index 0000000000..a439da36a3 --- /dev/null +++ b/src/cmd/internal/obj/abi_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type ABI"; DO NOT EDIT. + +package obj + +import "strconv" + +const _ABI_name = "ABI0ABIInternalABICount" + +var _ABI_index = [...]uint8{0, 4, 15, 23} + +func (i ABI) String() string { + if i >= ABI(len(_ABI_index)-1) { + return "ABI(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _ABI_name[_ABI_index[i]:_ABI_index[i+1]] +} diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index d924cbc214..d3721dd023 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -409,6 +409,28 @@ type FuncInfo struct { StackObjects *LSym } +//go:generate stringer -type ABI + +// ABI is the calling convention of a text symbol. +type ABI uint8 + +const ( + // ABI0 is the stable stack-based ABI. It's important that the + // value of this is "0": we can't distinguish between + // references to data and ABI0 text symbols in assembly code, + // and hence this doesn't distinguish between symbols without + // an ABI and text symbols with ABI0. + ABI0 ABI = iota + + // ABIInternal is the internal ABI that may change between Go + // versions. All Go functions use the internal ABI and the + // compiler generates wrappers for calls to and from other + // ABIs. + ABIInternal + + ABICount +) + // Attribute is a set of symbol attributes. type Attribute int16