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