1
2
3
4
5 package ssagen
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "io/ioutil"
11 "log"
12 "os"
13 "strings"
14
15 "cmd/compile/internal/base"
16 "cmd/compile/internal/ir"
17 "cmd/compile/internal/staticdata"
18 "cmd/compile/internal/typecheck"
19 "cmd/compile/internal/types"
20 "cmd/internal/obj"
21 "cmd/internal/objabi"
22 )
23
24
25
26 type SymABIs struct {
27 defs map[string]obj.ABI
28 refs map[string]obj.ABISet
29
30 localPrefix string
31 }
32
33 func NewSymABIs(myimportpath string) *SymABIs {
34 var localPrefix string
35 if myimportpath != "" {
36 localPrefix = objabi.PathToPrefix(myimportpath) + "."
37 }
38
39 return &SymABIs{
40 defs: make(map[string]obj.ABI),
41 refs: make(map[string]obj.ABISet),
42 localPrefix: localPrefix,
43 }
44 }
45
46
47
48
49
50 func (s *SymABIs) canonicalize(linksym string) string {
51
52
53
54 if s.localPrefix != "" && strings.HasPrefix(linksym, s.localPrefix) {
55 return `"".` + linksym[len(s.localPrefix):]
56 }
57 return linksym
58 }
59
60
61
62
63
64
65
66
67
68
69 func (s *SymABIs) ReadSymABIs(file string) {
70 data, err := ioutil.ReadFile(file)
71 if err != nil {
72 log.Fatalf("-symabis: %v", err)
73 }
74
75 for lineNum, line := range strings.Split(string(data), "\n") {
76 lineNum++
77 line = strings.TrimSpace(line)
78 if line == "" || strings.HasPrefix(line, "#") {
79 continue
80 }
81
82 parts := strings.Fields(line)
83 switch parts[0] {
84 case "def", "ref":
85
86 if len(parts) != 3 {
87 log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
88 }
89 sym, abistr := parts[1], parts[2]
90 abi, valid := obj.ParseABI(abistr)
91 if !valid {
92 log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
93 }
94
95 sym = s.canonicalize(sym)
96
97
98 if parts[0] == "def" {
99 s.defs[sym] = abi
100 } else {
101 s.refs[sym] |= obj.ABISetOf(abi)
102 }
103 default:
104 log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
105 }
106 }
107 }
108
109
110
111 func (s *SymABIs) GenABIWrappers() {
112
113
114
115
116
117
118
119 cgoExports := make(map[string][]*[]string)
120 for i, prag := range typecheck.Target.CgoPragmas {
121 switch prag[0] {
122 case "cgo_export_static", "cgo_export_dynamic":
123 symName := s.canonicalize(prag[1])
124 pprag := &typecheck.Target.CgoPragmas[i]
125 cgoExports[symName] = append(cgoExports[symName], pprag)
126 }
127 }
128
129
130
131
132
133
134 for _, fn := range typecheck.Target.Decls {
135 if fn.Op() != ir.ODCLFUNC {
136 continue
137 }
138 fn := fn.(*ir.Func)
139 nam := fn.Nname
140 if ir.IsBlank(nam) {
141 continue
142 }
143 sym := nam.Sym()
144 var symName string
145 if sym.Linkname != "" {
146 symName = s.canonicalize(sym.Linkname)
147 } else {
148
149 symName = sym.Pkg.Prefix + "." + sym.Name
150 }
151
152
153 defABI, hasDefABI := s.defs[symName]
154 if hasDefABI {
155 if len(fn.Body) != 0 {
156 base.ErrorfAt(fn.Pos(), "%v defined in both Go and assembly", fn)
157 }
158 fn.ABI = defABI
159 }
160
161 if fn.Pragma&ir.CgoUnsafeArgs != 0 {
162
163
164
165 fn.ABI = obj.ABI0
166 }
167
168
169
170 cgoExport := cgoExports[symName]
171 for _, pprag := range cgoExport {
172
173
174
175
176
177
178
179
180
181
182 if len(*pprag) == 2 {
183 *pprag = append(*pprag, (*pprag)[1])
184 }
185
186 *pprag = append(*pprag, fn.ABI.String())
187 }
188
189
190 if abis, ok := s.refs[symName]; ok {
191 fn.ABIRefs |= abis
192 }
193
194
195
196 fn.ABIRefs.Set(obj.ABIInternal, true)
197
198
199
200
201
202
203
204
205
206
207
208
209 hasBody := len(fn.Body) != 0
210 if sym.Linkname != "" && (hasBody || hasDefABI) && len(cgoExport) == 0 {
211 fn.ABIRefs |= obj.ABISetCallable
212 }
213
214
215
216 if len(cgoExport) > 0 && fn.ABIRefs&^obj.ABISetOf(fn.ABI) != 0 {
217 base.Fatalf("cgo exported function %s cannot have ABI wrappers", fn)
218 }
219
220 if !buildcfg.Experiment.RegabiWrappers {
221 continue
222 }
223
224 forEachWrapperABI(fn, makeABIWrapper)
225 }
226 }
227
228
229
230
231
232
233
234
235
236 func InitLSym(f *ir.Func, hasBody bool) {
237 if f.LSym != nil {
238 base.FatalfAt(f.Pos(), "InitLSym called twice on %v", f)
239 }
240
241 if nam := f.Nname; !ir.IsBlank(nam) {
242 f.LSym = nam.LinksymABI(f.ABI)
243 if f.Pragma&ir.Systemstack != 0 {
244 f.LSym.Set(obj.AttrCFunc, true)
245 }
246 if f.ABI == obj.ABIInternal || !buildcfg.Experiment.RegabiWrappers {
247
248
249
250
251
252
253
254
255 staticdata.NeedFuncSym(f)
256 }
257 }
258 if hasBody {
259 setupTextLSym(f, 0)
260 }
261 }
262
263 func forEachWrapperABI(fn *ir.Func, cb func(fn *ir.Func, wrapperABI obj.ABI)) {
264 need := fn.ABIRefs &^ obj.ABISetOf(fn.ABI)
265 if need == 0 {
266 return
267 }
268
269 for wrapperABI := obj.ABI(0); wrapperABI < obj.ABICount; wrapperABI++ {
270 if !need.Get(wrapperABI) {
271 continue
272 }
273 cb(fn, wrapperABI)
274 }
275 }
276
277
278
279 func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
280 if base.Debug.ABIWrap != 0 {
281 fmt.Fprintf(os.Stderr, "=-= %v to %v wrapper for %v\n", wrapperABI, f.ABI, f)
282 }
283
284
285 savepos := base.Pos
286 savedclcontext := typecheck.DeclContext
287 savedcurfn := ir.CurFunc
288
289 base.Pos = base.AutogeneratedPos
290 typecheck.DeclContext = ir.PEXTERN
291
292
293
294 ft := f.Nname.Type()
295 if ft.NumRecvs() != 0 {
296 panic("makeABIWrapper support for wrapping methods not implemented")
297 }
298
299
300 var noReceiver *ir.Field
301 tfn := ir.NewFuncType(base.Pos,
302 noReceiver,
303 typecheck.NewFuncParams(ft.Params(), true),
304 typecheck.NewFuncParams(ft.Results(), false))
305
306
307 fn := typecheck.DeclFunc(f.Nname.Sym(), tfn)
308 fn.ABI = wrapperABI
309
310 fn.SetABIWrapper(true)
311 fn.SetDupok(true)
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338 fn.Pragma |= ir.Nosplit
339
340
341
342
343
344
345
346
347
348
349 tailcall := tfn.Type().NumResults() == 0 && tfn.Type().NumParams() == 0 && tfn.Type().NumRecvs() == 0
350 if base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink {
351
352
353 tailcall = false
354 }
355 if base.Ctxt.Arch.Name == "amd64" && wrapperABI == obj.ABIInternal {
356
357
358 tailcall = false
359 }
360
361 var tail ir.Node
362 call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
363 call.Args = ir.ParamNames(tfn.Type())
364 call.IsDDD = tfn.Type().IsVariadic()
365 tail = call
366 if tailcall {
367 tail = ir.NewTailCallStmt(base.Pos, call)
368 } else if tfn.Type().NumResults() > 0 {
369 n := ir.NewReturnStmt(base.Pos, nil)
370 n.Results = []ir.Node{call}
371 tail = n
372 }
373 fn.Body.Append(tail)
374
375 typecheck.FinishFuncBody()
376 if base.Debug.DclStack != 0 {
377 types.CheckDclstack()
378 }
379
380 typecheck.Func(fn)
381 ir.CurFunc = fn
382 typecheck.Stmts(fn.Body)
383
384 typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
385
386
387 base.Pos = savepos
388 typecheck.DeclContext = savedclcontext
389 ir.CurFunc = savedcurfn
390 }
391
392
393 func setupTextLSym(f *ir.Func, flag int) {
394 if f.Dupok() {
395 flag |= obj.DUPOK
396 }
397 if f.Wrapper() {
398 flag |= obj.WRAPPER
399 }
400 if f.ABIWrapper() {
401 flag |= obj.ABIWRAPPER
402 }
403 if f.Needctxt() {
404 flag |= obj.NEEDCTXT
405 }
406 if f.Pragma&ir.Nosplit != 0 {
407 flag |= obj.NOSPLIT
408 }
409 if f.ReflectMethod() {
410 flag |= obj.REFLECTMETHOD
411 }
412
413
414
415
416
417
418
419
420
421
422
423 fnname := f.Sym().Name
424 if base.Ctxt.Pkgpath == "runtime" && fnname == "reflectcall" {
425 flag |= obj.WRAPPER
426 } else if base.Ctxt.Pkgpath == "reflect" {
427 switch fnname {
428 case "callReflect", "callMethod":
429 flag |= obj.WRAPPER
430 }
431 }
432
433 base.Ctxt.InitTextSym(f.LSym, flag)
434 }
435
View as plain text