summaryrefslogtreecommitdiff
path: root/src/cmd/6l
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-07-12 12:12:56 -0400
committerRuss Cox <rsc@golang.org>2013-07-12 12:12:56 -0400
commitbf003a838168ac2d3799f4f71c2abf628b37dbfd (patch)
tree8a4ec8fd04bda1b4a12e0539470f944919fe3229 /src/cmd/6l
parentcc67b3f1acc794557bb069b5684a428f8146f0e5 (diff)
downloadgo-bf003a838168ac2d3799f4f71c2abf628b37dbfd.tar.gz
cmd/ld: fix large stack split for preempt check
If the stack frame size is larger than the known-unmapped region at the bottom of the address space, then the stack split prologue cannot use the usual condition: SP - size >= stackguard because SP - size may wrap around to a very large number. Instead, if the stack frame is large, the prologue tests: SP - stackguard >= size (This ends up being a few instructions more expensive, so we don't do it always.) Preemption requests register by setting stackguard to a very large value, so that the first test (SP - size >= stackguard) cannot possibly succeed. Unfortunately, that same very large value causes a wraparound in the second test (SP - stackguard >= size), making it succeed incorrectly. To avoid *that* wraparound, we have to amend the test: stackguard != StackPreempt && SP - stackguard >= size This test is only used for functions with large frames, which essentially always split the stack, so the cost of the few instructions is noise. This CL and CL 11085043 together fix the known issues with preemption, at the beginning of a function, so we will be able to try turning it on again. R=ken2 CC=golang-dev https://codereview.appspot.com/11205043
Diffstat (limited to 'src/cmd/6l')
-rw-r--r--src/cmd/6l/pass.c38
1 files changed, 32 insertions, 6 deletions
diff --git a/src/cmd/6l/pass.c b/src/cmd/6l/pass.c
index 31d42eee4..77defed39 100644
--- a/src/cmd/6l/pass.c
+++ b/src/cmd/6l/pass.c
@@ -438,6 +438,7 @@ dostkoff(void)
}
q = P;
+ q1 = P;
if((p->from.scale & NOSPLIT) && autoffset >= StackSmall)
diag("nosplit func likely to overflow stack");
@@ -497,6 +498,7 @@ dostkoff(void)
q1->pcond = p;
}
+ q1 = P;
if(autoffset <= StackSmall) {
// small stack: SP <= stackguard
// CMPQ SP, stackguard
@@ -519,14 +521,38 @@ dostkoff(void)
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:
+ // 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 stackguard, 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;
@@ -535,8 +561,7 @@ dostkoff(void)
p = appendp(p);
p->as = ASUBQ;
- p->from.type = D_INDIR+D_CX;
- p->from.offset = 0;
+ p->from.type = D_SI;
p->to.type = D_AX;
p = appendp(p);
@@ -550,7 +575,6 @@ dostkoff(void)
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.
@@ -627,6 +651,8 @@ dostkoff(void)
if(q != P)
q->pcond = p->link;
+ if(q1 != P)
+ q1->pcond = q->link;
if(autoffset) {
p = appendp(p);