]> Cypherpunks repositories - gostls13.git/blob
7eeb7ef
[gostls13.git] /
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         "cmd/internal/sys"
11         "debug/macho"
12         "internal/testenv"
13         "io/ioutil"
14         "os"
15         "os/exec"
16         "path/filepath"
17         "regexp"
18         "runtime"
19         "strings"
20         "testing"
21 )
22
23 var AuthorPaidByTheColumnInch struct {
24         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."`
25
26         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."`
27
28         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."`
29
30         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."`
31 }
32
33 func TestLargeSymName(t *testing.T) {
34         // The compiler generates a symbol name using the string form of the
35         // type. This tests that the linker can read symbol names larger than
36         // the bufio buffer. Issue #15104.
37         _ = AuthorPaidByTheColumnInch
38 }
39
40 func TestIssue21703(t *testing.T) {
41         t.Parallel()
42
43         testenv.MustHaveGoBuild(t)
44
45         const source = `
46 package main
47 const X = "\n!\n"
48 func main() {}
49 `
50
51         tmpdir, err := ioutil.TempDir("", "issue21703")
52         if err != nil {
53                 t.Fatalf("failed to create temp dir: %v\n", err)
54         }
55         defer os.RemoveAll(tmpdir)
56
57         err = ioutil.WriteFile(filepath.Join(tmpdir, "main.go"), []byte(source), 0666)
58         if err != nil {
59                 t.Fatalf("failed to write main.go: %v\n", err)
60         }
61
62         cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "main.go")
63         cmd.Dir = tmpdir
64         out, err := cmd.CombinedOutput()
65         if err != nil {
66                 t.Fatalf("failed to compile main.go: %v, output: %s\n", err, out)
67         }
68
69         cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "main.o")
70         cmd.Dir = tmpdir
71         out, err = cmd.CombinedOutput()
72         if err != nil {
73                 t.Fatalf("failed to link main.o: %v, output: %s\n", err, out)
74         }
75 }
76
77 // TestIssue28429 ensures that the linker does not attempt to link
78 // sections not named *.o. Such sections may be used by a build system
79 // to, for example, save facts produced by a modular static analysis
80 // such as golang.org/x/tools/go/analysis.
81 func TestIssue28429(t *testing.T) {
82         t.Parallel()
83
84         testenv.MustHaveGoBuild(t)
85
86         tmpdir, err := ioutil.TempDir("", "issue28429-")
87         if err != nil {
88                 t.Fatalf("failed to create temp dir: %v", err)
89         }
90         defer os.RemoveAll(tmpdir)
91
92         write := func(name, content string) {
93                 err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
94                 if err != nil {
95                         t.Fatal(err)
96                 }
97         }
98
99         runGo := func(args ...string) {
100                 cmd := exec.Command(testenv.GoToolPath(t), args...)
101                 cmd.Dir = tmpdir
102                 out, err := cmd.CombinedOutput()
103                 if err != nil {
104                         t.Fatalf("'go %s' failed: %v, output: %s",
105                                 strings.Join(args, " "), err, out)
106                 }
107         }
108
109         // Compile a main package.
110         write("main.go", "package main; func main() {}")
111         runGo("tool", "compile", "-p", "main", "main.go")
112         runGo("tool", "pack", "c", "main.a", "main.o")
113
114         // Add an extra section with a short, non-.o name.
115         // This simulates an alternative build system.
116         write(".facts", "this is not an object file")
117         runGo("tool", "pack", "r", "main.a", ".facts")
118
119         // Verify that the linker does not attempt
120         // to compile the extra section.
121         runGo("tool", "link", "main.a")
122 }
123
124 func TestUnresolved(t *testing.T) {
125         testenv.MustHaveGoBuild(t)
126
127         t.Parallel()
128
129         tmpdir, err := ioutil.TempDir("", "unresolved-")
130         if err != nil {
131                 t.Fatalf("failed to create temp dir: %v", err)
132         }
133         defer os.RemoveAll(tmpdir)
134
135         write := func(name, content string) {
136                 err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
137                 if err != nil {
138                         t.Fatal(err)
139                 }
140         }
141
142         // Test various undefined references. Because of issue #29852,
143         // this used to give confusing error messages because the
144         // linker would find an undefined reference to "zero" created
145         // by the runtime package.
146
147         write("go.mod", "module testunresolved\n")
148         write("main.go", `package main
149
150 func main() {
151         x()
152 }
153
154 func x()
155 `)
156         write("main.s", `
157 TEXT ·x(SB),0,$0
158         MOVD zero<>(SB), AX
159         MOVD zero(SB), AX
160         MOVD ·zero(SB), AX
161         RET
162 `)
163         cmd := exec.Command(testenv.GoToolPath(t), "build")
164         cmd.Dir = tmpdir
165         cmd.Env = append(os.Environ(),
166                 "GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath"))
167         out, err := cmd.CombinedOutput()
168         if err == nil {
169                 t.Fatalf("expected build to fail, but it succeeded")
170         }
171         out = regexp.MustCompile("(?m)^#.*\n").ReplaceAll(out, nil)
172         got := string(out)
173         want := `main.x: relocation target zero not defined
174 main.x: relocation target zero not defined
175 main.x: relocation target main.zero not defined
176 `
177         if want != got {
178                 t.Fatalf("want:\n%sgot:\n%s", want, got)
179         }
180 }
181
182 func TestIssue33979(t *testing.T) {
183         testenv.MustHaveGoBuild(t)
184         testenv.MustHaveCGO(t)
185         testenv.MustInternalLink(t)
186
187         // Skip test on platforms that do not support cgo internal linking.
188         switch runtime.GOARCH {
189         case "mips", "mipsle", "mips64", "mips64le":
190                 t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
191         }
192         if runtime.GOOS == "aix" {
193                 t.Skipf("Skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
194         }
195
196         t.Parallel()
197
198         tmpdir, err := ioutil.TempDir("", "unresolved-")
199         if err != nil {
200                 t.Fatalf("failed to create temp dir: %v", err)
201         }
202         defer os.RemoveAll(tmpdir)
203
204         write := func(name, content string) {
205                 err := ioutil.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 := exec.Command(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         // Compile, assemble and pack the Go and C code.
253         runGo("tool", "asm", "-gensymabis", "-o", "symabis", "x.s")
254         runGo("tool", "compile", "-symabis", "symabis", "-p", "main", "-o", "x1.o", "main.go")
255         runGo("tool", "asm", "-o", "x2.o", "x.s")
256         run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...)
257         runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o")
258
259         // Now attempt to link using the internal linker.
260         cmd := exec.Command(testenv.GoToolPath(t), "tool", "link", "-linkmode=internal", "x.a")
261         cmd.Dir = tmpdir
262         out, err := cmd.CombinedOutput()
263         if err == nil {
264                 t.Fatalf("expected link to fail, but it succeeded")
265         }
266         re := regexp.MustCompile(`(?m)^main\(.*text\): relocation target undefined not defined$`)
267         if !re.Match(out) {
268                 t.Fatalf("got:\n%q\nwant:\n%s", out, re)
269         }
270 }
271
272 func TestBuildForTvOS(t *testing.T) {
273         testenv.MustHaveCGO(t)
274         testenv.MustHaveGoBuild(t)
275
276         // Only run this on darwin/amd64, where we can cross build for tvOS.
277         if runtime.GOARCH != "amd64" || runtime.GOOS != "darwin" {
278                 t.Skip("skipping on non-darwin/amd64 platform")
279         }
280         if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
281                 t.Skip("skipping in -short mode with $GO_BUILDER_NAME empty")
282         }
283         if err := exec.Command("xcrun", "--help").Run(); err != nil {
284                 t.Skipf("error running xcrun, required for iOS cross build: %v", err)
285         }
286
287         t.Parallel()
288
289         sdkPath, err := exec.Command("xcrun", "--sdk", "appletvos", "--show-sdk-path").Output()
290         if err != nil {
291                 t.Skip("failed to locate appletvos SDK, skipping")
292         }
293         CC := []string{
294                 "clang",
295                 "-arch",
296                 "arm64",
297                 "-isysroot", strings.TrimSpace(string(sdkPath)),
298                 "-mtvos-version-min=12.0",
299                 "-fembed-bitcode",
300                 "-framework", "CoreFoundation",
301         }
302         lib := filepath.Join("testdata", "testBuildFortvOS", "lib.go")
303         tmpDir, err := ioutil.TempDir("", "go-link-TestBuildFortvOS")
304         if err != nil {
305                 t.Fatal(err)
306         }
307         defer os.RemoveAll(tmpDir)
308
309         ar := filepath.Join(tmpDir, "lib.a")
310         cmd := exec.Command(testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", ar, lib)
311         cmd.Env = append(os.Environ(),
312                 "CGO_ENABLED=1",
313                 "GOOS=ios",
314                 "GOARCH=arm64",
315                 "CC="+strings.Join(CC, " "),
316                 "CGO_CFLAGS=", // ensure CGO_CFLAGS does not contain any flags. Issue #35459
317         )
318         if out, err := cmd.CombinedOutput(); err != nil {
319                 t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
320         }
321
322         link := exec.Command(CC[0], CC[1:]...)
323         link.Args = append(link.Args, ar, filepath.Join("testdata", "testBuildFortvOS", "main.m"))
324         if out, err := link.CombinedOutput(); err != nil {
325                 t.Fatalf("%v: %v:\n%s", link.Args, err, out)
326         }
327 }
328
329 var testXFlagSrc = `
330 package main
331 var X = "hello"
332 var Z = [99999]int{99998:12345} // make it large enough to be mmaped
333 func main() { println(X) }
334 `
335
336 func TestXFlag(t *testing.T) {
337         testenv.MustHaveGoBuild(t)
338
339         t.Parallel()
340
341         tmpdir, err := ioutil.TempDir("", "TestXFlag")
342         if err != nil {
343                 t.Fatal(err)
344         }
345         defer os.RemoveAll(tmpdir)
346
347         src := filepath.Join(tmpdir, "main.go")
348         err = ioutil.WriteFile(src, []byte(testXFlagSrc), 0666)
349         if err != nil {
350                 t.Fatal(err)
351         }
352
353         cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-X=main.X=meow", "-o", filepath.Join(tmpdir, "main"), src)
354         if out, err := cmd.CombinedOutput(); err != nil {
355                 t.Errorf("%v: %v:\n%s", cmd.Args, err, out)
356         }
357 }
358
359 var testMacOSVersionSrc = `
360 package main
361 func main() { }
362 `
363
364 func TestMacOSVersion(t *testing.T) {
365         testenv.MustHaveGoBuild(t)
366
367         t.Parallel()
368
369         tmpdir, err := ioutil.TempDir("", "TestMacOSVersion")
370         if err != nil {
371                 t.Fatal(err)
372         }
373         defer os.RemoveAll(tmpdir)
374
375         src := filepath.Join(tmpdir, "main.go")
376         err = ioutil.WriteFile(src, []byte(testMacOSVersionSrc), 0666)
377         if err != nil {
378                 t.Fatal(err)
379         }
380
381         exe := filepath.Join(tmpdir, "main")
382         cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal", "-o", exe, src)
383         cmd.Env = append(os.Environ(),
384                 "CGO_ENABLED=0",
385                 "GOOS=darwin",
386                 "GOARCH=amd64",
387         )
388         if out, err := cmd.CombinedOutput(); err != nil {
389                 t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
390         }
391         exef, err := os.Open(exe)
392         if err != nil {
393                 t.Fatal(err)
394         }
395         exem, err := macho.NewFile(exef)
396         if err != nil {
397                 t.Fatal(err)
398         }
399         found := false
400         const LC_VERSION_MIN_MACOSX = 0x24
401         checkMin := func(ver uint32) {
402                 major, minor := (ver>>16)&0xff, (ver>>8)&0xff
403                 if major != 10 || minor < 9 {
404                         t.Errorf("LC_VERSION_MIN_MACOSX version %d.%d < 10.9", major, minor)
405                 }
406         }
407         for _, cmd := range exem.Loads {
408                 raw := cmd.Raw()
409                 type_ := exem.ByteOrder.Uint32(raw)
410                 if type_ != LC_VERSION_MIN_MACOSX {
411                         continue
412                 }
413                 osVer := exem.ByteOrder.Uint32(raw[8:])
414                 checkMin(osVer)
415                 sdkVer := exem.ByteOrder.Uint32(raw[12:])
416                 checkMin(sdkVer)
417                 found = true
418                 break
419         }
420         if !found {
421                 t.Errorf("no LC_VERSION_MIN_MACOSX load command found")
422         }
423 }
424
425 const Issue34788src = `
426
427 package blah
428
429 func Blah(i int) int {
430         a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
431         return a[i&7]
432 }
433 `
434
435 func TestIssue34788Android386TLSSequence(t *testing.T) {
436         testenv.MustHaveGoBuild(t)
437
438         // This is a cross-compilation test, so it doesn't make
439         // sense to run it on every GOOS/GOARCH combination. Limit
440         // the test to amd64 + darwin/linux.
441         if runtime.GOARCH != "amd64" ||
442                 (runtime.GOOS != "darwin" && runtime.GOOS != "linux") {
443                 t.Skip("skipping on non-{linux,darwin}/amd64 platform")
444         }
445
446         t.Parallel()
447
448         tmpdir, err := ioutil.TempDir("", "TestIssue34788Android386TLSSequence")
449         if err != nil {
450                 t.Fatal(err)
451         }
452         defer os.RemoveAll(tmpdir)
453
454         src := filepath.Join(tmpdir, "blah.go")
455         err = ioutil.WriteFile(src, []byte(Issue34788src), 0666)
456         if err != nil {
457                 t.Fatal(err)
458         }
459
460         obj := filepath.Join(tmpdir, "blah.o")
461         cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src)
462         cmd.Env = append(os.Environ(), "GOARCH=386", "GOOS=android")
463         if out, err := cmd.CombinedOutput(); err != nil {
464                 t.Fatalf("failed to compile blah.go: %v, output: %s\n", err, out)
465         }
466
467         // Run objdump on the resulting object.
468         cmd = exec.Command(testenv.GoToolPath(t), "tool", "objdump", obj)
469         out, oerr := cmd.CombinedOutput()
470         if oerr != nil {
471                 t.Fatalf("failed to objdump blah.o: %v, output: %s\n", oerr, out)
472         }
473
474         // Sift through the output; we should not be seeing any R_TLS_LE relocs.
475         scanner := bufio.NewScanner(bytes.NewReader(out))
476         for scanner.Scan() {
477                 line := scanner.Text()
478                 if strings.Contains(line, "R_TLS_LE") {
479                         t.Errorf("objdump output contains unexpected R_TLS_LE reloc: %s", line)
480                 }
481         }
482 }
483
484 const testStrictDupGoSrc = `
485 package main
486 func f()
487 func main() { f() }
488 `
489
490 const testStrictDupAsmSrc1 = `
491 #include "textflag.h"
492 TEXT    ·f(SB), NOSPLIT|DUPOK, $0-0
493         RET
494 `
495
496 const testStrictDupAsmSrc2 = `
497 #include "textflag.h"
498 TEXT    ·f(SB), NOSPLIT|DUPOK, $0-0
499         JMP     0(PC)
500 `
501
502 func TestStrictDup(t *testing.T) {
503         // Check that -strictdups flag works.
504         testenv.MustHaveGoBuild(t)
505
506         t.Parallel()
507
508         tmpdir, err := ioutil.TempDir("", "TestStrictDup")
509         if err != nil {
510                 t.Fatal(err)
511         }
512         defer os.RemoveAll(tmpdir)
513
514         src := filepath.Join(tmpdir, "x.go")
515         err = ioutil.WriteFile(src, []byte(testStrictDupGoSrc), 0666)
516         if err != nil {
517                 t.Fatal(err)
518         }
519         src = filepath.Join(tmpdir, "a.s")
520         err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc1), 0666)
521         if err != nil {
522                 t.Fatal(err)
523         }
524         src = filepath.Join(tmpdir, "b.s")
525         err = ioutil.WriteFile(src, []byte(testStrictDupAsmSrc2), 0666)
526         if err != nil {
527                 t.Fatal(err)
528         }
529         src = filepath.Join(tmpdir, "go.mod")
530         err = ioutil.WriteFile(src, []byte("module teststrictdup\n"), 0666)
531         if err != nil {
532                 t.Fatal(err)
533         }
534
535         cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=1")
536         cmd.Dir = tmpdir
537         out, err := cmd.CombinedOutput()
538         if err != nil {
539                 t.Errorf("linking with -strictdups=1 failed: %v", err)
540         }
541         if !bytes.Contains(out, []byte("mismatched payload")) {
542                 t.Errorf("unexpected output:\n%s", out)
543         }
544
545         cmd = exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-strictdups=2")
546         cmd.Dir = tmpdir
547         out, err = cmd.CombinedOutput()
548         if err == nil {
549                 t.Errorf("linking with -strictdups=2 did not fail")
550         }
551         if !bytes.Contains(out, []byte("mismatched payload")) {
552                 t.Errorf("unexpected output:\n%s", out)
553         }
554 }
555
556 const testFuncAlignSrc = `
557 package main
558 import (
559         "fmt"
560         "reflect"
561 )
562 func alignPc()
563
564 func main() {
565         addr := reflect.ValueOf(alignPc).Pointer()
566         if (addr % 512) != 0 {
567                 fmt.Printf("expected 512 bytes alignment, got %v\n", addr)
568         } else {
569                 fmt.Printf("PASS")
570         }
571 }
572 `
573
574 const testFuncAlignAsmSrc = `
575 #include "textflag.h"
576
577 TEXT    ·alignPc(SB),NOSPLIT, $0-0
578         MOVD    $2, R0
579         PCALIGN $512
580         MOVD    $3, R1
581         RET
582 `
583
584 // TestFuncAlign verifies that the address of a function can be aligned
585 // with a specfic value on arm64.
586 func TestFuncAlign(t *testing.T) {
587         if runtime.GOARCH != "arm64" || runtime.GOOS != "linux" {
588                 t.Skip("skipping on non-linux/arm64 platform")
589         }
590         testenv.MustHaveGoBuild(t)
591
592         t.Parallel()
593
594         tmpdir, err := ioutil.TempDir("", "TestFuncAlign")
595         if err != nil {
596                 t.Fatal(err)
597         }
598         defer os.RemoveAll(tmpdir)
599
600         src := filepath.Join(tmpdir, "go.mod")
601         err = ioutil.WriteFile(src, []byte("module cmd/link/TestFuncAlign/falign"), 0666)
602         if err != nil {
603                 t.Fatal(err)
604         }
605         src = filepath.Join(tmpdir, "falign.go")
606         err = ioutil.WriteFile(src, []byte(testFuncAlignSrc), 0666)
607         if err != nil {
608                 t.Fatal(err)
609         }
610         src = filepath.Join(tmpdir, "falign.s")
611         err = ioutil.WriteFile(src, []byte(testFuncAlignAsmSrc), 0666)
612         if err != nil {
613                 t.Fatal(err)
614         }
615
616         // Build and run with old object file format.
617         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "falign")
618         cmd.Dir = tmpdir
619         out, err := cmd.CombinedOutput()
620         if err != nil {
621                 t.Errorf("build failed: %v", err)
622         }
623         cmd = exec.Command(tmpdir + "/falign")
624         out, err = cmd.CombinedOutput()
625         if err != nil {
626                 t.Errorf("failed to run with err %v, output: %s", err, out)
627         }
628         if string(out) != "PASS" {
629                 t.Errorf("unexpected output: %s\n", out)
630         }
631 }
632
633 const testTrampSrc = `
634 package main
635 import "fmt"
636 func main() {
637         fmt.Println("hello")
638
639         defer func(){
640                 if e := recover(); e == nil {
641                         panic("did not panic")
642                 }
643         }()
644         f1()
645 }
646
647 // Test deferreturn trampolines. See issue #39049.
648 func f1() { defer f2() }
649 func f2() { panic("XXX") }
650 `
651
652 func TestTrampoline(t *testing.T) {
653         // Test that trampoline insertion works as expected.
654         // For stress test, we set -debugtramp=2 flag, which sets a very low
655         // threshold for trampoline generation, and essentially all cross-package
656         // calls will use trampolines.
657         switch runtime.GOARCH {
658         case "arm", "ppc64", "ppc64le":
659         default:
660                 t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
661         }
662
663         testenv.MustHaveGoBuild(t)
664
665         t.Parallel()
666
667         tmpdir, err := ioutil.TempDir("", "TestTrampoline")
668         if err != nil {
669                 t.Fatal(err)
670         }
671         defer os.RemoveAll(tmpdir)
672
673         src := filepath.Join(tmpdir, "hello.go")
674         err = ioutil.WriteFile(src, []byte(testTrampSrc), 0666)
675         if err != nil {
676                 t.Fatal(err)
677         }
678         exe := filepath.Join(tmpdir, "hello.exe")
679
680         cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-debugtramp=2", "-o", exe, src)
681         out, err := cmd.CombinedOutput()
682         if err != nil {
683                 t.Fatalf("build failed: %v\n%s", err, out)
684         }
685         cmd = exec.Command(exe)
686         out, err = cmd.CombinedOutput()
687         if err != nil {
688                 t.Errorf("executable failed to run: %v\n%s", err, out)
689         }
690         if string(out) != "hello\n" {
691                 t.Errorf("unexpected output:\n%s", out)
692         }
693 }
694
695 func TestIndexMismatch(t *testing.T) {
696         // Test that index mismatch will cause a link-time error (not run-time error).
697         // This shouldn't happen with "go build". We invoke the compiler and the linker
698         // manually, and try to "trick" the linker with an inconsistent object file.
699         testenv.MustHaveGoBuild(t)
700
701         t.Parallel()
702
703         tmpdir, err := ioutil.TempDir("", "TestIndexMismatch")
704         if err != nil {
705                 t.Fatal(err)
706         }
707         defer os.RemoveAll(tmpdir)
708
709         aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go")
710         bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go")
711         mSrc := filepath.Join("testdata", "testIndexMismatch", "main.go")
712         aObj := filepath.Join(tmpdir, "a.o")
713         mObj := filepath.Join(tmpdir, "main.o")
714         exe := filepath.Join(tmpdir, "main.exe")
715
716         // Build a program with main package importing package a.
717         cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, aSrc)
718         t.Log(cmd)
719         out, err := cmd.CombinedOutput()
720         if err != nil {
721                 t.Fatalf("compiling a.go failed: %v\n%s", err, out)
722         }
723         cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-o", mObj, mSrc)
724         t.Log(cmd)
725         out, err = cmd.CombinedOutput()
726         if err != nil {
727                 t.Fatalf("compiling main.go failed: %v\n%s", err, out)
728         }
729         cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
730         t.Log(cmd)
731         out, err = cmd.CombinedOutput()
732         if err != nil {
733                 t.Errorf("linking failed: %v\n%s", err, out)
734         }
735
736         // Now, overwrite a.o with the object of b.go. This should
737         // result in an index mismatch.
738         cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, bSrc)
739         t.Log(cmd)
740         out, err = cmd.CombinedOutput()
741         if err != nil {
742                 t.Fatalf("compiling a.go failed: %v\n%s", err, out)
743         }
744         cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
745         t.Log(cmd)
746         out, err = cmd.CombinedOutput()
747         if err == nil {
748                 t.Fatalf("linking didn't fail")
749         }
750         if !bytes.Contains(out, []byte("fingerprint mismatch")) {
751                 t.Errorf("did not see expected error message. out:\n%s", out)
752         }
753 }
754
755 func TestPErsrc(t *testing.T) {
756         // Test that PE rsrc section is handled correctly (issue 39658).
757         testenv.MustHaveGoBuild(t)
758
759         if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" {
760                 t.Skipf("this is a windows/amd64-only test")
761         }
762
763         t.Parallel()
764
765         tmpdir, err := ioutil.TempDir("", "TestPErsrc")
766         if err != nil {
767                 t.Fatal(err)
768         }
769         defer os.RemoveAll(tmpdir)
770
771         pkgdir := filepath.Join("testdata", "testPErsrc")
772         exe := filepath.Join(tmpdir, "a.exe")
773         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
774         cmd.Dir = pkgdir
775         // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
776         out, err := cmd.CombinedOutput()
777         if err != nil {
778                 t.Fatalf("building failed: %v, output:\n%s", err, out)
779         }
780
781         // Check that the binary contains the rsrc data
782         b, err := ioutil.ReadFile(exe)
783         if err != nil {
784                 t.Fatalf("reading output failed: %v", err)
785         }
786         if !bytes.Contains(b, []byte("Hello Gophers!")) {
787                 t.Fatalf("binary does not contain expected content")
788         }
789
790         pkgdir = filepath.Join("testdata", "testPErsrc-complex")
791         exe = filepath.Join(tmpdir, "a.exe")
792         cmd = exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
793         cmd.Dir = pkgdir
794         // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
795         out, err = cmd.CombinedOutput()
796         if err != nil {
797                 t.Fatalf("building failed: %v, output:\n%s", err, out)
798         }
799
800         // Check that the binary contains the rsrc data
801         b, err = ioutil.ReadFile(exe)
802         if err != nil {
803                 t.Fatalf("reading output failed: %v", err)
804         }
805         if !bytes.Contains(b, []byte("resname RCDATA a.rc")) {
806                 t.Fatalf("binary does not contain expected content")
807         }
808 }
809
810 func TestContentAddressableSymbols(t *testing.T) {
811         // Test that the linker handles content-addressable symbols correctly.
812         testenv.MustHaveGoBuild(t)
813
814         t.Parallel()
815
816         tmpdir, err := ioutil.TempDir("", "TestContentAddressableSymbols")
817         if err != nil {
818                 t.Fatal(err)
819         }
820         defer os.RemoveAll(tmpdir)
821
822         src := filepath.Join("testdata", "testHashedSyms", "p.go")
823         cmd := exec.Command(testenv.GoToolPath(t), "run", src)
824         out, err := cmd.CombinedOutput()
825         if err != nil {
826                 t.Errorf("command %s failed: %v\n%s", cmd, err, out)
827         }
828 }
829
830 func TestReadOnly(t *testing.T) {
831         // Test that read-only data is indeed read-only.
832         testenv.MustHaveGoBuild(t)
833
834         t.Parallel()
835
836         src := filepath.Join("testdata", "testRO", "x.go")
837         cmd := exec.Command(testenv.GoToolPath(t), "run", src)
838         out, err := cmd.CombinedOutput()
839         if err == nil {
840                 t.Errorf("running test program did not fail. output:\n%s", out)
841         }
842 }
843
844 const testIssue38554Src = `
845 package main
846
847 type T [10<<20]byte
848
849 //go:noinline
850 func f() T {
851         return T{} // compiler will make a large stmp symbol, but not used.
852 }
853
854 func main() {
855         x := f()
856         println(x[1])
857 }
858 `
859
860 func TestIssue38554(t *testing.T) {
861         testenv.MustHaveGoBuild(t)
862
863         t.Parallel()
864
865         tmpdir, err := ioutil.TempDir("", "TestIssue38554")
866         if err != nil {
867                 t.Fatal(err)
868         }
869         defer os.RemoveAll(tmpdir)
870
871         src := filepath.Join(tmpdir, "x.go")
872         err = ioutil.WriteFile(src, []byte(testIssue38554Src), 0666)
873         if err != nil {
874                 t.Fatalf("failed to write source file: %v", err)
875         }
876         exe := filepath.Join(tmpdir, "x.exe")
877         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src)
878         out, err := cmd.CombinedOutput()
879         if err != nil {
880                 t.Fatalf("build failed: %v\n%s", err, out)
881         }
882
883         fi, err := os.Stat(exe)
884         if err != nil {
885                 t.Fatalf("failed to stat output file: %v", err)
886         }
887
888         // The test program is not much different from a helloworld, which is
889         // typically a little over 1 MB. We allow 5 MB. If the bad stmp is live,
890         // it will be over 10 MB.
891         const want = 5 << 20
892         if got := fi.Size(); got > want {
893                 t.Errorf("binary too big: got %d, want < %d", got, want)
894         }
895 }
896
897 const testIssue42396src = `
898 package main
899
900 //go:noinline
901 //go:nosplit
902 func callee(x int) {
903 }
904
905 func main() {
906         callee(9)
907 }
908 `
909
910 func TestIssue42396(t *testing.T) {
911         testenv.MustHaveGoBuild(t)
912
913         if !sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
914                 t.Skip("no race detector support")
915         }
916
917         t.Parallel()
918
919         tmpdir, err := ioutil.TempDir("", "TestIssue42396")
920         if err != nil {
921                 t.Fatal(err)
922         }
923         defer os.RemoveAll(tmpdir)
924
925         src := filepath.Join(tmpdir, "main.go")
926         err = ioutil.WriteFile(src, []byte(testIssue42396src), 0666)
927         if err != nil {
928                 t.Fatalf("failed to write source file: %v", err)
929         }
930         exe := filepath.Join(tmpdir, "main.exe")
931         cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-race", "-o", exe, src)
932         out, err := cmd.CombinedOutput()
933         if err == nil {
934                 t.Fatalf("build unexpectedly succeeded")
935         }
936
937         // Check to make sure that we see a reasonable error message
938         // and not a panic.
939         if strings.Contains(string(out), "panic:") {
940                 t.Fatalf("build should not fail with panic:\n%s", out)
941         }
942         const want = "reference to undefined builtin"
943         if !strings.Contains(string(out), want) {
944                 t.Fatalf("error message incorrect: expected it to contain %q but instead got:\n%s\n", want, out)
945         }
946 }
947
948 const testLargeRelocSrc = `
949 package main
950
951 var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
952
953 func main() {
954         check(x[1<<23-1], 0)
955         check(x[1<<23], 23)
956         check(x[1<<23+1], 0)
957         check(x[1<<24-1], 0)
958         check(x[1<<24], 24)
959         check(x[1<<24+1], 0)
960 }
961
962 func check(x, y byte) {
963         if x != y {
964                 panic("FAIL")
965         }
966 }
967 `
968
969 func TestLargeReloc(t *testing.T) {
970         // Test that large relocation addend is handled correctly.
971         // In particular, on darwin/arm64 when external linking,
972         // Mach-O relocation has only 24-bit addend. See issue #42738.
973         testenv.MustHaveGoBuild(t)
974         t.Parallel()
975
976         tmpdir, err := ioutil.TempDir("", "TestIssue42396")
977         if err != nil {
978                 t.Fatal(err)
979         }
980         defer os.RemoveAll(tmpdir)
981
982         src := filepath.Join(tmpdir, "x.go")
983         err = ioutil.WriteFile(src, []byte(testLargeRelocSrc), 0666)
984         if err != nil {
985                 t.Fatalf("failed to write source file: %v", err)
986         }
987         cmd := exec.Command(testenv.GoToolPath(t), "run", src)
988         out, err := cmd.CombinedOutput()
989         if err != nil {
990                 t.Errorf("build failed: %v. output:\n%s", err, out)
991         }
992
993         if testenv.HasCGO() { // currently all targets that support cgo can external link
994                 cmd = exec.Command(testenv.GoToolPath(t), "run", "-ldflags=-linkmode=external", src)
995                 out, err = cmd.CombinedOutput()
996                 if err != nil {
997                         t.Fatalf("build failed: %v. output:\n%s", err, out)
998                 }
999         }
1000 }