github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/internal/obj/s390x/objz.go (about) 1 // Based on cmd/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/gagliardetto/golang-go/cmd/internal/obj" 34 "github.com/gagliardetto/golang-go/cmd/internal/objabi" 35 "github.com/gagliardetto/golang-go/cmd/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 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 if p.Pcond != nil { 287 q := p.Pcond 288 for q.As == obj.ANOP { 289 q = q.Link 290 p.Pcond = q 291 } 292 } 293 294 case obj.ANOP: 295 q.Link = p.Link /* q is non-nop */ 296 p.Link.Mark |= p.Mark 297 298 default: 299 q = p 300 } 301 } 302 303 autosize := int32(0) 304 var pLast *obj.Prog 305 var pPre *obj.Prog 306 var pPreempt *obj.Prog 307 wasSplit := false 308 for p := c.cursym.Func.Text; p != nil; p = p.Link { 309 pLast = p 310 switch p.As { 311 case obj.ATEXT: 312 autosize = int32(textstksiz) 313 314 if p.Mark&LEAF != 0 && autosize == 0 { 315 // A leaf function with no locals has no frame. 316 p.From.Sym.Set(obj.AttrNoFrame, true) 317 } 318 319 if !p.From.Sym.NoFrame() { 320 // If there is a stack frame at all, it includes 321 // space to save the LR. 322 autosize += int32(c.ctxt.FixedFrameSize()) 323 } 324 325 if p.Mark&LEAF != 0 && autosize < objabi.StackSmall { 326 // A leaf function with a small stack can be marked 327 // NOSPLIT, avoiding a stack check. 328 p.From.Sym.Set(obj.AttrNoSplit, true) 329 } 330 331 p.To.Offset = int64(autosize) 332 333 q := p 334 335 if !p.From.Sym.NoSplit() { 336 p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check 337 pPre = p 338 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1) 339 wasSplit = true //need post part of split 340 } 341 342 if autosize != 0 { 343 // Make sure to save link register for non-empty frame, even if 344 // it is a leaf function, so that traceback works. 345 // Store link register before decrementing SP, so if a signal comes 346 // during the execution of the function prologue, the traceback 347 // code will not see a half-updated stack frame. 348 // This sequence is not async preemptible, as if we open a frame 349 // at the current SP, it will clobber the saved LR. 350 q = c.ctxt.StartUnsafePoint(p, c.newprog) 351 352 q = obj.Appendp(q, c.newprog) 353 q.As = AMOVD 354 q.From.Type = obj.TYPE_REG 355 q.From.Reg = REG_LR 356 q.To.Type = obj.TYPE_MEM 357 q.To.Reg = REGSP 358 q.To.Offset = int64(-autosize) 359 360 q = obj.Appendp(q, c.newprog) 361 q.As = AMOVD 362 q.From.Type = obj.TYPE_ADDR 363 q.From.Offset = int64(-autosize) 364 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 365 q.To.Type = obj.TYPE_REG 366 q.To.Reg = REGSP 367 q.Spadj = autosize 368 369 q = c.ctxt.EndUnsafePoint(q, c.newprog, -1) 370 } else if c.cursym.Func.Text.Mark&LEAF == 0 { 371 // A very few functions that do not return to their caller 372 // (e.g. gogo) are not identified as leaves but still have 373 // no frame. 374 c.cursym.Func.Text.Mark |= LEAF 375 } 376 377 if c.cursym.Func.Text.Mark&LEAF != 0 { 378 c.cursym.Set(obj.AttrLeaf, true) 379 break 380 } 381 382 if c.cursym.Func.Text.From.Sym.Wrapper() { 383 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 384 // 385 // MOVD g_panic(g), R3 386 // CMP R3, $0 387 // BEQ end 388 // MOVD panic_argp(R3), R4 389 // ADD $(autosize+8), R1, R5 390 // CMP R4, R5 391 // BNE end 392 // ADD $8, R1, R6 393 // MOVD R6, panic_argp(R3) 394 // end: 395 // NOP 396 // 397 // The NOP is needed to give the jumps somewhere to land. 398 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 399 400 q = obj.Appendp(q, c.newprog) 401 402 q.As = AMOVD 403 q.From.Type = obj.TYPE_MEM 404 q.From.Reg = REGG 405 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 406 q.To.Type = obj.TYPE_REG 407 q.To.Reg = REG_R3 408 409 q = obj.Appendp(q, c.newprog) 410 q.As = ACMP 411 q.From.Type = obj.TYPE_REG 412 q.From.Reg = REG_R3 413 q.To.Type = obj.TYPE_CONST 414 q.To.Offset = 0 415 416 q = obj.Appendp(q, c.newprog) 417 q.As = ABEQ 418 q.To.Type = obj.TYPE_BRANCH 419 p1 := q 420 421 q = obj.Appendp(q, c.newprog) 422 q.As = AMOVD 423 q.From.Type = obj.TYPE_MEM 424 q.From.Reg = REG_R3 425 q.From.Offset = 0 // Panic.argp 426 q.To.Type = obj.TYPE_REG 427 q.To.Reg = REG_R4 428 429 q = obj.Appendp(q, c.newprog) 430 q.As = AADD 431 q.From.Type = obj.TYPE_CONST 432 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize() 433 q.Reg = REGSP 434 q.To.Type = obj.TYPE_REG 435 q.To.Reg = REG_R5 436 437 q = obj.Appendp(q, c.newprog) 438 q.As = ACMP 439 q.From.Type = obj.TYPE_REG 440 q.From.Reg = REG_R4 441 q.To.Type = obj.TYPE_REG 442 q.To.Reg = REG_R5 443 444 q = obj.Appendp(q, c.newprog) 445 q.As = ABNE 446 q.To.Type = obj.TYPE_BRANCH 447 p2 := q 448 449 q = obj.Appendp(q, c.newprog) 450 q.As = AADD 451 q.From.Type = obj.TYPE_CONST 452 q.From.Offset = c.ctxt.FixedFrameSize() 453 q.Reg = REGSP 454 q.To.Type = obj.TYPE_REG 455 q.To.Reg = REG_R6 456 457 q = obj.Appendp(q, c.newprog) 458 q.As = AMOVD 459 q.From.Type = obj.TYPE_REG 460 q.From.Reg = REG_R6 461 q.To.Type = obj.TYPE_MEM 462 q.To.Reg = REG_R3 463 q.To.Offset = 0 // Panic.argp 464 465 q = obj.Appendp(q, c.newprog) 466 467 q.As = obj.ANOP 468 p1.Pcond = q 469 p2.Pcond = q 470 } 471 472 case obj.ARET: 473 retTarget := p.To.Sym 474 475 if c.cursym.Func.Text.Mark&LEAF != 0 { 476 if autosize == 0 { 477 p.As = ABR 478 p.From = obj.Addr{} 479 if retTarget == nil { 480 p.To.Type = obj.TYPE_REG 481 p.To.Reg = REG_LR 482 } else { 483 p.To.Type = obj.TYPE_BRANCH 484 p.To.Sym = retTarget 485 } 486 p.Mark |= BRANCH 487 break 488 } 489 490 p.As = AADD 491 p.From.Type = obj.TYPE_CONST 492 p.From.Offset = int64(autosize) 493 p.To.Type = obj.TYPE_REG 494 p.To.Reg = REGSP 495 p.Spadj = -autosize 496 497 q = obj.Appendp(p, c.newprog) 498 q.As = ABR 499 q.From = obj.Addr{} 500 q.To.Type = obj.TYPE_REG 501 q.To.Reg = REG_LR 502 q.Mark |= BRANCH 503 q.Spadj = autosize 504 break 505 } 506 507 p.As = AMOVD 508 p.From.Type = obj.TYPE_MEM 509 p.From.Reg = REGSP 510 p.From.Offset = 0 511 p.To.Type = obj.TYPE_REG 512 p.To.Reg = REG_LR 513 514 q = p 515 516 if autosize != 0 { 517 q = obj.Appendp(q, c.newprog) 518 q.As = AADD 519 q.From.Type = obj.TYPE_CONST 520 q.From.Offset = int64(autosize) 521 q.To.Type = obj.TYPE_REG 522 q.To.Reg = REGSP 523 q.Spadj = -autosize 524 } 525 526 q = obj.Appendp(q, c.newprog) 527 q.As = ABR 528 q.From = obj.Addr{} 529 if retTarget == nil { 530 q.To.Type = obj.TYPE_REG 531 q.To.Reg = REG_LR 532 } else { 533 q.To.Type = obj.TYPE_BRANCH 534 q.To.Sym = retTarget 535 } 536 q.Mark |= BRANCH 537 q.Spadj = autosize 538 539 case AADD: 540 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 541 p.Spadj = int32(-p.From.Offset) 542 } 543 544 case obj.AGETCALLERPC: 545 if cursym.Leaf() { 546 /* MOVD LR, Rd */ 547 p.As = AMOVD 548 p.From.Type = obj.TYPE_REG 549 p.From.Reg = REG_LR 550 } else { 551 /* MOVD (RSP), Rd */ 552 p.As = AMOVD 553 p.From.Type = obj.TYPE_MEM 554 p.From.Reg = REGSP 555 } 556 } 557 } 558 if wasSplit { 559 c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check 560 } 561 } 562 563 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 564 var q *obj.Prog 565 566 // MOVD g_stackguard(g), R3 567 p = obj.Appendp(p, c.newprog) 568 569 p.As = AMOVD 570 p.From.Type = obj.TYPE_MEM 571 p.From.Reg = REGG 572 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 573 if c.cursym.CFunc() { 574 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 575 } 576 p.To.Type = obj.TYPE_REG 577 p.To.Reg = REG_R3 578 579 // Mark the stack bound check and morestack call async nonpreemptible. 580 // If we get preempted here, when resumed the preemption request is 581 // cleared, but we'll still call morestack, which will double the stack 582 // unnecessarily. See issue #35470. 583 p = c.ctxt.StartUnsafePoint(p, c.newprog) 584 585 q = nil 586 if framesize <= objabi.StackSmall { 587 // small stack: SP < stackguard 588 // CMPUBGE stackguard, SP, label-of-call-to-morestack 589 590 p = obj.Appendp(p, c.newprog) 591 //q1 = p 592 p.From.Type = obj.TYPE_REG 593 p.From.Reg = REG_R3 594 p.Reg = REGSP 595 p.As = ACMPUBGE 596 p.To.Type = obj.TYPE_BRANCH 597 598 } else if framesize <= objabi.StackBig { 599 // large stack: SP-framesize < stackguard-StackSmall 600 // ADD $-(framesize-StackSmall), SP, R4 601 // CMPUBGE stackguard, R4, label-of-call-to-morestack 602 p = obj.Appendp(p, c.newprog) 603 604 p.As = AADD 605 p.From.Type = obj.TYPE_CONST 606 p.From.Offset = -(int64(framesize) - objabi.StackSmall) 607 p.Reg = REGSP 608 p.To.Type = obj.TYPE_REG 609 p.To.Reg = REG_R4 610 611 p = obj.Appendp(p, c.newprog) 612 p.From.Type = obj.TYPE_REG 613 p.From.Reg = REG_R3 614 p.Reg = REG_R4 615 p.As = ACMPUBGE 616 p.To.Type = obj.TYPE_BRANCH 617 618 } else { 619 // Such a large stack we need to protect against wraparound. 620 // If SP is close to zero: 621 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 622 // The +StackGuard on both sides is required to keep the left side positive: 623 // SP is allowed to be slightly below stackguard. See stack.h. 624 // 625 // Preemption sets stackguard to StackPreempt, a very large value. 626 // That breaks the math above, so we have to check for that explicitly. 627 // // stackguard is R3 628 // CMP R3, $StackPreempt 629 // BEQ label-of-call-to-morestack 630 // ADD $StackGuard, SP, R4 631 // SUB R3, R4 632 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 633 // CMPUBGE TEMP, R4, label-of-call-to-morestack 634 p = obj.Appendp(p, c.newprog) 635 636 p.As = ACMP 637 p.From.Type = obj.TYPE_REG 638 p.From.Reg = REG_R3 639 p.To.Type = obj.TYPE_CONST 640 p.To.Offset = objabi.StackPreempt 641 642 p = obj.Appendp(p, c.newprog) 643 q = p 644 p.As = ABEQ 645 p.To.Type = obj.TYPE_BRANCH 646 647 p = obj.Appendp(p, c.newprog) 648 p.As = AADD 649 p.From.Type = obj.TYPE_CONST 650 p.From.Offset = int64(objabi.StackGuard) 651 p.Reg = REGSP 652 p.To.Type = obj.TYPE_REG 653 p.To.Reg = REG_R4 654 655 p = obj.Appendp(p, c.newprog) 656 p.As = ASUB 657 p.From.Type = obj.TYPE_REG 658 p.From.Reg = REG_R3 659 p.To.Type = obj.TYPE_REG 660 p.To.Reg = REG_R4 661 662 p = obj.Appendp(p, c.newprog) 663 p.As = AMOVD 664 p.From.Type = obj.TYPE_CONST 665 p.From.Offset = int64(framesize) + int64(objabi.StackGuard) - objabi.StackSmall 666 p.To.Type = obj.TYPE_REG 667 p.To.Reg = REGTMP 668 669 p = obj.Appendp(p, c.newprog) 670 p.From.Type = obj.TYPE_REG 671 p.From.Reg = REGTMP 672 p.Reg = REG_R4 673 p.As = ACMPUBGE 674 p.To.Type = obj.TYPE_BRANCH 675 } 676 677 return p, q 678 } 679 680 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog { 681 // Now we are at the end of the function, but logically 682 // we are still in function prologue. We need to fix the 683 // SP data and PCDATA. 684 spfix := obj.Appendp(p, c.newprog) 685 spfix.As = obj.ANOP 686 spfix.Spadj = -framesize 687 688 pcdata := c.ctxt.EmitEntryStackMap(c.cursym, spfix, c.newprog) 689 pcdata = c.ctxt.StartUnsafePoint(pcdata, c.newprog) 690 691 // MOVD LR, R5 692 p = obj.Appendp(pcdata, c.newprog) 693 pPre.Pcond = p 694 p.As = AMOVD 695 p.From.Type = obj.TYPE_REG 696 p.From.Reg = REG_LR 697 p.To.Type = obj.TYPE_REG 698 p.To.Reg = REG_R5 699 if pPreempt != nil { 700 pPreempt.Pcond = p 701 } 702 703 // BL runtime.morestack(SB) 704 p = obj.Appendp(p, c.newprog) 705 706 p.As = ABL 707 p.To.Type = obj.TYPE_BRANCH 708 if c.cursym.CFunc() { 709 p.To.Sym = c.ctxt.Lookup("runtime.morestackc") 710 } else if !c.cursym.Func.Text.From.Sym.NeedCtxt() { 711 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt") 712 } else { 713 p.To.Sym = c.ctxt.Lookup("runtime.morestack") 714 } 715 716 p = c.ctxt.EndUnsafePoint(p, c.newprog, -1) 717 718 // BR start 719 p = obj.Appendp(p, c.newprog) 720 721 p.As = ABR 722 p.To.Type = obj.TYPE_BRANCH 723 p.Pcond = c.cursym.Func.Text.Link 724 return p 725 } 726 727 var unaryDst = map[obj.As]bool{ 728 ASTCK: true, 729 ASTCKC: true, 730 ASTCKE: true, 731 ASTCKF: true, 732 ANEG: true, 733 ANEGW: true, 734 AVONE: true, 735 AVZERO: true, 736 } 737 738 var Links390x = obj.LinkArch{ 739 Arch: sys.ArchS390X, 740 Init: buildop, 741 Preprocess: preprocess, 742 Assemble: spanz, 743 Progedit: progedit, 744 UnaryDst: unaryDst, 745 DWARFRegisters: S390XDWARFRegisters, 746 }