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