+ implemented support for instructions with non-native address size on i8086

(16-bit and 32-bit), i386 (16-bit and 32-bit) and x86_64 (32-bit and 64-bit).
  Known bug: 32-bit addresses with an offset have their offset truncated to its
  low 16-bits on i8086

git-svn-id: trunk@37409 -
This commit is contained in:
nickysn 2017-10-06 15:27:14 +00:00
parent bfd37969ad
commit 92a52a9f4d
5 changed files with 100 additions and 39 deletions

View File

@ -2650,7 +2650,7 @@
opcode : A_LEA;
ops : 2;
optypes : (ot_reg16 or ot_bits32 or ot_bits64,ot_memory,ot_none,ot_none);
code : #193#208#1#141#72;
code : #208#1#141#72;
flags : [if_8086]
),
(

View File

@ -2664,7 +2664,7 @@
opcode : A_LEA;
ops : 2;
optypes : (ot_reg16 or ot_bits32 or ot_bits64,ot_memory,ot_none,ot_none);
code : #193#208#1#141#72;
code : #208#1#141#72;
flags : [if_8086]
),
(

View File

@ -483,6 +483,9 @@ interface
function calcsize(p:PInsEntry):shortint;
procedure gencode(objdata:TObjData);
function NeedAddrPrefix(opidx:byte):boolean;
function NeedAddrPrefix:boolean;
procedure write0x66prefix(objdata:TObjData);
procedure write0x67prefix(objdata:TObjData);
procedure Swapoperands;
function FindInsentry(objdata:TObjData):boolean;
end;
@ -1704,6 +1707,8 @@ implementation
InsSize:=calcsize(insentry);
if segprefix<>NR_NO then
inc(InsSize);
if NeedAddrPrefix then
inc(InsSize);
{ Fix opsize if size if forced }
if insentry^.flags*[IF_SB,IF_SW,IF_SD]<>[] then
begin
@ -1759,13 +1764,51 @@ implementation
end
else if segprefix<>NR_NO then
InternalError(201001071);
{ Address size prefix? }
if NeedAddrPrefix then
begin
write0x67prefix(objdata);
{ fix the offset for GenNode }
inc(InsOffset);
end;
{ Generate the instruction }
GenCode(objdata);
end;
function is_16_bit_ref(const input:toper):boolean;
var
ir,br : Tregister;
isub,bsub : tsubregister;
has_16_bit_regs: Boolean;
begin
if (input.ref^.index<>NR_NO) and (getregtype(input.ref^.index)=R_MMREGISTER) then
exit(false);
ir:=input.ref^.index;
br:=input.ref^.base;
isub:=getsubreg(ir);
bsub:=getsubreg(br);
{ it's a direct address }
if (br=NR_NO) and (ir=NR_NO) then
begin
{$ifdef i8086}
result:=true;
{$else i8086}
result:=false;
{$endif}
end
else
{ it's an indirection }
begin
result := ((ir<>NR_NO) and (isub=R_SUBW)) or
((br<>NR_NO) and (bsub=R_SUBW));
end;
end;
function taicpu.needaddrprefix(opidx:byte):boolean;
begin
{$if defined(x86_64)}
result:=(oper[opidx]^.typ=top_ref) and
(oper[opidx]^.ref^.refaddr=addr_no) and
{$ifdef x86_64}
@ -1781,6 +1824,22 @@ implementation
(getsubreg(oper[opidx]^.ref^.base)<>R_SUBADDR)
)
);
{$elseif defined(i386)}
result:=(oper[opidx]^.typ=top_ref) and is_16_bit_ref(oper[opidx]^);
{$elseif defined(i8086)}
result:=(oper[opidx]^.typ=top_ref) and not is_16_bit_ref(oper[opidx]^);
{$endif}
end;
function taicpu.NeedAddrPrefix:boolean;
var
i: Integer;
begin
for i:=0 to ops-1 do
if needaddrprefix(i) then
exit(true);
result:=false;
end;
@ -2055,7 +2114,7 @@ implementation
end;
{$elseif defined(i386)}
{$elseif defined(i386) or defined(i8086)}
function process_ea_ref_32(const input:toper;out output:ea;rfield:longint):boolean;
var
@ -2210,7 +2269,6 @@ implementation
output.size:=1+output.bytes;
result:=true;
end;
{$elseif defined(i8086)}
procedure maybe_swap_index_base(var br,ir:Tregister);
var
@ -2322,10 +2380,11 @@ implementation
internalerror(200409263);
{$if defined(x86_64)}
result:=process_ea_ref_64_32(input,output,rfield);
{$elseif defined(i386)}
result:=process_ea_ref_32(input,output,rfield);
{$elseif defined(i8086)}
result:=process_ea_ref_16(input,output,rfield);
{$elseif defined(i386) or defined(i8086)}
if is_16_bit_ref(input) then
result:=process_ea_ref_16(input,output,rfield)
else
result:=process_ea_ref_32(input,output,rfield);
{$endif}
end;
@ -2593,6 +2652,30 @@ implementation
end;
procedure taicpu.write0x66prefix(objdata:TObjData);
const
b66: Byte=$66;
begin
{$ifdef i8086}
if (objdata.CPUType<>cpu_none) and (objdata.CPUType<cpu_386) then
Message(asmw_e_instruction_not_supported_by_cpu);
{$endif i8086}
objdata.writebytes(b66,1);
end;
procedure taicpu.write0x67prefix(objdata:TObjData);
const
b67: Byte=$67;
begin
{$ifdef i8086}
if (objdata.CPUType<>cpu_none) and (objdata.CPUType<cpu_386) then
Message(asmw_e_instruction_not_supported_by_cpu);
{$endif i8086}
objdata.writebytes(b67,1);
end;
procedure taicpu.GenCode(objdata:TObjData);
{
* the actual codes (C syntax, i.e. octal):
@ -2756,28 +2839,6 @@ implementation
end;
{$endif x86_64}
procedure write0x66prefix;
const
b66: Byte=$66;
begin
{$ifdef i8086}
if (objdata.CPUType<>cpu_none) and (objdata.CPUType<cpu_386) then
Message(asmw_e_instruction_not_supported_by_cpu);
{$endif i8086}
objdata.writebytes(b66,1);
end;
procedure write0x67prefix;
const
b67: Byte=$67;
begin
{$ifdef i8086}
if (objdata.CPUType<>cpu_none) and (objdata.CPUType<cpu_386) then
Message(asmw_e_instruction_not_supported_by_cpu);
{$endif i8086}
objdata.writebytes(b67,1);
end;
procedure objdata_writereloc(Data:TRelocDataInt;len:aword;p:TObjSymbol;Reloctype:TObjRelocationType);
begin
{$ifdef i386}
@ -2900,7 +2961,7 @@ implementation
{ Force word push/pop for registers }
if (opsize={$ifdef i8086}S_L{$else}S_W{$endif}) and ((codes[0]=#4) or (codes[0]=#6) or
((codes[0]=#1) and ((codes[2]=#5) or (codes[2]=#7)))) then
write0x66prefix;
write0x66prefix(objdata);
// needed VEX Prefix (for AVX etc.)
@ -3272,7 +3333,7 @@ implementation
begin
{$if defined(x86_64) or defined(i8086)}
if (oper[c and 3]^.ot and OT_SIZE_MASK)=OT_BITS32 then
write0x67prefix;
write0x67prefix(objdata);
{$endif x86_64 or i8086}
end;
&310 : { fixed 16-bit addr }
@ -3280,13 +3341,13 @@ implementation
{ every insentry having code 0310 must be marked with NOX86_64 }
InternalError(2011051302);
{$elseif defined(i386)}
write0x67prefix;
write0x67prefix(objdata);
{$elseif defined(i8086)}
{nothing};
{$endif}
&311 : { fixed 32-bit addr }
{$if defined(x86_64) or defined(i8086)}
write0x67prefix
write0x67prefix(objdata)
{$endif x86_64 or i8086}
;
&320,&321,&322 :
@ -3297,7 +3358,7 @@ implementation
{$elseif defined(i8086)}
OT_BITS32 :
{$endif}
write0x66prefix;
write0x66prefix(objdata);
{$ifndef x86_64}
OT_BITS64 :
Message(asmw_e_64bit_not_supported);
@ -3307,7 +3368,7 @@ implementation
&323 : {no action needed};
&325:
{$ifdef i8086}
write0x66prefix;
write0x66prefix(objdata);
{$else i8086}
{no action needed};
{$endif i8086}
@ -3317,7 +3378,7 @@ implementation
begin
{$ifndef i8086}
if not(needed_VEX) then
write0x66prefix;
write0x66prefix(objdata);
{$endif not i8086}
end;
&326 :

View File

@ -939,7 +939,7 @@ reg16|32,mem \320\1\xC5\110 8086,NOX86_64
[LEA,leaX]
(Ch_Wop2, Ch_Rop1)
reg16|32|64,mem \301\320\1\x8D\110 8086
reg16|32|64,mem \320\1\x8D\110 8086
[LEAVE]
(Ch_RWESP, Ch_WEBP)

View File

@ -2608,7 +2608,7 @@
opcode : A_LEA;
ops : 2;
optypes : (ot_reg16 or ot_bits32 or ot_bits64,ot_memory,ot_none,ot_none);
code : #193#208#1#141#72;
code : #208#1#141#72;
flags : [if_8086]
),
(