Example #1
0
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;
			}
		}
	}
}
Example #2
0
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;
		}
	}
}
Example #3
0
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;
			}
		}
	}
}
Example #4
0
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;
	}
}