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