mirror of
https://github.com/golang/go.git
synced 2025-05-14 11:54:38 +00:00
This commit adds a new option to the x86 assembler. If the GOAMD64 environment variable is set to alignedjumps (the default) and we're doing a 64 bit build, the assembler will make sure that neither stand alone nor macro-fused jumps will end on or cross 32 byte boundaries. To achieve this, functions are aligned on 32 byte boundaries, rather than 16 bytes, and jump instructions are padded to ensure that they do not cross or end on 32 byte boundaries. Jumps are padded by adding a NOP instruction of the appropriate length before the jump. The commit is likely to result in larger binary sizes when GOAMD64=alignedjumps. On the binaries tested so far, an increase of between 1.4% and 1.5% has been observed. Updates #35881 Co-authored-by: David Chase <drchase@google.com> Change-Id: Ief0722300bc3f987098e4fd92b22b14ad6281d91 Reviewed-on: https://go-review.googlesource.com/c/go/+/219357 Reviewed-by: Cherry Zhang <cherryyz@google.com> Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
203 lines
4.0 KiB
Go
203 lines
4.0 KiB
Go
// 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 (
|
|
defaultGOROOT string // set by linker
|
|
|
|
GOROOT = envOr("GOROOT", defaultGOROOT)
|
|
GOARCH = envOr("GOARCH", defaultGOARCH)
|
|
GOOS = envOr("GOOS", defaultGOOS)
|
|
GO386 = envOr("GO386", defaultGO386)
|
|
GOAMD64 = goamd64()
|
|
GOARM = goarm()
|
|
GOMIPS = gomips()
|
|
GOMIPS64 = gomips64()
|
|
GOPPC64 = goppc64()
|
|
GOWASM = gowasm()
|
|
GO_LDSO = defaultGO_LDSO
|
|
Version = version
|
|
)
|
|
|
|
const (
|
|
ElfRelocOffset = 256
|
|
MachoRelocOffset = 2048 // reserve enough space for ELF relocations
|
|
)
|
|
|
|
func goamd64() string {
|
|
switch v := envOr("GOAMD64", defaultGOAMD64); v {
|
|
case "normaljumps", "alignedjumps":
|
|
return v
|
|
}
|
|
log.Fatalf("Invalid GOAMD64 value. Must be normaljumps or alignedjumps.")
|
|
panic("unreachable")
|
|
}
|
|
|
|
func goarm() int {
|
|
switch v := envOr("GOARM", defaultGOARM); v {
|
|
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")
|
|
}
|
|
|
|
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")
|
|
}
|
|
|
|
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")
|
|
}
|
|
|
|
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")
|
|
}
|
|
|
|
type gowasmFeatures struct {
|
|
SignExt bool
|
|
SatConv bool
|
|
}
|
|
|
|
func (f gowasmFeatures) String() string {
|
|
var flags []string
|
|
if f.SatConv {
|
|
flags = append(flags, "satconv")
|
|
}
|
|
if f.SignExt {
|
|
flags = append(flags, "signext")
|
|
}
|
|
return strings.Join(flags, ",")
|
|
}
|
|
|
|
func gowasm() (f gowasmFeatures) {
|
|
for _, opt := range strings.Split(envOr("GOWASM", ""), ",") {
|
|
switch opt {
|
|
case "satconv":
|
|
f.SatConv = true
|
|
case "signext":
|
|
f.SignExt = true
|
|
case "":
|
|
// ignore
|
|
default:
|
|
log.Fatalf("Invalid GOWASM value. No such feature: " + opt)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func Getgoextlinkenabled() string {
|
|
return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
|
|
}
|
|
|
|
func init() {
|
|
for _, f := range strings.Split(goexperiment, ",") {
|
|
if f != "" {
|
|
addexp(f)
|
|
}
|
|
}
|
|
}
|
|
|
|
func Framepointer_enabled(goos, goarch string) bool {
|
|
return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && goos == "linux")
|
|
}
|
|
|
|
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 (
|
|
framepointer_enabled int = 1
|
|
Fieldtrack_enabled int
|
|
Preemptibleloops_enabled int
|
|
Staticlockranking_enabled int
|
|
)
|
|
|
|
// Toolchain experiments.
|
|
// These are controlled by the GOEXPERIMENT environment
|
|
// variable recorded when the toolchain is built.
|
|
// This list is also known to cmd/gc.
|
|
var exper = []struct {
|
|
name string
|
|
val *int
|
|
}{
|
|
{"fieldtrack", &Fieldtrack_enabled},
|
|
{"framepointer", &framepointer_enabled},
|
|
{"preemptibleloops", &Preemptibleloops_enabled},
|
|
{"staticlockranking", &Staticlockranking_enabled},
|
|
}
|
|
|
|
var defaultExpstring = Expstring()
|
|
|
|
func DefaultExpstring() string {
|
|
return defaultExpstring
|
|
}
|
|
|
|
func Expstring() string {
|
|
buf := "X"
|
|
for i := range exper {
|
|
if *exper[i].val != 0 {
|
|
buf += "," + exper[i].name
|
|
}
|
|
}
|
|
if buf == "X" {
|
|
buf += ",none"
|
|
}
|
|
return "X:" + buf[2:]
|
|
}
|