From 92a52a9f4dbaee1b2da474d01f7aab893c412656 Mon Sep 17 00:00:00 2001 From: nickysn Date: Fri, 6 Oct 2017 15:27:14 +0000 Subject: [PATCH] + 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 - --- compiler/i386/i386tab.inc | 2 +- compiler/i8086/i8086tab.inc | 2 +- compiler/x86/aasmcpu.pas | 131 +++++++++++++++++++++++++---------- compiler/x86/x86ins.dat | 2 +- compiler/x86_64/x8664tab.inc | 2 +- 5 files changed, 100 insertions(+), 39 deletions(-) diff --git a/compiler/i386/i386tab.inc b/compiler/i386/i386tab.inc index 3bb3d8aabb..258b15aada 100644 --- a/compiler/i386/i386tab.inc +++ b/compiler/i386/i386tab.inc @@ -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] ), ( diff --git a/compiler/i8086/i8086tab.inc b/compiler/i8086/i8086tab.inc index a2c525a97e..8c87b924e6 100644 --- a/compiler/i8086/i8086tab.inc +++ b/compiler/i8086/i8086tab.inc @@ -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] ), ( diff --git a/compiler/x86/aasmcpu.pas b/compiler/x86/aasmcpu.pas index 21524e3f46..fc88e47888 100644 --- a/compiler/x86/aasmcpu.pas +++ b/compiler/x86/aasmcpu.pas @@ -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.CPUTypecpu_none) and (objdata.CPUTypecpu_none) and (objdata.CPUTypecpu_none) and (objdata.CPUType