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