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