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