Source file
src/cmd/link/link_test.go
1
2
3
4
5 package main
6
7 import (
8 "bufio"
9 "bytes"
10 "debug/macho"
11 "errors"
12 "internal/platform"
13 "internal/testenv"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "regexp"
18 "runtime"
19 "strings"
20 "testing"
21
22 "cmd/internal/sys"
23 )
24
25 var AuthorPaidByTheColumnInch struct {
26 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."`
27
28 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."`
29
30 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."`
31
32 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."`
33 }
34
35 func TestLargeSymName(t *testing.T) {
36
37
38
39 _ = AuthorPaidByTheColumnInch
40 }
41
42 func TestIssue21703(t *testing.T) {
43 t.Parallel()
44
45 testenv.MustHaveGoBuild(t)
46 testenv.MustInternalLink(t, false)
47
48 const source = `
49 package main
50 const X = "\n!\n"
51 func main() {}
52 `
53
54 tmpdir := t.TempDir()
55 main := filepath.Join(tmpdir, "main.go")
56
57 err := os.WriteFile(main, []byte(source), 0666)
58 if err != nil {
59 t.Fatalf("failed to write main.go: %v\n", err)
60 }
61
62 importcfgfile := filepath.Join(tmpdir, "importcfg")
63 testenv.WriteImportcfg(t, importcfgfile, nil, main)
64
65 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
66 cmd.Dir = tmpdir
67 out, err := cmd.CombinedOutput()
68 if err != nil {
69 t.Fatalf("failed to compile main.go: %v, output: %s\n", err, out)
70 }
71
72 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "main.o")
73 cmd.Dir = tmpdir
74 out, err = cmd.CombinedOutput()
75 if err != nil {
76 if runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
77 testenv.SkipFlaky(t, 58806)
78 }
79 t.Fatalf("failed to link main.o: %v, output: %s\n", err, out)
80 }
81 }
82
83
84
85
86
87 func TestIssue28429(t *testing.T) {
88 t.Parallel()
89
90 testenv.MustHaveGoBuild(t)
91 testenv.MustInternalLink(t, false)
92
93 tmpdir := t.TempDir()
94
95 write := func(name, content string) {
96 err := os.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
97 if err != nil {
98 t.Fatal(err)
99 }
100 }
101
102 runGo := func(args ...string) {
103 cmd := testenv.Command(t, testenv.GoToolPath(t), args...)
104 cmd.Dir = tmpdir
105 out, err := cmd.CombinedOutput()
106 if err != nil {
107 if len(args) >= 2 && args[1] == "link" && runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
108 testenv.SkipFlaky(t, 58806)
109 }
110 t.Fatalf("'go %s' failed: %v, output: %s",
111 strings.Join(args, " "), err, out)
112 }
113 }
114
115
116 write("main.go", "package main; func main() {}")
117 importcfgfile := filepath.Join(tmpdir, "importcfg")
118 testenv.WriteImportcfg(t, importcfgfile, nil, filepath.Join(tmpdir, "main.go"))
119 runGo("tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
120 runGo("tool", "pack", "c", "main.a", "main.o")
121
122
123
124 write(".facts", "this is not an object file")
125 runGo("tool", "pack", "r", "main.a", ".facts")
126
127
128
129 runGo("tool", "link", "-importcfg="+importcfgfile, "main.a")
130 }
131
132 func TestUnresolved(t *testing.T) {
133 testenv.MustHaveGoBuild(t)
134
135 t.Parallel()
136
137 tmpdir := t.TempDir()
138
139 write := func(name, content string) {
140 err := os.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
141 if err != nil {
142 t.Fatal(err)
143 }
144 }
145
146
147
148
149
150
151 write("go.mod", "module testunresolved\n")
152 write("main.go", `package main
153
154 func main() {
155 x()
156 }
157
158 func x()
159 `)
160 write("main.s", `
161 TEXT ·x(SB),0,$0
162 MOVD zero<>(SB), AX
163 MOVD zero(SB), AX
164 MOVD ·zero(SB), AX
165 RET
166 `)
167 cmd := testenv.Command(t, testenv.GoToolPath(t), "build")
168 cmd.Dir = tmpdir
169 cmd.Env = append(os.Environ(),
170 "GOARCH=amd64", "GOOS=linux", "GOPATH="+filepath.Join(tmpdir, "_gopath"))
171 out, err := cmd.CombinedOutput()
172 if err == nil {
173 t.Fatalf("expected build to fail, but it succeeded")
174 }
175 out = regexp.MustCompile("(?m)^#.*\n").ReplaceAll(out, nil)
176 got := string(out)
177 want := `main.x: relocation target zero not defined
178 main.x: relocation target zero not defined
179 main.x: relocation target main.zero not defined
180 `
181 if want != got {
182 t.Fatalf("want:\n%sgot:\n%s", want, got)
183 }
184 }
185
186 func TestIssue33979(t *testing.T) {
187 testenv.MustHaveGoBuild(t)
188 testenv.MustHaveCGO(t)
189 testenv.MustInternalLink(t, true)
190
191 t.Parallel()
192
193 tmpdir := t.TempDir()
194
195 write := func(name, content string) {
196 err := os.WriteFile(filepath.Join(tmpdir, name), []byte(content), 0666)
197 if err != nil {
198 t.Fatal(err)
199 }
200 }
201
202 run := func(name string, args ...string) string {
203 cmd := testenv.Command(t, name, args...)
204 cmd.Dir = tmpdir
205 out, err := cmd.CombinedOutput()
206 if err != nil {
207 t.Fatalf("'go %s' failed: %v, output: %s", strings.Join(args, " "), err, out)
208 }
209 return string(out)
210 }
211 runGo := func(args ...string) string {
212 return run(testenv.GoToolPath(t), args...)
213 }
214
215
216
217
218
219
220 write("main.go", `package main
221 func main() {
222 x()
223 }
224 func x()
225 `)
226
227 write("x.s", `
228 TEXT ·x(SB),0,$0
229 CALL foo(SB)
230 RET
231 `)
232 write("x.c", `
233 void undefined();
234
235 void foo() {
236 undefined();
237 }
238 `)
239
240 cc := strings.TrimSpace(runGo("env", "CC"))
241 cflags := strings.Fields(runGo("env", "GOGCCFLAGS"))
242
243 importcfgfile := filepath.Join(tmpdir, "importcfg")
244 testenv.WriteImportcfg(t, importcfgfile, nil, "runtime")
245
246
247 runGo("tool", "asm", "-p=main", "-gensymabis", "-o", "symabis", "x.s")
248 runGo("tool", "compile", "-importcfg="+importcfgfile, "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go")
249 runGo("tool", "asm", "-p=main", "-o", "x2.o", "x.s")
250 run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...)
251 runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o")
252
253
254 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-linkmode=internal", "x.a")
255 cmd.Dir = tmpdir
256 out, err := cmd.CombinedOutput()
257 if err == nil {
258 t.Fatalf("expected link to fail, but it succeeded")
259 }
260 re := regexp.MustCompile(`(?m)^main\(.*text\): relocation target undefined not defined$`)
261 if !re.Match(out) {
262 t.Fatalf("got:\n%q\nwant:\n%s", out, re)
263 }
264 }
265
266 func TestBuildForTvOS(t *testing.T) {
267 testenv.MustHaveCGO(t)
268 testenv.MustHaveGoBuild(t)
269
270
271 if runtime.GOOS != "darwin" {
272 t.Skip("skipping on non-darwin platform")
273 }
274 if testing.Short() && os.Getenv("GO_BUILDER_NAME") == "" {
275 t.Skip("skipping in -short mode with $GO_BUILDER_NAME empty")
276 }
277 if err := testenv.Command(t, "xcrun", "--help").Run(); err != nil {
278 t.Skipf("error running xcrun, required for iOS cross build: %v", err)
279 }
280
281 t.Parallel()
282
283 sdkPath, err := testenv.Command(t, "xcrun", "--sdk", "appletvos", "--show-sdk-path").Output()
284 if err != nil {
285 t.Skip("failed to locate appletvos SDK, skipping")
286 }
287 CC := []string{
288 "clang",
289 "-arch",
290 "arm64",
291 "-isysroot", strings.TrimSpace(string(sdkPath)),
292 "-mtvos-version-min=12.0",
293 "-fembed-bitcode",
294 }
295 CGO_LDFLAGS := []string{"-framework", "CoreFoundation"}
296 lib := filepath.Join("testdata", "testBuildFortvOS", "lib.go")
297 tmpDir := t.TempDir()
298
299 ar := filepath.Join(tmpDir, "lib.a")
300 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode=c-archive", "-o", ar, lib)
301 env := []string{
302 "CGO_ENABLED=1",
303 "GOOS=ios",
304 "GOARCH=arm64",
305 "CC=" + strings.Join(CC, " "),
306 "CGO_CFLAGS=",
307 "CGO_LDFLAGS=" + strings.Join(CGO_LDFLAGS, " "),
308 }
309 cmd.Env = append(os.Environ(), env...)
310 t.Logf("%q %v", env, cmd)
311 if out, err := cmd.CombinedOutput(); err != nil {
312 t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
313 }
314
315 link := testenv.Command(t, CC[0], CC[1:]...)
316 link.Args = append(link.Args, CGO_LDFLAGS...)
317 link.Args = append(link.Args, "-o", filepath.Join(tmpDir, "a.out"))
318 link.Args = append(link.Args, ar, filepath.Join("testdata", "testBuildFortvOS", "main.m"))
319 t.Log(link)
320 if out, err := link.CombinedOutput(); err != nil {
321 t.Fatalf("%v: %v:\n%s", link.Args, err, out)
322 }
323 }
324
325 var testXFlagSrc = `
326 package main
327 var X = "hello"
328 var Z = [99999]int{99998:12345} // make it large enough to be mmaped
329 func main() { println(X) }
330 `
331
332 func TestXFlag(t *testing.T) {
333 testenv.MustHaveGoBuild(t)
334
335 t.Parallel()
336
337 tmpdir := t.TempDir()
338
339 src := filepath.Join(tmpdir, "main.go")
340 err := os.WriteFile(src, []byte(testXFlagSrc), 0666)
341 if err != nil {
342 t.Fatal(err)
343 }
344
345 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-X=main.X=meow", "-o", filepath.Join(tmpdir, "main"), src)
346 if out, err := cmd.CombinedOutput(); err != nil {
347 t.Errorf("%v: %v:\n%s", cmd.Args, err, out)
348 }
349 }
350
351 var trivialSrc = `
352 package main
353 func main() { }
354 `
355
356 func TestMachOBuildVersion(t *testing.T) {
357 testenv.MustHaveGoBuild(t)
358
359 t.Parallel()
360
361 tmpdir := t.TempDir()
362
363 src := filepath.Join(tmpdir, "main.go")
364 err := os.WriteFile(src, []byte(trivialSrc), 0666)
365 if err != nil {
366 t.Fatal(err)
367 }
368
369 exe := filepath.Join(tmpdir, "main")
370 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode=internal", "-o", exe, src)
371 cmd.Env = append(os.Environ(),
372 "CGO_ENABLED=0",
373 "GOOS=darwin",
374 "GOARCH=amd64",
375 )
376 if out, err := cmd.CombinedOutput(); err != nil {
377 t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
378 }
379 exef, err := os.Open(exe)
380 if err != nil {
381 t.Fatal(err)
382 }
383 defer exef.Close()
384 exem, err := macho.NewFile(exef)
385 if err != nil {
386 t.Fatal(err)
387 }
388 found := false
389 const LC_BUILD_VERSION = 0x32
390 checkMin := func(ver uint32) {
391 major, minor, patch := (ver>>16)&0xff, (ver>>8)&0xff, (ver>>0)&0xff
392 if major < 11 {
393 t.Errorf("LC_BUILD_VERSION version %d.%d.%d < 11.0.0", major, minor, patch)
394 }
395 }
396 for _, cmd := range exem.Loads {
397 raw := cmd.Raw()
398 type_ := exem.ByteOrder.Uint32(raw)
399 if type_ != LC_BUILD_VERSION {
400 continue
401 }
402 osVer := exem.ByteOrder.Uint32(raw[12:])
403 checkMin(osVer)
404 sdkVer := exem.ByteOrder.Uint32(raw[16:])
405 checkMin(sdkVer)
406 found = true
407 break
408 }
409 if !found {
410 t.Errorf("no LC_BUILD_VERSION load command found")
411 }
412 }
413
414 const Issue34788src = `
415
416 package blah
417
418 func Blah(i int) int {
419 a := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
420 return a[i&7]
421 }
422 `
423
424 func TestIssue34788Android386TLSSequence(t *testing.T) {
425 testenv.MustHaveGoBuild(t)
426
427
428
429
430 if runtime.GOARCH != "amd64" ||
431 (runtime.GOOS != "darwin" && runtime.GOOS != "linux") {
432 t.Skip("skipping on non-{linux,darwin}/amd64 platform")
433 }
434
435 t.Parallel()
436
437 tmpdir := t.TempDir()
438
439 src := filepath.Join(tmpdir, "blah.go")
440 err := os.WriteFile(src, []byte(Issue34788src), 0666)
441 if err != nil {
442 t.Fatal(err)
443 }
444
445 obj := filepath.Join(tmpdir, "blah.o")
446 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-p=blah", "-o", obj, src)
447 cmd.Env = append(os.Environ(), "GOARCH=386", "GOOS=android")
448 if out, err := cmd.CombinedOutput(); err != nil {
449 t.Fatalf("failed to compile blah.go: %v, output: %s\n", err, out)
450 }
451
452
453 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "objdump", obj)
454 out, oerr := cmd.CombinedOutput()
455 if oerr != nil {
456 t.Fatalf("failed to objdump blah.o: %v, output: %s\n", oerr, out)
457 }
458
459
460 scanner := bufio.NewScanner(bytes.NewReader(out))
461 for scanner.Scan() {
462 line := scanner.Text()
463 if strings.Contains(line, "R_TLS_LE") {
464 t.Errorf("objdump output contains unexpected R_TLS_LE reloc: %s", line)
465 }
466 }
467 }
468
469 const testStrictDupGoSrc = `
470 package main
471 func f()
472 func main() { f() }
473 `
474
475 const testStrictDupAsmSrc1 = `
476 #include "textflag.h"
477 TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
478 RET
479 `
480
481 const testStrictDupAsmSrc2 = `
482 #include "textflag.h"
483 TEXT ·f(SB), NOSPLIT|DUPOK, $0-0
484 JMP 0(PC)
485 `
486
487 const testStrictDupAsmSrc3 = `
488 #include "textflag.h"
489 GLOBL ·rcon(SB), RODATA|DUPOK, $64
490 `
491
492 const testStrictDupAsmSrc4 = `
493 #include "textflag.h"
494 GLOBL ·rcon(SB), RODATA|DUPOK, $32
495 `
496
497 func TestStrictDup(t *testing.T) {
498
499 testenv.MustHaveGoBuild(t)
500
501 asmfiles := []struct {
502 fname string
503 payload string
504 }{
505 {"a", testStrictDupAsmSrc1},
506 {"b", testStrictDupAsmSrc2},
507 {"c", testStrictDupAsmSrc3},
508 {"d", testStrictDupAsmSrc4},
509 }
510
511 t.Parallel()
512
513 tmpdir := t.TempDir()
514
515 src := filepath.Join(tmpdir, "x.go")
516 err := os.WriteFile(src, []byte(testStrictDupGoSrc), 0666)
517 if err != nil {
518 t.Fatal(err)
519 }
520 for _, af := range asmfiles {
521 src = filepath.Join(tmpdir, af.fname+".s")
522 err = os.WriteFile(src, []byte(af.payload), 0666)
523 if err != nil {
524 t.Fatal(err)
525 }
526 }
527 src = filepath.Join(tmpdir, "go.mod")
528 err = os.WriteFile(src, []byte("module teststrictdup\n"), 0666)
529 if err != nil {
530 t.Fatal(err)
531 }
532
533 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-strictdups=1")
534 cmd.Dir = tmpdir
535 out, err := cmd.CombinedOutput()
536 if err != nil {
537 t.Errorf("linking with -strictdups=1 failed: %v\n%s", err, string(out))
538 }
539 if !bytes.Contains(out, []byte("mismatched payload")) {
540 t.Errorf("unexpected output:\n%s", out)
541 }
542
543 cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-strictdups=2")
544 cmd.Dir = tmpdir
545 out, err = cmd.CombinedOutput()
546 if err == nil {
547 t.Errorf("linking with -strictdups=2 did not fail")
548 }
549
550
551 if !(bytes.Contains(out, []byte("mismatched payload: new length")) ||
552 bytes.Contains(out, []byte("mismatched payload: same length but different contents"))) ||
553 !bytes.Contains(out, []byte("mismatched payload: different sizes")) {
554 t.Errorf("unexpected output:\n%s", out)
555 }
556 }
557
558 const testFuncAlignSrc = `
559 package main
560 import (
561 "fmt"
562 )
563 func alignPc()
564 var alignPcFnAddr uintptr
565
566 func main() {
567 if alignPcFnAddr % 512 != 0 {
568 fmt.Printf("expected 512 bytes alignment, got %v\n", alignPcFnAddr)
569 } else {
570 fmt.Printf("PASS")
571 }
572 }
573 `
574
575 var testFuncAlignAsmSources = map[string]string{
576 "arm64": `
577 #include "textflag.h"
578
579 TEXT ·alignPc(SB),NOSPLIT, $0-0
580 MOVD $2, R0
581 PCALIGN $512
582 MOVD $3, R1
583 RET
584
585 GLOBL ·alignPcFnAddr(SB),RODATA,$8
586 DATA ·alignPcFnAddr(SB)/8,$·alignPc(SB)
587 `,
588 "loong64": `
589 #include "textflag.h"
590
591 TEXT ·alignPc(SB),NOSPLIT, $0-0
592 MOVV $2, R4
593 PCALIGN $512
594 MOVV $3, R5
595 RET
596
597 GLOBL ·alignPcFnAddr(SB),RODATA,$8
598 DATA ·alignPcFnAddr(SB)/8,$·alignPc(SB)
599 `,
600 }
601
602
603
604 func TestFuncAlign(t *testing.T) {
605 testFuncAlignAsmSrc := testFuncAlignAsmSources[runtime.GOARCH]
606 if len(testFuncAlignAsmSrc) == 0 || runtime.GOOS != "linux" {
607 t.Skip("skipping on non-linux/{arm64,loong64} platform")
608 }
609 testenv.MustHaveGoBuild(t)
610
611 t.Parallel()
612
613 tmpdir := t.TempDir()
614
615 src := filepath.Join(tmpdir, "go.mod")
616 err := os.WriteFile(src, []byte("module cmd/link/TestFuncAlign/falign"), 0666)
617 if err != nil {
618 t.Fatal(err)
619 }
620 src = filepath.Join(tmpdir, "falign.go")
621 err = os.WriteFile(src, []byte(testFuncAlignSrc), 0666)
622 if err != nil {
623 t.Fatal(err)
624 }
625 src = filepath.Join(tmpdir, "falign.s")
626 err = os.WriteFile(src, []byte(testFuncAlignAsmSrc), 0666)
627 if err != nil {
628 t.Fatal(err)
629 }
630
631
632 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "falign")
633 cmd.Dir = tmpdir
634 out, err := cmd.CombinedOutput()
635 if err != nil {
636 t.Errorf("build failed: %v", err)
637 }
638 cmd = testenv.Command(t, tmpdir+"/falign")
639 out, err = cmd.CombinedOutput()
640 if err != nil {
641 t.Errorf("failed to run with err %v, output: %s", err, out)
642 }
643 if string(out) != "PASS" {
644 t.Errorf("unexpected output: %s\n", out)
645 }
646 }
647
648 const testTrampSrc = `
649 package main
650 import "fmt"
651 func main() {
652 fmt.Println("hello")
653
654 defer func(){
655 if e := recover(); e == nil {
656 panic("did not panic")
657 }
658 }()
659 f1()
660 }
661
662 // Test deferreturn trampolines. See issue #39049.
663 func f1() { defer f2() }
664 func f2() { panic("XXX") }
665 `
666
667 func TestTrampoline(t *testing.T) {
668
669
670
671
672 buildmodes := []string{"default"}
673 switch runtime.GOARCH {
674 case "arm", "arm64", "ppc64":
675 case "ppc64le":
676
677 buildmodes = append(buildmodes, "pie")
678 default:
679 t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
680 }
681
682 testenv.MustHaveGoBuild(t)
683
684 t.Parallel()
685
686 tmpdir := t.TempDir()
687
688 src := filepath.Join(tmpdir, "hello.go")
689 err := os.WriteFile(src, []byte(testTrampSrc), 0666)
690 if err != nil {
691 t.Fatal(err)
692 }
693 exe := filepath.Join(tmpdir, "hello.exe")
694
695 for _, mode := range buildmodes {
696 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2", "-o", exe, src)
697 out, err := cmd.CombinedOutput()
698 if err != nil {
699 t.Fatalf("build (%s) failed: %v\n%s", mode, err, out)
700 }
701 cmd = testenv.Command(t, exe)
702 out, err = cmd.CombinedOutput()
703 if err != nil {
704 t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
705 }
706 if string(out) != "hello\n" {
707 t.Errorf("unexpected output (%s):\n%s", mode, out)
708 }
709 }
710 }
711
712 const testTrampCgoSrc = `
713 package main
714
715 // #include <stdio.h>
716 // void CHello() { printf("hello\n"); fflush(stdout); }
717 import "C"
718
719 func main() {
720 C.CHello()
721 }
722 `
723
724 func TestTrampolineCgo(t *testing.T) {
725
726
727
728
729 buildmodes := []string{"default"}
730 switch runtime.GOARCH {
731 case "arm", "arm64", "ppc64":
732 case "ppc64le":
733
734 buildmodes = append(buildmodes, "pie")
735 default:
736 t.Skipf("trampoline insertion is not implemented on %s", runtime.GOARCH)
737 }
738
739 testenv.MustHaveGoBuild(t)
740 testenv.MustHaveCGO(t)
741
742 t.Parallel()
743
744 tmpdir := t.TempDir()
745
746 src := filepath.Join(tmpdir, "hello.go")
747 err := os.WriteFile(src, []byte(testTrampCgoSrc), 0666)
748 if err != nil {
749 t.Fatal(err)
750 }
751 exe := filepath.Join(tmpdir, "hello.exe")
752
753 for _, mode := range buildmodes {
754 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2", "-o", exe, src)
755 out, err := cmd.CombinedOutput()
756 if err != nil {
757 t.Fatalf("build (%s) failed: %v\n%s", mode, err, out)
758 }
759 cmd = testenv.Command(t, exe)
760 out, err = cmd.CombinedOutput()
761 if err != nil {
762 t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
763 }
764 if string(out) != "hello\n" && string(out) != "hello\r\n" {
765 t.Errorf("unexpected output (%s):\n%s", mode, out)
766 }
767
768
769
770 if !testenv.CanInternalLink(true) {
771 continue
772 }
773 cmd = testenv.Command(t, testenv.GoToolPath(t), "build", "-buildmode="+mode, "-ldflags=-debugtramp=2 -linkmode=internal", "-o", exe, src)
774 out, err = cmd.CombinedOutput()
775 if err != nil {
776 t.Fatalf("build (%s) failed: %v\n%s", mode, err, out)
777 }
778 cmd = testenv.Command(t, exe)
779 out, err = cmd.CombinedOutput()
780 if err != nil {
781 t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
782 }
783 if string(out) != "hello\n" && string(out) != "hello\r\n" {
784 t.Errorf("unexpected output (%s):\n%s", mode, out)
785 }
786 }
787 }
788
789 func TestIndexMismatch(t *testing.T) {
790
791
792
793 testenv.MustHaveGoBuild(t)
794 testenv.MustInternalLink(t, false)
795
796 t.Parallel()
797
798 tmpdir := t.TempDir()
799
800 aSrc := filepath.Join("testdata", "testIndexMismatch", "a.go")
801 bSrc := filepath.Join("testdata", "testIndexMismatch", "b.go")
802 mSrc := filepath.Join("testdata", "testIndexMismatch", "main.go")
803 aObj := filepath.Join(tmpdir, "a.o")
804 mObj := filepath.Join(tmpdir, "main.o")
805 exe := filepath.Join(tmpdir, "main.exe")
806
807 importcfgFile := filepath.Join(tmpdir, "runtime.importcfg")
808 testenv.WriteImportcfg(t, importcfgFile, nil, "runtime")
809 importcfgWithAFile := filepath.Join(tmpdir, "witha.importcfg")
810 testenv.WriteImportcfg(t, importcfgWithAFile, map[string]string{"a": aObj}, "runtime")
811
812
813 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, aSrc)
814 t.Log(cmd)
815 out, err := cmd.CombinedOutput()
816 if err != nil {
817 t.Fatalf("compiling a.go failed: %v\n%s", err, out)
818 }
819 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgWithAFile, "-p=main", "-I", tmpdir, "-o", mObj, mSrc)
820 t.Log(cmd)
821 out, err = cmd.CombinedOutput()
822 if err != nil {
823 t.Fatalf("compiling main.go failed: %v\n%s", err, out)
824 }
825 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
826 t.Log(cmd)
827 out, err = cmd.CombinedOutput()
828 if err != nil {
829 if runtime.GOOS == "android" && runtime.GOARCH == "arm64" {
830 testenv.SkipFlaky(t, 58806)
831 }
832 t.Errorf("linking failed: %v\n%s", err, out)
833 }
834
835
836
837 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, bSrc)
838 t.Log(cmd)
839 out, err = cmd.CombinedOutput()
840 if err != nil {
841 t.Fatalf("compiling a.go failed: %v\n%s", err, out)
842 }
843 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
844 t.Log(cmd)
845 out, err = cmd.CombinedOutput()
846 if err == nil {
847 t.Fatalf("linking didn't fail")
848 }
849 if !bytes.Contains(out, []byte("fingerprint mismatch")) {
850 t.Errorf("did not see expected error message. out:\n%s", out)
851 }
852 }
853
854 func TestPErsrcBinutils(t *testing.T) {
855
856 testenv.MustHaveGoBuild(t)
857
858 if (runtime.GOARCH != "386" && runtime.GOARCH != "amd64") || runtime.GOOS != "windows" {
859
860 t.Skipf("this is only for windows/amd64 and windows/386")
861 }
862
863 t.Parallel()
864
865 tmpdir := t.TempDir()
866
867 pkgdir := filepath.Join("testdata", "pe-binutils")
868 exe := filepath.Join(tmpdir, "a.exe")
869 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe)
870 cmd.Dir = pkgdir
871
872 out, err := cmd.CombinedOutput()
873 if err != nil {
874 t.Fatalf("building failed: %v, output:\n%s", err, out)
875 }
876
877
878 b, err := os.ReadFile(exe)
879 if err != nil {
880 t.Fatalf("reading output failed: %v", err)
881 }
882 if !bytes.Contains(b, []byte("Hello Gophers!")) {
883 t.Fatalf("binary does not contain expected content")
884 }
885 }
886
887 func TestPErsrcLLVM(t *testing.T) {
888
889 testenv.MustHaveGoBuild(t)
890
891 if runtime.GOOS != "windows" {
892 t.Skipf("this is a windows-only test")
893 }
894
895 t.Parallel()
896
897 tmpdir := t.TempDir()
898
899 pkgdir := filepath.Join("testdata", "pe-llvm")
900 exe := filepath.Join(tmpdir, "a.exe")
901 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe)
902 cmd.Dir = pkgdir
903
904 out, err := cmd.CombinedOutput()
905 if err != nil {
906 t.Fatalf("building failed: %v, output:\n%s", err, out)
907 }
908
909
910 b, err := os.ReadFile(exe)
911 if err != nil {
912 t.Fatalf("reading output failed: %v", err)
913 }
914 if !bytes.Contains(b, []byte("resname RCDATA a.rc")) {
915 t.Fatalf("binary does not contain expected content")
916 }
917 }
918
919 func TestContentAddressableSymbols(t *testing.T) {
920
921 testenv.MustHaveGoBuild(t)
922
923 t.Parallel()
924
925 src := filepath.Join("testdata", "testHashedSyms", "p.go")
926 cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
927 out, err := cmd.CombinedOutput()
928 if err != nil {
929 t.Errorf("command %s failed: %v\n%s", cmd, err, out)
930 }
931 }
932
933 func TestReadOnly(t *testing.T) {
934
935 testenv.MustHaveGoBuild(t)
936
937 t.Parallel()
938
939 src := filepath.Join("testdata", "testRO", "x.go")
940 cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
941 out, err := cmd.CombinedOutput()
942 if err == nil {
943 t.Errorf("running test program did not fail. output:\n%s", out)
944 }
945 }
946
947 const testIssue38554Src = `
948 package main
949
950 type T [10<<20]byte
951
952 //go:noinline
953 func f() T {
954 return T{} // compiler will make a large stmp symbol, but not used.
955 }
956
957 func main() {
958 x := f()
959 println(x[1])
960 }
961 `
962
963 func TestIssue38554(t *testing.T) {
964 testenv.MustHaveGoBuild(t)
965
966 t.Parallel()
967
968 tmpdir := t.TempDir()
969
970 src := filepath.Join(tmpdir, "x.go")
971 err := os.WriteFile(src, []byte(testIssue38554Src), 0666)
972 if err != nil {
973 t.Fatalf("failed to write source file: %v", err)
974 }
975 exe := filepath.Join(tmpdir, "x.exe")
976 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src)
977 out, err := cmd.CombinedOutput()
978 if err != nil {
979 t.Fatalf("build failed: %v\n%s", err, out)
980 }
981
982 fi, err := os.Stat(exe)
983 if err != nil {
984 t.Fatalf("failed to stat output file: %v", err)
985 }
986
987
988
989
990 const want = 5 << 20
991 if got := fi.Size(); got > want {
992 t.Errorf("binary too big: got %d, want < %d", got, want)
993 }
994 }
995
996 const testIssue42396src = `
997 package main
998
999 //go:noinline
1000 //go:nosplit
1001 func callee(x int) {
1002 }
1003
1004 func main() {
1005 callee(9)
1006 }
1007 `
1008
1009 func TestIssue42396(t *testing.T) {
1010 testenv.MustHaveGoBuild(t)
1011
1012 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
1013 t.Skip("no race detector support")
1014 }
1015
1016 t.Parallel()
1017
1018 tmpdir := t.TempDir()
1019
1020 src := filepath.Join(tmpdir, "main.go")
1021 err := os.WriteFile(src, []byte(testIssue42396src), 0666)
1022 if err != nil {
1023 t.Fatalf("failed to write source file: %v", err)
1024 }
1025 exe := filepath.Join(tmpdir, "main.exe")
1026 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-gcflags=-race", "-o", exe, src)
1027 out, err := cmd.CombinedOutput()
1028 if err == nil {
1029 t.Fatalf("build unexpectedly succeeded")
1030 }
1031
1032
1033
1034 if strings.Contains(string(out), "panic:") {
1035 t.Fatalf("build should not fail with panic:\n%s", out)
1036 }
1037 const want = "reference to undefined builtin"
1038 if !strings.Contains(string(out), want) {
1039 t.Fatalf("error message incorrect: expected it to contain %q but instead got:\n%s\n", want, out)
1040 }
1041 }
1042
1043 const testLargeRelocSrc = `
1044 package main
1045
1046 var x = [1<<25]byte{1<<23: 23, 1<<24: 24}
1047
1048 var addr = [...]*byte{
1049 &x[1<<23-1],
1050 &x[1<<23],
1051 &x[1<<23+1],
1052 &x[1<<24-1],
1053 &x[1<<24],
1054 &x[1<<24+1],
1055 }
1056
1057 func main() {
1058 // check relocations in instructions
1059 check(x[1<<23-1], 0)
1060 check(x[1<<23], 23)
1061 check(x[1<<23+1], 0)
1062 check(x[1<<24-1], 0)
1063 check(x[1<<24], 24)
1064 check(x[1<<24+1], 0)
1065
1066 // check absolute address relocations in data
1067 check(*addr[0], 0)
1068 check(*addr[1], 23)
1069 check(*addr[2], 0)
1070 check(*addr[3], 0)
1071 check(*addr[4], 24)
1072 check(*addr[5], 0)
1073 }
1074
1075 func check(x, y byte) {
1076 if x != y {
1077 panic("FAIL")
1078 }
1079 }
1080 `
1081
1082 func TestLargeReloc(t *testing.T) {
1083
1084
1085
1086 testenv.MustHaveGoBuild(t)
1087 t.Parallel()
1088
1089 tmpdir := t.TempDir()
1090
1091 src := filepath.Join(tmpdir, "x.go")
1092 err := os.WriteFile(src, []byte(testLargeRelocSrc), 0666)
1093 if err != nil {
1094 t.Fatalf("failed to write source file: %v", err)
1095 }
1096 cmd := testenv.Command(t, testenv.GoToolPath(t), "run", src)
1097 out, err := cmd.CombinedOutput()
1098 if err != nil {
1099 t.Errorf("build failed: %v. output:\n%s", err, out)
1100 }
1101
1102 if testenv.HasCGO() {
1103 cmd = testenv.Command(t, testenv.GoToolPath(t), "run", "-ldflags=-linkmode=external", src)
1104 out, err = cmd.CombinedOutput()
1105 if err != nil {
1106 t.Fatalf("build failed: %v. output:\n%s", err, out)
1107 }
1108 }
1109 }
1110
1111 func TestUnlinkableObj(t *testing.T) {
1112
1113 testenv.MustHaveGoBuild(t)
1114 t.Parallel()
1115
1116 if true {
1117 t.Skip("TODO(mdempsky): Fix ICE when importing unlinkable objects for GOEXPERIMENT=unified")
1118 }
1119
1120 tmpdir := t.TempDir()
1121
1122 xSrc := filepath.Join(tmpdir, "x.go")
1123 pSrc := filepath.Join(tmpdir, "p.go")
1124 xObj := filepath.Join(tmpdir, "x.o")
1125 pObj := filepath.Join(tmpdir, "p.o")
1126 exe := filepath.Join(tmpdir, "x.exe")
1127 importcfgfile := filepath.Join(tmpdir, "importcfg")
1128 testenv.WriteImportcfg(t, importcfgfile, map[string]string{"p": pObj})
1129 err := os.WriteFile(xSrc, []byte("package main\nimport _ \"p\"\nfunc main() {}\n"), 0666)
1130 if err != nil {
1131 t.Fatalf("failed to write source file: %v", err)
1132 }
1133 err = os.WriteFile(pSrc, []byte("package p\n"), 0666)
1134 if err != nil {
1135 t.Fatalf("failed to write source file: %v", err)
1136 }
1137 cmd := testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-o", pObj, pSrc)
1138 out, err := cmd.CombinedOutput()
1139 if err != nil {
1140 t.Fatalf("compile p.go failed: %v. output:\n%s", err, out)
1141 }
1142 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "-o", xObj, xSrc)
1143 out, err = cmd.CombinedOutput()
1144 if err != nil {
1145 t.Fatalf("compile x.go failed: %v. output:\n%s", err, out)
1146 }
1147 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-o", exe, xObj)
1148 out, err = cmd.CombinedOutput()
1149 if err == nil {
1150 t.Fatalf("link did not fail")
1151 }
1152 if !bytes.Contains(out, []byte("unlinkable object")) {
1153 t.Errorf("did not see expected error message. out:\n%s", out)
1154 }
1155
1156
1157 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", pObj, pSrc)
1158 out, err = cmd.CombinedOutput()
1159 if err != nil {
1160 t.Fatalf("compile p.go failed: %v. output:\n%s", err, out)
1161 }
1162 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-o", xObj, xSrc)
1163 out, err = cmd.CombinedOutput()
1164 if err != nil {
1165 t.Fatalf("compile failed: %v. output:\n%s", err, out)
1166 }
1167
1168 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-o", exe, xObj)
1169 out, err = cmd.CombinedOutput()
1170 if err != nil {
1171 t.Errorf("link failed: %v. output:\n%s", err, out)
1172 }
1173 }
1174
1175 func TestExtLinkCmdlineDeterminism(t *testing.T) {
1176
1177 testenv.MustHaveGoBuild(t)
1178 testenv.MustHaveCGO(t)
1179 t.Parallel()
1180
1181
1182 testSrc := `
1183 package main
1184 import "C"
1185 //export F1
1186 func F1() {}
1187 //export F2
1188 func F2() {}
1189 //export F3
1190 func F3() {}
1191 func main() {}
1192 `
1193
1194 tmpdir := t.TempDir()
1195 src := filepath.Join(tmpdir, "x.go")
1196 if err := os.WriteFile(src, []byte(testSrc), 0666); err != nil {
1197 t.Fatal(err)
1198 }
1199 exe := filepath.Join(tmpdir, "x.exe")
1200
1201
1202
1203 linktmp := filepath.Join(tmpdir, "linktmp")
1204 if err := os.Mkdir(linktmp, 0777); err != nil {
1205 t.Fatal(err)
1206 }
1207
1208
1209
1210 ldflags := "-ldflags=-v -linkmode=external -tmpdir=" + linktmp
1211 var out0 []byte
1212 for i := 0; i < 5; i++ {
1213 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", ldflags, "-o", exe, src)
1214 out, err := cmd.CombinedOutput()
1215 if err != nil {
1216 t.Fatalf("build failed: %v, output:\n%s", err, out)
1217 }
1218 if err := os.Remove(exe); err != nil {
1219 t.Fatal(err)
1220 }
1221
1222
1223 j := bytes.Index(out, []byte("\nhost link:"))
1224 if j == -1 {
1225 t.Fatalf("host link step not found, output:\n%s", out)
1226 }
1227 out = out[j+1:]
1228 k := bytes.Index(out, []byte("\n"))
1229 if k == -1 {
1230 t.Fatalf("no newline after host link, output:\n%s", out)
1231 }
1232 out = out[:k]
1233
1234
1235
1236 fs := bytes.Fields(out)
1237 for i, f := range fs {
1238 if bytes.Equal(f, []byte(`"-o"`)) && i+1 < len(fs) {
1239 fs[i+1] = []byte("a.out")
1240 break
1241 }
1242 }
1243 out = bytes.Join(fs, []byte{' '})
1244
1245 if i == 0 {
1246 out0 = out
1247 continue
1248 }
1249 if !bytes.Equal(out0, out) {
1250 t.Fatalf("output differ:\n%s\n==========\n%s", out0, out)
1251 }
1252 }
1253 }
1254
1255
1256
1257 func TestResponseFile(t *testing.T) {
1258 t.Parallel()
1259
1260 testenv.MustHaveGoBuild(t)
1261
1262
1263
1264 testenv.MustHaveCGO(t)
1265
1266 tmpdir := t.TempDir()
1267
1268 src := filepath.Join(tmpdir, "x.go")
1269 if err := os.WriteFile(src, []byte(`package main; import "C"; func main() {}`), 0666); err != nil {
1270 t.Fatal(err)
1271 }
1272
1273 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", "output", "x.go")
1274 cmd.Dir = tmpdir
1275
1276
1277 var sb strings.Builder
1278 sb.WriteString(`'-ldflags=all="-extldflags=`)
1279 for i := 0; i < sys.ExecArgLengthLimit/len("-g"); i++ {
1280 if i > 0 {
1281 sb.WriteString(" ")
1282 }
1283 sb.WriteString("-g")
1284 }
1285 sb.WriteString(`"'`)
1286 cmd = testenv.CleanCmdEnv(cmd)
1287 cmd.Env = append(cmd.Env, "GOFLAGS="+sb.String())
1288
1289 out, err := cmd.CombinedOutput()
1290 if len(out) > 0 {
1291 t.Logf("%s", out)
1292 }
1293 if err != nil {
1294 t.Error(err)
1295 }
1296 }
1297
1298 func TestDynimportVar(t *testing.T) {
1299
1300
1301 if runtime.GOOS != "darwin" {
1302 t.Skip("skip on non-darwin platform")
1303 }
1304
1305 testenv.MustHaveGoBuild(t)
1306 testenv.MustHaveCGO(t)
1307
1308 t.Parallel()
1309
1310 tmpdir := t.TempDir()
1311 exe := filepath.Join(tmpdir, "a.exe")
1312 src := filepath.Join("testdata", "dynimportvar", "main.go")
1313
1314 for _, mode := range []string{"internal", "external"} {
1315 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-linkmode="+mode, "-o", exe, src)
1316 out, err := cmd.CombinedOutput()
1317 if err != nil {
1318 t.Fatalf("build (linkmode=%s) failed: %v\n%s", mode, err, out)
1319 }
1320 cmd = testenv.Command(t, exe)
1321 out, err = cmd.CombinedOutput()
1322 if err != nil {
1323 t.Errorf("executable failed to run (%s): %v\n%s", mode, err, out)
1324 }
1325 }
1326 }
1327
1328 const helloSrc = `
1329 package main
1330 var X = 42
1331 var Y int
1332 func main() { println("hello", X, Y) }
1333 `
1334
1335 func TestFlagS(t *testing.T) {
1336
1337 testenv.MustHaveGoBuild(t)
1338
1339 t.Parallel()
1340
1341 tmpdir := t.TempDir()
1342 exe := filepath.Join(tmpdir, "a.exe")
1343 src := filepath.Join(tmpdir, "a.go")
1344 err := os.WriteFile(src, []byte(helloSrc), 0666)
1345 if err != nil {
1346 t.Fatal(err)
1347 }
1348
1349 modes := []string{"auto"}
1350 if testenv.HasCGO() {
1351 modes = append(modes, "external")
1352 }
1353
1354
1355 syms := []string{"main.main", "main.X", "main.Y"}
1356
1357 for _, mode := range modes {
1358 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-s -linkmode="+mode, "-o", exe, src)
1359 out, err := cmd.CombinedOutput()
1360 if err != nil {
1361 t.Fatalf("build (linkmode=%s) failed: %v\n%s", mode, err, out)
1362 }
1363 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", exe)
1364 out, err = cmd.CombinedOutput()
1365 if err != nil && !errors.As(err, new(*exec.ExitError)) {
1366
1367
1368
1369 t.Errorf("(mode=%s) go tool nm failed: %v\n%s", mode, err, out)
1370 }
1371 for _, s := range syms {
1372 if bytes.Contains(out, []byte(s)) {
1373 t.Errorf("(mode=%s): unexpected symbol %s", mode, s)
1374 }
1375 }
1376 }
1377 }
1378
1379 func TestRandLayout(t *testing.T) {
1380
1381
1382 testenv.MustHaveGoBuild(t)
1383
1384 t.Parallel()
1385
1386 tmpdir := t.TempDir()
1387
1388 src := filepath.Join(tmpdir, "hello.go")
1389 err := os.WriteFile(src, []byte(trivialSrc), 0666)
1390 if err != nil {
1391 t.Fatal(err)
1392 }
1393
1394 var syms [2]string
1395 for i, seed := range []string{"123", "456"} {
1396 exe := filepath.Join(tmpdir, "hello"+seed+".exe")
1397 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-ldflags=-randlayout="+seed, "-o", exe, src)
1398 out, err := cmd.CombinedOutput()
1399 if err != nil {
1400 t.Fatalf("seed=%v: build failed: %v\n%s", seed, err, out)
1401 }
1402 cmd = testenv.Command(t, exe)
1403 err = cmd.Run()
1404 if err != nil {
1405 t.Fatalf("seed=%v: executable failed to run: %v\n%s", seed, err, out)
1406 }
1407 cmd = testenv.Command(t, testenv.GoToolPath(t), "tool", "nm", exe)
1408 out, err = cmd.CombinedOutput()
1409 if err != nil {
1410 t.Fatalf("seed=%v: fail to run \"go tool nm\": %v\n%s", seed, err, out)
1411 }
1412 syms[i] = string(out)
1413 }
1414 if syms[0] == syms[1] {
1415 t.Errorf("randlayout with different seeds produced same layout:\n%s\n===\n\n%s", syms[0], syms[1])
1416 }
1417 }
1418
1419 func TestCheckLinkname(t *testing.T) {
1420
1421 testenv.MustHaveGoBuild(t)
1422 t.Parallel()
1423
1424 tmpdir := t.TempDir()
1425
1426 tests := []struct {
1427 src string
1428 ok bool
1429 }{
1430
1431 {"ok.go", true},
1432
1433 {"push.go", true},
1434
1435 {"coro.go", false},
1436 {"coro_var.go", false},
1437
1438 {"coro_asm", false},
1439
1440 {"coro2.go", false},
1441
1442 {"fastrand.go", true},
1443 {"badlinkname.go", true},
1444 }
1445 for _, test := range tests {
1446 test := test
1447 t.Run(test.src, func(t *testing.T) {
1448 t.Parallel()
1449 src := filepath.Join("testdata", "linkname", test.src)
1450 exe := filepath.Join(tmpdir, test.src+".exe")
1451 cmd := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src)
1452 out, err := cmd.CombinedOutput()
1453 if test.ok && err != nil {
1454 t.Errorf("build failed unexpectedly: %v:\n%s", err, out)
1455 }
1456 if !test.ok && err == nil {
1457 t.Errorf("build succeeded unexpectedly: %v:\n%s", err, out)
1458 }
1459 })
1460 }
1461 }
1462
View as plain text