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