From 3c63238a55767eb0329761b3538362b67f66291e Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sat, 6 Sep 2014 13:19:08 -0400 Subject: 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 --- src/liblink/obj5.c | 123 +++++++++++++++++++++++++++++++---------------------- src/liblink/obj6.c | 78 ++++++++++++++++++++++++--------- src/liblink/obj8.c | 78 ++++++++++++++++++++++++--------- 3 files changed, 189 insertions(+), 90 deletions(-) (limited to 'src/liblink') 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; -- cgit v1.2.1