diff options
Diffstat (limited to 'src/cmd/internal/objabi')
-rw-r--r-- | src/cmd/internal/objabi/autotype.go | 38 | ||||
-rw-r--r-- | src/cmd/internal/objabi/flag.go | 373 | ||||
-rw-r--r-- | src/cmd/internal/objabi/flag_test.go | 26 | ||||
-rw-r--r-- | src/cmd/internal/objabi/funcdata.go | 51 | ||||
-rw-r--r-- | src/cmd/internal/objabi/funcid.go | 91 | ||||
-rw-r--r-- | src/cmd/internal/objabi/head.go | 109 | ||||
-rw-r--r-- | src/cmd/internal/objabi/line.go | 126 | ||||
-rw-r--r-- | src/cmd/internal/objabi/line_test.go | 50 | ||||
-rw-r--r-- | src/cmd/internal/objabi/path.go | 67 | ||||
-rw-r--r-- | src/cmd/internal/objabi/path_test.go | 33 | ||||
-rw-r--r-- | src/cmd/internal/objabi/reloctype.go | 378 | ||||
-rw-r--r-- | src/cmd/internal/objabi/reloctype_string.go | 100 | ||||
-rw-r--r-- | src/cmd/internal/objabi/stack.go | 40 | ||||
-rw-r--r-- | src/cmd/internal/objabi/symkind.go | 76 | ||||
-rw-r--r-- | src/cmd/internal/objabi/symkind_string.go | 42 | ||||
-rw-r--r-- | src/cmd/internal/objabi/typekind.go | 40 | ||||
-rw-r--r-- | src/cmd/internal/objabi/util.go | 33 |
17 files changed, 1673 insertions, 0 deletions
diff --git a/src/cmd/internal/objabi/autotype.go b/src/cmd/internal/objabi/autotype.go new file mode 100644 index 0000000..f9d17a3 --- /dev/null +++ b/src/cmd/internal/objabi/autotype.go @@ -0,0 +1,38 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// 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 objabi + +// Auto.name +const ( + A_AUTO = 1 + iota + A_PARAM + A_DELETED_AUTO +) diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go new file mode 100644 index 0000000..847ed48 --- /dev/null +++ b/src/cmd/internal/objabi/flag.go @@ -0,0 +1,373 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import ( + "flag" + "fmt" + "internal/buildcfg" + "io" + "log" + "os" + "reflect" + "sort" + "strconv" + "strings" +) + +func Flagcount(name, usage string, val *int) { + flag.Var((*count)(val), name, usage) +} + +func Flagfn1(name, usage string, f func(string)) { + flag.Var(fn1(f), name, usage) +} + +func Flagprint(w io.Writer) { + flag.CommandLine.SetOutput(w) + flag.PrintDefaults() +} + +func Flagparse(usage func()) { + flag.Usage = usage + os.Args = expandArgs(os.Args) + flag.Parse() +} + +// expandArgs expands "response files" arguments in the provided slice. +// +// A "response file" argument starts with '@' and the rest of that +// argument is a filename with CR-or-CRLF-separated arguments. Each +// argument in the named files can also contain response file +// arguments. See Issue 18468. +// +// The returned slice 'out' aliases 'in' iff the input did not contain +// any response file arguments. +// +// TODO: handle relative paths of recursive expansions in different directories? +// Is there a spec for this? Are relative paths allowed? +func expandArgs(in []string) (out []string) { + // out is nil until we see a "@" argument. + for i, s := range in { + if strings.HasPrefix(s, "@") { + if out == nil { + out = make([]string, 0, len(in)*2) + out = append(out, in[:i]...) + } + slurp, err := os.ReadFile(s[1:]) + if err != nil { + log.Fatal(err) + } + args := strings.Split(strings.TrimSpace(strings.Replace(string(slurp), "\r", "", -1)), "\n") + for i, arg := range args { + args[i] = DecodeArg(arg) + } + out = append(out, expandArgs(args)...) + } else if out != nil { + out = append(out, s) + } + } + if out == nil { + return in + } + return +} + +func AddVersionFlag() { + flag.Var(versionFlag{}, "V", "print version and exit") +} + +var buildID string // filled in by linker + +type versionFlag struct{} + +func (versionFlag) IsBoolFlag() bool { return true } +func (versionFlag) Get() interface{} { return nil } +func (versionFlag) String() string { return "" } +func (versionFlag) Set(s string) error { + name := os.Args[0] + name = name[strings.LastIndex(name, `/`)+1:] + name = name[strings.LastIndex(name, `\`)+1:] + name = strings.TrimSuffix(name, ".exe") + + p := "" + + if s == "goexperiment" { + // test/run.go uses this to discover the full set of + // experiment tags. Report everything. + p = " X:" + strings.Join(buildcfg.Experiment.All(), ",") + } else { + // If the enabled experiments differ from the baseline, + // include that difference. + if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { + p = " X:" + goexperiment + } + } + + // The go command invokes -V=full to get a unique identifier + // for this tool. It is assumed that the release version is sufficient + // for releases, but during development we include the full + // build ID of the binary, so that if the compiler is changed and + // rebuilt, we notice and rebuild all packages. + if s == "full" { + if strings.HasPrefix(buildcfg.Version, "devel") { + p += " buildID=" + buildID + } + } + + fmt.Printf("%s version %s%s\n", name, buildcfg.Version, p) + os.Exit(0) + return nil +} + +// 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) Get() interface{} { + return int(*c) +} + +func (c *count) IsBoolFlag() bool { + return true +} + +func (c *count) IsCountFlag() bool { + return true +} + +type fn1 func(string) + +func (f fn1) Set(s string) error { + f(s) + return nil +} + +func (f fn1) String() string { return "" } + +// DecodeArg decodes an argument. +// +// This function is public for testing with the parallel encoder. +func DecodeArg(arg string) string { + // If no encoding, fastpath out. + if !strings.ContainsAny(arg, "\\\n") { + return arg + } + + var b strings.Builder + var wasBS bool + for _, r := range arg { + if wasBS { + switch r { + case '\\': + b.WriteByte('\\') + case 'n': + b.WriteByte('\n') + default: + // This shouldn't happen. The only backslashes that reach here + // should encode '\n' and '\\' exclusively. + panic("badly formatted input") + } + } else if r == '\\' { + wasBS = true + continue + } else { + b.WriteRune(r) + } + wasBS = false + } + return b.String() +} + +type debugField struct { + name string + help string + concurrentOk bool // true if this field/flag is compatible with concurrent compilation + val interface{} // *int or *string +} + +type DebugFlag struct { + tab map[string]debugField + concurrentOk *bool // this is non-nil only for compiler's DebugFlags, but only compiler has concurrent:ok fields + debugSSA DebugSSA // this is non-nil only for compiler's DebugFlags. +} + +// A DebugSSA function is called to set a -d ssa/... option. +// If nil, those options are reported as invalid options. +// If DebugSSA returns a non-empty string, that text is reported as a compiler error. +// If phase is "help", it should print usage information and terminate the process. +type DebugSSA func(phase, flag string, val int, valString string) string + +// NewDebugFlag constructs a DebugFlag for the fields of debug, which +// must be a pointer to a struct. +// +// Each field of *debug is a different value, named for the lower-case of the field name. +// Each field must be an int or string and must have a `help` struct tag. +// There may be an "Any bool" field, which will be set if any debug flags are set. +// +// The returned flag takes a comma-separated list of settings. +// Each setting is name=value; for ints, name is short for name=1. +// +// If debugSSA is non-nil, any debug flags of the form ssa/... will be +// passed to debugSSA for processing. +func NewDebugFlag(debug interface{}, debugSSA DebugSSA) *DebugFlag { + flag := &DebugFlag{ + tab: make(map[string]debugField), + debugSSA: debugSSA, + } + + v := reflect.ValueOf(debug).Elem() + t := v.Type() + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + ptr := v.Field(i).Addr().Interface() + if f.Name == "ConcurrentOk" { + switch ptr := ptr.(type) { + default: + panic("debug.ConcurrentOk must have type bool") + case *bool: + flag.concurrentOk = ptr + } + continue + } + name := strings.ToLower(f.Name) + help := f.Tag.Get("help") + if help == "" { + panic(fmt.Sprintf("debug.%s is missing help text", f.Name)) + } + concurrent := f.Tag.Get("concurrent") + + switch ptr.(type) { + default: + panic(fmt.Sprintf("debug.%s has invalid type %v (must be int or string)", f.Name, f.Type)) + case *int, *string: + // ok + } + flag.tab[name] = debugField{name, help, concurrent == "ok", ptr} + } + + return flag +} + +func (f *DebugFlag) Set(debugstr string) error { + if debugstr == "" { + return nil + } + for _, name := range strings.Split(debugstr, ",") { + if name == "" { + continue + } + // display help about the debug option itself and quit + if name == "help" { + fmt.Print(debugHelpHeader) + maxLen, names := 0, []string{} + if f.debugSSA != nil { + maxLen = len("ssa/help") + } + for name := range f.tab { + if len(name) > maxLen { + maxLen = len(name) + } + names = append(names, name) + } + sort.Strings(names) + // Indent multi-line help messages. + nl := fmt.Sprintf("\n\t%-*s\t", maxLen, "") + for _, name := range names { + help := f.tab[name].help + fmt.Printf("\t%-*s\t%s\n", maxLen, name, strings.Replace(help, "\n", nl, -1)) + } + if f.debugSSA != nil { + // ssa options have their own help + fmt.Printf("\t%-*s\t%s\n", maxLen, "ssa/help", "print help about SSA debugging") + } + os.Exit(0) + } + + val, valstring, haveInt := 1, "", true + if i := strings.IndexAny(name, "=:"); i >= 0 { + var err error + name, valstring = name[:i], name[i+1:] + val, err = strconv.Atoi(valstring) + if err != nil { + val, haveInt = 1, false + } + } + + if t, ok := f.tab[name]; ok { + switch vp := t.val.(type) { + case nil: + // Ignore + case *string: + *vp = valstring + case *int: + if !haveInt { + log.Fatalf("invalid debug value %v", name) + } + *vp = val + default: + panic("bad debugtab type") + } + // assembler DebugFlags don't have a ConcurrentOk field to reset, so check against that. + if !t.concurrentOk && f.concurrentOk != nil { + *f.concurrentOk = false + } + } else if f.debugSSA != nil && strings.HasPrefix(name, "ssa/") { + // expect form ssa/phase/flag + // e.g. -d=ssa/generic_cse/time + // _ in phase name also matches space + phase := name[4:] + flag := "debug" // default flag is debug + if i := strings.Index(phase, "/"); i >= 0 { + flag = phase[i+1:] + phase = phase[:i] + } + err := f.debugSSA(phase, flag, val, valstring) + if err != "" { + log.Fatalf(err) + } + // Setting this false for -d=ssa/... preserves old behavior + // of turning off concurrency for any debug flags. + // It's not known for sure if this is necessary, but it is safe. + *f.concurrentOk = false + + } else { + return fmt.Errorf("unknown debug key %s\n", name) + } + } + + return nil +} + +const debugHelpHeader = `usage: -d arg[,arg]* and arg is <key>[=<value>] + +<key> is one of: + +` + +func (f *DebugFlag) String() string { + return "" +} diff --git a/src/cmd/internal/objabi/flag_test.go b/src/cmd/internal/objabi/flag_test.go new file mode 100644 index 0000000..935b9c2 --- /dev/null +++ b/src/cmd/internal/objabi/flag_test.go @@ -0,0 +1,26 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "testing" + +func TestDecodeArg(t *testing.T) { + t.Parallel() + tests := []struct { + arg, want string + }{ + {"", ""}, + {"hello", "hello"}, + {"hello\\n", "hello\n"}, + {"hello\\nthere", "hello\nthere"}, + {"hello\\\\there", "hello\\there"}, + {"\\\\\\n", "\\\n"}, + } + for _, test := range tests { + if got := DecodeArg(test.arg); got != test.want { + t.Errorf("decodoeArg(%q) = %q, want %q", test.arg, got, test.want) + } + } +} diff --git a/src/cmd/internal/objabi/funcdata.go b/src/cmd/internal/objabi/funcdata.go new file mode 100644 index 0000000..05a1d49 --- /dev/null +++ b/src/cmd/internal/objabi/funcdata.go @@ -0,0 +1,51 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +// This file defines the IDs for PCDATA and FUNCDATA instructions +// in Go binaries. +// +// These must agree with ../../../runtime/funcdata.h and +// ../../../runtime/symtab.go. + +const ( + PCDATA_UnsafePoint = 0 + PCDATA_StackMapIndex = 1 + PCDATA_InlTreeIndex = 2 + PCDATA_ArgLiveIndex = 3 + + FUNCDATA_ArgsPointerMaps = 0 + FUNCDATA_LocalsPointerMaps = 1 + FUNCDATA_StackObjects = 2 + FUNCDATA_InlTree = 3 + FUNCDATA_OpenCodedDeferInfo = 4 + FUNCDATA_ArgInfo = 5 + FUNCDATA_ArgLiveInfo = 6 + FUNCDATA_WrapInfo = 7 + + // ArgsSizeUnknown is set in Func.argsize to mark all functions + // whose argument size is unknown (C vararg functions, and + // assembly code without an explicit specification). + // This value is generated by the compiler, assembler, or linker. + ArgsSizeUnknown = -0x80000000 +) + +// Special PCDATA values. +const ( + // PCDATA_UnsafePoint values. + PCDATA_UnsafePointSafe = -1 // Safe for async preemption + PCDATA_UnsafePointUnsafe = -2 // Unsafe for async preemption + + // PCDATA_Restart1(2) apply on a sequence of instructions, within + // which if an async preemption happens, we should back off the PC + // to the start of the sequence when resuming. + // We need two so we can distinguish the start/end of the sequence + // in case that two sequences are next to each other. + PCDATA_Restart1 = -3 + PCDATA_Restart2 = -4 + + // Like PCDATA_Restart1, but back to function entry if async preempted. + PCDATA_RestartAtEntry = -5 +) diff --git a/src/cmd/internal/objabi/funcid.go b/src/cmd/internal/objabi/funcid.go new file mode 100644 index 0000000..c2eb4d5 --- /dev/null +++ b/src/cmd/internal/objabi/funcid.go @@ -0,0 +1,91 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "strings" + +// A FuncFlag records bits about a function, passed to the runtime. +type FuncFlag uint8 + +// Note: This list must match the list in runtime/symtab.go. +const ( + FuncFlag_TOPFRAME = 1 << iota + FuncFlag_SPWRITE + FuncFlag_ASM +) + +// A FuncID identifies particular functions that need to be treated +// specially by the runtime. +// Note that in some situations involving plugins, there may be multiple +// copies of a particular special runtime function. +type FuncID uint8 + +// Note: this list must match the list in runtime/symtab.go. +const ( + FuncID_normal FuncID = iota // not a special function + FuncID_abort + FuncID_asmcgocall + FuncID_asyncPreempt + FuncID_cgocallback + FuncID_debugCallV2 + FuncID_gcBgMarkWorker + FuncID_goexit + FuncID_gogo + FuncID_gopanic + FuncID_handleAsyncEvent + FuncID_mcall + FuncID_morestack + FuncID_mstart + FuncID_panicwrap + FuncID_rt0_go + FuncID_runfinq + FuncID_runtime_main + FuncID_sigpanic + FuncID_systemstack + FuncID_systemstack_switch + FuncID_wrapper // any autogenerated code (hash/eq algorithms, method wrappers, etc.) +) + +var funcIDs = map[string]FuncID{ + "abort": FuncID_abort, + "asmcgocall": FuncID_asmcgocall, + "asyncPreempt": FuncID_asyncPreempt, + "cgocallback": FuncID_cgocallback, + "debugCallV2": FuncID_debugCallV2, + "gcBgMarkWorker": FuncID_gcBgMarkWorker, + "rt0_go": FuncID_rt0_go, + "goexit": FuncID_goexit, + "gogo": FuncID_gogo, + "gopanic": FuncID_gopanic, + "handleAsyncEvent": FuncID_handleAsyncEvent, + "main": FuncID_runtime_main, + "mcall": FuncID_mcall, + "morestack": FuncID_morestack, + "mstart": FuncID_mstart, + "panicwrap": FuncID_panicwrap, + "runfinq": FuncID_runfinq, + "sigpanic": FuncID_sigpanic, + "systemstack_switch": FuncID_systemstack_switch, + "systemstack": FuncID_systemstack, + + // Don't show in call stack but otherwise not special. + "deferreturn": FuncID_wrapper, + "runOpenDeferFrame": FuncID_wrapper, + "deferCallSave": FuncID_wrapper, +} + +// Get the function ID for the named function in the named file. +// The function should be package-qualified. +func GetFuncID(name string, isWrapper bool) FuncID { + if isWrapper { + return FuncID_wrapper + } + if strings.HasPrefix(name, "runtime.") { + if id, ok := funcIDs[name[len("runtime."):]]; ok { + return id + } + } + return FuncID_normal +} diff --git a/src/cmd/internal/objabi/head.go b/src/cmd/internal/objabi/head.go new file mode 100644 index 0000000..763910f --- /dev/null +++ b/src/cmd/internal/objabi/head.go @@ -0,0 +1,109 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// 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 objabi + +import "fmt" + +// HeadType is the executable header type. +type HeadType uint8 + +const ( + Hunknown HeadType = iota + Hdarwin + Hdragonfly + Hfreebsd + Hjs + Hlinux + Hnetbsd + Hopenbsd + Hplan9 + Hsolaris + Hwindows + Haix +) + +func (h *HeadType) Set(s string) error { + switch s { + case "aix": + *h = Haix + case "darwin", "ios": + *h = Hdarwin + case "dragonfly": + *h = Hdragonfly + case "freebsd": + *h = Hfreebsd + case "js": + *h = Hjs + case "linux", "android": + *h = Hlinux + case "netbsd": + *h = Hnetbsd + case "openbsd": + *h = Hopenbsd + case "plan9": + *h = Hplan9 + case "illumos", "solaris": + *h = Hsolaris + case "windows": + *h = Hwindows + default: + return fmt.Errorf("invalid headtype: %q", s) + } + return nil +} + +func (h HeadType) String() string { + switch h { + case Haix: + return "aix" + case Hdarwin: + return "darwin" + case Hdragonfly: + return "dragonfly" + case Hfreebsd: + return "freebsd" + case Hjs: + return "js" + case Hlinux: + return "linux" + case Hnetbsd: + return "netbsd" + case Hopenbsd: + return "openbsd" + case Hplan9: + return "plan9" + case Hsolaris: + return "solaris" + case Hwindows: + return "windows" + } + return fmt.Sprintf("HeadType(%d)", h) +} diff --git a/src/cmd/internal/objabi/line.go b/src/cmd/internal/objabi/line.go new file mode 100644 index 0000000..beee129 --- /dev/null +++ b/src/cmd/internal/objabi/line.go @@ -0,0 +1,126 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import ( + "internal/buildcfg" + "os" + "path/filepath" + "strings" +) + +// WorkingDir returns the current working directory +// (or "/???" if the directory cannot be identified), +// with "/" as separator. +func WorkingDir() string { + var path string + path, _ = os.Getwd() + if path == "" { + path = "/???" + } + return filepath.ToSlash(path) +} + +// AbsFile returns the absolute filename for file in the given directory, +// as rewritten by the rewrites argument. +// For unrewritten paths, AbsFile rewrites a leading $GOROOT prefix to the literal "$GOROOT". +// If the resulting path is the empty string, the result is "??". +// +// The rewrites argument is a ;-separated list of rewrites. +// Each rewrite is of the form "prefix" or "prefix=>replace", +// where prefix must match a leading sequence of path elements +// and is either removed entirely or replaced by the replacement. +func AbsFile(dir, file, rewrites string) string { + abs := file + if dir != "" && !filepath.IsAbs(file) { + abs = filepath.Join(dir, file) + } + + abs, rewritten := ApplyRewrites(abs, rewrites) + if !rewritten && buildcfg.GOROOT != "" && hasPathPrefix(abs, buildcfg.GOROOT) { + abs = "$GOROOT" + abs[len(buildcfg.GOROOT):] + } + + if abs == "" { + abs = "??" + } + return abs +} + +// ApplyRewrites returns the filename for file in the given directory, +// as rewritten by the rewrites argument. +// +// The rewrites argument is a ;-separated list of rewrites. +// Each rewrite is of the form "prefix" or "prefix=>replace", +// where prefix must match a leading sequence of path elements +// and is either removed entirely or replaced by the replacement. +func ApplyRewrites(file, rewrites string) (string, bool) { + start := 0 + for i := 0; i <= len(rewrites); i++ { + if i == len(rewrites) || rewrites[i] == ';' { + if new, ok := applyRewrite(file, rewrites[start:i]); ok { + return new, true + } + start = i + 1 + } + } + + return file, false +} + +// applyRewrite applies the rewrite to the path, +// returning the rewritten path and a boolean +// indicating whether the rewrite applied at all. +func applyRewrite(path, rewrite string) (string, bool) { + prefix, replace := rewrite, "" + if j := strings.LastIndex(rewrite, "=>"); j >= 0 { + prefix, replace = rewrite[:j], rewrite[j+len("=>"):] + } + + if prefix == "" || !hasPathPrefix(path, prefix) { + return path, false + } + if len(path) == len(prefix) { + return replace, true + } + if replace == "" { + return path[len(prefix)+1:], true + } + return replace + path[len(prefix):], true +} + +// Does s have t as a path prefix? +// That is, does s == t or does s begin with t followed by a slash? +// For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true. +// Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true. +// We do not allow full Unicode case folding, for fear of causing more confusion +// or harm than good. (For an example of the kinds of things that can go wrong, +// see http://article.gmane.org/gmane.linux.kernel/1853266.) +func hasPathPrefix(s string, t string) bool { + if len(t) > len(s) { + return false + } + var i int + for i = 0; i < len(t); i++ { + cs := int(s[i]) + ct := int(t[i]) + if 'A' <= cs && cs <= 'Z' { + cs += 'a' - 'A' + } + if 'A' <= ct && ct <= 'Z' { + ct += 'a' - 'A' + } + if cs == '\\' { + cs = '/' + } + if ct == '\\' { + ct = '/' + } + if cs != ct { + return false + } + } + return i >= len(s) || s[i] == '/' || s[i] == '\\' +} diff --git a/src/cmd/internal/objabi/line_test.go b/src/cmd/internal/objabi/line_test.go new file mode 100644 index 0000000..1fa0ff1 --- /dev/null +++ b/src/cmd/internal/objabi/line_test.go @@ -0,0 +1,50 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import ( + "path/filepath" + "runtime" + "testing" +) + +// On Windows, "/foo" is reported as a relative path +// (it is relative to the current drive letter), +// so we need add a drive letter to test absolute path cases. +func drive() string { + if runtime.GOOS == "windows" { + return "c:" + } + return "" +} + +var absFileTests = []struct { + dir string + file string + rewrites string + abs string +}{ + {"/d", "f", "", "/d/f"}, + {"/d", drive() + "/f", "", drive() + "/f"}, + {"/d", "f/g", "", "/d/f/g"}, + {"/d", drive() + "/f/g", "", drive() + "/f/g"}, + + {"/d", "f", "/d/f", "??"}, + {"/d", "f/g", "/d/f", "g"}, + {"/d", "f/g", "/d/f=>h", "h/g"}, + {"/d", "f/g", "/d/f=>/h", "/h/g"}, + {"/d", "f/g", "/d/f=>/h;/d/e=>/i", "/h/g"}, + {"/d", "e/f", "/d/f=>/h;/d/e=>/i", "/i/f"}, +} + +func TestAbsFile(t *testing.T) { + for _, tt := range absFileTests { + abs := filepath.FromSlash(AbsFile(filepath.FromSlash(tt.dir), filepath.FromSlash(tt.file), tt.rewrites)) + want := filepath.FromSlash(tt.abs) + if abs != want { + t.Errorf("AbsFile(%q, %q, %q) = %q, want %q", tt.dir, tt.file, tt.rewrites, abs, want) + } + } +} diff --git a/src/cmd/internal/objabi/path.go b/src/cmd/internal/objabi/path.go new file mode 100644 index 0000000..aacab9a --- /dev/null +++ b/src/cmd/internal/objabi/path.go @@ -0,0 +1,67 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "strings" + +// PathToPrefix converts raw string to the prefix that will be used in the +// symbol table. All control characters, space, '%' and '"', as well as +// non-7-bit clean bytes turn into %xx. The period needs escaping only in the +// last segment of the path, and it makes for happier users if we escape that as +// little as possible. +func PathToPrefix(s string) string { + slash := strings.LastIndex(s, "/") + // check for chars that need escaping + n := 0 + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + n++ + } + } + + // quick exit + if n == 0 { + return s + } + + // escape + const hex = "0123456789abcdef" + p := make([]byte, 0, len(s)+2*n) + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + p = append(p, '%', hex[c>>4], hex[c&0xF]) + } else { + p = append(p, c) + } + } + + return string(p) +} + +// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it +// belongs to the collection of "runtime-related" packages, including +// "runtime" itself, "reflect", "syscall", and the +// "runtime/internal/*" packages. The compiler and/or assembler in +// some cases need to be aware of when they are building such a +// package, for example to enable features such as ABI selectors in +// assembly sources. +// +// Keep in sync with cmd/dist/build.go:IsRuntimePackagePath. +func IsRuntimePackagePath(pkgpath string) bool { + rval := false + switch pkgpath { + case "runtime": + rval = true + case "reflect": + rval = true + case "syscall": + rval = true + case "internal/bytealg": + rval = true + default: + rval = strings.HasPrefix(pkgpath, "runtime/internal") + } + return rval +} diff --git a/src/cmd/internal/objabi/path_test.go b/src/cmd/internal/objabi/path_test.go new file mode 100644 index 0000000..05d7fb4 --- /dev/null +++ b/src/cmd/internal/objabi/path_test.go @@ -0,0 +1,33 @@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "testing" + +func TestPathToPrefix(t *testing.T) { + tests := []struct { + Path string + Expected string + }{{"foo/bar/v1", "foo/bar/v1"}, + {"foo/bar/v.1", "foo/bar/v%2e1"}, + {"f.o.o/b.a.r/v1", "f.o.o/b.a.r/v1"}, + {"f.o.o/b.a.r/v.1", "f.o.o/b.a.r/v%2e1"}, + {"f.o.o/b.a.r/v..1", "f.o.o/b.a.r/v%2e%2e1"}, + {"f.o.o/b.a.r/v..1.", "f.o.o/b.a.r/v%2e%2e1%2e"}, + {"f.o.o/b.a.r/v%1", "f.o.o/b.a.r/v%251"}, + {"runtime", "runtime"}, + {"sync/atomic", "sync/atomic"}, + {"golang.org/x/tools/godoc", "golang.org/x/tools/godoc"}, + {"foo.bar/baz.quux", "foo.bar/baz%2equux"}, + {"", ""}, + {"%foo%bar", "%25foo%25bar"}, + {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"}, + } + for _, tc := range tests { + if got := PathToPrefix(tc.Path); got != tc.Expected { + t.Errorf("expected PathToPrefix(%s) = %s, got %s", tc.Path, tc.Expected, got) + } + } +} diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go new file mode 100644 index 0000000..2bc7b2d --- /dev/null +++ b/src/cmd/internal/objabi/reloctype.go @@ -0,0 +1,378 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// 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 objabi + +type RelocType int16 + +//go:generate stringer -type=RelocType +const ( + R_ADDR RelocType = 1 + iota + // R_ADDRPOWER relocates a pair of "D-form" instructions (instructions with 16-bit + // immediates in the low half of the instruction word), usually addis followed by + // another add or a load, inserting the "high adjusted" 16 bits of the address of + // the referenced symbol into the immediate field of the first instruction and the + // low 16 bits into that of the second instruction. + R_ADDRPOWER + // R_ADDRARM64 relocates an adrp, add pair to compute the address of the + // referenced symbol. + R_ADDRARM64 + // R_ADDRMIPS (only used on mips/mips64) resolves to the low 16 bits of an external + // address, by encoding it into the instruction. + R_ADDRMIPS + // R_ADDROFF resolves to a 32-bit offset from the beginning of the section + // holding the data being relocated to the referenced symbol. + R_ADDROFF + R_SIZE + R_CALL + R_CALLARM + R_CALLARM64 + R_CALLIND + R_CALLPOWER + // R_CALLMIPS (only used on mips64) resolves to non-PC-relative target address + // of a CALL (JAL) instruction, by encoding the address into the instruction. + R_CALLMIPS + R_CONST + R_PCREL + // R_TLS_LE, used on 386, amd64, and ARM, resolves to the offset of the + // thread-local symbol from the thread local base and is used to implement the + // "local exec" model for tls access (r.Sym is not set on intel platforms but is + // set to a TLS symbol -- runtime.tlsg -- in the linker when externally linking). + R_TLS_LE + // R_TLS_IE, used 386, amd64, and ARM resolves to the PC-relative offset to a GOT + // slot containing the offset from the thread-local symbol from the thread local + // base and is used to implemented the "initial exec" model for tls access (r.Sym + // is not set on intel platforms but is set to a TLS symbol -- runtime.tlsg -- in + // the linker when externally linking). + R_TLS_IE + R_GOTOFF + R_PLT0 + R_PLT1 + R_PLT2 + R_USEFIELD + // R_USETYPE resolves to an *rtype, but no relocation is created. The + // linker uses this as a signal that the pointed-to type information + // should be linked into the final binary, even if there are no other + // direct references. (This is used for types reachable by reflection.) + R_USETYPE + // R_USEIFACE marks a type is converted to an interface in the function this + // relocation is applied to. The target is a type descriptor. + // This is a marker relocation (0-sized), for the linker's reachabililty + // analysis. + R_USEIFACE + // R_USEIFACEMETHOD marks an interface method that is used in the function + // this relocation is applied to. The target is an interface type descriptor. + // The addend is the offset of the method in the type descriptor. + // This is a marker relocation (0-sized), for the linker's reachabililty + // analysis. + R_USEIFACEMETHOD + // Similar to R_USEIFACEMETHOD, except instead of indicating a type + + // method offset with Sym+Add, Sym points to a symbol containing the name + // of the method being called. See the description in + // cmd/compile/internal/reflectdata/reflect.go:MarkUsedIfaceMethod for details. + R_USEGENERICIFACEMETHOD + // R_METHODOFF resolves to a 32-bit offset from the beginning of the section + // holding the data being relocated to the referenced symbol. + // It is a variant of R_ADDROFF used when linking from the uncommonType of a + // *rtype, and may be set to zero by the linker if it determines the method + // text is unreachable by the linked program. + R_METHODOFF + // R_KEEP tells the linker to keep the referred-to symbol in the final binary + // if the symbol containing the R_KEEP relocation is in the final binary. + R_KEEP + R_POWER_TOC + R_GOTPCREL + // R_JMPMIPS (only used on mips64) resolves to non-PC-relative target address + // of a JMP instruction, by encoding the address into the instruction. + // The stack nosplit check ignores this since it is not a function call. + R_JMPMIPS + + // R_DWARFSECREF resolves to the offset of the symbol from its section. + // Target of relocation must be size 4 (in current implementation). + R_DWARFSECREF + + // R_DWARFFILEREF resolves to an index into the DWARF .debug_line + // file table for the specified file symbol. Must be applied to an + // attribute of form DW_FORM_data4. + R_DWARFFILEREF + + // Platform dependent relocations. Architectures with fixed width instructions + // have the inherent issue that a 32-bit (or 64-bit!) displacement cannot be + // stuffed into a 32-bit instruction, so an address needs to be spread across + // several instructions, and in turn this requires a sequence of relocations, each + // updating a part of an instruction. This leads to relocation codes that are + // inherently processor specific. + + // Arm64. + + // Set a MOV[NZ] immediate field to bits [15:0] of the offset from the thread + // local base to the thread local variable defined by the referenced (thread + // local) symbol. Error if the offset does not fit into 16 bits. + R_ARM64_TLS_LE + + // Relocates an ADRP; LD64 instruction sequence to load the offset between + // the thread local base and the thread local variable defined by the + // referenced (thread local) symbol from the GOT. + R_ARM64_TLS_IE + + // R_ARM64_GOTPCREL relocates an adrp, ld64 pair to compute the address of the GOT + // slot of the referenced symbol. + R_ARM64_GOTPCREL + + // R_ARM64_GOT resolves a GOT-relative instruction sequence, usually an adrp + // followed by another ld instruction. + R_ARM64_GOT + + // R_ARM64_PCREL resolves a PC-relative addresses instruction sequence, usually an + // adrp followed by another add instruction. + R_ARM64_PCREL + + // R_ARM64_PCREL_LDST8 resolves a PC-relative addresses instruction sequence, usually an + // adrp followed by a LD8 or ST8 instruction. + R_ARM64_PCREL_LDST8 + + // R_ARM64_PCREL_LDST16 resolves a PC-relative addresses instruction sequence, usually an + // adrp followed by a LD16 or ST16 instruction. + R_ARM64_PCREL_LDST16 + + // R_ARM64_PCREL_LDST32 resolves a PC-relative addresses instruction sequence, usually an + // adrp followed by a LD32 or ST32 instruction. + R_ARM64_PCREL_LDST32 + + // R_ARM64_PCREL_LDST64 resolves a PC-relative addresses instruction sequence, usually an + // adrp followed by a LD64 or ST64 instruction. + R_ARM64_PCREL_LDST64 + + // R_ARM64_LDST8 sets a LD/ST immediate value to bits [11:0] of a local address. + R_ARM64_LDST8 + + // R_ARM64_LDST16 sets a LD/ST immediate value to bits [11:1] of a local address. + R_ARM64_LDST16 + + // R_ARM64_LDST32 sets a LD/ST immediate value to bits [11:2] of a local address. + R_ARM64_LDST32 + + // R_ARM64_LDST64 sets a LD/ST immediate value to bits [11:3] of a local address. + R_ARM64_LDST64 + + // R_ARM64_LDST128 sets a LD/ST immediate value to bits [11:4] of a local address. + R_ARM64_LDST128 + + // PPC64. + + // R_POWER_TLS_LE is used to implement the "local exec" model for tls + // access. It resolves to the offset of the thread-local symbol from the + // thread pointer (R13) and is split against a pair of instructions to + // support a 32 bit displacement. + R_POWER_TLS_LE + + // R_POWER_TLS_IE is used to implement the "initial exec" model for tls access. It + // relocates a D-form, DS-form instruction sequence like R_ADDRPOWER_DS. It + // inserts to the offset of GOT slot for the thread-local symbol from the TOC (the + // GOT slot is filled by the dynamic linker with the offset of the thread-local + // symbol from the thread pointer (R13)). + R_POWER_TLS_IE + + // R_POWER_TLS marks an X-form instruction such as "ADD R3,R13,R4" as completing + // a sequence of GOT-relative relocations to compute a TLS address. This can be + // used by the system linker to to rewrite the GOT-relative TLS relocation into a + // simpler thread-pointer relative relocation. See table 3.26 and 3.28 in the + // ppc64 elfv2 1.4 ABI on this transformation. Likewise, the second argument + // (usually called RB in X-form instructions) is assumed to be R13. + R_POWER_TLS + + // R_POWER_TLS_IE_PCREL34 is similar to R_POWER_TLS_IE, but marks a single MOVD + // which has been assembled as a single prefixed load doubleword without using the + // TOC. + R_POWER_TLS_IE_PCREL34 + + // R_POWER_TLS_LE_TPREL34 is similar to R_POWER_TLS_LE, but computes an offset from + // the thread pointer in one prefixed instruction. + R_POWER_TLS_LE_TPREL34 + + // R_ADDRPOWER_DS is similar to R_ADDRPOWER above, but assumes the second + // instruction is a "DS-form" instruction, which has an immediate field occupying + // bits [15:2] of the instruction word. Bits [15:2] of the address of the + // relocated symbol are inserted into this field; it is an error if the last two + // bits of the address are not 0. + R_ADDRPOWER_DS + + // R_ADDRPOWER_GOT relocates a D-form + DS-form instruction sequence by inserting + // a relative displacement of referenced symbol's GOT entry to the TOC pointer. + R_ADDRPOWER_GOT + + // R_ADDRPOWER_GOT_PCREL34 is identical to R_ADDRPOWER_GOT, but uses a PC relative + // sequence to generate a GOT symbol addresss. + R_ADDRPOWER_GOT_PCREL34 + + // R_ADDRPOWER_PCREL relocates two D-form instructions like R_ADDRPOWER, but + // inserts the displacement from the place being relocated to the address of the + // relocated symbol instead of just its address. + R_ADDRPOWER_PCREL + + // R_ADDRPOWER_TOCREL relocates two D-form instructions like R_ADDRPOWER, but + // inserts the offset from the TOC to the address of the relocated symbol + // rather than the symbol's address. + R_ADDRPOWER_TOCREL + + // R_ADDRPOWER_TOCREL_DS relocates a D-form, DS-form instruction sequence like + // R_ADDRPOWER_DS but inserts the offset from the TOC to the address of the + // relocated symbol rather than the symbol's address. + R_ADDRPOWER_TOCREL_DS + + // R_ADDRPOWER_D34 relocates a single prefixed D-form load/store operation. All + // prefixed forms are D form. The high 18 bits are stored in the prefix, + // and the low 16 are stored in the suffix. The address is absolute. + R_ADDRPOWER_D34 + + // R_ADDRPOWER_PCREL34 relates a single prefixed D-form load/store/add operation. + // All prefixed forms are D form. The resulting address is relative to the + // PC. It is a signed 34 bit offset. + R_ADDRPOWER_PCREL34 + + // RISC-V. + + // R_RISCV_CALL relocates a J-type instruction with a 21 bit PC-relative + // address. + R_RISCV_CALL + + // R_RISCV_CALL_TRAMP is the same as R_RISCV_CALL but denotes the use of a + // trampoline, which we may be able to avoid during relocation. These are + // only used by the linker and are not emitted by the compiler or assembler. + R_RISCV_CALL_TRAMP + + // R_RISCV_PCREL_ITYPE resolves a 32-bit PC-relative address using an + // AUIPC + I-type instruction pair. + R_RISCV_PCREL_ITYPE + + // R_RISCV_PCREL_STYPE resolves a 32-bit PC-relative address using an + // AUIPC + S-type instruction pair. + R_RISCV_PCREL_STYPE + + // R_RISCV_TLS_IE_ITYPE resolves a 32-bit TLS initial-exec TOC offset + // address using an AUIPC + I-type instruction pair. + R_RISCV_TLS_IE_ITYPE + + // R_RISCV_TLS_IE_STYPE resolves a 32-bit TLS initial-exec TOC offset + // address using an AUIPC + S-type instruction pair. + R_RISCV_TLS_IE_STYPE + + // R_PCRELDBL relocates s390x 2-byte aligned PC-relative addresses. + // TODO(mundaym): remove once variants can be serialized - see issue 14218. + R_PCRELDBL + + // Loong64. + + // R_ADDRLOONG64 resolves to the low 12 bits of an external address, by encoding + // it into the instruction. + R_ADDRLOONG64 + + // R_ADDRLOONG64U resolves to the sign-adjusted "upper" 20 bits (bit 5-24) of an + // external address, by encoding it into the instruction. + R_ADDRLOONG64U + + // R_ADDRLOONG64TLS resolves to the low 12 bits of a TLS address (offset from + // thread pointer), by encoding it into the instruction. + R_ADDRLOONG64TLS + + // R_ADDRLOONG64TLSU resolves to the high 20 bits of a TLS address (offset from + // thread pointer), by encoding it into the instruction. + R_ADDRLOONG64TLSU + + // R_CALLLOONG64 resolves to non-PC-relative target address of a CALL (BL/JIRL) + // instruction, by encoding the address into the instruction. + R_CALLLOONG64 + + // R_JMPLOONG64 resolves to non-PC-relative target address of a JMP instruction, + // by encoding the address into the instruction. + R_JMPLOONG64 + + // R_ADDRMIPSU (only used on mips/mips64) resolves to the sign-adjusted "upper" 16 + // bits (bit 16-31) of an external address, by encoding it into the instruction. + R_ADDRMIPSU + // R_ADDRMIPSTLS (only used on mips64) resolves to the low 16 bits of a TLS + // address (offset from thread pointer), by encoding it into the instruction. + R_ADDRMIPSTLS + + // R_ADDRCUOFF resolves to a pointer-sized offset from the start of the + // symbol's DWARF compile unit. + R_ADDRCUOFF + + // R_WASMIMPORT resolves to the index of the WebAssembly function import. + R_WASMIMPORT + + // R_XCOFFREF (only used on aix/ppc64) prevents garbage collection by ld + // of a symbol. This isn't a real relocation, it can be placed in anywhere + // in a symbol and target any symbols. + R_XCOFFREF + + // R_WEAK marks the relocation as a weak reference. + // A weak relocation does not make the symbol it refers to reachable, + // and is only honored by the linker if the symbol is in some other way + // reachable. + R_WEAK = -1 << 15 + + R_WEAKADDR = R_WEAK | R_ADDR + R_WEAKADDROFF = R_WEAK | R_ADDROFF +) + +// IsDirectCall reports whether r is a relocation for a direct call. +// A direct call is a CALL instruction that takes the target address +// as an immediate. The address is embedded into the instruction, possibly +// with limited width. An indirect call is a CALL instruction that takes +// the target address in register or memory. +func (r RelocType) IsDirectCall() bool { + switch r { + case R_CALL, R_CALLARM, R_CALLARM64, R_CALLLOONG64, R_CALLMIPS, R_CALLPOWER, R_RISCV_CALL, R_RISCV_CALL_TRAMP: + return true + } + return false +} + +// IsDirectJump reports whether r is a relocation for a direct jump. +// A direct jump is a JMP instruction that takes the target address +// as an immediate. The address is embedded into the instruction, possibly +// with limited width. An indirect jump is a JMP instruction that takes +// the target address in register or memory. +func (r RelocType) IsDirectJump() bool { + switch r { + case R_JMPMIPS: + return true + case R_JMPLOONG64: + return true + } + return false +} + +// IsDirectCallOrJump reports whether r is a relocation for a direct +// call or a direct jump. +func (r RelocType) IsDirectCallOrJump() bool { + return r.IsDirectCall() || r.IsDirectJump() +} diff --git a/src/cmd/internal/objabi/reloctype_string.go b/src/cmd/internal/objabi/reloctype_string.go new file mode 100644 index 0000000..9ce37d0 --- /dev/null +++ b/src/cmd/internal/objabi/reloctype_string.go @@ -0,0 +1,100 @@ +// Code generated by "stringer -type=RelocType"; DO NOT EDIT. + +package objabi + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[R_ADDR-1] + _ = x[R_ADDRPOWER-2] + _ = x[R_ADDRARM64-3] + _ = x[R_ADDRMIPS-4] + _ = x[R_ADDROFF-5] + _ = x[R_SIZE-6] + _ = x[R_CALL-7] + _ = x[R_CALLARM-8] + _ = x[R_CALLARM64-9] + _ = x[R_CALLIND-10] + _ = x[R_CALLPOWER-11] + _ = x[R_CALLMIPS-12] + _ = x[R_CONST-13] + _ = x[R_PCREL-14] + _ = x[R_TLS_LE-15] + _ = x[R_TLS_IE-16] + _ = x[R_GOTOFF-17] + _ = x[R_PLT0-18] + _ = x[R_PLT1-19] + _ = x[R_PLT2-20] + _ = x[R_USEFIELD-21] + _ = x[R_USETYPE-22] + _ = x[R_USEIFACE-23] + _ = x[R_USEIFACEMETHOD-24] + _ = x[R_USEGENERICIFACEMETHOD-25] + _ = x[R_METHODOFF-26] + _ = x[R_KEEP-27] + _ = x[R_POWER_TOC-28] + _ = x[R_GOTPCREL-29] + _ = x[R_JMPMIPS-30] + _ = x[R_DWARFSECREF-31] + _ = x[R_DWARFFILEREF-32] + _ = x[R_ARM64_TLS_LE-33] + _ = x[R_ARM64_TLS_IE-34] + _ = x[R_ARM64_GOTPCREL-35] + _ = x[R_ARM64_GOT-36] + _ = x[R_ARM64_PCREL-37] + _ = x[R_ARM64_PCREL_LDST8-38] + _ = x[R_ARM64_PCREL_LDST16-39] + _ = x[R_ARM64_PCREL_LDST32-40] + _ = x[R_ARM64_PCREL_LDST64-41] + _ = x[R_ARM64_LDST8-42] + _ = x[R_ARM64_LDST16-43] + _ = x[R_ARM64_LDST32-44] + _ = x[R_ARM64_LDST64-45] + _ = x[R_ARM64_LDST128-46] + _ = x[R_POWER_TLS_LE-47] + _ = x[R_POWER_TLS_IE-48] + _ = x[R_POWER_TLS-49] + _ = x[R_POWER_TLS_IE_PCREL34-50] + _ = x[R_POWER_TLS_LE_TPREL34-51] + _ = x[R_ADDRPOWER_DS-52] + _ = x[R_ADDRPOWER_GOT-53] + _ = x[R_ADDRPOWER_GOT_PCREL34-54] + _ = x[R_ADDRPOWER_PCREL-55] + _ = x[R_ADDRPOWER_TOCREL-56] + _ = x[R_ADDRPOWER_TOCREL_DS-57] + _ = x[R_ADDRPOWER_D34-58] + _ = x[R_ADDRPOWER_PCREL34-59] + _ = x[R_RISCV_CALL-60] + _ = x[R_RISCV_CALL_TRAMP-61] + _ = x[R_RISCV_PCREL_ITYPE-62] + _ = x[R_RISCV_PCREL_STYPE-63] + _ = x[R_RISCV_TLS_IE_ITYPE-64] + _ = x[R_RISCV_TLS_IE_STYPE-65] + _ = x[R_PCRELDBL-66] + _ = x[R_ADDRLOONG64-67] + _ = x[R_ADDRLOONG64U-68] + _ = x[R_ADDRLOONG64TLS-69] + _ = x[R_ADDRLOONG64TLSU-70] + _ = x[R_CALLLOONG64-71] + _ = x[R_JMPLOONG64-72] + _ = x[R_ADDRMIPSU-73] + _ = x[R_ADDRMIPSTLS-74] + _ = x[R_ADDRCUOFF-75] + _ = x[R_WASMIMPORT-76] + _ = x[R_XCOFFREF-77] +} + +const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_USEGENERICIFACEMETHODR_METHODOFFR_KEEPR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_PCREL_LDST8R_ARM64_PCREL_LDST16R_ARM64_PCREL_LDST32R_ARM64_PCREL_LDST64R_ARM64_LDST8R_ARM64_LDST16R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_POWER_TLS_IE_PCREL34R_POWER_TLS_LE_TPREL34R_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_GOT_PCREL34R_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_ADDRPOWER_D34R_ADDRPOWER_PCREL34R_RISCV_CALLR_RISCV_CALL_TRAMPR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_RISCV_TLS_IE_ITYPER_RISCV_TLS_IE_STYPER_PCRELDBLR_ADDRLOONG64R_ADDRLOONG64UR_ADDRLOONG64TLSR_ADDRLOONG64TLSUR_CALLLOONG64R_JMPLOONG64R_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF" + +var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 53, 59, 68, 79, 88, 99, 109, 116, 123, 131, 139, 147, 153, 159, 165, 175, 184, 194, 210, 233, 244, 250, 261, 271, 280, 293, 307, 321, 335, 351, 362, 375, 394, 414, 434, 454, 467, 481, 495, 509, 524, 538, 552, 563, 585, 607, 621, 636, 659, 676, 694, 715, 730, 749, 761, 779, 798, 817, 837, 857, 867, 880, 894, 910, 927, 940, 952, 963, 976, 987, 999, 1009} + +func (i RelocType) String() string { + i -= 1 + if i < 0 || i >= RelocType(len(_RelocType_index)-1) { + return "RelocType(" + strconv.FormatInt(int64(i+1), 10) + ")" + } + return _RelocType_name[_RelocType_index[i]:_RelocType_index[i+1]] +} diff --git a/src/cmd/internal/objabi/stack.go b/src/cmd/internal/objabi/stack.go new file mode 100644 index 0000000..88b4990 --- /dev/null +++ b/src/cmd/internal/objabi/stack.go @@ -0,0 +1,40 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import "internal/buildcfg" + +// For the linkers. Must match Go definitions. + +const ( + STACKSYSTEM = 0 + StackSystem = STACKSYSTEM + StackBig = 4096 + StackSmall = 128 +) + +func StackLimit(race bool) int { + // This arithmetic must match that in runtime/stack.go:{_StackGuard,_StackLimit}. + stackGuard := 928*stackGuardMultiplier(race) + StackSystem + stackLimit := stackGuard - StackSystem - StackSmall + return stackLimit +} + +// stackGuardMultiplier returns a multiplier to apply to the default +// stack guard size. Larger multipliers are used for non-optimized +// builds that have larger stack frames or for specific targets. +func stackGuardMultiplier(race bool) int { + // This arithmetic must match that in runtime/internal/sys/consts.go:StackGuardMultiplier. + n := 1 + // On AIX, a larger stack is needed for syscalls. + if buildcfg.GOOS == "aix" { + n += 1 + } + // The race build also needs more stack. + if race { + n += 1 + } + return n +} diff --git a/src/cmd/internal/objabi/symkind.go b/src/cmd/internal/objabi/symkind.go new file mode 100644 index 0000000..a58816e --- /dev/null +++ b/src/cmd/internal/objabi/symkind.go @@ -0,0 +1,76 @@ +// Derived from Inferno utils/6l/l.h and related files. +// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h +// +// 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 objabi + +// A SymKind describes the kind of memory represented by a symbol. +type SymKind uint8 + +// Defined SymKind values. +// These are used to index into cmd/link/internal/sym/AbiSymKindToSymKind +// +// TODO(rsc): Give idiomatic Go names. +// +//go:generate stringer -type=SymKind +const ( + // An otherwise invalid zero value for the type + Sxxx SymKind = iota + // Executable instructions + STEXT + // Read only static data + SRODATA + // Static data that does not contain any pointers + SNOPTRDATA + // Static data + SDATA + // Statically data that is initially all 0s + SBSS + // Statically data that is initially all 0s and does not contain pointers + SNOPTRBSS + // Thread-local data that is initially all 0s + STLSBSS + // Debugging data + SDWARFCUINFO + SDWARFCONST + SDWARFFCN + SDWARFABSFCN + SDWARFTYPE + SDWARFVAR + SDWARFRANGE + SDWARFLOC + SDWARFLINES + // Coverage instrumentation counter for libfuzzer. + SLIBFUZZER_8BIT_COUNTER + // Coverage instrumentation counter, aux variable for cmd/cover + SCOVERAGE_COUNTER + SCOVERAGE_AUXVAR + + // Update cmd/link/internal/sym/AbiSymKindToSymKind for new SymKind values. +) diff --git a/src/cmd/internal/objabi/symkind_string.go b/src/cmd/internal/objabi/symkind_string.go new file mode 100644 index 0000000..be4e91f --- /dev/null +++ b/src/cmd/internal/objabi/symkind_string.go @@ -0,0 +1,42 @@ +// Code generated by "stringer -type=SymKind"; DO NOT EDIT. + +package objabi + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Sxxx-0] + _ = x[STEXT-1] + _ = x[SRODATA-2] + _ = x[SNOPTRDATA-3] + _ = x[SDATA-4] + _ = x[SBSS-5] + _ = x[SNOPTRBSS-6] + _ = x[STLSBSS-7] + _ = x[SDWARFCUINFO-8] + _ = x[SDWARFCONST-9] + _ = x[SDWARFFCN-10] + _ = x[SDWARFABSFCN-11] + _ = x[SDWARFTYPE-12] + _ = x[SDWARFVAR-13] + _ = x[SDWARFRANGE-14] + _ = x[SDWARFLOC-15] + _ = x[SDWARFLINES-16] + _ = x[SLIBFUZZER_8BIT_COUNTER-17] + _ = x[SCOVERAGE_COUNTER-18] + _ = x[SCOVERAGE_AUXVAR-19] +} + +const _SymKind_name = "SxxxSTEXTSRODATASNOPTRDATASDATASBSSSNOPTRBSSSTLSBSSSDWARFCUINFOSDWARFCONSTSDWARFFCNSDWARFABSFCNSDWARFTYPESDWARFVARSDWARFRANGESDWARFLOCSDWARFLINESSLIBFUZZER_8BIT_COUNTERSCOVERAGE_COUNTERSCOVERAGE_AUXVAR" + +var _SymKind_index = [...]uint8{0, 4, 9, 16, 26, 31, 35, 44, 51, 63, 74, 83, 95, 105, 114, 125, 134, 145, 168, 185, 201} + +func (i SymKind) String() string { + if i >= SymKind(len(_SymKind_index)-1) { + return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _SymKind_name[_SymKind_index[i]:_SymKind_index[i+1]] +} diff --git a/src/cmd/internal/objabi/typekind.go b/src/cmd/internal/objabi/typekind.go new file mode 100644 index 0000000..990ff18 --- /dev/null +++ b/src/cmd/internal/objabi/typekind.go @@ -0,0 +1,40 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +// Must match runtime and reflect. +// Included by cmd/gc. + +const ( + KindBool = 1 + iota + KindInt + KindInt8 + KindInt16 + KindInt32 + KindInt64 + KindUint + KindUint8 + KindUint16 + KindUint32 + KindUint64 + KindUintptr + KindFloat32 + KindFloat64 + KindComplex64 + KindComplex128 + KindArray + KindChan + KindFunc + KindInterface + KindMap + KindPtr + KindSlice + KindString + KindStruct + KindUnsafePointer + KindDirectIface = 1 << 5 + KindGCProg = 1 << 6 + KindMask = (1 << 5) - 1 +) diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go new file mode 100644 index 0000000..a3e1242 --- /dev/null +++ b/src/cmd/internal/objabi/util.go @@ -0,0 +1,33 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package objabi + +import ( + "fmt" + "strings" + + "internal/buildcfg" +) + +const ( + ElfRelocOffset = 256 + MachoRelocOffset = 2048 // reserve enough space for ELF relocations + GlobalDictPrefix = ".dict" // prefix for names of global dictionaries +) + +// HeaderString returns the toolchain configuration string written in +// Go object headers. This string ensures we don't attempt to import +// or link object files that are incompatible with each other. This +// string always starts with "go object ". +func HeaderString() string { + archExtra := "" + if k, v := buildcfg.GOGOARCH(); k != "" && v != "" { + archExtra = " " + k + "=" + v + } + return fmt.Sprintf("go object %s %s %s%s X:%s\n", + buildcfg.GOOS, buildcfg.GOARCH, + buildcfg.Version, archExtra, + strings.Join(buildcfg.Experiment.Enabled(), ",")) +} |