func addstacksplit(ctxt *liblink.Link, cursym *liblink.LSym) { var p *liblink.Prog var q *liblink.Prog var autoffset int64 var deltasp int64 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 = 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.Typ = D_CONST p.From.Offset = 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 = -ctxt.Arch.Ptrsize p = liblink.Appendp(ctxt, p) p.As = ANOP p.Spadj = ctxt.Arch.Ptrsize } if q != nil { q.Pcond = p } deltasp = autoffset if cursym.Text.From.Scale&liblink.WRAPPER != 0 { // g->panicwrap += autoffset + ctxt->arch->ptrsize; p = liblink.Appendp(ctxt, p) p.As = AADDL p.From.Typ = D_CONST p.From.Offset = autoffset + ctxt.Arch.Ptrsize p.To.Typ = D_INDIR + D_CX p.To.Offset = 2 * ctxt.Arch.Ptrsize } 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.Typ = D_SP p.To.Typ = D_DI p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Typ = D_CONST p.From.Offset = autoffset / 4 p.To.Typ = D_CX p = liblink.Appendp(ctxt, p) p.As = AMOVL p.From.Typ = D_CONST p.From.Offset = 0 p.To.Typ = 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 = p.From.Typ if a == D_AUTO { p.From.Offset += deltasp } if a == D_PARAM { p.From.Offset += deltasp + 4 } a = p.To.Typ if a == D_AUTO { p.To.Offset += deltasp } if a == D_PARAM { p.To.Offset += 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 cursym.Text.From.Scale&liblink.WRAPPER != 0 { p = load_g_cx(ctxt, p) p = liblink.Appendp(ctxt, p) // g->panicwrap -= autoffset + ctxt->arch->ptrsize; p.As = ASUBL p.From.Typ = D_CONST p.From.Offset = autoffset + ctxt.Arch.Ptrsize p.To.Typ = D_INDIR + D_CX p.To.Offset = 2 * ctxt.Arch.Ptrsize p = liblink.Appendp(ctxt, p) p.As = ARET } if autoffset != 0 { p.As = AADJSP p.From.Typ = D_CONST p.From.Offset = -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 } } }