1
0
mirror of https://github.com/golang/go synced 2024-11-23 11:20:05 -07:00

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 <minux@golang.org>
This commit is contained in:
Austin Clements 2014-12-18 11:40:48 -05:00
parent 15c67e21da
commit 9b1b0a46dd
2 changed files with 11 additions and 16 deletions

View File

@ -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,

View File

@ -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;