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 if cursym.Func().Text.Mark&LEAF != 0 {
356 if autosize == 0 {
357 p.As = AB
358 p.From = obj.Addr{}
359 if p.To.Sym != nil {
360 p.To.Type = obj.TYPE_BRANCH
361 } else {
362 p.To.Type = obj.TYPE_MEM
363 p.To.Offset = 0
364 p.To.Reg = REGLINK
365 }
366
367 break
368 }
369 }
370
371 p.As = AMOVW
372 p.Scond |= C_PBIT
373 p.From.Type = obj.TYPE_MEM
374 p.From.Offset = int64(autosize)
375 p.From.Reg = REGSP
376 p.To.Type = obj.TYPE_REG
377 p.To.Reg = REGPC
378
379
380
381
382
383 if p.To.Sym != nil {
384 p.To.Reg = REGLINK
385 q2 = obj.Appendp(p, newprog)
386 q2.As = AB
387 q2.To.Type = obj.TYPE_BRANCH
388 q2.To.Sym = p.To.Sym
389 p.To.Sym = nil
390 p.To.Name = obj.NAME_NONE
391 p = q2
392 }
393
394 case AADD:
395 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
396 p.Spadj = int32(-p.From.Offset)
397 }
398
399 case ASUB:
400 if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
401 p.Spadj = int32(p.From.Offset)
402 }
403
404 case ADIV, ADIVU, AMOD, AMODU:
405 if cursym.Func().Text.From.Sym.NoSplit() {
406 ctxt.Diag("cannot divide in NOSPLIT function")
407 }
408 const debugdivmod = false
409 if debugdivmod {
410 break
411 }
412 if p.From.Type != obj.TYPE_REG {
413 break
414 }
415 if p.To.Type != obj.TYPE_REG {
416 break
417 }
418
419
420 q1 := *p
421 if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
422 ctxt.Diag("div already using REGTMP: %v", p)
423 }
424
425
426 p.As = AMOVW
427 p.Pos = q1.Pos
428 p.From.Type = obj.TYPE_MEM
429 p.From.Reg = REGG
430 p.From.Offset = 6 * 4
431 p.Reg = 0
432 p.To.Type = obj.TYPE_REG
433 p.To.Reg = REGTMP
434
435
436 p = obj.Appendp(p, newprog)
437 p.As = AMOVW
438 p.Pos = q1.Pos
439 p.From.Type = obj.TYPE_REG
440 p.From.Reg = q1.From.Reg
441 p.To.Type = obj.TYPE_MEM
442 p.To.Reg = REGTMP
443 p.To.Offset = 7 * 4
444
445
446 p = obj.Appendp(p, newprog)
447 p.As = AMOVW
448 p.Pos = q1.Pos
449 p.From.Type = obj.TYPE_REG
450 p.From.Reg = q1.Reg
451 if q1.Reg == 0 {
452 p.From.Reg = q1.To.Reg
453 }
454 p.To.Type = obj.TYPE_REG
455 p.To.Reg = REG_R8
456 p.To.Offset = 0
457
458
459 p = obj.Appendp(p, newprog)
460 p.As = ABL
461 p.Pos = q1.Pos
462 p.To.Type = obj.TYPE_BRANCH
463 switch o {
464 case ADIV:
465 p.To.Sym = symdiv
466 case ADIVU:
467 p.To.Sym = symdivu
468 case AMOD:
469 p.To.Sym = symmod
470 case AMODU:
471 p.To.Sym = symmodu
472 }
473
474
475 p = obj.Appendp(p, newprog)
476 p.As = AMOVW
477 p.Pos = q1.Pos
478 p.From.Type = obj.TYPE_REG
479 p.From.Reg = REGTMP
480 p.From.Offset = 0
481 p.To.Type = obj.TYPE_REG
482 p.To.Reg = q1.To.Reg
483
484 case AMOVW:
485 if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
486 p.Spadj = int32(-p.To.Offset)
487 }
488 if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
489 p.Spadj = int32(-p.From.Offset)
490 }
491 if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
492 p.Spadj = int32(-p.From.Offset)
493 }
494
495 case obj.AGETCALLERPC:
496 if cursym.Leaf() {
497
498 p.As = AMOVW
499 p.From.Type = obj.TYPE_REG
500 p.From.Reg = REGLINK
501 } else {
502
503 p.As = AMOVW
504 p.From.Type = obj.TYPE_MEM
505 p.From.Reg = REGSP
506 }
507 }
508
509 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
510 f := c.cursym.Func()
511 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
512 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
513 if ctxt.Debugvlog || !ctxt.IsAsm {
514 ctxt.Logf("auto-SPWRITE: %s %v\n", c.cursym.Name, p)
515 if !ctxt.IsAsm {
516 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
517 ctxt.DiagFlush()
518 log.Fatalf("bad SPWRITE")
519 }
520 }
521 }
522 }
523 }
524 }
525
526 func (c *ctxt5) stacksplit(p *obj.Prog, framesize int32) *obj.Prog {
527 if c.ctxt.Flag_maymorestack != "" {
528
529 const frameSize = 8
530
531 p = obj.Appendp(p, c.newprog)
532 p.As = AMOVW
533 p.Scond |= C_WBIT
534 p.From.Type = obj.TYPE_REG
535 p.From.Reg = REGLINK
536 p.To.Type = obj.TYPE_MEM
537 p.To.Offset = -frameSize
538 p.To.Reg = REGSP
539 p.Spadj = frameSize
540
541
542 p = obj.Appendp(p, c.newprog)
543 p.As = AMOVW
544 p.From.Type = obj.TYPE_REG
545 p.From.Reg = REGCTXT
546 p.To.Type = obj.TYPE_MEM
547 p.To.Offset = 4
548 p.To.Reg = REGSP
549
550
551 p = obj.Appendp(p, c.newprog)
552 p.As = obj.ACALL
553 p.To.Type = obj.TYPE_BRANCH
554
555 p.To.Sym = c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
556
557
558
559
560 p = obj.Appendp(p, c.newprog)
561 p.As = AMOVW
562 p.From.Type = obj.TYPE_MEM
563 p.From.Offset = 4
564 p.From.Reg = REGSP
565 p.To.Type = obj.TYPE_REG
566 p.To.Reg = REGCTXT
567
568
569 p.As = AMOVW
570 p.Scond |= C_PBIT
571 p.From.Type = obj.TYPE_MEM
572 p.From.Offset = frameSize
573 p.From.Reg = REGSP
574 p.To.Type = obj.TYPE_REG
575 p.To.Reg = REGLINK
576 p.Spadj = -frameSize
577 }
578
579
580 startPred := p
581
582
583 p = obj.Appendp(p, c.newprog)
584
585 p.As = AMOVW
586 p.From.Type = obj.TYPE_MEM
587 p.From.Reg = REGG
588 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
589 if c.cursym.CFunc() {
590 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
591 }
592 p.To.Type = obj.TYPE_REG
593 p.To.Reg = REG_R1
594
595
596
597
598
599 p = c.ctxt.StartUnsafePoint(p, c.newprog)
600
601 if framesize <= abi.StackSmall {
602
603
604 p = obj.Appendp(p, c.newprog)
605
606 p.As = ACMP
607 p.From.Type = obj.TYPE_REG
608 p.From.Reg = REG_R1
609 p.Reg = REGSP
610 } else if framesize <= abi.StackBig {
611
612
613
614 p = obj.Appendp(p, c.newprog)
615
616 p.As = AMOVW
617 p.From.Type = obj.TYPE_ADDR
618 p.From.Reg = REGSP
619 p.From.Offset = -(int64(framesize) - abi.StackSmall)
620 p.To.Type = obj.TYPE_REG
621 p.To.Reg = REG_R2
622
623 p = obj.Appendp(p, c.newprog)
624 p.As = ACMP
625 p.From.Type = obj.TYPE_REG
626 p.From.Reg = REG_R1
627 p.Reg = REG_R2
628 } else {
629
630
631
632
633
634
635
636
637
638
639
640
641
642 p = obj.Appendp(p, c.newprog)
643 p.As = ASUB
644 p.Scond = C_SBIT
645 p.From.Type = obj.TYPE_CONST
646 p.From.Offset = int64(framesize) - abi.StackSmall
647 p.Reg = REGSP
648 p.To.Type = obj.TYPE_REG
649 p.To.Reg = REG_R2
650
651 p = obj.Appendp(p, c.newprog)
652 p.As = ACMP
653 p.Scond = C_SCOND_HS
654 p.From.Type = obj.TYPE_REG
655 p.From.Reg = REG_R1
656 p.Reg = REG_R2
657 }
658
659
660 bls := obj.Appendp(p, c.newprog)
661 bls.As = ABLS
662 bls.To.Type = obj.TYPE_BRANCH
663
664 end := c.ctxt.EndUnsafePoint(bls, c.newprog, -1)
665
666 var last *obj.Prog
667 for last = c.cursym.Func().Text; last.Link != nil; last = last.Link {
668 }
669
670
671
672
673 spfix := obj.Appendp(last, c.newprog)
674 spfix.As = obj.ANOP
675 spfix.Spadj = -framesize
676
677 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
678 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
679
680
681 movw := obj.Appendp(pcdata, c.newprog)
682 movw.As = AMOVW
683 movw.From.Type = obj.TYPE_REG
684 movw.From.Reg = REGLINK
685 movw.To.Type = obj.TYPE_REG
686 movw.To.Reg = REG_R3
687
688 bls.To.SetTarget(movw)
689
690
691 call := obj.Appendp(movw, c.newprog)
692 call.As = obj.ACALL
693 call.To.Type = obj.TYPE_BRANCH
694 morestack := "runtime.morestack"
695 switch {
696 case c.cursym.CFunc():
697 morestack = "runtime.morestackc"
698 case !c.cursym.Func().Text.From.Sym.NeedCtxt():
699 morestack = "runtime.morestack_noctxt"
700 }
701 call.To.Sym = c.ctxt.Lookup(morestack)
702
703 pcdata = c.ctxt.EndUnsafePoint(call, c.newprog, -1)
704
705
706 b := obj.Appendp(pcdata, c.newprog)
707 b.As = obj.AJMP
708 b.To.Type = obj.TYPE_BRANCH
709 b.To.SetTarget(startPred.Link)
710 b.Spadj = +framesize
711
712 return end
713 }
714
715 var unaryDst = map[obj.As]bool{
716 ASWI: true,
717 AWORD: true,
718 }
719
720 var Linkarm = obj.LinkArch{
721 Arch: sys.ArchARM,
722 Init: buildop,
723 Preprocess: preprocess,
724 Assemble: span5,
725 Progedit: progedit,
726 UnaryDst: unaryDst,
727 DWARFRegisters: ARMDWARFRegisters,
728 }
729
View as plain text