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