github.com/gernest/nezuko@v0.1.2/internal/obj/s390x/objz.go (about) 1 // Based on github.com/gernest/nezuko/internal/obj/ppc64/obj9.go. 2 // 3 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 4 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 5 // Portions Copyright © 1997-1999 Vita Nuova Limited 6 // Portions Copyright © 2000-2008 Vita Nuova Holdings Limited (www.vitanuova.com) 7 // Portions Copyright © 2004,2006 Bruce Ellis 8 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 9 // Revisions Copyright © 2000-2008 Lucent Technologies Inc. and others 10 // Portions Copyright © 2009 The Go Authors. All rights reserved. 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining a copy 13 // of this software and associated documentation files (the "Software"), to deal 14 // in the Software without restriction, including without limitation the rights 15 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 // copies of the Software, and to permit persons to whom the Software is 17 // furnished to do so, subject to the following conditions: 18 // 19 // The above copyright notice and this permission notice shall be included in 20 // all copies or substantial portions of the Software. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 // THE SOFTWARE. 29 30 package s390x 31 32 import ( 33 "github.com/gernest/nezuko/internal/obj" 34 "github.com/gernest/nezuko/internal/objabi" 35 "github.com/gernest/nezuko/internal/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 // Rewrite BR/BL to symbol as TYPE_BRANCH. 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 // Rewrite float constants to values stored in memory unless they are +0. 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 { // +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 { // +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 // put constants not loadable by LOAD IMMEDIATE into memory 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 // Rewrite SUB constants into ADD. 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 // Rewrite p, if necessary, to access global data via the global offset table. 115 func (c *ctxtz) rewriteToUseGot(p *obj.Prog) { 116 // At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in 117 // assembly code. 118 if p.As == AEXRL { 119 return 120 } 121 122 // We only care about global data: NAME_EXTERN means a global 123 // symbol in the Go sense, and p.Sym.Local is true for a few 124 // internally defined symbols. 125 // Rewrites must not clobber flags and therefore cannot use the 126 // ADD instruction. 127 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 128 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 129 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx or REGTMP2; MOVD $<off>(Rx or REGTMP2), Rx 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 // Cannot use R0 as input to address calculation. 140 // REGTMP might be used by the assembler. 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 // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP2; MOVD (REGTMP2), Ry 158 // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP2; MOVD Ry, (REGTMP2) 159 // An addition may be inserted between the two MOVs if there is an offset. 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 // TODO(minux): add morestack short-cuts with small fixed frame-size. 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 // Compatibility hack. 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 /* 234 * find leaf subroutines 235 * strip NOPs 236 * expand RET 237 */ 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 ABEQ, 253 ABGE, 254 ABGT, 255 ABLE, 256 ABLT, 257 ABLEU, 258 ABLTU, 259 ABNE, 260 ABR, 261 ABVC, 262 ABVS, 263 ACMPBEQ, 264 ACMPBGE, 265 ACMPBGT, 266 ACMPBLE, 267 ACMPBLT, 268 ACMPBNE, 269 ACMPUBEQ, 270 ACMPUBGE, 271 ACMPUBGT, 272 ACMPUBLE, 273 ACMPUBLT, 274 ACMPUBNE: 275 q = p 276 p.Mark |= BRANCH 277 if p.Pcond != nil { 278 q := p.Pcond 279 for q.As == obj.ANOP { 280 q = q.Link 281 p.Pcond = q 282 } 283 } 284 285 case obj.ANOP: 286 q.Link = p.Link /* q is non-nop */ 287 p.Link.Mark |= p.Mark 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 wasSplit := false 299 for p := c.cursym.Func.Text; p != nil; p = p.Link { 300 pLast = p 301 switch p.As { 302 case obj.ATEXT: 303 autosize = int32(textstksiz) 304 305 if p.Mark&LEAF != 0 && autosize == 0 { 306 // A leaf function with no locals has no frame. 307 p.From.Sym.Set(obj.AttrNoFrame, true) 308 } 309 310 if !p.From.Sym.NoFrame() { 311 // If there is a stack frame at all, it includes 312 // space to save the LR. 313 autosize += int32(c.ctxt.FixedFrameSize()) 314 } 315 316 if p.Mark&LEAF != 0 && autosize < objabi.StackSmall { 317 // A leaf function with a small stack can be marked 318 // NOSPLIT, avoiding a stack check. 319 p.From.Sym.Set(obj.AttrNoSplit, true) 320 } 321 322 p.To.Offset = int64(autosize) 323 324 q := p 325 326 if !p.From.Sym.NoSplit() { 327 p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check 328 pPre = p 329 wasSplit = true //need post part of split 330 } 331 332 if autosize != 0 { 333 // Make sure to save link register for non-empty frame, even if 334 // it is a leaf function, so that traceback works. 335 // Store link register before decrementing SP, so if a signal comes 336 // during the execution of the function prologue, the traceback 337 // code will not see a half-updated stack frame. 338 q = obj.Appendp(p, c.newprog) 339 q.As = AMOVD 340 q.From.Type = obj.TYPE_REG 341 q.From.Reg = REG_LR 342 q.To.Type = obj.TYPE_MEM 343 q.To.Reg = REGSP 344 q.To.Offset = int64(-autosize) 345 346 q = obj.Appendp(q, c.newprog) 347 q.As = AMOVD 348 q.From.Type = obj.TYPE_ADDR 349 q.From.Offset = int64(-autosize) 350 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 351 q.To.Type = obj.TYPE_REG 352 q.To.Reg = REGSP 353 q.Spadj = autosize 354 } else if c.cursym.Func.Text.Mark&LEAF == 0 { 355 // A very few functions that do not return to their caller 356 // (e.g. gogo) are not identified as leaves but still have 357 // no frame. 358 c.cursym.Func.Text.Mark |= LEAF 359 } 360 361 if c.cursym.Func.Text.Mark&LEAF != 0 { 362 c.cursym.Set(obj.AttrLeaf, true) 363 break 364 } 365 366 if c.cursym.Func.Text.From.Sym.Wrapper() { 367 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 368 // 369 // MOVD g_panic(g), R3 370 // CMP R3, $0 371 // BEQ end 372 // MOVD panic_argp(R3), R4 373 // ADD $(autosize+8), R1, R5 374 // CMP R4, R5 375 // BNE end 376 // ADD $8, R1, R6 377 // MOVD R6, panic_argp(R3) 378 // end: 379 // NOP 380 // 381 // The NOP is needed to give the jumps somewhere to land. 382 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 383 384 q = obj.Appendp(q, c.newprog) 385 386 q.As = AMOVD 387 q.From.Type = obj.TYPE_MEM 388 q.From.Reg = REGG 389 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 390 q.To.Type = obj.TYPE_REG 391 q.To.Reg = REG_R3 392 393 q = obj.Appendp(q, c.newprog) 394 q.As = ACMP 395 q.From.Type = obj.TYPE_REG 396 q.From.Reg = REG_R3 397 q.To.Type = obj.TYPE_CONST 398 q.To.Offset = 0 399 400 q = obj.Appendp(q, c.newprog) 401 q.As = ABEQ 402 q.To.Type = obj.TYPE_BRANCH 403 p1 := q 404 405 q = obj.Appendp(q, c.newprog) 406 q.As = AMOVD 407 q.From.Type = obj.TYPE_MEM 408 q.From.Reg = REG_R3 409 q.From.Offset = 0 // Panic.argp 410 q.To.Type = obj.TYPE_REG 411 q.To.Reg = REG_R4 412 413 q = obj.Appendp(q, c.newprog) 414 q.As = AADD 415 q.From.Type = obj.TYPE_CONST 416 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize() 417 q.Reg = REGSP 418 q.To.Type = obj.TYPE_REG 419 q.To.Reg = REG_R5 420 421 q = obj.Appendp(q, c.newprog) 422 q.As = ACMP 423 q.From.Type = obj.TYPE_REG 424 q.From.Reg = REG_R4 425 q.To.Type = obj.TYPE_REG 426 q.To.Reg = REG_R5 427 428 q = obj.Appendp(q, c.newprog) 429 q.As = ABNE 430 q.To.Type = obj.TYPE_BRANCH 431 p2 := q 432 433 q = obj.Appendp(q, c.newprog) 434 q.As = AADD 435 q.From.Type = obj.TYPE_CONST 436 q.From.Offset = c.ctxt.FixedFrameSize() 437 q.Reg = REGSP 438 q.To.Type = obj.TYPE_REG 439 q.To.Reg = REG_R6 440 441 q = obj.Appendp(q, c.newprog) 442 q.As = AMOVD 443 q.From.Type = obj.TYPE_REG 444 q.From.Reg = REG_R6 445 q.To.Type = obj.TYPE_MEM 446 q.To.Reg = REG_R3 447 q.To.Offset = 0 // Panic.argp 448 449 q = obj.Appendp(q, c.newprog) 450 451 q.As = obj.ANOP 452 p1.Pcond = q 453 p2.Pcond = q 454 } 455 456 case obj.ARET: 457 retTarget := p.To.Sym 458 459 if c.cursym.Func.Text.Mark&LEAF != 0 { 460 if autosize == 0 { 461 p.As = ABR 462 p.From = obj.Addr{} 463 if retTarget == nil { 464 p.To.Type = obj.TYPE_REG 465 p.To.Reg = REG_LR 466 } else { 467 p.To.Type = obj.TYPE_BRANCH 468 p.To.Sym = retTarget 469 } 470 p.Mark |= BRANCH 471 break 472 } 473 474 p.As = AADD 475 p.From.Type = obj.TYPE_CONST 476 p.From.Offset = int64(autosize) 477 p.To.Type = obj.TYPE_REG 478 p.To.Reg = REGSP 479 p.Spadj = -autosize 480 481 q = obj.Appendp(p, c.newprog) 482 q.As = ABR 483 q.From = obj.Addr{} 484 q.To.Type = obj.TYPE_REG 485 q.To.Reg = REG_LR 486 q.Mark |= BRANCH 487 q.Spadj = autosize 488 break 489 } 490 491 p.As = AMOVD 492 p.From.Type = obj.TYPE_MEM 493 p.From.Reg = REGSP 494 p.From.Offset = 0 495 p.To.Type = obj.TYPE_REG 496 p.To.Reg = REG_LR 497 498 q = p 499 500 if autosize != 0 { 501 q = obj.Appendp(q, c.newprog) 502 q.As = AADD 503 q.From.Type = obj.TYPE_CONST 504 q.From.Offset = int64(autosize) 505 q.To.Type = obj.TYPE_REG 506 q.To.Reg = REGSP 507 q.Spadj = -autosize 508 } 509 510 q = obj.Appendp(q, c.newprog) 511 q.As = ABR 512 q.From = obj.Addr{} 513 if retTarget == nil { 514 q.To.Type = obj.TYPE_REG 515 q.To.Reg = REG_LR 516 } else { 517 q.To.Type = obj.TYPE_BRANCH 518 q.To.Sym = retTarget 519 } 520 q.Mark |= BRANCH 521 q.Spadj = autosize 522 523 case AADD: 524 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 525 p.Spadj = int32(-p.From.Offset) 526 } 527 528 case obj.AGETCALLERPC: 529 if cursym.Leaf() { 530 /* MOVD LR, Rd */ 531 p.As = AMOVD 532 p.From.Type = obj.TYPE_REG 533 p.From.Reg = REG_LR 534 } else { 535 /* MOVD (RSP), Rd */ 536 p.As = AMOVD 537 p.From.Type = obj.TYPE_MEM 538 p.From.Reg = REGSP 539 } 540 } 541 } 542 if wasSplit { 543 c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check 544 } 545 } 546 547 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 548 var q *obj.Prog 549 550 // MOVD g_stackguard(g), R3 551 p = obj.Appendp(p, c.newprog) 552 553 p.As = AMOVD 554 p.From.Type = obj.TYPE_MEM 555 p.From.Reg = REGG 556 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 557 if c.cursym.CFunc() { 558 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 559 } 560 p.To.Type = obj.TYPE_REG 561 p.To.Reg = REG_R3 562 563 q = nil 564 if framesize <= objabi.StackSmall { 565 // small stack: SP < stackguard 566 // CMP stackguard, SP 567 568 //p.To.Type = obj.TYPE_REG 569 //p.To.Reg = REGSP 570 571 // q1: BLT done 572 573 p = obj.Appendp(p, c.newprog) 574 //q1 = p 575 p.From.Type = obj.TYPE_REG 576 p.From.Reg = REG_R3 577 p.Reg = REGSP 578 p.As = ACMPUBGE 579 p.To.Type = obj.TYPE_BRANCH 580 //p = obj.Appendp(ctxt, p) 581 582 //p.As = ACMPU 583 //p.From.Type = obj.TYPE_REG 584 //p.From.Reg = REG_R3 585 //p.To.Type = obj.TYPE_REG 586 //p.To.Reg = REGSP 587 588 //p = obj.Appendp(ctxt, p) 589 //p.As = ABGE 590 //p.To.Type = obj.TYPE_BRANCH 591 592 } else if framesize <= objabi.StackBig { 593 // large stack: SP-framesize < stackguard-StackSmall 594 // ADD $-(framesize-StackSmall), SP, R4 595 // CMP stackguard, R4 596 p = obj.Appendp(p, c.newprog) 597 598 p.As = AADD 599 p.From.Type = obj.TYPE_CONST 600 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 601 p.Reg = REGSP 602 p.To.Type = obj.TYPE_REG 603 p.To.Reg = REG_R4 604 605 p = obj.Appendp(p, c.newprog) 606 p.From.Type = obj.TYPE_REG 607 p.From.Reg = REG_R3 608 p.Reg = REG_R4 609 p.As = ACMPUBGE 610 p.To.Type = obj.TYPE_BRANCH 611 612 } else { 613 // Such a large stack we need to protect against wraparound. 614 // If SP is close to zero: 615 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 616 // The +StackGuard on both sides is required to keep the left side positive: 617 // SP is allowed to be slightly below stackguard. See stack.h. 618 // 619 // Preemption sets stackguard to StackPreempt, a very large value. 620 // That breaks the math above, so we have to check for that explicitly. 621 // // stackguard is R3 622 // CMP R3, $StackPreempt 623 // BEQ label-of-call-to-morestack 624 // ADD $StackGuard, SP, R4 625 // SUB R3, R4 626 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 627 // CMPUBGE TEMP, R4 628 p = obj.Appendp(p, c.newprog) 629 630 p.As = ACMP 631 p.From.Type = obj.TYPE_REG 632 p.From.Reg = REG_R3 633 p.To.Type = obj.TYPE_CONST 634 p.To.Offset = objabi.StackPreempt 635 636 p = obj.Appendp(p, c.newprog) 637 q = p 638 p.As = ABEQ 639 p.To.Type = obj.TYPE_BRANCH 640 641 p = obj.Appendp(p, c.newprog) 642 p.As = AADD 643 p.From.Type = obj.TYPE_CONST 644 p.From.Offset = int64(objabi.StackGuard) 645 p.Reg = REGSP 646 p.To.Type = obj.TYPE_REG 647 p.To.Reg = REG_R4 648 649 p = obj.Appendp(p, c.newprog) 650 p.As = ASUB 651 p.From.Type = obj.TYPE_REG 652 p.From.Reg = REG_R3 653 p.To.Type = obj.TYPE_REG 654 p.To.Reg = REG_R4 655 656 p = obj.Appendp(p, c.newprog) 657 p.As = AMOVD 658 p.From.Type = obj.TYPE_CONST 659 p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall 660 p.To.Type = obj.TYPE_REG 661 p.To.Reg = REGTMP 662 663 p = obj.Appendp(p, c.newprog) 664 p.From.Type = obj.TYPE_REG 665 p.From.Reg = REGTMP 666 p.Reg = REG_R4 667 p.As = ACMPUBGE 668 p.To.Type = obj.TYPE_BRANCH 669 } 670 671 return p, q 672 } 673 674 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog { 675 // Now we are at the end of the function, but logically 676 // we are still in function prologue. We need to fix the 677 // SP data and PCDATA. 678 spfix := obj.Appendp(p, c.newprog) 679 spfix.As = obj.ANOP 680 spfix.Spadj = -framesize 681 682 pcdata := c.ctxt.EmitEntryLiveness(c.cursym, spfix, c.newprog) 683 684 // MOVD LR, R5 685 p = obj.Appendp(pcdata, c.newprog) 686 pPre.Pcond = p 687 p.As = AMOVD 688 p.From.Type = obj.TYPE_REG 689 p.From.Reg = REG_LR 690 p.To.Type = obj.TYPE_REG 691 p.To.Reg = REG_R5 692 if pPreempt != nil { 693 pPreempt.Pcond = p 694 } 695 696 // BL runtime.morestack(SB) 697 p = obj.Appendp(p, c.newprog) 698 699 p.As = ABL 700 p.To.Type = obj.TYPE_BRANCH 701 if c.cursym.CFunc() { 702 p.To.Sym = c.ctxt.Lookup("runtime.morestackc") 703 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() { 704 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt") 705 } else { 706 p.To.Sym = c.ctxt.Lookup("runtime.morestack") 707 } 708 709 // BR start 710 p = obj.Appendp(p, c.newprog) 711 712 p.As = ABR 713 p.To.Type = obj.TYPE_BRANCH 714 p.Pcond = c.cursym.Func.Text.Link 715 return p 716 } 717 718 var unaryDst = map[obj.As]bool{ 719 ASTCK: true, 720 ASTCKC: true, 721 ASTCKE: true, 722 ASTCKF: true, 723 ANEG: true, 724 ANEGW: true, 725 AVONE: true, 726 AVZERO: true, 727 } 728 729 var Links390x = obj.LinkArch{ 730 Arch: sys.ArchS390X, 731 Init: buildop, 732 Preprocess: preprocess, 733 Assemble: spanz, 734 Progedit: progedit, 735 UnaryDst: unaryDst, 736 DWARFRegisters: S390XDWARFRegisters, 737 }