1
2
3
4
5 package ld
6
7 import (
8 "cmd/internal/objabi"
9 "cmd/internal/sys"
10 "fmt"
11 "log"
12 )
13
14
15
16
17
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 switch objabi.GOOS + "/" + objabi.GOARCH {
39 case "darwin/arm64", "windows/arm":
40 *mode = BuildModePIE
41 default:
42 *mode = BuildModeExe
43 }
44 case "pie":
45 switch objabi.GOOS {
46 case "aix", "android", "linux", "windows", "darwin", "ios":
47 case "freebsd":
48 switch objabi.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 objabi.GOOS {
59 case "aix", "darwin", "ios", "linux":
60 case "freebsd":
61 switch objabi.GOARCH {
62 case "amd64":
63 default:
64 return badmode()
65 }
66 case "windows":
67 switch objabi.GOARCH {
68 case "amd64", "386", "arm":
69 default:
70 return badmode()
71 }
72 default:
73 return badmode()
74 }
75 *mode = BuildModeCArchive
76 case "c-shared":
77 switch objabi.GOARCH {
78 case "386", "amd64", "arm", "arm64", "ppc64le", "s390x":
79 default:
80 return badmode()
81 }
82 *mode = BuildModeCShared
83 case "shared":
84 switch objabi.GOOS {
85 case "linux":
86 switch objabi.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 objabi.GOOS {
97 case "linux":
98 switch objabi.GOARCH {
99 case "386", "amd64", "arm", "arm64", "s390x", "ppc64le":
100 default:
101 return badmode()
102 }
103 case "darwin":
104 switch objabi.GOARCH {
105 case "amd64", "arm64":
106 default:
107 return badmode()
108 }
109 case "freebsd":
110 switch objabi.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 ""
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
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
179
180 func mustLinkExternal(ctxt *Link) (res bool, reason string) {
181 if ctxt.Debugvlog > 1 {
182 defer func() {
183 if res {
184 log.Printf("external linking is forced by: %s\n", reason)
185 }
186 }()
187 }
188
189 if sys.MustLinkExternal(objabi.GOOS, objabi.GOARCH) {
190 return true, fmt.Sprintf("%s/%s requires external linking", objabi.GOOS, objabi.GOARCH)
191 }
192
193 if *flagMsan {
194 return true, "msan"
195 }
196
197
198
199
200 if iscgo && ctxt.Arch.InFamily(sys.MIPS64, sys.MIPS, sys.PPC64, sys.RISCV64) {
201 return true, objabi.GOARCH + " does not support internal cgo"
202 }
203 if iscgo && objabi.GOOS == "android" {
204 return true, objabi.GOOS + " does not support internal cgo"
205 }
206
207
208
209
210 if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
211 return true, "race on " + objabi.GOARCH
212 }
213
214
215 switch ctxt.BuildMode {
216 case BuildModeCArchive:
217 return true, "buildmode=c-archive"
218 case BuildModeCShared:
219 return true, "buildmode=c-shared"
220 case BuildModePIE:
221 switch objabi.GOOS + "/" + objabi.GOARCH {
222 case "linux/amd64", "linux/arm64", "android/arm64":
223 case "windows/386", "windows/amd64", "windows/arm":
224 case "darwin/amd64", "darwin/arm64":
225 default:
226
227 return true, "buildmode=pie"
228 }
229 case BuildModePlugin:
230 return true, "buildmode=plugin"
231 case BuildModeShared:
232 return true, "buildmode=shared"
233 }
234 if ctxt.linkShared {
235 return true, "dynamically linking with a shared library"
236 }
237
238 return false, ""
239 }
240
241
242
243
244
245
246 func determineLinkMode(ctxt *Link) {
247 extNeeded, extReason := mustLinkExternal(ctxt)
248 via := ""
249
250 if ctxt.LinkMode == LinkAuto {
251
252
253
254
255 switch objabi.Getgoextlinkenabled() {
256 case "0":
257 ctxt.LinkMode = LinkInternal
258 via = "via GO_EXTLINK_ENABLED "
259 case "1":
260 ctxt.LinkMode = LinkExternal
261 via = "via GO_EXTLINK_ENABLED "
262 default:
263 if extNeeded || (iscgo && externalobj) {
264 ctxt.LinkMode = LinkExternal
265 } else {
266 ctxt.LinkMode = LinkInternal
267 }
268 }
269 }
270
271 switch ctxt.LinkMode {
272 case LinkInternal:
273 if extNeeded {
274 Exitf("internal linking requested %sbut external linking required: %s", via, extReason)
275 }
276 case LinkExternal:
277 switch {
278 case objabi.GOARCH == "ppc64" && objabi.GOOS != "aix":
279 Exitf("external linking not supported for %s/ppc64", objabi.GOOS)
280 }
281 }
282 }
283
View as plain text