github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/link/internal/ld/main.go (about) 1 // Inferno utils/6l/obj.c 2 // https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 package ld 32 33 import ( 34 "bufio" 35 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 36 "github.com/gagliardetto/golang-go/cmd/internal/sys" 37 "github.com/gagliardetto/golang-go/cmd/link/internal/sym" 38 "flag" 39 "log" 40 "os" 41 "runtime" 42 "runtime/pprof" 43 "strings" 44 ) 45 46 var ( 47 pkglistfornote []byte 48 windowsgui bool // writes a "GUI binary" instead of a "console binary" 49 ownTmpDir bool // set to true if tmp dir created by linker (e.g. no -tmpdir) 50 ) 51 52 func init() { 53 flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...") 54 } 55 56 // Flags used by the linker. The exported flags are used by the architecture-specific packages. 57 var ( 58 flagBuildid = flag.String("buildid", "", "record `id` as Go toolchain build id") 59 60 flagOutfile = flag.String("o", "", "write output to `file`") 61 flagPluginPath = flag.String("pluginpath", "", "full path name for plugin") 62 63 flagInstallSuffix = flag.String("installsuffix", "", "set package directory `suffix`") 64 flagDumpDep = flag.Bool("dumpdep", false, "dump symbol dependency graph") 65 flagRace = flag.Bool("race", false, "enable race detector") 66 flagMsan = flag.Bool("msan", false, "enable MSan interface") 67 68 flagFieldTrack = flag.String("k", "", "set field tracking `symbol`") 69 flagLibGCC = flag.String("libgcc", "", "compiler support lib for internal linking; use \"none\" to disable") 70 flagTmpdir = flag.String("tmpdir", "", "use `directory` for temporary files") 71 72 flagExtld = flag.String("extld", "", "use `linker` when linking in external mode") 73 flagExtldflags = flag.String("extldflags", "", "pass `flags` to external linker") 74 flagExtar = flag.String("extar", "", "archive program for buildmode=c-archive") 75 76 flagA = flag.Bool("a", false, "disassemble output") 77 FlagC = flag.Bool("c", false, "dump call graph") 78 FlagD = flag.Bool("d", false, "disable dynamic executable") 79 flagF = flag.Bool("f", false, "ignore version mismatch") 80 flagG = flag.Bool("g", false, "disable go package data checks") 81 flagH = flag.Bool("h", false, "halt on error") 82 flagN = flag.Bool("n", false, "dump symbol table") 83 FlagS = flag.Bool("s", false, "disable symbol table") 84 flagU = flag.Bool("u", false, "reject unsafe packages") 85 FlagW = flag.Bool("w", false, "disable DWARF generation") 86 Flag8 bool // use 64-bit addresses in symbol table 87 flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker") 88 FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines") 89 FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).") 90 flagNewobj = flag.Bool("newobj", false, "use new object file format") 91 92 FlagRound = flag.Int("R", -1, "set address rounding `quantum`") 93 FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") 94 flagEntrySymbol = flag.String("E", "", "set `entry` symbol name") 95 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 ) 100 101 // Main is the main entry point for the linker code. 102 func Main(arch *sys.Arch, theArch Arch) { 103 thearch = theArch 104 ctxt := linknew(arch) 105 ctxt.Bso = bufio.NewWriter(os.Stdout) 106 107 // For testing behavior of go command when tools crash silently. 108 // Undocumented, not in standard flag parser to avoid 109 // exposing in usage message. 110 for _, arg := range os.Args { 111 if arg == "-crash_for_testing" { 112 os.Exit(2) 113 } 114 } 115 116 final := gorootFinal() 117 addstrdata1(ctxt, "runtime/internal/sys.DefaultGoroot="+final) 118 addstrdata1(ctxt, "github.com/gagliardetto/golang-go/cmd/internal/objabi.defaultGOROOT="+final) 119 120 // TODO(matloob): define these above and then check flag values here 121 if ctxt.Arch.Family == sys.AMD64 && objabi.GOOS == "plan9" { 122 flag.BoolVar(&Flag8, "8", false, "use 64-bit addresses in symbol table") 123 } 124 flagHeadType := flag.String("H", "", "set header `type`") 125 flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries") 126 flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`") 127 flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`") 128 flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible") 129 objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo) 130 objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) }) 131 objabi.AddVersionFlag() // -V 132 objabi.Flagfn1("X", "add string value `definition` of the form importpath.name=value", func(s string) { addstrdata1(ctxt, s) }) 133 objabi.Flagcount("v", "print link trace", &ctxt.Debugvlog) 134 objabi.Flagfn1("importcfg", "read import configuration from `file`", ctxt.readImportCfg) 135 136 objabi.Flagparse(usage) 137 138 switch *flagHeadType { 139 case "": 140 case "windowsgui": 141 ctxt.HeadType = objabi.Hwindows 142 windowsgui = true 143 default: 144 if err := ctxt.HeadType.Set(*flagHeadType); err != nil { 145 Errorf(nil, "%v", err) 146 usage() 147 } 148 } 149 150 if objabi.Fieldtrack_enabled != 0 { 151 ctxt.Reachparent = make(map[*sym.Symbol]*sym.Symbol) 152 } 153 checkStrictDups = *FlagStrictDups 154 155 startProfile() 156 if ctxt.BuildMode == BuildModeUnset { 157 ctxt.BuildMode = BuildModeExe 158 } 159 160 if ctxt.BuildMode != BuildModeShared && flag.NArg() != 1 { 161 usage() 162 } 163 164 if *flagOutfile == "" { 165 *flagOutfile = "a.out" 166 if ctxt.HeadType == objabi.Hwindows { 167 *flagOutfile += ".exe" 168 } 169 } 170 171 interpreter = *flagInterpreter 172 173 libinit(ctxt) // creates outfile 174 175 if ctxt.HeadType == objabi.Hunknown { 176 ctxt.HeadType.Set(objabi.GOOS) 177 } 178 179 ctxt.computeTLSOffset() 180 thearch.Archinit(ctxt) 181 182 if ctxt.linkShared && !ctxt.IsELF { 183 Exitf("-linkshared can only be used on elf systems") 184 } 185 186 if ctxt.Debugvlog != 0 { 187 ctxt.Logf("HEADER = -H%d -T0x%x -R0x%x\n", ctxt.HeadType, uint64(*FlagTextAddr), uint32(*FlagRound)) 188 } 189 190 switch ctxt.BuildMode { 191 case BuildModeShared: 192 for i := 0; i < flag.NArg(); i++ { 193 arg := flag.Arg(i) 194 parts := strings.SplitN(arg, "=", 2) 195 var pkgpath, file string 196 if len(parts) == 1 { 197 pkgpath, file = "main", arg 198 } else { 199 pkgpath, file = parts[0], parts[1] 200 } 201 pkglistfornote = append(pkglistfornote, pkgpath...) 202 pkglistfornote = append(pkglistfornote, '\n') 203 addlibpath(ctxt, "command line", "command line", file, pkgpath, "") 204 } 205 case BuildModePlugin: 206 addlibpath(ctxt, "command line", "command line", flag.Arg(0), *flagPluginPath, "") 207 default: 208 addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "") 209 } 210 ctxt.loadlib() 211 212 deadcode(ctxt) 213 if *flagNewobj { 214 ctxt.loadlibfull() // XXX do it here for now 215 } 216 ctxt.linksetup() 217 ctxt.dostrdata() 218 219 dwarfGenerateDebugInfo(ctxt) 220 if objabi.Fieldtrack_enabled != 0 { 221 fieldtrack(ctxt) 222 } 223 ctxt.mangleTypeSym() 224 ctxt.callgraph() 225 226 ctxt.doelf() 227 if ctxt.HeadType == objabi.Hdarwin { 228 ctxt.domacho() 229 } 230 ctxt.dostkcheck() 231 if ctxt.HeadType == objabi.Hwindows { 232 ctxt.dope() 233 ctxt.windynrelocsyms() 234 } 235 if ctxt.HeadType == objabi.Haix { 236 ctxt.doxcoff() 237 } 238 239 ctxt.addexport() 240 thearch.Gentext(ctxt) // trampolines, call stubs, etc. 241 ctxt.textbuildid() 242 ctxt.textaddress() 243 ctxt.pclntab() 244 ctxt.findfunctab() 245 ctxt.typelink() 246 ctxt.symtab() 247 ctxt.buildinfo() 248 ctxt.dodata() 249 order := ctxt.address() 250 dwarfcompress(ctxt) 251 filesize := ctxt.layout(order) 252 253 // Write out the output file. 254 // It is split into two parts (Asmb and Asmb2). The first 255 // part writes most of the content (sections and segments), 256 // for which we have computed the size and offset, in a 257 // mmap'd region. The second part writes more content, for 258 // which we don't know the size. 259 var outputMmapped bool 260 if ctxt.Arch.Family != sys.Wasm { 261 // Don't mmap if we're building for Wasm. Wasm file 262 // layout is very different so filesize is meaningless. 263 err := ctxt.Out.Mmap(filesize) 264 outputMmapped = err == nil 265 } 266 if outputMmapped { 267 // Asmb will redirect symbols to the output file mmap, and relocations 268 // will be applied directly there. 269 thearch.Asmb(ctxt) 270 ctxt.reloc() 271 ctxt.Out.Munmap() 272 } else { 273 // If we don't mmap, we need to apply relocations before 274 // writing out. 275 ctxt.reloc() 276 thearch.Asmb(ctxt) 277 } 278 thearch.Asmb2(ctxt) 279 280 ctxt.undef() 281 ctxt.hostlink() 282 if ctxt.Debugvlog != 0 { 283 ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym)) 284 ctxt.Logf("%d liveness data\n", liveness) 285 } 286 ctxt.Bso.Flush() 287 ctxt.archive() 288 289 errorexit() 290 } 291 292 type Rpath struct { 293 set bool 294 val string 295 } 296 297 func (r *Rpath) Set(val string) error { 298 r.set = true 299 r.val = val 300 return nil 301 } 302 303 func (r *Rpath) String() string { 304 return r.val 305 } 306 307 func startProfile() { 308 if *cpuprofile != "" { 309 f, err := os.Create(*cpuprofile) 310 if err != nil { 311 log.Fatalf("%v", err) 312 } 313 if err := pprof.StartCPUProfile(f); err != nil { 314 log.Fatalf("%v", err) 315 } 316 AtExit(pprof.StopCPUProfile) 317 } 318 if *memprofile != "" { 319 if *memprofilerate != 0 { 320 runtime.MemProfileRate = int(*memprofilerate) 321 } 322 f, err := os.Create(*memprofile) 323 if err != nil { 324 log.Fatalf("%v", err) 325 } 326 AtExit(func() { 327 // Profile all outstanding allocations. 328 runtime.GC() 329 // compilebench parses the memory profile to extract memstats, 330 // which are only written in the legacy pprof format. 331 // See golang.org/issue/18641 and runtime/pprof/pprof.go:writeHeap. 332 const writeLegacyFormat = 1 333 if err := pprof.Lookup("heap").WriteTo(f, writeLegacyFormat); err != nil { 334 log.Fatalf("%v", err) 335 } 336 }) 337 } 338 }