]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/internal/obj/x86/obj6.go
internal/buildcfg: move build configuration out of cmd/internal/objabi
[gostls13.git] / src / cmd / internal / obj / x86 / obj6.go
1 // Inferno utils/6l/pass.c
2 // https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/pass.c
3 //
4 //      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
5 //      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 //      Portions Copyright © 1997-1999 Vita Nuova Limited
7 //      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 //      Portions Copyright © 2004,2006 Bruce Ellis
9 //      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 //      Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 //      Portions Copyright © 2009 The Go Authors. All rights reserved.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 // THE SOFTWARE.
30
31 package x86
32
33 import (
34         "cmd/internal/obj"
35         "cmd/internal/objabi"
36         "cmd/internal/src"
37         "cmd/internal/sys"
38         "internal/buildcfg"
39         "log"
40         "math"
41         "path"
42         "strings"
43 )
44
45 func CanUse1InsnTLS(ctxt *obj.Link) bool {
46         if isAndroid {
47                 // Android uses a global variable for the tls offset.
48                 return false
49         }
50
51         if ctxt.Arch.Family == sys.I386 {
52                 switch ctxt.Headtype {
53                 case objabi.Hlinux,
54                         objabi.Hplan9,
55                         objabi.Hwindows:
56                         return false
57                 }
58
59                 return true
60         }
61
62         switch ctxt.Headtype {
63         case objabi.Hplan9, objabi.Hwindows:
64                 return false
65         case objabi.Hlinux, objabi.Hfreebsd:
66                 return !ctxt.Flag_shared
67         }
68
69         return true
70 }
71
72 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
73         // Thread-local storage references use the TLS pseudo-register.
74         // As a register, TLS refers to the thread-local storage base, and it
75         // can only be loaded into another register:
76         //
77         //         MOVQ TLS, AX
78         //
79         // An offset from the thread-local storage base is written off(reg)(TLS*1).
80         // Semantically it is off(reg), but the (TLS*1) annotation marks this as
81         // indexing from the loaded TLS base. This emits a relocation so that
82         // if the linker needs to adjust the offset, it can. For example:
83         //
84         //         MOVQ TLS, AX
85         //         MOVQ 0(AX)(TLS*1), CX // load g into CX
86         //
87         // On systems that support direct access to the TLS memory, this
88         // pair of instructions can be reduced to a direct TLS memory reference:
89         //
90         //         MOVQ 0(TLS), CX // load g into CX
91         //
92         // The 2-instruction and 1-instruction forms correspond to the two code
93         // sequences for loading a TLS variable in the local exec model given in "ELF
94         // Handling For Thread-Local Storage".
95         //
96         // We apply this rewrite on systems that support the 1-instruction form.
97         // The decision is made using only the operating system and the -shared flag,
98         // not the link mode. If some link modes on a particular operating system
99         // require the 2-instruction form, then all builds for that operating system
100         // will use the 2-instruction form, so that the link mode decision can be
101         // delayed to link time.
102         //
103         // In this way, all supported systems use identical instructions to
104         // access TLS, and they are rewritten appropriately first here in
105         // liblink and then finally using relocations in the linker.
106         //
107         // When -shared is passed, we leave the code in the 2-instruction form but
108         // assemble (and relocate) them in different ways to generate the initial
109         // exec code sequence. It's a bit of a fluke that this is possible without
110         // rewriting the instructions more comprehensively, and it only does because
111         // we only support a single TLS variable (g).
112
113         if CanUse1InsnTLS(ctxt) {
114                 // Reduce 2-instruction sequence to 1-instruction sequence.
115                 // Sequences like
116                 //      MOVQ TLS, BX
117                 //      ... off(BX)(TLS*1) ...
118                 // become
119                 //      NOP
120                 //      ... off(TLS) ...
121                 //
122                 // TODO(rsc): Remove the Hsolaris special case. It exists only to
123                 // guarantee we are producing byte-identical binaries as before this code.
124                 // But it should be unnecessary.
125                 if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 && ctxt.Headtype != objabi.Hsolaris {
126                         obj.Nopout(p)
127                 }
128                 if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
129                         p.From.Reg = REG_TLS
130                         p.From.Scale = 0
131                         p.From.Index = REG_NONE
132                 }
133
134                 if p.To.Type == obj.TYPE_MEM && p.To.Index == REG_TLS && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
135                         p.To.Reg = REG_TLS
136                         p.To.Scale = 0
137                         p.To.Index = REG_NONE
138                 }
139         } else {
140                 // load_g, below, always inserts the 1-instruction sequence. Rewrite it
141                 // as the 2-instruction sequence if necessary.
142                 //      MOVQ 0(TLS), BX
143                 // becomes
144                 //      MOVQ TLS, BX
145                 //      MOVQ 0(BX)(TLS*1), BX
146                 if (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
147                         q := obj.Appendp(p, newprog)
148                         q.As = p.As
149                         q.From = p.From
150                         q.From.Type = obj.TYPE_MEM
151                         q.From.Reg = p.To.Reg
152                         q.From.Index = REG_TLS
153                         q.From.Scale = 2 // TODO: use 1
154                         q.To = p.To
155                         p.From.Type = obj.TYPE_REG
156                         p.From.Reg = REG_TLS
157                         p.From.Index = REG_NONE
158                         p.From.Offset = 0
159                 }
160         }
161
162         // Android uses a tls offset determined at runtime. Rewrite
163         //      MOVQ TLS, BX
164         // to
165         //      MOVQ runtime.tls_g(SB), BX
166         if isAndroid && (p.As == AMOVQ || p.As == AMOVL) && p.From.Type == obj.TYPE_REG && p.From.Reg == REG_TLS && p.To.Type == obj.TYPE_REG && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
167                 p.From.Type = obj.TYPE_MEM
168                 p.From.Name = obj.NAME_EXTERN
169                 p.From.Reg = REG_NONE
170                 p.From.Sym = ctxt.Lookup("runtime.tls_g")
171                 p.From.Index = REG_NONE
172         }
173
174         // TODO: Remove.
175         if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
176                 if p.From.Scale == 1 && p.From.Index == REG_TLS {
177                         p.From.Scale = 2
178                 }
179                 if p.To.Scale == 1 && p.To.Index == REG_TLS {
180                         p.To.Scale = 2
181                 }
182         }
183
184         // Rewrite 0 to $0 in 3rd argument to CMPPS etc.
185         // That's what the tables expect.
186         switch p.As {
187         case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
188                 if p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_NONE && p.To.Reg == REG_NONE && p.To.Index == REG_NONE && p.To.Sym == nil {
189                         p.To.Type = obj.TYPE_CONST
190                 }
191         }
192
193         // Rewrite CALL/JMP/RET to symbol as TYPE_BRANCH.
194         switch p.As {
195         case obj.ACALL, obj.AJMP, obj.ARET:
196                 if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
197                         p.To.Type = obj.TYPE_BRANCH
198                 }
199         }
200
201         // Rewrite MOVL/MOVQ $XXX(FP/SP) as LEAL/LEAQ.
202         if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
203                 switch p.As {
204                 case AMOVL:
205                         p.As = ALEAL
206                         p.From.Type = obj.TYPE_MEM
207                 case AMOVQ:
208                         p.As = ALEAQ
209                         p.From.Type = obj.TYPE_MEM
210                 }
211         }
212
213         // Rewrite float constants to values stored in memory.
214         switch p.As {
215         // Convert AMOVSS $(0), Xx to AXORPS Xx, Xx
216         case AMOVSS:
217                 if p.From.Type == obj.TYPE_FCONST {
218                         //  f == 0 can't be used here due to -0, so use Float64bits
219                         if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
220                                 if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
221                                         p.As = AXORPS
222                                         p.From = p.To
223                                         break
224                                 }
225                         }
226                 }
227                 fallthrough
228
229         case AFMOVF,
230                 AFADDF,
231                 AFSUBF,
232                 AFSUBRF,
233                 AFMULF,
234                 AFDIVF,
235                 AFDIVRF,
236                 AFCOMF,
237                 AFCOMFP,
238                 AADDSS,
239                 ASUBSS,
240                 AMULSS,
241                 ADIVSS,
242                 ACOMISS,
243                 AUCOMISS:
244                 if p.From.Type == obj.TYPE_FCONST {
245                         f32 := float32(p.From.Val.(float64))
246                         p.From.Type = obj.TYPE_MEM
247                         p.From.Name = obj.NAME_EXTERN
248                         p.From.Sym = ctxt.Float32Sym(f32)
249                         p.From.Offset = 0
250                 }
251
252         case AMOVSD:
253                 // Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
254                 if p.From.Type == obj.TYPE_FCONST {
255                         //  f == 0 can't be used here due to -0, so use Float64bits
256                         if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
257                                 if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
258                                         p.As = AXORPS
259                                         p.From = p.To
260                                         break
261                                 }
262                         }
263                 }
264                 fallthrough
265
266         case AFMOVD,
267                 AFADDD,
268                 AFSUBD,
269                 AFSUBRD,
270                 AFMULD,
271                 AFDIVD,
272                 AFDIVRD,
273                 AFCOMD,
274                 AFCOMDP,
275                 AADDSD,
276                 ASUBSD,
277                 AMULSD,
278                 ADIVSD,
279                 ACOMISD,
280                 AUCOMISD:
281                 if p.From.Type == obj.TYPE_FCONST {
282                         f64 := p.From.Val.(float64)
283                         p.From.Type = obj.TYPE_MEM
284                         p.From.Name = obj.NAME_EXTERN
285                         p.From.Sym = ctxt.Float64Sym(f64)
286                         p.From.Offset = 0
287                 }
288         }
289
290         if ctxt.Flag_dynlink {
291                 rewriteToUseGot(ctxt, p, newprog)
292         }
293
294         if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
295                 rewriteToPcrel(ctxt, p, newprog)
296         }
297 }
298
299 // Rewrite p, if necessary, to access global data via the global offset table.
300 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
301         var lea, mov obj.As
302         var reg int16
303         if ctxt.Arch.Family == sys.AMD64 {
304                 lea = ALEAQ
305                 mov = AMOVQ
306                 reg = REG_R15
307         } else {
308                 lea = ALEAL
309                 mov = AMOVL
310                 reg = REG_CX
311                 if p.As == ALEAL && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
312                         // Special case: clobber the destination register with
313                         // the PC so we don't have to clobber CX.
314                         // The SSA backend depends on CX not being clobbered across LEAL.
315                         // See cmd/compile/internal/ssa/gen/386.rules (search for Flag_shared).
316                         reg = p.To.Reg
317                 }
318         }
319
320         if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
321                 //     ADUFFxxx $offset
322                 // becomes
323                 //     $MOV runtime.duffxxx@GOT, $reg
324                 //     $LEA $offset($reg), $reg
325                 //     CALL $reg
326                 // (we use LEAx rather than ADDx because ADDx clobbers
327                 // flags and duffzero on 386 does not otherwise do so).
328                 var sym *obj.LSym
329                 if p.As == obj.ADUFFZERO {
330                         sym = ctxt.LookupABI("runtime.duffzero", obj.ABIInternal)
331                 } else {
332                         sym = ctxt.LookupABI("runtime.duffcopy", obj.ABIInternal)
333                 }
334                 offset := p.To.Offset
335                 p.As = mov
336                 p.From.Type = obj.TYPE_MEM
337                 p.From.Name = obj.NAME_GOTREF
338                 p.From.Sym = sym
339                 p.To.Type = obj.TYPE_REG
340                 p.To.Reg = reg
341                 p.To.Offset = 0
342                 p.To.Sym = nil
343                 p1 := obj.Appendp(p, newprog)
344                 p1.As = lea
345                 p1.From.Type = obj.TYPE_MEM
346                 p1.From.Offset = offset
347                 p1.From.Reg = reg
348                 p1.To.Type = obj.TYPE_REG
349                 p1.To.Reg = reg
350                 p2 := obj.Appendp(p1, newprog)
351                 p2.As = obj.ACALL
352                 p2.To.Type = obj.TYPE_REG
353                 p2.To.Reg = reg
354         }
355
356         // We only care about global data: NAME_EXTERN means a global
357         // symbol in the Go sense, and p.Sym.Local is true for a few
358         // internally defined symbols.
359         if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
360                 // $LEA sym, Rx becomes $MOV $sym, Rx which will be rewritten below
361                 p.As = mov
362                 p.From.Type = obj.TYPE_ADDR
363         }
364         if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
365                 // $MOV $sym, Rx becomes $MOV sym@GOT, Rx
366                 // $MOV $sym+<off>, Rx becomes $MOV sym@GOT, Rx; $LEA <off>(Rx), Rx
367                 // On 386 only, more complicated things like PUSHL $sym become $MOV sym@GOT, CX; PUSHL CX
368                 cmplxdest := false
369                 pAs := p.As
370                 var dest obj.Addr
371                 if p.To.Type != obj.TYPE_REG || pAs != mov {
372                         if ctxt.Arch.Family == sys.AMD64 {
373                                 ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
374                         }
375                         cmplxdest = true
376                         dest = p.To
377                         p.As = mov
378                         p.To.Type = obj.TYPE_REG
379                         p.To.Reg = reg
380                         p.To.Sym = nil
381                         p.To.Name = obj.NAME_NONE
382                 }
383                 p.From.Type = obj.TYPE_MEM
384                 p.From.Name = obj.NAME_GOTREF
385                 q := p
386                 if p.From.Offset != 0 {
387                         q = obj.Appendp(p, newprog)
388                         q.As = lea
389                         q.From.Type = obj.TYPE_MEM
390                         q.From.Reg = p.To.Reg
391                         q.From.Offset = p.From.Offset
392                         q.To = p.To
393                         p.From.Offset = 0
394                 }
395                 if cmplxdest {
396                         q = obj.Appendp(q, newprog)
397                         q.As = pAs
398                         q.To = dest
399                         q.From.Type = obj.TYPE_REG
400                         q.From.Reg = reg
401                 }
402         }
403         if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
404                 ctxt.Diag("don't know how to handle %v with -dynlink", p)
405         }
406         var source *obj.Addr
407         // MOVx sym, Ry becomes $MOV sym@GOT, R15; MOVx (R15), Ry
408         // MOVx Ry, sym becomes $MOV sym@GOT, R15; MOVx Ry, (R15)
409         // An addition may be inserted between the two MOVs if there is an offset.
410         if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
411                 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
412                         ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
413                 }
414                 source = &p.From
415         } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
416                 source = &p.To
417         } else {
418                 return
419         }
420         if p.As == obj.ACALL {
421                 // When dynlinking on 386, almost any call might end up being a call
422                 // to a PLT, so make sure the GOT pointer is loaded into BX.
423                 // RegTo2 is set on the replacement call insn to stop it being
424                 // processed when it is in turn passed to progedit.
425                 //
426                 // We disable open-coded defers in buildssa() on 386 ONLY with shared
427                 // libraries because of this extra code added before deferreturn calls.
428                 if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
429                         return
430                 }
431                 p1 := obj.Appendp(p, newprog)
432                 p2 := obj.Appendp(p1, newprog)
433
434                 p1.As = ALEAL
435                 p1.From.Type = obj.TYPE_MEM
436                 p1.From.Name = obj.NAME_STATIC
437                 p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
438                 p1.To.Type = obj.TYPE_REG
439                 p1.To.Reg = REG_BX
440
441                 p2.As = p.As
442                 p2.Scond = p.Scond
443                 p2.From = p.From
444                 if p.RestArgs != nil {
445                         p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
446                 }
447                 p2.Reg = p.Reg
448                 p2.To = p.To
449                 // p.To.Type was set to TYPE_BRANCH above, but that makes checkaddr
450                 // in ../pass.go complain, so set it back to TYPE_MEM here, until p2
451                 // itself gets passed to progedit.
452                 p2.To.Type = obj.TYPE_MEM
453                 p2.RegTo2 = 1
454
455                 obj.Nopout(p)
456                 return
457
458         }
459         if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
460                 return
461         }
462         if source.Type != obj.TYPE_MEM {
463                 ctxt.Diag("don't know how to handle %v with -dynlink", p)
464         }
465         p1 := obj.Appendp(p, newprog)
466         p2 := obj.Appendp(p1, newprog)
467
468         p1.As = mov
469         p1.From.Type = obj.TYPE_MEM
470         p1.From.Sym = source.Sym
471         p1.From.Name = obj.NAME_GOTREF
472         p1.To.Type = obj.TYPE_REG
473         p1.To.Reg = reg
474
475         p2.As = p.As
476         p2.From = p.From
477         p2.To = p.To
478         if p.From.Name == obj.NAME_EXTERN {
479                 p2.From.Reg = reg
480                 p2.From.Name = obj.NAME_NONE
481                 p2.From.Sym = nil
482         } else if p.To.Name == obj.NAME_EXTERN {
483                 p2.To.Reg = reg
484                 p2.To.Name = obj.NAME_NONE
485                 p2.To.Sym = nil
486         } else {
487                 return
488         }
489         obj.Nopout(p)
490 }
491
492 func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
493         // RegTo2 is set on the instructions we insert here so they don't get
494         // processed twice.
495         if p.RegTo2 != 0 {
496                 return
497         }
498         if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
499                 return
500         }
501         // Any Prog (aside from the above special cases) with an Addr with Name ==
502         // NAME_EXTERN, NAME_STATIC or NAME_GOTREF has a CALL __x86.get_pc_thunk.XX
503         // inserted before it.
504         isName := func(a *obj.Addr) bool {
505                 if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
506                         return false
507                 }
508                 if a.Sym.Type == objabi.STLSBSS {
509                         return false
510                 }
511                 return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
512         }
513
514         if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
515                 // Handle things like "MOVL $sym, (SP)" or "PUSHL $sym" by rewriting
516                 // to "MOVL $sym, CX; MOVL CX, (SP)" or "MOVL $sym, CX; PUSHL CX"
517                 // respectively.
518                 if p.To.Type != obj.TYPE_REG {
519                         q := obj.Appendp(p, newprog)
520                         q.As = p.As
521                         q.From.Type = obj.TYPE_REG
522                         q.From.Reg = REG_CX
523                         q.To = p.To
524                         p.As = AMOVL
525                         p.To.Type = obj.TYPE_REG
526                         p.To.Reg = REG_CX
527                         p.To.Sym = nil
528                         p.To.Name = obj.NAME_NONE
529                 }
530         }
531
532         if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
533                 return
534         }
535         var dst int16 = REG_CX
536         if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
537                 dst = p.To.Reg
538                 // Why? See the comment near the top of rewriteToUseGot above.
539                 // AMOVLs might be introduced by the GOT rewrites.
540         }
541         q := obj.Appendp(p, newprog)
542         q.RegTo2 = 1
543         r := obj.Appendp(q, newprog)
544         r.RegTo2 = 1
545         q.As = obj.ACALL
546         thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
547         q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
548         q.To.Type = obj.TYPE_MEM
549         q.To.Name = obj.NAME_EXTERN
550         r.As = p.As
551         r.Scond = p.Scond
552         r.From = p.From
553         r.RestArgs = p.RestArgs
554         r.Reg = p.Reg
555         r.To = p.To
556         if isName(&p.From) {
557                 r.From.Reg = dst
558         }
559         if isName(&p.To) {
560                 r.To.Reg = dst
561         }
562         if p.GetFrom3() != nil && isName(p.GetFrom3()) {
563                 r.GetFrom3().Reg = dst
564         }
565         obj.Nopout(p)
566 }
567
568 // Prog.mark
569 const (
570         markBit = 1 << 0 // used in errorCheck to avoid duplicate work
571 )
572
573 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
574         if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
575                 return
576         }
577
578         p := cursym.Func().Text
579         autoffset := int32(p.To.Offset)
580         if autoffset < 0 {
581                 autoffset = 0
582         }
583
584         hasCall := false
585         for q := p; q != nil; q = q.Link {
586                 if q.As == obj.ACALL || q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO {
587                         hasCall = true
588                         break
589                 }
590         }
591
592         var bpsize int
593         if ctxt.Arch.Family == sys.AMD64 &&
594                 !p.From.Sym.NoFrame() && // (1) below
595                 !(autoffset == 0 && p.From.Sym.NoSplit()) && // (2) below
596                 !(autoffset == 0 && !hasCall) { // (3) below
597                 // Make room to save a base pointer.
598                 // There are 2 cases we must avoid:
599                 // 1) If noframe is set (which we do for functions which tail call).
600                 // 2) Scary runtime internals which would be all messed up by frame pointers.
601                 //    We detect these using a heuristic: frameless nosplit functions.
602                 //    TODO: Maybe someday we label them all with NOFRAME and get rid of this heuristic.
603                 // For performance, we also want to avoid:
604                 // 3) Frameless leaf functions
605                 bpsize = ctxt.Arch.PtrSize
606                 autoffset += int32(bpsize)
607                 p.To.Offset += int64(bpsize)
608         } else {
609                 bpsize = 0
610         }
611
612         textarg := int64(p.To.Val.(int32))
613         cursym.Func().Args = int32(textarg)
614         cursym.Func().Locals = int32(p.To.Offset)
615
616         // TODO(rsc): Remove.
617         if ctxt.Arch.Family == sys.I386 && cursym.Func().Locals < 0 {
618                 cursym.Func().Locals = 0
619         }
620
621         // TODO(rsc): Remove 'ctxt.Arch.Family == sys.AMD64 &&'.
622         if ctxt.Arch.Family == sys.AMD64 && autoffset < objabi.StackSmall && !p.From.Sym.NoSplit() {
623                 leaf := true
624         LeafSearch:
625                 for q := p; q != nil; q = q.Link {
626                         switch q.As {
627                         case obj.ACALL:
628                                 // Treat common runtime calls that take no arguments
629                                 // the same as duffcopy and duffzero.
630                                 if !isZeroArgRuntimeCall(q.To.Sym) {
631                                         leaf = false
632                                         break LeafSearch
633                                 }
634                                 fallthrough
635                         case obj.ADUFFCOPY, obj.ADUFFZERO:
636                                 if autoffset >= objabi.StackSmall-8 {
637                                         leaf = false
638                                         break LeafSearch
639                                 }
640                         }
641                 }
642
643                 if leaf {
644                         p.From.Sym.Set(obj.AttrNoSplit, true)
645                 }
646         }
647
648         var regg int16
649         if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
650                 if ctxt.Arch.Family == sys.AMD64 && buildcfg.Experiment.RegabiG && cursym.ABI() == obj.ABIInternal {
651                         regg = REGG // use the g register directly in ABIInternal
652                 } else {
653                         p = obj.Appendp(p, newprog)
654                         regg = REG_CX
655                         if ctxt.Arch.Family == sys.AMD64 {
656                                 // Using this register means that stacksplit works w/ //go:registerparams even when !buildcfg.Experiment.RegabiG
657                                 regg = REGG // == REG_R14
658                         }
659                         p = load_g(ctxt, p, newprog, regg) // load g into regg
660                 }
661         }
662         var regEntryTmp0, regEntryTmp1 int16
663         if ctxt.Arch.Family == sys.AMD64 {
664                 regEntryTmp0, regEntryTmp1 = REGENTRYTMP0, REGENTRYTMP1
665         } else {
666                 regEntryTmp0, regEntryTmp1 = REG_BX, REG_DI
667         }
668
669         if !cursym.Func().Text.From.Sym.NoSplit() {
670                 p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg), regg) // emit split check
671         }
672
673         // Delve debugger would like the next instruction to be noted as the end of the function prologue.
674         // TODO: are there other cases (e.g., wrapper functions) that need marking?
675         markedPrologue := false
676
677         if autoffset != 0 {
678                 if autoffset%int32(ctxt.Arch.RegSize) != 0 {
679                         ctxt.Diag("unaligned stack size %d", autoffset)
680                 }
681                 p = obj.Appendp(p, newprog)
682                 p.As = AADJSP
683                 p.From.Type = obj.TYPE_CONST
684                 p.From.Offset = int64(autoffset)
685                 p.Spadj = autoffset
686                 p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
687                 markedPrologue = true
688         }
689
690         if bpsize > 0 {
691                 // Save caller's BP
692                 p = obj.Appendp(p, newprog)
693
694                 p.As = AMOVQ
695                 p.From.Type = obj.TYPE_REG
696                 p.From.Reg = REG_BP
697                 p.To.Type = obj.TYPE_MEM
698                 p.To.Reg = REG_SP
699                 p.To.Scale = 1
700                 p.To.Offset = int64(autoffset) - int64(bpsize)
701                 if !markedPrologue {
702                         p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
703                 }
704
705                 // Move current frame to BP
706                 p = obj.Appendp(p, newprog)
707
708                 p.As = ALEAQ
709                 p.From.Type = obj.TYPE_MEM
710                 p.From.Reg = REG_SP
711                 p.From.Scale = 1
712                 p.From.Offset = int64(autoffset) - int64(bpsize)
713                 p.To.Type = obj.TYPE_REG
714                 p.To.Reg = REG_BP
715         }
716
717         if cursym.Func().Text.From.Sym.Wrapper() {
718                 // if g._panic != nil && g._panic.argp == FP {
719                 //   g._panic.argp = bottom-of-frame
720                 // }
721                 //
722                 //      MOVQ g_panic(g), regEntryTmp0
723                 //      TESTQ regEntryTmp0, regEntryTmp0
724                 //      JNE checkargp
725                 // end:
726                 //      NOP
727                 //  ... rest of function ...
728                 // checkargp:
729                 //      LEAQ (autoffset+8)(SP), regEntryTmp1
730                 //      CMPQ panic_argp(regEntryTmp0), regEntryTmp1
731                 //      JNE end
732                 //  MOVQ SP, panic_argp(regEntryTmp0)
733                 //  JMP end
734                 //
735                 // The NOP is needed to give the jumps somewhere to land.
736                 // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
737                 //
738                 // The layout is chosen to help static branch prediction:
739                 // Both conditional jumps are unlikely, so they are arranged to be forward jumps.
740
741                 // MOVQ g_panic(g), regEntryTmp0
742                 p = obj.Appendp(p, newprog)
743                 p.As = AMOVQ
744                 p.From.Type = obj.TYPE_MEM
745                 p.From.Reg = regg
746                 p.From.Offset = 4 * int64(ctxt.Arch.PtrSize) // g_panic
747                 p.To.Type = obj.TYPE_REG
748                 p.To.Reg = regEntryTmp0
749                 if ctxt.Arch.Family == sys.I386 {
750                         p.As = AMOVL
751                 }
752
753                 // TESTQ regEntryTmp0, regEntryTmp0
754                 p = obj.Appendp(p, newprog)
755                 p.As = ATESTQ
756                 p.From.Type = obj.TYPE_REG
757                 p.From.Reg = regEntryTmp0
758                 p.To.Type = obj.TYPE_REG
759                 p.To.Reg = regEntryTmp0
760                 if ctxt.Arch.Family == sys.I386 {
761                         p.As = ATESTL
762                 }
763
764                 // JNE checkargp (checkargp to be resolved later)
765                 jne := obj.Appendp(p, newprog)
766                 jne.As = AJNE
767                 jne.To.Type = obj.TYPE_BRANCH
768
769                 // end:
770                 //  NOP
771                 end := obj.Appendp(jne, newprog)
772                 end.As = obj.ANOP
773
774                 // Fast forward to end of function.
775                 var last *obj.Prog
776                 for last = end; last.Link != nil; last = last.Link {
777                 }
778
779                 // LEAQ (autoffset+8)(SP), regEntryTmp1
780                 p = obj.Appendp(last, newprog)
781                 p.As = ALEAQ
782                 p.From.Type = obj.TYPE_MEM
783                 p.From.Reg = REG_SP
784                 p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
785                 p.To.Type = obj.TYPE_REG
786                 p.To.Reg = regEntryTmp1
787                 if ctxt.Arch.Family == sys.I386 {
788                         p.As = ALEAL
789                 }
790
791                 // Set jne branch target.
792                 jne.To.SetTarget(p)
793
794                 // CMPQ panic_argp(regEntryTmp0), regEntryTmp1
795                 p = obj.Appendp(p, newprog)
796                 p.As = ACMPQ
797                 p.From.Type = obj.TYPE_MEM
798                 p.From.Reg = regEntryTmp0
799                 p.From.Offset = 0 // Panic.argp
800                 p.To.Type = obj.TYPE_REG
801                 p.To.Reg = regEntryTmp1
802                 if ctxt.Arch.Family == sys.I386 {
803                         p.As = ACMPL
804                 }
805
806                 // JNE end
807                 p = obj.Appendp(p, newprog)
808                 p.As = AJNE
809                 p.To.Type = obj.TYPE_BRANCH
810                 p.To.SetTarget(end)
811
812                 // MOVQ SP, panic_argp(regEntryTmp0)
813                 p = obj.Appendp(p, newprog)
814                 p.As = AMOVQ
815                 p.From.Type = obj.TYPE_REG
816                 p.From.Reg = REG_SP
817                 p.To.Type = obj.TYPE_MEM
818                 p.To.Reg = regEntryTmp0
819                 p.To.Offset = 0 // Panic.argp
820                 if ctxt.Arch.Family == sys.I386 {
821                         p.As = AMOVL
822                 }
823
824                 // JMP end
825                 p = obj.Appendp(p, newprog)
826                 p.As = obj.AJMP
827                 p.To.Type = obj.TYPE_BRANCH
828                 p.To.SetTarget(end)
829
830                 // Reset p for following code.
831                 p = end
832         }
833
834         var deltasp int32
835         for p = cursym.Func().Text; p != nil; p = p.Link {
836                 pcsize := ctxt.Arch.RegSize
837                 switch p.From.Name {
838                 case obj.NAME_AUTO:
839                         p.From.Offset += int64(deltasp) - int64(bpsize)
840                 case obj.NAME_PARAM:
841                         p.From.Offset += int64(deltasp) + int64(pcsize)
842                 }
843                 if p.GetFrom3() != nil {
844                         switch p.GetFrom3().Name {
845                         case obj.NAME_AUTO:
846                                 p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
847                         case obj.NAME_PARAM:
848                                 p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
849                         }
850                 }
851                 switch p.To.Name {
852                 case obj.NAME_AUTO:
853                         p.To.Offset += int64(deltasp) - int64(bpsize)
854                 case obj.NAME_PARAM:
855                         p.To.Offset += int64(deltasp) + int64(pcsize)
856                 }
857
858                 switch p.As {
859                 default:
860                         if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SP && p.As != ACMPL && p.As != ACMPQ {
861                                 f := cursym.Func()
862                                 if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
863                                         f.FuncFlag |= objabi.FuncFlag_SPWRITE
864                                         if ctxt.Debugvlog || !ctxt.IsAsm {
865                                                 ctxt.Logf("auto-SPWRITE: %s %v\n", cursym.Name, p)
866                                                 if !ctxt.IsAsm {
867                                                         ctxt.Diag("invalid auto-SPWRITE in non-assembly")
868                                                         ctxt.DiagFlush()
869                                                         log.Fatalf("bad SPWRITE")
870                                                 }
871                                         }
872                                 }
873                         }
874                         continue
875
876                 case APUSHL, APUSHFL:
877                         deltasp += 4
878                         p.Spadj = 4
879                         continue
880
881                 case APUSHQ, APUSHFQ:
882                         deltasp += 8
883                         p.Spadj = 8
884                         continue
885
886                 case APUSHW, APUSHFW:
887                         deltasp += 2
888                         p.Spadj = 2
889                         continue
890
891                 case APOPL, APOPFL:
892                         deltasp -= 4
893                         p.Spadj = -4
894                         continue
895
896                 case APOPQ, APOPFQ:
897                         deltasp -= 8
898                         p.Spadj = -8
899                         continue
900
901                 case APOPW, APOPFW:
902                         deltasp -= 2
903                         p.Spadj = -2
904                         continue
905
906                 case AADJSP:
907                         p.Spadj = int32(p.From.Offset)
908                         deltasp += int32(p.From.Offset)
909                         continue
910
911                 case obj.ARET:
912                         // do nothing
913                 }
914
915                 if autoffset != deltasp {
916                         ctxt.Diag("%s: unbalanced PUSH/POP", cursym)
917                 }
918
919                 if autoffset != 0 {
920                         to := p.To // Keep To attached to RET for retjmp below
921                         p.To = obj.Addr{}
922                         if bpsize > 0 {
923                                 // Restore caller's BP
924                                 p.As = AMOVQ
925
926                                 p.From.Type = obj.TYPE_MEM
927                                 p.From.Reg = REG_SP
928                                 p.From.Scale = 1
929                                 p.From.Offset = int64(autoffset) - int64(bpsize)
930                                 p.To.Type = obj.TYPE_REG
931                                 p.To.Reg = REG_BP
932                                 p = obj.Appendp(p, newprog)
933                         }
934
935                         p.As = AADJSP
936                         p.From.Type = obj.TYPE_CONST
937                         p.From.Offset = int64(-autoffset)
938                         p.Spadj = -autoffset
939                         p = obj.Appendp(p, newprog)
940                         p.As = obj.ARET
941                         p.To = to
942
943                         // If there are instructions following
944                         // this ARET, they come from a branch
945                         // with the same stackframe, so undo
946                         // the cleanup.
947                         p.Spadj = +autoffset
948                 }
949
950                 if p.To.Sym != nil { // retjmp
951                         p.As = obj.AJMP
952                 }
953         }
954 }
955
956 func isZeroArgRuntimeCall(s *obj.LSym) bool {
957         if s == nil {
958                 return false
959         }
960         switch s.Name {
961         case "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift":
962                 return true
963         }
964         if strings.HasPrefix(s.Name, "runtime.panicIndex") || strings.HasPrefix(s.Name, "runtime.panicSlice") {
965                 // These functions do take arguments (in registers),
966                 // but use no stack before they do a stack check. We
967                 // should include them. See issue 31219.
968                 return true
969         }
970         return false
971 }
972
973 func indir_cx(ctxt *obj.Link, a *obj.Addr) {
974         a.Type = obj.TYPE_MEM
975         a.Reg = REG_CX
976 }
977
978 // Append code to p to load g into cx.
979 // Overwrites p with the first instruction (no first appendp).
980 // Overwriting p is unusual but it lets use this in both the
981 // prologue (caller must call appendp first) and in the epilogue.
982 // Returns last new instruction.
983 func load_g(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc, rg int16) *obj.Prog {
984         p.As = AMOVQ
985         if ctxt.Arch.PtrSize == 4 {
986                 p.As = AMOVL
987         }
988         p.From.Type = obj.TYPE_MEM
989         p.From.Reg = REG_TLS
990         p.From.Offset = 0
991         p.To.Type = obj.TYPE_REG
992         p.To.Reg = rg
993
994         next := p.Link
995         progedit(ctxt, p, newprog)
996         for p.Link != next {
997                 p = p.Link
998                 progedit(ctxt, p, newprog)
999         }
1000
1001         if p.From.Index == REG_TLS {
1002                 p.From.Scale = 2
1003         }
1004
1005         return p
1006 }
1007
1008 // Append code to p to check for stack split.
1009 // Appends to (does not overwrite) p.
1010 // Assumes g is in rg.
1011 // Returns last new instruction.
1012 func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32, rg int16) *obj.Prog {
1013         cmp := ACMPQ
1014         lea := ALEAQ
1015         mov := AMOVQ
1016         sub := ASUBQ
1017
1018         if ctxt.Arch.Family == sys.I386 {
1019                 cmp = ACMPL
1020                 lea = ALEAL
1021                 mov = AMOVL
1022                 sub = ASUBL
1023         }
1024
1025         tmp := int16(REG_AX) // use AX for 32-bit
1026         if ctxt.Arch.Family == sys.AMD64 {
1027                 // Avoid register parameters.
1028                 tmp = int16(REGENTRYTMP0)
1029         }
1030
1031         var q1 *obj.Prog
1032         if framesize <= objabi.StackSmall {
1033                 // small stack: SP <= stackguard
1034                 //      CMPQ SP, stackguard
1035                 p = obj.Appendp(p, newprog)
1036
1037                 p.As = cmp
1038                 p.From.Type = obj.TYPE_REG
1039                 p.From.Reg = REG_SP
1040                 p.To.Type = obj.TYPE_MEM
1041                 p.To.Reg = rg
1042                 p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
1043                 if cursym.CFunc() {
1044                         p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
1045                 }
1046
1047                 // Mark the stack bound check and morestack call async nonpreemptible.
1048                 // If we get preempted here, when resumed the preemption request is
1049                 // cleared, but we'll still call morestack, which will double the stack
1050                 // unnecessarily. See issue #35470.
1051                 p = ctxt.StartUnsafePoint(p, newprog)
1052         } else if framesize <= objabi.StackBig {
1053                 // large stack: SP-framesize <= stackguard-StackSmall
1054                 //      LEAQ -xxx(SP), tmp
1055                 //      CMPQ tmp, stackguard
1056                 p = obj.Appendp(p, newprog)
1057
1058                 p.As = lea
1059                 p.From.Type = obj.TYPE_MEM
1060                 p.From.Reg = REG_SP
1061                 p.From.Offset = -(int64(framesize) - objabi.StackSmall)
1062                 p.To.Type = obj.TYPE_REG
1063                 p.To.Reg = tmp
1064
1065                 p = obj.Appendp(p, newprog)
1066                 p.As = cmp
1067                 p.From.Type = obj.TYPE_REG
1068                 p.From.Reg = tmp
1069                 p.To.Type = obj.TYPE_MEM
1070                 p.To.Reg = rg
1071                 p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
1072                 if cursym.CFunc() {
1073                         p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
1074                 }
1075
1076                 p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
1077         } else {
1078                 // Such a large stack we need to protect against underflow.
1079                 // The runtime guarantees SP > objabi.StackBig, but
1080                 // framesize is large enough that SP-framesize may
1081                 // underflow, causing a direct comparison with the
1082                 // stack guard to incorrectly succeed. We explicitly
1083                 // guard against underflow.
1084                 //
1085                 //      MOVQ    SP, tmp
1086                 //      SUBQ    $(framesize - StackSmall), tmp
1087                 //      // If subtraction wrapped (carry set), morestack.
1088                 //      JCS     label-of-call-to-morestack
1089                 //      CMPQ    tmp, stackguard
1090
1091                 p = obj.Appendp(p, newprog)
1092
1093                 p.As = mov
1094                 p.From.Type = obj.TYPE_REG
1095                 p.From.Reg = REG_SP
1096                 p.To.Type = obj.TYPE_REG
1097                 p.To.Reg = tmp
1098
1099                 p = ctxt.StartUnsafePoint(p, newprog) // see the comment above
1100
1101                 p = obj.Appendp(p, newprog)
1102                 p.As = sub
1103                 p.From.Type = obj.TYPE_CONST
1104                 p.From.Offset = int64(framesize) - objabi.StackSmall
1105                 p.To.Type = obj.TYPE_REG
1106                 p.To.Reg = tmp
1107
1108                 p = obj.Appendp(p, newprog)
1109                 p.As = AJCS
1110                 p.To.Type = obj.TYPE_BRANCH
1111                 q1 = p
1112
1113                 p = obj.Appendp(p, newprog)
1114                 p.As = cmp
1115                 p.From.Type = obj.TYPE_REG
1116                 p.From.Reg = tmp
1117                 p.To.Type = obj.TYPE_MEM
1118                 p.To.Reg = rg
1119                 p.To.Offset = 2 * int64(ctxt.Arch.PtrSize) // G.stackguard0
1120                 if cursym.CFunc() {
1121                         p.To.Offset = 3 * int64(ctxt.Arch.PtrSize) // G.stackguard1
1122                 }
1123         }
1124
1125         // common
1126         jls := obj.Appendp(p, newprog)
1127         jls.As = AJLS
1128         jls.To.Type = obj.TYPE_BRANCH
1129
1130         end := ctxt.EndUnsafePoint(jls, newprog, -1)
1131
1132         var last *obj.Prog
1133         for last = cursym.Func().Text; last.Link != nil; last = last.Link {
1134         }
1135
1136         // Now we are at the end of the function, but logically
1137         // we are still in function prologue. We need to fix the
1138         // SP data and PCDATA.
1139         spfix := obj.Appendp(last, newprog)
1140         spfix.As = obj.ANOP
1141         spfix.Spadj = -framesize
1142
1143         pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
1144         spill := ctxt.StartUnsafePoint(pcdata, newprog)
1145         pcdata = cursym.Func().SpillRegisterArgs(spill, newprog)
1146
1147         call := obj.Appendp(pcdata, newprog)
1148         call.Pos = cursym.Func().Text.Pos
1149         call.As = obj.ACALL
1150         call.To.Type = obj.TYPE_BRANCH
1151         call.To.Name = obj.NAME_EXTERN
1152         morestack := "runtime.morestack"
1153         switch {
1154         case cursym.CFunc():
1155                 morestack = "runtime.morestackc"
1156         case !cursym.Func().Text.From.Sym.NeedCtxt():
1157                 morestack = "runtime.morestack_noctxt"
1158         }
1159         call.To.Sym = ctxt.Lookup(morestack)
1160         // When compiling 386 code for dynamic linking, the call needs to be adjusted
1161         // to follow PIC rules. This in turn can insert more instructions, so we need
1162         // to keep track of the start of the call (where the jump will be to) and the
1163         // end (which following instructions are appended to).
1164         callend := call
1165         progedit(ctxt, callend, newprog)
1166         for ; callend.Link != nil; callend = callend.Link {
1167                 progedit(ctxt, callend.Link, newprog)
1168         }
1169
1170         pcdata = cursym.Func().UnspillRegisterArgs(callend, newprog)
1171         pcdata = ctxt.EndUnsafePoint(pcdata, newprog, -1)
1172
1173         jmp := obj.Appendp(pcdata, newprog)
1174         jmp.As = obj.AJMP
1175         jmp.To.Type = obj.TYPE_BRANCH
1176         jmp.To.SetTarget(cursym.Func().Text.Link)
1177         jmp.Spadj = +framesize
1178
1179         jls.To.SetTarget(spill)
1180         if q1 != nil {
1181                 q1.To.SetTarget(spill)
1182         }
1183
1184         return end
1185 }
1186
1187 func isR15(r int16) bool {
1188         return r == REG_R15 || r == REG_R15B
1189 }
1190 func addrMentionsR15(a *obj.Addr) bool {
1191         if a == nil {
1192                 return false
1193         }
1194         return isR15(a.Reg) || isR15(a.Index)
1195 }
1196 func progMentionsR15(p *obj.Prog) bool {
1197         return addrMentionsR15(&p.From) || addrMentionsR15(&p.To) || isR15(p.Reg) || addrMentionsR15(p.GetFrom3())
1198 }
1199
1200 // progOverwritesR15 reports whether p writes to R15 and does not depend on
1201 // the previous value of R15.
1202 func progOverwritesR15(p *obj.Prog) bool {
1203         if !(p.To.Type == obj.TYPE_REG && isR15(p.To.Reg)) {
1204                 // Not writing to R15.
1205                 return false
1206         }
1207         if (p.As == AXORL || p.As == AXORQ) && p.From.Type == obj.TYPE_REG && isR15(p.From.Reg) {
1208                 // These look like uses of R15, but aren't, so we must detect these
1209                 // before the use check below.
1210                 return true
1211         }
1212         if addrMentionsR15(&p.From) || isR15(p.Reg) || addrMentionsR15(p.GetFrom3()) {
1213                 // use before overwrite
1214                 return false
1215         }
1216         if p.As == AMOVL || p.As == AMOVQ || p.As == APOPQ {
1217                 return true
1218                 // TODO: MOVB might be ok if we only ever use R15B.
1219         }
1220         return false
1221 }
1222
1223 func addrUsesGlobal(a *obj.Addr) bool {
1224         if a == nil {
1225                 return false
1226         }
1227         return a.Name == obj.NAME_EXTERN && !a.Sym.Local()
1228 }
1229 func progUsesGlobal(p *obj.Prog) bool {
1230         if p.As == obj.ACALL || p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
1231                 // These opcodes don't use a GOT to access their argument (see rewriteToUseGot),
1232                 // or R15 would be dead at them anyway.
1233                 return false
1234         }
1235         if p.As == ALEAQ {
1236                 // The GOT entry is placed directly in the destination register; R15 is not used.
1237                 return false
1238         }
1239         return addrUsesGlobal(&p.From) || addrUsesGlobal(&p.To) || addrUsesGlobal(p.GetFrom3())
1240 }
1241
1242 func errorCheck(ctxt *obj.Link, s *obj.LSym) {
1243         // When dynamic linking, R15 is used to access globals. Reject code that
1244         // uses R15 after a global variable access.
1245         if !ctxt.Flag_dynlink {
1246                 return
1247         }
1248
1249         // Flood fill all the instructions where R15's value is junk.
1250         // If there are any uses of R15 in that set, report an error.
1251         var work []*obj.Prog
1252         var mentionsR15 bool
1253         for p := s.Func().Text; p != nil; p = p.Link {
1254                 if progUsesGlobal(p) {
1255                         work = append(work, p)
1256                         p.Mark |= markBit
1257                 }
1258                 if progMentionsR15(p) {
1259                         mentionsR15 = true
1260                 }
1261         }
1262         if mentionsR15 {
1263                 for len(work) > 0 {
1264                         p := work[len(work)-1]
1265                         work = work[:len(work)-1]
1266                         if q := p.To.Target(); q != nil && q.Mark&markBit == 0 {
1267                                 q.Mark |= markBit
1268                                 work = append(work, q)
1269                         }
1270                         if p.As == obj.AJMP || p.As == obj.ARET {
1271                                 continue // no fallthrough
1272                         }
1273                         if progMentionsR15(p) {
1274                                 if progOverwritesR15(p) {
1275                                         // R15 is overwritten by this instruction. Its value is not junk any more.
1276                                         continue
1277                                 }
1278                                 pos := ctxt.PosTable.Pos(p.Pos)
1279                                 ctxt.Diag("%s:%s: when dynamic linking, R15 is clobbered by a global variable access and is used here: %v", path.Base(pos.Filename()), pos.LineNumber(), p)
1280                                 break // only report one error
1281                         }
1282                         if q := p.Link; q != nil && q.Mark&markBit == 0 {
1283                                 q.Mark |= markBit
1284                                 work = append(work, q)
1285                         }
1286                 }
1287         }
1288
1289         // Clean up.
1290         for p := s.Func().Text; p != nil; p = p.Link {
1291                 p.Mark &^= markBit
1292         }
1293 }
1294
1295 var unaryDst = map[obj.As]bool{
1296         ABSWAPL:     true,
1297         ABSWAPQ:     true,
1298         ACLDEMOTE:   true,
1299         ACLFLUSH:    true,
1300         ACLFLUSHOPT: true,
1301         ACLWB:       true,
1302         ACMPXCHG16B: true,
1303         ACMPXCHG8B:  true,
1304         ADECB:       true,
1305         ADECL:       true,
1306         ADECQ:       true,
1307         ADECW:       true,
1308         AFBSTP:      true,
1309         AFFREE:      true,
1310         AFLDENV:     true,
1311         AFSAVE:      true,
1312         AFSTCW:      true,
1313         AFSTENV:     true,
1314         AFSTSW:      true,
1315         AFXSAVE64:   true,
1316         AFXSAVE:     true,
1317         AINCB:       true,
1318         AINCL:       true,
1319         AINCQ:       true,
1320         AINCW:       true,
1321         ANEGB:       true,
1322         ANEGL:       true,
1323         ANEGQ:       true,
1324         ANEGW:       true,
1325         ANOTB:       true,
1326         ANOTL:       true,
1327         ANOTQ:       true,
1328         ANOTW:       true,
1329         APOPL:       true,
1330         APOPQ:       true,
1331         APOPW:       true,
1332         ARDFSBASEL:  true,
1333         ARDFSBASEQ:  true,
1334         ARDGSBASEL:  true,
1335         ARDGSBASEQ:  true,
1336         ARDRANDL:    true,
1337         ARDRANDQ:    true,
1338         ARDRANDW:    true,
1339         ARDSEEDL:    true,
1340         ARDSEEDQ:    true,
1341         ARDSEEDW:    true,
1342         ASETCC:      true,
1343         ASETCS:      true,
1344         ASETEQ:      true,
1345         ASETGE:      true,
1346         ASETGT:      true,
1347         ASETHI:      true,
1348         ASETLE:      true,
1349         ASETLS:      true,
1350         ASETLT:      true,
1351         ASETMI:      true,
1352         ASETNE:      true,
1353         ASETOC:      true,
1354         ASETOS:      true,
1355         ASETPC:      true,
1356         ASETPL:      true,
1357         ASETPS:      true,
1358         ASGDT:       true,
1359         ASIDT:       true,
1360         ASLDTL:      true,
1361         ASLDTQ:      true,
1362         ASLDTW:      true,
1363         ASMSWL:      true,
1364         ASMSWQ:      true,
1365         ASMSWW:      true,
1366         ASTMXCSR:    true,
1367         ASTRL:       true,
1368         ASTRQ:       true,
1369         ASTRW:       true,
1370         AXSAVE64:    true,
1371         AXSAVE:      true,
1372         AXSAVEC64:   true,
1373         AXSAVEC:     true,
1374         AXSAVEOPT64: true,
1375         AXSAVEOPT:   true,
1376         AXSAVES64:   true,
1377         AXSAVES:     true,
1378 }
1379
1380 var Linkamd64 = obj.LinkArch{
1381         Arch:           sys.ArchAMD64,
1382         Init:           instinit,
1383         ErrorCheck:     errorCheck,
1384         Preprocess:     preprocess,
1385         Assemble:       span6,
1386         Progedit:       progedit,
1387         UnaryDst:       unaryDst,
1388         DWARFRegisters: AMD64DWARFRegisters,
1389 }
1390
1391 var Link386 = obj.LinkArch{
1392         Arch:           sys.Arch386,
1393         Init:           instinit,
1394         Preprocess:     preprocess,
1395         Assemble:       span6,
1396         Progedit:       progedit,
1397         UnaryDst:       unaryDst,
1398         DWARFRegisters: X86DWARFRegisters,
1399 }