github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/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 "cmd/internal/objabi" 9 "cmd/internal/sys" 10 "fmt" 11 "log" 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, objabi.GOOS, objabi.GOARCH) 33 } 34 switch s { 35 default: 36 return fmt.Errorf("invalid buildmode: %q", s) 37 case "exe": 38 *mode = BuildModeExe 39 case "pie": 40 switch objabi.GOOS { 41 case "android", "linux": 42 case "darwin": 43 switch objabi.GOARCH { 44 case "amd64": 45 default: 46 return badmode() 47 } 48 default: 49 return badmode() 50 } 51 *mode = BuildModePIE 52 case "c-archive": 53 switch objabi.GOOS { 54 case "darwin", "linux": 55 case "windows": 56 switch objabi.GOARCH { 57 case "amd64", "386": 58 default: 59 return badmode() 60 } 61 default: 62 return badmode() 63 } 64 *mode = BuildModeCArchive 65 case "c-shared": 66 switch objabi.GOARCH { 67 case "386", "amd64", "arm", "arm64", "ppc64le", "s390x": 68 default: 69 return badmode() 70 } 71 *mode = BuildModeCShared 72 case "shared": 73 switch objabi.GOOS { 74 case "linux": 75 switch objabi.GOARCH { 76 case "386", "amd64", "arm", "arm64", "ppc64le", "s390x": 77 default: 78 return badmode() 79 } 80 default: 81 return badmode() 82 } 83 *mode = BuildModeShared 84 case "plugin": 85 switch objabi.GOOS { 86 case "linux": 87 switch objabi.GOARCH { 88 case "386", "amd64", "arm", "arm64", "s390x", "ppc64le": 89 default: 90 return badmode() 91 } 92 case "darwin": 93 switch objabi.GOARCH { 94 case "amd64": 95 default: 96 return badmode() 97 } 98 default: 99 return badmode() 100 } 101 *mode = BuildModePlugin 102 } 103 return nil 104 } 105 106 func (mode *BuildMode) String() string { 107 switch *mode { 108 case BuildModeUnset: 109 return "" // avoid showing a default in usage message 110 case BuildModeExe: 111 return "exe" 112 case BuildModePIE: 113 return "pie" 114 case BuildModeCArchive: 115 return "c-archive" 116 case BuildModeCShared: 117 return "c-shared" 118 case BuildModeShared: 119 return "shared" 120 case BuildModePlugin: 121 return "plugin" 122 } 123 return fmt.Sprintf("BuildMode(%d)", uint8(*mode)) 124 } 125 126 // LinkMode indicates whether an external linker is used for the final link. 127 type LinkMode uint8 128 129 const ( 130 LinkAuto LinkMode = iota 131 LinkInternal 132 LinkExternal 133 ) 134 135 func (mode *LinkMode) Set(s string) error { 136 switch s { 137 default: 138 return fmt.Errorf("invalid linkmode: %q", s) 139 case "auto": 140 *mode = LinkAuto 141 case "internal": 142 *mode = LinkInternal 143 case "external": 144 *mode = LinkExternal 145 } 146 return nil 147 } 148 149 func (mode *LinkMode) String() string { 150 switch *mode { 151 case LinkAuto: 152 return "auto" 153 case LinkInternal: 154 return "internal" 155 case LinkExternal: 156 return "external" 157 } 158 return fmt.Sprintf("LinkMode(%d)", uint8(*mode)) 159 } 160 161 // mustLinkExternal reports whether the program being linked requires 162 // the external linker be used to complete the link. 163 func mustLinkExternal(ctxt *Link) (res bool, reason string) { 164 if ctxt.Debugvlog > 1 { 165 defer func() { 166 if res { 167 log.Printf("external linking is forced by: %s\n", reason) 168 } 169 }() 170 } 171 172 switch objabi.GOOS { 173 case "android": 174 return true, "android" 175 case "darwin": 176 if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) { 177 return true, "iOS" 178 } 179 } 180 181 if *flagMsan { 182 return true, "msan" 183 } 184 185 // Internally linking cgo is incomplete on some architectures. 186 // https://golang.org/issue/10373 187 // https://golang.org/issue/14449 188 // https://golang.org/issue/21961 189 if iscgo && ctxt.Arch.InFamily(sys.ARM64, sys.MIPS64, sys.MIPS, sys.PPC64) { 190 return true, objabi.GOARCH + " does not support internal cgo" 191 } 192 193 // Some build modes require work the internal linker cannot do (yet). 194 switch ctxt.BuildMode { 195 case BuildModeCArchive: 196 return true, "buildmode=c-archive" 197 case BuildModeCShared: 198 return true, "buildmode=c-shared" 199 case BuildModePIE: 200 switch objabi.GOOS + "/" + objabi.GOARCH { 201 case "linux/amd64": 202 default: 203 // Internal linking does not support TLS_IE. 204 return true, "buildmode=pie" 205 } 206 case BuildModePlugin: 207 return true, "buildmode=plugin" 208 case BuildModeShared: 209 return true, "buildmode=shared" 210 } 211 if ctxt.linkShared { 212 return true, "dynamically linking with a shared library" 213 } 214 215 return false, "" 216 } 217 218 // determineLinkMode sets ctxt.LinkMode. 219 // 220 // It is called after flags are processed and inputs are processed, 221 // so the ctxt.LinkMode variable has an initial value from the -linkmode 222 // flag and the iscgo externalobj variables are set. 223 func determineLinkMode(ctxt *Link) { 224 switch ctxt.LinkMode { 225 case LinkAuto: 226 // The environment variable GO_EXTLINK_ENABLED controls the 227 // default value of -linkmode. If it is not set when the 228 // linker is called we take the value it was set to when 229 // cmd/link was compiled. (See make.bash.) 230 switch objabi.Getgoextlinkenabled() { 231 case "0": 232 if needed, reason := mustLinkExternal(ctxt); needed { 233 Exitf("internal linking requested via GO_EXTLINK_ENABLED, but external linking required: %s", reason) 234 } 235 ctxt.LinkMode = LinkInternal 236 case "1": 237 ctxt.LinkMode = LinkExternal 238 default: 239 if needed, _ := mustLinkExternal(ctxt); needed { 240 ctxt.LinkMode = LinkExternal 241 } else if iscgo && externalobj { 242 ctxt.LinkMode = LinkExternal 243 } else if ctxt.BuildMode == BuildModePIE { 244 ctxt.LinkMode = LinkExternal // https://golang.org/issue/18968 245 } else { 246 ctxt.LinkMode = LinkInternal 247 } 248 } 249 case LinkInternal: 250 if needed, reason := mustLinkExternal(ctxt); needed { 251 Exitf("internal linking requested but external linking required: %s", reason) 252 } 253 } 254 }