Source file
src/cmd/link/link_test.go
1
2
3
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
35
36
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
74
75
76
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
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
107
108 write(".facts", "this is not an object file")
109 runGo("tool", "pack", "r", "main.a", ".facts")
110
111
112
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
131
132
133
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
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
210
211
212
213
214 write("main.go", `package main
215 func main() {
216 x()
217 }
218 func x()
219 `)
220
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
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
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
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=",
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"))
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
414
415
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
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
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
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
536
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
573
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
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
638
639
640
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
689
690
691
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
727
728 if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || (runtime.GOARCH == "arm64" && runtime.GOOS == "windows") || !testenv.CanInternalLink() {
729 return
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
748
749
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
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
784
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
804 testenv.MustHaveGoBuild(t)
805
806 if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" {
807
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
820 out, err := cmd.CombinedOutput()
821 if err != nil {
822 t.Fatalf("building failed: %v, output:\n%s", err, out)
823 }
824
825
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
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
852 out, err := cmd.CombinedOutput()
853 if err != nil {
854 t.Fatalf("building failed: %v, output:\n%s", err, out)
855 }
856
857
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
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
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
936
937
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
981
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
1014
1015
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() {
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 }
1040
View as plain text