github.com/bir3/gocompiler@v0.3.205/src/cmd/link/internal/ld/config.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ld 6 7 import ( 8 "github.com/bir3/gocompiler/src/cmd/internal/sys" 9 "fmt" 10 "github.com/bir3/gocompiler/src/internal/buildcfg" 11 "github.com/bir3/gocompiler/src/internal/platform" 12 ) 13 14 // A BuildMode indicates the sort of object we are building. 15 // 16 // Possible build modes are the same as those for the -buildmode flag 17 // in cmd/go, and are documented in 'go help buildmode'. 18 type BuildMode uint8 19 20 const ( 21 BuildModeUnset BuildMode = iota 22 BuildModeExe 23 BuildModePIE 24 BuildModeCArchive 25 BuildModeCShared 26 BuildModeShared 27 BuildModePlugin 28 ) 29 30 func (mode *BuildMode) Set(s string) error { 31 badmode := func() error { 32 return fmt.Errorf("buildmode %s not supported on %s/%s", s, buildcfg.GOOS, buildcfg.GOARCH) 33 } 34 switch s { 35 default: 36 return fmt.Errorf("invalid buildmode: %q", s) 37 case "exe": 38 switch buildcfg.GOOS + "/" + buildcfg.GOARCH { 39 case "darwin/arm64", "windows/arm", "windows/arm64": // On these platforms, everything is PIE 40 *mode = BuildModePIE 41 default: 42 *mode = BuildModeExe 43 } 44 case "pie": 45 switch buildcfg.GOOS { 46 case "aix", "android", "linux", "windows", "darwin", "ios": 47 case "freebsd": 48 switch buildcfg.GOARCH { 49 case "amd64": 50 default: 51 return badmode() 52 } 53 default: 54 return badmode() 55 } 56 *mode = BuildModePIE 57 case "c-archive": 58 switch buildcfg.GOOS { 59 case "aix", "darwin", "ios", "linux": 60 case "freebsd": 61 switch buildcfg.GOARCH { 62 case "amd64": 63 default: 64 return badmode() 65 } 66 case "windows": 67 switch buildcfg.GOARCH { 68 case "amd64", "386", "arm", "arm64": 69 default: 70 return badmode() 71 } 72 default: 73 return badmode() 74 } 75 *mode = BuildModeCArchive 76 case "c-shared": 77 switch buildcfg.GOARCH { 78 case "386", "amd64", "arm", "arm64", "ppc64le", "riscv64", "s390x": 79 default: 80 return badmode() 81 } 82 *mode = BuildModeCShared 83 case "shared": 84 switch buildcfg.GOOS { 85 case "linux": 86 switch buildcfg.GOARCH { 87 case "386", "amd64", "arm", "arm64", "ppc64le", "s390x": 88 default: 89 return badmode() 90 } 91 default: 92 return badmode() 93 } 94 *mode = BuildModeShared 95 case "plugin": 96 switch buildcfg.GOOS { 97 case "linux": 98 switch buildcfg.GOARCH { 99 case "386", "amd64", "arm", "arm64", "s390x", "ppc64le": 100 default: 101 return badmode() 102 } 103 case "darwin": 104 switch buildcfg.GOARCH { 105 case "amd64", "arm64": 106 default: 107 return badmode() 108 } 109 case "freebsd": 110 switch buildcfg.GOARCH { 111 case "amd64": 112 default: 113 return badmode() 114 } 115 default: 116 return badmode() 117 } 118 *mode = BuildModePlugin 119 } 120 return nil 121 } 122 123 func (mode *BuildMode) String() string { 124 switch *mode { 125 case BuildModeUnset: 126 return "" // avoid showing a default in usage message 127 case BuildModeExe: 128 return "exe" 129 case BuildModePIE: 130 return "pie" 131 case BuildModeCArchive: 132 return "c-archive" 133 case BuildModeCShared: 134 return "c-shared" 135 case BuildModeShared: 136 return "shared" 137 case BuildModePlugin: 138 return "plugin" 139 } 140 return fmt.Sprintf("BuildMode(%d)", uint8(*mode)) 141 } 142 143 // LinkMode indicates whether an external linker is used for the final link. 144 type LinkMode uint8 145 146 const ( 147 LinkAuto LinkMode = iota 148 LinkInternal 149 LinkExternal 150 ) 151 152 func (mode *LinkMode) Set(s string) error { 153 switch s { 154 default: 155 return fmt.Errorf("invalid linkmode: %q", s) 156 case "auto": 157 *mode = LinkAuto 158 case "internal": 159 *mode = LinkInternal 160 case "external": 161 *mode = LinkExternal 162 } 163 return nil 164 } 165 166 func (mode *LinkMode) String() string { 167 switch *mode { 168 case LinkAuto: 169 return "auto" 170 case LinkInternal: 171 return "internal" 172 case LinkExternal: 173 return "external" 174 } 175 return fmt.Sprintf("LinkMode(%d)", uint8(*mode)) 176 } 177 178 // mustLinkExternal reports whether the program being linked requires 179 // the external linker be used to complete the link. 180 func mustLinkExternal(ctxt *Link) (res bool, reason string) { 181 if ctxt.Debugvlog > 1 { 182 defer func() { 183 if res { 184 ctxt.Logf("external linking is forced by: %s\n", reason) 185 } 186 }() 187 } 188 189 if platform.MustLinkExternal(buildcfg.GOOS, buildcfg.GOARCH) { 190 return true, fmt.Sprintf("%s/%s requires external linking", buildcfg.GOOS, buildcfg.GOARCH) 191 } 192 193 if *flagMsan { 194 return true, "msan" 195 } 196 197 if *flagAsan { 198 return true, "asan" 199 } 200 201 // Internally linking cgo is incomplete on some architectures. 202 // https://golang.org/issue/14449 203 if iscgo && ctxt.Arch.InFamily(sys.Loong64, sys.MIPS64, sys.MIPS, sys.RISCV64) { 204 return true, buildcfg.GOARCH + " does not support internal cgo" 205 } 206 if iscgo && (buildcfg.GOOS == "android" || buildcfg.GOOS == "dragonfly") { 207 // It seems that on Dragonfly thread local storage is 208 // set up by the dynamic linker, so internal cgo linking 209 // doesn't work. Test case is "go test runtime/cgo". 210 return true, buildcfg.GOOS + " does not support internal cgo" 211 } 212 if iscgo && buildcfg.GOOS == "windows" && buildcfg.GOARCH == "arm64" { 213 // windows/arm64 internal linking is not implemented. 214 return true, buildcfg.GOOS + "/" + buildcfg.GOARCH + " does not support internal cgo" 215 } 216 if iscgo && ctxt.Arch == sys.ArchPPC64 { 217 // Big Endian PPC64 cgo internal linking is not implemented for aix or linux. 218 return true, buildcfg.GOOS + " does not support internal cgo" 219 } 220 221 // Some build modes require work the internal linker cannot do (yet). 222 switch ctxt.BuildMode { 223 case BuildModeCArchive: 224 return true, "buildmode=c-archive" 225 case BuildModeCShared: 226 return true, "buildmode=c-shared" 227 case BuildModePIE: 228 switch buildcfg.GOOS + "/" + buildcfg.GOARCH { 229 case "android/arm64": 230 case "linux/amd64", "linux/arm64", "linux/ppc64le": 231 case "windows/386", "windows/amd64", "windows/arm", "windows/arm64": 232 case "darwin/amd64", "darwin/arm64": 233 default: 234 // Internal linking does not support TLS_IE. 235 return true, "buildmode=pie" 236 } 237 case BuildModePlugin: 238 return true, "buildmode=plugin" 239 case BuildModeShared: 240 return true, "buildmode=shared" 241 } 242 if ctxt.linkShared { 243 return true, "dynamically linking with a shared library" 244 } 245 246 if unknownObjFormat { 247 return true, "some input objects have an unrecognized file format" 248 } 249 250 if len(dynimportfail) > 0 { 251 // This error means that we were unable to generate 252 // the _cgo_import.go file for some packages. 253 // This typically means that there are some dependencies 254 // that the cgo tool could not figure out. 255 // See issue #52863. 256 return true, fmt.Sprintf("some packages could not be built to support internal linking (%v)", dynimportfail) 257 } 258 259 return false, "" 260 } 261 262 // determineLinkMode sets ctxt.LinkMode. 263 // 264 // It is called after flags are processed and inputs are processed, 265 // so the ctxt.LinkMode variable has an initial value from the -linkmode 266 // flag and the iscgo, externalobj, and unknownObjFormat variables are set. 267 func determineLinkMode(ctxt *Link) { 268 extNeeded, extReason := mustLinkExternal(ctxt) 269 via := "" 270 271 if ctxt.LinkMode == LinkAuto { 272 // The environment variable GO_EXTLINK_ENABLED controls the 273 // default value of -linkmode. If it is not set when the 274 // linker is called we take the value it was set to when 275 // cmd/link was compiled. (See make.bash.) 276 switch buildcfg.Getgoextlinkenabled() { 277 case "0": 278 ctxt.LinkMode = LinkInternal 279 via = "via GO_EXTLINK_ENABLED " 280 case "1": 281 ctxt.LinkMode = LinkExternal 282 via = "via GO_EXTLINK_ENABLED " 283 default: 284 preferExternal := len(preferlinkext) != 0 285 if preferExternal && ctxt.Debugvlog > 0 { 286 ctxt.Logf("external linking prefer list is %v\n", preferlinkext) 287 } 288 if extNeeded || (iscgo && (externalobj || preferExternal)) { 289 ctxt.LinkMode = LinkExternal 290 } else { 291 ctxt.LinkMode = LinkInternal 292 } 293 } 294 } 295 296 switch ctxt.LinkMode { 297 case LinkInternal: 298 if extNeeded { 299 Exitf("internal linking requested %sbut external linking required: %s", via, extReason) 300 } 301 case LinkExternal: 302 switch { 303 case buildcfg.GOARCH == "ppc64" && buildcfg.GOOS != "aix": 304 Exitf("external linking not supported for %s/ppc64", buildcfg.GOOS) 305 } 306 } 307 }