1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 package ld
32
33 import (
34 "bufio"
35 "cmd/internal/goobj"
36 "cmd/internal/objabi"
37 "cmd/internal/quoted"
38 "cmd/internal/sys"
39 "cmd/internal/telemetry/counter"
40 "cmd/link/internal/benchmark"
41 "flag"
42 "internal/buildcfg"
43 "log"
44 "os"
45 "runtime"
46 "runtime/pprof"
47 "strconv"
48 "strings"
49 )
50
51 var (
52 pkglistfornote []byte
53 windowsgui bool
54 ownTmpDir bool
55 )
56
57 func init() {
58 flag.Var(&flagExtld, "extld", "use `linker` when linking in external mode")
59 flag.Var(&flagExtldflags, "extldflags", "pass `flags` to external linker")
60 flag.Var(&macOS, "macos", "mac OS version to write in build info (only used in internal linking)")
61 flag.Var(&macSDK, "macsdk", "mac SDK version to write in build info (only used in internal linking)")
62 flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
63 flag.Var(&flagW, "w", "disable DWARF generation")
64 }
65
66
67 var (
68 flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id")
69 flagBindNow = flag.Bool("bindnow", false, "mark a dynamically linked ELF object for immediate function binding")
70
71 flagOutfile = flag.String("o", "", "write output to `file`")
72 flagPluginPath = flag.String("pluginpath", "", "full path name for plugin")
73 flagFipso = flag.String("fipso", "", "write fips module to `file`")
74
75 flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`")
76 flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
77 flagRace = flag.Bool("race", false, "enable race detector")
78 flagMsan = flag.Bool("msan", false, "enable MSan interface")
79 flagAsan = flag.Bool("asan", false, "enable ASan interface")
80 flagAslr = flag.Bool("aslr", true, "enable ASLR for buildmode=c-shared on windows")
81
82 flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
83 flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
84 flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files")
85
86 flagExtld quoted.Flag
87 flagExtldflags quoted.Flag
88 flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
89
90 flagCaptureHostObjs = flag.String("capturehostobjs", "", "capture host object files loaded during internal linking to specified dir")
91
92 flagA = flag.Bool("a", false, "no-op (deprecated)")
93 FlagC = flag.Bool("c", false, "dump call graph")
94 FlagD = flag.Bool("d", false, "disable dynamic executable")
95 flagF = flag.Bool("f", false, "ignore version mismatch")
96 flagG = flag.Bool("g", false, "disable go package data checks")
97 flagH = flag.Bool("h", false, "halt on error")
98 flagN = flag.Bool("n", false, "no-op (deprecated)")
99 FlagS = flag.Bool("s", false, "disable symbol table")
100 flag8 bool
101 flagHostBuildid = flag.String("B", "", "set ELF NT_GNU_BUILD_ID `note` or Mach-O UUID; use \"gobuildid\" to generate it from the Go build ID; \"none\" to disable")
102 flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
103 flagCheckLinkname = flag.Bool("checklinkname", true, "check linkname symbol references")
104 FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
105 FlagDebugTextSize = flag.Int("debugtextsize", 0, "debug text section max size")
106 flagDebugNosplit = flag.Bool("debugnosplit", false, "dump nosplit call graph")
107 FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
108 FlagRound = flag.Int64("R", -1, "set address rounding `quantum`")
109 FlagTextAddr = flag.Int64("T", -1, "set the start address of text symbols")
110 FlagDataAddr = flag.Int64("D", -1, "set the start address of data symbols")
111 FlagFuncAlign = flag.Int("funcalign", 0, "set function align to `N` bytes")
112 flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
113 flagPruneWeakMap = flag.Bool("pruneweakmap", true, "prune weak mapinit refs")
114 flagRandLayout = flag.Int64("randlayout", 0, "randomize function layout")
115 flagAllErrors = flag.Bool("e", false, "no limit on number of errors reported")
116 cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
117 memprofile = flag.String("memprofile", "", "write memory profile to `file`")
118 memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
119 benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
120 benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
121
122 flagW ternaryFlag
123 FlagW = new(bool)
124 )
125
126
127
128
129
130 type ternaryFlag int
131
132 const (
133 ternaryFlagUnset ternaryFlag = iota
134 ternaryFlagFalse
135 ternaryFlagTrue
136 )
137
138 func (t *ternaryFlag) Set(s string) error {
139 v, err := strconv.ParseBool(s)
140 if err != nil {
141 return err
142 }
143 if v {
144 *t = ternaryFlagTrue
145 } else {
146 *t = ternaryFlagFalse
147 }
148 return nil
149 }
150
151 func (t *ternaryFlag) String() string {
152 switch *t {
153 case ternaryFlagFalse:
154 return "false"
155 case ternaryFlagTrue:
156 return "true"
157 }
158 return "unset"
159 }
160
161 func (t *ternaryFlag) IsBoolFlag() bool { return true }
162
163
164 func Main(arch *sys.Arch, theArch Arch) {
165 log.SetPrefix("link: ")
166 log.SetFlags(0)
167 counter.Open()
168 counter.Inc("link/invocations")
169
170 thearch = theArch
171 ctxt := linknew(arch)
172 ctxt.Bso = bufio.NewWriter(os.Stdout)
173
174
175
176
177 for _, arg := range os.Args {
178 if arg == "-crash_for_testing" {
179 os.Exit(2)
180 }
181 }
182
183 if buildcfg.GOROOT == "" {
184
185
186
187 } else {
188 addstrdata1(ctxt, "runtime.defaultGOROOT="+buildcfg.GOROOT)
189 }
190
191 buildVersion := buildcfg.Version
192 if goexperiment := buildcfg.Experiment.String(); goexperiment != "" {
193 sep := " "
194 if !strings.Contains(buildVersion, "-") {
195 sep = "-"
196 }
197 buildVersion += sep + "X:" + goexperiment
198 }
199 addstrdata1(ctxt, "runtime.buildVersion="+buildVersion)
200
201
202 if ctxt.Arch.Family == sys.AMD64 && buildcfg.GOOS == "plan9" {
203 flag.BoolVar(&flag8, "8", false, "use 64-bit addresses in symbol table")
204 }
205 flagHeadType := flag.String("H", "", "set header `type`")
206 flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries")
207 flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
208 flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
209 flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
210 objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
211 objabi.AddVersionFlag()
212 objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
213 objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog)
214 objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg)
215
216 objabi.Flagparse(usage)
217 counter.CountFlags("link/flag:", *flag.CommandLine)
218
219 if ctxt.Debugvlog > 0 {
220
221 defer func() { ctxt.loader.Dump() }()
222 }
223 if ctxt.Debugvlog > 1 {
224
225 AtExit(func() {
226 if nerrors > 0 {
227 ctxt.loader.Dump()
228 }
229 })
230 }
231
232 switch *flagHeadType {
233 case "":
234 case "windowsgui":
235 ctxt.HeadType = objabi.Hwindows
236 windowsgui = true
237 default:
238 if err := ctxt.HeadType.Set(*flagHeadType); err != nil {
239 Errorf("%v", err)
240 usage()
241 }
242 }
243 if ctxt.HeadType == objabi.Hunknown {
244 ctxt.HeadType.Set(buildcfg.GOOS)
245 }
246
247 if !*flagAslr && ctxt.BuildMode != BuildModeCShared {
248 Errorf("-aslr=false is only allowed for -buildmode=c-shared")
249 usage()
250 }
251
252 if *FlagD && ctxt.UsesLibc() {
253 Exitf("dynamic linking required on %s; -d flag cannot be used", buildcfg.GOOS)
254 }
255
256 isPowerOfTwo := func(n int64) bool {
257 return n > 0 && n&(n-1) == 0
258 }
259 if *FlagRound != -1 && (*FlagRound < 4096 || !isPowerOfTwo(*FlagRound)) {
260 Exitf("invalid -R value 0x%x", *FlagRound)
261 }
262 if *FlagFuncAlign != 0 && !isPowerOfTwo(int64(*FlagFuncAlign)) {
263 Exitf("invalid -funcalign value %d", *FlagFuncAlign)
264 }
265
266 checkStrictDups = *FlagStrictDups
267
268 switch flagW {
269 case ternaryFlagFalse:
270 *FlagW = false
271 case ternaryFlagTrue:
272 *FlagW = true
273 case ternaryFlagUnset:
274 *FlagW = *FlagS
275 if ctxt.IsDarwin() && ctxt.BuildMode == BuildModeCShared {
276 *FlagW = true
277 }
278 }
279
280 if !buildcfg.Experiment.RegabiWrappers {
281 abiInternalVer = 0
282 }
283
284 startProfile()
285 if ctxt.BuildMode == BuildModeUnset {
286 ctxt.BuildMode.Set("exe")
287 }
288
289 if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 {
290 usage()
291 }
292
293 if *flagOutfile == "" {
294 *flagOutfile = "a.out"
295 if ctxt.HeadType == objabi.Hwindows {
296 *flagOutfile += ".exe"
297 }
298 }
299
300 interpreter = *flagInterpreter
301
302 if *flagHostBuildid == "" && *flagBuildid != "" {
303 *flagHostBuildid = "gobuildid"
304 }
305 addbuildinfo(ctxt)
306
307
308 var bench *benchmark.Metrics
309 if len(*benchmarkFlag) != 0 {
310 if *benchmarkFlag == "mem" {
311 bench = benchmark.New(benchmark.GC, *benchmarkFileFlag)
312 } else if *benchmarkFlag == "cpu" {
313 bench = benchmark.New(benchmark.NoGC, *benchmarkFileFlag)
314 } else {
315 Errorf("unknown benchmark flag: %q", *benchmarkFlag)
316 usage()
317 }
318 }
319
320 bench.Start("libinit")
321 libinit(ctxt)
322 bench.Start("computeTLSOffset")
323 ctxt.computeTLSOffset()
324 bench.Start("Archinit")
325 thearch.Archinit(ctxt)
326
327 if *FlagDataAddr != -1 && *FlagDataAddr%*FlagRound != 0 {
328 Exitf("invalid -D value 0x%x: not aligned to rounding quantum 0x%x", *FlagDataAddr, *FlagRound)
329 }
330
331 if ctxt.linkShared && !ctxt.IsELF {
332 Exitf("-linkshared can only be used on elf systems")
333 }
334
335 if ctxt.Debugvlog != 0 {
336 onOff := func(b bool) string {
337 if b {
338 return "on"
339 }
340 return "off"
341 }
342 ctxt.Logf("build mode: %s, symbol table: %s, DWARF: %s\n", ctxt.BuildMode, onOff(!*FlagS), onOff(dwarfEnabled(ctxt)))
343 ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
344 }
345
346 zerofp := goobj.FingerprintType{}
347 switch ctxt.BuildMode {
348 case BuildModeShared:
349 for i := 0; i < flag.NArg(); i++ {
350 arg := flag.Arg(i)
351 parts := strings.SplitN(arg, "=", 2)
352 var pkgpath, file string
353 if len(parts) == 1 {
354 pkgpath, file = "main", arg
355 } else {
356 pkgpath, file = parts[0], parts[1]
357 }
358 pkglistfornote = append(pkglistfornote, pkgpath...)
359 pkglistfornote = append(pkglistfornote, '\n')
360 addlibpath(ctxt, "command line", "command line", file, pkgpath, "", zerofp)
361 }
362 case BuildModePlugin:
363 addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "", zerofp)
364 default:
365 addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "", zerofp)
366 }
367 bench.Start("loadlib")
368 ctxt.loadlib()
369
370 bench.Start("inittasks")
371 ctxt.inittasks()
372
373 bench.Start("deadcode")
374 deadcode(ctxt)
375
376 bench.Start("linksetup")
377 ctxt.linksetup()
378
379 bench.Start("dostrdata")
380 ctxt.dostrdata()
381 if buildcfg.Experiment.FieldTrack {
382 bench.Start("fieldtrack")
383 fieldtrack(ctxt.Arch, ctxt.loader)
384 }
385
386 bench.Start("dwarfGenerateDebugInfo")
387 dwarfGenerateDebugInfo(ctxt)
388
389 bench.Start("callgraph")
390 ctxt.callgraph()
391
392 bench.Start("doStackCheck")
393 ctxt.doStackCheck()
394
395 bench.Start("mangleTypeSym")
396 ctxt.mangleTypeSym()
397
398 if ctxt.IsELF {
399 bench.Start("doelf")
400 ctxt.doelf()
401 }
402 if ctxt.IsDarwin() {
403 bench.Start("domacho")
404 ctxt.domacho()
405 }
406 if ctxt.IsWindows() {
407 bench.Start("dope")
408 ctxt.dope()
409 bench.Start("windynrelocsyms")
410 ctxt.windynrelocsyms()
411 }
412 if ctxt.IsAIX() {
413 bench.Start("doxcoff")
414 ctxt.doxcoff()
415 }
416
417 bench.Start("textbuildid")
418 ctxt.textbuildid()
419 bench.Start("addexport")
420 ctxt.setArchSyms()
421 ctxt.addexport()
422 bench.Start("Gentext")
423 thearch.Gentext(ctxt, ctxt.loader)
424
425 bench.Start("textaddress")
426 ctxt.textaddress()
427 bench.Start("buildinfo")
428 ctxt.buildinfo()
429 bench.Start("pclntab")
430 containers := ctxt.findContainerSyms()
431 pclnState := ctxt.pclntab(containers)
432 bench.Start("findfunctab")
433 ctxt.findfunctab(pclnState, containers)
434 bench.Start("dwarfGenerateDebugSyms")
435 dwarfGenerateDebugSyms(ctxt)
436 bench.Start("symtab")
437 symGroupType := ctxt.symtab(pclnState)
438 bench.Start("dodata")
439 ctxt.dodata(symGroupType)
440 bench.Start("address")
441 order := ctxt.address()
442 bench.Start("dwarfcompress")
443 dwarfcompress(ctxt)
444 bench.Start("layout")
445 filesize := ctxt.layout(order)
446
447
448
449
450
451
452
453 if ctxt.Arch.Family != sys.Wasm {
454
455
456 if err := ctxt.Out.Mmap(filesize); err != nil {
457 Exitf("mapping output file failed: %v", err)
458 }
459 }
460
461
462 bench.Start("Asmb")
463 asmb(ctxt)
464 exitIfErrors()
465
466
467
468 bench.Start("GenSymsLate")
469 if thearch.GenSymsLate != nil {
470 thearch.GenSymsLate(ctxt, ctxt.loader)
471 }
472
473 asmbfips(ctxt, *flagFipso)
474
475 bench.Start("Asmb2")
476 asmb2(ctxt)
477
478 bench.Start("Munmap")
479 ctxt.Out.Close()
480
481 bench.Start("hostlink")
482 ctxt.hostlink()
483 if ctxt.Debugvlog != 0 {
484 ctxt.Logf("%s", ctxt.loader.Stat())
485 ctxt.Logf("%d liveness data\n", liveness)
486 }
487 bench.Start("Flush")
488 ctxt.Bso.Flush()
489 bench.Start("archive")
490 ctxt.archive()
491 bench.Report(os.Stdout)
492
493 errorexit()
494 }
495
496 type Rpath struct {
497 set bool
498 val string
499 }
500
501 func (r *Rpath) Set(val string) error {
502 r.set = true
503 r.val = val
504 return nil
505 }
506
507 func (r *Rpath) String() string {
508 return r.val
509 }
510
511 func startProfile() {
512 if *cpuprofile != "" {
513 f, err := os.Create(*cpuprofile)
514 if err != nil {
515 log.Fatalf("%v", err)
516 }
517 if err := pprof.StartCPUProfile(f); err != nil {
518 log.Fatalf("%v", err)
519 }
520 AtExit(func() {
521 pprof.StopCPUProfile()
522 if err = f.Close(); err != nil {
523 log.Fatalf("error closing cpu profile: %v", err)
524 }
525 })
526 }
527 if *memprofile != "" {
528 if *memprofilerate != 0 {
529 runtime.MemProfileRate = int(*memprofilerate)
530 }
531 f, err := os.Create(*memprofile)
532 if err != nil {
533 log.Fatalf("%v", err)
534 }
535 AtExit(func() {
536
537 runtime.GC()
538
539
540
541 const writeLegacyFormat = 1
542 if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
543 log.Fatalf("%v", err)
544 }
545
546 if err := f.Close(); err != nil {
547 log.Fatalf("could not close %v: %v", *memprofile, err)
548 }
549 })
550 }
551 }
552
View as plain text