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 package s390x
31
32 import (
33 "cmd/internal/obj"
34 "cmd/internal/objabi"
35 "cmd/internal/sys"
36 "log"
37 "math"
38 )
39
40 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) {
41 p.From.Class = 0
42 p.To.Class = 0
43
44 c := ctxtz{ctxt: ctxt, newprog: newprog}
45
46
47 switch p.As {
48 case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY:
49 if p.To.Sym != nil {
50 p.To.Type = obj.TYPE_BRANCH
51 }
52 }
53
54
55 switch p.As {
56 case AFMOVS:
57 if p.From.Type == obj.TYPE_FCONST {
58 f32 := float32(p.From.Val.(float64))
59 if math.Float32bits(f32) == 0 {
60 break
61 }
62 p.From.Type = obj.TYPE_MEM
63 p.From.Sym = ctxt.Float32Sym(f32)
64 p.From.Name = obj.NAME_EXTERN
65 p.From.Offset = 0
66 }
67
68 case AFMOVD:
69 if p.From.Type == obj.TYPE_FCONST {
70 f64 := p.From.Val.(float64)
71 if math.Float64bits(f64) == 0 {
72 break
73 }
74 p.From.Type = obj.TYPE_MEM
75 p.From.Sym = ctxt.Float64Sym(f64)
76 p.From.Name = obj.NAME_EXTERN
77 p.From.Offset = 0
78 }
79
80
81 case AMOVD:
82 if p.From.Type == obj.TYPE_CONST {
83 val := p.From.Offset
84 if int64(int32(val)) != val &&
85 int64(uint32(val)) != val &&
86 int64(uint64(val)&(0xffffffff<<32)) != val {
87 p.From.Type = obj.TYPE_MEM
88 p.From.Sym = ctxt.Int64Sym(p.From.Offset)
89 p.From.Name = obj.NAME_EXTERN
90 p.From.Offset = 0
91 }
92 }
93 }
94
95
96 switch p.As {
97 case ASUBC:
98 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
99 p.From.Offset = -p.From.Offset
100 p.As = AADDC
101 }
102
103 case ASUB:
104 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) {
105 p.From.Offset = -p.From.Offset
106 p.As = AADD
107 }
108 }
109
110 if c.ctxt.Flag_dynlink {
111 c.rewriteToUseGot(p)
112 }
113 }
114
115
116 func (c *ctxtz) rewriteToUseGot(p *obj.Prog) {
117
118
119 if p.As == AEXRL {
120 return
121 }
122
123
124
125
126
127
128 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
129
130
131 if p.To.Type != obj.TYPE_REG || p.As != AMOVD {
132 c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p)
133 }
134 p.From.Type = obj.TYPE_MEM
135 p.From.Name = obj.NAME_GOTREF
136 q := p
137 if p.From.Offset != 0 {
138 target := p.To.Reg
139 if target == REG_R0 {
140
141
142 p.To.Reg = REGTMP2
143 }
144 q = obj.Appendp(q, c.newprog)
145 q.As = AMOVD
146 q.From.Type = obj.TYPE_ADDR
147 q.From.Offset = p.From.Offset
148 q.From.Reg = p.To.Reg
149 q.To.Type = obj.TYPE_REG
150 q.To.Reg = target
151 p.From.Offset = 0
152 }
153 }
154 if p.GetFrom3() != nil && p.GetFrom3().Name == obj.NAME_EXTERN {
155 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
156 }
157 var source *obj.Addr
158
159
160
161 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() {
162 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
163 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
164 }
165 source = &p.From
166 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() {
167 source = &p.To
168 } else {
169 return
170 }
171 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
172 return
173 }
174 if source.Sym.Type == objabi.STLSBSS {
175 return
176 }
177 if source.Type != obj.TYPE_MEM {
178 c.ctxt.Diag("don't know how to handle %v with -dynlink", p)
179 }
180 p1 := obj.Appendp(p, c.newprog)
181 p2 := obj.Appendp(p1, c.newprog)
182
183 p1.As = AMOVD
184 p1.From.Type = obj.TYPE_MEM
185 p1.From.Sym = source.Sym
186 p1.From.Name = obj.NAME_GOTREF
187 p1.To.Type = obj.TYPE_REG
188 p1.To.Reg = REGTMP2
189
190 p2.As = p.As
191 p2.From = p.From
192 p2.To = p.To
193 if p.From.Name == obj.NAME_EXTERN {
194 p2.From.Reg = REGTMP2
195 p2.From.Name = obj.NAME_NONE
196 p2.From.Sym = nil
197 } else if p.To.Name == obj.NAME_EXTERN {
198 p2.To.Reg = REGTMP2
199 p2.To.Name = obj.NAME_NONE
200 p2.To.Sym = nil
201 } else {
202 return
203 }
204 obj.Nopout(p)
205 }
206
207 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
208
209 if cursym.Func().Text == nil || cursym.Func().Text.Link == nil {
210 return
211 }
212
213 c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog}
214
215 p := c.cursym.Func().Text
216 textstksiz := p.To.Offset
217 if textstksiz == -8 {
218
219 p.From.Sym.Set(obj.AttrNoFrame, true)
220 textstksiz = 0
221 }
222 if textstksiz%8 != 0 {
223 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz)
224 }
225 if p.From.Sym.NoFrame() {
226 if textstksiz != 0 {
227 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz)
228 }
229 }
230
231 c.cursym.Func().Args = p.To.Val.(int32)
232 c.cursym.Func().Locals = int32(textstksiz)
233
234
239
240 var q *obj.Prog
241 for p := c.cursym.Func().Text; p != nil; p = p.Link {
242 switch p.As {
243 case obj.ATEXT:
244 q = p
245 p.Mark |= LEAF
246
247 case ABL, ABCL:
248 q = p
249 c.cursym.Func().Text.Mark &^= LEAF
250 fallthrough
251
252 case ABC,
253 ABRC,
254 ABEQ,
255 ABGE,
256 ABGT,
257 ABLE,
258 ABLT,
259 ABLEU,
260 ABLTU,
261 ABNE,
262 ABR,
263 ABVC,
264 ABVS,
265 ACRJ,
266 ACGRJ,
267 ACLRJ,
268 ACLGRJ,
269 ACIJ,
270 ACGIJ,
271 ACLIJ,
272 ACLGIJ,
273 ACMPBEQ,
274 ACMPBGE,
275 ACMPBGT,
276 ACMPBLE,
277 ACMPBLT,
278 ACMPBNE,
279 ACMPUBEQ,
280 ACMPUBGE,
281 ACMPUBGT,
282 ACMPUBLE,
283 ACMPUBLT,
284 ACMPUBNE:
285 q = p
286 p.Mark |= BRANCH
287
288 default:
289 q = p
290 }
291 }
292
293 autosize := int32(0)
294 var pLast *obj.Prog
295 var pPre *obj.Prog
296 var pPreempt *obj.Prog
297 var pCheck *obj.Prog
298 wasSplit := false
299 for p := c.cursym.Func().Text; p != nil; p = p.Link {
300 pLast = p
301 switch p.As {
302 case obj.ATEXT:
303 autosize = int32(textstksiz)
304
305 if p.Mark&LEAF != 0 && autosize == 0 {
306
307 p.From.Sym.Set(obj.AttrNoFrame, true)
308 }
309
310 if !p.From.Sym.NoFrame() {
311
312
313 autosize += int32(c.ctxt.FixedFrameSize())
314 }
315
316 if p.Mark&LEAF != 0 && autosize < objabi.StackSmall {
317
318
319 p.From.Sym.Set(obj.AttrNoSplit, true)
320 }
321
322 p.To.Offset = int64(autosize)
323
324 q := p
325
326 if !p.From.Sym.NoSplit() {
327 p, pPreempt, pCheck = c.stacksplitPre(p, autosize)
328 pPre = p
329 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
330 wasSplit = true
331 }
332
333 if autosize != 0 {
334
335
336
337
338
339
340
341 q = c.ctxt.StartUnsafePoint(p, c.newprog)
342
343 q = obj.Appendp(q, c.newprog)
344 q.As = AMOVD
345 q.From.Type = obj.TYPE_REG
346 q.From.Reg = REG_LR
347 q.To.Type = obj.TYPE_MEM
348 q.To.Reg = REGSP
349 q.To.Offset = int64(-autosize)
350
351 q = obj.Appendp(q, c.newprog)
352 q.As = AMOVD
353 q.From.Type = obj.TYPE_ADDR
354 q.From.Offset = int64(-autosize)
355 q.From.Reg = REGSP
356 q.To.Type = obj.TYPE_REG
357 q.To.Reg = REGSP
358 q.Spadj = autosize
359
360 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1)
361 } else if c.cursym.Func().Text.Mark&LEAF == 0 {
362
363
364
365 c.cursym.Func().Text.Mark |= LEAF
366 }
367
368 if c.cursym.Func().Text.Mark&LEAF != 0 {
369 c.cursym.Set(obj.AttrLeaf, true)
370 break
371 }
372
373 if c.cursym.Func().Text.From.Sym.Wrapper() {
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391 q = obj.Appendp(q, c.newprog)
392
393 q.As = AMOVD
394 q.From.Type = obj.TYPE_MEM
395 q.From.Reg = REGG
396 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize)
397 q.To.Type = obj.TYPE_REG
398 q.To.Reg = REG_R3
399
400 q = obj.Appendp(q, c.newprog)
401 q.As = ACMP
402 q.From.Type = obj.TYPE_REG
403 q.From.Reg = REG_R3
404 q.To.Type = obj.TYPE_CONST
405 q.To.Offset = 0
406
407 q = obj.Appendp(q, c.newprog)
408 q.As = ABEQ
409 q.To.Type = obj.TYPE_BRANCH
410 p1 := q
411
412 q = obj.Appendp(q, c.newprog)
413 q.As = AMOVD
414 q.From.Type = obj.TYPE_MEM
415 q.From.Reg = REG_R3
416 q.From.Offset = 0
417 q.To.Type = obj.TYPE_REG
418 q.To.Reg = REG_R4
419
420 q = obj.Appendp(q, c.newprog)
421 q.As = AADD
422 q.From.Type = obj.TYPE_CONST
423 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize()
424 q.Reg = REGSP
425 q.To.Type = obj.TYPE_REG
426 q.To.Reg = REG_R5
427
428 q = obj.Appendp(q, c.newprog)
429 q.As = ACMP
430 q.From.Type = obj.TYPE_REG
431 q.From.Reg = REG_R4
432 q.To.Type = obj.TYPE_REG
433 q.To.Reg = REG_R5
434
435 q = obj.Appendp(q, c.newprog)
436 q.As = ABNE
437 q.To.Type = obj.TYPE_BRANCH
438 p2 := q
439
440 q = obj.Appendp(q, c.newprog)
441 q.As = AADD
442 q.From.Type = obj.TYPE_CONST
443 q.From.Offset = c.ctxt.FixedFrameSize()
444 q.Reg = REGSP
445 q.To.Type = obj.TYPE_REG
446 q.To.Reg = REG_R6
447
448 q = obj.Appendp(q, c.newprog)
449 q.As = AMOVD
450 q.From.Type = obj.TYPE_REG
451 q.From.Reg = REG_R6
452 q.To.Type = obj.TYPE_MEM
453 q.To.Reg = REG_R3
454 q.To.Offset = 0
455
456 q = obj.Appendp(q, c.newprog)
457
458 q.As = obj.ANOP
459 p1.To.SetTarget(q)
460 p2.To.SetTarget(q)
461 }
462
463 case obj.ARET:
464 retTarget := p.To.Sym
465
466 if c.cursym.Func().Text.Mark&LEAF != 0 {
467 if autosize == 0 {
468 p.As = ABR
469 p.From = obj.Addr{}
470 if retTarget == nil {
471 p.To.Type = obj.TYPE_REG
472 p.To.Reg = REG_LR
473 } else {
474 p.To.Type = obj.TYPE_BRANCH
475 p.To.Sym = retTarget
476 }
477 p.Mark |= BRANCH
478 break
479 }
480
481 p.As = AADD
482 p.From.Type = obj.TYPE_CONST
483 p.From.Offset = int64(autosize)
484 p.To.Type = obj.TYPE_REG
485 p.To.Reg = REGSP
486 p.Spadj = -autosize
487
488 q = obj.Appendp(p, c.newprog)
489 q.As = ABR
490 q.From = obj.Addr{}
491 if retTarget == nil {
492 q.To.Type = obj.TYPE_REG
493 q.To.Reg = REG_LR
494 } else {
495 q.To.Type = obj.TYPE_BRANCH
496 q.To.Sym = retTarget
497 }
498 q.Mark |= BRANCH
499 q.Spadj = autosize
500 break
501 }
502
503 p.As = AMOVD
504 p.From.Type = obj.TYPE_MEM
505 p.From.Reg = REGSP
506 p.From.Offset = 0
507 p.To = obj.Addr{
508 Type: obj.TYPE_REG,
509 Reg: REG_LR,
510 }
511
512 q = p
513
514 if autosize != 0 {
515 q = obj.Appendp(q, c.newprog)
516 q.As = AADD
517 q.From.Type = obj.TYPE_CONST
518 q.From.Offset = int64(autosize)
519 q.To.Type = obj.TYPE_REG
520 q.To.Reg = REGSP
521 q.Spadj = -autosize
522 }
523
524 q = obj.Appendp(q, c.newprog)
525 q.As = ABR
526 q.From = obj.Addr{}
527 if retTarget == nil {
528 q.To.Type = obj.TYPE_REG
529 q.To.Reg = REG_LR
530 } else {
531 q.To.Type = obj.TYPE_BRANCH
532 q.To.Sym = retTarget
533 }
534 q.Mark |= BRANCH
535 q.Spadj = autosize
536
537 case AADD:
538 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
539 p.Spadj = int32(-p.From.Offset)
540 }
541
542 case obj.AGETCALLERPC:
543 if cursym.Leaf() {
544
545 p.As = AMOVD
546 p.From.Type = obj.TYPE_REG
547 p.From.Reg = REG_LR
548 } else {
549
550 p.As = AMOVD
551 p.From.Type = obj.TYPE_MEM
552 p.From.Reg = REGSP
553 }
554 }
555
556 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
557 f := c.cursym.Func()
558 if f.FuncFlag&objabi.FuncFlag_SPWRITE == 0 {
559 c.cursym.Func().FuncFlag |= objabi.FuncFlag_SPWRITE
560 if ctxt.Debugvlog || !ctxt.IsAsm {
561 ctxt.Logf("auto-SPWRITE: %s\n", c.cursym.Name)
562 if !ctxt.IsAsm {
563 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
564 ctxt.DiagFlush()
565 log.Fatalf("bad SPWRITE")
566 }
567 }
568 }
569 }
570 }
571 if wasSplit {
572 c.stacksplitPost(pLast, pPre, pPreempt, pCheck, autosize)
573 }
574 }
575
576
577
578
579
580 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCheck *obj.Prog) {
581 if c.ctxt.Flag_maymorestack != "" {
582
583 const frameSize = 16
584 p = c.ctxt.StartUnsafePoint(p, c.newprog)
585
586 p = obj.Appendp(p, c.newprog)
587 p.As = AMOVD
588 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
589 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: -frameSize}
590
591 p = obj.Appendp(p, c.newprog)
592 p.As = AMOVD
593 p.From = obj.Addr{Type: obj.TYPE_ADDR, Offset: -frameSize, Reg: REGSP}
594 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
595 p.Spadj = frameSize
596
597 p = obj.Appendp(p, c.newprog)
598 p.As = AMOVD
599 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
600 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
601
602
603 p = obj.Appendp(p, c.newprog)
604 p.As = ABL
605
606 sym := c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
607 p.To = obj.Addr{Type: obj.TYPE_BRANCH, Sym: sym}
608
609
610
611
612 p = obj.Appendp(p, c.newprog)
613 p.As = AMOVD
614 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
615 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
616
617 p = obj.Appendp(p, c.newprog)
618 p.As = AMOVD
619 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 0}
620 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
621
622 p = obj.Appendp(p, c.newprog)
623 p.As = AMOVD
624 p.From = obj.Addr{Type: obj.TYPE_CONST, Reg: REGSP, Offset: frameSize}
625 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
626 p.Spadj = -frameSize
627
628 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
629 }
630
631
632 p = obj.Appendp(p, c.newprog)
633
634 pCheck = p
635
636 p.As = AMOVD
637 p.From.Type = obj.TYPE_MEM
638 p.From.Reg = REGG
639 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
640 if c.cursym.CFunc() {
641 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
642 }
643 p.To.Type = obj.TYPE_REG
644 p.To.Reg = REG_R3
645
646
647
648
649
650 p = c.ctxt.StartUnsafePoint(p, c.newprog)
651
652 if framesize <= objabi.StackSmall {
653
654
655
656 p = obj.Appendp(p, c.newprog)
657 p.From.Type = obj.TYPE_REG
658 p.From.Reg = REG_R3
659 p.Reg = REGSP
660 p.As = ACMPUBGE
661 p.To.Type = obj.TYPE_BRANCH
662
663 return p, nil, pCheck
664 }
665
666
667
668 offset := int64(framesize) - objabi.StackSmall
669 if framesize > objabi.StackBig {
670
671
672
673
674
675
676
677
678
679
680 p = obj.Appendp(p, c.newprog)
681 p.As = AMOVD
682 p.From.Type = obj.TYPE_CONST
683 p.From.Offset = offset
684 p.To.Type = obj.TYPE_REG
685 p.To.Reg = REG_R4
686
687 p = obj.Appendp(p, c.newprog)
688 pPreempt = p
689 p.As = ACMPUBLT
690 p.From.Type = obj.TYPE_REG
691 p.From.Reg = REGSP
692 p.Reg = REG_R4
693 p.To.Type = obj.TYPE_BRANCH
694 }
695
696
697
698
699 p = obj.Appendp(p, c.newprog)
700 p.As = AADD
701 p.From.Type = obj.TYPE_CONST
702 p.From.Offset = -offset
703 p.Reg = REGSP
704 p.To.Type = obj.TYPE_REG
705 p.To.Reg = REG_R4
706
707 p = obj.Appendp(p, c.newprog)
708 p.From.Type = obj.TYPE_REG
709 p.From.Reg = REG_R3
710 p.Reg = REG_R4
711 p.As = ACMPUBGE
712 p.To.Type = obj.TYPE_BRANCH
713
714 return p, pPreempt, pCheck
715 }
716
717
718
719
720
721
722
723 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre, pPreempt, pCheck *obj.Prog, framesize int32) *obj.Prog {
724
725
726
727 spfix := obj.Appendp(p, c.newprog)
728 spfix.As = obj.ANOP
729 spfix.Spadj = -framesize
730
731 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
732 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
733
734
735 p = obj.Appendp(pcdata, c.newprog)
736 pPre.To.SetTarget(p)
737 p.As = AMOVD
738 p.From.Type = obj.TYPE_REG
739 p.From.Reg = REG_LR
740 p.To.Type = obj.TYPE_REG
741 p.To.Reg = REG_R5
742 if pPreempt != nil {
743 pPreempt.To.SetTarget(p)
744 }
745
746
747 p = obj.Appendp(p, c.newprog)
748
749 p.As = ABL
750 p.To.Type = obj.TYPE_BRANCH
751 if c.cursym.CFunc() {
752 p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
753 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
754 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
755 } else {
756 p.To.Sym = c.ctxt.Lookup("runtime.morestack")
757 }
758
759 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
760
761
762 p = obj.Appendp(p, c.newprog)
763
764 p.As = ABR
765 p.To.Type = obj.TYPE_BRANCH
766 p.To.SetTarget(pCheck)
767 return p
768 }
769
770 var unaryDst = map[obj.As]bool{
771 ASTCK: true,
772 ASTCKC: true,
773 ASTCKE: true,
774 ASTCKF: true,
775 ANEG: true,
776 ANEGW: true,
777 AVONE: true,
778 AVZERO: true,
779 }
780
781 var Links390x = obj.LinkArch{
782 Arch: sys.ArchS390X,
783 Init: buildop,
784 Preprocess: preprocess,
785 Assemble: spanz,
786 Progedit: progedit,
787 UnaryDst: unaryDst,
788 DWARFRegisters: S390XDWARFRegisters,
789 }
790
View as plain text