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 case obj.ARET:
388 retTarget, retReg := p.To.Sym, p.To.Reg
389 if retReg == obj.REG_NONE {
390 retReg = REG_LR
391 }
392
393 if c.cursym.Func().Text.Mark&LEAF != 0 {
394 if autosize == 0 {
395 p.As = ABR
396 p.From = obj.Addr{}
397 if retTarget == nil {
398 p.To.Type = obj.TYPE_REG
399 p.To.Reg = retReg
400 } else {
401 p.To.Type = obj.TYPE_BRANCH
402 p.To.Sym = retTarget
403 }
404 p.Mark |= BRANCH
405 break
406 }
407
408 p.As = AADD
409 p.From.Type = obj.TYPE_CONST
410 p.From.Offset = int64(autosize)
411 p.To.Type = obj.TYPE_REG
412 p.To.Reg = REGSP
413 p.Spadj = -autosize
414
415 q = obj.Appendp(p, c.newprog)
416 q.As = ABR
417 q.From = obj.Addr{}
418 if retTarget == nil {
419 q.To.Type = obj.TYPE_REG
420 q.To.Reg = retReg
421 } else {
422 q.To.Type = obj.TYPE_BRANCH
423 q.To.Sym = retTarget
424 }
425 q.Mark |= BRANCH
426 q.Spadj = autosize
427 break
428 }
429
430 p.As = AMOVD
431 p.From.Type = obj.TYPE_MEM
432 p.From.Reg = REGSP
433 p.From.Offset = 0
434 p.To = obj.Addr{
435 Type: obj.TYPE_REG,
436 Reg: REG_LR,
437 }
438
439 q = p
440
441 if autosize != 0 {
442 q = obj.Appendp(q, c.newprog)
443 q.As = AADD
444 q.From.Type = obj.TYPE_CONST
445 q.From.Offset = int64(autosize)
446 q.To.Type = obj.TYPE_REG
447 q.To.Reg = REGSP
448 q.Spadj = -autosize
449 }
450
451 q = obj.Appendp(q, c.newprog)
452 q.As = ABR
453 q.From = obj.Addr{}
454 if retTarget == nil {
455 q.To.Type = obj.TYPE_REG
456 q.To.Reg = retReg
457 } else {
458 q.To.Type = obj.TYPE_BRANCH
459 q.To.Sym = retTarget
460 }
461 q.Mark |= BRANCH
462 q.Spadj = autosize
463
464 case AADD:
465 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
466 p.Spadj = int32(-p.From.Offset)
467 }
468
469 case obj.AGETCALLERPC:
470 if cursym.Leaf() {
471
472 p.As = AMOVD
473 p.From.Type = obj.TYPE_REG
474 p.From.Reg = REG_LR
475 } else {
476
477 p.As = AMOVD
478 p.From.Type = obj.TYPE_MEM
479 p.From.Reg = REGSP
480 }
481 }
482
483 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.Spadj == 0 {
484 f := c.cursym.Func()
485 if f.FuncFlag&abi.FuncFlagSPWrite == 0 {
486 c.cursym.Func().FuncFlag |= abi.FuncFlagSPWrite
487 if ctxt.Debugvlog || !ctxt.IsAsm {
488 ctxt.Logf("auto-SPWRITE: %s\n", c.cursym.Name)
489 if !ctxt.IsAsm {
490 ctxt.Diag("invalid auto-SPWRITE in non-assembly")
491 ctxt.DiagFlush()
492 log.Fatalf("bad SPWRITE")
493 }
494 }
495 }
496 }
497 }
498 if wasSplit {
499 c.stacksplitPost(pLast, pPre, pPreempt, pCheck, autosize)
500 }
501 }
502
503
504
505
506
507 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (pPre, pPreempt, pCheck *obj.Prog) {
508 if c.ctxt.Flag_maymorestack != "" {
509
510 const frameSize = 16
511 p = c.ctxt.StartUnsafePoint(p, c.newprog)
512
513
514
515 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
516
517
518
519 p = obj.Appendp(p, c.newprog)
520 p.As = AMOVD
521 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
522 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: -frameSize}
523
524 p = obj.Appendp(p, c.newprog)
525 p.As = AMOVD
526 p.From = obj.Addr{Type: obj.TYPE_ADDR, Offset: -frameSize, Reg: REGSP}
527 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
528 p.Spadj = frameSize
529
530 p = obj.Appendp(p, c.newprog)
531 p.As = AMOVD
532 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
533 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
534
535
536 p = obj.Appendp(p, c.newprog)
537 p.As = ABL
538
539 sym := c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
540 p.To = obj.Addr{Type: obj.TYPE_BRANCH, Sym: sym}
541
542
543
544
545 p = obj.Appendp(p, c.newprog)
546 p.As = AMOVD
547 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
548 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
549
550 p = obj.Appendp(p, c.newprog)
551 p.As = AMOVD
552 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 0}
553 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
554
555 p = obj.Appendp(p, c.newprog)
556 p.As = AMOVD
557 p.From = obj.Addr{Type: obj.TYPE_CONST, Reg: REGSP, Offset: frameSize}
558 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
559 p.Spadj = -frameSize
560
561
562 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
563 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
564 }
565
566
567 p = obj.Appendp(p, c.newprog)
568
569 pCheck = p
570
571 p.As = AMOVD
572 p.From.Type = obj.TYPE_MEM
573 p.From.Reg = REGG
574 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
575 if c.cursym.CFunc() {
576 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
577 }
578 p.To.Type = obj.TYPE_REG
579 p.To.Reg = REG_R10
580
581
582
583
584
585 p = c.ctxt.StartUnsafePoint(p, c.newprog)
586
587 if framesize <= abi.StackSmall {
588
589
590
591 p = obj.Appendp(p, c.newprog)
592 p.From.Type = obj.TYPE_REG
593 p.From.Reg = REG_R10
594 p.Reg = REGSP
595 p.As = ACMPUBGE
596 p.To.Type = obj.TYPE_BRANCH
597
598 return p, nil, pCheck
599 }
600
601
602
603 offset := int64(framesize) - abi.StackSmall
604 if framesize > abi.StackBig {
605
606
607
608
609
610
611
612
613
614
615 p = obj.Appendp(p, c.newprog)
616 p.As = AMOVD
617 p.From.Type = obj.TYPE_CONST
618 p.From.Offset = offset
619 p.To.Type = obj.TYPE_REG
620 p.To.Reg = REG_R11
621
622 p = obj.Appendp(p, c.newprog)
623 pPreempt = p
624 p.As = ACMPUBLT
625 p.From.Type = obj.TYPE_REG
626 p.From.Reg = REGSP
627 p.Reg = REG_R11
628 p.To.Type = obj.TYPE_BRANCH
629 }
630
631
632
633
634 p = obj.Appendp(p, c.newprog)
635 p.As = AADD
636 p.From.Type = obj.TYPE_CONST
637 p.From.Offset = -offset
638 p.Reg = REGSP
639 p.To.Type = obj.TYPE_REG
640 p.To.Reg = REG_R11
641
642 p = obj.Appendp(p, c.newprog)
643 p.From.Type = obj.TYPE_REG
644 p.From.Reg = REG_R10
645 p.Reg = REG_R11
646 p.As = ACMPUBGE
647 p.To.Type = obj.TYPE_BRANCH
648
649 return p, pPreempt, pCheck
650 }
651
652
653
654
655
656
657
658 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre, pPreempt, pCheck *obj.Prog, framesize int32) *obj.Prog {
659
660
661
662 spfix := obj.Appendp(p, c.newprog)
663 spfix.As = obj.ANOP
664 spfix.Spadj = -framesize
665
666 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
667 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
668 if pPreempt != nil {
669 pPreempt.To.SetTarget(pcdata)
670 }
671 pPre.To.SetTarget(pcdata)
672
673
674
675 spill := c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
676
677
678 p = obj.Appendp(spill, c.newprog)
679 p.As = AMOVD
680 p.From.Type = obj.TYPE_REG
681 p.From.Reg = REG_LR
682 p.To.Type = obj.TYPE_REG
683 p.To.Reg = REG_R5
684
685
686 p = obj.Appendp(p, c.newprog)
687
688 p.As = ABL
689 p.To.Type = obj.TYPE_BRANCH
690 if c.cursym.CFunc() {
691 p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
692 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
693 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
694 } else {
695 p.To.Sym = c.ctxt.Lookup("runtime.morestack")
696 }
697
698
699 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
700 unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
701
702
703 p = obj.Appendp(unspill, c.newprog)
704
705 p.As = ABR
706 p.To.Type = obj.TYPE_BRANCH
707 p.To.SetTarget(pCheck)
708 return p
709 }
710
711 var unaryDst = map[obj.As]bool{
712 ASTCK: true,
713 ASTCKC: true,
714 ASTCKE: true,
715 ASTCKF: true,
716 ANEG: true,
717 ANEGW: true,
718 AVONE: true,
719 AVZERO: true,
720 }
721
722 var Links390x = obj.LinkArch{
723 Arch: sys.ArchS390X,
724 Init: buildop,
725 Preprocess: preprocess,
726 Assemble: spanz,
727 Progedit: progedit,
728 UnaryDst: unaryDst,
729 DWARFRegisters: S390XDWARFRegisters,
730 }
731
View as plain text