void dostkoff(void) { Prog *p, *q, *q1; int32 autoffset, deltasp; int a, pcsize; uint32 moreconst1, moreconst2, i; for(i=0; i<nelem(morename); i++) { symmorestack[i] = lookup(morename[i], 0); if(symmorestack[i]->type != STEXT) diag("morestack trampoline not defined - %s", morename[i]); pmorestack[i] = symmorestack[i]->text; } for(cursym = textp; cursym != nil; cursym = cursym->next) { if(cursym->text == nil || cursym->text->link == nil) continue; p = cursym->text; parsetextconst(p->to.offset); autoffset = textstksiz; if(autoffset < 0) autoffset = 0; q = P; if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) diag("nosplit func likely to overflow stack"); if(!(p->from.scale & NOSPLIT)) { p = appendp(p); // load g into CX p->as = AMOVQ; if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd) // ELF uses FS p->from.type = D_INDIR+D_FS; else p->from.type = D_INDIR+D_GS; p->from.offset = tlsoffset+0; p->to.type = D_CX; if(HEADTYPE == Hwindows) { // movq %gs:0x28, %rcx // movq (%rcx), %rcx p->as = AMOVQ; p->from.type = D_INDIR+D_GS; p->from.offset = 0x28; p->to.type = D_CX; p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_CX; } if(debug['K']) { // 6l -K means check not only for stack // overflow but stack underflow. // On underflow, INT 3 (breakpoint). // Underflow itself is rare but this also // catches out-of-sync stack guard info p = appendp(p); p->as = ACMPQ; p->from.type = D_INDIR+D_CX; p->from.offset = 8; p->to.type = D_SP; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; } if(autoffset < StackBig) { // do we need to call morestack? if(autoffset <= StackSmall) { // small stack p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_INDIR+D_CX; } else { // large stack p = appendp(p); p->as = ALEAQ; p->from.type = D_INDIR+D_SP; p->from.offset = -(autoffset-StackSmall); p->to.type = D_AX; p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; p->to.type = D_INDIR+D_CX; } // common p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q = p; } /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ moreconst1 = 0; if(autoffset+160+textarg > 4096) moreconst1 = (autoffset+160) & ~7LL; moreconst2 = textarg; // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(p); if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[0]; p->to.sym = symmorestack[0]; } else if(moreconst1 != 0 && moreconst2 == 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst1; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[1]; p->to.sym = symmorestack[1]; } else if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { i = moreconst2/8 + 3; p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[i]; p->to.sym = symmorestack[i]; } else if(moreconst1 == 0 && moreconst2 != 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst2; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[2]; p->to.sym = symmorestack[2]; } else { p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = (uint64)moreconst2 << 32; p->from.offset |= moreconst1; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[3]; p->to.sym = symmorestack[3]; } } if(q != P) q->pcond = p->link; if(autoffset) { p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; p->from.offset = autoffset; p->spadj = autoffset; if(q != P) q->pcond = p; } deltasp = autoffset; if(debug['K'] > 1 && autoffset) { // 6l -KK means double-check for stack overflow // even after calling morestack and even if the // function is marked as nosplit. p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_BX; p = appendp(p); p->as = ASUBQ; p->from.type = D_CONST; p->from.offset = StackSmall+32; p->to.type = D_BX; p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_BX; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; } for(; p != P; p = p->link) { pcsize = p->mode/8; a = p->from.type; if(a == D_AUTO) p->from.offset += deltasp; if(a == D_PARAM) p->from.offset += deltasp + pcsize; a = p->to.type; if(a == D_AUTO) p->to.offset += deltasp; if(a == D_PARAM) p->to.offset += deltasp + pcsize; switch(p->as) { default: continue; case APUSHL: case APUSHFL: deltasp += 4; p->spadj = 4; continue; case APUSHQ: case APUSHFQ: deltasp += 8; p->spadj = 8; continue; case APUSHW: case APUSHFW: deltasp += 2; p->spadj = 2; continue; case APOPL: case APOPFL: deltasp -= 4; p->spadj = -4; continue; case APOPQ: case APOPFQ: deltasp -= 8; p->spadj = -8; continue; case APOPW: case APOPFW: deltasp -= 2; p->spadj = -2; continue; case ARET: break; } if(autoffset != deltasp) diag("unbalanced PUSH/POP"); if(autoffset) { p->as = AADJSP; p->from.type = D_CONST; p->from.offset = -autoffset; p->spadj = -autoffset; p = appendp(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; } } } }
void dostkoff(void) { Prog *p, *q, *q1; int32 autoffset, deltasp; int a, pcsize; uint32 moreconst1, moreconst2, i; Sym *gmsym; gmsym = lookup("runtime.tlsgm", 0); for(i=0; i<nelem(morename); i++) { symmorestack[i] = lookup(morename[i], 0); if(symmorestack[i]->type != STEXT) diag("morestack trampoline not defined - %s", morename[i]); pmorestack[i] = symmorestack[i]->text; } for(cursym = textp; cursym != nil; cursym = cursym->next) { if(cursym->text == nil || cursym->text->link == nil) continue; p = cursym->text; parsetextconst(p->to.offset); autoffset = textstksiz; if(autoffset < 0) autoffset = 0; if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { for(q = p; q != P; q = q->link) if(q->as == ACALL) goto noleaf; p->from.scale |= NOSPLIT; noleaf:; } q = P; q1 = P; if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) diag("nosplit func likely to overflow stack"); if(!(p->from.scale & NOSPLIT)) { if(flag_shared) { // Load TLS offset with MOVQ $runtime.tlsgm(SB), CX p = appendp(p); p->as = AMOVQ; p->from.type = D_EXTERN; p->from.sym = gmsym; p->to.type = D_CX; } p = appendp(p); // load g into CX p->as = AMOVQ; if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd || HEADTYPE == Hplan9x64 || HEADTYPE == Hdragonfly) // ELF uses FS p->from.type = D_INDIR+D_FS; else p->from.type = D_INDIR+D_GS; if(flag_shared) { // Add TLS offset stored in CX p->from.index = p->from.type - D_INDIR; p->from.type = D_INDIR + D_CX; } p->from.offset = tlsoffset+0; p->to.type = D_CX; if(HEADTYPE == Hwindows) { // movq %gs:0x28, %rcx // movq (%rcx), %rcx p->as = AMOVQ; p->from.type = D_INDIR+D_GS; p->from.offset = 0x28; p->to.type = D_CX; p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_CX; } if(debug['K']) { // 6l -K means check not only for stack // overflow but stack underflow. // On underflow, INT 3 (breakpoint). // Underflow itself is rare but this also // catches out-of-sync stack guard info p = appendp(p); p->as = ACMPQ; p->from.type = D_INDIR+D_CX; p->from.offset = 8; p->to.type = D_SP; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; } q1 = P; if(autoffset <= StackSmall) { // small stack: SP <= stackguard // CMPQ SP, stackguard p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_INDIR+D_CX; } else if(autoffset <= StackBig) { // large stack: SP-framesize <= stackguard-StackSmall // LEAQ -xxx(SP), AX // CMPQ AX, stackguard p = appendp(p); p->as = ALEAQ; p->from.type = D_INDIR+D_SP; p->from.offset = -(autoffset-StackSmall); p->to.type = D_AX; p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; p->to.type = D_INDIR+D_CX; } else { // Such a large stack we need to protect against wraparound. // If SP is close to zero: // SP-stackguard+StackGuard <= framesize + (StackGuard-StackSmall) // The +StackGuard on both sides is required to keep the left side positive: // SP is allowed to be slightly below stackguard. See stack.h. // // Preemption sets stackguard to StackPreempt, a very large value. // That breaks the math above, so we have to check for that explicitly. // MOVQ stackguard, CX // CMPQ CX, $StackPreempt // JEQ label-of-call-to-morestack // LEAQ StackGuard(SP), AX // SUBQ CX, AX // CMPQ AX, $(autoffset+(StackGuard-StackSmall)) p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_SI; p = appendp(p); p->as = ACMPQ; p->from.type = D_SI; p->to.type = D_CONST; p->to.offset = StackPreempt; p = appendp(p); p->as = AJEQ; p->to.type = D_BRANCH; q1 = p; p = appendp(p); p->as = ALEAQ; p->from.type = D_INDIR+D_SP; p->from.offset = StackGuard; p->to.type = D_AX; p = appendp(p); p->as = ASUBQ; p->from.type = D_SI; p->to.type = D_AX; p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; p->to.type = D_CONST; p->to.offset = autoffset+(StackGuard-StackSmall); } // common p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; q = p; // If we ask for more stack, we'll get a minimum of StackMin bytes. // We need a stack frame large enough to hold the top-of-stack data, // the function arguments+results, our caller's PC, our frame, // a word for the return PC of the next call, and then the StackLimit bytes // that must be available on entry to any function called from a function // that did a stack check. If StackMin is enough, don't ask for a specific // amount: then we can use the custom functions and save a few // instructions. moreconst1 = 0; if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin) moreconst1 = autoffset; moreconst2 = textarg; if(moreconst2 == 1) // special marker moreconst2 = 0; if((moreconst2&7) != 0) diag("misaligned argument size in stack split"); // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(p); if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[0]; p->to.sym = symmorestack[0]; } else if(moreconst1 != 0 && moreconst2 == 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst1; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[1]; p->to.sym = symmorestack[1]; } else if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { i = moreconst2/8 + 3; p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[i]; p->to.sym = symmorestack[i]; } else if(moreconst1 == 0 && moreconst2 != 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst2; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[2]; p->to.sym = symmorestack[2]; } else { p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = (uint64)moreconst2 << 32; p->from.offset |= moreconst1; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[3]; p->to.sym = symmorestack[3]; } p = appendp(p); p->as = AJMP; p->to.type = D_BRANCH; p->pcond = cursym->text->link; } if(q != P) q->pcond = p->link; if(q1 != P) q1->pcond = q->link; if(autoffset) { p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; p->from.offset = autoffset; p->spadj = autoffset; if(q != P) q->pcond = p; } else { // zero-byte stack adjustment. // Insert a fake non-zero adjustment so that stkcheck can // recognize the end of the stack-splitting prolog. p = appendp(p); p->as = ANOP; p->spadj = -PtrSize; p = appendp(p); p->as = ANOP; p->spadj = PtrSize; } deltasp = autoffset; if(debug['K'] > 1 && autoffset) { // 6l -KK means double-check for stack overflow // even after calling morestack and even if the // function is marked as nosplit. p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_BX; p = appendp(p); p->as = ASUBQ; p->from.type = D_CONST; p->from.offset = StackSmall+32; p->to.type = D_BX; p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_BX; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; } if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { // 6l -Z means zero the stack frame on entry. // This slows down function calls but can help avoid // false positives in garbage collection. p = appendp(p); p->as = AMOVQ; p->from.type = D_SP; p->to.type = D_DI; p = appendp(p); p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = autoffset/8; p->to.type = D_CX; p = appendp(p); p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = 0; p->to.type = D_AX; p = appendp(p); p->as = AREP; p = appendp(p); p->as = ASTOSQ; } for(; p != P; p = p->link) { pcsize = p->mode/8; a = p->from.type; if(a == D_AUTO) p->from.offset += deltasp; if(a == D_PARAM) p->from.offset += deltasp + pcsize; a = p->to.type; if(a == D_AUTO) p->to.offset += deltasp; if(a == D_PARAM) p->to.offset += deltasp + pcsize; switch(p->as) { default: continue; case APUSHL: case APUSHFL: deltasp += 4; p->spadj = 4; continue; case APUSHQ: case APUSHFQ: deltasp += 8; p->spadj = 8; continue; case APUSHW: case APUSHFW: deltasp += 2; p->spadj = 2; continue; case APOPL: case APOPFL: deltasp -= 4; p->spadj = -4; continue; case APOPQ: case APOPFQ: deltasp -= 8; p->spadj = -8; continue; case APOPW: case APOPFW: deltasp -= 2; p->spadj = -2; continue; case ARET: break; } if(autoffset != deltasp) diag("unbalanced PUSH/POP"); if(autoffset) { p->as = AADJSP; p->from.type = D_CONST; p->from.offset = -autoffset; p->spadj = -autoffset; p = appendp(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) // retjmp p->as = AJMP; } } }
void dostkoff(void) { Prog *p, *q, *q1; int32 autoffset, deltasp; int a, pcsize; uint32 moreconst1, moreconst2, i; for(i=0; i<nelem(morename); i++) { symmorestack[i] = lookup(morename[i], 0); if(symmorestack[i]->type != STEXT) diag("morestack trampoline not defined - %s", morename[i]); pmorestack[i] = symmorestack[i]->text; } for(cursym = textp; cursym != nil; cursym = cursym->next) { if(cursym->text == nil || cursym->text->link == nil) continue; p = cursym->text; parsetextconst(p->to.offset); autoffset = textstksiz; if(autoffset < 0) autoffset = 0; if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) { for(q = p; q != P; q = q->link) if(q->as == ACALL) goto noleaf; p->from.scale |= NOSPLIT; noleaf:; } q = P; if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) diag("nosplit func likely to overflow stack"); if(!(p->from.scale & NOSPLIT)) { p = appendp(p); // load g into CX p->as = AMOVQ; if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd || HEADTYPE == Hopenbsd || HEADTYPE == Hnetbsd || HEADTYPE == Hplan9x64) // ELF uses FS p->from.type = D_INDIR+D_FS; else p->from.type = D_INDIR+D_GS; p->from.offset = tlsoffset+0; p->to.type = D_CX; if(HEADTYPE == Hwindows) { // movq %gs:0x28, %rcx // movq (%rcx), %rcx p->as = AMOVQ; p->from.type = D_INDIR+D_GS; p->from.offset = 0x28; p->to.type = D_CX; p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_CX; } if(debug['K']) { // 6l -K means check not only for stack // overflow but stack underflow. // On underflow, INT 3 (breakpoint). // Underflow itself is rare but this also // catches out-of-sync stack guard info p = appendp(p); p->as = ACMPQ; p->from.type = D_INDIR+D_CX; p->from.offset = 8; p->to.type = D_SP; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; } if(autoffset < StackBig) { // do we need to call morestack? if(autoffset <= StackSmall) { // small stack p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_INDIR+D_CX; } else { // large stack p = appendp(p); p->as = ALEAQ; p->from.type = D_INDIR+D_SP; p->from.offset = -(autoffset-StackSmall); p->to.type = D_AX; p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; p->to.type = D_INDIR+D_CX; } // common p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q = p; } // If we ask for more stack, we'll get a minimum of StackMin bytes. // We need a stack frame large enough to hold the top-of-stack data, // the function arguments+results, our caller's PC, our frame, // a word for the return PC of the next call, and then the StackLimit bytes // that must be available on entry to any function called from a function // that did a stack check. If StackMin is enough, don't ask for a specific // amount: then we can use the custom functions and save a few // instructions. moreconst1 = 0; if(StackTop + textarg + PtrSize + autoffset + PtrSize + StackLimit >= StackMin) moreconst1 = autoffset; moreconst2 = textarg; // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(p); if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[0]; p->to.sym = symmorestack[0]; } else if(moreconst1 != 0 && moreconst2 == 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst1; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[1]; p->to.sym = symmorestack[1]; } else if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { i = moreconst2/8 + 3; p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[i]; p->to.sym = symmorestack[i]; } else if(moreconst1 == 0 && moreconst2 != 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst2; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[2]; p->to.sym = symmorestack[2]; } else { p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = (uint64)moreconst2 << 32; p->from.offset |= moreconst1; p->to.type = D_AX; p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[3]; p->to.sym = symmorestack[3]; } } if(q != P) q->pcond = p->link; if(autoffset) { p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; p->from.offset = autoffset; p->spadj = autoffset; if(q != P) q->pcond = p; } else { // zero-byte stack adjustment. // Insert a fake non-zero adjustment so that stkcheck can // recognize the end of the stack-splitting prolog. p = appendp(p); p->as = ANOP; p->spadj = -PtrSize; p = appendp(p); p->as = ANOP; p->spadj = PtrSize; } deltasp = autoffset; if(debug['K'] > 1 && autoffset) { // 6l -KK means double-check for stack overflow // even after calling morestack and even if the // function is marked as nosplit. p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_CX; p->from.offset = 0; p->to.type = D_BX; p = appendp(p); p->as = ASUBQ; p->from.type = D_CONST; p->from.offset = StackSmall+32; p->to.type = D_BX; p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_BX; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; } if(debug['Z'] && autoffset && !(cursym->text->from.scale&NOSPLIT)) { // 6l -Z means zero the stack frame on entry. // This slows down function calls but can help avoid // false positives in garbage collection. p = appendp(p); p->as = AMOVQ; p->from.type = D_SP; p->to.type = D_DI; p = appendp(p); p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = autoffset/8; p->to.type = D_CX; p = appendp(p); p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = 0; p->to.type = D_AX; p = appendp(p); p->as = AREP; p = appendp(p); p->as = ASTOSQ; } for(; p != P; p = p->link) { pcsize = p->mode/8; a = p->from.type; if(a == D_AUTO) p->from.offset += deltasp; if(a == D_PARAM) p->from.offset += deltasp + pcsize; a = p->to.type; if(a == D_AUTO) p->to.offset += deltasp; if(a == D_PARAM) p->to.offset += deltasp + pcsize; switch(p->as) { default: continue; case APUSHL: case APUSHFL: deltasp += 4; p->spadj = 4; continue; case APUSHQ: case APUSHFQ: deltasp += 8; p->spadj = 8; continue; case APUSHW: case APUSHFW: deltasp += 2; p->spadj = 2; continue; case APOPL: case APOPFL: deltasp -= 4; p->spadj = -4; continue; case APOPQ: case APOPFQ: deltasp -= 8; p->spadj = -8; continue; case APOPW: case APOPFW: deltasp -= 2; p->spadj = -2; continue; case ARET: break; } if(autoffset != deltasp) diag("unbalanced PUSH/POP"); if(autoffset) { p->as = AADJSP; p->from.type = D_CONST; p->from.offset = -autoffset; p->spadj = -autoffset; p = appendp(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; } } } }
void dostkoff(void) { Prog *p, *q, *q1; int32 autoffset, deltasp; int a, f, curframe, curbecome, maxbecome, pcsize; uint32 moreconst1, moreconst2, i; for(i=0; i<nelem(morename); i++) { symmorestack[i] = lookup(morename[i], 0); pmorestack[i] = P; } for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { for(i=0; i<nelem(morename); i++) { if(p->from.sym == symmorestack[i]) { pmorestack[i] = p; break; } } } } for(i=0; i<nelem(morename); i++) { if(pmorestack[i] == P) diag("morestack trampoline not defined"); } curframe = 0; curbecome = 0; maxbecome = 0; curtext = 0; for(p = firstp; p != P; p = p->link) { /* find out how much arg space is used in this TEXT */ if(p->to.type == (D_INDIR+D_SP)) if(p->to.offset > curframe) curframe = p->to.offset; switch(p->as) { case ATEXT: if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } curframe = 0; curbecome = 0; curtext = p; break; case ARET: /* special form of RET is BECOME */ if(p->from.type == D_CONST) if(p->from.offset > curbecome) curbecome = p->from.offset; break; } } if(curtext && curtext->from.sym) { curtext->from.sym->frame = curframe; curtext->from.sym->become = curbecome; if(curbecome > maxbecome) maxbecome = curbecome; } if(debug['b']) print("max become = %d\n", maxbecome); xdefine("ALEFbecome", STEXT, maxbecome); curtext = 0; for(p = firstp; p != P; p = p->link) { switch(p->as) { case ATEXT: curtext = p; break; case ACALL: if(curtext != P && curtext->from.sym != S && curtext->to.offset >= 0) { f = maxbecome - curtext->from.sym->frame; if(f <= 0) break; /* calling a become or calling a variable */ if(p->to.sym == S || p->to.sym->become) { curtext->to.offset += f; if(debug['b']) { curp = p; print("%D calling %D increase %d\n", &curtext->from, &p->to, f); } } } break; } } autoffset = 0; deltasp = 0; for(p = firstp; p != P; p = p->link) { if(p->as == ATEXT) { curtext = p; parsetextconst(p->to.offset); autoffset = textstksiz; if(autoffset < 0) autoffset = 0; q = P; q1 = P; if((p->from.scale & NOSPLIT) && autoffset >= StackSmall) diag("nosplit func likely to overflow stack"); if(!(p->from.scale & NOSPLIT)) { if(debug['K']) { // 6l -K means check not only for stack // overflow but stack underflow. // On underflow, INT 3 (breakpoint). // Underflow itself is rare but this also // catches out-of-sync stack guard info p = appendp(p); p->as = ACMPQ; p->from.type = D_INDIR+D_R15; p->from.offset = 8; p->to.type = D_SP; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; } if(autoffset < StackBig) { // do we need to call morestack? if(autoffset <= StackSmall) { // small stack p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_INDIR+D_R15; if(q1) { q1->pcond = p; q1 = P; } } else { // large stack p = appendp(p); p->as = ALEAQ; p->from.type = D_INDIR+D_SP; p->from.offset = -(autoffset-StackSmall); p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACMPQ; p->from.type = D_AX; p->to.type = D_INDIR+D_R15; } // common p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; p->to.offset = 4; q = p; } /* 160 comes from 3 calls (3*8) 4 safes (4*8) and 104 guard */ moreconst1 = 0; if(autoffset+160 > 4096) moreconst1 = (autoffset+160) & ~7LL; moreconst2 = textarg; // 4 varieties varieties (const1==0 cross const2==0) // and 6 subvarieties of (const1==0 and const2!=0) p = appendp(p); if(moreconst1 == 0 && moreconst2 == 0) { p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[0]; p->to.sym = symmorestack[0]; if(q1) { q1->pcond = p; q1 = P; } } else if(moreconst1 != 0 && moreconst2 == 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst1; p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[1]; p->to.sym = symmorestack[1]; } else if(moreconst1 == 0 && moreconst2 <= 48 && moreconst2%8 == 0) { i = moreconst2/8 + 3; p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[i]; p->to.sym = symmorestack[i]; if(q1) { q1->pcond = p; q1 = P; } } else if(moreconst1 == 0 && moreconst2 != 0) { p->as = AMOVL; p->from.type = D_CONST; p->from.offset = moreconst2; p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[2]; p->to.sym = symmorestack[2]; } else { p->as = AMOVQ; p->from.type = D_CONST; p->from.offset = (uint64)moreconst2 << 32; p->from.offset |= moreconst1; p->to.type = D_AX; if(q1) { q1->pcond = p; q1 = P; } p = appendp(p); p->as = ACALL; p->to.type = D_BRANCH; p->pcond = pmorestack[3]; p->to.sym = symmorestack[3]; } } if(q != P) q->pcond = p->link; if(autoffset) { p = appendp(p); p->as = AADJSP; p->from.type = D_CONST; p->from.offset = autoffset; if(q != P) q->pcond = p; } deltasp = autoffset; if(debug['K'] > 1 && autoffset) { // 6l -KK means double-check for stack overflow // even after calling morestack and even if the // function is marked as nosplit. p = appendp(p); p->as = AMOVQ; p->from.type = D_INDIR+D_R15; p->from.offset = 0; p->to.type = D_BX; p = appendp(p); p->as = ASUBQ; p->from.type = D_CONST; p->from.offset = StackSmall+32; p->to.type = D_BX; p = appendp(p); p->as = ACMPQ; p->from.type = D_SP; p->to.type = D_BX; p = appendp(p); p->as = AJHI; p->to.type = D_BRANCH; q1 = p; p = appendp(p); p->as = AINT; p->from.type = D_CONST; p->from.offset = 3; p = appendp(p); p->as = ANOP; q1->pcond = p; q1 = P; } } pcsize = p->mode/8; a = p->from.type; if(a == D_AUTO) p->from.offset += deltasp; if(a == D_PARAM) p->from.offset += deltasp + pcsize; a = p->to.type; if(a == D_AUTO) p->to.offset += deltasp; if(a == D_PARAM) p->to.offset += deltasp + pcsize; switch(p->as) { default: continue; case APUSHL: case APUSHFL: deltasp += 4; continue; case APUSHQ: case APUSHFQ: deltasp += 8; continue; case APUSHW: case APUSHFW: deltasp += 2; continue; case APOPL: case APOPFL: deltasp -= 4; continue; case APOPQ: case APOPFQ: deltasp -= 8; continue; case APOPW: case APOPFW: deltasp -= 2; continue; case ARET: break; } if(autoffset != deltasp) diag("unbalanced PUSH/POP"); if(p->from.type == D_CONST) goto become; if(autoffset) { p->as = AADJSP; p->from.type = D_CONST; p->from.offset = -autoffset; p = appendp(p); p->as = ARET; } continue; become: q = p; p = appendp(p); p->as = AJMP; p->to = q->to; p->pcond = q->pcond; q->as = AADJSP; q->from = zprg.from; q->from.type = D_CONST; q->from.offset = -autoffset; q->to = zprg.to; continue; } }