Source file src/pkg/cmd/internal/obj/arm/obj5.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 arm
32
33 import (
34 "cmd/internal/obj"
35 "cmd/internal/objabi"
36 "cmd/internal/sys"
37 )
38
39 var progedit_tlsfallback *obj.LSym
40
41 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
42 p.From.Class = 0
43 p.To.Class = 0
44
45 c := ctxt5{ctxt: ctxt, newprog: newprog}
46
47
48 switch p.As {
49 case AB, ABL, obj.ADUFFZERO, obj.ADUFFCOPY:
50 if p.To.Type == obj.TYPE_MEM && (p.To.Name == obj.NAME_EXTERN || p.To.Name == obj.NAME_STATIC) && p.To.Sym != nil {
51 p.To.Type = obj.TYPE_BRANCH
52 }
53 }
54
55
56 switch p.As {
57
58 case AMRC:
59 if p.To.Offset&0xffff0fff == 0xee1d0f70 {
60
61
62 if p.To.Offset&0xf000 != 0 {
63 ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
64 }
65
66 if objabi.GOARM < 7 {
67
68 if progedit_tlsfallback == nil {
69 progedit_tlsfallback = ctxt.Lookup("runtime.read_tls_fallback")
70 }
71
72
73 p.As = AMOVW
74
75 p.From.Type = obj.TYPE_REG
76 p.From.Reg = REGLINK
77 p.To.Type = obj.TYPE_REG
78 p.To.Reg = REGTMP
79
80
81 p = obj.Appendp(p, newprog)
82
83 p.As = ABL
84 p.To.Type = obj.TYPE_BRANCH
85 p.To.Sym = progedit_tlsfallback
86 p.To.Offset = 0
87
88
89 p = obj.Appendp(p, newprog)
90
91 p.As = AMOVW
92 p.From.Type = obj.TYPE_REG
93 p.From.Reg = REGTMP
94 p.To.Type = obj.TYPE_REG
95 p.To.Reg = REGLINK
96 break
97 }
98 }
99
100
101 p.As = AWORD
102 }
103
104
105 switch p.As {
106 case AMOVF:
107 if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
108 f32 := float32(p.From.Val.(float64))
109 p.From.Type = obj.TYPE_MEM
110 p.From.Sym = ctxt.Float32Sym(f32)
111 p.From.Name = obj.NAME_EXTERN
112 p.From.Offset = 0
113 }
114
115 case AMOVD:
116 if p.From.Type == obj.TYPE_FCONST && c.chipfloat5(p.From.Val.(float64)) < 0 && (c.chipzero5(p.From.Val.(float64)) < 0 || p.Scond&C_SCOND != C_SCOND_NONE) {
117 p.From.Type = obj.TYPE_MEM
118 p.From.Sym = ctxt.Float64Sym(p.From.Val.(float64))
119 p.From.Name = obj.NAME_EXTERN
120 p.From.Offset = 0
121 }
122 }
123
124 if ctxt.Flag_dynlink {
125 c.rewriteToUseGot(p)
126 }
127 }
128
129
130 func (c *ctxt5) rewriteToUseGot(p *obj.Prog) {
131 if p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO {
132
133
134
135
136
137 var sym *obj.LSym
138 if p.As == obj.ADUFFZERO {
139 sym = c.ctxt.Lookup("runtime.duffzero")
140 } else {
141 sym = c.ctxt.Lookup("runtime.duffcopy")
142 }
143 offset := p.To.Offset
144 p.As = AMOVW
145 p.From.Type = obj.TYPE_MEM
146 p.From.Name = obj.NAME_GOTREF
147 p.From.Sym = sym
148 p.To.Type = obj.TYPE_REG
149 p.To.Reg = REG_R9
150 p.To.Name = obj.NAME_NONE
151 p.To.Offset = 0
152 p.To.Sym = nil
153 p1 := obj.Appendp(p, c.newprog)
154 p1.As = AADD
155 p1.From.Type = obj.TYPE_CONST
156 p1.From.Offset = offset
157 p1.To.Type = obj.TYPE_REG
158 p1.To.Reg = REG_R9
159 p2 := obj.Appendp(p1, c.newprog)
160 p2.As = obj.ACALL
161 p2.To.Type = obj.TYPE_MEM
162 p2.To.Reg = REG_R9
163 return
164 }
165
166
167
168
169 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
170
171
172 if p.As != AMOVW {
173 c.ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
174 }
175 if p.To.Type != obj.TYPE_REG {
176 c.ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
177 }
178 p.From.Type = obj.TYPE_MEM
179 p.From.Name = obj.NAME_GOTREF
180 if p.From.Offset != 0 {
181 q := obj.Appendp(p, c.newprog)
182 q.As = AADD
183 q.From.Type = obj.TYPE_CONST
184 q.From.Offset = p.From.Offset
185 q.To = p.To
186 p.From.Offset = 0
187 }
188 }
189 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
190 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
191 }
192 var source *obj.Addr
193
194
195
196 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
197 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
198 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
199 }
200 source = &p.From
201 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
202 source = &p.To
203 } else {
204 return
205 }
206 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
207 return
208 }
209 if source.Sym.Type == objabi.STLSBSS {
210 return
211 }
212 if source.Type != obj.TYPE_MEM {
213 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
214 }
215 p1 := obj.Appendp(p, c.newprog)
216 p2 := obj.Appendp(p1, c.newprog)
217
218 p1.As = AMOVW
219 p1.From.Type = obj.TYPE_MEM
220 p1.From.Sym = source.Sym
221 p1.From.Name = obj.NAME_GOTREF
222 p1.To.Type = obj.TYPE_REG
223 p1.To.Reg = REG_R9
224
225 p2.As = p.As
226 p2.From = p.From
227 p2.To = p.To
228 if p.From.Name == obj.NAME_EXTERN {
229 p2.From.Reg = REG_R9
230 p2.From.Name = obj.NAME_NONE
231 p2.From.Sym = nil
232 } else if p.To.Name == obj.NAME_EXTERN {
233 p2.To.Reg = REG_R9
234 p2.To.Name = obj.NAME_NONE
235 p2.To.Sym = nil
236 } else {
237 return
238 }
239 obj.Nopout(p)
240 }
241
242
243 const (
244 FOLL = 1 << 0
245 LABEL = 1 << 1
246 LEAF = 1 << 2
247 )
248
249 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
250 autosize := int32(0)
251
252 if cursym.Func.Text == nil || cursym.Func.Text.Link == nil {
253 return
254 }
255
256 c := ctxt5{ctxt: ctxt, cursym: cursym, newprog: newprog}
257
258 p := c.cursym.Func.Text
259 autoffset := int32(p.To.Offset)
260 if autoffset == -4 {
261
262 p.From.Sym.Set(obj.AttrNoFrame, true)
263 autoffset = 0
264 }
265 if autoffset < 0 || autoffset%4 != 0 {
266 c.ctxt.Diag("frame size %d not 0 or a positive multiple of 4", autoffset)
267 }
268 if p.From.Sym.NoFrame() {
269 if autoffset != 0 {
270 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", autoffset)
271 }
272 }
273
274 cursym.Func.Locals = autoffset
275 cursym.Func.Args = p.To.Val.(int32)
276
277
283 var q1 *obj.Prog
284 var q *obj.Prog
285 for p := cursym.Func.Text; p != nil; p = p.Link {
286 switch p.As {
287 case obj.ATEXT:
288 p.Mark |= LEAF
289
290 case obj.ARET:
291 break
292
293 case ADIV, ADIVU, AMOD, AMODU:
294 q = p
295 cursym.Func.Text.Mark &^= LEAF
296 continue
297
298 case obj.ANOP:
299 q1 = p.Link
300 q.Link = q1
301 if q1 != nil {
302 q1.Mark |= p.Mark
303 }
304 continue
305
306 case ABL,
307 ABX,
308 obj.ADUFFZERO,
309 obj.ADUFFCOPY:
310 cursym.Func.Text.Mark &^= LEAF
311 fallthrough
312
313 case AB,
314 ABEQ,
315 ABNE,
316 ABCS,
317 ABHS,
318 ABCC,
319 ABLO,
320 ABMI,
321 ABPL,
322 ABVS,
323 ABVC,
324 ABHI,
325 ABLS,
326 ABGE,
327 ABLT,
328 ABGT,
329 ABLE:
330 q1 = p.Pcond
331 if q1 != nil {
332 for q1.As == obj.ANOP {
333 q1 = q1.Link
334 p.Pcond = q1
335 }
336 }
337 }
338
339 q = p
340 }
341
342 var q2 *obj.Prog
343 for p := cursym.Func.Text; p != nil; p = p.Link {
344 o := p.As
345 switch o {
346 case obj.ATEXT:
347 autosize = autoffset
348
349 if p.Mark&LEAF != 0 && autosize == 0 {
350
351 p.From.Sym.Set(obj.AttrNoFrame, true)
352 }
353
354 if !p.From.Sym.NoFrame() {
355
356
357 autosize += 4
358 }
359
360 if autosize == 0 && cursym.Func.Text.Mark&LEAF == 0 {
361
362
363 if ctxt.Debugvlog {
364 ctxt.Logf("save suppressed in: %s\n", cursym.Name)
365 }
366
367 cursym.Func.Text.Mark |= LEAF
368 }
369
370
371 p.To.Offset = int64(autosize) - 4
372
373 if cursym.Func.Text.Mark&LEAF != 0 {
374 cursym.Set(obj.AttrLeaf, true)
375 if p.From.Sym.NoFrame() {
376 break
377 }
378 }
379
380 if !p.From.Sym.NoSplit() {
381 p = c.stacksplit(p, autosize)
382 }
383
384
385 p = obj.Appendp(p, c.newprog)
386
387 p.As = AMOVW
388 p.Scond |= C_WBIT
389 p.From.Type = obj.TYPE_REG
390 p.From.Reg = REGLINK
391 p.To.Type = obj.TYPE_MEM
392 p.To.Offset = int64(-autosize)
393 p.To.Reg = REGSP
394 p.Spadj = autosize
395
396 if cursym.Func.Text.From.Sym.Wrapper() {
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417 p = obj.Appendp(p, newprog)
418 p.As = AMOVW
419 p.From.Type = obj.TYPE_MEM
420 p.From.Reg = REGG
421 p.From.Offset = 4 * int64(ctxt.Arch.PtrSize)
422 p.To.Type = obj.TYPE_REG
423 p.To.Reg = REG_R1
424
425 p = obj.Appendp(p, newprog)
426 p.As = ACMP
427 p.From.Type = obj.TYPE_CONST
428 p.From.Offset = 0
429 p.Reg = REG_R1
430
431
432 bne := obj.Appendp(p, newprog)
433 bne.As = ABNE
434 bne.To.Type = obj.TYPE_BRANCH
435
436
437 end := obj.Appendp(bne, newprog)
438 end.As = obj.ANOP
439
440
441 var last *obj.Prog
442 for last = end; last.Link != nil; last = last.Link {
443 }
444
445
446 mov := obj.Appendp(last, newprog)
447 mov.As = AMOVW
448 mov.From.Type = obj.TYPE_MEM
449 mov.From.Reg = REG_R1
450 mov.From.Offset = 0
451 mov.To.Type = obj.TYPE_REG
452 mov.To.Reg = REG_R2
453
454
455 bne.Pcond = mov
456
457
458 p = obj.Appendp(mov, newprog)
459 p.As = AADD
460 p.From.Type = obj.TYPE_CONST
461 p.From.Offset = int64(autosize) + 4
462 p.Reg = REG_R13
463 p.To.Type = obj.TYPE_REG
464 p.To.Reg = REG_R3
465
466
467 p = obj.Appendp(p, newprog)
468 p.As = ACMP
469 p.From.Type = obj.TYPE_REG
470 p.From.Reg = REG_R2
471 p.Reg = REG_R3
472
473
474 p = obj.Appendp(p, newprog)
475 p.As = ABNE
476 p.To.Type = obj.TYPE_BRANCH
477 p.Pcond = end
478
479
480 p = obj.Appendp(p, newprog)
481 p.As = AADD
482 p.From.Type = obj.TYPE_CONST
483 p.From.Offset = 4
484 p.Reg = REG_R13
485 p.To.Type = obj.TYPE_REG
486 p.To.Reg = REG_R4
487
488
489 p = obj.Appendp(p, newprog)
490 p.As = AMOVW
491 p.From.Type = obj.TYPE_REG
492 p.From.Reg = REG_R4
493 p.To.Type = obj.TYPE_MEM
494 p.To.Reg = REG_R1
495 p.To.Offset = 0
496
497
498 p = obj.Appendp(p, newprog)
499 p.As = AB
500 p.To.Type = obj.TYPE_BRANCH
501 p.Pcond = end
502
503
504 p = end
505 }
506
507 case obj.ARET:
508 nocache(p)
509 if cursym.Func.Text.Mark&LEAF != 0 {
510 if autosize == 0 {
511 p.As = AB
512 p.From = obj.Addr{}
513 if p.To.Sym != nil {
514 p.To.Type = obj.TYPE_BRANCH
515 } else {
516 p.To.Type = obj.TYPE_MEM
517 p.To.Offset = 0
518 p.To.Reg = REGLINK
519 }
520
521 break
522 }
523 }
524
525 p.As = AMOVW
526 p.Scond |= C_PBIT
527 p.From.Type = obj.TYPE_MEM
528 p.From.Offset = int64(autosize)
529 p.From.Reg = REGSP
530 p.To.Type = obj.TYPE_REG
531 p.To.Reg = REGPC
532
533
534
535
536 if p.To.Sym != nil {
537 p.To.Reg = REGLINK
538 q2 = obj.Appendp(p, newprog)
539 q2.As = AB
540 q2.To.Type = obj.TYPE_BRANCH
541 q2.To.Sym = p.To.Sym
542 p.To.Sym = nil
543 p = q2
544 }
545
546 case AADD:
547 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
548 p.Spadj = int32(-p.From.Offset)
549 }
550
551 case ASUB:
552 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
553 p.Spadj = int32(p.From.Offset)
554 }
555
556 case ADIV, ADIVU, AMOD, AMODU:
557 if cursym.Func.Text.From.Sym.NoSplit() {
558 ctxt.Diag("cannot divide in NOSPLIT function")
559 }
560 const debugdivmod = false
561 if debugdivmod {
562 break
563 }
564 if p.From.Type != obj.TYPE_REG {
565 break
566 }
567 if p.To.Type != obj.TYPE_REG {
568 break
569 }
570
571
572 q1 := *p
573 if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
574 ctxt.Diag("div already using REGTMP: %v", p)
575 }
576
577
578 p.As = AMOVW
579 p.Pos = q1.Pos
580 p.From.Type = obj.TYPE_MEM
581 p.From.Reg = REGG
582 p.From.Offset = 6 * 4
583 p.Reg = 0
584 p.To.Type = obj.TYPE_REG
585 p.To.Reg = REGTMP
586
587
588 p = obj.Appendp(p, newprog)
589 p.As = AMOVW
590 p.Pos = q1.Pos
591 p.From.Type = obj.TYPE_REG
592 p.From.Reg = q1.From.Reg
593 p.To.Type = obj.TYPE_MEM
594 p.To.Reg = REGTMP
595 p.To.Offset = 8 * 4
596
597
598 p = obj.Appendp(p, newprog)
599 p.As = AMOVW
600 p.Pos = q1.Pos
601 p.From.Type = obj.TYPE_REG
602 p.From.Reg = q1.Reg
603 if q1.Reg == 0 {
604 p.From.Reg = q1.To.Reg
605 }
606 p.To.Type = obj.TYPE_REG
607 p.To.Reg = REG_R8
608 p.To.Offset = 0
609
610
611 p = obj.Appendp(p, newprog)
612 p.As = ABL
613 p.Pos = q1.Pos
614 p.To.Type = obj.TYPE_BRANCH
615 switch o {
616 case ADIV:
617 p.To.Sym = symdiv
618 case ADIVU:
619 p.To.Sym = symdivu
620 case AMOD:
621 p.To.Sym = symmod
622 case AMODU:
623 p.To.Sym = symmodu
624 }
625
626
627 p = obj.Appendp(p, newprog)
628 p.As = AMOVW
629 p.Pos = q1.Pos
630 p.From.Type = obj.TYPE_REG
631 p.From.Reg = REGTMP
632 p.From.Offset = 0
633 p.To.Type = obj.TYPE_REG
634 p.To.Reg = q1.To.Reg
635
636 case AMOVW:
637 if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
638 p.Spadj = int32(-p.To.Offset)
639 }
640 if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
641 p.Spadj = int32(-p.From.Offset)
642 }
643 if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
644 p.Spadj = int32(-p.From.Offset)
645 }
646
647 case obj.AGETCALLERPC:
648 if cursym.Leaf() {
649
650 p.As = AMOVW
651 p.From.Type = obj.TYPE_REG
652 p.From.Reg = REGLINK
653 } else {
654
655 p.As = AMOVW
656 p.From.Type = obj.TYPE_MEM
657 p.From.Reg = REGSP
658 }
659 }
660 }
661 }
662
663 func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
664
665 p = obj.Appendp(p, c.newprog)
666
667 p.As = AMOVW
668 p.From.Type = obj.TYPE_MEM
669 p.From.Reg = REGG
670 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
671 if c.cursym.CFunc() {
672 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
673 }
674 p.To.Type = obj.TYPE_REG
675 p.To.Reg = REG_R1
676
677 if framesize <= objabi.StackSmall {
678
679
680 p = obj.Appendp(p, c.newprog)
681
682 p.As = ACMP
683 p.From.Type = obj.TYPE_REG
684 p.From.Reg = REG_R1
685 p.Reg = REGSP
686 } else if framesize <= objabi.StackBig {
687
688
689
690 p = obj.Appendp(p, c.newprog)
691
692 p.As = AMOVW
693 p.From.Type = obj.TYPE_ADDR
694 p.From.Reg = REGSP
695 p.From.Offset = -(int64(framesize) - objabi.StackSmall)
696 p.To.Type = obj.TYPE_REG
697 p.To.Reg = REG_R2
698
699 p = obj.Appendp(p, c.newprog)
700 p.As = ACMP
701 p.From.Type = obj.TYPE_REG
702 p.From.Reg = REG_R1
703 p.Reg = REG_R2
704 } else {
705
706
707
708
709
710
711
712
713
714
715 p = obj.Appendp(p, c.newprog)
716
717 p.As = ACMP
718 p.From.Type = obj.TYPE_CONST
719 p.From.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
720 p.Reg = REG_R1
721
722 p = obj.Appendp(p, c.newprog)
723 p.As = AMOVW
724 p.From.Type = obj.TYPE_ADDR
725 p.From.Reg = REGSP
726 p.From.Offset = int64(objabi.StackGuard)
727 p.To.Type = obj.TYPE_REG
728 p.To.Reg = REG_R2
729 p.Scond = C_SCOND_NE
730
731 p = obj.Appendp(p, c.newprog)
732 p.As = ASUB
733 p.From.Type = obj.TYPE_REG
734 p.From.Reg = REG_R1
735 p.To.Type = obj.TYPE_REG
736 p.To.Reg = REG_R2
737 p.Scond = C_SCOND_NE
738
739 p = obj.Appendp(p, c.newprog)
740 p.As = AMOVW
741 p.From.Type = obj.TYPE_ADDR
742 p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
743 p.To.Type = obj.TYPE_REG
744 p.To.Reg = REG_R3
745 p.Scond = C_SCOND_NE
746
747 p = obj.Appendp(p, c.newprog)
748 p.As = ACMP
749 p.From.Type = obj.TYPE_REG
750 p.From.Reg = REG_R3
751 p.Reg = REG_R2
752 p.Scond = C_SCOND_NE
753 }
754
755
756 bls := obj.Appendp(p, c.newprog)
757 bls.As = ABLS
758 bls.To.Type = obj.TYPE_BRANCH
759
760 var last *obj.Prog
761 for last = c.cursym.Func.Text; last.Link != nil; last = last.Link {
762 }
763
764
765
766
767 spfix := obj.Appendp(last, c.newprog)
768 spfix.As = obj.ANOP
769 spfix.Spadj = -framesize
770
771 pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog)
772
773
774 movw := obj.Appendp(pcdata, c.newprog)
775 movw.As = AMOVW
776 movw.From.Type = obj.TYPE_REG
777 movw.From.Reg = REGLINK
778 movw.To.Type = obj.TYPE_REG
779 movw.To.Reg = REG_R3
780
781 bls.Pcond = movw
782
783
784 call := obj.Appendp(movw, c.newprog)
785 call.As = obj.ACALL
786 call.To.Type = obj.TYPE_BRANCH
787 morestack := "runtime.morestack"
788 switch {
789 case c.cursym.CFunc():
790 morestack = "runtime.morestackc"
791 case !c.cursym.Func.Text.From.Sym.NeedCtxt():
792 morestack = "runtime.morestack_noctxt"
793 }
794 call.To.Sym = c.ctxt.Lookup(morestack)
795
796
797 b := obj.Appendp(call, c.newprog)
798 b.As = obj.AJMP
799 b.To.Type = obj.TYPE_BRANCH
800 b.Pcond = c.cursym.Func.Text.Link
801 b.Spadj = +framesize
802
803 return bls
804 }
805
806 var unaryDst = map[obj.As]bool{
807 ASWI: true,
808 AWORD: true,
809 }
810
811 var Linkarm = obj.LinkArch{
812 Arch: sys.ArchARM,
813 Init: buildop,
814 Preprocess: preprocess,
815 Assemble: span5,
816 Progedit: progedit,
817 UnaryDst: unaryDst,
818 DWARFRegisters: ARMDWARFRegisters,
819 }
820
View as plain text