Source file src/cmd/link/link_test.go

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"debug/macho"
    11  	"errors"
    12  	"internal/platform"
    13  	"internal/testenv"
    14  	"os"
    15  	"os/exec"
    16  	"path/filepath"
    17  	"regexp"
    18  	"runtime"
    19  	"strconv"
    20  	"strings"
    21  	"testing"
    22  
    23  	imacho "cmd/internal/macho"
    24  	"cmd/internal/objfile"
    25  	"cmd/internal/sys"
    26  )
    27  
    28  var AuthorPaidByTheColumnInch struct {
    29  	fog int `text:"London. Michaelmas term lately over, and the Lord Chancellor sitting in Lincoln’s Inn Hall. Implacable November weather. As much mud in the streets as if the waters had but newly retired from the face of the earth, and it would not be wonderful to meet a Megalosaurus, forty feet long or so, waddling like an elephantine lizard up Holborn Hill. Smoke lowering down from chimney-pots, making a soft black drizzle, with flakes of soot in it as big as full-grown snowflakes—gone into mourning, one might imagine, for the death of the sun. Dogs, undistinguishable in mire. Horses, scarcely better; splashed to their very blinkers. Foot passengers, jostling one another’s umbrellas in a general infection of ill temper, and losing their foot-hold at street-corners, where tens of thousands of other foot passengers have been slipping and sliding since the day broke (if this day ever broke), adding new deposits to the crust upon crust of mud, sticking at those points tenaciously to the pavement, and accumulating at compound interest.  	Fog everywhere. Fog up the river, where it flows among green aits and meadows; fog down the river, where it rolls defiled among the tiers of shipping and the waterside pollutions of a great (and dirty) city. Fog on the Essex marshes, fog on the Kentish heights. Fog creeping into the cabooses of collier-brigs; fog lying out on the yards and hovering in the rigging of great ships; fog drooping on the gunwales of barges and small boats. Fog in the eyes and throats of ancient Greenwich pensioners, wheezing by the firesides of their wards; fog in the stem and bowl of the afternoon pipe of the wrathful skipper, down in his close cabin; fog cruelly pinching the toes and fingers of his shivering little ‘prentice boy on deck. Chance people on the bridges peeping over the parapets into a nether sky of fog, with fog all round them, as if they were up in a balloon and hanging in the misty clouds.  	Gas looming through the fog in divers places in the streets, much as the sun may, from the spongey fields, be seen to loom by husbandman and ploughboy. Most of the shops lighted two hours before their time—as the gas seems to know, for it has a haggard and unwilling look.  	The raw afternoon is rawest, and the dense fog is densest, and the muddy streets are muddiest near that leaden-headed old obstruction, appropriate ornament for the threshold of a leaden-headed old corporation, Temple Bar. And hard by Temple Bar, in Lincoln’s Inn Hall, at the very heart of the fog, sits the Lord High Chancellor in his High Court of Chancery."`
    30  
    31  	wind int `text:"It was grand to see how the wind awoke, and bent the trees, and drove the rain before it like a cloud of smoke; and to hear the solemn thunder, and to see the lightning; and while thinking with awe of the tremendous powers by which our little lives are encompassed, to consider how beneficent they are, and how upon the smallest flower and leaf there was already a freshness poured from all this seeming rage, which seemed to make creation new again."`
    32  
    33  	jarndyce int `text:"Jarndyce and Jarndyce drones on. This scarecrow of a suit has, over the course of time, become so complicated, that no man alive knows what it means. The parties to it understand it least; but it has been observed that no two Chancery lawyers can talk about it for five minutes, without coming to a total disagreement as to all the premises. Innumerable children have been born into the cause; innumerable young people have married into it; innumerable old people have died out of it. Scores of persons have deliriously found themselves made parties in Jarndyce and Jarndyce, without knowing how or why; whole families have inherited legendary hatreds with the suit. The little plaintiff or defendant, who was promised a new rocking-horse when Jarndyce and Jarndyce should be settled, has grown up, possessed himself of a real horse, and trotted away into the other world. Fair wards of court have faded into mothers and grandmothers; a long procession of Chancellors has come in and gone out; the legion of bills in the suit have been transformed into mere bills of mortality; there are not three Jarndyces left upon the earth perhaps, since old Tom Jarndyce in despair blew his brains out at a coffee-house in Chancery Lane; but Jarndyce and Jarndyce still drags its dreary length before the Court, perennially hopeless."`
    34  
    35  	principle int `text:"The one great principle of the English law is, to make business for itself. There is no other principle distinctly, certainly, and consistently maintained through all its narrow turnings. Viewed by this light it becomes a coherent scheme, and not the monstrous maze the laity are apt to think it. Let them but once clearly perceive that its grand principle is to make business for itself at their expense, and surely they will cease to grumble."`
    36  }
    37  
    38  func TestLargeSymName(t *testing.T) {
    39  	// The compiler generates a symbol name using the string form of the
    40  	// type. This tests that the linker can read symbol names larger than
    41  	// the bufio buffer. Issue #15104.
    42  	_ = AuthorPaidByTheColumnInch
    43  }
    44  
    45  func TestIssue21703(t *testing.T) {
    46  	t.Parallel()
    47  
    48  	testenv.MustHaveGoBuild(t)
    49  	// N.B. the build below explictly doesn't pass through
    50  	// -asan/-msan/-race, so we don't care about those.
    51  	testenv.MustInternalLink(t, testenv.NoSpecialBuildTypes)
    52  
    53  	const source = `
    54  package main
    55  const X = "\n!\n"
    56  func main() {}
    57  `
    58  
    59  	tmpdir := t.TempDir()
    60  	main := filepath.Join(tmpdir, "main.go")
    61  
    62  	err := os.WriteFile(main, []byte(source), 0666)
    63  	if err != nil {
    64  		t.Fatalf("failed to write main.go: %v\n", err)
    65  	}
    66  
    67  	importcfgfile := filepath.Join(tmpdir, "importcfg")
    68  	testenv.WriteImportcfg(t, importcfgfile, nil, main)
    69  
    70  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
    71  	cmd.Dir = tmpdir
    72  	out, err := cmd.CombinedOutput()
    73  	if err != nil {
    74  		t.Fatalf("failed to compile main.go: %v, output: %s\n", err, out)
    75  	}
    76  
    77  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "main.o")
    78  	cmd.Dir = tmpdir
    79  	out, err = cmd.CombinedOutput()
    80  	if err != nil {
    81  		if runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
    82  			testenv.SkipFlaky(t, 58806)
    83  		}
    84  		t.Fatalf("failed to link main.o: %v, output: %s\n", err, out)
    85  	}
    86  }
    87  
    88  // TestIssue28429 ensures that the linker does not attempt to link
    89  // sections not named *.o. Such sections may be used by a build system
    90  // to, for example, save facts produced by a modular static analysis
    91  // such as golang.org/x/tools/go/analysis.
    92  func TestIssue28429(t *testing.T) {
    93  	t.Parallel()
    94  
    95  	testenv.MustHaveGoBuild(t)
    96  	// N.B. go build below explictly doesn't pass through
    97  	// -asan/-msan/-race, so we don't care about those.
    98  	testenv.MustInternalLink(t, testenv.NoSpecialBuildTypes)
    99  
   100  	tmpdir := t.TempDir()
   101  
   102  	write := func(name, content string) {
   103  		err := os.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
   104  		if err != nil {
   105  			t.Fatal(err)
   106  		}
   107  	}
   108  
   109  	runGo := func(args ...string) {
   110  		cmd := testenv.Command(t, testenv.GoToolPath(t), args...)
   111  		cmd.Dir = tmpdir
   112  		out, err := cmd.CombinedOutput()
   113  		if err != nil {
   114  			if len(args) >= 2 && args[1] == "link" && runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
   115  				testenv.SkipFlaky(t, 58806)
   116  			}
   117  			t.Fatalf("'go %s' failed: %v, output: %s",
   118  				strings.Join(args, " "), err, out)
   119  		}
   120  	}
   121  
   122  	// Compile a main package.
   123  	write("main.go", "package main; func main() {}")
   124  	importcfgfile := filepath.Join(tmpdir, "importcfg")
   125  	testenv.WriteImportcfg(t, importcfgfile, nil, filepath.Join(tmpdir, "main.go"))
   126  	runGo("tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
   127  	runGo("tool", "pack", "c", "main.a", "main.o")
   128  
   129  	// Add an extra section with a short, non-.o name.
   130  	// This simulates an alternative build system.
   131  	write(".facts", "this is not an object file")
   132  	runGo("tool", "pack", "r", "main.a", ".facts")
   133  
   134  	// Verify that the linker does not attempt
   135  	// to compile the extra section.
   136  	runGo("tool", "link", "-importcfg="+importcfgfile, "main.a")
   137  }
   138  
   139  func TestUnresolved(t *testing.T) {
   140  	testenv.MustHaveGoBuild(t)
   141  
   142  	t.Parallel()
   143  
   144  	tmpdir := t.TempDir()
   145  
   146  	write := func(name, content string) {
   147  		err := os.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
   148  		if err != nil {
   149  			t.Fatal(err)
   150  		}
   151  	}
   152  
   153  	// Test various undefined references. Because of issue #29852,
   154  	// this used to give confusing error messages because the
   155  	// linker would find an undefined reference to "zero" created
   156  	// by the runtime package.
   157  
   158  	write("go.mod", "module testunresolved\n")
   159  	write("main.go", `package main
   160  
   161  func main() {
   162          x()
   163  }
   164  
   165  func x()
   166  `)
   167  	write("main.s", `
   168  TEXT ·x(SB),0,$0
   169          MOVD zero<>(SB), AX
   170          MOVD zero(SB), AX
   171          MOVD ·zero(SB), AX
   172          RET
   173  `)
   174  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build")
   175  	cmd.Dir = tmpdir
   176  	cmd.Env = append(os.Environ(),
   177  		"GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath"))
   178  	out, err := cmd.CombinedOutput()
   179  	if err == nil {
   180  		t.Fatalf("expected build to fail, but it succeeded")
   181  	}
   182  	out = regexp.MustCompile("(?m)^#.*\n").ReplaceAll(out, nil)
   183  	got := string(out)
   184  	want := `main.x: relocation target zero not defined
   185  main.x: relocation target zero not defined
   186  main.x: relocation target main.zero not defined
   187  `
   188  	if want != got {
   189  		t.Fatalf("want:\n%sgot:\n%s", want, got)
   190  	}
   191  }
   192  
   193  func TestIssue33979(t *testing.T) {
   194  	testenv.MustHaveGoBuild(t)
   195  	testenv.MustHaveCGO(t)
   196  	// N.B. go build below explictly doesn't pass through
   197  	// -asan/-msan/-race, so we don't care about those.
   198  	testenv.MustInternalLink(t, testenv.SpecialBuildTypes{Cgo: true})
   199  
   200  	t.Parallel()
   201  
   202  	tmpdir := t.TempDir()
   203  
   204  	write := func(name, content string) {
   205  		err := os.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
   206  		if err != nil {
   207  			t.Fatal(err)
   208  		}
   209  	}
   210  
   211  	run := func(name string, args ...string) string {
   212  		cmd := testenv.Command(t, name, args...)
   213  		cmd.Dir = tmpdir
   214  		out, err := cmd.CombinedOutput()
   215  		if err != nil {
   216  			t.Fatalf("'go %s' failed: %v, output: %s", strings.Join(args, " "), err, out)
   217  		}
   218  		return string(out)
   219  	}
   220  	runGo := func(args ...string) string {
   221  		return run(testenv.GoToolPath(t), args...)
   222  	}
   223  
   224  	// Test object with undefined reference that was not generated
   225  	// by Go, resulting in an SXREF symbol being loaded during linking.
   226  	// Because of issue #33979, the SXREF symbol would be found during
   227  	// error reporting, resulting in confusing error messages.
   228  
   229  	write("main.go", `package main
   230  func main() {
   231          x()
   232  }
   233  func x()
   234  `)
   235  	// The following assembly must work on all architectures.
   236  	write("x.s", `
   237  TEXT ·x(SB),0,$0
   238          CALL foo(SB)
   239          RET
   240  `)
   241  	write("x.c", `
   242  void undefined();
   243  
   244  void foo() {
   245          undefined();
   246  }
   247  `)
   248  
   249  	cc := strings.TrimSpace(runGo("env", "CC"))
   250  	cflags := strings.Fields(runGo("env", "GOGCCFLAGS"))
   251  
   252  	importcfgfile := filepath.Join(tmpdir, "importcfg")
   253  	testenv.WriteImportcfg(t, importcfgfile, nil, "runtime")
   254  
   255  	// Compile, assemble and pack the Go and C code.
   256  	runGo("tool", "asm", "-p=main", "-gensymabis", "-o", "symabis", "x.s")
   257  	runGo("tool", "compile", "-importcfg="+importcfgfile, "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go")
   258  	runGo("tool", "asm", "-p=main", "-o", "x2.o", "x.s")
   259  	run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...)
   260  	runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o")
   261  
   262  	// Now attempt to link using the internal linker.
   263  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-linkmode=internal", "x.a")
   264  	cmd.Dir = tmpdir
   265  	out, err := cmd.CombinedOutput()
   266  	if err == nil {
   267  		t.Fatalf("expected link to fail, but it succeeded")
   268  	}
   269  	re := regexp.MustCompile(`(?m)^main\(.*text\): relocation target undefined not defined$`)
   270  	if !re.Match(out) {
   271  		t.Fatalf("got:\n%q\nwant:\n%s", out, re)
   272  	}
   273  }
   274  
   275  func TestBuildForTvOS(t *testing.T) {
   276  	testenv.MustHaveCGO(t)
   277  	testenv.MustHaveGoBuild(t)
   278  
   279  	// Only run this on darwin, where we can cross build for tvOS.
   280  	if runtime.GOOS != "darwin" {
   281  		t.Skip("skipping on non-darwin platform")
   282  	}
   283  	if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
   284  		t.Skip("skipping in -short mode with $GO_BUILDER_NAME empty")
   285  	}
   286  	if err := testenv.Command(t, "xcrun", "--help").Run(); err != nil {
   287  		t.Skipf("error running xcrun, required for iOS cross build: %v", err)
   288  	}
   289  
   290  	t.Parallel()
   291  
   292  	sdkPath, err := testenv.Command(t, "xcrun", "--sdk", "appletvos", "--show-sdk-path").Output()
   293  	if err != nil {
   294  		t.Skip("failed to locate appletvos SDK, skipping")
   295  	}
   296  	CC := []string{
   297  		"clang",
   298  		"-arch",
   299  		"arm64",
   300  		"-isysroot", strings.TrimSpace(string(sdkPath)),
   301  		"-mtvos-version-min=12.0",
   302  		"-fembed-bitcode",
   303  	}
   304  	CGO_LDFLAGS := []string{"-framework", "CoreFoundation"}
   305  	lib := filepath.Join("testdata", "testBuildFortvOS", "lib.go")
   306  	tmpDir := t.TempDir()
   307  
   308  	ar := filepath.Join(tmpDir, "lib.a")
   309  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", ar, lib)
   310  	env := []string{
   311  		"CGO_ENABLED=1",
   312  		"GOOS=ios",
   313  		"GOARCH=arm64",
   314  		"CC=" + strings.Join(CC, " "),
   315  		"CGO_CFLAGS=", // ensure CGO_CFLAGS does not contain any flags. Issue #35459
   316  		"CGO_LDFLAGS=" + strings.Join(CGO_LDFLAGS, " "),
   317  	}
   318  	cmd.Env = append(os.Environ(), env...)
   319  	t.Logf("%q %v", env, cmd)
   320  	if out, err := cmd.CombinedOutput(); err != nil {
   321  		t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
   322  	}
   323  
   324  	link := testenv.Command(t, CC[0], CC[1:]...)
   325  	link.Args = append(link.Args, CGO_LDFLAGS...)
   326  	link.Args = append(link.Args, "-o", filepath.Join(tmpDir, "a.out")) // Avoid writing to package directory.
   327  	link.Args = append(link.Args, ar, filepath.Join("testdata", "testBuildFortvOS", "main.m"))
   328  	t.Log(link)
   329  	if out, err := link.CombinedOutput(); err != nil {
   330  		t.Fatalf("%v: %v:\n%s", link.Args, err, out)
   331  	}
   332  }
   333  
   334  var testXFlagSrc = `
   335  package main
   336  var X = "hello"
   337  var Z = [99999]int{99998:12345} // make it large enough to be mmaped
   338  func main() { println(X) }
   339  `
   340  
   341  func TestXFlag(t *testing.T) {
   342  	testenv.MustHaveGoBuild(t)
   343  
   344  	t.Parallel()
   345  
   346  	tmpdir := t.TempDir()
   347  
   348  	src := filepath.Join(tmpdir, "main.go")
   349  	err := os.WriteFile(src, []byte(testXFlagSrc), 0666)
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  
   354  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-X=main.X=meow", "-o", filepath.Join(tmpdir, "main"), src)
   355  	if out, err := cmd.CombinedOutput(); err != nil {
   356  		t.Errorf("%v: %v:\n%s", cmd.Args, err, out)
   357  	}
   358  }
   359  
   360  var trivialSrc = `
   361  package main
   362  func main() { }
   363  `
   364  
   365  func TestMachOBuildVersion(t *testing.T) {
   366  	testenv.MustHaveGoBuild(t)
   367  
   368  	t.Parallel()
   369  
   370  	tmpdir := t.TempDir()
   371  
   372  	src := filepath.Join(tmpdir, "main.go")
   373  	err := os.WriteFile(src, []byte(trivialSrc), 0666)
   374  	if err != nil {
   375  		t.Fatal(err)
   376  	}
   377  
   378  	exe := filepath.Join(tmpdir, "main")
   379  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal", "-o", exe, src)
   380  	cmd.Env = append(os.Environ(),
   381  		"CGO_ENABLED=0",
   382  		"GOOS=darwin",
   383  		"GOARCH=amd64",
   384  	)
   385  	if out, err := cmd.CombinedOutput(); err != nil {
   386  		t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
   387  	}
   388  	exef, err := os.Open(exe)
   389  	if err != nil {
   390  		t.Fatal(err)
   391  	}
   392  	defer exef.Close()
   393  	exem, err := macho.NewFile(exef)
   394  	if err != nil {
   395  		t.Fatal(err)
   396  	}
   397  	found := false
   398  	checkMin := func(ver uint32) {
   399  		major, minor, patch := (ver>>16)&0xff, (ver>>8)&0xff, (ver>>0)&0xff
   400  		if major < 12 {
   401  			t.Errorf("LC_BUILD_VERSION version %d.%d.%d < 12.0.0", major, minor, patch)
   402  		}
   403  	}
   404  	for _, cmd := range exem.Loads {
   405  		raw := cmd.Raw()
   406  		type_ := exem.ByteOrder.Uint32(raw)
   407  		if type_ != imacho.LC_BUILD_VERSION {
   408  			continue
   409  		}
   410  		osVer := exem.ByteOrder.Uint32(raw[12:])
   411  		checkMin(osVer)
   412  		sdkVer := exem.ByteOrder.Uint32(raw[16:])
   413  		checkMin(sdkVer)
   414  		found = true
   415  		break
   416  	}
   417  	if !found {
   418  		t.Errorf("no LC_BUILD_VERSION load command found")
   419  	}
   420  }
   421  
   422  func TestMachOUUID(t *testing.T) {
   423  	testenv.MustHaveGoBuild(t)
   424  	if runtime.GOOS != "darwin" {
   425  		t.Skip("this is only for darwin")
   426  	}
   427  
   428  	t.Parallel()
   429  
   430  	tmpdir := t.TempDir()
   431  
   432  	src := filepath.Join(tmpdir, "main.go")
   433  	err := os.WriteFile(src, []byte(trivialSrc), 0666)
   434  	if err != nil {
   435  		t.Fatal(err)
   436  	}
   437  
   438  	extractUUID := func(exe string) string {
   439  		exem, err := macho.Open(exe)
   440  		if err != nil {
   441  			t.Fatal(err)
   442  		}
   443  		defer exem.Close()
   444  		for _, cmd := range exem.Loads {
   445  			raw := cmd.Raw()
   446  			type_ := exem.ByteOrder.Uint32(raw)
   447  			if type_ != imacho.LC_UUID {
   448  				continue
   449  			}
   450  			return string(raw[8:24])
   451  		}
   452  		return ""
   453  	}
   454  
   455  	tests := []struct{ name, ldflags, expect string }{
   456  		{"default", "", "gobuildid"},
   457  		{"gobuildid", "-B=gobuildid", "gobuildid"},
   458  		{"specific", "-B=0x0123456789ABCDEF0123456789ABCDEF", "\x01\x23\x45\x67\x89\xAB\xCD\xEF\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
   459  		{"none", "-B=none", ""},
   460  	}
   461  	if testenv.HasCGO() {
   462  		for _, test := range tests {
   463  			t1 := test
   464  			t1.name += "_external"
   465  			t1.ldflags += " -linkmode=external"
   466  			tests = append(tests, t1)
   467  		}
   468  	}
   469  	for _, test := range tests {
   470  		t.Run(test.name, func(t *testing.T) {
   471  			exe := filepath.Join(tmpdir, test.name)
   472  			cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags="+test.ldflags, "-o", exe, src)
   473  			if out, err := cmd.CombinedOutput(); err != nil {
   474  				t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
   475  			}
   476  			uuid := extractUUID(exe)
   477  			if test.expect == "gobuildid" {
   478  				// Go buildid is not known in source code. Check UUID is present,
   479  				// and satisfies UUIDv3.
   480  				if uuid == "" {
   481  					t.Fatal("expect nonempty UUID, got empty")
   482  				}
   483  				// The version number is the high 4 bits of byte 6.
   484  				if uuid[6]>>4 != 3 {
   485  					t.Errorf("expect v3 UUID, got %X (version %d)", uuid, uuid[6]>>4)
   486  				}
   487  			} else if uuid != test.expect {
   488  				t.Errorf("UUID mismatch: got %X, want %X", uuid, test.expect)
   489  			}
   490  		})
   491  	}
   492  }
   493  
   494  const Issue34788src = `
   495  
   496  package blah
   497  
   498  func Blah(i int) int {
   499  	a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
   500  	return a[i&7]
   501  }
   502  `
   503  
   504  func TestIssue34788Android386TLSSequence(t *testing.T) {
   505  	testenv.MustHaveGoBuild(t)
   506  
   507  	// This is a cross-compilation test, so it doesn't make
   508  	// sense to run it on every GOOS/GOARCH combination. Limit
   509  	// the test to amd64 + darwin/linux.
   510  	if runtime.GOARCH != "amd64" ||
   511  		(runtime.GOOS != "darwin" && runtime.GOOS != "linux") {
   512  		t.Skip("skipping on non-{linux,darwin}/amd64 platform")
   513  	}
   514  
   515  	t.Parallel()
   516  
   517  	tmpdir := t.TempDir()
   518  
   519  	src := filepath.Join(tmpdir, "blah.go")
   520  	err := os.WriteFile(src, []byte(Issue34788src), 0666)
   521  	if err != nil {
   522  		t.Fatal(err)
   523  	}
   524  
   525  	obj := filepath.Join(tmpdir, "blah.o")
   526  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-p=blah", "-o", obj, src)
   527  	cmd.Env = append(os.Environ(), "GOARCH=386", "GOOS=android")
   528  	if out, err := cmd.CombinedOutput(); err != nil {
   529  		t.Fatalf("failed to compile blah.go: %v, output: %s\n", err, out)
   530  	}
   531  
   532  	// Run objdump on the resulting object.
   533  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "objdump", obj)
   534  	out, oerr := cmd.CombinedOutput()
   535  	if oerr != nil {
   536  		t.Fatalf("failed to objdump blah.o: %v, output: %s\n", oerr, out)
   537  	}
   538  
   539  	// Sift through the output; we should not be seeing any R_TLS_LE relocs.
   540  	scanner := bufio.NewScanner(bytes.NewReader(out))
   541  	for scanner.Scan() {
   542  		line := scanner.Text()
   543  		if strings.Contains(line, "R_TLS_LE") {
   544  			t.Errorf("objdump output contains unexpected R_TLS_LE reloc: %s", line)
   545  		}
   546  	}
   547  }
   548  
   549  const testStrictDupGoSrc = `
   550  package main
   551  func f()
   552  func main() { f() }
   553  `
   554  
   555  const testStrictDupAsmSrc1 = `
   556  #include "textflag.h"
   557  TEXT	·f(SB), NOSPLIT|DUPOK, $0-0
   558  	RET
   559  `
   560  
   561  const testStrictDupAsmSrc2 = `
   562  #include "textflag.h"
   563  TEXT	·f(SB), NOSPLIT|DUPOK, $0-0
   564  	JMP	0(PC)
   565  `
   566  
   567  const testStrictDupAsmSrc3 = `
   568  #include "textflag.h"
   569  GLOBL ·rcon(SB), RODATA|DUPOK, $64
   570  `
   571  
   572  const testStrictDupAsmSrc4 = `
   573  #include "textflag.h"
   574  GLOBL ·rcon(SB), RODATA|DUPOK, $32
   575  `
   576  
   577  func TestStrictDup(t *testing.T) {
   578  	// Check that -strictdups flag works.
   579  	testenv.MustHaveGoBuild(t)
   580  
   581  	asmfiles := []struct {
   582  		fname   string
   583  		payload string
   584  	}{
   585  		{"a", testStrictDupAsmSrc1},
   586  		{"b", testStrictDupAsmSrc2},
   587  		{"c", testStrictDupAsmSrc3},
   588  		{"d", testStrictDupAsmSrc4},
   589  	}
   590  
   591  	t.Parallel()
   592  
   593  	tmpdir := t.TempDir()
   594  
   595  	src := filepath.Join(tmpdir, "x.go")
   596  	err := os.WriteFile(src, []byte(testStrictDupGoSrc), 0666)
   597  	if err != nil {
   598  		t.Fatal(err)
   599  	}
   600  	for _, af := range asmfiles {
   601  		src = filepath.Join(tmpdir, af.fname+".s")
   602  		err = os.WriteFile(src, []byte(af.payload), 0666)
   603  		if err != nil {
   604  			t.Fatal(err)
   605  		}
   606  	}
   607  	src = filepath.Join(tmpdir, "go.mod")
   608  	err = os.WriteFile(src, []byte("module teststrictdup\n"), 0666)
   609  	if err != nil {
   610  		t.Fatal(err)
   611  	}
   612  
   613  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-strictdups=1")
   614  	cmd.Dir = tmpdir
   615  	out, err := cmd.CombinedOutput()
   616  	if err != nil {
   617  		t.Errorf("linking with -strictdups=1 failed: %v\n%s", err, string(out))
   618  	}
   619  	if !bytes.Contains(out, []byte("mismatched payload")) {
   620  		t.Errorf("unexpected output:\n%s", out)
   621  	}
   622  
   623  	cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-strictdups=2")
   624  	cmd.Dir = tmpdir
   625  	out, err = cmd.CombinedOutput()
   626  	if err == nil {
   627  		t.Errorf("linking with -strictdups=2 did not fail")
   628  	}
   629  	// NB: on amd64 we get the 'new length' error, on arm64 the 'different
   630  	// contents' error.
   631  	if !(bytes.Contains(out, []byte("mismatched payload: new length")) ||
   632  		bytes.Contains(out, []byte("mismatched payload: same length but different contents"))) ||
   633  		!bytes.Contains(out, []byte("mismatched payload: different sizes")) {
   634  		t.Errorf("unexpected output:\n%s", out)
   635  	}
   636  }
   637  
   638  const testFuncAlignSrc = `
   639  package main
   640  import (
   641  	"fmt"
   642  )
   643  func alignPc()
   644  var alignPcFnAddr uintptr
   645  
   646  func main() {
   647  	if alignPcFnAddr % 512 != 0 {
   648  		fmt.Printf("expected 512 bytes alignment, got %v\n", alignPcFnAddr)
   649  	} else {
   650  		fmt.Printf("PASS")
   651  	}
   652  }
   653  `
   654  
   655  var testFuncAlignAsmSources = map[string]string{
   656  	"arm64": `
   657  #include "textflag.h"
   658  
   659  TEXT	·alignPc(SB),NOSPLIT, $0-0
   660  	MOVD	$2, R0
   661  	PCALIGN	$512
   662  	MOVD	$3, R1
   663  	RET
   664  
   665  GLOBL	·alignPcFnAddr(SB),RODATA,$8
   666  DATA	·alignPcFnAddr(SB)/8,$·alignPc(SB)
   667  `,
   668  	"loong64": `
   669  #include "textflag.h"
   670  
   671  TEXT	·alignPc(SB),NOSPLIT, $0-0
   672  	MOVV	$2, R4
   673  	PCALIGN	$512
   674  	MOVV	$3, R5
   675  	RET
   676  
   677  GLOBL	·alignPcFnAddr(SB),RODATA,$8
   678  DATA	·alignPcFnAddr(SB)/8,$·alignPc(SB)
   679  `,
   680  }
   681  
   682  // TestFuncAlign verifies that the address of a function can be aligned
   683  // with a specific value on arm64 and loong64.
   684  func TestFuncAlign(t *testing.T) {
   685  	testFuncAlignAsmSrc := testFuncAlignAsmSources[runtime.GOARCH]
   686  	if len(testFuncAlignAsmSrc) == 0 || runtime.GOOS != "linux" {
   687  		t.Skip("skipping on non-linux/{arm64,loong64} platform")
   688  	}
   689  	testenv.MustHaveGoBuild(t)
   690  
   691  	t.Parallel()
   692  
   693  	tmpdir := t.TempDir()
   694  
   695  	src := filepath.Join(tmpdir, "go.mod")
   696  	err := os.WriteFile(src, []byte("module cmd/link/TestFuncAlign/falign"), 0666)
   697  	if err != nil {
   698  		t.Fatal(err)
   699  	}
   700  	src = filepath.Join(tmpdir, "falign.go")
   701  	err = os.WriteFile(src, []byte(testFuncAlignSrc), 0666)
   702  	if err != nil {
   703  		t.Fatal(err)
   704  	}
   705  	src = filepath.Join(tmpdir, "falign.s")
   706  	err = os.WriteFile(src, []byte(testFuncAlignAsmSrc), 0666)
   707  	if err != nil {
   708  		t.Fatal(err)
   709  	}
   710  
   711  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "falign")
   712  	cmd.Dir = tmpdir
   713  	out, err := cmd.CombinedOutput()
   714  	if err != nil {
   715  		t.Errorf("build failed: %v", err)
   716  	}
   717  	cmd = testenv.Command(t, tmpdir+"/falign")
   718  	out, err = cmd.CombinedOutput()
   719  	if err != nil {
   720  		t.Errorf("failed to run with err %v, output: %s", err, out)
   721  	}
   722  	if string(out) != "PASS" {
   723  		t.Errorf("unexpected output: %s\n", out)
   724  	}
   725  }
   726  
   727  const testFuncAlignOptionSrc = `
   728  package main
   729  //go:noinline
   730  func foo() {
   731  }
   732  //go:noinline
   733  func bar() {
   734  }
   735  //go:noinline
   736  func baz() {
   737  }
   738  func main() {
   739  	foo()
   740  	bar()
   741  	baz()
   742  }
   743  `
   744  
   745  // TestFuncAlignOption verifies that the -funcalign option changes the function alignment
   746  func TestFuncAlignOption(t *testing.T) {
   747  	testenv.MustHaveGoBuild(t)
   748  
   749  	t.Parallel()
   750  
   751  	tmpdir := t.TempDir()
   752  
   753  	src := filepath.Join(tmpdir, "falign.go")
   754  	err := os.WriteFile(src, []byte(testFuncAlignOptionSrc), 0666)
   755  	if err != nil {
   756  		t.Fatal(err)
   757  	}
   758  
   759  	alignTest := func(align uint64) {
   760  		exeName := "falign.exe"
   761  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-funcalign="+strconv.FormatUint(align, 10), "-o", exeName, "falign.go")
   762  		cmd.Dir = tmpdir
   763  		out, err := cmd.CombinedOutput()
   764  		if err != nil {
   765  			t.Errorf("build failed: %v \n%s", err, out)
   766  		}
   767  		exe := filepath.Join(tmpdir, exeName)
   768  		cmd = testenv.Command(t, exe)
   769  		out, err = cmd.CombinedOutput()
   770  		if err != nil {
   771  			t.Errorf("failed to run with err %v, output: %s", err, out)
   772  		}
   773  
   774  		// Check function alignment
   775  		f, err := objfile.Open(exe)
   776  		if err != nil {
   777  			t.Fatalf("failed to open file:%v\n", err)
   778  		}
   779  		defer f.Close()
   780  
   781  		fname := map[string]bool{"_main.foo": false,
   782  			"_main.bar": false,
   783  			"_main.baz": false}
   784  		syms, err := f.Symbols()
   785  		for _, s := range syms {
   786  			fn := s.Name
   787  			if _, ok := fname[fn]; !ok {
   788  				fn = "_" + s.Name
   789  				if _, ok := fname[fn]; !ok {
   790  					continue
   791  				}
   792  			}
   793  			if s.Addr%align != 0 {
   794  				t.Fatalf("unaligned function: %s %x. Expected alignment: %d\n", fn, s.Addr, align)
   795  			}
   796  			fname[fn] = true
   797  		}
   798  		for k, v := range fname {
   799  			if !v {
   800  				t.Fatalf("function %s not found\n", k)
   801  			}
   802  		}
   803  	}
   804  	alignTest(16)
   805  	alignTest(32)
   806  }
   807  
   808  const testTrampSrc = `
   809  package main
   810  import "fmt"
   811  func main() {
   812  	fmt.Println("hello")
   813  
   814  	defer func(){
   815  		if e := recover(); e == nil {
   816  			panic("did not panic")
   817  		}
   818  	}()
   819  	f1()
   820  }
   821  
   822  // Test deferreturn trampolines. See issue #39049.
   823  func f1() { defer f2() }
   824  func f2() { panic("XXX") }
   825  `
   826  
   827  func TestTrampoline(t *testing.T) {
   828  	// Test that trampoline insertion works as expected.
   829  	// For stress test, we set -debugtramp=2 flag, which sets a very low
   830  	// threshold for trampoline generation, and essentially all cross-package
   831  	// calls will use trampolines.
   832  	buildmodes := []string{"default"}
   833  	switch runtime.GOARCH {
   834  	case "arm", "arm64", "ppc64", "loong64":
   835  	case "ppc64le":
   836  		// Trampolines are generated differently when internal linking PIE, test them too.
   837  		buildmodes = append(buildmodes, "pie")
   838  	default:
   839  		t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
   840  	}
   841  
   842  	testenv.MustHaveGoBuild(t)
   843  
   844  	t.Parallel()
   845  
   846  	tmpdir := t.TempDir()
   847  
   848  	src := filepath.Join(tmpdir, "hello.go")
   849  	err := os.WriteFile(src, []byte(testTrampSrc), 0666)
   850  	if err != nil {
   851  		t.Fatal(err)
   852  	}
   853  	exe := filepath.Join(tmpdir, "hello.exe")
   854  
   855  	for _, mode := range buildmodes {
   856  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2", "-o", exe, src)
   857  		out, err := cmd.CombinedOutput()
   858  		if err != nil {
   859  			t.Fatalf("build (%s) failed: %v\n%s", mode, err, out)
   860  		}
   861  		cmd = testenv.Command(t, exe)
   862  		out, err = cmd.CombinedOutput()
   863  		if err != nil {
   864  			t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
   865  		}
   866  		if string(out) != "hello\n" {
   867  			t.Errorf("unexpected output (%s):\n%s", mode, out)
   868  		}
   869  
   870  		out, err = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", exe).CombinedOutput()
   871  		if err != nil {
   872  			t.Errorf("nm failure: %s\n%s\n", err, string(out))
   873  		}
   874  		if ok, _ := regexp.Match("T runtime.deferreturn(\\+0)?-tramp0", out); !ok {
   875  			t.Errorf("Trampoline T runtime.deferreturn(+0)?-tramp0 is missing")
   876  		}
   877  	}
   878  }
   879  
   880  const testTrampCgoSrc = `
   881  package main
   882  
   883  // #include <stdio.h>
   884  // void CHello() { printf("hello\n"); fflush(stdout); }
   885  import "C"
   886  
   887  func main() {
   888  	C.CHello()
   889  }
   890  `
   891  
   892  func TestTrampolineCgo(t *testing.T) {
   893  	// Test that trampoline insertion works for cgo code.
   894  	// For stress test, we set -debugtramp=2 flag, which sets a very low
   895  	// threshold for trampoline generation, and essentially all cross-package
   896  	// calls will use trampolines.
   897  	buildmodes := []string{"default"}
   898  	switch runtime.GOARCH {
   899  	case "arm", "arm64", "ppc64", "loong64":
   900  	case "ppc64le":
   901  		// Trampolines are generated differently when internal linking PIE, test them too.
   902  		buildmodes = append(buildmodes, "pie")
   903  	default:
   904  		t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
   905  	}
   906  
   907  	testenv.MustHaveGoBuild(t)
   908  	testenv.MustHaveCGO(t)
   909  
   910  	t.Parallel()
   911  
   912  	tmpdir := t.TempDir()
   913  
   914  	src := filepath.Join(tmpdir, "hello.go")
   915  	err := os.WriteFile(src, []byte(testTrampCgoSrc), 0666)
   916  	if err != nil {
   917  		t.Fatal(err)
   918  	}
   919  	exe := filepath.Join(tmpdir, "hello.exe")
   920  
   921  	for _, mode := range buildmodes {
   922  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2", "-o", exe, src)
   923  		out, err := cmd.CombinedOutput()
   924  		if err != nil {
   925  			t.Fatalf("build (%s) failed: %v\n%s", mode, err, out)
   926  		}
   927  		cmd = testenv.Command(t, exe)
   928  		out, err = cmd.CombinedOutput()
   929  		if err != nil {
   930  			t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
   931  		}
   932  		if string(out) != "hello\n" && string(out) != "hello\r\n" {
   933  			t.Errorf("unexpected output (%s):\n%s", mode, out)
   934  		}
   935  
   936  		// Test internal linking mode.
   937  
   938  		if !testenv.CanInternalLink(true) {
   939  			continue
   940  		}
   941  		cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2 -linkmode=internal", "-o", exe, src)
   942  		out, err = cmd.CombinedOutput()
   943  		if err != nil {
   944  			t.Fatalf("build (%s) failed: %v\n%s", mode, err, out)
   945  		}
   946  		cmd = testenv.Command(t, exe)
   947  		out, err = cmd.CombinedOutput()
   948  		if err != nil {
   949  			t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
   950  		}
   951  		if string(out) != "hello\n" && string(out) != "hello\r\n" {
   952  			t.Errorf("unexpected output (%s):\n%s", mode, out)
   953  		}
   954  	}
   955  }
   956  
   957  func TestIndexMismatch(t *testing.T) {
   958  	// Test that index mismatch will cause a link-time error (not run-time error).
   959  	// This shouldn't happen with "go build". We invoke the compiler and the linker
   960  	// manually, and try to "trick" the linker with an inconsistent object file.
   961  	testenv.MustHaveGoBuild(t)
   962  	// N.B. the build below explictly doesn't pass through
   963  	// -asan/-msan/-race, so we don't care about those.
   964  	testenv.MustInternalLink(t, testenv.NoSpecialBuildTypes)
   965  
   966  	t.Parallel()
   967  
   968  	tmpdir := t.TempDir()
   969  
   970  	aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go")
   971  	bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go")
   972  	mSrc := filepath.Join("testdata", "testIndexMismatch", "main.go")
   973  	aObj := filepath.Join(tmpdir, "a.o")
   974  	mObj := filepath.Join(tmpdir, "main.o")
   975  	exe := filepath.Join(tmpdir, "main.exe")
   976  
   977  	importcfgFile := filepath.Join(tmpdir, "runtime.importcfg")
   978  	testenv.WriteImportcfg(t, importcfgFile, nil, "runtime")
   979  	importcfgWithAFile := filepath.Join(tmpdir, "witha.importcfg")
   980  	testenv.WriteImportcfg(t, importcfgWithAFile, map[string]string{"a": aObj}, "runtime")
   981  
   982  	// Build a program with main package importing package a.
   983  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, aSrc)
   984  	t.Log(cmd)
   985  	out, err := cmd.CombinedOutput()
   986  	if err != nil {
   987  		t.Fatalf("compiling a.go failed: %v\n%s", err, out)
   988  	}
   989  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgWithAFile, "-p=main", "-I", tmpdir, "-o", mObj, mSrc)
   990  	t.Log(cmd)
   991  	out, err = cmd.CombinedOutput()
   992  	if err != nil {
   993  		t.Fatalf("compiling main.go failed: %v\n%s", err, out)
   994  	}
   995  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
   996  	t.Log(cmd)
   997  	out, err = cmd.CombinedOutput()
   998  	if err != nil {
   999  		if runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
  1000  			testenv.SkipFlaky(t, 58806)
  1001  		}
  1002  		t.Errorf("linking failed: %v\n%s", err, out)
  1003  	}
  1004  
  1005  	// Now, overwrite a.o with the object of b.go. This should
  1006  	// result in an index mismatch.
  1007  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, bSrc)
  1008  	t.Log(cmd)
  1009  	out, err = cmd.CombinedOutput()
  1010  	if err != nil {
  1011  		t.Fatalf("compiling a.go failed: %v\n%s", err, out)
  1012  	}
  1013  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
  1014  	t.Log(cmd)
  1015  	out, err = cmd.CombinedOutput()
  1016  	if err == nil {
  1017  		t.Fatalf("linking didn't fail")
  1018  	}
  1019  	if !bytes.Contains(out, []byte("fingerprint mismatch")) {
  1020  		t.Errorf("did not see expected error message. out:\n%s", out)
  1021  	}
  1022  }
  1023  
  1024  func TestPErsrcBinutils(t *testing.T) {
  1025  	// Test that PE rsrc section is handled correctly (issue 39658).
  1026  	testenv.MustHaveGoBuild(t)
  1027  
  1028  	if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" {
  1029  		// This test is limited to amd64 and 386, because binutils is limited as such
  1030  		t.Skipf("this is only for windows/amd64 and windows/386")
  1031  	}
  1032  
  1033  	t.Parallel()
  1034  
  1035  	tmpdir := t.TempDir()
  1036  
  1037  	pkgdir := filepath.Join("testdata", "pe-binutils")
  1038  	exe := filepath.Join(tmpdir, "a.exe")
  1039  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe)
  1040  	cmd.Dir = pkgdir
  1041  	// cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
  1042  	out, err := cmd.CombinedOutput()
  1043  	if err != nil {
  1044  		t.Fatalf("building failed: %v, output:\n%s", err, out)
  1045  	}
  1046  
  1047  	// Check that the binary contains the rsrc data
  1048  	b, err := os.ReadFile(exe)
  1049  	if err != nil {
  1050  		t.Fatalf("reading output failed: %v", err)
  1051  	}
  1052  	if !bytes.Contains(b, []byte("Hello Gophers!")) {
  1053  		t.Fatalf("binary does not contain expected content")
  1054  	}
  1055  }
  1056  
  1057  func TestPErsrcLLVM(t *testing.T) {
  1058  	// Test that PE rsrc section is handled correctly (issue 39658).
  1059  	testenv.MustHaveGoBuild(t)
  1060  
  1061  	if runtime.GOOS != "windows" {
  1062  		t.Skipf("this is a windows-only test")
  1063  	}
  1064  
  1065  	t.Parallel()
  1066  
  1067  	tmpdir := t.TempDir()
  1068  
  1069  	pkgdir := filepath.Join("testdata", "pe-llvm")
  1070  	exe := filepath.Join(tmpdir, "a.exe")
  1071  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe)
  1072  	cmd.Dir = pkgdir
  1073  	// cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
  1074  	out, err := cmd.CombinedOutput()
  1075  	if err != nil {
  1076  		t.Fatalf("building failed: %v, output:\n%s", err, out)
  1077  	}
  1078  
  1079  	// Check that the binary contains the rsrc data
  1080  	b, err := os.ReadFile(exe)
  1081  	if err != nil {
  1082  		t.Fatalf("reading output failed: %v", err)
  1083  	}
  1084  	if !bytes.Contains(b, []byte("resname RCDATA a.rc")) {
  1085  		t.Fatalf("binary does not contain expected content")
  1086  	}
  1087  }
  1088  
  1089  func TestContentAddressableSymbols(t *testing.T) {
  1090  	// Test that the linker handles content-addressable symbols correctly.
  1091  	testenv.MustHaveGoBuild(t)
  1092  
  1093  	t.Parallel()
  1094  
  1095  	src := filepath.Join("testdata", "testHashedSyms", "p.go")
  1096  	cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
  1097  	out, err := cmd.CombinedOutput()
  1098  	if err != nil {
  1099  		t.Errorf("command %s failed: %v\n%s", cmd, err, out)
  1100  	}
  1101  }
  1102  
  1103  func TestReadOnly(t *testing.T) {
  1104  	// Test that read-only data is indeed read-only.
  1105  	testenv.MustHaveGoBuild(t)
  1106  
  1107  	t.Parallel()
  1108  
  1109  	src := filepath.Join("testdata", "testRO", "x.go")
  1110  	cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
  1111  	out, err := cmd.CombinedOutput()
  1112  	if err == nil {
  1113  		t.Errorf("running test program did not fail. output:\n%s", out)
  1114  	}
  1115  }
  1116  
  1117  const testIssue38554Src = `
  1118  package main
  1119  
  1120  type T [10<<20]byte
  1121  
  1122  //go:noinline
  1123  func f() T {
  1124  	return T{} // compiler will make a large stmp symbol, but not used.
  1125  }
  1126  
  1127  func main() {
  1128  	x := f()
  1129  	println(x[1])
  1130  }
  1131  `
  1132  
  1133  func TestIssue38554(t *testing.T) {
  1134  	testenv.MustHaveGoBuild(t)
  1135  
  1136  	t.Parallel()
  1137  
  1138  	tmpdir := t.TempDir()
  1139  
  1140  	src := filepath.Join(tmpdir, "x.go")
  1141  	err := os.WriteFile(src, []byte(testIssue38554Src), 0666)
  1142  	if err != nil {
  1143  		t.Fatalf("failed to write source file: %v", err)
  1144  	}
  1145  	exe := filepath.Join(tmpdir, "x.exe")
  1146  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src)
  1147  	out, err := cmd.CombinedOutput()
  1148  	if err != nil {
  1149  		t.Fatalf("build failed: %v\n%s", err, out)
  1150  	}
  1151  
  1152  	fi, err := os.Stat(exe)
  1153  	if err != nil {
  1154  		t.Fatalf("failed to stat output file: %v", err)
  1155  	}
  1156  
  1157  	// The test program is not much different from a helloworld, which is
  1158  	// typically a little over 1 MB. We allow 5 MB. If the bad stmp is live,
  1159  	// it will be over 10 MB.
  1160  	const want = 5 << 20
  1161  	if got := fi.Size(); got > want {
  1162  		t.Errorf("binary too big: got %d, want < %d", got, want)
  1163  	}
  1164  }
  1165  
  1166  const testIssue42396src = `
  1167  package main
  1168  
  1169  //go:noinline
  1170  //go:nosplit
  1171  func callee(x int) {
  1172  }
  1173  
  1174  func main() {
  1175  	callee(9)
  1176  }
  1177  `
  1178  
  1179  func TestIssue42396(t *testing.T) {
  1180  	testenv.MustHaveGoBuild(t)
  1181  
  1182  	if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
  1183  		t.Skip("no race detector support")
  1184  	}
  1185  
  1186  	t.Parallel()
  1187  
  1188  	tmpdir := t.TempDir()
  1189  
  1190  	src := filepath.Join(tmpdir, "main.go")
  1191  	err := os.WriteFile(src, []byte(testIssue42396src), 0666)
  1192  	if err != nil {
  1193  		t.Fatalf("failed to write source file: %v", err)
  1194  	}
  1195  	exe := filepath.Join(tmpdir, "main.exe")
  1196  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-gcflags=-race", "-o", exe, src)
  1197  	out, err := cmd.CombinedOutput()
  1198  	if err == nil {
  1199  		t.Fatalf("build unexpectedly succeeded")
  1200  	}
  1201  
  1202  	// Check to make sure that we see a reasonable error message
  1203  	// and not a panic.
  1204  	if strings.Contains(string(out), "panic:") {
  1205  		t.Fatalf("build should not fail with panic:\n%s", out)
  1206  	}
  1207  	const want = "reference to undefined builtin"
  1208  	if !strings.Contains(string(out), want) {
  1209  		t.Fatalf("error message incorrect: expected it to contain %q but instead got:\n%s\n", want, out)
  1210  	}
  1211  }
  1212  
  1213  const testLargeRelocSrc = `
  1214  package main
  1215  
  1216  var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
  1217  
  1218  var addr = [...]*byte{
  1219  	&x[1<<23-1],
  1220  	&x[1<<23],
  1221  	&x[1<<23+1],
  1222  	&x[1<<24-1],
  1223  	&x[1<<24],
  1224  	&x[1<<24+1],
  1225  }
  1226  
  1227  func main() {
  1228  	// check relocations in instructions
  1229  	check(x[1<<23-1], 0)
  1230  	check(x[1<<23], 23)
  1231  	check(x[1<<23+1], 0)
  1232  	check(x[1<<24-1], 0)
  1233  	check(x[1<<24], 24)
  1234  	check(x[1<<24+1], 0)
  1235  
  1236  	// check absolute address relocations in data
  1237  	check(*addr[0], 0)
  1238  	check(*addr[1], 23)
  1239  	check(*addr[2], 0)
  1240  	check(*addr[3], 0)
  1241  	check(*addr[4], 24)
  1242  	check(*addr[5], 0)
  1243  }
  1244  
  1245  func check(x, y byte) {
  1246  	if x != y {
  1247  		panic("FAIL")
  1248  	}
  1249  }
  1250  `
  1251  
  1252  func TestLargeReloc(t *testing.T) {
  1253  	// Test that large relocation addend is handled correctly.
  1254  	// In particular, on darwin/arm64 when external linking,
  1255  	// Mach-O relocation has only 24-bit addend. See issue #42738.
  1256  	testenv.MustHaveGoBuild(t)
  1257  	t.Parallel()
  1258  
  1259  	tmpdir := t.TempDir()
  1260  
  1261  	src := filepath.Join(tmpdir, "x.go")
  1262  	err := os.WriteFile(src, []byte(testLargeRelocSrc), 0666)
  1263  	if err != nil {
  1264  		t.Fatalf("failed to write source file: %v", err)
  1265  	}
  1266  	cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
  1267  	out, err := cmd.CombinedOutput()
  1268  	if err != nil {
  1269  		t.Errorf("build failed: %v. output:\n%s", err, out)
  1270  	}
  1271  
  1272  	if testenv.HasCGO() { // currently all targets that support cgo can external link
  1273  		cmd = testenv.Command(t, testenv.GoToolPath(t), "run", "-ldflags=-linkmode=external", src)
  1274  		out, err = cmd.CombinedOutput()
  1275  		if err != nil {
  1276  			t.Fatalf("build failed: %v. output:\n%s", err, out)
  1277  		}
  1278  	}
  1279  }
  1280  
  1281  func TestUnlinkableObj(t *testing.T) {
  1282  	// Test that the linker emits an error with unlinkable object.
  1283  	testenv.MustHaveGoBuild(t)
  1284  	t.Parallel()
  1285  
  1286  	if true /* was buildcfg.Experiment.Unified */ {
  1287  		t.Skip("TODO(mdempsky): Fix ICE when importing unlinkable objects for GOEXPERIMENT=unified")
  1288  	}
  1289  
  1290  	tmpdir := t.TempDir()
  1291  
  1292  	xSrc := filepath.Join(tmpdir, "x.go")
  1293  	pSrc := filepath.Join(tmpdir, "p.go")
  1294  	xObj := filepath.Join(tmpdir, "x.o")
  1295  	pObj := filepath.Join(tmpdir, "p.o")
  1296  	exe := filepath.Join(tmpdir, "x.exe")
  1297  	importcfgfile := filepath.Join(tmpdir, "importcfg")
  1298  	testenv.WriteImportcfg(t, importcfgfile, map[string]string{"p": pObj})
  1299  	err := os.WriteFile(xSrc, []byte("package main\nimport _ \"p\"\nfunc main() {}\n"), 0666)
  1300  	if err != nil {
  1301  		t.Fatalf("failed to write source file: %v", err)
  1302  	}
  1303  	err = os.WriteFile(pSrc, []byte("package p\n"), 0666)
  1304  	if err != nil {
  1305  		t.Fatalf("failed to write source file: %v", err)
  1306  	}
  1307  	cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-o", pObj, pSrc) // without -p
  1308  	out, err := cmd.CombinedOutput()
  1309  	if err != nil {
  1310  		t.Fatalf("compile p.go failed: %v. output:\n%s", err, out)
  1311  	}
  1312  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "-o", xObj, xSrc)
  1313  	out, err = cmd.CombinedOutput()
  1314  	if err != nil {
  1315  		t.Fatalf("compile x.go failed: %v. output:\n%s", err, out)
  1316  	}
  1317  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-o", exe, xObj)
  1318  	out, err = cmd.CombinedOutput()
  1319  	if err == nil {
  1320  		t.Fatalf("link did not fail")
  1321  	}
  1322  	if !bytes.Contains(out, []byte("unlinkable object")) {
  1323  		t.Errorf("did not see expected error message. out:\n%s", out)
  1324  	}
  1325  
  1326  	// It is okay to omit -p for (only) main package.
  1327  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", pObj, pSrc)
  1328  	out, err = cmd.CombinedOutput()
  1329  	if err != nil {
  1330  		t.Fatalf("compile p.go failed: %v. output:\n%s", err, out)
  1331  	}
  1332  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-o", xObj, xSrc) // without -p
  1333  	out, err = cmd.CombinedOutput()
  1334  	if err != nil {
  1335  		t.Fatalf("compile failed: %v. output:\n%s", err, out)
  1336  	}
  1337  
  1338  	cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-o", exe, xObj)
  1339  	out, err = cmd.CombinedOutput()
  1340  	if err != nil {
  1341  		t.Errorf("link failed: %v. output:\n%s", err, out)
  1342  	}
  1343  }
  1344  
  1345  func TestExtLinkCmdlineDeterminism(t *testing.T) {
  1346  	// Test that we pass flags in deterministic order to the external linker
  1347  	testenv.MustHaveGoBuild(t)
  1348  	testenv.MustHaveCGO(t) // this test requires -linkmode=external
  1349  	t.Parallel()
  1350  
  1351  	// test source code, with some cgo exports
  1352  	testSrc := `
  1353  package main
  1354  import "C"
  1355  //export F1
  1356  func F1() {}
  1357  //export F2
  1358  func F2() {}
  1359  //export F3
  1360  func F3() {}
  1361  func main() {}
  1362  `
  1363  
  1364  	tmpdir := t.TempDir()
  1365  	src := filepath.Join(tmpdir, "x.go")
  1366  	if err := os.WriteFile(src, []byte(testSrc), 0666); err != nil {
  1367  		t.Fatal(err)
  1368  	}
  1369  	exe := filepath.Join(tmpdir, "x.exe")
  1370  
  1371  	// Use a deterministic tmp directory so the temporary file paths are
  1372  	// deterministic.
  1373  	linktmp := filepath.Join(tmpdir, "linktmp")
  1374  	if err := os.Mkdir(linktmp, 0777); err != nil {
  1375  		t.Fatal(err)
  1376  	}
  1377  
  1378  	// Link with -v -linkmode=external to see the flags we pass to the
  1379  	// external linker.
  1380  	ldflags := "-ldflags=-v -linkmode=external -tmpdir=" + linktmp
  1381  	var out0 []byte
  1382  	for i := 0; i < 5; i++ {
  1383  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", ldflags, "-o", exe, src)
  1384  		out, err := cmd.CombinedOutput()
  1385  		if err != nil {
  1386  			t.Fatalf("build failed: %v, output:\n%s", err, out)
  1387  		}
  1388  		if err := os.Remove(exe); err != nil {
  1389  			t.Fatal(err)
  1390  		}
  1391  
  1392  		// extract the "host link" invocation
  1393  		j := bytes.Index(out, []byte("\nhost link:"))
  1394  		if j == -1 {
  1395  			t.Fatalf("host link step not found, output:\n%s", out)
  1396  		}
  1397  		out = out[j+1:]
  1398  		k := bytes.Index(out, []byte("\n"))
  1399  		if k == -1 {
  1400  			t.Fatalf("no newline after host link, output:\n%s", out)
  1401  		}
  1402  		out = out[:k]
  1403  
  1404  		// filter out output file name, which is passed by the go
  1405  		// command and is nondeterministic.
  1406  		fs := bytes.Fields(out)
  1407  		for i, f := range fs {
  1408  			if bytes.Equal(f, []byte(`"-o"`)) && i+1 < len(fs) {
  1409  				fs[i+1] = []byte("a.out")
  1410  				break
  1411  			}
  1412  		}
  1413  		out = bytes.Join(fs, []byte{' '})
  1414  
  1415  		if i == 0 {
  1416  			out0 = out
  1417  			continue
  1418  		}
  1419  		if !bytes.Equal(out0, out) {
  1420  			t.Fatalf("output differ:\n%s\n==========\n%s", out0, out)
  1421  		}
  1422  	}
  1423  }
  1424  
  1425  // TestResponseFile tests that creating a response file to pass to the
  1426  // external linker works correctly.
  1427  func TestResponseFile(t *testing.T) {
  1428  	t.Parallel()
  1429  
  1430  	testenv.MustHaveGoBuild(t)
  1431  
  1432  	// This test requires -linkmode=external. Currently all
  1433  	// systems that support cgo support -linkmode=external.
  1434  	testenv.MustHaveCGO(t)
  1435  
  1436  	tmpdir := t.TempDir()
  1437  
  1438  	src := filepath.Join(tmpdir, "x.go")
  1439  	if err := os.WriteFile(src, []byte(`package main; import "C"; func main() {}`), 0666); err != nil {
  1440  		t.Fatal(err)
  1441  	}
  1442  
  1443  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "output", "x.go")
  1444  	cmd.Dir = tmpdir
  1445  
  1446  	// Add enough arguments to push cmd/link into creating a response file.
  1447  	var sb strings.Builder
  1448  	sb.WriteString(`'-ldflags=all="-extldflags=`)
  1449  	for i := 0; i < sys.ExecArgLengthLimit/len("-g"); i++ {
  1450  		if i > 0 {
  1451  			sb.WriteString(" ")
  1452  		}
  1453  		sb.WriteString("-g")
  1454  	}
  1455  	sb.WriteString(`"'`)
  1456  	cmd = testenv.CleanCmdEnv(cmd)
  1457  	cmd.Env = append(cmd.Env, "GOFLAGS="+sb.String())
  1458  
  1459  	out, err := cmd.CombinedOutput()
  1460  	if len(out) > 0 {
  1461  		t.Logf("%s", out)
  1462  	}
  1463  	if err != nil {
  1464  		t.Error(err)
  1465  	}
  1466  }
  1467  
  1468  func TestDynimportVar(t *testing.T) {
  1469  	// Test that we can access dynamically imported variables.
  1470  	// Currently darwin only.
  1471  	if runtime.GOOS != "darwin" {
  1472  		t.Skip("skip on non-darwin platform")
  1473  	}
  1474  
  1475  	testenv.MustHaveGoBuild(t)
  1476  	testenv.MustHaveCGO(t)
  1477  
  1478  	t.Parallel()
  1479  
  1480  	tmpdir := t.TempDir()
  1481  	exe := filepath.Join(tmpdir, "a.exe")
  1482  	src := filepath.Join("testdata", "dynimportvar", "main.go")
  1483  
  1484  	for _, mode := range []string{"internal", "external"} {
  1485  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode="+mode, "-o", exe, src)
  1486  		out, err := cmd.CombinedOutput()
  1487  		if err != nil {
  1488  			t.Fatalf("build (linkmode=%s) failed: %v\n%s", mode, err, out)
  1489  		}
  1490  		cmd = testenv.Command(t, exe)
  1491  		out, err = cmd.CombinedOutput()
  1492  		if err != nil {
  1493  			t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
  1494  		}
  1495  	}
  1496  }
  1497  
  1498  const helloSrc = `
  1499  package main
  1500  var X = 42
  1501  var Y int
  1502  func main() { println("hello", X, Y) }
  1503  `
  1504  
  1505  func TestFlagS(t *testing.T) {
  1506  	// Test that the -s flag strips the symbol table.
  1507  	testenv.MustHaveGoBuild(t)
  1508  
  1509  	t.Parallel()
  1510  
  1511  	tmpdir := t.TempDir()
  1512  	exe := filepath.Join(tmpdir, "a.exe")
  1513  	src := filepath.Join(tmpdir, "a.go")
  1514  	err := os.WriteFile(src, []byte(helloSrc), 0666)
  1515  	if err != nil {
  1516  		t.Fatal(err)
  1517  	}
  1518  
  1519  	modes := []string{"auto"}
  1520  	if testenv.HasCGO() {
  1521  		modes = append(modes, "external")
  1522  	}
  1523  
  1524  	// check a text symbol, a data symbol, and a BSS symbol
  1525  	syms := []string{"main.main", "main.X", "main.Y"}
  1526  
  1527  	for _, mode := range modes {
  1528  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-s -linkmode="+mode, "-o", exe, src)
  1529  		out, err := cmd.CombinedOutput()
  1530  		if err != nil {
  1531  			t.Fatalf("build (linkmode=%s) failed: %v\n%s", mode, err, out)
  1532  		}
  1533  		cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", exe)
  1534  		out, err = cmd.CombinedOutput()
  1535  		if err != nil && !errors.As(err, new(*exec.ExitError)) {
  1536  			// Error exit is fine as it may have no symbols.
  1537  			// On darwin we need to emit dynamic symbol references so it
  1538  			// actually has some symbols, and nm succeeds.
  1539  			t.Errorf("(mode=%s) go tool nm failed: %v\n%s", mode, err, out)
  1540  		}
  1541  		for _, s := range syms {
  1542  			if bytes.Contains(out, []byte(s)) {
  1543  				t.Errorf("(mode=%s): unexpected symbol %s", mode, s)
  1544  			}
  1545  		}
  1546  	}
  1547  }
  1548  
  1549  func TestRandLayout(t *testing.T) {
  1550  	// Test that the -randlayout flag randomizes function order and
  1551  	// generates a working binary.
  1552  	testenv.MustHaveGoBuild(t)
  1553  
  1554  	t.Parallel()
  1555  
  1556  	tmpdir := t.TempDir()
  1557  
  1558  	src := filepath.Join(tmpdir, "hello.go")
  1559  	err := os.WriteFile(src, []byte(trivialSrc), 0666)
  1560  	if err != nil {
  1561  		t.Fatal(err)
  1562  	}
  1563  
  1564  	var syms [2]string
  1565  	for i, seed := range []string{"123", "456"} {
  1566  		exe := filepath.Join(tmpdir, "hello"+seed+".exe")
  1567  		cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-randlayout="+seed, "-o", exe, src)
  1568  		out, err := cmd.CombinedOutput()
  1569  		if err != nil {
  1570  			t.Fatalf("seed=%v: build failed: %v\n%s", seed, err, out)
  1571  		}
  1572  		cmd = testenv.Command(t, exe)
  1573  		err = cmd.Run()
  1574  		if err != nil {
  1575  			t.Fatalf("seed=%v: executable failed to run: %v\n%s", seed, err, out)
  1576  		}
  1577  		cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", exe)
  1578  		out, err = cmd.CombinedOutput()
  1579  		if err != nil {
  1580  			t.Fatalf("seed=%v: fail to run \"go tool nm\": %v\n%s", seed, err, out)
  1581  		}
  1582  		syms[i] = string(out)
  1583  	}
  1584  	if syms[0] == syms[1] {
  1585  		t.Errorf("randlayout with different seeds produced same layout:\n%s\n===\n\n%s", syms[0], syms[1])
  1586  	}
  1587  }
  1588  
  1589  func TestCheckLinkname(t *testing.T) {
  1590  	// Test that code containing blocked linknames does not build.
  1591  	testenv.MustHaveGoBuild(t)
  1592  	t.Parallel()
  1593  
  1594  	tmpdir := t.TempDir()
  1595  
  1596  	tests := []struct {
  1597  		src string
  1598  		ok  bool
  1599  	}{
  1600  		// use (instantiation) of public API is ok
  1601  		{"ok.go", true},
  1602  		// push linkname is ok
  1603  		{"push.go", true},
  1604  		// using a linknamed variable to reference an assembly
  1605  		// function in the same package is ok
  1606  		{"textvar", true},
  1607  		// pull linkname of blocked symbol is not ok
  1608  		{"coro.go", false},
  1609  		{"coro_var.go", false},
  1610  		// assembly reference is not ok
  1611  		{"coro_asm", false},
  1612  		// pull-only linkname is not ok
  1613  		{"coro2.go", false},
  1614  		// pull linkname of a builtin symbol is not ok
  1615  		{"builtin.go", false},
  1616  		// legacy bad linkname is ok, for now
  1617  		{"fastrand.go", true},
  1618  		{"badlinkname.go", true},
  1619  	}
  1620  	for _, test := range tests {
  1621  		test := test
  1622  		t.Run(test.src, func(t *testing.T) {
  1623  			t.Parallel()
  1624  			src := "./testdata/linkname/" + test.src
  1625  			exe := filepath.Join(tmpdir, test.src+".exe")
  1626  			cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src)
  1627  			out, err := cmd.CombinedOutput()
  1628  			if test.ok && err != nil {
  1629  				t.Errorf("build failed unexpectedly: %v:\n%s", err, out)
  1630  			}
  1631  			if !test.ok && err == nil {
  1632  				t.Errorf("build succeeded unexpectedly: %v:\n%s", err, out)
  1633  			}
  1634  		})
  1635  	}
  1636  }
  1637  
  1638  func TestLinknameBSS(t *testing.T) {
  1639  	// Test that the linker chooses the right one as the definition
  1640  	// for linknamed variables. See issue #72032.
  1641  	testenv.MustHaveGoBuild(t)
  1642  	t.Parallel()
  1643  
  1644  	tmpdir := t.TempDir()
  1645  
  1646  	src := filepath.Join("testdata", "linkname", "sched.go")
  1647  	exe := filepath.Join(tmpdir, "sched.exe")
  1648  	cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src)
  1649  	out, err := cmd.CombinedOutput()
  1650  	if err != nil {
  1651  		t.Fatalf("build failed unexpectedly: %v:\n%s", err, out)
  1652  	}
  1653  
  1654  	// Check the symbol size.
  1655  	f, err := objfile.Open(exe)
  1656  	if err != nil {
  1657  		t.Fatalf("fail to open executable: %v", err)
  1658  	}
  1659  	defer f.Close()
  1660  	syms, err := f.Symbols()
  1661  	if err != nil {
  1662  		t.Fatalf("fail to get symbols: %v", err)
  1663  	}
  1664  	found := false
  1665  	for _, s := range syms {
  1666  		if s.Name == "runtime.sched" || s.Name == "_runtime.sched" {
  1667  			found = true
  1668  			if s.Size < 100 {
  1669  				// As of Go 1.25 (Mar 2025), runtime.sched has 6848 bytes on
  1670  				// darwin/arm64. It should always be larger than 100 bytes on
  1671  				// all platforms.
  1672  				t.Errorf("runtime.sched symbol size too small: want > 100, got %d", s.Size)
  1673  			}
  1674  		}
  1675  	}
  1676  	if !found {
  1677  		t.Errorf("runtime.sched symbol not found")
  1678  	}
  1679  
  1680  	// Executable should run.
  1681  	cmd = testenv.Command(t, exe)
  1682  	out, err = cmd.CombinedOutput()
  1683  	if err != nil {
  1684  		t.Errorf("executable failed to run: %v\n%s", err, out)
  1685  	}
  1686  }
  1687  

View as plain text