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
511
512 p = c.cursym.Func().SpillRegisterArgs(p, c.newprog)
513
514
515
516 p = obj.Appendp(p, c.newprog)
517 p.As = AMOVD
518 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
519 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: -frameSize}
520
521 p = obj.Appendp(p, c.newprog)
522 p.As = AMOVD
523 p.From = obj.Addr{Type: obj.TYPE_ADDR, Offset: -frameSize, Reg: REGSP}
524 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
525 p.Spadj = frameSize
526
527 p = obj.Appendp(p, c.newprog)
528 p.As = AMOVD
529 p.From = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
530 p.To = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
531
532
533 p = obj.Appendp(p, c.newprog)
534 p.As = ABL
535
536 sym := c.ctxt.LookupABI(c.ctxt.Flag_maymorestack, c.cursym.ABI())
537 p.To = obj.Addr{Type: obj.TYPE_BRANCH, Sym: sym}
538
539
540
541
542 p = obj.Appendp(p, c.newprog)
543 p.As = AMOVD
544 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 8}
545 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGCTXT}
546
547 p = obj.Appendp(p, c.newprog)
548 p.As = AMOVD
549 p.From = obj.Addr{Type: obj.TYPE_MEM, Reg: REGSP, Offset: 0}
550 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REG_LR}
551
552 p = obj.Appendp(p, c.newprog)
553 p.As = AMOVD
554 p.From = obj.Addr{Type: obj.TYPE_CONST, Reg: REGSP, Offset: frameSize}
555 p.To = obj.Addr{Type: obj.TYPE_REG, Reg: REGSP}
556 p.Spadj = -frameSize
557
558
559 p = c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
560 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
561 }
562
563
564 p = obj.Appendp(p, c.newprog)
565
566 pCheck = p
567
568 p.As = AMOVD
569 p.From.Type = obj.TYPE_MEM
570 p.From.Reg = REGG
571 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize)
572 if c.cursym.CFunc() {
573 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize)
574 }
575 p.To.Type = obj.TYPE_REG
576 p.To.Reg = REG_R10
577
578
579
580
581
582 p = c.ctxt.StartUnsafePoint(p, c.newprog)
583
584 if framesize <= abi.StackSmall {
585
586
587
588 p = obj.Appendp(p, c.newprog)
589 p.From.Type = obj.TYPE_REG
590 p.From.Reg = REG_R10
591 p.Reg = REGSP
592 p.As = ACMPUBGE
593 p.To.Type = obj.TYPE_BRANCH
594
595 return p, nil, pCheck
596 }
597
598
599
600 offset := int64(framesize) - abi.StackSmall
601 if framesize > abi.StackBig {
602
603
604
605
606
607
608
609
610
611
612 p = obj.Appendp(p, c.newprog)
613 p.As = AMOVD
614 p.From.Type = obj.TYPE_CONST
615 p.From.Offset = offset
616 p.To.Type = obj.TYPE_REG
617 p.To.Reg = REG_R11
618
619 p = obj.Appendp(p, c.newprog)
620 pPreempt = p
621 p.As = ACMPUBLT
622 p.From.Type = obj.TYPE_REG
623 p.From.Reg = REGSP
624 p.Reg = REG_R11
625 p.To.Type = obj.TYPE_BRANCH
626 }
627
628
629
630
631 p = obj.Appendp(p, c.newprog)
632 p.As = AADD
633 p.From.Type = obj.TYPE_CONST
634 p.From.Offset = -offset
635 p.Reg = REGSP
636 p.To.Type = obj.TYPE_REG
637 p.To.Reg = REG_R11
638
639 p = obj.Appendp(p, c.newprog)
640 p.From.Type = obj.TYPE_REG
641 p.From.Reg = REG_R10
642 p.Reg = REG_R11
643 p.As = ACMPUBGE
644 p.To.Type = obj.TYPE_BRANCH
645
646 return p, pPreempt, pCheck
647 }
648
649
650
651
652
653
654
655 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre, pPreempt, pCheck *obj.Prog, framesize int32) *obj.Prog {
656
657
658
659 spfix := obj.Appendp(p, c.newprog)
660 spfix.As = obj.ANOP
661 spfix.Spadj = -framesize
662
663 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog)
664 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog)
665 if pPreempt != nil {
666 pPreempt.To.SetTarget(pcdata)
667 }
668 pPre.To.SetTarget(pcdata)
669
670
671
672 spill := c.cursym.Func().SpillRegisterArgs(pcdata, c.newprog)
673
674
675 p = obj.Appendp(spill, c.newprog)
676 p.As = AMOVD
677 p.From.Type = obj.TYPE_REG
678 p.From.Reg = REG_LR
679 p.To.Type = obj.TYPE_REG
680 p.To.Reg = REG_R5
681
682
683 p = obj.Appendp(p, c.newprog)
684
685 p.As = ABL
686 p.To.Type = obj.TYPE_BRANCH
687 if c.cursym.CFunc() {
688 p.To.Sym = c.ctxt.Lookup("runtime.morestackc")
689 } else if !c.cursym.Func().Text.From.Sym.NeedCtxt() {
690 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt")
691 } else {
692 p.To.Sym = c.ctxt.Lookup("runtime.morestack")
693 }
694
695
696 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1)
697 unspill := c.cursym.Func().UnspillRegisterArgs(p, c.newprog)
698
699
700 p = obj.Appendp(unspill, c.newprog)
701
702 p.As = ABR
703 p.To.Type = obj.TYPE_BRANCH
704 p.To.SetTarget(pCheck)
705 return p
706 }
707
708 var unaryDst = map[obj.As]bool{
709 ASTCK: true,
710 ASTCKC: true,
711 ASTCKE: true,
712 ASTCKF: true,
713 ANEG: true,
714 ANEGW: true,
715 AVONE: true,
716 AVZERO: true,
717 }
718
719 var Links390x = obj.LinkArch{
720 Arch: sys.ArchS390X,
721 Init: buildop,
722 Preprocess: preprocess,
723 Assemble: spanz,
724 Progedit: progedit,
725 UnaryDst: unaryDst,
726 DWARFRegisters: S390XDWARFRegisters,
727 }
728
View as plain text