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 "github.com/twitchyliquid64/golang-asm/obj"
35 "github.com/twitchyliquid64/golang-asm/objabi"
36 "github.com/twitchyliquid64/golang-asm/src"
37 "github.com/twitchyliquid64/golang-asm/sys"
38 "math"
39 "strings"
40 )
41
42 func CanUse1InsnTLS(ctxt *obj.Link) bool {
43 if isAndroid {
44
45 return false
46 }
47
48 if ctxt.Arch.Family == sys.I386 {
49 switch ctxt.Headtype {
50 case objabi.Hlinux,
51 objabi.Hplan9,
52 objabi.Hwindows:
53 return false
54 }
55
56 return true
57 }
58
59 switch ctxt.Headtype {
60 case objabi.Hplan9, objabi.Hwindows:
61 return false
62 case objabi.Hlinux, objabi.Hfreebsd:
63 return !ctxt.Flag_shared
64 }
65
66 return true
67 }
68
69 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
70
71
72
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 if CanUse1InsnTLS(ctxt) {
111
112
113
114
115
116
117
118
119
120
121
122 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 {
123 obj.Nopout(p)
124 }
125 if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
126 p.From.Reg = REG_TLS
127 p.From.Scale = 0
128 p.From.Index = REG_NONE
129 }
130
131 if p.To.Type == obj.TYPE_MEM && p.To.Index == REG_TLS && REG_AX <= p.To.Reg && p.To.Reg <= REG_R15 {
132 p.To.Reg = REG_TLS
133 p.To.Scale = 0
134 p.To.Index = REG_NONE
135 }
136 } else {
137
138
139
140
141
142
143 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 {
144 q := obj.Appendp(p, newprog)
145 q.As = p.As
146 q.From = p.From
147 q.From.Type = obj.TYPE_MEM
148 q.From.Reg = p.To.Reg
149 q.From.Index = REG_TLS
150 q.From.Scale = 2
151 q.To = p.To
152 p.From.Type = obj.TYPE_REG
153 p.From.Reg = REG_TLS
154 p.From.Index = REG_NONE
155 p.From.Offset = 0
156 }
157 }
158
159
160
161
162
163 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 {
164 p.From.Type = obj.TYPE_MEM
165 p.From.Name = obj.NAME_EXTERN
166 p.From.Reg = REG_NONE
167 p.From.Sym = ctxt.Lookup("runtime.tls_g")
168 p.From.Index = REG_NONE
169 }
170
171
172 if ctxt.Headtype == objabi.Hwindows && ctxt.Arch.Family == sys.AMD64 || ctxt.Headtype == objabi.Hplan9 {
173 if p.From.Scale == 1 && p.From.Index == REG_TLS {
174 p.From.Scale = 2
175 }
176 if p.To.Scale == 1 && p.To.Index == REG_TLS {
177 p.To.Scale = 2
178 }
179 }
180
181
182
183 switch p.As {
184 case ACMPPD, ACMPPS, ACMPSD, ACMPSS:
185 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 {
186 p.To.Type = obj.TYPE_CONST
187 }
188 }
189
190
191 switch p.As {
192 case obj.ACALL, obj.AJMP, obj.ARET:
193 if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
194 p.To.Type = obj.TYPE_BRANCH
195 }
196 }
197
198
199 if p.From.Type == obj.TYPE_ADDR && (ctxt.Arch.Family == sys.AMD64 || p.From.Name != obj.NAME_EXTERN && p.From.Name != obj.NAME_STATIC) {
200 switch p.As {
201 case AMOVL:
202 p.As = ALEAL
203 p.From.Type = obj.TYPE_MEM
204 case AMOVQ:
205 p.As = ALEAQ
206 p.From.Type = obj.TYPE_MEM
207 }
208 }
209
210
211 switch p.As {
212
213 case AMOVSS:
214 if p.From.Type == obj.TYPE_FCONST {
215
216 if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
217 if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
218 p.As = AXORPS
219 p.From = p.To
220 break
221 }
222 }
223 }
224 fallthrough
225
226 case AFMOVF,
227 AFADDF,
228 AFSUBF,
229 AFSUBRF,
230 AFMULF,
231 AFDIVF,
232 AFDIVRF,
233 AFCOMF,
234 AFCOMFP,
235 AADDSS,
236 ASUBSS,
237 AMULSS,
238 ADIVSS,
239 ACOMISS,
240 AUCOMISS:
241 if p.From.Type == obj.TYPE_FCONST {
242 f32 := float32(p.From.Val.(float64))
243 p.From.Type = obj.TYPE_MEM
244 p.From.Name = obj.NAME_EXTERN
245 p.From.Sym = ctxt.Float32Sym(f32)
246 p.From.Offset = 0
247 }
248
249 case AMOVSD:
250
251 if p.From.Type == obj.TYPE_FCONST {
252
253 if f := p.From.Val.(float64); math.Float64bits(f) == 0 {
254 if p.To.Type == obj.TYPE_REG && REG_X0 <= p.To.Reg && p.To.Reg <= REG_X15 {
255 p.As = AXORPS
256 p.From = p.To
257 break
258 }
259 }
260 }
261 fallthrough
262
263 case AFMOVD,
264 AFADDD,
265 AFSUBD,
266 AFSUBRD,
267 AFMULD,
268 AFDIVD,
269 AFDIVRD,
270 AFCOMD,
271 AFCOMDP,
272 AADDSD,
273 ASUBSD,
274 AMULSD,
275 ADIVSD,
276 ACOMISD,
277 AUCOMISD:
278 if p.From.Type == obj.TYPE_FCONST {
279 f64 := p.From.Val.(float64)
280 p.From.Type = obj.TYPE_MEM
281 p.From.Name = obj.NAME_EXTERN
282 p.From.Sym = ctxt.Float64Sym(f64)
283 p.From.Offset = 0
284 }
285 }
286
287 if ctxt.Flag_dynlink {
288 rewriteToUseGot(ctxt, p, newprog)
289 }
290
291 if ctxt.Flag_shared && ctxt.Arch.Family == sys.I386 {
292 rewriteToPcrel(ctxt, p, newprog)
293 }
294 }
295
296
297 func rewriteToUseGot(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
298 var lea, mov obj.As
299 var reg int16
300 if ctxt.Arch.Family == sys.AMD64 {
301 lea = ALEAQ
302 mov = AMOVQ
303 reg = REG_R15
304 } else {
305 lea = ALEAL
306 mov = AMOVL
307 reg = REG_CX
308 if p.As == ALEAL && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
309
310
311
312
313 reg = p.To.Reg
314 }
315 }
316
317 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
318
319
320
321
322
323
324
325 var sym *obj.LSym
326 if p.As == obj.ADUFFZERO {
327 sym = ctxt.Lookup("runtime.duffzero")
328 } else {
329 sym = ctxt.Lookup("runtime.duffcopy")
330 }
331 offset := p.To.Offset
332 p.As = mov
333 p.From.Type = obj.TYPE_MEM
334 p.From.Name = obj.NAME_GOTREF
335 p.From.Sym = sym
336 p.To.Type = obj.TYPE_REG
337 p.To.Reg = reg
338 p.To.Offset = 0
339 p.To.Sym = nil
340 p1 := obj.Appendp(p, newprog)
341 p1.As = lea
342 p1.From.Type = obj.TYPE_MEM
343 p1.From.Offset = offset
344 p1.From.Reg = reg
345 p1.To.Type = obj.TYPE_REG
346 p1.To.Reg = reg
347 p2 := obj.Appendp(p1, newprog)
348 p2.As = obj.ACALL
349 p2.To.Type = obj.TYPE_REG
350 p2.To.Reg = reg
351 }
352
353
354
355
356 if p.As == lea && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
357
358 p.As = mov
359 p.From.Type = obj.TYPE_ADDR
360 }
361 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
362
363
364
365 cmplxdest := false
366 pAs := p.As
367 var dest obj.Addr
368 if p.To.Type != obj.TYPE_REG || pAs != mov {
369 if ctxt.Arch.Family == sys.AMD64 {
370 ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
371 }
372 cmplxdest = true
373 dest = p.To
374 p.As = mov
375 p.To.Type = obj.TYPE_REG
376 p.To.Reg = reg
377 p.To.Sym = nil
378 p.To.Name = obj.NAME_NONE
379 }
380 p.From.Type = obj.TYPE_MEM
381 p.From.Name = obj.NAME_GOTREF
382 q := p
383 if p.From.Offset != 0 {
384 q = obj.Appendp(p, newprog)
385 q.As = lea
386 q.From.Type = obj.TYPE_MEM
387 q.From.Reg = p.To.Reg
388 q.From.Offset = p.From.Offset
389 q.To = p.To
390 p.From.Offset = 0
391 }
392 if cmplxdest {
393 q = obj.Appendp(q, newprog)
394 q.As = pAs
395 q.To = dest
396 q.From.Type = obj.TYPE_REG
397 q.From.Reg = reg
398 }
399 }
400 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
401 ctxt.Diag("don't know how to handle %v with -dynlink", p)
402 }
403 var source *obj.Addr
404
405
406
407 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
408 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
409 ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
410 }
411 source = &p.From
412 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
413 source = &p.To
414 } else {
415 return
416 }
417 if p.As == obj.ACALL {
418
419
420
421
422
423
424
425 if ctxt.Arch.Family == sys.AMD64 || (p.To.Sym != nil && p.To.Sym.Local()) || p.RegTo2 != 0 {
426 return
427 }
428 p1 := obj.Appendp(p, newprog)
429 p2 := obj.Appendp(p1, newprog)
430
431 p1.As = ALEAL
432 p1.From.Type = obj.TYPE_MEM
433 p1.From.Name = obj.NAME_STATIC
434 p1.From.Sym = ctxt.Lookup("_GLOBAL_OFFSET_TABLE_")
435 p1.To.Type = obj.TYPE_REG
436 p1.To.Reg = REG_BX
437
438 p2.As = p.As
439 p2.Scond = p.Scond
440 p2.From = p.From
441 if p.RestArgs != nil {
442 p2.RestArgs = append(p2.RestArgs, p.RestArgs...)
443 }
444 p2.Reg = p.Reg
445 p2.To = p.To
446
447
448
449 p2.To.Type = obj.TYPE_MEM
450 p2.RegTo2 = 1
451
452 obj.Nopout(p)
453 return
454
455 }
456 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ARET || p.As == obj.AJMP {
457 return
458 }
459 if source.Type != obj.TYPE_MEM {
460 ctxt.Diag("don't know how to handle %v with -dynlink", p)
461 }
462 p1 := obj.Appendp(p, newprog)
463 p2 := obj.Appendp(p1, newprog)
464
465 p1.As = mov
466 p1.From.Type = obj.TYPE_MEM
467 p1.From.Sym = source.Sym
468 p1.From.Name = obj.NAME_GOTREF
469 p1.To.Type = obj.TYPE_REG
470 p1.To.Reg = reg
471
472 p2.As = p.As
473 p2.From = p.From
474 p2.To = p.To
475 if p.From.Name == obj.NAME_EXTERN {
476 p2.From.Reg = reg
477 p2.From.Name = obj.NAME_NONE
478 p2.From.Sym = nil
479 } else if p.To.Name == obj.NAME_EXTERN {
480 p2.To.Reg = reg
481 p2.To.Name = obj.NAME_NONE
482 p2.To.Sym = nil
483 } else {
484 return
485 }
486 obj.Nopout(p)
487 }
488
489 func rewriteToPcrel(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
490
491
492 if p.RegTo2 != 0 {
493 return
494 }
495 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
496 return
497 }
498
499
500
501 isName := func(a *obj.Addr) bool {
502 if a.Sym == nil || (a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR) || a.Reg != 0 {
503 return false
504 }
505 if a.Sym.Type == objabi.STLSBSS {
506 return false
507 }
508 return a.Name == obj.NAME_EXTERN || a.Name == obj.NAME_STATIC || a.Name == obj.NAME_GOTREF
509 }
510
511 if isName(&p.From) && p.From.Type == obj.TYPE_ADDR {
512
513
514
515 if p.To.Type != obj.TYPE_REG {
516 q := obj.Appendp(p, newprog)
517 q.As = p.As
518 q.From.Type = obj.TYPE_REG
519 q.From.Reg = REG_CX
520 q.To = p.To
521 p.As = AMOVL
522 p.To.Type = obj.TYPE_REG
523 p.To.Reg = REG_CX
524 p.To.Sym = nil
525 p.To.Name = obj.NAME_NONE
526 }
527 }
528
529 if !isName(&p.From) && !isName(&p.To) && (p.GetFrom3() == nil || !isName(p.GetFrom3())) {
530 return
531 }
532 var dst int16 = REG_CX
533 if (p.As == ALEAL || p.As == AMOVL) && p.To.Reg != p.From.Reg && p.To.Reg != p.From.Index {
534 dst = p.To.Reg
535
536
537 }
538 q := obj.Appendp(p, newprog)
539 q.RegTo2 = 1
540 r := obj.Appendp(q, newprog)
541 r.RegTo2 = 1
542 q.As = obj.ACALL
543 thunkname := "__x86.get_pc_thunk." + strings.ToLower(rconv(int(dst)))
544 q.To.Sym = ctxt.LookupInit(thunkname, func(s *obj.LSym) { s.Set(obj.AttrLocal, true) })
545 q.To.Type = obj.TYPE_MEM
546 q.To.Name = obj.NAME_EXTERN
547 r.As = p.As
548 r.Scond = p.Scond
549 r.From = p.From
550 r.RestArgs = p.RestArgs
551 r.Reg = p.Reg
552 r.To = p.To
553 if isName(&p.From) {
554 r.From.Reg = dst
555 }
556 if isName(&p.To) {
557 r.To.Reg = dst
558 }
559 if p.GetFrom3() != nil && isName(p.GetFrom3()) {
560 r.GetFrom3().Reg = dst
561 }
562 obj.Nopout(p)
563 }
564
565 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
566 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
567 return
568 }
569
570 p := cursym.Func.Text
571 autoffset := int32(p.To.Offset)
572 if autoffset < 0 {
573 autoffset = 0
574 }
575
576 hasCall := false
577 for q := p; q != nil; q = q.Link {
578 if q.As == obj.ACALL || q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO {
579 hasCall = true
580 break
581 }
582 }
583
584 var bpsize int
585 if ctxt.Arch.Family == sys.AMD64 &&
586 !p.From.Sym.NoFrame() &&
587 !(autoffset == 0 && p.From.Sym.NoSplit()) &&
588 !(autoffset == 0 && !hasCall) {
589
590
591
592
593
594
595
596
597 bpsize = ctxt.Arch.PtrSize
598 autoffset += int32(bpsize)
599 p.To.Offset += int64(bpsize)
600 } else {
601 bpsize = 0
602 }
603
604 textarg := int64(p.To.Val.(int32))
605 cursym.Func.Args = int32(textarg)
606 cursym.Func.Locals = int32(p.To.Offset)
607
608
609 if ctxt.Arch.Family == sys.I386 && cursym.Func.Locals < 0 {
610 cursym.Func.Locals = 0
611 }
612
613
614 if ctxt.Arch.Family == sys.AMD64 && autoffset < objabi.StackSmall && !p.From.Sym.NoSplit() {
615 leaf := true
616 LeafSearch:
617 for q := p; q != nil; q = q.Link {
618 switch q.As {
619 case obj.ACALL:
620
621
622 if !isZeroArgRuntimeCall(q.To.Sym) {
623 leaf = false
624 break LeafSearch
625 }
626 fallthrough
627 case obj.ADUFFCOPY, obj.ADUFFZERO:
628 if autoffset >= objabi.StackSmall-8 {
629 leaf = false
630 break LeafSearch
631 }
632 }
633 }
634
635 if leaf {
636 p.From.Sym.Set(obj.AttrNoSplit, true)
637 }
638 }
639
640 if !p.From.Sym.NoSplit() || p.From.Sym.Wrapper() {
641 p = obj.Appendp(p, newprog)
642 p = load_g_cx(ctxt, p, newprog)
643 }
644
645 if !cursym.Func.Text.From.Sym.NoSplit() {
646 p = stacksplit(ctxt, cursym, p, newprog, autoffset, int32(textarg))
647 }
648
649
650
651 markedPrologue := false
652
653 if autoffset != 0 {
654 if autoffset%int32(ctxt.Arch.RegSize) != 0 {
655 ctxt.Diag("unaligned stack size %d", autoffset)
656 }
657 p = obj.Appendp(p, newprog)
658 p.As = AADJSP
659 p.From.Type = obj.TYPE_CONST
660 p.From.Offset = int64(autoffset)
661 p.Spadj = autoffset
662 p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
663 markedPrologue = true
664 }
665
666 if bpsize > 0 {
667
668 p = obj.Appendp(p, newprog)
669
670 p.As = AMOVQ
671 p.From.Type = obj.TYPE_REG
672 p.From.Reg = REG_BP
673 p.To.Type = obj.TYPE_MEM
674 p.To.Reg = REG_SP
675 p.To.Scale = 1
676 p.To.Offset = int64(autoffset) - int64(bpsize)
677 if !markedPrologue {
678 p.Pos = p.Pos.WithXlogue(src.PosPrologueEnd)
679 }
680
681
682 p = obj.Appendp(p, newprog)
683
684 p.As = ALEAQ
685 p.From.Type = obj.TYPE_MEM
686 p.From.Reg = REG_SP
687 p.From.Scale = 1
688 p.From.Offset = int64(autoffset) - int64(bpsize)
689 p.To.Type = obj.TYPE_REG
690 p.To.Reg = REG_BP
691 }
692
693 if cursym.Func.Text.From.Sym.Wrapper() {
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718 p = obj.Appendp(p, newprog)
719 p.As = AMOVQ
720 p.From.Type = obj.TYPE_MEM
721 p.From.Reg = REG_CX
722 p.From.Offset = 4 * int64(ctxt.Arch.PtrSize)
723 p.To.Type = obj.TYPE_REG
724 p.To.Reg = REG_BX
725 if ctxt.Arch.Family == sys.I386 {
726 p.As = AMOVL
727 }
728
729
730 p = obj.Appendp(p, newprog)
731 p.As = ATESTQ
732 p.From.Type = obj.TYPE_REG
733 p.From.Reg = REG_BX
734 p.To.Type = obj.TYPE_REG
735 p.To.Reg = REG_BX
736 if ctxt.Arch.Family == sys.I386 {
737 p.As = ATESTL
738 }
739
740
741 jne := obj.Appendp(p, newprog)
742 jne.As = AJNE
743 jne.To.Type = obj.TYPE_BRANCH
744
745
746
747 end := obj.Appendp(jne, newprog)
748 end.As = obj.ANOP
749
750
751 var last *obj.Prog
752 for last = end; last.Link != nil; last = last.Link {
753 }
754
755
756 p = obj.Appendp(last, newprog)
757 p.As = ALEAQ
758 p.From.Type = obj.TYPE_MEM
759 p.From.Reg = REG_SP
760 p.From.Offset = int64(autoffset) + int64(ctxt.Arch.RegSize)
761 p.To.Type = obj.TYPE_REG
762 p.To.Reg = REG_DI
763 if ctxt.Arch.Family == sys.I386 {
764 p.As = ALEAL
765 }
766
767
768 jne.To.SetTarget(p)
769
770
771 p = obj.Appendp(p, newprog)
772 p.As = ACMPQ
773 p.From.Type = obj.TYPE_MEM
774 p.From.Reg = REG_BX
775 p.From.Offset = 0
776 p.To.Type = obj.TYPE_REG
777 p.To.Reg = REG_DI
778 if ctxt.Arch.Family == sys.I386 {
779 p.As = ACMPL
780 }
781
782
783 p = obj.Appendp(p, newprog)
784 p.As = AJNE
785 p.To.Type = obj.TYPE_BRANCH
786 p.To.SetTarget(end)
787
788
789 p = obj.Appendp(p, newprog)
790 p.As = AMOVQ
791 p.From.Type = obj.TYPE_REG
792 p.From.Reg = REG_SP
793 p.To.Type = obj.TYPE_MEM
794 p.To.Reg = REG_BX
795 p.To.Offset = 0
796 if ctxt.Arch.Family == sys.I386 {
797 p.As = AMOVL
798 }
799
800
801 p = obj.Appendp(p, newprog)
802 p.As = obj.AJMP
803 p.To.Type = obj.TYPE_BRANCH
804 p.To.SetTarget(end)
805
806
807 p = end
808 }
809
810 var deltasp int32
811 for p = cursym.Func.Text; p != nil; p = p.Link {
812 pcsize := ctxt.Arch.RegSize
813 switch p.From.Name {
814 case obj.NAME_AUTO:
815 p.From.Offset += int64(deltasp) - int64(bpsize)
816 case obj.NAME_PARAM:
817 p.From.Offset += int64(deltasp) + int64(pcsize)
818 }
819 if p.GetFrom3() != nil {
820 switch p.GetFrom3().Name {
821 case obj.NAME_AUTO:
822 p.GetFrom3().Offset += int64(deltasp) - int64(bpsize)
823 case obj.NAME_PARAM:
824 p.GetFrom3().Offset += int64(deltasp) + int64(pcsize)
825 }
826 }
827 switch p.To.Name {
828 case obj.NAME_AUTO:
829 p.To.Offset += int64(deltasp) - int64(bpsize)
830 case obj.NAME_PARAM:
831 p.To.Offset += int64(deltasp) + int64(pcsize)
832 }
833
834 switch p.As {
835 default:
836 continue
837
838 case APUSHL, APUSHFL:
839 deltasp += 4
840 p.Spadj = 4
841 continue
842
843 case APUSHQ, APUSHFQ:
844 deltasp += 8
845 p.Spadj = 8
846 continue
847
848 case APUSHW, APUSHFW:
849 deltasp += 2
850 p.Spadj = 2
851 continue
852
853 case APOPL, APOPFL:
854 deltasp -= 4
855 p.Spadj = -4
856 continue
857
858 case APOPQ, APOPFQ:
859 deltasp -= 8
860 p.Spadj = -8
861 continue
862
863 case APOPW, APOPFW:
864 deltasp -= 2
865 p.Spadj = -2
866 continue
867
868 case AADJSP:
869 p.Spadj = int32(p.From.Offset)
870 deltasp += int32(p.From.Offset)
871 continue
872
873 case obj.ARET:
874
875 }
876
877 if autoffset != deltasp {
878 ctxt.Diag("unbalanced PUSH/POP")
879 }
880
881 if autoffset != 0 {
882 to := p.To
883 p.To = obj.Addr{}
884 if bpsize > 0 {
885
886 p.As = AMOVQ
887
888 p.From.Type = obj.TYPE_MEM
889 p.From.Reg = REG_SP
890 p.From.Scale = 1
891 p.From.Offset = int64(autoffset) - int64(bpsize)
892 p.To.Type = obj.TYPE_REG
893 p.To.Reg = REG_BP
894 p = obj.Appendp(p, newprog)
895 }
896
897 p.As = AADJSP
898 p.From.Type = obj.TYPE_CONST
899 p.From.Offset = int64(-autoffset)
900 p.Spadj = -autoffset
901 p = obj.Appendp(p, newprog)
902 p.As = obj.ARET
903 p.To = to
904
905
906
907
908
909 p.Spadj = +autoffset
910 }
911
912 if p.To.Sym != nil {
913 p.As = obj.AJMP
914 }
915 }
916 }
917
918 func isZeroArgRuntimeCall(s *obj.LSym) bool {
919 if s == nil {
920 return false
921 }
922 switch s.Name {
923 case "runtime.panicdivide", "runtime.panicwrap", "runtime.panicshift":
924 return true
925 }
926 if strings.HasPrefix(s.Name, "runtime.panicIndex") || strings.HasPrefix(s.Name, "runtime.panicSlice") {
927
928
929
930 return true
931 }
932 return false
933 }
934
935 func indir_cx(ctxt *obj.Link, a *obj.Addr) {
936 a.Type = obj.TYPE_MEM
937 a.Reg = REG_CX
938 }
939
940
941
942
943
944
945 func load_g_cx(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) *obj.Prog {
946 p.As = AMOVQ
947 if ctxt.Arch.PtrSize == 4 {
948 p.As = AMOVL
949 }
950 p.From.Type = obj.TYPE_MEM
951 p.From.Reg = REG_TLS
952 p.From.Offset = 0
953 p.To.Type = obj.TYPE_REG
954 p.To.Reg = REG_CX
955
956 next := p.Link
957 progedit(ctxt, p, newprog)
958 for p.Link != next {
959 p = p.Link
960 progedit(ctxt, p, newprog)
961 }
962
963 if p.From.Index == REG_TLS {
964 p.From.Scale = 2
965 }
966
967 return p
968 }
969
970
971
972
973
974 func stacksplit(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog, newprog obj.ProgAlloc, framesize int32, textarg int32) *obj.Prog {
975 cmp := ACMPQ
976 lea := ALEAQ
977 mov := AMOVQ
978 sub := ASUBQ
979
980 if ctxt.Arch.Family == sys.I386 {
981 cmp = ACMPL
982 lea = ALEAL
983 mov = AMOVL
984 sub = ASUBL
985 }
986
987 var q1 *obj.Prog
988 if framesize <= objabi.StackSmall {
989
990
991 p = obj.Appendp(p, newprog)
992
993 p.As = cmp
994 p.From.Type = obj.TYPE_REG
995 p.From.Reg = REG_SP
996 indir_cx(ctxt, &p.To)
997 p.To.Offset = 2 * int64(ctxt.Arch.PtrSize)
998 if cursym.CFunc() {
999 p.To.Offset = 3 * int64(ctxt.Arch.PtrSize)
1000 }
1001
1002
1003
1004
1005
1006 p = ctxt.StartUnsafePoint(p, newprog)
1007 } else if framesize <= objabi.StackBig {
1008
1009
1010
1011 p = obj.Appendp(p, newprog)
1012
1013 p.As = lea
1014 p.From.Type = obj.TYPE_MEM
1015 p.From.Reg = REG_SP
1016 p.From.Offset = -(int64(framesize) - objabi.StackSmall)
1017 p.To.Type = obj.TYPE_REG
1018 p.To.Reg = REG_AX
1019
1020 p = obj.Appendp(p, newprog)
1021 p.As = cmp
1022 p.From.Type = obj.TYPE_REG
1023 p.From.Reg = REG_AX
1024 indir_cx(ctxt, &p.To)
1025 p.To.Offset = 2 * int64(ctxt.Arch.PtrSize)
1026 if cursym.CFunc() {
1027 p.To.Offset = 3 * int64(ctxt.Arch.PtrSize)
1028 }
1029
1030 p = ctxt.StartUnsafePoint(p, newprog)
1031 } else {
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047 p = obj.Appendp(p, newprog)
1048
1049 p.As = mov
1050 indir_cx(ctxt, &p.From)
1051 p.From.Offset = 2 * int64(ctxt.Arch.PtrSize)
1052 if cursym.CFunc() {
1053 p.From.Offset = 3 * int64(ctxt.Arch.PtrSize)
1054 }
1055 p.To.Type = obj.TYPE_REG
1056 p.To.Reg = REG_SI
1057
1058 p = ctxt.StartUnsafePoint(p, newprog)
1059
1060 p = obj.Appendp(p, newprog)
1061 p.As = cmp
1062 p.From.Type = obj.TYPE_REG
1063 p.From.Reg = REG_SI
1064 p.To.Type = obj.TYPE_CONST
1065 p.To.Offset = objabi.StackPreempt
1066 if ctxt.Arch.Family == sys.I386 {
1067 p.To.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
1068 }
1069
1070 p = obj.Appendp(p, newprog)
1071 p.As = AJEQ
1072 p.To.Type = obj.TYPE_BRANCH
1073 q1 = p
1074
1075 p = obj.Appendp(p, newprog)
1076 p.As = lea
1077 p.From.Type = obj.TYPE_MEM
1078 p.From.Reg = REG_SP
1079 p.From.Offset = int64(objabi.StackGuard)
1080 p.To.Type = obj.TYPE_REG
1081 p.To.Reg = REG_AX
1082
1083 p = obj.Appendp(p, newprog)
1084 p.As = sub
1085 p.From.Type = obj.TYPE_REG
1086 p.From.Reg = REG_SI
1087 p.To.Type = obj.TYPE_REG
1088 p.To.Reg = REG_AX
1089
1090 p = obj.Appendp(p, newprog)
1091 p.As = cmp
1092 p.From.Type = obj.TYPE_REG
1093 p.From.Reg = REG_AX
1094 p.To.Type = obj.TYPE_CONST
1095 p.To.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
1096 }
1097
1098
1099 jls := obj.Appendp(p, newprog)
1100 jls.As = AJLS
1101 jls.To.Type = obj.TYPE_BRANCH
1102
1103 end := ctxt.EndUnsafePoint(jls, newprog, -1)
1104
1105 var last *obj.Prog
1106 for last = cursym.Func.Text; last.Link != nil; last = last.Link {
1107 }
1108
1109
1110
1111
1112 spfix := obj.Appendp(last, newprog)
1113 spfix.As = obj.ANOP
1114 spfix.Spadj = -framesize
1115
1116 pcdata := ctxt.EmitEntryStackMap(cursym, spfix, newprog)
1117 pcdata = ctxt.StartUnsafePoint(pcdata, newprog)
1118
1119 call := obj.Appendp(pcdata, newprog)
1120 call.Pos = cursym.Func.Text.Pos
1121 call.As = obj.ACALL
1122 call.To.Type = obj.TYPE_BRANCH
1123 call.To.Name = obj.NAME_EXTERN
1124 morestack := "runtime.morestack"
1125 switch {
1126 case cursym.CFunc():
1127 morestack = "runtime.morestackc"
1128 case !cursym.Func.Text.From.Sym.NeedCtxt():
1129 morestack = "runtime.morestack_noctxt"
1130 }
1131 call.To.Sym = ctxt.Lookup(morestack)
1132
1133
1134
1135
1136 callend := call
1137 progedit(ctxt, callend, newprog)
1138 for ; callend.Link != nil; callend = callend.Link {
1139 progedit(ctxt, callend.Link, newprog)
1140 }
1141
1142 pcdata = ctxt.EndUnsafePoint(callend, newprog, -1)
1143
1144 jmp := obj.Appendp(pcdata, newprog)
1145 jmp.As = obj.AJMP
1146 jmp.To.Type = obj.TYPE_BRANCH
1147 jmp.To.SetTarget(cursym.Func.Text.Link)
1148 jmp.Spadj = +framesize
1149
1150 jls.To.SetTarget(call)
1151 if q1 != nil {
1152 q1.To.SetTarget(call)
1153 }
1154
1155 return end
1156 }
1157
1158 var unaryDst = map[obj.As]bool{
1159 ABSWAPL: true,
1160 ABSWAPQ: true,
1161 ACLDEMOTE: true,
1162 ACLFLUSH: true,
1163 ACLFLUSHOPT: true,
1164 ACLWB: true,
1165 ACMPXCHG16B: true,
1166 ACMPXCHG8B: true,
1167 ADECB: true,
1168 ADECL: true,
1169 ADECQ: true,
1170 ADECW: true,
1171 AFBSTP: true,
1172 AFFREE: true,
1173 AFLDENV: true,
1174 AFSAVE: true,
1175 AFSTCW: true,
1176 AFSTENV: true,
1177 AFSTSW: true,
1178 AFXSAVE64: true,
1179 AFXSAVE: true,
1180 AINCB: true,
1181 AINCL: true,
1182 AINCQ: true,
1183 AINCW: true,
1184 ANEGB: true,
1185 ANEGL: true,
1186 ANEGQ: true,
1187 ANEGW: true,
1188 ANOTB: true,
1189 ANOTL: true,
1190 ANOTQ: true,
1191 ANOTW: true,
1192 APOPL: true,
1193 APOPQ: true,
1194 APOPW: true,
1195 ARDFSBASEL: true,
1196 ARDFSBASEQ: true,
1197 ARDGSBASEL: true,
1198 ARDGSBASEQ: true,
1199 ARDRANDL: true,
1200 ARDRANDQ: true,
1201 ARDRANDW: true,
1202 ARDSEEDL: true,
1203 ARDSEEDQ: true,
1204 ARDSEEDW: true,
1205 ASETCC: true,
1206 ASETCS: true,
1207 ASETEQ: true,
1208 ASETGE: true,
1209 ASETGT: true,
1210 ASETHI: true,
1211 ASETLE: true,
1212 ASETLS: true,
1213 ASETLT: true,
1214 ASETMI: true,
1215 ASETNE: true,
1216 ASETOC: true,
1217 ASETOS: true,
1218 ASETPC: true,
1219 ASETPL: true,
1220 ASETPS: true,
1221 ASGDT: true,
1222 ASIDT: true,
1223 ASLDTL: true,
1224 ASLDTQ: true,
1225 ASLDTW: true,
1226 ASMSWL: true,
1227 ASMSWQ: true,
1228 ASMSWW: true,
1229 ASTMXCSR: true,
1230 ASTRL: true,
1231 ASTRQ: true,
1232 ASTRW: true,
1233 AXSAVE64: true,
1234 AXSAVE: true,
1235 AXSAVEC64: true,
1236 AXSAVEC: true,
1237 AXSAVEOPT64: true,
1238 AXSAVEOPT: true,
1239 AXSAVES64: true,
1240 AXSAVES: true,
1241 }
1242
1243 var Linkamd64 = obj.LinkArch{
1244 Arch: sys.ArchAMD64,
1245 Init: instinit,
1246 Preprocess: preprocess,
1247 Assemble: span6,
1248 Progedit: progedit,
1249 UnaryDst: unaryDst,
1250 DWARFRegisters: AMD64DWARFRegisters,
1251 }
1252
1253 var Link386 = obj.LinkArch{
1254 Arch: sys.Arch386,
1255 Init: instinit,
1256 Preprocess: preprocess,
1257 Assemble: span6,
1258 Progedit: progedit,
1259 UnaryDst: unaryDst,
1260 DWARFRegisters: X86DWARFRegisters,
1261 }
1262
View as plain text