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