github.com/tidwall/go@v0.0.0-20170415222209-6694a6888b7d/src/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 "cmd/internal/obj" 34 "cmd/internal/sys" 35 "math" 36 ) 37 38 func progedit(ctxt *obj.Link, p *obj.Prog, newprog obj.ProgAlloc) { 39 p.From.Class = 0 40 p.To.Class = 0 41 42 c := ctxtz{ctxt: ctxt, newprog: newprog} 43 44 // Rewrite BR/BL to symbol as TYPE_BRANCH. 45 switch p.As { 46 case ABR, ABL, obj.ARET, obj.ADUFFZERO, obj.ADUFFCOPY: 47 if p.To.Sym != nil { 48 p.To.Type = obj.TYPE_BRANCH 49 } 50 } 51 52 // Rewrite float constants to values stored in memory unless they are +0. 53 switch p.As { 54 case AFMOVS: 55 if p.From.Type == obj.TYPE_FCONST { 56 f32 := float32(p.From.Val.(float64)) 57 if math.Float32bits(f32) == 0 { // +0 58 break 59 } 60 p.From.Type = obj.TYPE_MEM 61 p.From.Sym = ctxt.Float32Sym(f32) 62 p.From.Name = obj.NAME_EXTERN 63 p.From.Offset = 0 64 } 65 66 case AFMOVD: 67 if p.From.Type == obj.TYPE_FCONST { 68 f64 := p.From.Val.(float64) 69 if math.Float64bits(f64) == 0 { // +0 70 break 71 } 72 p.From.Type = obj.TYPE_MEM 73 p.From.Sym = ctxt.Float64Sym(f64) 74 p.From.Name = obj.NAME_EXTERN 75 p.From.Offset = 0 76 } 77 78 // put constants not loadable by LOAD IMMEDIATE into memory 79 case AMOVD: 80 if p.From.Type == obj.TYPE_CONST { 81 val := p.From.Offset 82 if int64(int32(val)) != val && 83 int64(uint32(val)) != val && 84 int64(uint64(val)&(0xffffffff<<32)) != val { 85 p.From.Type = obj.TYPE_MEM 86 p.From.Sym = ctxt.Int64Sym(p.From.Offset) 87 p.From.Name = obj.NAME_EXTERN 88 p.From.Offset = 0 89 } 90 } 91 } 92 93 // Rewrite SUB constants into ADD. 94 switch p.As { 95 case ASUBC: 96 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) { 97 p.From.Offset = -p.From.Offset 98 p.As = AADDC 99 } 100 101 case ASUB: 102 if p.From.Type == obj.TYPE_CONST && isint32(-p.From.Offset) { 103 p.From.Offset = -p.From.Offset 104 p.As = AADD 105 } 106 } 107 108 if c.ctxt.Flag_dynlink { 109 c.rewriteToUseGot(p) 110 } 111 } 112 113 // Rewrite p, if necessary, to access global data via the global offset table. 114 func (c *ctxtz) rewriteToUseGot(p *obj.Prog) { 115 // At the moment EXRL instructions are not emitted by the compiler and only reference local symbols in 116 // assembly code. 117 if p.As == AEXRL { 118 return 119 } 120 121 // We only care about global data: NAME_EXTERN means a global 122 // symbol in the Go sense, and p.Sym.Local is true for a few 123 // internally defined symbols. 124 if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 125 // MOVD $sym, Rx becomes MOVD sym@GOT, Rx 126 // MOVD $sym+<off>, Rx becomes MOVD sym@GOT, Rx; ADD <off>, Rx 127 if p.To.Type != obj.TYPE_REG || p.As != AMOVD { 128 c.ctxt.Diag("do not know how to handle LEA-type insn to non-register in %v with -dynlink", p) 129 } 130 p.From.Type = obj.TYPE_MEM 131 p.From.Name = obj.NAME_GOTREF 132 q := p 133 if p.From.Offset != 0 { 134 q = obj.Appendp(p, c.newprog) 135 q.As = AADD 136 q.From.Type = obj.TYPE_CONST 137 q.From.Offset = p.From.Offset 138 q.To = p.To 139 p.From.Offset = 0 140 } 141 } 142 if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN { 143 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 144 } 145 var source *obj.Addr 146 // MOVD sym, Ry becomes MOVD sym@GOT, REGTMP; MOVD (REGTMP), Ry 147 // MOVD Ry, sym becomes MOVD sym@GOT, REGTMP; MOVD Ry, (REGTMP) 148 // An addition may be inserted between the two MOVs if there is an offset. 149 if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local() { 150 if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 151 c.ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p) 152 } 153 source = &p.From 154 } else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local() { 155 source = &p.To 156 } else { 157 return 158 } 159 if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP { 160 return 161 } 162 if source.Sym.Type == obj.STLSBSS { 163 return 164 } 165 if source.Type != obj.TYPE_MEM { 166 c.ctxt.Diag("don't know how to handle %v with -dynlink", p) 167 } 168 p1 := obj.Appendp(p, c.newprog) 169 p2 := obj.Appendp(p1, c.newprog) 170 171 p1.As = AMOVD 172 p1.From.Type = obj.TYPE_MEM 173 p1.From.Sym = source.Sym 174 p1.From.Name = obj.NAME_GOTREF 175 p1.To.Type = obj.TYPE_REG 176 p1.To.Reg = REGTMP 177 178 p2.As = p.As 179 p2.From = p.From 180 p2.To = p.To 181 if p.From.Name == obj.NAME_EXTERN { 182 p2.From.Reg = REGTMP 183 p2.From.Name = obj.NAME_NONE 184 p2.From.Sym = nil 185 } else if p.To.Name == obj.NAME_EXTERN { 186 p2.To.Reg = REGTMP 187 p2.To.Name = obj.NAME_NONE 188 p2.To.Sym = nil 189 } else { 190 return 191 } 192 obj.Nopout(p) 193 } 194 195 func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { 196 // TODO(minux): add morestack short-cuts with small fixed frame-size. 197 if cursym.Text == nil || cursym.Text.Link == nil { 198 return 199 } 200 201 c := ctxtz{ctxt: ctxt, cursym: cursym, newprog: newprog} 202 203 p := c.cursym.Text 204 textstksiz := p.To.Offset 205 if textstksiz == -8 { 206 // Compatibility hack. 207 p.From.Sym.Set(obj.AttrNoFrame, true) 208 textstksiz = 0 209 } 210 if textstksiz%8 != 0 { 211 c.ctxt.Diag("frame size %d not a multiple of 8", textstksiz) 212 } 213 if p.From.Sym.NoFrame() { 214 if textstksiz != 0 { 215 c.ctxt.Diag("NOFRAME functions must have a frame size of 0, not %d", textstksiz) 216 } 217 } 218 219 c.cursym.Args = p.To.Val.(int32) 220 c.cursym.Locals = int32(textstksiz) 221 222 /* 223 * find leaf subroutines 224 * strip NOPs 225 * expand RET 226 */ 227 228 var q *obj.Prog 229 for p := c.cursym.Text; p != nil; p = p.Link { 230 switch p.As { 231 case obj.ATEXT: 232 q = p 233 p.Mark |= LEAF 234 235 case ABL, ABCL: 236 q = p 237 c.cursym.Text.Mark &^= LEAF 238 fallthrough 239 240 case ABC, 241 ABEQ, 242 ABGE, 243 ABGT, 244 ABLE, 245 ABLT, 246 ABLEU, 247 ABLTU, 248 ABNE, 249 ABR, 250 ABVC, 251 ABVS, 252 ACMPBEQ, 253 ACMPBGE, 254 ACMPBGT, 255 ACMPBLE, 256 ACMPBLT, 257 ACMPBNE, 258 ACMPUBEQ, 259 ACMPUBGE, 260 ACMPUBGT, 261 ACMPUBLE, 262 ACMPUBLT, 263 ACMPUBNE: 264 q = p 265 p.Mark |= BRANCH 266 if p.Pcond != nil { 267 q := p.Pcond 268 for q.As == obj.ANOP { 269 q = q.Link 270 p.Pcond = q 271 } 272 } 273 274 case obj.ANOP: 275 q.Link = p.Link /* q is non-nop */ 276 p.Link.Mark |= p.Mark 277 278 default: 279 q = p 280 } 281 } 282 283 autosize := int32(0) 284 var pLast *obj.Prog 285 var pPre *obj.Prog 286 var pPreempt *obj.Prog 287 wasSplit := false 288 for p := c.cursym.Text; p != nil; p = p.Link { 289 pLast = p 290 switch p.As { 291 case obj.ATEXT: 292 autosize = int32(textstksiz) 293 294 if p.Mark&LEAF != 0 && autosize == 0 { 295 // A leaf function with no locals has no frame. 296 p.From.Sym.Set(obj.AttrNoFrame, true) 297 } 298 299 if !p.From.Sym.NoFrame() { 300 // If there is a stack frame at all, it includes 301 // space to save the LR. 302 autosize += int32(c.ctxt.FixedFrameSize()) 303 } 304 305 if p.Mark&LEAF != 0 && autosize < obj.StackSmall { 306 // A leaf function with a small stack can be marked 307 // NOSPLIT, avoiding a stack check. 308 p.From.Sym.Set(obj.AttrNoSplit, true) 309 } 310 311 p.To.Offset = int64(autosize) 312 313 q := p 314 315 if !p.From.Sym.NoSplit() { 316 p, pPreempt = c.stacksplitPre(p, autosize) // emit pre part of split check 317 pPre = p 318 wasSplit = true //need post part of split 319 } 320 321 if autosize != 0 { 322 // Make sure to save link register for non-empty frame, even if 323 // it is a leaf function, so that traceback works. 324 // Store link register before decrementing SP, so if a signal comes 325 // during the execution of the function prologue, the traceback 326 // code will not see a half-updated stack frame. 327 q = obj.Appendp(p, c.newprog) 328 q.As = AMOVD 329 q.From.Type = obj.TYPE_REG 330 q.From.Reg = REG_LR 331 q.To.Type = obj.TYPE_MEM 332 q.To.Reg = REGSP 333 q.To.Offset = int64(-autosize) 334 335 q = obj.Appendp(q, c.newprog) 336 q.As = AMOVD 337 q.From.Type = obj.TYPE_ADDR 338 q.From.Offset = int64(-autosize) 339 q.From.Reg = REGSP // not actually needed - REGSP is assumed if no reg is provided 340 q.To.Type = obj.TYPE_REG 341 q.To.Reg = REGSP 342 q.Spadj = autosize 343 } else if c.cursym.Text.Mark&LEAF == 0 { 344 // A very few functions that do not return to their caller 345 // (e.g. gogo) are not identified as leaves but still have 346 // no frame. 347 c.cursym.Text.Mark |= LEAF 348 } 349 350 if c.cursym.Text.Mark&LEAF != 0 { 351 c.cursym.Set(obj.AttrLeaf, true) 352 break 353 } 354 355 if c.cursym.Text.From.Sym.Wrapper() { 356 // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame 357 // 358 // MOVD g_panic(g), R3 359 // CMP R3, $0 360 // BEQ end 361 // MOVD panic_argp(R3), R4 362 // ADD $(autosize+8), R1, R5 363 // CMP R4, R5 364 // BNE end 365 // ADD $8, R1, R6 366 // MOVD R6, panic_argp(R3) 367 // end: 368 // NOP 369 // 370 // The NOP is needed to give the jumps somewhere to land. 371 // It is a liblink NOP, not a s390x NOP: it encodes to 0 instruction bytes. 372 373 q = obj.Appendp(q, c.newprog) 374 375 q.As = AMOVD 376 q.From.Type = obj.TYPE_MEM 377 q.From.Reg = REGG 378 q.From.Offset = 4 * int64(c.ctxt.Arch.PtrSize) // G.panic 379 q.To.Type = obj.TYPE_REG 380 q.To.Reg = REG_R3 381 382 q = obj.Appendp(q, c.newprog) 383 q.As = ACMP 384 q.From.Type = obj.TYPE_REG 385 q.From.Reg = REG_R3 386 q.To.Type = obj.TYPE_CONST 387 q.To.Offset = 0 388 389 q = obj.Appendp(q, c.newprog) 390 q.As = ABEQ 391 q.To.Type = obj.TYPE_BRANCH 392 p1 := q 393 394 q = obj.Appendp(q, c.newprog) 395 q.As = AMOVD 396 q.From.Type = obj.TYPE_MEM 397 q.From.Reg = REG_R3 398 q.From.Offset = 0 // Panic.argp 399 q.To.Type = obj.TYPE_REG 400 q.To.Reg = REG_R4 401 402 q = obj.Appendp(q, c.newprog) 403 q.As = AADD 404 q.From.Type = obj.TYPE_CONST 405 q.From.Offset = int64(autosize) + c.ctxt.FixedFrameSize() 406 q.Reg = REGSP 407 q.To.Type = obj.TYPE_REG 408 q.To.Reg = REG_R5 409 410 q = obj.Appendp(q, c.newprog) 411 q.As = ACMP 412 q.From.Type = obj.TYPE_REG 413 q.From.Reg = REG_R4 414 q.To.Type = obj.TYPE_REG 415 q.To.Reg = REG_R5 416 417 q = obj.Appendp(q, c.newprog) 418 q.As = ABNE 419 q.To.Type = obj.TYPE_BRANCH 420 p2 := q 421 422 q = obj.Appendp(q, c.newprog) 423 q.As = AADD 424 q.From.Type = obj.TYPE_CONST 425 q.From.Offset = c.ctxt.FixedFrameSize() 426 q.Reg = REGSP 427 q.To.Type = obj.TYPE_REG 428 q.To.Reg = REG_R6 429 430 q = obj.Appendp(q, c.newprog) 431 q.As = AMOVD 432 q.From.Type = obj.TYPE_REG 433 q.From.Reg = REG_R6 434 q.To.Type = obj.TYPE_MEM 435 q.To.Reg = REG_R3 436 q.To.Offset = 0 // Panic.argp 437 438 q = obj.Appendp(q, c.newprog) 439 440 q.As = obj.ANOP 441 p1.Pcond = q 442 p2.Pcond = q 443 } 444 445 case obj.ARET: 446 retTarget := p.To.Sym 447 448 if c.cursym.Text.Mark&LEAF != 0 { 449 if autosize == 0 { 450 p.As = ABR 451 p.From = obj.Addr{} 452 if retTarget == nil { 453 p.To.Type = obj.TYPE_REG 454 p.To.Reg = REG_LR 455 } else { 456 p.To.Type = obj.TYPE_BRANCH 457 p.To.Sym = retTarget 458 } 459 p.Mark |= BRANCH 460 break 461 } 462 463 p.As = AADD 464 p.From.Type = obj.TYPE_CONST 465 p.From.Offset = int64(autosize) 466 p.To.Type = obj.TYPE_REG 467 p.To.Reg = REGSP 468 p.Spadj = -autosize 469 470 q = obj.Appendp(p, c.newprog) 471 q.As = ABR 472 q.From = obj.Addr{} 473 q.To.Type = obj.TYPE_REG 474 q.To.Reg = REG_LR 475 q.Mark |= BRANCH 476 q.Spadj = autosize 477 break 478 } 479 480 p.As = AMOVD 481 p.From.Type = obj.TYPE_MEM 482 p.From.Reg = REGSP 483 p.From.Offset = 0 484 p.To.Type = obj.TYPE_REG 485 p.To.Reg = REG_LR 486 487 q = p 488 489 if autosize != 0 { 490 q = obj.Appendp(q, c.newprog) 491 q.As = AADD 492 q.From.Type = obj.TYPE_CONST 493 q.From.Offset = int64(autosize) 494 q.To.Type = obj.TYPE_REG 495 q.To.Reg = REGSP 496 q.Spadj = -autosize 497 } 498 499 q = obj.Appendp(q, c.newprog) 500 q.As = ABR 501 q.From = obj.Addr{} 502 if retTarget == nil { 503 q.To.Type = obj.TYPE_REG 504 q.To.Reg = REG_LR 505 } else { 506 q.To.Type = obj.TYPE_BRANCH 507 q.To.Sym = retTarget 508 } 509 q.Mark |= BRANCH 510 q.Spadj = autosize 511 512 case AADD: 513 if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST { 514 p.Spadj = int32(-p.From.Offset) 515 } 516 } 517 } 518 if wasSplit { 519 c.stacksplitPost(pLast, pPre, pPreempt, autosize) // emit post part of split check 520 } 521 } 522 523 func (c *ctxtz) stacksplitPre(p *obj.Prog, framesize int32) (*obj.Prog, *obj.Prog) { 524 var q *obj.Prog 525 526 // MOVD g_stackguard(g), R3 527 p = obj.Appendp(p, c.newprog) 528 529 p.As = AMOVD 530 p.From.Type = obj.TYPE_MEM 531 p.From.Reg = REGG 532 p.From.Offset = 2 * int64(c.ctxt.Arch.PtrSize) // G.stackguard0 533 if c.cursym.CFunc() { 534 p.From.Offset = 3 * int64(c.ctxt.Arch.PtrSize) // G.stackguard1 535 } 536 p.To.Type = obj.TYPE_REG 537 p.To.Reg = REG_R3 538 539 q = nil 540 if framesize <= obj.StackSmall { 541 // small stack: SP < stackguard 542 // CMP stackguard, SP 543 544 //p.To.Type = obj.TYPE_REG 545 //p.To.Reg = REGSP 546 547 // q1: BLT done 548 549 p = obj.Appendp(p, c.newprog) 550 //q1 = p 551 p.From.Type = obj.TYPE_REG 552 p.From.Reg = REG_R3 553 p.Reg = REGSP 554 p.As = ACMPUBGE 555 p.To.Type = obj.TYPE_BRANCH 556 //p = obj.Appendp(ctxt, p) 557 558 //p.As = ACMPU 559 //p.From.Type = obj.TYPE_REG 560 //p.From.Reg = REG_R3 561 //p.To.Type = obj.TYPE_REG 562 //p.To.Reg = REGSP 563 564 //p = obj.Appendp(ctxt, p) 565 //p.As = ABGE 566 //p.To.Type = obj.TYPE_BRANCH 567 568 } else if framesize <= obj.StackBig { 569 // large stack: SP-framesize < stackguard-StackSmall 570 // ADD $-(framesize-StackSmall), SP, R4 571 // CMP stackguard, R4 572 p = obj.Appendp(p, c.newprog) 573 574 p.As = AADD 575 p.From.Type = obj.TYPE_CONST 576 p.From.Offset = -(int64(framesize) - obj.StackSmall) 577 p.Reg = REGSP 578 p.To.Type = obj.TYPE_REG 579 p.To.Reg = REG_R4 580 581 p = obj.Appendp(p, c.newprog) 582 p.From.Type = obj.TYPE_REG 583 p.From.Reg = REG_R3 584 p.Reg = REG_R4 585 p.As = ACMPUBGE 586 p.To.Type = obj.TYPE_BRANCH 587 588 } else { 589 // Such a large stack we need to protect against wraparound. 590 // If SP is close to zero: 591 // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) 592 // The +StackGuard on both sides is required to keep the left side positive: 593 // SP is allowed to be slightly below stackguard. See stack.h. 594 // 595 // Preemption sets stackguard to StackPreempt, a very large value. 596 // That breaks the math above, so we have to check for that explicitly. 597 // // stackguard is R3 598 // CMP R3, $StackPreempt 599 // BEQ label-of-call-to-morestack 600 // ADD $StackGuard, SP, R4 601 // SUB R3, R4 602 // MOVD $(framesize+(StackGuard-StackSmall)), TEMP 603 // CMPUBGE TEMP, R4 604 p = obj.Appendp(p, c.newprog) 605 606 p.As = ACMP 607 p.From.Type = obj.TYPE_REG 608 p.From.Reg = REG_R3 609 p.To.Type = obj.TYPE_CONST 610 p.To.Offset = obj.StackPreempt 611 612 p = obj.Appendp(p, c.newprog) 613 q = p 614 p.As = ABEQ 615 p.To.Type = obj.TYPE_BRANCH 616 617 p = obj.Appendp(p, c.newprog) 618 p.As = AADD 619 p.From.Type = obj.TYPE_CONST 620 p.From.Offset = obj.StackGuard 621 p.Reg = REGSP 622 p.To.Type = obj.TYPE_REG 623 p.To.Reg = REG_R4 624 625 p = obj.Appendp(p, c.newprog) 626 p.As = ASUB 627 p.From.Type = obj.TYPE_REG 628 p.From.Reg = REG_R3 629 p.To.Type = obj.TYPE_REG 630 p.To.Reg = REG_R4 631 632 p = obj.Appendp(p, c.newprog) 633 p.As = AMOVD 634 p.From.Type = obj.TYPE_CONST 635 p.From.Offset = int64(framesize) + obj.StackGuard - obj.StackSmall 636 p.To.Type = obj.TYPE_REG 637 p.To.Reg = REGTMP 638 639 p = obj.Appendp(p, c.newprog) 640 p.From.Type = obj.TYPE_REG 641 p.From.Reg = REGTMP 642 p.Reg = REG_R4 643 p.As = ACMPUBGE 644 p.To.Type = obj.TYPE_BRANCH 645 } 646 647 return p, q 648 } 649 650 func (c *ctxtz) stacksplitPost(p *obj.Prog, pPre *obj.Prog, pPreempt *obj.Prog, framesize int32) *obj.Prog { 651 // Now we are at the end of the function, but logically 652 // we are still in function prologue. We need to fix the 653 // SP data and PCDATA. 654 spfix := obj.Appendp(p, c.newprog) 655 spfix.As = obj.ANOP 656 spfix.Spadj = -framesize 657 658 pcdata := obj.Appendp(spfix, c.newprog) 659 pcdata.Pos = c.cursym.Text.Pos 660 pcdata.As = obj.APCDATA 661 pcdata.From.Type = obj.TYPE_CONST 662 pcdata.From.Offset = obj.PCDATA_StackMapIndex 663 pcdata.To.Type = obj.TYPE_CONST 664 pcdata.To.Offset = -1 // pcdata starts at -1 at function entry 665 666 // MOVD LR, R5 667 p = obj.Appendp(pcdata, c.newprog) 668 pPre.Pcond = p 669 p.As = AMOVD 670 p.From.Type = obj.TYPE_REG 671 p.From.Reg = REG_LR 672 p.To.Type = obj.TYPE_REG 673 p.To.Reg = REG_R5 674 if pPreempt != nil { 675 pPreempt.Pcond = p 676 } 677 678 // BL runtime.morestack(SB) 679 p = obj.Appendp(p, c.newprog) 680 681 p.As = ABL 682 p.To.Type = obj.TYPE_BRANCH 683 if c.cursym.CFunc() { 684 p.To.Sym = c.ctxt.Lookup("runtime.morestackc", 0) 685 } else if !c.cursym.Text.From.Sym.NeedCtxt() { 686 p.To.Sym = c.ctxt.Lookup("runtime.morestack_noctxt", 0) 687 } else { 688 p.To.Sym = c.ctxt.Lookup("runtime.morestack", 0) 689 } 690 691 // BR start 692 p = obj.Appendp(p, c.newprog) 693 694 p.As = ABR 695 p.To.Type = obj.TYPE_BRANCH 696 p.Pcond = c.cursym.Text.Link 697 return p 698 } 699 700 var unaryDst = map[obj.As]bool{ 701 ASTCK: true, 702 ASTCKC: true, 703 ASTCKE: true, 704 ASTCKF: true, 705 ANEG: true, 706 ANEGW: true, 707 AVONE: true, 708 AVZERO: true, 709 } 710 711 var Links390x = obj.LinkArch{ 712 Arch: sys.ArchS390X, 713 Init: buildop, 714 Preprocess: preprocess, 715 Assemble: spanz, 716 Progedit: progedit, 717 UnaryDst: unaryDst, 718 }