]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/link/link_test.go
[dev.typeparams] all: merge master (fdab5be) into dev.typeparams
[gostls13.git] / 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         "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 )
549 func alignPc()
550 var alignPcFnAddr uintptr
551
552 func main() {
553         if alignPcFnAddr % 512 != 0 {
554                 fmt.Printf("expected 512 bytes alignment, got %v\n", alignPcFnAddr)
555         } else {
556                 fmt.Printf("PASS")
557         }
558 }
559 `
560
561 const testFuncAlignAsmSrc = `
562 #include "textflag.h"
563
564 TEXT    ·alignPc(SB),NOSPLIT, $0-0
565         MOVD    $2, R0
566         PCALIGN $512
567         MOVD    $3, R1
568         RET
569
570 GLOBL   ·alignPcFnAddr(SB),RODATA,$8
571 DATA    ·alignPcFnAddr(SB)/8,$·alignPc(SB)
572 `
573
574 // TestFuncAlign verifies that the address of a function can be aligned
575 // with a specific value on arm64.
576 func TestFuncAlign(t *testing.T) {
577         if runtime.GOARCH != "arm64" || runtime.GOOS != "linux" {
578                 t.Skip("skipping on non-linux/arm64 platform")
579         }
580         testenv.MustHaveGoBuild(t)
581
582         t.Parallel()
583
584         tmpdir := t.TempDir()
585
586         src := filepath.Join(tmpdir, "go.mod")
587         err := ioutil.WriteFile(src, []byte("module cmd/link/TestFuncAlign/falign"), 0666)
588         if err != nil {
589                 t.Fatal(err)
590         }
591         src = filepath.Join(tmpdir, "falign.go")
592         err = ioutil.WriteFile(src, []byte(testFuncAlignSrc), 0666)
593         if err != nil {
594                 t.Fatal(err)
595         }
596         src = filepath.Join(tmpdir, "falign.s")
597         err = ioutil.WriteFile(src, []byte(testFuncAlignAsmSrc), 0666)
598         if err != nil {
599                 t.Fatal(err)
600         }
601
602         // Build and run with old object file format.
603         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "falign")
604         cmd.Dir = tmpdir
605         out, err := cmd.CombinedOutput()
606         if err != nil {
607                 t.Errorf("build failed: %v", err)
608         }
609         cmd = exec.Command(tmpdir + "/falign")
610         out, err = cmd.CombinedOutput()
611         if err != nil {
612                 t.Errorf("failed to run with err %v, output: %s", err, out)
613         }
614         if string(out) != "PASS" {
615                 t.Errorf("unexpected output: %s\n", out)
616         }
617 }
618
619 const testTrampSrc = `
620 package main
621 import "fmt"
622 func main() {
623         fmt.Println("hello")
624
625         defer func(){
626                 if e := recover(); e == nil {
627                         panic("did not panic")
628                 }
629         }()
630         f1()
631 }
632
633 // Test deferreturn trampolines. See issue #39049.
634 func f1() { defer f2() }
635 func f2() { panic("XXX") }
636 `
637
638 func TestTrampoline(t *testing.T) {
639         // Test that trampoline insertion works as expected.
640         // For stress test, we set -debugtramp=2 flag, which sets a very low
641         // threshold for trampoline generation, and essentially all cross-package
642         // calls will use trampolines.
643         switch runtime.GOARCH {
644         case "arm", "arm64", "ppc64", "ppc64le":
645         default:
646                 t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
647         }
648
649         testenv.MustHaveGoBuild(t)
650
651         t.Parallel()
652
653         tmpdir := t.TempDir()
654
655         src := filepath.Join(tmpdir, "hello.go")
656         err := ioutil.WriteFile(src, []byte(testTrampSrc), 0666)
657         if err != nil {
658                 t.Fatal(err)
659         }
660         exe := filepath.Join(tmpdir, "hello.exe")
661
662         cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-debugtramp=2", "-o", exe, src)
663         out, err := cmd.CombinedOutput()
664         if err != nil {
665                 t.Fatalf("build failed: %v\n%s", err, out)
666         }
667         cmd = exec.Command(exe)
668         out, err = cmd.CombinedOutput()
669         if err != nil {
670                 t.Errorf("executable failed to run: %v\n%s", err, out)
671         }
672         if string(out) != "hello\n" {
673                 t.Errorf("unexpected output:\n%s", out)
674         }
675 }
676
677 const testTrampCgoSrc = `
678 package main
679
680 // #include <stdio.h>
681 // void CHello() { printf("hello\n"); fflush(stdout); }
682 import "C"
683
684 func main() {
685         C.CHello()
686 }
687 `
688
689 func TestTrampolineCgo(t *testing.T) {
690         // Test that trampoline insertion works for cgo code.
691         // For stress test, we set -debugtramp=2 flag, which sets a very low
692         // threshold for trampoline generation, and essentially all cross-package
693         // calls will use trampolines.
694         switch runtime.GOARCH {
695         case "arm", "arm64", "ppc64", "ppc64le":
696         default:
697                 t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
698         }
699
700         testenv.MustHaveGoBuild(t)
701         testenv.MustHaveCGO(t)
702
703         t.Parallel()
704
705         tmpdir := t.TempDir()
706
707         src := filepath.Join(tmpdir, "hello.go")
708         err := ioutil.WriteFile(src, []byte(testTrampCgoSrc), 0666)
709         if err != nil {
710                 t.Fatal(err)
711         }
712         exe := filepath.Join(tmpdir, "hello.exe")
713
714         cmd := exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-debugtramp=2", "-o", exe, src)
715         out, err := cmd.CombinedOutput()
716         if err != nil {
717                 t.Fatalf("build failed: %v\n%s", err, out)
718         }
719         cmd = exec.Command(exe)
720         out, err = cmd.CombinedOutput()
721         if err != nil {
722                 t.Errorf("executable failed to run: %v\n%s", err, out)
723         }
724         if string(out) != "hello\n" && string(out) != "hello\r\n" {
725                 t.Errorf("unexpected output:\n%s", out)
726         }
727
728         // Test internal linking mode.
729
730         if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || (runtime.GOARCH == "arm64" && runtime.GOOS == "windows") || !testenv.CanInternalLink() {
731                 return // internal linking cgo is not supported
732         }
733         cmd = exec.Command(testenv.GoToolPath(t), "build", "-ldflags=-debugtramp=2 -linkmode=internal", "-o", exe, src)
734         out, err = cmd.CombinedOutput()
735         if err != nil {
736                 t.Fatalf("build failed: %v\n%s", err, out)
737         }
738         cmd = exec.Command(exe)
739         out, err = cmd.CombinedOutput()
740         if err != nil {
741                 t.Errorf("executable failed to run: %v\n%s", err, out)
742         }
743         if string(out) != "hello\n" && string(out) != "hello\r\n" {
744                 t.Errorf("unexpected output:\n%s", out)
745         }
746 }
747
748 func TestIndexMismatch(t *testing.T) {
749         // Test that index mismatch will cause a link-time error (not run-time error).
750         // This shouldn't happen with "go build". We invoke the compiler and the linker
751         // manually, and try to "trick" the linker with an inconsistent object file.
752         testenv.MustHaveGoBuild(t)
753
754         t.Parallel()
755
756         tmpdir := t.TempDir()
757
758         aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go")
759         bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go")
760         mSrc := filepath.Join("testdata", "testIndexMismatch", "main.go")
761         aObj := filepath.Join(tmpdir, "a.o")
762         mObj := filepath.Join(tmpdir, "main.o")
763         exe := filepath.Join(tmpdir, "main.exe")
764
765         // Build a program with main package importing package a.
766         cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, aSrc)
767         t.Log(cmd)
768         out, err := cmd.CombinedOutput()
769         if err != nil {
770                 t.Fatalf("compiling a.go failed: %v\n%s", err, out)
771         }
772         cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-o", mObj, mSrc)
773         t.Log(cmd)
774         out, err = cmd.CombinedOutput()
775         if err != nil {
776                 t.Fatalf("compiling main.go failed: %v\n%s", err, out)
777         }
778         cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
779         t.Log(cmd)
780         out, err = cmd.CombinedOutput()
781         if err != nil {
782                 t.Errorf("linking failed: %v\n%s", err, out)
783         }
784
785         // Now, overwrite a.o with the object of b.go. This should
786         // result in an index mismatch.
787         cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, bSrc)
788         t.Log(cmd)
789         out, err = cmd.CombinedOutput()
790         if err != nil {
791                 t.Fatalf("compiling a.go failed: %v\n%s", err, out)
792         }
793         cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
794         t.Log(cmd)
795         out, err = cmd.CombinedOutput()
796         if err == nil {
797                 t.Fatalf("linking didn't fail")
798         }
799         if !bytes.Contains(out, []byte("fingerprint mismatch")) {
800                 t.Errorf("did not see expected error message. out:\n%s", out)
801         }
802 }
803
804 func TestPErsrcBinutils(t *testing.T) {
805         // Test that PE rsrc section is handled correctly (issue 39658).
806         testenv.MustHaveGoBuild(t)
807
808         if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" {
809                 // This test is limited to amd64 and 386, because binutils is limited as such
810                 t.Skipf("this is only for windows/amd64 and windows/386")
811         }
812
813         t.Parallel()
814
815         tmpdir := t.TempDir()
816
817         pkgdir := filepath.Join("testdata", "pe-binutils")
818         exe := filepath.Join(tmpdir, "a.exe")
819         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
820         cmd.Dir = pkgdir
821         // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
822         out, err := cmd.CombinedOutput()
823         if err != nil {
824                 t.Fatalf("building failed: %v, output:\n%s", err, out)
825         }
826
827         // Check that the binary contains the rsrc data
828         b, err := ioutil.ReadFile(exe)
829         if err != nil {
830                 t.Fatalf("reading output failed: %v", err)
831         }
832         if !bytes.Contains(b, []byte("Hello Gophers!")) {
833                 t.Fatalf("binary does not contain expected content")
834         }
835 }
836
837 func TestPErsrcLLVM(t *testing.T) {
838         // Test that PE rsrc section is handled correctly (issue 39658).
839         testenv.MustHaveGoBuild(t)
840
841         if runtime.GOOS != "windows" {
842                 t.Skipf("this is a windows-only test")
843         }
844
845         t.Parallel()
846
847         tmpdir := t.TempDir()
848
849         pkgdir := filepath.Join("testdata", "pe-llvm")
850         exe := filepath.Join(tmpdir, "a.exe")
851         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
852         cmd.Dir = pkgdir
853         // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
854         out, err := cmd.CombinedOutput()
855         if err != nil {
856                 t.Fatalf("building failed: %v, output:\n%s", err, out)
857         }
858
859         // Check that the binary contains the rsrc data
860         b, err := ioutil.ReadFile(exe)
861         if err != nil {
862                 t.Fatalf("reading output failed: %v", err)
863         }
864         if !bytes.Contains(b, []byte("resname RCDATA a.rc")) {
865                 t.Fatalf("binary does not contain expected content")
866         }
867 }
868
869 func TestContentAddressableSymbols(t *testing.T) {
870         // Test that the linker handles content-addressable symbols correctly.
871         testenv.MustHaveGoBuild(t)
872
873         t.Parallel()
874
875         src := filepath.Join("testdata", "testHashedSyms", "p.go")
876         cmd := exec.Command(testenv.GoToolPath(t), "run", src)
877         out, err := cmd.CombinedOutput()
878         if err != nil {
879                 t.Errorf("command %s failed: %v\n%s", cmd, err, out)
880         }
881 }
882
883 func TestReadOnly(t *testing.T) {
884         // Test that read-only data is indeed read-only.
885         testenv.MustHaveGoBuild(t)
886
887         t.Parallel()
888
889         src := filepath.Join("testdata", "testRO", "x.go")
890         cmd := exec.Command(testenv.GoToolPath(t), "run", src)
891         out, err := cmd.CombinedOutput()
892         if err == nil {
893                 t.Errorf("running test program did not fail. output:\n%s", out)
894         }
895 }
896
897 const testIssue38554Src = `
898 package main
899
900 type T [10<<20]byte
901
902 //go:noinline
903 func f() T {
904         return T{} // compiler will make a large stmp symbol, but not used.
905 }
906
907 func main() {
908         x := f()
909         println(x[1])
910 }
911 `
912
913 func TestIssue38554(t *testing.T) {
914         testenv.MustHaveGoBuild(t)
915
916         t.Parallel()
917
918         tmpdir := t.TempDir()
919
920         src := filepath.Join(tmpdir, "x.go")
921         err := ioutil.WriteFile(src, []byte(testIssue38554Src), 0666)
922         if err != nil {
923                 t.Fatalf("failed to write source file: %v", err)
924         }
925         exe := filepath.Join(tmpdir, "x.exe")
926         cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe, src)
927         out, err := cmd.CombinedOutput()
928         if err != nil {
929                 t.Fatalf("build failed: %v\n%s", err, out)
930         }
931
932         fi, err := os.Stat(exe)
933         if err != nil {
934                 t.Fatalf("failed to stat output file: %v", err)
935         }
936
937         // The test program is not much different from a helloworld, which is
938         // typically a little over 1 MB. We allow 5 MB. If the bad stmp is live,
939         // it will be over 10 MB.
940         const want = 5 << 20
941         if got := fi.Size(); got > want {
942                 t.Errorf("binary too big: got %d, want < %d", got, want)
943         }
944 }
945
946 const testIssue42396src = `
947 package main
948
949 //go:noinline
950 //go:nosplit
951 func callee(x int) {
952 }
953
954 func main() {
955         callee(9)
956 }
957 `
958
959 func TestIssue42396(t *testing.T) {
960         testenv.MustHaveGoBuild(t)
961
962         if !sys.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
963                 t.Skip("no race detector support")
964         }
965
966         t.Parallel()
967
968         tmpdir := t.TempDir()
969
970         src := filepath.Join(tmpdir, "main.go")
971         err := ioutil.WriteFile(src, []byte(testIssue42396src), 0666)
972         if err != nil {
973                 t.Fatalf("failed to write source file: %v", err)
974         }
975         exe := filepath.Join(tmpdir, "main.exe")
976         cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-race", "-o", exe, src)
977         out, err := cmd.CombinedOutput()
978         if err == nil {
979                 t.Fatalf("build unexpectedly succeeded")
980         }
981
982         // Check to make sure that we see a reasonable error message
983         // and not a panic.
984         if strings.Contains(string(out), "panic:") {
985                 t.Fatalf("build should not fail with panic:\n%s", out)
986         }
987         const want = "reference to undefined builtin"
988         if !strings.Contains(string(out), want) {
989                 t.Fatalf("error message incorrect: expected it to contain %q but instead got:\n%s\n", want, out)
990         }
991 }
992
993 const testLargeRelocSrc = `
994 package main
995
996 var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
997
998 func main() {
999         check(x[1<<23-1], 0)
1000         check(x[1<<23], 23)
1001         check(x[1<<23+1], 0)
1002         check(x[1<<24-1], 0)
1003         check(x[1<<24], 24)
1004         check(x[1<<24+1], 0)
1005 }
1006
1007 func check(x, y byte) {
1008         if x != y {
1009                 panic("FAIL")
1010         }
1011 }
1012 `
1013
1014 func TestLargeReloc(t *testing.T) {
1015         // Test that large relocation addend is handled correctly.
1016         // In particular, on darwin/arm64 when external linking,
1017         // Mach-O relocation has only 24-bit addend. See issue #42738.
1018         testenv.MustHaveGoBuild(t)
1019         t.Parallel()
1020
1021         tmpdir := t.TempDir()
1022
1023         src := filepath.Join(tmpdir, "x.go")
1024         err := ioutil.WriteFile(src, []byte(testLargeRelocSrc), 0666)
1025         if err != nil {
1026                 t.Fatalf("failed to write source file: %v", err)
1027         }
1028         cmd := exec.Command(testenv.GoToolPath(t), "run", src)
1029         out, err := cmd.CombinedOutput()
1030         if err != nil {
1031                 t.Errorf("build failed: %v. output:\n%s", err, out)
1032         }
1033
1034         if testenv.HasCGO() { // currently all targets that support cgo can external link
1035                 cmd = exec.Command(testenv.GoToolPath(t), "run", "-ldflags=-linkmode=external", src)
1036                 out, err = cmd.CombinedOutput()
1037                 if err != nil {
1038                         t.Fatalf("build failed: %v. output:\n%s", err, out)
1039                 }
1040         }
1041 }