mirror of
https://github.com/golang/go
synced 2024-11-23 08:30: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:
parent
15c67e21da
commit
9b1b0a46dd
@ -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,
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user