From 9b1b0a46dd3c9704a49a5ba1950212c6fff7917d Mon Sep 17 00:00:00 2001 From: Austin Clements Date: Thu, 18 Dec 2014 11:40:48 -0500 Subject: [PATCH] liblink: fail for too-large register offset constants Previously, liblink would silently truncate register offset constants to 32 bits. For example, MOVD $0x200000004(R2),R3 would assemble to addis r31,r2,0 addi r3,r31,4 To fix this, limit C_LACON to 32 bit (signed) offsets and introduce a new C_DACON operand type for larger register offsets. We don't implement this currently, but at least liblink will now give an error if it encounters an address like this. Change-Id: I8e87def8cc4cc5b75498b0fb543ac7666cf2964e Reviewed-on: https://go-review.googlesource.com/1758 Reviewed-by: Minux Ma --- src/cmd/9l/9.out.h | 7 ++++--- src/liblink/asm9.c | 20 +++++++------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/cmd/9l/9.out.h b/src/cmd/9l/9.out.h index 016163b6fa5..e7601f02794 100644 --- a/src/cmd/9l/9.out.h +++ b/src/cmd/9l/9.out.h @@ -101,15 +101,16 @@ enum C_SPR, /* special processor register */ C_ZCON, C_SCON, /* 16 bit signed */ - C_UCON, /* low 16 bits 0 */ + C_UCON, /* 32 bit signed, low 16 bits 0 */ C_ADDCON, /* -0x8000 <= v < 0 */ C_ANDCON, /* 0 < v <= 0xFFFF */ C_LCON, /* other 32 */ C_DCON, /* other 64 (could subdivide further) */ - C_SACON, /* $n(REG) where n is small */ + C_SACON, /* $n(REG) where n <= int16 */ C_SECON, - C_LACON, /* $n(REG) where n is large */ + C_LACON, /* $n(REG) where int16 < n <= int32 */ C_LECON, + C_DACON, /* $n(REG) where int32 < n */ C_SBRA, C_LBRA, C_SAUTO, diff --git a/src/liblink/asm9.c b/src/liblink/asm9.c index 5a379270d19..64fc6512074 100644 --- a/src/liblink/asm9.c +++ b/src/liblink/asm9.c @@ -683,7 +683,9 @@ aclass(Link *ctxt, Addr *a) if(a->reg != NREG) { if(-BIG <= ctxt->instoffset && ctxt->instoffset <= BIG) return C_SACON; - return C_LACON; + if(isint32(ctxt->instoffset)) + return C_LACON; + return C_DACON; } consize: if(ctxt->instoffset >= 0) { @@ -1800,12 +1802,10 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out) if(p->to.reg == REGTMP) ctxt->diag("can't synthesize large constant\n%P", p); v = regoff(ctxt, &p->from); - if(v & 0x8000L) - v += 0x10000L; r = p->from.reg; if(r == NREG) r = o->param; - o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v)); o2 = AOP_IRR(OP_ADDI, p->to.reg, REGTMP, v); break; @@ -1913,34 +1913,28 @@ asmout(Link *ctxt, Prog *p, Optab *o, int32 *out) case 35: /* mov r,lext/lauto/loreg ==> cau $(v>>16),sb,r'; store o(r') */ v = regoff(ctxt, &p->to); - if(v & 0x8000L) - v += 0x10000L; r = p->to.reg; if(r == NREG) r = o->param; - o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v)); o2 = AOP_IRR(opstore(ctxt, p->as), p->from.reg, REGTMP, v); break; case 36: /* mov bz/h/hz lext/lauto/lreg,r ==> lbz/lha/lhz etc */ v = regoff(ctxt, &p->from); - if(v & 0x8000L) - v += 0x10000L; r = p->from.reg; if(r == NREG) r = o->param; - o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v)); o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v); break; case 37: /* movb lext/lauto/lreg,r ==> lbz o(reg),r; extsb r */ v = regoff(ctxt, &p->from); - if(v & 0x8000L) - v += 0x10000L; r = p->from.reg; if(r == NREG) r = o->param; - o1 = AOP_IRR(OP_ADDIS, REGTMP, r, v>>16); + o1 = AOP_IRR(OP_ADDIS, REGTMP, r, high16adjusted(v)); o2 = AOP_IRR(opload(ctxt, p->as), p->to.reg, REGTMP, v); o3 = LOP_RRR(OP_EXTSB, p->to.reg, p->to.reg, 0); break;