Commit 354a3a15 authored by Rémy Oudompheng's avatar Rémy Oudompheng

cmd/8l: fix misassembling of MOVB involving (AX)(BX*1)

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
parent 73b83a22
...@@ -794,19 +794,71 @@ uchar ymovtab[] = ...@@ -794,19 +794,71 @@ uchar ymovtab[] =
0 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 int
isax(Adr *a) byteswapreg(Adr *a)
{ {
int cana, canb, canc, cand;
cana = canb = canc = cand = 1;
switch(a->type) { switch(a->type) {
case D_NONE:
cana = cand = 0;
break;
case D_AX: case D_AX:
case D_AL: case D_AL:
case D_AH: case D_AH:
case D_INDIR+D_AX: 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) if(cana)
return 1; 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; return 0;
} }
...@@ -879,7 +931,7 @@ doasm(Prog *p) ...@@ -879,7 +931,7 @@ doasm(Prog *p)
Optab *o; Optab *o;
Prog *q, pp; Prog *q, pp;
uchar *t; uchar *t;
int z, op, ft, tt; int z, op, ft, tt, breg;
int32 v, pre; int32 v, pre;
Reloc rel, *r; Reloc rel, *r;
Adr *a; Adr *a;
...@@ -1272,15 +1324,13 @@ bad: ...@@ -1272,15 +1324,13 @@ bad:
pp = *p; pp = *p;
z = p->from.type; z = p->from.type;
if(z >= D_BP && z <= D_DI) { if(z >= D_BP && z <= D_DI) {
if(isax(&p->to) || p->to.type == D_NONE) { if((breg = byteswapreg(&p->to)) != D_AX) {
// We certainly don't want to exchange
// with AX if the op is MUL or DIV.
*andptr++ = 0x87; /* xchg lhs,bx */ *andptr++ = 0x87; /* xchg lhs,bx */
asmand(&p->from, reg[D_BX]); asmand(&p->from, reg[breg]);
subreg(&pp, z, D_BX); subreg(&pp, z, breg);
doasm(&pp); doasm(&pp);
*andptr++ = 0x87; /* xchg lhs,bx */ *andptr++ = 0x87; /* xchg lhs,bx */
asmand(&p->from, reg[D_BX]); asmand(&p->from, reg[breg]);
} else { } else {
*andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */ *andptr++ = 0x90 + reg[z]; /* xchg lsh,ax */
subreg(&pp, z, D_AX); subreg(&pp, z, D_AX);
...@@ -1291,13 +1341,13 @@ bad: ...@@ -1291,13 +1341,13 @@ bad:
} }
z = p->to.type; z = p->to.type;
if(z >= D_BP && z <= D_DI) { if(z >= D_BP && z <= D_DI) {
if(isax(&p->from)) { if((breg = byteswapreg(&p->from)) != D_AX) {
*andptr++ = 0x87; /* xchg rhs,bx */ *andptr++ = 0x87; /* xchg rhs,bx */
asmand(&p->to, reg[D_BX]); asmand(&p->to, reg[breg]);
subreg(&pp, z, D_BX); subreg(&pp, z, breg);
doasm(&pp); doasm(&pp);
*andptr++ = 0x87; /* xchg rhs,bx */ *andptr++ = 0x87; /* xchg rhs,bx */
asmand(&p->to, reg[D_BX]); asmand(&p->to, reg[breg]);
} else { } else {
*andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */ *andptr++ = 0x90 + reg[z]; /* xchg rsh,ax */
subreg(&pp, z, D_AX); subreg(&pp, z, D_AX);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment