"Fossies" - the Fresh Open Source Software Archive 
Member "go/src/cmd/compile/internal/ssagen/abi.go" (26 Apr 2023, 10823 Bytes) of package /linux/misc/go1.20.4.src.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Go source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the last
Fossies "Diffs" side-by-side code changes report for "abi.go":
1.19.3_vs_1.20rc1.
1 // Copyright 2009 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 ssagen
6
7 import (
8 "fmt"
9 "internal/buildcfg"
10 "log"
11 "os"
12 "strings"
13
14 "cmd/compile/internal/base"
15 "cmd/compile/internal/ir"
16 "cmd/compile/internal/typecheck"
17 "cmd/compile/internal/types"
18 "cmd/internal/obj"
19 )
20
21 // SymABIs records information provided by the assembler about symbol
22 // definition ABIs and reference ABIs.
23 type SymABIs struct {
24 defs map[string]obj.ABI
25 refs map[string]obj.ABISet
26 }
27
28 func NewSymABIs() *SymABIs {
29 return &SymABIs{
30 defs: make(map[string]obj.ABI),
31 refs: make(map[string]obj.ABISet),
32 }
33 }
34
35 // canonicalize returns the canonical name used for a linker symbol in
36 // s's maps. Symbols in this package may be written either as "".X or
37 // with the package's import path already in the symbol. This rewrites
38 // both to use the full path, which matches compiler-generated linker
39 // symbol names.
40 func (s *SymABIs) canonicalize(linksym string) string {
41 // If the symbol is already prefixed with "", rewrite it to start
42 // with LocalPkg.Prefix.
43 //
44 // TODO(mdempsky): Have cmd/asm stop writing out symbols like this.
45 if strings.HasPrefix(linksym, `"".`) {
46 return types.LocalPkg.Prefix + linksym[2:]
47 }
48 return linksym
49 }
50
51 // ReadSymABIs reads a symabis file that specifies definitions and
52 // references of text symbols by ABI.
53 //
54 // The symabis format is a set of lines, where each line is a sequence
55 // of whitespace-separated fields. The first field is a verb and is
56 // either "def" for defining a symbol ABI or "ref" for referencing a
57 // symbol using an ABI. For both "def" and "ref", the second field is
58 // the symbol name and the third field is the ABI name, as one of the
59 // named cmd/internal/obj.ABI constants.
60 func (s *SymABIs) ReadSymABIs(file string) {
61 data, err := os.ReadFile(file)
62 if err != nil {
63 log.Fatalf("-symabis: %v", err)
64 }
65
66 for lineNum, line := range strings.Split(string(data), "\n") {
67 lineNum++ // 1-based
68 line = strings.TrimSpace(line)
69 if line == "" || strings.HasPrefix(line, "#") {
70 continue
71 }
72
73 parts := strings.Fields(line)
74 switch parts[0] {
75 case "def", "ref":
76 // Parse line.
77 if len(parts) != 3 {
78 log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
79 }
80 sym, abistr := parts[1], parts[2]
81 abi, valid := obj.ParseABI(abistr)
82 if !valid {
83 log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
84 }
85
86 sym = s.canonicalize(sym)
87
88 // Record for later.
89 if parts[0] == "def" {
90 s.defs[sym] = abi
91 } else {
92 s.refs[sym] |= obj.ABISetOf(abi)
93 }
94 default:
95 log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
96 }
97 }
98 }
99
100 // GenABIWrappers applies ABI information to Funcs and generates ABI
101 // wrapper functions where necessary.
102 func (s *SymABIs) GenABIWrappers() {
103 // For cgo exported symbols, we tell the linker to export the
104 // definition ABI to C. That also means that we don't want to
105 // create ABI wrappers even if there's a linkname.
106 //
107 // TODO(austin): Maybe we want to create the ABI wrappers, but
108 // ensure the linker exports the right ABI definition under
109 // the unmangled name?
110 cgoExports := make(map[string][]*[]string)
111 for i, prag := range typecheck.Target.CgoPragmas {
112 switch prag[0] {
113 case "cgo_export_static", "cgo_export_dynamic":
114 symName := s.canonicalize(prag[1])
115 pprag := &typecheck.Target.CgoPragmas[i]
116 cgoExports[symName] = append(cgoExports[symName], pprag)
117 }
118 }
119
120 // Apply ABI defs and refs to Funcs and generate wrappers.
121 //
122 // This may generate new decls for the wrappers, but we
123 // specifically *don't* want to visit those, lest we create
124 // wrappers for wrappers.
125 for _, fn := range typecheck.Target.Decls {
126 if fn.Op() != ir.ODCLFUNC {
127 continue
128 }
129 fn := fn.(*ir.Func)
130 nam := fn.Nname
131 if ir.IsBlank(nam) {
132 continue
133 }
134 sym := nam.Sym()
135
136 symName := sym.Linkname
137 if symName == "" {
138 symName = sym.Pkg.Prefix + "." + sym.Name
139 }
140 symName = s.canonicalize(symName)
141
142 // Apply definitions.
143 defABI, hasDefABI := s.defs[symName]
144 if hasDefABI {
145 if len(fn.Body) != 0 {
146 base.ErrorfAt(fn.Pos(), "%v defined in both Go and assembly", fn)
147 }
148 fn.ABI = defABI
149 }
150
151 if fn.Pragma&ir.CgoUnsafeArgs != 0 {
152 // CgoUnsafeArgs indicates the function (or its callee) uses
153 // offsets to dispatch arguments, which currently using ABI0
154 // frame layout. Pin it to ABI0.
155 fn.ABI = obj.ABI0
156 }
157
158 // If cgo-exported, add the definition ABI to the cgo
159 // pragmas.
160 cgoExport := cgoExports[symName]
161 for _, pprag := range cgoExport {
162 // The export pragmas have the form:
163 //
164 // cgo_export_* <local> [<remote>]
165 //
166 // If <remote> is omitted, it's the same as
167 // <local>.
168 //
169 // Expand to
170 //
171 // cgo_export_* <local> <remote> <ABI>
172 if len(*pprag) == 2 {
173 *pprag = append(*pprag, (*pprag)[1])
174 }
175 // Add the ABI argument.
176 *pprag = append(*pprag, fn.ABI.String())
177 }
178
179 // Apply references.
180 if abis, ok := s.refs[symName]; ok {
181 fn.ABIRefs |= abis
182 }
183 // Assume all functions are referenced at least as
184 // ABIInternal, since they may be referenced from
185 // other packages.
186 fn.ABIRefs.Set(obj.ABIInternal, true)
187
188 // If a symbol is defined in this package (either in
189 // Go or assembly) and given a linkname, it may be
190 // referenced from another package, so make it
191 // callable via any ABI. It's important that we know
192 // it's defined in this package since other packages
193 // may "pull" symbols using linkname and we don't want
194 // to create duplicate ABI wrappers.
195 //
196 // However, if it's given a linkname for exporting to
197 // C, then we don't make ABI wrappers because the cgo
198 // tool wants the original definition.
199 hasBody := len(fn.Body) != 0
200 if sym.Linkname != "" && (hasBody || hasDefABI) && len(cgoExport) == 0 {
201 fn.ABIRefs |= obj.ABISetCallable
202 }
203
204 // Double check that cgo-exported symbols don't get
205 // any wrappers.
206 if len(cgoExport) > 0 && fn.ABIRefs&^obj.ABISetOf(fn.ABI) != 0 {
207 base.Fatalf("cgo exported function %v cannot have ABI wrappers", fn)
208 }
209
210 if !buildcfg.Experiment.RegabiWrappers {
211 continue
212 }
213
214 forEachWrapperABI(fn, makeABIWrapper)
215 }
216 }
217
218 func forEachWrapperABI(fn *ir.Func, cb func(fn *ir.Func, wrapperABI obj.ABI)) {
219 need := fn.ABIRefs &^ obj.ABISetOf(fn.ABI)
220 if need == 0 {
221 return
222 }
223
224 for wrapperABI := obj.ABI(0); wrapperABI < obj.ABICount; wrapperABI++ {
225 if !need.Get(wrapperABI) {
226 continue
227 }
228 cb(fn, wrapperABI)
229 }
230 }
231
232 // makeABIWrapper creates a new function that will be called with
233 // wrapperABI and calls "f" using f.ABI.
234 func makeABIWrapper(f *ir.Func, wrapperABI obj.ABI) {
235 if base.Debug.ABIWrap != 0 {
236 fmt.Fprintf(os.Stderr, "=-= %v to %v wrapper for %v\n", wrapperABI, f.ABI, f)
237 }
238
239 // Q: is this needed?
240 savepos := base.Pos
241 savedclcontext := typecheck.DeclContext
242 savedcurfn := ir.CurFunc
243
244 base.Pos = base.AutogeneratedPos
245 typecheck.DeclContext = ir.PEXTERN
246
247 // At the moment we don't support wrapping a method, we'd need machinery
248 // below to handle the receiver. Panic if we see this scenario.
249 ft := f.Nname.Type()
250 if ft.NumRecvs() != 0 {
251 base.ErrorfAt(f.Pos(), "makeABIWrapper support for wrapping methods not implemented")
252 return
253 }
254
255 // Reuse f's types.Sym to create a new ODCLFUNC/function.
256 fn := typecheck.DeclFunc(f.Nname.Sym(), nil,
257 typecheck.NewFuncParams(ft.Params(), true),
258 typecheck.NewFuncParams(ft.Results(), false))
259 fn.ABI = wrapperABI
260
261 fn.SetABIWrapper(true)
262 fn.SetDupok(true)
263
264 // ABI0-to-ABIInternal wrappers will be mainly loading params from
265 // stack into registers (and/or storing stack locations back to
266 // registers after the wrapped call); in most cases they won't
267 // need to allocate stack space, so it should be OK to mark them
268 // as NOSPLIT in these cases. In addition, my assumption is that
269 // functions written in assembly are NOSPLIT in most (but not all)
270 // cases. In the case of an ABIInternal target that has too many
271 // parameters to fit into registers, the wrapper would need to
272 // allocate stack space, but this seems like an unlikely scenario.
273 // Hence: mark these wrappers NOSPLIT.
274 //
275 // ABIInternal-to-ABI0 wrappers on the other hand will be taking
276 // things in registers and pushing them onto the stack prior to
277 // the ABI0 call, meaning that they will always need to allocate
278 // stack space. If the compiler marks them as NOSPLIT this seems
279 // as though it could lead to situations where the linker's
280 // nosplit-overflow analysis would trigger a link failure. On the
281 // other hand if they not tagged NOSPLIT then this could cause
282 // problems when building the runtime (since there may be calls to
283 // asm routine in cases where it's not safe to grow the stack). In
284 // most cases the wrapper would be (in effect) inlined, but are
285 // there (perhaps) indirect calls from the runtime that could run
286 // into trouble here.
287 // FIXME: at the moment all.bash does not pass when I leave out
288 // NOSPLIT for these wrappers, so all are currently tagged with NOSPLIT.
289 fn.Pragma |= ir.Nosplit
290
291 // Generate call. Use tail call if no params and no returns,
292 // but a regular call otherwise.
293 //
294 // Note: ideally we would be using a tail call in cases where
295 // there are params but no returns for ABI0->ABIInternal wrappers,
296 // provided that all params fit into registers (e.g. we don't have
297 // to allocate any stack space). Doing this will require some
298 // extra work in typecheck/walk/ssa, might want to add a new node
299 // OTAILCALL or something to this effect.
300 tailcall := fn.Type().NumResults() == 0 && fn.Type().NumParams() == 0 && fn.Type().NumRecvs() == 0
301 if base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink {
302 // cannot tailcall on PPC64 with dynamic linking, as we need
303 // to restore R2 after call.
304 tailcall = false
305 }
306 if base.Ctxt.Arch.Name == "amd64" && wrapperABI == obj.ABIInternal {
307 // cannot tailcall from ABIInternal to ABI0 on AMD64, as we need
308 // to special registers (X15) when returning to ABIInternal.
309 tailcall = false
310 }
311
312 var tail ir.Node
313 call := ir.NewCallExpr(base.Pos, ir.OCALL, f.Nname, nil)
314 call.Args = ir.ParamNames(fn.Type())
315 call.IsDDD = fn.Type().IsVariadic()
316 tail = call
317 if tailcall {
318 tail = ir.NewTailCallStmt(base.Pos, call)
319 } else if fn.Type().NumResults() > 0 {
320 n := ir.NewReturnStmt(base.Pos, nil)
321 n.Results = []ir.Node{call}
322 tail = n
323 }
324 fn.Body.Append(tail)
325
326 typecheck.FinishFuncBody()
327 if base.Debug.DclStack != 0 {
328 types.CheckDclstack()
329 }
330
331 typecheck.Func(fn)
332 ir.CurFunc = fn
333 typecheck.Stmts(fn.Body)
334
335 typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
336
337 // Restore previous context.
338 base.Pos = savepos
339 typecheck.DeclContext = savedclcontext
340 ir.CurFunc = savedcurfn
341 }