1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 if CanUse1InsnTLS(ctxt) {
114
115
116
117
118
119
120
121
122
123
124
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
141
142
143
144
145
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
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
163
164
165
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
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
185
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
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
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
214 switch p.As {
215
216 case AMOVSS:
217 if p.From.Type == obj.TYPE_FCONST {
218
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
254 if p.From.Type == obj.TYPE_FCONST {
255
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
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
313
314
315
316 reg = p.To.Reg
317 }
318 }
319
320 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
321
322
323
324
325
326
327
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
357
358
359 if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
360
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
366
367
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
408
409
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
422
423
424
425
426
427
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
450
451
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
494
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
502
503
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
516
517
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
539
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
569 const (
570 markBit = 1 << 0
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() &&
595 !(autoffset == 0 && p.From.Sym.NoSplit()) &&
596 !(autoffset == 0 && !hasCall) {
597
598
599
600
601
602
603
604
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
617 if ctxt.Arch.Family == sys.I386 && cursym.Func().Locals < 0 {
618 cursym.Func().Locals = 0
619 }
620
621
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
629
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
652 } else {
653 p = obj.Appendp(p, newprog)
654 regg = REG_CX
655 if ctxt.Arch.Family == sys.AMD64 {
656
657 regg = REGG
658 }
659 p = load_g(ctxt, p, newprog, 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)
671 }
672
673
674
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
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
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
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
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)
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
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
765 jne := obj.Appendp(p, newprog)
766 jne.As = AJNE
767 jne.To.Type = obj.TYPE_BRANCH
768
769
770
771 end := obj.Appendp(jne, newprog)
772 end.As = obj.ANOP
773
774
775 var last *obj.Prog
776 for last = end; last.Link != nil; last = last.Link {
777 }
778
779
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
792 jne.To.SetTarget(p)
793
794
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
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
807 p = obj.Appendp(p, newprog)
808 p.As = AJNE
809 p.To.Type = obj.TYPE_BRANCH
810 p.To.SetTarget(end)
811
812
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
820 if ctxt.Arch.Family == sys.I386 {
821 p.As = AMOVL
822 }
823
824
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
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
913 }
914
915 if autoffset != deltasp {
916 ctxt.Diag("%s: unbalanced PUSH/POP", cursym)
917 }
918
919 if autoffset != 0 {
920 to := p.To
921 p.To = obj.Addr{}
922 if bpsize > 0 {
923
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
944
945
946
947 p.Spadj = +autoffset
948 }
949
950 if p.To.Sym != nil {
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
966
967
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
979
980
981
982
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
1009
1010
1011
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)
1026 if ctxt.Arch.Family == sys.AMD64 {
1027
1028 tmp = int16(REGENTRYTMP0)
1029 }
1030
1031 var q1 *obj.Prog
1032 if framesize <= objabi.StackSmall {
1033
1034
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)
1043 if cursym.CFunc() {
1044 p.To.Offset = 3 * int64(ctxt.Arch.PtrSize)
1045 }
1046
1047
1048
1049
1050
1051 p = ctxt.StartUnsafePoint(p, newprog)
1052 } else if framesize <= objabi.StackBig {
1053
1054
1055
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)
1072 if cursym.CFunc() {
1073 p.To.Offset = 3 * int64(ctxt.Arch.PtrSize)
1074 }
1075
1076 p = ctxt.StartUnsafePoint(p, newprog)
1077 } else {
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
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)
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)
1120 if cursym.CFunc() {
1121 p.To.Offset = 3 * int64(ctxt.Arch.PtrSize)
1122 }
1123 }
1124
1125
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
1137
1138
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
1161
1162
1163
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
1201
1202 func progOverwritesR15(p *obj.Prog) bool {
1203 if !(p.To.Type == obj.TYPE_REG && isR15(p.To.Reg)) {
1204
1205 return false
1206 }
1207 if (p.As == AXORL || p.As == AXORQ) && p.From.Type == obj.TYPE_REG && isR15(p.From.Reg) {
1208
1209
1210 return true
1211 }
1212 if addrMentionsR15(&p.From) || isR15(p.Reg) || addrMentionsR15(p.GetFrom3()) {
1213
1214 return false
1215 }
1216 if p.As == AMOVL || p.As == AMOVQ || p.As == APOPQ {
1217 return true
1218
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
1232
1233 return false
1234 }
1235 if p.As == ALEAQ {
1236
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
1244
1245 if !ctxt.Flag_dynlink {
1246 return
1247 }
1248
1249
1250
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
1272 }
1273 if progMentionsR15(p) {
1274 if progOverwritesR15(p) {
1275
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
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
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 }
1400
View as plain text