]> Cypherpunks repositories - gostls13.git/commitdiff
liblink: fail for too-large register offset constants
authorAustin Clements <austin@google.com>
Thu, 18 Dec 2014 16:40:48 +0000 (11:40 -0500)
committerAustin Clements <austin@google.com>
Thu, 18 Dec 2014 22:32:18 +0000 (22:32 +0000)
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>
src/cmd/9l/9.out.h
src/liblink/asm9.c

index 016163b6fa575a570330e3a66686e2f76d94ff36..e7601f027944b4c16918e287c16db7e6d3802805 100644 (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,
index 5a379270d19634e2e584884f46b3fb107f5b1262..64fc65120749e824c16d4ebc76fcfcb4c00fd418 100644 (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;