diff options
author | Russ Cox <rsc@golang.org> | 2014-09-06 13:19:08 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2014-09-06 13:19:08 -0400 |
commit | 3c63238a55767eb0329761b3538362b67f66291e (patch) | |
tree | 5fc3426c74bfcc9a30d46c38d3f68afe37cc0679 /src/liblink/obj5.c | |
parent | 38481ac10bb2aff82282b12a26d989e70ca7b375 (diff) | |
download | go-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/obj5.c')
-rw-r--r-- | src/liblink/obj5.c | 123 |
1 files changed, 73 insertions, 50 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; |