func addstacksplit(ctxt *liblink.Link, cursym *liblink.LSym) { var p *liblink.Prog var q *liblink.Prog var p1 *liblink.Prog var p2 *liblink.Prog var autoffset int32 var deltasp int32 var a int if ctxt.Symmorestack[0] == nil { ctxt.Symmorestack[0] = liblink.Linklookup(ctxt, "runtime.morestack", 0) ctxt.Symmorestack[1] = liblink.Linklookup(ctxt, "runtime.morestack_noctxt", 0) } if ctxt.Headtype == liblink.Hplan9 && ctxt.Plan9privates == nil { ctxt.Plan9privates = liblink.Linklookup(ctxt, "_privates", 0) } ctxt.Cursym = cursym if cursym.Text == nil || cursym.Text.Link == nil { return } p = cursym.Text autoffset = int32(p.To.Offset) if autoffset < 0 { autoffset = 0 } cursym.Locals = autoffset cursym.Args = p.To.Offset2 q = nil if !(p.From.Scale&liblink.NOSPLIT != 0) || (p.From.Scale&liblink.WRAPPER != 0) { p = liblink.Appendp(ctxt, p) p = load_g_cx(ctxt, p) // load g into CX } if !(cursym.Text.From.Scale&liblink.NOSPLIT != 0) { p = stacksplit(ctxt, p, autoffset, bool2int(!(cursym.Text.From.Scale&liblink.NEEDCTXT != 0)), &q) // emit split check } if autoffset != 0 { p = liblink.Appendp(ctxt, p) p.As = AADJSP p.From.Type_ = D_CONST p.From.Offset = int64(autoffset) p.Spadj = autoffset } else { // zero-byte stack adjustment. // Insert a fake non-zero adjustment so that stkcheck can // recognize the end of the stack-splitting prolog. p = liblink.Appendp(ctxt, p) p.As = ANOP p.Spadj = int32(-ctxt.Arch.Ptrsize) p = liblink.Appendp(ctxt, p) p.As = ANOP p.Spadj = int32(ctxt.Arch.Ptrsize) } if q != nil { q.Pcond = p } deltasp = autoffset if cursym.Text.From.Scale&liblink.WRAPPER != 0 { // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame // // MOVL g_panic(CX), BX // TESTL BX, BX // JEQ end // LEAL (autoffset+4)(SP), DI // CMPL panic_argp(BX), DI // JNE end // MOVL SP, panic_argp(BX) // end: // NOP // // The NOP is needed to give the jumps somewhere to land. // It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes. p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Type_ = D_INDIR + D_CX p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic p.To.Type_ = D_BX p = liblink.Appendp(ctxt, p) p.As = ATESTL p.From.Type_ = D_BX p.To.Type_ = D_BX p = liblink.Appendp(ctxt, p) p.As = AJEQ p.To.Type_ = D_BRANCH p1 = p p = liblink.Appendp(ctxt, p) p.As = ALEAL p.From.Type_ = D_INDIR + D_SP p.From.Offset = int64(autoffset) + 4 p.To.Type_ = D_DI p = liblink.Appendp(ctxt, p) p.As = ACMPL p.From.Type_ = D_INDIR + D_BX p.From.Offset = 0 // Panic.argp p.To.Type_ = D_DI p = liblink.Appendp(ctxt, p) p.As = AJNE p.To.Type_ = D_BRANCH p2 = p p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Type_ = D_SP p.To.Type_ = D_INDIR + D_BX p.To.Offset = 0 // Panic.argp p = liblink.Appendp(ctxt, p) p.As = ANOP p1.Pcond = p p2.Pcond = p } if ctxt.Debugzerostack != 0 && autoffset != 0 && !(cursym.Text.From.Scale&liblink.NOSPLIT != 0) { // 8l -Z means zero the stack frame on entry. // This slows down function calls but can help avoid // false positives in garbage collection. p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Type_ = D_SP p.To.Type_ = D_DI p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Type_ = D_CONST p.From.Offset = int64(autoffset) / 4 p.To.Type_ = D_CX p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Type_ = D_CONST p.From.Offset = 0 p.To.Type_ = D_AX p = liblink.Appendp(ctxt, p) p.As = AREP p = liblink.Appendp(ctxt, p) p.As = ASTOSL } for ; p != nil; p = p.Link { a = int(p.From.Type_) if a == D_AUTO { p.From.Offset += int64(deltasp) } if a == D_PARAM { p.From.Offset += int64(deltasp) + 4 } a = int(p.To.Type_) if a == D_AUTO { p.To.Offset += int64(deltasp) } if a == D_PARAM { p.To.Offset += int64(deltasp) + 4 } switch p.As { default: continue case APUSHL, APUSHFL: deltasp += 4 p.Spadj = 4 continue case APUSHW, APUSHFW: deltasp += 2 p.Spadj = 2 continue case APOPL, APOPFL: deltasp -= 4 p.Spadj = -4 continue case APOPW, APOPFW: deltasp -= 2 p.Spadj = -2 continue case ARET: break } if autoffset != deltasp { ctxt.Diag("unbalanced PUSH/POP") } if autoffset != 0 { p.As = AADJSP p.From.Type_ = D_CONST p.From.Offset = int64(-autoffset) p.Spadj = -autoffset p = liblink.Appendp(ctxt, p) p.As = ARET // If there are instructions following // this ARET, they come from a branch // with the same stackframe, so undo // the cleanup. p.Spadj = +autoffset } if p.To.Sym != nil { // retjmp p.As = AJMP } } }