mirror of
https://github.com/golang/go
synced 2024-10-01 01:18:32 -06:00
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
This commit is contained in:
parent
73b83a228e
commit
354a3a1513
@ -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;
|
||||||
}
|
}
|
||||||
if(a->index == D_AX)
|
switch(a->index) {
|
||||||
return 1;
|
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(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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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:
|
|||||||
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:
|
|||||||
}
|
}
|
||||||
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);
|
||||||
|
Loading…
Reference in New Issue
Block a user