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