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