mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
cmd/link/internal/ld: introduce -funcalign=N option
This patch adds linker option -funcalign=N that allows to set alignment for function entries. This CL is based on vasiliy.leonenko@gmail.com's cl/615736. For #72130 Change-Id: I57e5c9c4c71a989533643fda63a9a79c5c897dea Reviewed-on: https://go-review.googlesource.com/c/go/+/660996 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
parent
5b36f61356
commit
9302a57134
@ -83,6 +83,8 @@ Flags:
|
||||
Set space-separated flags to pass to the external linker.
|
||||
-f
|
||||
Ignore version mismatch in the linked archives.
|
||||
-funcalign N
|
||||
Set function alignment to N bytes
|
||||
-g
|
||||
Disable Go package data checks.
|
||||
-importcfg file
|
||||
|
@ -2658,9 +2658,7 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s loader.Sym, va uint64
|
||||
}
|
||||
|
||||
align := ldr.SymAlign(s)
|
||||
if align == 0 {
|
||||
align = int32(Funcalign)
|
||||
}
|
||||
align = max(align, int32(Funcalign))
|
||||
va = uint64(Rnd(int64(va), int64(align)))
|
||||
if sect.Align < align {
|
||||
sect.Align = align
|
||||
|
@ -377,7 +377,11 @@ func mayberemoveoutfile() {
|
||||
}
|
||||
|
||||
func libinit(ctxt *Link) {
|
||||
Funcalign = thearch.Funcalign
|
||||
if *FlagFuncAlign != 0 {
|
||||
Funcalign = *FlagFuncAlign
|
||||
} else {
|
||||
Funcalign = thearch.Funcalign
|
||||
}
|
||||
|
||||
// add goroot to the end of the libdir list.
|
||||
suffix := ""
|
||||
|
@ -105,6 +105,7 @@ var (
|
||||
FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
|
||||
FlagRound = flag.Int64("R", -1, "set address rounding `quantum`")
|
||||
FlagTextAddr = flag.Int64("T", -1, "set the start address of text symbols")
|
||||
FlagFuncAlign = flag.Int("funcalign", 0, "set function align to `N` bytes")
|
||||
flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
|
||||
flagPruneWeakMap = flag.Bool("pruneweakmap", true, "prune weak mapinit refs")
|
||||
flagRandLayout = flag.Int64("randlayout", 0, "randomize function layout")
|
||||
@ -251,6 +252,9 @@ func Main(arch *sys.Arch, theArch Arch) {
|
||||
if *FlagRound != -1 && (*FlagRound < 4096 || !isPowerOfTwo(*FlagRound)) {
|
||||
Exitf("invalid -R value 0x%x", *FlagRound)
|
||||
}
|
||||
if *FlagFuncAlign != 0 && !isPowerOfTwo(int64(*FlagFuncAlign)) {
|
||||
Exitf("invalid -funcalign value %d", *FlagFuncAlign)
|
||||
}
|
||||
|
||||
checkStrictDups = *FlagStrictDups
|
||||
|
||||
|
@ -16,6 +16,7 @@ import (
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -701,7 +702,6 @@ func TestFuncAlign(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Build and run with old object file format.
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "falign")
|
||||
cmd.Dir = tmpdir
|
||||
out, err := cmd.CombinedOutput()
|
||||
@ -718,6 +718,87 @@ func TestFuncAlign(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
const testFuncAlignOptionSrc = `
|
||||
package main
|
||||
//go:noinline
|
||||
func foo() {
|
||||
}
|
||||
//go:noinline
|
||||
func bar() {
|
||||
}
|
||||
//go:noinline
|
||||
func baz() {
|
||||
}
|
||||
func main() {
|
||||
foo()
|
||||
bar()
|
||||
baz()
|
||||
}
|
||||
`
|
||||
|
||||
// TestFuncAlignOption verifies that the -funcalign option changes the function alignment
|
||||
func TestFuncAlignOption(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
src := filepath.Join(tmpdir, "falign.go")
|
||||
err := os.WriteFile(src, []byte(testFuncAlignOptionSrc), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
alignTest := func(align uint64) {
|
||||
exeName := "falign.exe"
|
||||
cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-funcalign="+strconv.FormatUint(align, 10), "-o", exeName, "falign.go")
|
||||
cmd.Dir = tmpdir
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("build failed: %v \n%s", err, out)
|
||||
}
|
||||
exe := filepath.Join(tmpdir, exeName)
|
||||
cmd = testenv.Command(t, exe)
|
||||
out, err = cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Errorf("failed to run with err %v, output: %s", err, out)
|
||||
}
|
||||
|
||||
// Check function alignment
|
||||
f, err := objfile.Open(exe)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to open file:%v\n", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
fname := map[string]bool{"_main.foo": false,
|
||||
"_main.bar": false,
|
||||
"_main.baz": false}
|
||||
syms, err := f.Symbols()
|
||||
for _, s := range syms {
|
||||
fn := s.Name
|
||||
if _, ok := fname[fn]; !ok {
|
||||
fn = "_" + s.Name
|
||||
if _, ok := fname[fn]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if s.Addr%align != 0 {
|
||||
t.Fatalf("unaligned function: %s %x. Expected alignment: %d\n", fn, s.Addr, align)
|
||||
}
|
||||
fname[fn] = true
|
||||
}
|
||||
for k, v := range fname {
|
||||
if !v {
|
||||
t.Fatalf("function %s not found\n", k)
|
||||
}
|
||||
}
|
||||
}
|
||||
alignTest(16)
|
||||
alignTest(32)
|
||||
}
|
||||
|
||||
const testTrampSrc = `
|
||||
package main
|
||||
import "fmt"
|
||||
|
Loading…
x
Reference in New Issue
Block a user