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[] =
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);
......
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