]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/8l: fix misassembling of MOVB involving (AX)(BX*1)
authorRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 31 Jan 2013 07:52:46 +0000 (08:52 +0100)
committerRémy Oudompheng <oudomphe@phare.normalesup.org>
Thu, 31 Jan 2013 07:52:46 +0000 (08:52 +0100)
The linker accepts MOVB involving non-byte-addressable
registers, by generating XCHG instructions to AX or BX.
It does not handle the case where nor AX nor BX are available.

See also revision 1470920a2804.

Assembling
    TEXT ·Truc(SB),7,$0
    MOVB BP, (BX)(AX*1)
    RET

gives before:
   08048c60 <main.Truc>:
    8048c60:       87 dd         xchg   %ebx,%ebp
    8048c62:       88 1c 03      mov    %bl,(%ebx,%eax,1)
    8048c65:       87 dd         xchg   %ebx,%ebp
    8048c67:       c3            ret

and after:
   08048c60 <main.Truc>:
    8048c60:       87 cd         xchg   %ecx,%ebp
    8048c62:       88 0c 03      mov    %cl,(%ebx,%eax,1)
    8048c65:       87 cd         xchg   %ecx,%ebp
    8048c67:       c3            ret

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/7226066

src/cmd/8l/span.c

index 9e3447c2d28d1d0aa4d398284e4f2acd27c4e502..b828d8645dd2d17f77ef8435276ea277dcce6aa8 100644 (file)
@@ -794,19 +794,71 @@ uchar     ymovtab[] =
        0
 };
 
+// byteswapreg returns a byte-addressable register (AX, BX, CX, DX)
+// which is not referenced in a->type.
+// If a is empty, it returns BX to account for MULB-like instructions
+// that might use DX and AX.
 int
-isax(Adr *a)
+byteswapreg(Adr *a)
 {
+       int cana, canb, canc, cand;
+
+       cana = canb = canc = cand = 1;
 
        switch(a->type) {
+       case D_NONE:
+               cana = cand = 0;
+               break;
        case D_AX:
        case D_AL:
        case D_AH:
        case D_INDIR+D_AX:
-               return 1;
+               cana = 0;
+               break;
+       case D_BX:
+       case D_BL:
+       case D_BH:
+       case D_INDIR+D_BX:
+               canb = 0;
+               break;
+       case D_CX:
+       case D_CL:
+       case D_CH:
+       case D_INDIR+D_CX:
+               canc = 0;
+               break;
+       case D_DX:
+       case D_DL:
+       case D_DH:
+       case D_INDIR+D_DX:
+               cand = 0;
+               break;
+       }
+       switch(a->index) {
+       case D_AX:
+               cana = 0;
+               break;
+       case D_BX:
+               canb = 0;
+               break;
+       case D_CX:
+               canc = 0;
+               break;
+       case D_DX:
+               cand = 0;
+               break;
        }
-       if(a->index == D_AX)
-               return 1;
+       if(cana)
+               return D_AX;
+       if(canb)
+               return D_BX;
+       if(canc)
+               return D_CX;
+       if(cand)
+               return D_DX;
+
+       diag("impossible byte register");
+       errorexit();
        return 0;
 }
 
@@ -879,7 +931,7 @@ doasm(Prog *p)
        Optab *o;
        Prog *q, pp;
        uchar *t;
-       int z, op, ft, tt;
+       int z, op, ft, tt, breg;
        int32 v, pre;
        Reloc rel, *r;
        Adr *a;
@@ -1272,15 +1324,13 @@ bad:
        pp = *p;
        z = p->from.type;
        if(z >= D_BP && z <= D_DI) {
-               if(isax(&p->to) || p->to.type == D_NONE) {
-                       // We certainly don't want to exchange
-                       // with AX if the op is MUL or DIV.
+               if((breg = byteswapreg(&p->to)) != D_AX) {
                        *andptr++ = 0x87;                       /* xchg lhs,bx */
-                       asmand(&p->from, reg[D_BX]);
-                       subreg(&pp, z, D_BX);
+                       asmand(&p->from, reg[breg]);
+                       subreg(&pp, z, breg);
                        doasm(&pp);
                        *andptr++ = 0x87;                       /* xchg lhs,bx */
-                       asmand(&p->from, reg[D_BX]);
+                       asmand(&p->from, reg[breg]);
                } else {
                        *andptr++ = 0x90 + reg[z];              /* xchg lsh,ax */
                        subreg(&pp, z, D_AX);
@@ -1291,13 +1341,13 @@ bad:
        }
        z = p->to.type;
        if(z >= D_BP && z <= D_DI) {
-               if(isax(&p->from)) {
+               if((breg = byteswapreg(&p->from)) != D_AX) {
                        *andptr++ = 0x87;                       /* xchg rhs,bx */
-                       asmand(&p->to, reg[D_BX]);
-                       subreg(&pp, z, D_BX);
+                       asmand(&p->to, reg[breg]);
+                       subreg(&pp, z, breg);
                        doasm(&pp);
                        *andptr++ = 0x87;                       /* xchg rhs,bx */
-                       asmand(&p->to, reg[D_BX]);
+                       asmand(&p->to, reg[breg]);
                } else {
                        *andptr++ = 0x90 + reg[z];              /* xchg rsh,ax */
                        subreg(&pp, z, D_AX);