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