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