summaryrefslogtreecommitdiff
path: root/src/liblink
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-09-06 13:19:08 -0400
committerRuss Cox <rsc@golang.org>2014-09-06 13:19:08 -0400
commit3c63238a55767eb0329761b3538362b67f66291e (patch)
tree5fc3426c74bfcc9a30d46c38d3f68afe37cc0679 /src/liblink
parent38481ac10bb2aff82282b12a26d989e70ca7b375 (diff)
downloadgo-3c63238a55767eb0329761b3538362b67f66291e.tar.gz
runtime: fix panic/wrapper/recover math
The gp->panicwrap adjustment is just fatally flawed. Now that there is a Panic.argp field, update that instead. That can be done on entry only, so that unwinding doesn't need to worry about undoing anything. The wrappers emit a few more instructions in the prologue but everything else in the system gets much simpler. It also fixes (without trying) a broken test I never checked in. Fixes issue 7491. LGTM=khr R=khr CC=dvyukov, golang-codereviews, iant, r https://codereview.appspot.com/135490044
Diffstat (limited to 'src/liblink')
-rw-r--r--src/liblink/obj5.c123
-rw-r--r--src/liblink/obj6.c78
-rw-r--r--src/liblink/obj8.c78
3 files changed, 189 insertions, 90 deletions
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c
index de920b029..d7008a48c 100644
--- a/src/liblink/obj5.c
+++ b/src/liblink/obj5.c
@@ -241,7 +241,7 @@ nocache(Prog *p)
static void
addstacksplit(Link *ctxt, LSym *cursym)
{
- Prog *p, *pl, *q, *q1, *q2;
+ Prog *p, *pl, *p1, *p2, *q, *q1, *q2;
int o;
int32 autosize, autoffset;
@@ -437,32 +437,93 @@ addstacksplit(Link *ctxt, LSym *cursym)
p->spadj = autosize;
if(cursym->text->reg & WRAPPER) {
- // g->panicwrap += autosize;
- // MOVW panicwrap_offset(g), R3
- // ADD $autosize, R3
- // MOVW R3 panicwrap_offset(g)
+ // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+ //
+ // MOVW g_panic(g), R1
+ // CMP $0, R1
+ // B.EQ end
+ // MOVW panic_argp(R1), R2
+ // ADD $(autosize+4), R13, R3
+ // CMP R2, R3
+ // B.NE end
+ // ADD $4, R13, R4
+ // MOVW R4, panic_argp(R1)
+ // end:
+ // NOP
+ //
+ // The NOP is needed to give the jumps somewhere to land.
+ // It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
+
p = appendp(ctxt, p);
p->as = AMOVW;
p->from.type = D_OREG;
p->from.reg = REGG;
- p->from.offset = 2*ctxt->arch->ptrsize;
+ p->from.offset = 2*ctxt->arch->ptrsize; // G.panic
p->to.type = D_REG;
- p->to.reg = 3;
+ p->to.reg = 1;
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_CONST;
+ p->from.offset = 0;
+ p->to.type = D_REG;
+ p->to.reg = 1;
+
+ p = appendp(ctxt, p);
+ p->as = AB;
+ p->scond = C_SCOND_EQ;
+ p->to.type = D_BRANCH;
+ p1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVW;
+ p->from.type = D_OREG;
+ p->from.reg = 1;
+ p->from.offset = 0; // Panic.argp
+ p->to.type = D_REG;
+ p->to.reg = 2;
p = appendp(ctxt, p);
p->as = AADD;
p->from.type = D_CONST;
- p->from.offset = autosize;
+ p->from.offset = autosize+4;
+ p->reg = 13;
p->to.type = D_REG;
p->to.reg = 3;
-
+
+ p = appendp(ctxt, p);
+ p->as = ACMP;
+ p->from.type = D_REG;
+ p->from.offset = 2;
+ p->to.type = D_REG;
+ p->to.reg = 3;
+
+ p = appendp(ctxt, p);
+ p->as = AB;
+ p->scond = C_SCOND_NE;
+ p->to.type = D_BRANCH;
+ p2 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AADD;
+ p->from.type = D_CONST;
+ p->from.offset = 4;
+ p->reg = 13;
+ p->to.type = D_REG;
+ p->to.reg = 4;
+
p = appendp(ctxt, p);
p->as = AMOVW;
p->from.type = D_REG;
- p->from.reg = 3;
+ p->from.reg = 4;
p->to.type = D_OREG;
- p->to.reg = REGG;
- p->to.offset = 2*ctxt->arch->ptrsize;
+ p->to.reg = 1;
+ p->to.offset = 0; // Panic.argp
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p1->pcond = p;
+ p2->pcond = p;
}
break;
@@ -483,44 +544,6 @@ addstacksplit(Link *ctxt, LSym *cursym)
}
}
- if(cursym->text->reg & WRAPPER) {
- int scond;
-
- // Preserve original RET's cond, to allow RET.EQ
- // in the implementation of reflect.call.
- scond = p->scond;
- p->scond = C_SCOND_NONE;
-
- // g->panicwrap -= autosize;
- // MOVW panicwrap_offset(g), R3
- // SUB $autosize, R3
- // MOVW R3 panicwrap_offset(g)
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.reg = REGG;
- p->from.offset = 2*ctxt->arch->ptrsize;
- p->to.type = D_REG;
- p->to.reg = 3;
- p = appendp(ctxt, p);
-
- p->as = ASUB;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = 3;
- p = appendp(ctxt, p);
-
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = 3;
- p->to.type = D_OREG;
- p->to.reg = REGG;
- p->to.offset = 2*ctxt->arch->ptrsize;
- p = appendp(ctxt, p);
-
- p->scond = scond;
- }
-
p->as = AMOVW;
p->scond |= C_PBIT;
p->from.type = D_OREG;
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
index eef3b4294..c6b8e0964 100644
--- a/src/liblink/obj6.c
+++ b/src/liblink/obj6.c
@@ -388,7 +388,7 @@ parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
static void
addstacksplit(Link *ctxt, LSym *cursym)
{
- Prog *p, *q, *q1;
+ Prog *p, *q, *q1, *p1, *p2;
int32 autoffset, deltasp;
int a, pcsize;
uint32 i;
@@ -463,13 +463,64 @@ addstacksplit(Link *ctxt, LSym *cursym)
deltasp = autoffset;
if(cursym->text->from.scale & WRAPPER) {
- // g->panicwrap += autoffset + ctxt->arch->regsize;
+ // if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+ //
+ // MOVQ g_panic(CX), BX
+ // TESTQ BX, BX
+ // JEQ end
+ // LEAQ (autoffset+8)(SP), DI
+ // CMPQ panic_argp(BX), DI
+ // JNE end
+ // MOVQ 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 = appendp(ctxt, p);
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + ctxt->arch->regsize;
- indir_cx(ctxt, &p->to);
- p->to.offset = 2*ctxt->arch->ptrsize;
+ p->as = AMOVQ;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 2*ctxt->arch->ptrsize; // G.panic
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = ATESTQ;
+ p->from.type = D_BX;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = AJEQ;
+ p->to.type = D_BRANCH;
+ p1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = ALEAQ;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = autoffset+8;
+ p->to.type = D_DI;
+
+ p = appendp(ctxt, p);
+ p->as = ACMPQ;
+ p->from.type = D_INDIR+D_BX;
+ p->from.offset = 0; // Panic.argp
+ p->to.type = D_DI;
+
+ p = appendp(ctxt, p);
+ p->as = AJNE;
+ p->to.type = D_BRANCH;
+ p2 = p;
+
+ p = appendp(ctxt, p);
+ p->as = AMOVQ;
+ p->from.type = D_SP;
+ p->to.type = D_INDIR+D_BX;
+ p->to.offset = 0; // Panic.argp
+
+ p = appendp(ctxt, p);
+ p->as = ANOP;
+ p1->pcond = p;
+ p2->pcond = p;
}
if(ctxt->debugstack > 1 && autoffset) {
@@ -589,19 +640,6 @@ addstacksplit(Link *ctxt, LSym *cursym)
if(autoffset != deltasp)
ctxt->diag("unbalanced PUSH/POP");
- if(cursym->text->from.scale & WRAPPER) {
- p = load_g_cx(ctxt, p);
- p = appendp(ctxt, p);
- // g->panicwrap -= autoffset + ctxt->arch->regsize;
- p->as = ASUBL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + ctxt->arch->regsize;
- indir_cx(ctxt, &p->to);
- p->to.offset = 2*ctxt->arch->ptrsize;
- p = appendp(ctxt, p);
- p->as = ARET;
- }
-
if(autoffset) {
p->as = AADJSP;
p->from.type = D_CONST;
diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c
index 50e6d8236..fa1e1ca24 100644
--- a/src/liblink/obj8.c
+++ b/src/liblink/obj8.c
@@ -261,7 +261,7 @@ static Prog* stacksplit(Link*, Prog*, int32, int, Prog**);
static void
addstacksplit(Link *ctxt, LSym *cursym)
{
- Prog *p, *q;
+ Prog *p, *q, *p1, *p2;
int32 autoffset, deltasp;
int a;
@@ -317,13 +317,64 @@ addstacksplit(Link *ctxt, LSym *cursym)
deltasp = autoffset;
if(cursym->text->from.scale & WRAPPER) {
- // g->panicwrap += autoffset + ctxt->arch->ptrsize;
+ // 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 = appendp(ctxt, p);
- p->as = AADDL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + ctxt->arch->ptrsize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*ctxt->arch->ptrsize;
+ p->as = AMOVL;
+ p->from.type = D_INDIR+D_CX;
+ p->from.offset = 2*ctxt->arch->ptrsize; // G.panic
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = ATESTL;
+ p->from.type = D_BX;
+ p->to.type = D_BX;
+
+ p = appendp(ctxt, p);
+ p->as = AJEQ;
+ p->to.type = D_BRANCH;
+ p1 = p;
+
+ p = appendp(ctxt, p);
+ p->as = ALEAL;
+ p->from.type = D_INDIR+D_SP;
+ p->from.offset = autoffset+4;
+ p->to.type = D_DI;
+
+ p = 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 = appendp(ctxt, p);
+ p->as = AJNE;
+ p->to.type = D_BRANCH;
+ p2 = p;
+
+ p = 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 = appendp(ctxt, p);
+ p->as = ANOP;
+ p1->pcond = p;
+ p2->pcond = p;
}
if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
@@ -396,19 +447,6 @@ addstacksplit(Link *ctxt, LSym *cursym)
if(autoffset != deltasp)
ctxt->diag("unbalanced PUSH/POP");
- if(cursym->text->from.scale & WRAPPER) {
- p = load_g_cx(ctxt, p);
- p = appendp(ctxt, p);
- // g->panicwrap -= autoffset + ctxt->arch->ptrsize;
- p->as = ASUBL;
- p->from.type = D_CONST;
- p->from.offset = autoffset + ctxt->arch->ptrsize;
- p->to.type = D_INDIR+D_CX;
- p->to.offset = 2*ctxt->arch->ptrsize;
- p = appendp(ctxt, p);
- p->as = ARET;
- }
-
if(autoffset) {
p->as = AADJSP;
p->from.type = D_CONST;