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
280 for p := cursym.Func().Text; p != nil; p = p.Link {
281 switch p.As {
282 case obj.ATEXT:
283 p.Mark |= LEAF
284
285 case ADIV, ADIVU, AMOD, AMODU:
286 cursym.Func().Text.Mark &^= LEAF
287
288 case ABL,
289 ABX,
290 obj.ADUFFZERO,
291 obj.ADUFFCOPY:
292 cursym.Func().Text.Mark &^= LEAF
293 }
294 }
295
296 var q2 *obj.Prog
297 for p := cursym.Func().Text; p != nil; p = p.Link {
298 o := p.As
299 switch o {
300 case obj.ATEXT:
301 autosize = autoffset
302
303 if p.Mark&LEAF != 0 && autosize == 0 {
304
305 p.From.Sym.Set(obj.AttrNoFrame, true)
306 }
307
308 if !p.From.Sym.NoFrame() {
309
310
311 autosize += 4
312 }
313
314 if autosize == 0 && cursym.Func().Text.Mark&LEAF == 0 {
315
316
317 if ctxt.Debugvlog {
318 ctxt.Logf("save suppressed in: %s\n", cursym.Name)
319 }
320
321 cursym.Func().Text.Mark |= LEAF
322 }
323
324
325 p.To.Offset = int64(autosize) - 4
326
327 if cursym.Func().Text.Mark&LEAF != 0 {
328 cursym.Set(obj.AttrLeaf, true)
329 if p.From.Sym.NoFrame() {
330 break
331 }
332 }
333
334 if !p.From.Sym.NoSplit() {
335 p = c.stacksplit(p, autosize)
336 }
337
338
339 p = obj.Appendp(p, c.newprog)
340
341 p.As = AMOVW
342 p.Scond |= C_WBIT
343 p.From.Type = obj.TYPE_REG
344 p.From.Reg = REGLINK
345 p.To.Type = obj.TYPE_MEM
346 p.To.Offset = int64(-autosize)
347 p.To.Reg = REGSP
348 p.Spadj = autosize
349
350 if cursym.Func().Text.From.Sym.Wrapper() {
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371 p = obj.Appendp(p, newprog)
372 p.As = AMOVW
373 p.From.Type = obj.TYPE_MEM
374 p.From.Reg = REGG
375 p.From.Offset = 4 * int64(ctxt.Arch.PtrSize)
376 p.To.Type = obj.TYPE_REG
377 p.To.Reg = REG_R1
378
379 p = obj.Appendp(p, newprog)
380 p.As = ACMP
381 p.From.Type = obj.TYPE_CONST
382 p.From.Offset = 0
383 p.Reg = REG_R1
384
385
386 bne := obj.Appendp(p, newprog)
387 bne.As = ABNE
388 bne.To.Type = obj.TYPE_BRANCH
389
390
391 end := obj.Appendp(bne, newprog)
392 end.As = obj.ANOP
393
394
395 var last *obj.Prog
396 for last = end; last.Link != nil; last = last.Link {
397 }
398
399
400 mov := obj.Appendp(last, newprog)
401 mov.As = AMOVW
402 mov.From.Type = obj.TYPE_MEM
403 mov.From.Reg = REG_R1
404 mov.From.Offset = 0
405 mov.To.Type = obj.TYPE_REG
406 mov.To.Reg = REG_R2
407
408
409 bne.To.SetTarget(mov)
410
411
412 p = obj.Appendp(mov, newprog)
413 p.As = AADD
414 p.From.Type = obj.TYPE_CONST
415 p.From.Offset = int64(autosize) + 4
416 p.Reg = REG_R13
417 p.To.Type = obj.TYPE_REG
418 p.To.Reg = REG_R3
419
420
421 p = obj.Appendp(p, newprog)
422 p.As = ACMP
423 p.From.Type = obj.TYPE_REG
424 p.From.Reg = REG_R2
425 p.Reg = REG_R3
426
427
428 p = obj.Appendp(p, newprog)
429 p.As = ABNE
430 p.To.Type = obj.TYPE_BRANCH
431 p.To.SetTarget(end)
432
433
434 p = obj.Appendp(p, newprog)
435 p.As = AADD
436 p.From.Type = obj.TYPE_CONST
437 p.From.Offset = 4
438 p.Reg = REG_R13
439 p.To.Type = obj.TYPE_REG
440 p.To.Reg = REG_R4
441
442
443 p = obj.Appendp(p, newprog)
444 p.As = AMOVW
445 p.From.Type = obj.TYPE_REG
446 p.From.Reg = REG_R4
447 p.To.Type = obj.TYPE_MEM
448 p.To.Reg = REG_R1
449 p.To.Offset = 0
450
451
452 p = obj.Appendp(p, newprog)
453 p.As = AB
454 p.To.Type = obj.TYPE_BRANCH
455 p.To.SetTarget(end)
456
457
458 p = end
459 }
460
461 case obj.ARET:
462 nocache(p)
463 if cursym.Func().Text.Mark&LEAF != 0 {
464 if autosize == 0 {
465 p.As = AB
466 p.From = obj.Addr{}
467 if p.To.Sym != nil {
468 p.To.Type = obj.TYPE_BRANCH
469 } else {
470 p.To.Type = obj.TYPE_MEM
471 p.To.Offset = 0
472 p.To.Reg = REGLINK
473 }
474
475 break
476 }
477 }
478
479 p.As = AMOVW
480 p.Scond |= C_PBIT
481 p.From.Type = obj.TYPE_MEM
482 p.From.Offset = int64(autosize)
483 p.From.Reg = REGSP
484 p.To.Type = obj.TYPE_REG
485 p.To.Reg = REGPC
486
487
488
489
490
491 if p.To.Sym != nil {
492 p.To.Reg = REGLINK
493 q2 = obj.Appendp(p, newprog)
494 q2.As = AB
495 q2.To.Type = obj.TYPE_BRANCH
496 q2.To.Sym = p.To.Sym
497 p.To.Sym = nil
498 p.To.Name = obj.NAME_NONE
499 p = q2
500 }
501
502 case AADD:
503 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
504 p.Spadj = int32(-p.From.Offset)
505 }
506
507 case ASUB:
508 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
509 p.Spadj = int32(p.From.Offset)
510 }
511
512 case ADIV, ADIVU, AMOD, AMODU:
513 if cursym.Func().Text.From.Sym.NoSplit() {
514 ctxt.Diag("cannot divide in NOSPLIT function")
515 }
516 const debugdivmod = false
517 if debugdivmod {
518 break
519 }
520 if p.From.Type != obj.TYPE_REG {
521 break
522 }
523 if p.To.Type != obj.TYPE_REG {
524 break
525 }
526
527
528 q1 := *p
529 if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
530 ctxt.Diag("div already using REGTMP: %v", p)
531 }
532
533
534 p.As = AMOVW
535 p.Pos = q1.Pos
536 p.From.Type = obj.TYPE_MEM
537 p.From.Reg = REGG
538 p.From.Offset = 6 * 4
539 p.Reg = 0
540 p.To.Type = obj.TYPE_REG
541 p.To.Reg = REGTMP
542
543
544 p = obj.Appendp(p, newprog)
545 p.As = AMOVW
546 p.Pos = q1.Pos
547 p.From.Type = obj.TYPE_REG
548 p.From.Reg = q1.From.Reg
549 p.To.Type = obj.TYPE_MEM
550 p.To.Reg = REGTMP
551 p.To.Offset = 8 * 4
552
553
554 p = obj.Appendp(p, newprog)
555 p.As = AMOVW
556 p.Pos = q1.Pos
557 p.From.Type = obj.TYPE_REG
558 p.From.Reg = q1.Reg
559 if q1.Reg == 0 {
560 p.From.Reg = q1.To.Reg
561 }
562 p.To.Type = obj.TYPE_REG
563 p.To.Reg = REG_R8
564 p.To.Offset = 0
565
566
567 p = obj.Appendp(p, newprog)
568 p.As = ABL
569 p.Pos = q1.Pos
570 p.To.Type = obj.TYPE_BRANCH
571 switch o {
572 case ADIV:
573 p.To.Sym = symdiv
574 case ADIVU:
575 p.To.Sym = symdivu
576 case AMOD:
577 p.To.Sym = symmod
578 case AMODU:
579 p.To.Sym = symmodu
580 }
581
582
583 p = obj.Appendp(p, newprog)
584 p.As = AMOVW
585 p.Pos = q1.Pos
586 p.From.Type = obj.TYPE_REG
587 p.From.Reg = REGTMP
588 p.From.Offset = 0
589 p.To.Type = obj.TYPE_REG
590 p.To.Reg = q1.To.Reg
591
592 case AMOVW:
593 if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
594 p.Spadj = int32(-p.To.Offset)
595 }
596 if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
597 p.Spadj = int32(-p.From.Offset)
598 }
599 if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
600 p.Spadj = int32(-p.From.Offset)
601 }
602
603 case obj.AGETCALLERPC:
604 if cursym.Leaf() {
605
606 p.As = AMOVW
607 p.From.Type = obj.TYPE_REG
608 p.From.Reg = REGLINK
609 } else {
610
611 p.As = AMOVW
612 p.From.Type = obj.TYPE_MEM
613 p.From.Reg = REGSP
614 }
615 }
616 }
617 }
618
619 func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
620
621 p = obj.Appendp(p, c.newprog)
622
623 p.As = AMOVW
624 p.From.Type = obj.TYPE_MEM
625 p.From.Reg = REGG
626 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
627 if c.cursym.CFunc() {
628 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
629 }
630 p.To.Type = obj.TYPE_REG
631 p.To.Reg = REG_R1
632
633
634
635
636
637 p = c.ctxt.StartUnsafePoint(p, c.newprog)
638
639 if framesize <= objabi.StackSmall {
640
641
642 p = obj.Appendp(p, c.newprog)
643
644 p.As = ACMP
645 p.From.Type = obj.TYPE_REG
646 p.From.Reg = REG_R1
647 p.Reg = REGSP
648 } else if framesize <= objabi.StackBig {
649
650
651
652 p = obj.Appendp(p, c.newprog)
653
654 p.As = AMOVW
655 p.From.Type = obj.TYPE_ADDR
656 p.From.Reg = REGSP
657 p.From.Offset = -(int64(framesize) - objabi.StackSmall)
658 p.To.Type = obj.TYPE_REG
659 p.To.Reg = REG_R2
660
661 p = obj.Appendp(p, c.newprog)
662 p.As = ACMP
663 p.From.Type = obj.TYPE_REG
664 p.From.Reg = REG_R1
665 p.Reg = REG_R2
666 } else {
667
668
669
670
671
672
673
674
675
676
677 p = obj.Appendp(p, c.newprog)
678
679 p.As = ACMP
680 p.From.Type = obj.TYPE_CONST
681 p.From.Offset = int64(uint32(objabi.StackPreempt & (1<<32 - 1)))
682 p.Reg = REG_R1
683
684 p = obj.Appendp(p, c.newprog)
685 p.As = AMOVW
686 p.From.Type = obj.TYPE_ADDR
687 p.From.Reg = REGSP
688 p.From.Offset = int64(objabi.StackGuard)
689 p.To.Type = obj.TYPE_REG
690 p.To.Reg = REG_R2
691 p.Scond = C_SCOND_NE
692
693 p = obj.Appendp(p, c.newprog)
694 p.As = ASUB
695 p.From.Type = obj.TYPE_REG
696 p.From.Reg = REG_R1
697 p.To.Type = obj.TYPE_REG
698 p.To.Reg = REG_R2
699 p.Scond = C_SCOND_NE
700
701 p = obj.Appendp(p, c.newprog)
702 p.As = AMOVW
703 p.From.Type = obj.TYPE_ADDR
704 p.From.Offset = int64(framesize) + (int64(objabi.StackGuard) - objabi.StackSmall)
705 p.To.Type = obj.TYPE_REG
706 p.To.Reg = REG_R3
707 p.Scond = C_SCOND_NE
708
709 p = obj.Appendp(p, c.newprog)
710 p.As = ACMP
711 p.From.Type = obj.TYPE_REG
712 p.From.Reg = REG_R3
713 p.Reg = REG_R2
714 p.Scond = C_SCOND_NE
715 }
716
717
718 bls := obj.Appendp(p, c.newprog)
719 bls.As = ABLS
720 bls.To.Type = obj.TYPE_BRANCH
721
722 end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
723
724 var last *obj.Prog
725 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
726 }
727
728
729
730
731 spfix := obj.Appendp(last, c.newprog)
732 spfix.As = obj.ANOP
733 spfix.Spadj = -framesize
734
735 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
736 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
737
738
739 movw := obj.Appendp(pcdata, c.newprog)
740 movw.As = AMOVW
741 movw.From.Type = obj.TYPE_REG
742 movw.From.Reg = REGLINK
743 movw.To.Type = obj.TYPE_REG
744 movw.To.Reg = REG_R3
745
746 bls.To.SetTarget(movw)
747
748
749 call := obj.Appendp(movw, c.newprog)
750 call.As = obj.ACALL
751 call.To.Type = obj.TYPE_BRANCH
752 morestack := "runtime.morestack"
753 switch {
754 case c.cursym.CFunc():
755 morestack = "runtime.morestackc"
756 case !c.cursym.Func().Text.From.Sym.NeedCtxt():
757 morestack = "runtime.morestack_noctxt"
758 }
759 call.To.Sym = c.ctxt.Lookup(morestack)
760
761 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
762
763
764 b := obj.Appendp(pcdata, c.newprog)
765 b.As = obj.AJMP
766 b.To.Type = obj.TYPE_BRANCH
767 b.To.SetTarget(c.cursym.Func().Text.Link)
768 b.Spadj = +framesize
769
770 return end
771 }
772
773 var unaryDst = map[obj.As]bool{
774 ASWI: true,
775 AWORD: true,
776 }
777
778 var Linkarm = obj.LinkArch{
779 Arch: sys.ArchARM,
780 Init: buildop,
781 Preprocess: preprocess,
782 Assemble: span5,
783 Progedit: progedit,
784 UnaryDst: unaryDst,
785 DWARFRegisters: ARMDWARFRegisters,
786 }
787
View as plain text