2017-04-18 12:53:25 -07:00
|
|
|
// 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"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func envOr(key, value string) string {
|
|
|
|
|
if x := os.Getenv(key); x != "" {
|
|
|
|
|
return x
|
|
|
|
|
}
|
|
|
|
|
return value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
cmd/link: set runtime.GOROOT default during link
Suppose you build the Go toolchain in directory A,
move the whole thing to directory B, and then use
it from B to build a new program hello.exe, and then
run hello.exe, and hello.exe crashes with a stack
trace into the standard library.
Long ago, you'd have seen hello.exe print file names
in the A directory tree, even though the files had moved
to the B directory tree. About two years ago we changed
the compiler to write down these files with the name
"$GOROOT" (that literal string) instead of A, so that the
final link from B could replace "$GOROOT" with B,
so that hello.exe's crash would show the correct source
file paths in the stack trace. (golang.org/cl/18200)
Now suppose that you do the same thing but hello.exe
doesn't crash: it prints fmt.Println(runtime.GOROOT()).
And you run hello.exe after clearing $GOROOT from the
environment.
Long ago, you'd have seen hello.exe print A instead of B.
Before this CL, you'd still see hello.exe print A instead of B.
This case is the one instance where a moved toolchain
still divulges its origin. Not anymore. After this CL, hello.exe
will print B, because the linker sets runtime/internal/sys.DefaultGoroot
with the effective GOROOT from link time.
This makes the default result of runtime.GOROOT once again
match the file names recorded in the binary, after two years
of divergence.
With that cleared up, we can reintroduce GOROOT into the
link action ID and also reenable TestExecutableGOROOT/RelocatedExe.
When $GOROOT_FINAL is set during link, it is used
in preference to $GOROOT, as always, but it was easier
to explain the behavior above without introducing that
complication.
Fixes #22155.
Fixes #20284.
Fixes #22475.
Change-Id: Ifdaeb77fd4678fdb337cf59ee25b2cd873ec1016
Reviewed-on: https://go-review.googlesource.com/86835
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-01-08 11:59:29 -05:00
|
|
|
defaultGOROOT string // set by linker
|
|
|
|
|
|
2021-03-15 15:43:45 -04:00
|
|
|
GOROOT = envOr("GOROOT", defaultGOROOT)
|
|
|
|
|
GOARCH = envOr("GOARCH", defaultGOARCH)
|
|
|
|
|
GOOS = envOr("GOOS", defaultGOOS)
|
|
|
|
|
GO386 = envOr("GO386", defaultGO386)
|
|
|
|
|
GOARM = goarm()
|
|
|
|
|
GOMIPS = gomips()
|
|
|
|
|
GOMIPS64 = gomips64()
|
|
|
|
|
GOPPC64 = goppc64()
|
|
|
|
|
GOWASM = gowasm()
|
|
|
|
|
GO_LDSO = defaultGO_LDSO
|
|
|
|
|
Version = version
|
|
|
|
|
|
|
|
|
|
// GOEXPERIMENT is a comma-separated list of enabled
|
|
|
|
|
// experiments. This is derived from the GOEXPERIMENT
|
|
|
|
|
// environment variable if set, or the value of GOEXPERIMENT
|
|
|
|
|
// when make.bash was run if not.
|
|
|
|
|
GOEXPERIMENT string // Set by package init
|
2017-04-18 12:53:25 -07:00
|
|
|
)
|
|
|
|
|
|
2019-04-16 02:49:09 +00:00
|
|
|
const (
|
|
|
|
|
ElfRelocOffset = 256
|
2020-10-30 18:36:41 -04:00
|
|
|
MachoRelocOffset = 2048 // reserve enough space for ELF relocations
|
2019-04-16 02:49:09 +00:00
|
|
|
)
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
func goarm() int {
|
2020-11-24 17:48:38 +01:00
|
|
|
def := defaultGOARM
|
2020-11-25 19:12:13 +01:00
|
|
|
if GOOS == "android" && GOARCH == "arm" {
|
|
|
|
|
// Android arm devices always support GOARM=7.
|
2020-11-24 17:48:38 +01:00
|
|
|
def = "7"
|
|
|
|
|
}
|
|
|
|
|
switch v := envOr("GOARM", def); v {
|
2017-04-18 12:53:25 -07:00
|
|
|
case "5":
|
|
|
|
|
return 5
|
|
|
|
|
case "6":
|
|
|
|
|
return 6
|
|
|
|
|
case "7":
|
|
|
|
|
return 7
|
|
|
|
|
}
|
|
|
|
|
// Fail here, rather than validate at multiple call sites.
|
|
|
|
|
log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
|
|
|
|
|
panic("unreachable")
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-22 18:23:31 +02:00
|
|
|
func gomips() string {
|
|
|
|
|
switch v := envOr("GOMIPS", defaultGOMIPS); v {
|
|
|
|
|
case "hardfloat", "softfloat":
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
log.Fatalf("Invalid GOMIPS value. Must be hardfloat or softfloat.")
|
|
|
|
|
panic("unreachable")
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-26 15:37:27 +02:00
|
|
|
func gomips64() string {
|
|
|
|
|
switch v := envOr("GOMIPS64", defaultGOMIPS64); v {
|
|
|
|
|
case "hardfloat", "softfloat":
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
log.Fatalf("Invalid GOMIPS64 value. Must be hardfloat or softfloat.")
|
|
|
|
|
panic("unreachable")
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 17:16:28 -02:00
|
|
|
func goppc64() int {
|
|
|
|
|
switch v := envOr("GOPPC64", defaultGOPPC64); v {
|
|
|
|
|
case "power8":
|
|
|
|
|
return 8
|
|
|
|
|
case "power9":
|
|
|
|
|
return 9
|
|
|
|
|
}
|
|
|
|
|
log.Fatalf("Invalid GOPPC64 value. Must be power8 or power9.")
|
|
|
|
|
panic("unreachable")
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-23 14:18:19 +01:00
|
|
|
type gowasmFeatures struct {
|
2019-03-23 15:25:42 +01:00
|
|
|
SignExt bool
|
2019-03-24 12:14:27 +01:00
|
|
|
SatConv bool
|
2019-03-23 14:18:19 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-08 11:23:42 -04:00
|
|
|
func (f gowasmFeatures) String() string {
|
2019-03-23 14:18:19 +01:00
|
|
|
var flags []string
|
2019-03-24 12:14:27 +01:00
|
|
|
if f.SatConv {
|
|
|
|
|
flags = append(flags, "satconv")
|
|
|
|
|
}
|
2019-03-23 15:25:42 +01:00
|
|
|
if f.SignExt {
|
|
|
|
|
flags = append(flags, "signext")
|
|
|
|
|
}
|
2019-03-23 14:18:19 +01:00
|
|
|
return strings.Join(flags, ",")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gowasm() (f gowasmFeatures) {
|
|
|
|
|
for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
|
|
|
|
|
switch opt {
|
2019-03-24 12:14:27 +01:00
|
|
|
case "satconv":
|
|
|
|
|
f.SatConv = true
|
2019-03-23 15:25:42 +01:00
|
|
|
case "signext":
|
|
|
|
|
f.SignExt = true
|
2019-03-23 14:18:19 +01:00
|
|
|
case "":
|
|
|
|
|
// ignore
|
|
|
|
|
default:
|
|
|
|
|
log.Fatalf("Invalid GOWASM value. No such feature: " + opt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
func Getgoextlinkenabled() string {
|
|
|
|
|
return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func init() {
|
2021-03-15 15:43:45 -04:00
|
|
|
// Capture "default" experiments.
|
|
|
|
|
defaultExpstring = Expstring()
|
|
|
|
|
|
|
|
|
|
goexperiment := envOr("GOEXPERIMENT", defaultGOEXPERIMENT)
|
|
|
|
|
|
|
|
|
|
for _, f := range strings.Split(goexperiment, ",") {
|
2017-04-18 12:53:25 -07:00
|
|
|
if f != "" {
|
|
|
|
|
addexp(f)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-01 11:16:33 -04:00
|
|
|
|
|
|
|
|
// regabi is only supported on amd64.
|
|
|
|
|
if GOARCH != "amd64" {
|
|
|
|
|
Regabi_enabled = 0
|
|
|
|
|
}
|
2021-03-15 15:43:45 -04:00
|
|
|
|
|
|
|
|
// Set GOEXPERIMENT to the parsed and canonicalized set of experiments.
|
|
|
|
|
GOEXPERIMENT = expList()
|
2017-04-18 12:53:25 -07:00
|
|
|
}
|
|
|
|
|
|
2020-08-21 11:09:45 -07:00
|
|
|
// Note: must agree with runtime.framepointer_enabled.
|
runtime: enable framepointer on all arm64
Frame pointers were already enabled on linux, darwin, ios,
but not freebsd, android, openbsd, netbsd.
But the space was reserved on all platforms, leading to
two different arm64 framepointer conditions in different
parts of the code, one of which had no name
(framepointer_enabled || GOARCH == "arm64",
which might have been "framepointer_space_reserved").
So on the disabled systems, the stack layouts were still
set up for frame pointers and the only difference was not
actually maintaining the FP register in the generated code.
Reduce complexity by just enabling the frame pointer
completely on all the arm64 systems.
This commit passes on freebsd, android, netbsd.
I have not been able to try it on openbsd.
This CL is part of a stack adding windows/arm64
support (#36439), intended to land in the Go 1.17 cycle.
This CL is, however, not windows/arm64-specific.
It is cleanup meant to make the port (and future ports) easier.
Change-Id: I83bd23369d24b76db4c6a648fa74f6917819a093
Reviewed-on: https://go-review.googlesource.com/c/go/+/288814
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2021-01-27 11:34:42 -05:00
|
|
|
var Framepointer_enabled = GOARCH == "amd64" || GOARCH == "arm64"
|
2017-04-18 12:53:25 -07:00
|
|
|
|
|
|
|
|
func addexp(s string) {
|
|
|
|
|
// Could do general integer parsing here, but the runtime copy doesn't yet.
|
|
|
|
|
v := 1
|
|
|
|
|
name := s
|
|
|
|
|
if len(name) > 2 && name[:2] == "no" {
|
|
|
|
|
v = 0
|
|
|
|
|
name = name[2:]
|
|
|
|
|
}
|
|
|
|
|
for i := 0; i < len(exper); i++ {
|
|
|
|
|
if exper[i].name == name {
|
|
|
|
|
if exper[i].val != nil {
|
|
|
|
|
*exper[i].val = v
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Printf("unknown experiment %s\n", s)
|
|
|
|
|
os.Exit(2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
runtime: static lock ranking for the runtime (enabled by GOEXPERIMENT)
I took some of the infrastructure from Austin's lock logging CR
https://go-review.googlesource.com/c/go/+/192704 (with deadlock
detection from the logs), and developed a setup to give static lock
ranking for runtime locks.
Static lock ranking establishes a documented total ordering among locks,
and then reports an error if the total order is violated. This can
happen if a deadlock happens (by acquiring a sequence of locks in
different orders), or if just one side of a possible deadlock happens.
Lock ordering deadlocks cannot happen as long as the lock ordering is
followed.
Along the way, I found a deadlock involving the new timer code, which Ian fixed
via https://go-review.googlesource.com/c/go/+/207348, as well as two other
potential deadlocks.
See the constants at the top of runtime/lockrank.go to show the static
lock ranking that I ended up with, along with some comments. This is
great documentation of the current intended lock ordering when acquiring
multiple locks in the runtime.
I also added an array lockPartialOrder[] which shows and enforces the
current partial ordering among locks (which is embedded within the total
ordering). This is more specific about the dependencies among locks.
I don't try to check the ranking within a lock class with multiple locks
that can be acquired at the same time (i.e. check the ranking when
multiple hchan locks are acquired).
Currently, I am doing a lockInit() call to set the lock rank of most
locks. Any lock that is not otherwise initialized is assumed to be a
leaf lock (a very high rank lock), so that eliminates the need to do
anything for a bunch of locks (including all architecture-dependent
locks). For two locks, root.lock and notifyList.lock (only in the
runtime/sema.go file), it is not as easy to do lock initialization, so
instead, I am passing the lock rank with the lock calls.
For Windows compilation, I needed to increase the StackGuard size from
896 to 928 because of the new lock-rank checking functions.
Checking of the static lock ranking is enabled by setting
GOEXPERIMENT=staticlockranking before doing a run.
To make sure that the static lock ranking code has no overhead in memory
or CPU when not enabled by GOEXPERIMENT, I changed 'go build/install' so
that it defines a build tag (with the same name) whenever any experiment
has been baked into the toolchain (by checking Expstring()). This allows
me to avoid increasing the size of the 'mutex' type when static lock
ranking is not enabled.
Fixes #38029
Change-Id: I154217ff307c47051f8dae9c2a03b53081acd83a
Reviewed-on: https://go-review.googlesource.com/c/go/+/207619
Reviewed-by: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-11-13 17:34:47 -08:00
|
|
|
Fieldtrack_enabled int
|
|
|
|
|
Preemptibleloops_enabled int
|
|
|
|
|
Staticlockranking_enabled int
|
2020-09-01 11:16:33 -04:00
|
|
|
Regabi_enabled int
|
2017-04-18 12:53:25 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Toolchain experiments.
|
|
|
|
|
// These are controlled by the GOEXPERIMENT environment
|
|
|
|
|
// variable recorded when the toolchain is built.
|
|
|
|
|
var exper = []struct {
|
|
|
|
|
name string
|
|
|
|
|
val *int
|
|
|
|
|
}{
|
|
|
|
|
{"fieldtrack", &Fieldtrack_enabled},
|
|
|
|
|
{"preemptibleloops", &Preemptibleloops_enabled},
|
runtime: static lock ranking for the runtime (enabled by GOEXPERIMENT)
I took some of the infrastructure from Austin's lock logging CR
https://go-review.googlesource.com/c/go/+/192704 (with deadlock
detection from the logs), and developed a setup to give static lock
ranking for runtime locks.
Static lock ranking establishes a documented total ordering among locks,
and then reports an error if the total order is violated. This can
happen if a deadlock happens (by acquiring a sequence of locks in
different orders), or if just one side of a possible deadlock happens.
Lock ordering deadlocks cannot happen as long as the lock ordering is
followed.
Along the way, I found a deadlock involving the new timer code, which Ian fixed
via https://go-review.googlesource.com/c/go/+/207348, as well as two other
potential deadlocks.
See the constants at the top of runtime/lockrank.go to show the static
lock ranking that I ended up with, along with some comments. This is
great documentation of the current intended lock ordering when acquiring
multiple locks in the runtime.
I also added an array lockPartialOrder[] which shows and enforces the
current partial ordering among locks (which is embedded within the total
ordering). This is more specific about the dependencies among locks.
I don't try to check the ranking within a lock class with multiple locks
that can be acquired at the same time (i.e. check the ranking when
multiple hchan locks are acquired).
Currently, I am doing a lockInit() call to set the lock rank of most
locks. Any lock that is not otherwise initialized is assumed to be a
leaf lock (a very high rank lock), so that eliminates the need to do
anything for a bunch of locks (including all architecture-dependent
locks). For two locks, root.lock and notifyList.lock (only in the
runtime/sema.go file), it is not as easy to do lock initialization, so
instead, I am passing the lock rank with the lock calls.
For Windows compilation, I needed to increase the StackGuard size from
896 to 928 because of the new lock-rank checking functions.
Checking of the static lock ranking is enabled by setting
GOEXPERIMENT=staticlockranking before doing a run.
To make sure that the static lock ranking code has no overhead in memory
or CPU when not enabled by GOEXPERIMENT, I changed 'go build/install' so
that it defines a build tag (with the same name) whenever any experiment
has been baked into the toolchain (by checking Expstring()). This allows
me to avoid increasing the size of the 'mutex' type when static lock
ranking is not enabled.
Fixes #38029
Change-Id: I154217ff307c47051f8dae9c2a03b53081acd83a
Reviewed-on: https://go-review.googlesource.com/c/go/+/207619
Reviewed-by: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-11-13 17:34:47 -08:00
|
|
|
{"staticlockranking", &Staticlockranking_enabled},
|
2020-09-01 11:16:33 -04:00
|
|
|
{"regabi", &Regabi_enabled},
|
2017-04-18 12:53:25 -07:00
|
|
|
}
|
|
|
|
|
|
2021-03-15 15:43:45 -04:00
|
|
|
var defaultExpstring string
|
2017-07-17 10:45:27 -04:00
|
|
|
|
2021-03-15 15:43:45 -04:00
|
|
|
// expList returns the list of enabled GOEXPERIMENTS as a
|
|
|
|
|
// commas-separated list.
|
|
|
|
|
func expList() string {
|
|
|
|
|
buf := ""
|
2017-04-18 12:53:25 -07:00
|
|
|
for i := range exper {
|
|
|
|
|
if *exper[i].val != 0 {
|
|
|
|
|
buf += "," + exper[i].name
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-03-15 15:43:45 -04:00
|
|
|
if len(buf) == 0 {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return buf[1:]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Expstring returns the GOEXPERIMENT string that should appear in Go
|
|
|
|
|
// version signatures. This always starts with "X:".
|
|
|
|
|
func Expstring() string {
|
|
|
|
|
list := expList()
|
|
|
|
|
if list == "" {
|
|
|
|
|
return "X:none"
|
2017-04-18 12:53:25 -07:00
|
|
|
}
|
2021-03-15 15:43:45 -04:00
|
|
|
return "X:" + list
|
2017-04-18 12:53:25 -07:00
|
|
|
}
|