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/sys"
38 "cmd/link/internal/benchmark"
39 "flag"
40 "internal/buildcfg"
41 "log"
42 "os"
43 "runtime"
44 "runtime/pprof"
45 "strings"
46 )
47
48 var (
49 pkglistfornote []byte
50 windowsgui bool
51 ownTmpDir bool
52 )
53
54 func init() {
55 flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
56 }
57
58
59 var (
60 flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id")
61
62 flagOutfile = flag.String("o", "", "write output to `file`")
63 flagPluginPath = flag.String("pluginpath", "", "full path name for plugin")
64
65 flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`")
66 flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph")
67 flagRace = flag.Bool("race", false, "enable race detector")
68 flagMsan = flag.Bool("msan", false, "enable MSan interface")
69 flagAslr = flag.Bool("aslr", true, "enable ASLR for buildmode=c-shared on windows")
70
71 flagFieldTrack = flag.String("k", "", "set field tracking `symbol`")
72 flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable")
73 flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files")
74
75 flagExtld = flag.String("extld", "", "use `linker` when linking in external mode")
76 flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker")
77 flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive")
78
79 flagA = flag.Bool("a", false, "no-op (deprecated)")
80 FlagC = flag.Bool("c", false, "dump call graph")
81 FlagD = flag.Bool("d", false, "disable dynamic executable")
82 flagF = flag.Bool("f", false, "ignore version mismatch")
83 flagG = flag.Bool("g", false, "disable go package data checks")
84 flagH = flag.Bool("h", false, "halt on error")
85 flagN = flag.Bool("n", false, "dump symbol table")
86 FlagS = flag.Bool("s", false, "disable symbol table")
87 FlagW = flag.Bool("w", false, "disable DWARF generation")
88 flag8 bool
89 flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker")
90 FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines")
91 FlagDebugTextSize = flag.Int("debugtextsize", 0, "debug text section max size")
92 FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).")
93 FlagRound = flag.Int("R", -1, "set address rounding `quantum`")
94 FlagTextAddr = flag.Int64("T", -1, "set text segment `address`")
95 flagEntrySymbol = flag.String("E", "", "set `entry` symbol name")
96 cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`")
97 memprofile = flag.String("memprofile", "", "write memory profile to `file`")
98 memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`")
99 benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking")
100 benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof")
101 )
102
103
104 func Main(arch *sys.Arch, theArch Arch) {
105 thearch = theArch
106 ctxt := linknew(arch)
107 ctxt.Bso = bufio.NewWriter(os.Stdout)
108
109
110
111
112 for _, arg := range os.Args {
113 if arg == "-crash_for_testing" {
114 os.Exit(2)
115 }
116 }
117
118 final := gorootFinal()
119 addstrdata1(ctxt, "runtime.defaultGOROOT="+final)
120 addstrdata1(ctxt, "internal/buildcfg.defaultGOROOT="+final)
121
122 buildVersion := buildcfg.Version
123 if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" {
124 buildVersion += " X:" + goexperiment
125 }
126 addstrdata1(ctxt, "runtime.buildVersion="+buildVersion)
127
128
129 if ctxt.Arch.Family == sys.AMD64 && buildcfg.GOOS == "plan9" {
130 flag.BoolVar(&flag8, "8", false, "use 64-bit addresses in symbol table")
131 }
132 flagHeadType := flag.String("H", "", "set header `type`")
133 flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries")
134 flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
135 flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
136 flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
137 objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
138 objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
139 objabi.AddVersionFlag()
140 objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) })
141 objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog)
142 objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg)
143
144 objabi.Flagparse(usage)
145
146 if ctxt.Debugvlog > 0 {
147
148 defer func() { ctxt.loader.Dump() }()
149 }
150
151 switch *flagHeadType {
152 case "":
153 case "windowsgui":
154 ctxt.HeadType = objabi.Hwindows
155 windowsgui = true
156 default:
157 if err := ctxt.HeadType.Set(*flagHeadType); err != nil {
158 Errorf(nil, "%v", err)
159 usage()
160 }
161 }
162 if ctxt.HeadType == objabi.Hunknown {
163 ctxt.HeadType.Set(buildcfg.GOOS)
164 }
165
166 if !*flagAslr && ctxt.BuildMode != BuildModeCShared {
167 Errorf(nil, "-aslr=false is only allowed for -buildmode=c-shared")
168 usage()
169 }
170
171 checkStrictDups = *FlagStrictDups
172
173 startProfile()
174 if ctxt.BuildMode == BuildModeUnset {
175 ctxt.BuildMode.Set("exe")
176 }
177
178 if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 {
179 usage()
180 }
181
182 if *flagOutfile == "" {
183 *flagOutfile = "a.out"
184 if ctxt.HeadType == objabi.Hwindows {
185 *flagOutfile += ".exe"
186 }
187 }
188
189 interpreter = *flagInterpreter
190
191 if *flagBuildid == "" && ctxt.Target.IsOpenbsd() {
192
193
194
195
196 *flagBuildid = "go-openbsd"
197 }
198
199
200 var bench *benchmark.Metrics
201 if len(*benchmarkFlag) != 0 {
202 if *benchmarkFlag == "mem" {
203 bench = benchmark.New(benchmark.GC, *benchmarkFileFlag)
204 } else if *benchmarkFlag == "cpu" {
205 bench = benchmark.New(benchmark.NoGC, *benchmarkFileFlag)
206 } else {
207 Errorf(nil, "unknown benchmark flag: %q", *benchmarkFlag)
208 usage()
209 }
210 }
211
212 bench.Start("libinit")
213 libinit(ctxt)
214 bench.Start("computeTLSOffset")
215 ctxt.computeTLSOffset()
216 bench.Start("Archinit")
217 thearch.Archinit(ctxt)
218
219 if ctxt.linkShared && !ctxt.IsELF {
220 Exitf("-linkshared can only be used on elf systems")
221 }
222
223 if ctxt.Debugvlog != 0 {
224 ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound))
225 }
226
227 zerofp := goobj.FingerprintType{}
228 switch ctxt.BuildMode {
229 case BuildModeShared:
230 for i := 0; i < flag.NArg(); i++ {
231 arg := flag.Arg(i)
232 parts := strings.SplitN(arg, "=", 2)
233 var pkgpath, file string
234 if len(parts) == 1 {
235 pkgpath, file = "main", arg
236 } else {
237 pkgpath, file = parts[0], parts[1]
238 }
239 pkglistfornote = append(pkglistfornote, pkgpath...)
240 pkglistfornote = append(pkglistfornote, '\n')
241 addlibpath(ctxt, "command line", "command line", file, pkgpath, "", zerofp)
242 }
243 case BuildModePlugin:
244 addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "", zerofp)
245 default:
246 addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "", zerofp)
247 }
248 bench.Start("loadlib")
249 ctxt.loadlib()
250
251 bench.Start("deadcode")
252 deadcode(ctxt)
253
254 bench.Start("linksetup")
255 ctxt.linksetup()
256
257 bench.Start("dostrdata")
258 ctxt.dostrdata()
259 if buildcfg.Experiment.FieldTrack {
260 bench.Start("fieldtrack")
261 fieldtrack(ctxt.Arch, ctxt.loader)
262 }
263
264 bench.Start("dwarfGenerateDebugInfo")
265 dwarfGenerateDebugInfo(ctxt)
266
267 bench.Start("callgraph")
268 ctxt.callgraph()
269
270 bench.Start("dostkcheck")
271 ctxt.dostkcheck()
272
273 bench.Start("mangleTypeSym")
274 ctxt.mangleTypeSym()
275
276 if ctxt.IsELF {
277 bench.Start("doelf")
278 ctxt.doelf()
279 }
280 if ctxt.IsDarwin() {
281 bench.Start("domacho")
282 ctxt.domacho()
283 }
284 if ctxt.IsWindows() {
285 bench.Start("dope")
286 ctxt.dope()
287 bench.Start("windynrelocsyms")
288 ctxt.windynrelocsyms()
289 }
290 if ctxt.IsAIX() {
291 bench.Start("doxcoff")
292 ctxt.doxcoff()
293 }
294
295 bench.Start("textbuildid")
296 ctxt.textbuildid()
297 bench.Start("addexport")
298 ctxt.setArchSyms()
299 ctxt.addexport()
300 bench.Start("Gentext")
301 thearch.Gentext(ctxt, ctxt.loader)
302
303 bench.Start("textaddress")
304 ctxt.textaddress()
305 bench.Start("typelink")
306 ctxt.typelink()
307 bench.Start("buildinfo")
308 ctxt.buildinfo()
309 bench.Start("pclntab")
310 containers := ctxt.findContainerSyms()
311 pclnState := ctxt.pclntab(containers)
312 bench.Start("findfunctab")
313 ctxt.findfunctab(pclnState, containers)
314 bench.Start("dwarfGenerateDebugSyms")
315 dwarfGenerateDebugSyms(ctxt)
316 bench.Start("symtab")
317 symGroupType := ctxt.symtab(pclnState)
318 bench.Start("dodata")
319 ctxt.dodata(symGroupType)
320 bench.Start("address")
321 order := ctxt.address()
322 bench.Start("dwarfcompress")
323 dwarfcompress(ctxt)
324 bench.Start("layout")
325 filesize := ctxt.layout(order)
326
327
328
329
330
331
332
333 if ctxt.Arch.Family != sys.Wasm {
334
335
336 if err := ctxt.Out.Mmap(filesize); err != nil {
337 Exitf("mapping output file failed: %v", err)
338 }
339 }
340
341
342 bench.Start("Asmb")
343 asmb(ctxt)
344
345 exitIfErrors()
346
347
348
349 bench.Start("GenSymsLate")
350 if thearch.GenSymsLate != nil {
351 thearch.GenSymsLate(ctxt, ctxt.loader)
352 }
353
354 bench.Start("Asmb2")
355 asmb2(ctxt)
356
357 bench.Start("Munmap")
358 ctxt.Out.Close()
359
360 bench.Start("hostlink")
361 ctxt.hostlink()
362 if ctxt.Debugvlog != 0 {
363 ctxt.Logf("%s", ctxt.loader.Stat())
364 ctxt.Logf("%d liveness data\n", liveness)
365 }
366 bench.Start("Flush")
367 ctxt.Bso.Flush()
368 bench.Start("archive")
369 ctxt.archive()
370 bench.Report(os.Stdout)
371
372 errorexit()
373 }
374
375 type Rpath struct {
376 set bool
377 val string
378 }
379
380 func (r *Rpath) Set(val string) error {
381 r.set = true
382 r.val = val
383 return nil
384 }
385
386 func (r *Rpath) String() string {
387 return r.val
388 }
389
390 func startProfile() {
391 if *cpuprofile != "" {
392 f, err := os.Create(*cpuprofile)
393 if err != nil {
394 log.Fatalf("%v", err)
395 }
396 if err := pprof.StartCPUProfile(f); err != nil {
397 log.Fatalf("%v", err)
398 }
399 AtExit(pprof.StopCPUProfile)
400 }
401 if *memprofile != "" {
402 if *memprofilerate != 0 {
403 runtime.MemProfileRate = int(*memprofilerate)
404 }
405 f, err := os.Create(*memprofile)
406 if err != nil {
407 log.Fatalf("%v", err)
408 }
409 AtExit(func() {
410
411 runtime.GC()
412
413
414
415 const writeLegacyFormat = 1
416 if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil {
417 log.Fatalf("%v", err)
418 }
419 })
420 }
421 }
422
View as plain text