{****************************************************************************
Copyright (c) 1993,96 by Florian Klämpfl
****************************************************************************}
{ Assembler:
History:
18.9.1995:
Programm angelegt
19.9.1995:
* Opcodetabellen implementiert
* einfache Befehle können schon übersetzt werden
* ~2000 einfache Befehle pro Sekunde
* Cache eingebaut => >10000 einfache Befehle pro Sekunde
20.9.1995:
* Symboltabellenmechanismen eingebaut
}
unit asmgen;
interface
uses
objects,systems,globals,cobjects,strings;
type
tasmop = (MOV,MOVZX,MOVSX,A_GLOBAL,A_LABEL,A_STATIC,ASCII,ADD,
CALL,DIRECT,IDIV,IMUL,JMP,LEA,MUL,NEG,A_NOT,
POP,POPAD,PUSH,PUSHAD,RET,SUB,XCHG,A_XOR,
FILD,CMP,JZ,A_INC,A_DEC,SETE,SETNE,SETL,
SETG,SETLE,SETGE,JE,JNE,JL,JG,JLE,JGE,
A_OR,FLD,FADD,FMUL,FSUB,FDIV,FCHS,FLD1,
FIDIV,CLTD,JNZ,FSTP,A_DOUBLE,A_AND,JNO,A_NOTH,A_NONE,
ENTER,LEAVE,CLD,MOVS,REP,A_SHL,A_SHR,A_LONG,A_BOUND,
A_BYTE,A_WORD,JNS,JS,JO,SAR,A_TEST,STABS,STABD,
FCOM,FCOMP,FCOMPP,FXCH,FADDP,FMULP,FSUBP,FDIVP,
FNSTS,SAHF,FDIVRP,FSUBRP,SETC,SETNC,JC,JNC,
JA,JAE,JB,JBE,SETA,SETAE,SETB,SETBE,
A_ALIGN,AAA,AAD,AAM,AAS,CBW,CDQ,CLC,CLI,
CLTS,CMC,CWD,CWDE,DAA,DAS,HLT,IRET,LAHF,
LODS,LOCK,NOP,PUSHA,PUSHF,PUSHFD,
STC,STD,STI,STOS,WAIT,XLAT,XLATB,MOVSB,
MOVSBL,MOVSBW,MOVSWL,MOVZB,MOVZWL,POPA,A_IN,
A_OUT,LDS,LCS,LES,LFS,LGS,LSS,POPF,SBB,ADC,
A_DIV,ROR,ROL,RCL,RCR,SAL,SHLD,SHRD,
LCALL,LJMP,LRET,JNAE,JNB,JNA,JNBE,JP,JNP,
JPE,JPO,JNGE,JNG,JNL,JNLE,JCXZ,JECXZ,
LOOP,CMPS,INS,OUTS,SCAS,BSF,BSR,BT,BTC,BTR,BTS,INT,
INT3,INTO,BOUNDL,BOUNDW,
LOOPZ,LOOPE,LOOPNZ,LOOPNE,SETO,SETNO,SETNAE,SETNB,
SETZ,SETNZ,SETNA,SETNBE,SETS,SETNS,SETP,SETPE,SETNP,
SETPO,SETNGE,SETNL,SETNG,SETNLE,ARPL,LAR,LGDT,LIDT,
LLDT,LMSW,LSL,LTR,SGDT,SIDT,SLDT,SMSW,STR,VERR,VERW,
FABS,FBLD,FBSTP,FCLEX,FNCLEX,
FCOS,FDECSTP,FDISI,FNDISI,
FDIVR,FENI,FNENI,FFREE,FIADD,FICOM,FICOMP,
FIDIVR,FIMUL,FINCSTP,FINIT,FNINIT,FIST,FISTP,FISUB,
FISUBR,FLDCW,FLDENV,FLDLG2,FLDLN2,FLDL2E,
FLDL2T,FLDPI,FLDS,FLDZ,FNOP,FPATAN,
FPREM,FPREM1,FPTAN,FRNDINT,FRSTOR,FSAVE,FNSAVE,
FSCALE,FSETPM,FSIN,FSINCOS,FSQRT,FST,FSTCW,FNSTCW,
FSTENV,FNSTENV,FSTSW,FNSTSW,FTST,FUCOM,FUCOMP,
FUCOMPP,FWAIT,FXAM,FXTRACT,FYL2X,FYL2XP1,F2XM1,
FILDQ,FILDS,FILDL,FLDL,FLDT,FISTQ,FISTS,FISTL,FSTL,FSTS,
FSTPS,FISTPL,FSTPL,FISTPS,FISTPQ,FSTPT,
FCOMPS,FICOMPL,FCOMPL,FICOMPS,
FCOMS,FICOML,FCOML,FICOMS,FIADDL,FADDL,FIADDS,
FISUBL,FSUBL,FISUBS,FSUBS,FSUBR,FSUBRS,FISUBRL,
FSUBRL,FISUBRS,FMULS,FIMULL,FMULL,FIMULS,FDIVS,FIDIVL,
FDIVL,FIDIVS,FDIVRS,FIDIVRL,FDIVRL,FIDIVRS,CS,DS,
ES,FS,GS,SS,REPE,REPNE,ADDR_WORD,FADDS);
topsize = (S_NO,S_B,S_W,S_L,S_BW,S_BL,S_WL);
{ Aufzählungstyp für die Register }
{ Reihefolge nicht verändern ! }
tregister = (R_NO,R_EAX,R_ECX,R_EDX,R_EBX,R_ESP,R_EBP,R_ESI,R_EDI,
R_AX,R_CX,R_DX,R_BX,R_SP,R_BP,R_SI,R_DI,
R_AL,R_CL,R_DL,R_BL);
tsetofregisters =set of tregister;
tdisposing = (D_LABEL,D_STRING);
preferenz = ^treferenz;
treferenz = record
isintvalue : boolean;
base,index : tregister;
scalefactor : byte;
offset : longint;
symbol : pstring;
end;
tsimplasmoptyp = (IS_MEM,IS_REG,IS_CONST);
tsimplasmop = record
case optyp : tsimplasmoptyp of
IS_MEM : (ref : treferenz);
IS_REG : (reg : tregister);
end;
pasmrec = ^tasmrec;
tasmrec = record
next : pasmrec;
opsize : topsize;
instruc : tasmop;
linenr : longint;
infile : pinputstack;
case disposing : tdisposing of
D_LABEL : (l : longint);
D_STRING : (t : pchar);
end;
pasmlist = ^tasmlist;
tasmlist = object
wurzel,last : pasmrec;
constructor init;
destructor done;
{ wird am Ende angehängt }
procedure concat(p : pasmrec);
procedure concatlist(p : pasmlist);
{ fügen am Anfang ein }
procedure insert(p : pasmrec);
procedure insertlist(p : pasmlist);
end;
const
regid2str : array[R_NO..R_BL] of string[4] =
('','%eax','%ecx','%edx','%ebx','%esp','%ebp','%esi','%edi',
'%ax','%cx','%dx','%bx','%sp','%bp','%si','%di',
'%al','%cl','%dl','%bl');
procedure asmgeninit;
function gennasmrec(i : tasmop;s : topsize;const t : string) : pasmrec;
function genlasmrec(i : tasmop;l : longint) : pasmrec;
function genpasmrec(i : tasmop;s : topsize;pc : pchar) : pasmrec;
procedure writemainasmlist(const filename : string);
procedure writeofile(const filename : string);
procedure disposeasmrec(p : pasmrec);
function getreferenzstring(const ref : treferenz) : string;
procedure clear_referenz(var ref : treferenz);
function tolabel(l : longint) : string;
{ für den Sprungoptimierer }
type
pusedinfo = ^tusedinfo;
tusedinfo = record
used_at : pasmrec;
next : pusedinfo;
end;
plabelinfo = ^tlabelinfo;
tlabelinfo = record
defined : pasmrec;
used : pusedinfo;
next : plabelinfo;
end;
procedure registerlabel(l : longint);
function getinforec(l : longint) : plabelinfo;
procedure delused(p : pasmrec);
procedure registerused(p : pasmrec;l : longint);
{ gibt eine eindeutige Nummer für ein Label zurück }
function getlabel : longint;
{ eindeutiges Label fuer einen Konstante }
function getconstlabel : longint;
{ ... hier aber nicht registriert }
function getunreglabel : longint;
{ Registerkonvertierungen }
function reg8toreg16(reg : tregister) : tregister;
function reg8toreg32(reg : tregister) : tregister;
function reg16toreg8(reg : tregister) : tregister;
function reg32toreg8(reg : tregister) : tregister;
function reg32toreg16(reg : tregister) : tregister;
function reg16toreg32(reg : tregister) : tregister;
{$ifdef tp}
procedure setnext(p : pasmrec;to_ : pasmrec);
function getnext(p : pasmrec) : pasmrec;
{$endif}
var
mainasmlist,startupasmlist : tasmlist;
{ asmlist fuer das Datensegment }
datasegment : tasmlist;
{ asmlist fuer die Konstanten }
constsegment : tasmlist;
{ gibt die Anzahl der erzeugten Zeilen an }
asmlines : longint;
{ ist true, wenn ein push oder pusha generiert wurde }
pushgened : boolean;
{ Assemblerliste, in die die VMT's eingefügt werden }
vmtasmlist : tasmlist;
{$ifdef tp}
{ tasmrec auf dem Heap, wenn die asmrec's in }
{ EMS-Speicher abgelgt werden }
hasmrec : pasmrec;
{$endif}
{**********************************************************************
Der Assembler
**********************************************************************}
const
bufsize = 10000;
bytebufsize = 1000;
type
tsegment = (SEG_UNKNOWN,SEG_TEXT,SEG_DATA,SEG_BSS);
pasmsym = ^tasmsym;
pminstruc = ^tminstruc;
preloc = ^treloc;
treloc = record
codefrag : pminstruc;
seg : tsegment;
addr : longint;
next : preloc;
end;
tasmsym = record
seg : tsegment;
is_global : boolean;
name : pchar;
codefrag : pminstruc;
addr : longint;
relocs : preloc;
left,right : pasmsym;
end;
pbytebufferrec = ^tbytebufferrec;
tbytebufferrec = record
buf : array[0..bytebufsize] of byte;
next : pbytebufferrec;
end;
tbytebuffer = object
data,last : pbytebufferrec;
nextpos,size : longint;
constructor init;
destructor done;
procedure setdata(d : pbyte;bytes : longint);
procedure writedata(var f : file);
end;
tminstruc = record
size : word;
jmpb : byte;
addr : longint;
data : pbyte;
_label : pasmsym;
extra : longint;
next : pminstruc;
end;
tbuffer = array[0..bufsize] of byte;
pbuffer = ^tbuffer;
tassembler = object
aktrec : pasmrec;
wurzel,last : pminstruc;
bufp : longint;
buffer : pbuffer;
syms : pasmsym;
current_seg : tsegment;
bsssize : longint;
binary,textseg,dataseg : tbytebuffer;
constructor init;
destructor done;
procedure assembl(instruc : tasmop;opsize : topsize;p_ : pchar;asmrec : pasmrec);
procedure concat(s : byte;var data);
procedure concatjmp(jmpb : byte;_label : pasmsym;extra : longint);
function searchl(s : pchar) : pasmsym;
procedure insertl(p : pasmsym);
procedure write_file(var ppufile : file);
procedure do_asm(p : pchar);
procedure reloc_sym(name : pchar;seg : tsegment);
end;
implementation
var
{ Zähler zum Erzeugen von Labels }
labelcount : longint;
function reg8toreg16(reg : tregister) : tregister;
begin
reg8toreg16:=reg32toreg16(reg8toreg32(reg));
end;
function reg16toreg8(reg : tregister) : tregister;
begin
reg16toreg8:=reg32toreg8(reg16toreg32(reg));
end;
function reg16toreg32(reg : tregister) : tregister;
begin
reg16toreg32:=tregister(byte(reg)-byte(R_EDI));
end;
function reg32toreg16(reg : tregister) : tregister;
begin
reg32toreg16:=tregister(byte(reg)+byte(R_EDI));
end;
function reg32toreg8(reg : tregister) : tregister;
begin
reg32toreg8:=tregister(byte(reg)+byte(R_DI));
end;
function reg8toreg32(reg : tregister) : tregister;
begin
reg8toreg32:=tregister(byte(reg)-byte(R_DI));
end;
function getlabel : longint;
begin
inc(labelcount);
{ if jumpoptimize then
registerlabel(labelcount); }
getlabel:=labelcount;
end;
function getconstlabel : longint;
begin
inc(labelcount);
getconstlabel:=labelcount;
end;
function getunreglabel : longint;
begin
inc(labelcount);
getunreglabel:=labelcount;
end;
{ Verwaltung der Labelpositionen (für Sprungoptimierungen) }
const
labelcontsize = 500;
type
tlabelcontainer = array[0..labelcontsize-1] of plabelinfo;
var
labelcontainer : ^tlabelcontainer;
function getinforec(l : longint) : plabelinfo;
var
hp : plabelinfo;
i : word;
begin
hp:=labelcontainer^[l mod labelcontsize];
for i:=1 to (l div labelcontsize) do
hp:=hp^.next;
getinforec:=hp;
end;
procedure registerlabel(l : longint);
var
hp : plabelinfo;
begin
new(hp);
hp^.next:=labelcontainer^[l mod labelcontsize];
hp^.used:=nil;
hp^.defined:=nil;
labelcontainer^[l mod labelcontsize]:=hp;
end;
procedure delused(p : pasmrec);
var
hp1 : plabelinfo;
hp2,hp3 : pusedinfo;
l : longint;
begin
l:=p^.l;
hp1:=getinforec(l);
hp2:=hp1^.used;
if hp2^.used_at=p then
begin
hp3:=hp2^.next;
dispose(hp2);
hp1^.used:=hp3;
end
else
begin
while hp2^.next^.used_at<>p do
hp2:=hp2^.next;
hp3:=hp2^.next^.next;
dispose(hp2^.next);
hp2^.next:=hp3;
end;
end;
procedure registerused(p : pasmrec;l : longint);
var
hp1 : plabelinfo;
hp2 : pusedinfo;
begin
hp1:=getinforec(l);
new(hp2);
hp2^.used_at:=p;
hp2^.next:=hp1^.used;
hp1^.used:=hp2;
end;
function getreferenzstring(const ref : treferenz) : string;
var
s : string;
begin
if ref.isintvalue then
s:='$'+tostr(ref.offset)
else
{$ifdef tp}
with ref do
begin
s:='';
if assigned(symbol) then
s:=symbol^;
if offset<0 then s:=s+tostr(offset)
else if (offset>0) then
begin
if (symbol=nil) then s:=tostr(offset)
else s:=s+'+'+tostr(offset);
end;
if (index<>R_NO) and (base=R_NO) then
s:=s+'(,'+regid2str[index]+','+tostr(scalefactor)+')'
else if (index=R_NO) and (base<>R_NO) then
s:=s+'('+regid2str[base]+')'
else if (index<>R_NO) and (base<>R_NO) then
s:=s+'('+regid2str[base]+','
+regid2str[index]+','+tostr(scalefactor)+')';
end;
{$else}
begin
s:='';
if assigned(ref.symbol) then
s:=ref.symbol^;
if ref.offset<0 then s:=s+tostr(ref.offset)
else if (ref.offset>0) then
begin
if (ref.symbol=nil) then s:=tostr(ref.offset)
else s:=s+'+'+tostr(ref.offset);
end;
if (ref.index<>R_NO) and (ref.base=R_NO) then
s:=s+'(,'+regid2str[ref.index]+','+tostr(ref.scalefactor)+')'
else if (ref.index=R_NO) and (ref.base<>R_NO) then
s:=s+'('+regid2str[ref.base]+')'
else if (ref.index<>R_NO) and (ref.base<>R_NO) then
s:=s+'('+regid2str[ref.base]+','
+regid2str[ref.index]+','+tostr(ref.scalefactor)+')';
end;
{$endif}
getreferenzstring:=s;
end;
procedure clear_referenz(var ref : treferenz);
begin
{$ifdef tp}
with ref do
begin
index:=R_NO;
base:=R_NO;
offset:=0;
scalefactor:=1;
symbol:=nil;
isintvalue:=false;
end;
{$else}
ref.index:=R_NO;
ref.base:=R_NO;
ref.offset:=0;
ref.scalefactor:=1;
ref.symbol:=nil;
ref.isintvalue:=false;
{$endif}
end;
{ ******************************************************** }
const
op_2_asm : array[MOV..A_ALIGN] of string[7] =
('mov','movz','movs','.comm','','.lcomm','.ascii','add',
'call','','idiv','imul','jmp','lea','mul','neg','not',
'pop','popal','push','pushal','ret','sub','xchg','xor',
'fild','cmp','jz','inc','dec','sete','setne','setl',
'setg','setle','setge','je','jne','jl','jg','jle','jge',
'or','fld','fadd','fmul','fsub','fdivr','fchs','fld1',
'fidiv','cltd','jnz','fstp','.double','and','jno','','',
'enter','leave','cld','movs','rep','shl','shr','.long','bound',
'.byte','.word','jns','js','jo','sar','test','.stabs','.stabd',
'fcom','fcomp','fcompp','fxch','faddp','fmulp','fsubrp','fdivrp',
'fnsts','sahf','fdivp','fsubp','setc','setnc','jc','jnc',
'ja','jae','jb','jbe','seta','setae','setb','setbe',
'.align');
const postf_2_asm : array[S_NO..S_WL] of string[2] = ('','b','w','l','bw',
'bl','wl');
constructor tasmlist.init;
begin
wurzel:=nil;
last:=nil;
end;
{$ifdef tp}
procedure setnext(p : pasmrec;to_ : pasmrec);
begin
symbolstream.seek(longint(p));
symbolstream.read(hasmrec^,sizeof(tasmrec));
hasmrec^.next:=to_;
symbolstream.seek(longint(p));
symbolstream.write(hasmrec^,sizeof(tasmrec));
end;
function getnext(p : pasmrec) : pasmrec;
begin
symbolstream.seek(longint(p));
symbolstream.read(hasmrec^,sizeof(tasmrec));
getnext:=hasmrec^.next;
end;
{$endif}
destructor tasmlist.done;
var
hp : pasmrec;
begin
hp:=wurzel;
while assigned(hp) do
begin
{$ifdef tp}
if use_big then
wurzel:=getnext(hp)
else
{$endif}
wurzel:=hp^.next;
disposeasmrec(hp);
hp:=wurzel;
end;
end;
procedure tasmlist.insert(p : pasmrec);
begin
{$ifdef tp}
if use_big then
setnext(p,wurzel)
else
{$endif}
p^.next:=wurzel;
wurzel:=p;
if last=nil then last:=p;
end;
procedure tasmlist.insertlist(p : pasmlist);
begin
if p^.last=nil then
exit;
{$ifdef tp}
if use_big then
setnext(p^.last,wurzel)
else
{$endif}
p^.last^.next:=wurzel;
wurzel:=p^.wurzel;
if last=nil then last:=p^.last;
p^.last:=nil;
p^.wurzel:=nil;
end;
procedure tasmlist.concat(p : pasmrec);
begin
if wurzel=nil then wurzel:=p
else
begin
{$ifdef tp}
if use_big then
setnext(last,p)
else
{$endif}
last^.next:=p;
end;
last:=p;
end;
procedure tasmlist.concatlist(p : pasmlist);
begin
if p^.wurzel=nil then exit;
if wurzel=nil then wurzel:=p^.wurzel
else
begin
{$ifdef tp}
if use_big then
setnext(last,p^.wurzel)
else
{$endif}
last^.next:=p^.wurzel;
end;
last:=p^.last;
p^.last:=nil;
p^.wurzel:=nil;
end;
procedure disposeasmrec(p : pasmrec);
begin
{$ifdef tp}
if not(use_big) then
{$endif tp}
begin
if (p^.disposing=D_STRING) then
strdispose(p^.t);
dispose(p);
end;
end;
procedure asmgeninit;
procedure writeasm(s : string);
begin
startupasmlist.concat(gennasmrec(DIRECT,S_NO,'// '+s));
end;
function janein(b : boolean) : string;
begin
if b then janein:='Ja'
else janein:='Nein';
end;
var
i : integer;
begin
{$ifdef tp}
new(hasmrec);
{$endif}
labelcount:=0;
mainasmlist.init;
startupasmlist.init;
writeasm('compiled by FPKPascal '+version);
writeasm('');
writeasm('target os:');
writeasm(' '+target_info.target_name);
startupasmlist.concat(gennasmrec(DIRECT,S_NO,'.text'));
startupasmlist.concat(gennasmrec(DIRECT,S_NO,'.align 4'));
asmlines:=0;
end;
function gennasmrec(i : tasmop;s : topsize;const t : string) : pasmrec;
var
p : pasmrec;
l : longint;
b : array[0..255] of char;
begin
if (i=PUSH) or (i=PUSHAD) then pushgened:=true;
{$ifdef tp}
if use_big then
p:=hasmrec
else
{$endif}
new(p);
p^.linenr:=inputstack^.line_no;
p^.infile:=inputstack;
p^.instruc:=i;
p^.disposing:=D_STRING;
p^.opsize:=s;
{$ifdef tp}
if use_big then
begin
strpcopy(b,t);
p^.t:=pchar(symbolstream.size);
symbolstream.seek(longint(p^.t));
symbolstream.strwrite(b);
end
else
{$endif}
p^.t:=strpnew(t);
p^.next:=nil;
{$ifdef tp}
if use_big then
begin
gennasmrec:=pasmrec(symbolstream.size);
symbolstream.seek(symbolstream.size);
symbolstream.write(p^,sizeof(tasmrec));
end
else
{$endif}
gennasmrec:=p;
end;
function genpasmrec(i : tasmop;s : topsize;pc : pchar) : pasmrec;
var
p : pasmrec;
begin
if (i=PUSH) or (i=PUSHAD) then pushgened:=true;
{$ifdef tp}
if use_big then
p:=hasmrec
else
{$endif}
new(p);
p^.linenr:=inputstack^.line_no;
p^.infile:=inputstack;
p^.instruc:=i;
p^.disposing:=D_STRING;
p^.opsize:=s;
{$ifdef TP}
if use_big then
begin
p^.t:=pchar(symbolstream.size);
symbolstream.seek(longint(p^.t));
symbolstream.strwrite(pc);
end
else
{$endif}
p^.t:=strnew(pc);
p^.next:=nil;
{$ifdef tp}
if use_big then
begin
genpasmrec:=pasmrec(symbolstream.size);
symbolstream.seek(symbolstream.size);
symbolstream.write(p^,sizeof(tasmrec));
end
else
{$endif}
genpasmrec:=p;
end;
function genlasmrec(i : tasmop;l : longint) : pasmrec;
var
p : pasmrec;
begin
{$ifdef tp}
if use_big then
p:=hasmrec
else
{$endif}
new(p);
p^.linenr:=inputstack^.line_no;
p^.infile:=inputstack;
p^.instruc:=i;
p^.opsize:=S_NO;
p^.disposing:=D_LABEL;
p^.l:=l;
p^.next:=nil;
{$ifdef tp}
if use_big then
begin
genlasmrec:=pasmrec(symbolstream.size);
symbolstream.seek(symbolstream.size);
symbolstream.write(p^,sizeof(tasmrec));
end
else
{$endif}
genlasmrec:=p;
end;
const
{$ifdef tp}
asmbufsize = 65000;
{$else}
{ voll zuschlagen: }
asmbufsize = 1024*1024;
{$endif}
type
tasmbuffer = array[1..asmbufsize] of char;
var
asmbuffer : ^tasmbuffer;
asmbuffersize : longint;
asmbufferpos : longint;
asmfile : file;
procedure writestring(const s : string);
begin
if asmbufferpos+length(s)+2>asmbuffersize then
begin
blockwrite(asmfile,asmbuffer^,asmbufferpos-1);
asmbufferpos:=1;
end;
move(s[1],asmbuffer^[asmbufferpos],length(s));
inc(asmbufferpos,length(s));
end;
procedure writechararray(p : pchar);
var
w : word;
begin
w:=strlen(p);
if asmbufferpos+w+2>asmbuffersize then
begin
blockwrite(asmfile,asmbuffer^,asmbufferpos-1);
asmbufferpos:=1;
end;
move(p^,asmbuffer^[asmbufferpos],w);
inc(asmbufferpos,w);
end;
function tolabel(l : longint) : string;
var
s : string;
begin
system.str(l,s);
tolabel:='L'+s;
end;
{**********************************************************************
Der Assembler
**********************************************************************}
const
Unknown = $0;
Reg8 = $1; { 8 bit reg }
Reg16 = $2; { 16 bit reg }
Reg32 = $4; { 32 bit reg }
Reg = (Reg8 or Reg16 or Reg32); { gen'l register }
WordReg = (Reg16 or Reg32); { f or push/pop operands }
Imm8 = $8; { 8 bit immediate }
Imm8S = $10; { 8 bit immediate sign extended }
Imm16 = $20; { 16 bit immediate }
Imm32 = $40; { 32 bit immediate }
Imm1 = $80; { 1 bit immediate }
ImmUnknown = Imm32; { f or unknown expressions }
Imm = (Imm8 or Imm8S or Imm16 or Imm32); { gen'l immediate }
Disp8 = $200; { 8 bit displacement (f or jumps) }
Disp16 = $400; { 16 bit displacement }
Disp32 = $800; { 32 bit displacement }
Disp = (Disp8 or Disp16 or Disp32); { General displacement }
DispUnknown = Disp32; { f or unknown size displacements }
Mem8 = $1000;
Mem16 = $2000;
Mem32 = $4000;
BaseIndex = $8000;
Mem = (Disp or Mem8 or Mem16 or Mem32 or BaseIndex); { General mem or y }
WordMem = (Mem16 or Mem32 or Disp or BaseIndex);
ByteMem = (Mem8 or Disp or BaseIndex);
InOutPortReg = $10000; { register to hold in/out p or t addr = dx }
ShiftCount = $20000; { register to hold shift cound = cl }
Control = $40000; { Control register }
Debug = $80000; { Debug register }
Test = $100000; { Test register }
FloatReg = $200000; { Float register }
FloatAcc = $400000; { Float stack top %st(0) }
SReg2 = $800000; { 2 bit segment register }
SReg3 = $1000000; { 3 bit segment register }
Acc = $2000000; { Accumulat or %al or %ax or %eax }
ImplicitRegister = (InOutPortReg or ShiftCount or Acc or FloatAcc);
JumpAbsolute = $4000000;
Abs8 = $08000000;
Abs16 = $10000000;
Abs32 = $20000000;
Abs = (Abs8 or Abs16 or Abs32);
None = $ff;
_W = $1; { set if operands are words or dwords }
D = $2; { D = 0 if Reg --> Regmem; D = 1 if Regmem --> Reg }
{ direction flag for floating insns: MUST BE = $400 }
FloatD = $400;
{ shorthand }
DW = (D or _W);
ShortForm = $10; { register is in low 3 bits of opcode }
ShortFormW = $20; { ShortForm and W bit is = $8 }
Seg2ShortForm = $40; { encoding of load segment reg insns }
Seg3ShortForm = $80; { fs/gs segment register insns. }
Jump = $100; { special case for jump insns. }
JumpInterSegment = $200; { special case for intersegment leaps/calls }
DONT_USE = $400;
NoModrm = $800;
Modrm = $1000;
imulKludge = $2000;
JumpByte = $4000;
JumpDword = $8000;
ReverseRegRegmem = $10000;
type
ttemplate = record
i : tasmop;
ops : byte;
oc : longint;
eb : byte;
m : longint;
o1,o2,o3 : longint;
end;
tins_cache = array[MOV..FADDS] of longint;
var
ins_cache : tins_cache;
const
it : array[0..442] of ttemplate = (
(i : MOV;ops : 2;oc : $a0;eb : None;m : DW or NoModrm;o1 : Disp32;o2 : Acc;o3 : 0 ),
(i : MOV;ops : 2;oc : $88;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0 ),
(i : MOV;ops : 2;oc : $b0;eb : None;m : ShortFormW;o1 : Imm;o2 : Reg;o3 : 0 ),
(i : MOV;ops : 2;oc : $c6;eb : None;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0 ),
(i : MOV;ops : 2;oc : $8c;eb : None;m : D or Modrm;o1 : SReg3 or SReg2;o2 : Reg16 or Mem16;o3 : 0 ),
(i : MOV;ops : 2;oc : $0f20;eb : None;m : D or Modrm;o1 : Control;o2 : Reg32;o3 : 0),
(i : MOV;ops : 2;oc : $0f21;eb : None;m : D or Modrm;o1 : Debug;o2 : Reg32;o3 : 0),
(i : MOV;ops : 2;oc : $0f24;eb : None;m : D or Modrm;o1 : Test;o2 : Reg32;o3 : 0),
(i : MOVSB;ops : 2;oc : $0fbe;eb : None;m : ReverseRegRegmem or Modrm;o1 : Reg8 or Mem;o2 : Reg16 or Reg32;o3 : 0),
(i : MOVSBL;ops : 2;oc : $0fbe;eb : None;m : ReverseRegRegmem or Modrm;o1 : Reg8 or Mem;o2 : Reg32;o3 : 0),
(i : MOVSBW;ops : 2;oc : $660fbe;eb : None;m : ReverseRegRegmem or Modrm;o1 : Reg8 or Mem;o2 : Reg16;o3 : 0),
(i : MOVSWL;ops : 2;oc : $0fbf;eb : None;m : ReverseRegRegmem or Modrm;o1 : Reg16 or Mem;o2 : Reg32;o3 : 0),
(i : MOVZB;ops : 2;oc : $0fb6;eb : None;m : ReverseRegRegmem or Modrm;o1 : Reg8 or Mem;o2 : Reg16 or Reg32;o3 : 0),
(i : MOVZWL;ops : 2;oc : $0fb7;eb : None;m : ReverseRegRegmem or Modrm;o1 : Reg16 or Mem;o2 : Reg32;o3 : 0),
(i : PUSH;ops : 1;oc : $50;eb : None;m : ShortForm;o1 : WordReg;o2 : 0;o3 : 0 ),
(i : PUSH;ops : 1;oc : $ff;eb : $6;m : Modrm;o1 : WordReg or WordMem;o2 : 0;o3 : 0 ),
(i : PUSH;ops : 1;oc : $6a;eb : None;m : NoModrm;o1 : Imm8S;o2 : 0;o3 : 0),
(i : PUSH;ops : 1;oc : $68;eb : None;m : NoModrm;o1 : Imm32 or Imm16;o2 : 0;o3 : 0),
(i : PUSH;ops : 1;oc : $06;eb : None;m : Seg2ShortForm;o1 : SReg2;o2 : 0;o3 : 0 ),
(i : PUSH;ops : 1;oc : $0fa0;eb : None;m : Seg3ShortForm;o1 : SReg3;o2 : 0;o3 : 0 ),
(i : PUSHA;ops : 0;oc : $60;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0 ),
(i : POP;ops : 1;oc : $58;eb : None;m : ShortForm;o1 : WordReg;o2 : 0;o3 : 0 ),
(i : POP;ops : 1;oc : $8f;eb : $0;m : Modrm;o1 : WordReg or WordMem;o2 : 0;o3 : 0 ),
(i : POP;ops : 1;oc : $07;eb : None;m : Seg2ShortForm;o1 : SReg2;o2 : 0;o3 : 0 ),
(i : POP;ops : 1;oc : $0fa1;eb : None;m : Seg3ShortForm;o1 : SReg3;o2 : 0;o3 : 0 ),
(i : POPA;ops : 0;oc : $61;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0 ),
(i : XCHG;ops : 2;oc : $90;eb : None;m : ShortForm;o1 : WordReg;o2 : Acc;o3 : 0 ),
(i : XCHG;ops : 2;oc : $90;eb : None;m : ShortForm;o1 : Acc;o2 : WordReg;o3 : 0 ),
(i : XCHG;ops : 2;oc : $86;eb : None;m : _W or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0 ),
(i : XCHG;ops : 2;oc : $86;eb : None;m : _W or Modrm;o1 : Reg or Mem;o2 : Reg;o3 : 0 ),
(i : A_IN;ops : 2;oc : $e4;eb : None;m : _W or NoModrm;o1 : Imm8;o2 : Acc;o3 : 0 ),
(i : A_IN;ops : 2;oc : $ec;eb : None;m : _W or NoModrm;o1 : InOutPortReg;o2 : Acc;o3 : 0 ),
(i : A_OUT;ops : 2;oc : $e6;eb : None;m : _W or NoModrm;o1 : Acc;o2 : Imm8;o3 : 0 ),
(i : A_OUT;ops : 2;oc : $ee;eb : None;m : _W or NoModrm;o1 : Acc;o2 : InOutPortReg;o3 : 0 ),
(i : LEA;ops : 2;oc : $8d;eb : None;m : Modrm;o1 : WordMem;o2 : WordReg;o3 : 0 ),
(i : LDS;ops : 2;oc : $c5;eb : None;m : Modrm;o1 : Mem;o2 : Reg32;o3 : 0),
(i : LES;ops : 2;oc : $c4;eb : None;m : Modrm;o1 : Mem;o2 : Reg32;o3 : 0),
(i : LFS;ops : 2;oc : $0fb4;eb : None;m : Modrm;o1 : Mem;o2 : Reg32;o3 : 0),
(i : LGS;ops : 2;oc : $0fb5;eb : None;m : Modrm;o1 : Mem;o2 : Reg32;o3 : 0),
(i : LSS;ops : 2;oc : $0fb2;eb : None;m : Modrm;o1 : Mem;o2 : Reg32;o3 : 0),
(i : CLC;ops : 0;oc : $f8;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CLD;ops : 0;oc : $fc;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CLI;ops : 0;oc : $fa;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CLTS;ops : 0;oc : $0f06;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CMC;ops : 0;oc : $f5;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : LAHF;ops : 0;oc : $9f;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : SAHF;ops : 0;oc : $9e;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : PUSHF;ops : 0;oc : $9c;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : POPF;ops : 0;oc : $9d;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : STC;ops : 0;oc : $f9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : STD;ops : 0;oc : $fd;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : STI;ops : 0;oc : $fb;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : ADD;ops : 2;oc : $0;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : ADD;ops : 2;oc : $83;eb : 0;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : ADD;ops : 2;oc : $4;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : ADD;ops : 2;oc : $80;eb : 0;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : A_INC;ops : 1;oc : $40;eb : None;m : ShortForm;o1 : WordReg;o2 : 0;o3 : 0),
(i : A_INC;ops : 1;oc : $fe;eb : 0;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : SUB;ops : 2;oc : $28;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : SUB;ops : 2;oc : $83;eb : 5;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : SUB;ops : 2;oc : $2c;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : SUB;ops : 2;oc : $80;eb : 5;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : A_DEC;ops : 1;oc : $48;eb : None;m : ShortForm;o1 : WordReg;o2 : 0;o3 : 0),
(i : A_DEC;ops : 1;oc : $fe;eb : 1;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : SBB;ops : 2;oc : $18;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : SBB;ops : 2;oc : $83;eb : 3;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : SBB;ops : 2;oc : $1c;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : SBB;ops : 2;oc : $80;eb : 3;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : CMP;ops : 2;oc : $38;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : CMP;ops : 2;oc : $83;eb : 7;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : CMP;ops : 2;oc : $3c;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : CMP;ops : 2;oc : $80;eb : 7;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : A_TEST;ops : 2;oc : $84;eb : None;m : _W or Modrm;o1 : Reg or Mem;o2 : Reg;o3 : 0),
(i : A_TEST;ops : 2;oc : $84;eb : None;m : _W or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : A_TEST;ops : 2;oc : $a8;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : A_TEST;ops : 2;oc : $f6;eb : 0;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : A_AND;ops : 2;oc : $20;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : A_AND;ops : 2;oc : $83;eb : 4;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : A_AND;ops : 2;oc : $24;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : A_AND;ops : 2;oc : $80;eb : 4;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : A_OR;ops : 2;oc : $08;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : A_OR;ops : 2;oc : $83;eb : 1;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : A_OR;ops : 2;oc : $0c;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : A_OR;ops : 2;oc : $80;eb : 1;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : A_XOR;ops : 2;oc : $30;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : A_XOR;ops : 2;oc : $83;eb : 6;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : A_XOR;ops : 2;oc : $34;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : A_XOR;ops : 2;oc : $80;eb : 6;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : ADC;ops : 2;oc : $10;eb : None;m : DW or Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : ADC;ops : 2;oc : $83;eb : 2;m : Modrm;o1 : Imm8S;o2 : WordReg or WordMem;o3 : 0),
(i : ADC;ops : 2;oc : $14;eb : None;m : _W or NoModrm;o1 : Imm;o2 : Acc;o3 : 0),
(i : ADC;ops : 2;oc : $80;eb : 2;m : _W or Modrm;o1 : Imm;o2 : Reg or Mem;o3 : 0),
(i : NEG;ops : 1;oc : $f6;eb : 3;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : A_NOT;ops : 1;oc : $f6;eb : 2;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : AAA;ops : 0;oc : $37;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : AAS;ops : 0;oc : $3f;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : DAA;ops : 0;oc : $27;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : DAS;ops : 0;oc : $2f;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : AAD;ops : 0;oc : $d50a;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : AAM;ops : 0;oc : $d40a;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CBW;ops : 0;oc : $6698;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CWD;ops : 0;oc : $6699;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CWDE;ops : 0;oc : $98;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CDQ;ops : 0;oc : $99;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : MUL;ops : 1;oc : $f6;eb : 4;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : IMUL;ops : 1;oc : $f6;eb : 5;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : IMUL;ops : 2;oc : $0faf;eb : None;m : Modrm or ReverseRegRegmem;o1 : WordReg or Mem;o2 : WordReg;o3 : 0),
(i : IMUL;ops : 3;oc : $6b;eb : None;m : Modrm or ReverseRegRegmem;o1 : Imm8S;o2 : WordReg or Mem;o3 : WordReg),
(i : IMUL;ops : 3;oc : $69;eb : None;m : Modrm or ReverseRegRegmem;o1 : Imm16 or Imm32;o2 : WordReg or Mem;
o3 : WordReg),
(i : IMUL;ops : 2;oc : $6b;eb : None;m : Modrm or imulKludge;o1 : Imm8S;o2 : WordReg;o3 : 0),
(i : IMUL;ops : 2;oc : $69;eb : None;m : Modrm or imulKludge;o1 : Imm16 or Imm32;o2 : WordReg;o3 : 0),
(i : A_DIV;ops : 1;oc : $f6;eb : 6;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : A_DIV;ops : 2;oc : $f6;eb : 6;m : _W or Modrm;o1 : Reg or Mem;o2 : Acc;o3 : 0),
(i : IDIV;ops : 1;oc : $f6;eb : 7;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : IDIV;ops : 2;oc : $f6;eb : 7;m : _W or Modrm;o1 : Reg or Mem;o2 : Acc;o3 : 0),
(i : ROL;ops : 2;oc : $d0;eb : 0;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : ROL;ops : 2;oc : $c0;eb : 0;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : ROL;ops : 2;oc : $d2;eb : 0;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : ROL;ops : 1;oc : $d0;eb : 0;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : ROR;ops : 2;oc : $d0;eb : 1;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : ROR;ops : 2;oc : $c0;eb : 1;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : ROR;ops : 2;oc : $d2;eb : 1;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : ROR;ops : 1;oc : $d0;eb : 1;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : RCL;ops : 2;oc : $d0;eb : 2;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : RCL;ops : 2;oc : $c0;eb : 2;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : RCL;ops : 2;oc : $d2;eb : 2;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : RCL;ops : 1;oc : $d0;eb : 2;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : RCR;ops : 2;oc : $d0;eb : 3;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : RCR;ops : 2;oc : $c0;eb : 3;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : RCR;ops : 2;oc : $d2;eb : 3;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : RCR;ops : 1;oc : $d0;eb : 3;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : SAL;ops : 2;oc : $d0;eb : 4;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : SAL;ops : 2;oc : $c0;eb : 4;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : SAL;ops : 2;oc : $d2;eb : 4;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : SAL;ops : 1;oc : $d0;eb : 4;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : A_SHL;ops : 2;oc : $d0;eb : 4;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : A_SHL;ops : 2;oc : $c0;eb : 4;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : A_SHL;ops : 2;oc : $d2;eb : 4;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : A_SHL;ops : 1;oc : $d0;eb : 4;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : SHLD;ops : 3;oc : $0fa4;eb : None;m : Modrm;o1 : Imm8;o2 : WordReg;o3 : WordReg or Mem),
(i : SHLD;ops : 3;oc : $0fa5;eb : None;m : Modrm;o1 : ShiftCount;o2 : WordReg;o3 : WordReg or Mem),
(i : A_SHR;ops : 2;oc : $d0;eb : 5;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : A_SHR;ops : 2;oc : $c0;eb : 5;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : A_SHR;ops : 2;oc : $d2;eb : 5;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : A_SHR;ops : 1;oc : $d0;eb : 5;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : SHRD;ops : 3;oc : $0fac;eb : None;m : Modrm;o1 : Imm8;o2 : WordReg;o3 : WordReg or Mem),
(i : SHRD;ops : 3;oc : $0fad;eb : None;m : Modrm;o1 : ShiftCount;o2 : WordReg;o3 : WordReg or Mem),
(i : SAR;ops : 2;oc : $d0;eb : 7;m : _W or Modrm;o1 : Imm1;o2 : Reg or Mem;o3 : 0),
(i : SAR;ops : 2;oc : $c0;eb : 7;m : _W or Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : SAR;ops : 2;oc : $d2;eb : 7;m : _W or Modrm;o1 : ShiftCount;o2 : Reg or Mem;o3 : 0),
(i : SAR;ops : 1;oc : $d0;eb : 7;m : _W or Modrm;o1 : Reg or Mem;o2 : 0;o3 : 0),
(i : CALL;ops : 1;oc : $e8;eb : None;m : JumpDword;o1 : Disp32;o2 : 0;o3 : 0),
(i : CALL;ops : 1;oc : $ff;eb : 2;m : Modrm;o1 : Reg or Mem or JumpAbsolute;o2 : 0;o3 : 0),
(i : LCALL;ops : 2;oc : $9a;eb : None;m : JumpInterSegment;o1 : Imm16;o2 : Abs32;o3 : 0),
(i : LCALL;ops : 1;oc : $ff;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : JMP;ops : 1;oc : $eb;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JMP;ops : 1;oc : $ff;eb : 4;m : Modrm;o1 : Reg32 or Mem or JumpAbsolute;o2 : 0;o3 : 0),
(i : LJMP;ops : 2;oc : $ea;eb : None;m : JumpInterSegment;o1 : Imm16;o2 : Imm32;o3 : 0),
(i : LJMP;ops : 1;oc : $ff;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : RET;ops : 0;oc : $c3;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : RET;ops : 1;oc : $c2;eb : None;m : NoModrm;o1 : Imm16;o2 : 0;o3 : 0),
(i : LRET;ops : 0;oc : $cb;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : LRET;ops : 1;oc : $ca;eb : None;m : NoModrm;o1 : Imm16;o2 : 0;o3 : 0),
(i : ENTER;ops : 2;oc : $c8;eb : None;m : NoModrm;o1 : Imm16;o2 : Imm8;o3 : 0),
(i : LEAVE;ops : 0;oc : $c9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : JO;ops : 1;oc : $70;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNO;ops : 1;oc : $71;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JB;ops : 1;oc : $72;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JC;ops : 1;oc : $72;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNAE;ops : 1;oc : $72;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNB;ops : 1;oc : $73;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNC;ops : 1;oc : $73;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JAE;ops : 1;oc : $73;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JE;ops : 1;oc : $74;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JZ;ops : 1;oc : $74;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNE;ops : 1;oc : $75;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNZ;ops : 1;oc : $75;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JBE;ops : 1;oc : $76;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNA;ops : 1;oc : $76;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNBE;ops : 1;oc : $77;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JA;ops : 1;oc : $77;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JS;ops : 1;oc : $78;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNS;ops : 1;oc : $79;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JP;ops : 1;oc : $7a;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JPE;ops : 1;oc : $7a;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNP;ops : 1;oc : $7b;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JPO;ops : 1;oc : $7b;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JL;ops : 1;oc : $7c;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNGE;ops : 1;oc : $7c;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNL;ops : 1;oc : $7d;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JGE;ops : 1;oc : $7d;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JLE;ops : 1;oc : $7e;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNG;ops : 1;oc : $7e;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JNLE;ops : 1;oc : $7f;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JG;ops : 1;oc : $7f;eb : None;m : Jump;o1 : Disp;o2 : 0;o3 : 0),
(i : JCXZ;ops : 1;oc : $67e3;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : JECXZ;ops : 1;oc : $e3;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : LOOP;ops : 1;oc : $e2;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : LOOPZ;ops : 1;oc : $e1;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : LOOPE;ops : 1;oc : $e1;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : LOOPNZ;ops : 1;oc : $e0;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : LOOPNE;ops : 1;oc : $e0;eb : None;m : JumpByte;o1 : Disp;o2 : 0;o3 : 0),
(i : SETO;ops : 1;oc : $0f90;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNO;ops : 1;oc : $0f91;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETB;ops : 1;oc : $0f92;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNAE;ops : 1;oc : $0f92;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNB;ops : 1;oc : $0f93;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETAE;ops : 1;oc : $0f93;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETE;ops : 1;oc : $0f94;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETZ;ops : 1;oc : $0f94;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNE;ops : 1;oc : $0f95;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNZ;ops : 1;oc : $0f95;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETBE;ops : 1;oc : $0f96;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNA;ops : 1;oc : $0f96;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNBE;ops : 1;oc : $0f97;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETA;ops : 1;oc : $0f97;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETS;ops : 1;oc : $0f98;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNS;ops : 1;oc : $0f99;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETP;ops : 1;oc : $0f9a;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETPE;ops : 1;oc : $0f9a;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNP;ops : 1;oc : $0f9b;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETPO;ops : 1;oc : $0f9b;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETL;ops : 1;oc : $0f9c;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNGE;ops : 1;oc : $0f9c;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNL;ops : 1;oc : $0f9d;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETGE;ops : 1;oc : $0f9d;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETLE;ops : 1;oc : $0f9e;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNG;ops : 1;oc : $0f9e;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETNLE;ops : 1;oc : $0f9f;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : SETG;ops : 1;oc : $0f9f;eb : 0;m : Modrm;o1 : Reg8 or Mem;o2 : 0;o3 : 0),
(i : CMPS;ops : 0;oc : $a6;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : INS;ops : 0;oc : $6c;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : OUTS;ops : 0;oc : $6e;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : LODS;ops : 0;oc : $ac;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : MOVS;ops : 0;oc : $a4;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : SCAS;ops : 0;oc : $ae;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : STOS;ops : 0;oc : $aa;eb : None;m : _W or NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : XLAT;ops : 0;oc : $d7;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : BSF;ops : 2;oc : $0fbc;eb : None;m : Modrm or ReverseRegRegmem;o1 : Reg or Mem;o2 : Reg;o3 : 0),
(i : BSR;ops : 2;oc : $0fbd;eb : None;m : Modrm or ReverseRegRegmem;o1 : Reg or Mem;o2 : Reg;o3 : 0),
(i : BT;ops : 2;oc : $0fa3;eb : None;m : Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : BT;ops : 2;oc : $0fba;eb : 4;m : Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : BTC;ops : 2;oc : $0fbb;eb : None;m : Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : BTC;ops : 2;oc : $0fba;eb : 7;m : Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : BTR;ops : 2;oc : $0fb3;eb : None;m : Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : BTR;ops : 2;oc : $0fba;eb : 6;m : Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : BTS;ops : 2;oc : $0fab;eb : None;m : Modrm;o1 : Reg;o2 : Reg or Mem;o3 : 0),
(i : BTS;ops : 2;oc : $0fba;eb : 5;m : Modrm;o1 : Imm8;o2 : Reg or Mem;o3 : 0),
(i : INT;ops : 1;oc : $cd;eb : None;m : NoModrm;o1 : Imm8;o2 : 0;o3 : 0),
(i : INT3;ops : 0;oc : $cc;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : INTO;ops : 0;oc : $ce;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : IRET;ops : 0;oc : $cf;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : BOUNDL;ops : 2;oc : $62;eb : None;m : Modrm;o1 : Reg32;o2 : Mem;o3 : 0),
(i : BOUNDW;ops : 2;oc : $6662;eb : None;m : Modrm;o1 : Reg16;o2 : Mem;o3 : 0),
(i : HLT;ops : 0;oc : $f4;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : WAIT;ops : 0;oc : $9b;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : NOP;ops : 0;oc : $90;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : ARPL;ops : 2;oc : $63;eb : None;m : Modrm;o1 : Reg16;o2 : Reg16 or Mem;o3 : 0),
(i : LAR;ops : 2;oc : $0f02;eb : None;m : Modrm or ReverseRegRegmem;o1 : WordReg or Mem;o2 : WordReg;o3 : 0),
(i : LGDT;ops : 1;oc : $0f01;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : LIDT;ops : 1;oc : $0f01;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : LLDT;ops : 1;oc : $0f00;eb : 2;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : LMSW;ops : 1;oc : $0f01;eb : 6;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : LSL;ops : 2;oc : $0f03;eb : None;m : Modrm or ReverseRegRegmem;o1 : WordReg or Mem;o2 : WordReg;o3 : 0),
(i : LTR;ops : 1;oc : $0f00;eb : 3;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : SGDT;ops : 1;oc : $0f01;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : SIDT;ops : 1;oc : $0f01;eb : 1;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : SLDT;ops : 1;oc : $0f00;eb : 0;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : SMSW;ops : 1;oc : $0f01;eb : 4;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : STR;ops : 1;oc : $0f00;eb : 1;m : Modrm;o1 : Reg16 or Mem;o2 : 0;o3 : 0),
(i : VERR;ops : 1;oc : $0f00;eb : 4;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : VERW;ops : 1;oc : $0f00;eb : 5;m : Modrm;o1 : WordReg or Mem;o2 : 0;o3 : 0),
(i : FLD;ops : 1;oc : $d9c0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FLDS;ops : 1;oc : $d9;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FILDL;ops : 1;oc : $db;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FLDL;ops : 1;oc : $dd;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FLDL;ops : 1;oc : $d9c0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FILDS;ops : 1;oc : $df;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FILDQ;ops : 1;oc : $df;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FLDT;ops : 1;oc : $db;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FBLD;ops : 1;oc : $df;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FST;ops : 1;oc : $ddd0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FSTS;ops : 1;oc : $d9;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISTL;ops : 1;oc : $db;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTL;ops : 1;oc : $dd;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTL;ops : 1;oc : $ddd0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FISTS;ops : 1;oc : $df;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTP;ops : 1;oc : $ddd8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FSTPS;ops : 1;oc : $d9;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISTPL;ops : 1;oc : $db;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTPL;ops : 1;oc : $dd;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTPL;ops : 1;oc : $ddd8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FISTPS;ops : 1;oc : $df;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISTPQ;ops : 1;oc : $df;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTPT;ops : 1;oc : $db;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FBSTP;ops : 1;oc : $df;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FXCH;ops : 1;oc : $d9c8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FCOM;ops : 1;oc : $d8d0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FCOMS;ops : 1;oc : $d8;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FICOML;ops : 1;oc : $da;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FCOML;ops : 1;oc : $dc;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FCOML;ops : 1;oc : $d8d0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FICOMS;ops : 1;oc : $de;eb : 2;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FCOMP;ops : 1;oc : $d8d8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FCOMPS;ops : 1;oc : $d8;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FICOMPL;ops : 1;oc : $da;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FCOMPL;ops : 1;oc : $dc;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FCOMPL;ops : 1;oc : $d8d8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FICOMPS;ops : 1;oc : $de;eb : 3;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FCOMPP;ops : 0;oc : $ded9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FUCOM;ops : 1;oc : $dde0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FUCOMP;ops : 1;oc : $dde8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FUCOMPP;ops : 0;oc : $dae9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FTST;ops : 0;oc : $d9e4;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FXAM;ops : 0;oc : $d9e5;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLD1;ops : 0;oc : $d9e8;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDL2T;ops : 0;oc : $d9e9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDL2E;ops : 0;oc : $d9ea;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDPI;ops : 0;oc : $d9eb;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDLG2;ops : 0;oc : $d9ec;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDLN2;ops : 0;oc : $d9ed;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDZ;ops : 0;oc : $d9ee;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FADD;ops : 1;oc : $d8c0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FADD;ops : 2;oc : $d8c0;eb : None;m : ShortForm or FloatD;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FADD;ops : 0;oc : $dcc1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FADDP;ops : 1;oc : $dac0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FADDP;ops : 2;oc : $dac0;eb : None;m : ShortForm or FloatD;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FADDP;ops : 0;oc : $dec1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FADDS;ops : 1;oc : $d8;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIADDL;ops : 1;oc : $da;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FADDL;ops : 1;oc : $dc;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIADDS;ops : 1;oc : $de;eb : 0;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSUB;ops : 1;oc : $d8e0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FSUB;ops : 2;oc : $d8e0;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FSUB;ops : 2;oc : $dce8;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FSUB;ops : 0;oc : $dce1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSUBP;ops : 1;oc : $dae0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FSUBP;ops : 2;oc : $dae0;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FSUBP;ops : 2;oc : $dee0;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FSUBP;ops : 0;oc : $dee1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSUBS;ops : 1;oc : $d8;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISUBL;ops : 1;oc : $da;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSUBL;ops : 1;oc : $dc;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISUBS;ops : 1;oc : $de;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSUBR;ops : 1;oc : $d8e8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FSUBR;ops : 2;oc : $d8e8;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FSUBR;ops : 2;oc : $dce8;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FSUBR;ops : 0;oc : $dce9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSUBRP;ops : 1;oc : $dae8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FSUBRP;ops : 2;oc : $dae8;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FSUBRP;ops : 2;oc : $dee8;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FSUBRP;ops : 0;oc : $dee9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSUBRS;ops : 1;oc : $d8;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISUBRL;ops : 1;oc : $da;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSUBRL;ops : 1;oc : $dc;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FISUBRS;ops : 1;oc : $de;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FMUL;ops : 1;oc : $d8c8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FMUL;ops : 2;oc : $d8c8;eb : None;m : ShortForm or FloatD;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FMUL;ops : 0;oc : $dcc9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FMULP;ops : 1;oc : $dac8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FMULP;ops : 2;oc : $dac8;eb : None;m : ShortForm or FloatD;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FMULP;ops : 0;oc : $dec9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FMULS;ops : 1;oc : $d8;eb : 1;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIMULL;ops : 1;oc : $da;eb : 1;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FMULL;ops : 1;oc : $dc;eb : 1;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIMULS;ops : 1;oc : $de;eb : 1;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FDIV;ops : 1;oc : $d8f0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FDIV;ops : 2;oc : $d8f0;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FDIV;ops : 2;oc : $dcf0;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FDIV;ops : 0;oc : $dcf1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FDIVP;ops : 1;oc : $daf0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FDIVP;ops : 2;oc : $daf0;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FDIVP;ops : 2;oc : $def0;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FDIVP;ops : 0;oc : $def1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FDIVS;ops : 1;oc : $d8;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIDIVL;ops : 1;oc : $da;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FDIVL;ops : 1;oc : $dc;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIDIVS;ops : 1;oc : $de;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FDIVR;ops : 1;oc : $d8f8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FDIVR;ops : 2;oc : $d8f8;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FDIVR;ops : 2;oc : $dcf8;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FDIVR;ops : 0;oc : $dcf9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FDIVRP;ops : 1;oc : $daf8;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FDIVRP;ops : 2;oc : $daf8;eb : None;m : ShortForm;o1 : FloatReg;o2 : FloatAcc;o3 : 0),
(i : FDIVRP;ops : 2;oc : $def8;eb : None;m : ShortForm;o1 : FloatAcc;o2 : FloatReg;o3 : 0),
(i : FDIVRP;ops : 0;oc : $def9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FDIVRS;ops : 1;oc : $d8;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIDIVRL;ops : 1;oc : $da;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FDIVRL;ops : 1;oc : $dc;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FIDIVRS;ops : 1;oc : $de;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : F2XM1;ops : 0;oc : $d9f0;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FYL2X;ops : 0;oc : $d9f1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FPTAN;ops : 0;oc : $d9f2;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FPATAN;ops : 0;oc : $d9f3;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FXTRACT;ops : 0;oc : $d9f4;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FPREM1;ops : 0;oc : $d9f5;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FDECSTP;ops : 0;oc : $d9f6;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FINCSTP;ops : 0;oc : $d9f7;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FPREM;ops : 0;oc : $d9f8;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FYL2XP1;ops : 0;oc : $d9f9;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSQRT;ops : 0;oc : $d9fa;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSINCOS;ops : 0;oc : $d9fb;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FRNDINT;ops : 0;oc : $d9fc;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSCALE;ops : 0;oc : $d9fd;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSIN;ops : 0;oc : $d9fe;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FCOS;ops : 0;oc : $d9ff;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FCHS;ops : 0;oc : $d9e0;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FABS;ops : 0;oc : $d9e1;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FNINIT;ops : 0;oc : $dbe3;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FINIT;ops : 0;oc : $dbe3;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FLDCW;ops : 1;oc : $d9;eb : 5;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FNSTCW;ops : 1;oc : $d9;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTCW;ops : 1;oc : $d9;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FNSTSW;ops : 1;oc : $dfe0;eb : None;m : NoModrm;o1 : Acc;o2 : 0;o3 : 0),
(i : FNSTSW;ops : 1;oc : $dd;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FNSTSW;ops : 0;oc : $dfe0;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FSTSW;ops : 1;oc : $dfe0;eb : None;m : NoModrm;o1 : Acc;o2 : 0;o3 : 0),
(i : FSTSW;ops : 1;oc : $dd;eb : 7;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTSW;ops : 0;oc : $dfe0;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FNCLEX;ops : 0;oc : $dbe2;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FCLEX;ops : 0;oc : $dbe2;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FNSTENV;ops : 1;oc : $d9;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSTENV;ops : 1;oc : $d9;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FLDENV;ops : 1;oc : $d9;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FNSAVE;ops : 1;oc : $dd;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FSAVE;ops : 1;oc : $dd;eb : 6;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FRSTOR;ops : 1;oc : $dd;eb : 4;m : Modrm;o1 : Mem;o2 : 0;o3 : 0),
(i : FFREE;ops : 1;oc : $ddc0;eb : None;m : ShortForm;o1 : FloatReg;o2 : 0;o3 : 0),
(i : FNOP;ops : 0;oc : $d9d0;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FWAIT;ops : 0;oc : $9b;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : ADDR_WORD;ops : 0;oc : $67;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : A_WORD;ops : 0;oc : $66;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : LOCK;ops : 0;oc : $f0;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : CS;ops : 0;oc : $2e;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : DS;ops : 0;oc : $3e;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : ES;ops : 0;oc : $26;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : FS;ops : 0;oc : $64;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : GS;ops : 0;oc : $65;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : SS;ops : 0;oc : $36;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : REP;ops : 0;oc : $f3;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : REPE;ops : 0;oc : $f3;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : REPNE;ops : 0;oc : $f2;eb : None;m : NoModrm;o1 : 0;o2 : 0;o3 : 0),
(i : A_NONE));
constructor tbytebuffer.init;
begin
new(data);
data^.next:=nil;
last:=data;
nextpos:=1;
size:=0;
end;
destructor tbytebuffer.done;
begin
while assigned(data) do
begin
last:=data^.next;
dispose(data);
data:=last;
end;
end;
procedure tbytebuffer.setdata(d : pbyte;bytes : longint);
var
hbytes : longint;
hp : pbytebufferrec;
begin
inc(size,bytes);
while bytes>0 do
begin
hbytes:=min(bytes,bytebufsize-nextpos+1);
move(d^,last^.buf[nextpos],hbytes);
inc(nextpos,hbytes);
dec(bytes,hbytes);
if nextpos>bytebufsize then
begin
new(hp);
hp^.next:=nil;
last^.next:=hp;
last:=hp;
nextpos:=1;
end;
end;
end;
procedure tbytebuffer.writedata(var f : file);
var
hp : pbytebufferrec;
begin
hp:=data;
while hp<>last do
begin
blockwrite(f,hp^.buf[1],bytebufsize);
hp:=hp^.next
end;
if nextpos>1 then
blockwrite(f,hp^.buf[1],nextpos-1);
end;
procedure tassembler.insertl(p : pasmsym);
procedure insert(var at : pasmsym);
var
i : longint;
begin
if at=nil then
at:=p
else
begin
i:=strcomp(at^.name,p^.name);
if i>0 then
insert(at^.left)
else if i<0 then
insert(at^.right)
else
_asm_error(dupid,aktrec^.linenr);
end;
end;
begin
insert(syms);
end;
procedure tassembler.reloc_sym(name : pchar;seg : tsegment);
var
p : preloc;
_as : pasmsym;
begin
new(p);
p^.codefrag:=last;
p^.seg:=seg;
p^.addr:=bufp;
_as:=searchl(name);
p^.next:=_as^.relocs;
_as^.relocs:=p;
end;
function tassembler.searchl(s : pchar) : pasmsym;
function search(var at : pasmsym) : pasmsym;
var
p : pasmsym;
i : longint;
begin
if at=nil then
begin
new(p);
p^.name:=strnew(s);
p^.left:=nil;
p^.right:=nil;
p^.relocs:=nil;
p^.seg:=SEG_UNKNOWN;
p^.addr:=0;
p^.codefrag:=nil;
p^.is_global:=false;
at:=p;
search:=p;
end
else
begin
i:=strcomp(at^.name,s);
if i>0 then
search:=search(at^.left)
else if i<0 then
search:=search(at^.right)
else
search:=at;
end;
end;
begin
searchl:=search(syms);
end;
constructor tassembler.init;
begin
syms:=nil;
new(wurzel);
last:=wurzel;
wurzel^.next:=nil;
wurzel^.addr:=0;
new(buffer);
bufp:=0;
current_seg:=SEG_TEXT;
binary.init;
dataseg.init;
textseg.init;
end;
procedure tassembler.assembl(instruc : tasmop;opsize : topsize;p_ : pchar;asmrec : pasmrec);
var
p : pchar;
function op(var ref : treferenz) : longint;
var
l : longint;
_op : longint;
function getnumber : longint;
var
s : string;
i : longint;
w : word;
begin
s:='';
repeat
s:=s+p^;
p:=p+1;
until not((p^>='0') and (p^<='9'));
val(s,i,w);
if w<>0 then
_asm_error(asmerror,aktrec^.linenr);
getnumber:=i;
end;
function getregister : tregister;
var
r : tregister;
is_32 : boolean;
begin
if p^<>'%' then
_asm_error(asmerror,aktrec^.linenr);
p:=p+1;
if p^='e' then
begin
is_32:=true;
p:=p+1;
end;
case p^ of
'a' : begin
p:=p+1;
case p^ of
'x' : r:=R_AX;
'l' : r:=R_AL;
else _asm_error(asmerror,aktrec^.linenr);
end;
p:=p+1;
end;
'b' : begin
p:=p+1;
case p^ of
'x' : r:=R_BX;
'l' : r:=R_BL;
'p' : r:=R_BP;
else _asm_error(asmerror,aktrec^.linenr);
end;
p:=p+1;
end;
'c' : begin
p:=p+1;
case p^ of
'x' : r:=R_CX;
'l' : r:=R_CL;
else _asm_error(asmerror,aktrec^.linenr);
end;
p:=p+1;
end;
'd' : begin
p:=p+1;
case p^ of
'x' : r:=R_DX;
'l' : r:=R_DL;
'i' : r:=R_DI;
else _asm_error(asmerror,aktrec^.linenr);
end;
p:=p+1;
end;
's' : begin
p:=p+1;
case p^ of
'i' : r:=R_SI;
'p' : r:=R_SP;
else _asm_error(asmerror,aktrec^.linenr);
end;
p:=p+1;
end;
else _asm_error(asmerror,aktrec^.linenr);
end;
if is_32 then
r:=tregister(byte(r)-byte(R_EDI));
getregister:=r;
end;
function readsymbol : pchar;
var
name : pchar;
begin
l:=0;
while true do
case (p+l)^ of
'0'..'9','a'..'z','A'..'Z',
'_','@','$' : inc(l);
else break;
end;
getmem(name,l+1);
strlcopy(name,p,l);
p:=p+l;
readsymbol:=name;
end;
begin
if p^='$' then
begin
ref.symbol:=nil;
ref.offset:=0;
p:=p+1;
if (p^>='0') and (p^<='9') then
begin
ref.offset:=getnumber;
if ref.offset=1 then
_op:=Imm1 or Imm8S or Imm16 or Imm32
else if (ref.offset>=-128) and (ref.offset<=127) then
_op:=Imm8S or Imm16 or Imm32
else if (ref.offset>=0) and (ref.offset<=255) then
_op:=Imm8 or Imm16 or Imm32
else if (ref.offset>=-32768) and (ref.offset<=65535) then
_op:=Imm16 or Imm32
else
_op:=Imm32;
end
else
begin
ref.symbol:=_2pstring(readsymbol);
_op:=ImmUnknown;
end;
op:=_op;
exit;
end
else if p^='%' then
begin
ref.base:=getregister;
if ref.base in [R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_EBP,R_ESP] then
_op:=Reg32
else if ref.base in [R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_BP,R_SP] then
_op:=Reg16
else if ref.base in [R_AL,R_BL,R_CL,R_DL] then
_op:=Reg16
else _asm_error(asmerror,aktrec^.linenr);
if ref.base=R_DX then
_op:=_op or InOutPortReg;
if ref.base=R_CL then
_op:=_op or ShiftCount;
if (ref.base=R_AL) or (ref.base=R_AX) or (ref.base=R_EAX) then
_op:=_op or Acc;
op:=_op;
exit;
end
else
begin
_op:=Disp32;
ref.base:=R_NO;
ref.index:=R_NO;
ref.offset:=0;
ref.scalefactor:=1;
ref.symbol:=nil;
if ((upcase(p^)>='A') and (upcase(p^)<='Z'))
or (p^='_') then
ref.symbol:=_2pstring(readsymbol);
if ((p^>='0') and (p^<='9')) or
(p^='+') or (p^='-') then
begin
if p^='-' then
begin
p:=p+1;
ref.offset:=-getnumber;
end
else
begin
if p^='+' then
p:=p+1;
ref.offset:=getnumber;
end;
end;
if (p^='(') then
begin
p:=p+1;
if p^='%' then
ref.base:=getregister;
if p^=',' then
begin
p:=p+1;
if p^='%' then
ref.index:=getregister;
if p^=',' then
begin
p:=p+1;
case p^ of
'1' : ref.scalefactor:=1;
'2' : ref.scalefactor:=2;
'4' : ref.scalefactor:=4;
'8' : ref.scalefactor:=8;
')' : ;
else _asm_error(asmerror,aktrec^.linenr);
end;
end;
end;
if p^<>')' then
_asm_error(asmerror,aktrec^.linenr);
end;
end;
op:=_op;
end;
procedure putconst32(const r : treferenz);
var
l : longint;
begin
l:=r.offset;
if assigned(r.symbol) then
reloc_sym(_2pchar(r.symbol),current_seg);
_2pstring(pchar(r.symbol));
concat(4,l);
end;
procedure putconst16(const r : treferenz);
var
l : longint;
begin
l:=r.offset;
if assigned(r.symbol) then
_asm_error(asmerror,aktrec^.linenr);
concat(2,l);
end;
procedure putconst8(const r : treferenz);
var
l : longint;
begin
l:=r.offset;
if assigned(r.symbol) then
_asm_error(asmerror,aktrec^.linenr);
concat(1,l);
end;
procedure gen_modrm(r1,r2 : tregister;b : byte;var r : treferenz);
var
modrm,sib : byte;
_8bit : boolean;
begin
if r1<>R_NO then
modrm:=(byte(r1)-byte(R_EAX)) shl 3
else
modrm:=b shl 3;
if r2<>R_NO then
begin
modrm:=modrm or $c0 or (byte(r2)-byte(R_EAX));
concat(1,modrm);
end
else
begin
_8bit:=false;
if assigned(r.symbol) then
modrm:=modrm or $80
else
if r.offset<>0 then
begin
if (r.offset>=-128) and (r.offset<=127) then
begin
_8bit:=true;
modrm:=modrm or $40;
end
else
modrm:=modrm or $80
end;
if (r.index<>R_NO) or (r.base=R_ESP) then
begin
{ !!!! Noch nicht korrekt }
modrm:=modrm or 4;
case r.scalefactor of
1 : sib:=$0;
2 : sib:=$40;
4 : sib:=$80;
8 : sib:=$c0;
else _asm_error(asmerror,aktrec^.linenr);
end;
sib:=sib or ((byte(r.index)-byte(R_EAX)) shl 3);
sib:=sib or (byte(r.base)-byte(R_EAX));
concat(1,modrm);
concat(1,sib);
end
else
begin
modrm:=modrm or (byte(r.base)-longint(R_EAX));
concat(1,modrm);
end;
if assigned(r.symbol) or (r.offset<>0) then
begin
if assigned(r.symbol) then
reloc_sym(_2pchar(r.symbol),current_seg);
_2pstring(pchar(r.symbol));
if _8bit then
concat(1,r.offset)
else
concat(4,r.offset);
end;
end;
end;
var
i,ops : integer;
r1,r2,r3 : treferenz;
t1,t2,t3 : longint;
{ Hilfswerte }
b,shortformbyte : byte;
w : word;
l : longint;
hlabel : pasmsym;
{ true, wenn die Anweisung verwendet werden soll }
fits : boolean;
{ true, wenn op1 und op2 vertauscht werden }
do_swap : boolean;
begin
aktrec:=asmrec;
p:=p_;
r1.symbol:=nil;
r2.symbol:=nil;
r3.symbol:=nil;
t1:=Unknown;
t2:=Unknown;
t3:=Unknown;
if (p=nil) or (p^=#0) then
ops:=0
else
begin
ops:=1;
t1:=op(r1);
if p^=',' then
begin
p:=p+1;
inc(ops);
t2:=op(r2);
if p^=',' then
begin
p:=p+1;
inc(ops);
t3:=op(r3);
end;
end;
if p^<>#0 then
_asm_error(asmerror,aktrec^.linenr);
end;
if ins_cache[instruc]<>-1 then
i:=ins_cache[instruc]
else i:=0;
{ handle extra instructions }
case instruc of
A_LONG : begin
{ if ops<>1 then
_asm_error(asmerror,aktrec^.linenr);
l:=getnumber;
concat(4,l); }
end;
end;
fits:=false;
while not(fits) do
begin
{ wenn der Befehl das erstemal auftaucht, dann
Cache setzen }
if (it[i].i=instruc) and (ins_cache[instruc]=-1) then
ins_cache[instruc]:=i;
if (it[i].i=instruc) and (ops=it[i].ops) then
begin
do_swap:=false;
{ first fit }
case ops of
0 : fits:=true;
1 : if (t1 and it[i].o1)<>0 then
fits:=true;
2 : if ((t1 and it[i].o1)<>0) and
((t2 and it[i].o2)<>0) then
fits:=true
{ erlaubt zu Tauschen ? }
else if ((it[i].m and D)<>0) and
((t1 and it[i].o2)<>0) and
((t2 and it[i].o1)<>0) then
begin
do_swap:=true;
fits:=true;
end;
3 : if ((t1 and it[i].o1)<>0) and
((t2 and it[i].o2)<>0) and
((t3 and it[i].o3)<>0) then
fits:=true;
end;
if fits then
begin
if do_swap then
shortformbyte:=2
else
shortformbyte:=0;
{ Befehlsvorgabe wird als extra Anweisung behandelt
ausgegeben }
{ ???? Hier müsste eine Adressvorgabe ausgeknobelt werden }
{ Operandengröße ausgeben }
{ und gegebenenfalls Opcodemod ändern }
case opsize of
S_W : begin
if (it[i].m and _W)<>0 then
begin
b:=$66;
concat(1,b);
inc(shortformbyte);
end
else if (it[i].m and ShortForm)<>0 then
begin
b:=$66;
concat(1,b);
end
else if (it[i].m and ShortFormW)<>0 then
begin
b:=$66;
concat(1,b);
inc(shortformbyte,8);
end;
end;
S_L : begin
if (it[i].m and _W)<>0 then
inc(shortformbyte)
else if (it[i].m and ShortFormW)<>0 then
inc(shortformbyte,8);
end;
end;
{ ???? Segmentvorgabe ausgeben }
{ Vorsicht mit movzxwl etc da Opvorgabe in Code }
{ Jump }
if ((it[i].m and Jump)<>0) or
((it[i].m and JumpByte)<>0) then
begin
if assigned(r1.symbol) then
begin
hlabel:=searchl(_2pchar(r1.symbol));
_2pstring(pchar(r1.symbol));
end
else
hlabel:=nil;
concatjmp(it[i].oc,hlabel,r1.offset);
break; { OK }
end;
{ ShortForm und ShortFormW}
if ((it[i].m and ShortForm)<>0) or
((it[i].m and ShortFormW)<>0) then
begin
if (t1 and Reg16)<>0 then
begin
if opsize<>S_W then
_asm_error(asmerror,aktrec^.linenr);
shortformbyte:=shortformbyte+byte(r1.base)-byte(R_AX);
end
else if (t1 and Reg32)<>0 then
begin
if opsize<>S_L then
_asm_error(asmerror,aktrec^.linenr);
shortformbyte:=shortformbyte+byte(r1.base)-byte(R_EAX);
end
else if ((t1 and Reg8)<>0) and ((it[i].m and ShortFormW)<>0) then
begin
if opsize<>S_B then
_asm_error(asmerror,aktrec^.linenr);
shortformbyte:=shortformbyte+byte(r1.base)-byte(R_AL);
end
else _asm_error(asmerror,aktrec^.linenr);
end;
{ Opcode ausgeben }
{ dabei Änderungen des Opcodes beachten }
if (it[i].oc<=255) then
begin
b:=it[i].oc+shortformbyte;
concat(1,b);
end
else
begin
if (it[i].oc>65535) then
begin
b:=(it[i].oc shr 16) and $ff;
concat(1,b);
end;
w:=it[i].oc and $ffff;
b:=hi(w);
concat(1,b);
b:=lo(w)+shortformbyte;
concat(1,b);
end;
if (it[i].m and Modrm)<>0 then
begin
if do_swap then
begin
r3:=r1;
t3:=t1;
r1:=r2;
t1:=t2;
r2:=r3;
t2:=t3;
end;
{ Register überprüfen und auf 32-Bit umrechnen }
if (t1 and Reg)<>0 then
begin
if (t1 and Reg32)<>0 then
begin
if opsize<>S_L then
_asm_error(asmerror,aktrec^.linenr);
end
else if (t1 and Reg8)<>0 then
begin
r1.base:=tregister(byte(r1.base)-byte(R_AL)+1);
if opsize<>S_B then
_asm_error(asmerror,aktrec^.linenr);
end
else if (t1 and Reg16)<>0 then
begin
r1.base:=tregister(byte(r1.base)-byte(R_AX)+1);
if opsize<>S_W then
_asm_error(asmerror,aktrec^.linenr);
end;
end;
if (t2 and Reg)<>0 then
begin
if (t2 and Reg32)<>0 then
begin
if opsize<>S_L then
_asm_error(asmerror,aktrec^.linenr);
end
else if (t2 and Reg8)<>0 then
begin
r2.base:=tregister(byte(r2.base)-byte(R_AL)+1);
if opsize<>S_B then
_asm_error(asmerror,aktrec^.linenr);
end
else if (t2 and Reg16)<>0 then
begin
r1.base:=tregister(byte(r2.base)-byte(R_AX)+1);
if opsize<>S_W then
_asm_error(asmerror,aktrec^.linenr);
end;
end;
{ Memoryreferenzregister überprüfen }
if (t1 and Mem)<>0 then
begin
if (not(r1.base in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,
R_ESI,R_EDI])) or (not(r1.index in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,
R_ESI,R_EDI])) then
_asm_error(asmerror,aktrec^.linenr);
end;
if (t2 and Mem)<>0 then
begin
if (not(r2.base in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,
R_ESI,R_EDI])) or (not(r2.index in [R_NO,R_EAX,R_EBX,R_ECX,R_EDX,R_ESP,R_EBP,
R_ESI,R_EDI])) then
_asm_error(asmerror,aktrec^.linenr);
end;
{ Register in ModRm wird nicht verwendet }
if (it[i].eb<>None) then
begin
case it[i].ops of
1 : begin
if (t1 and Mem)<>0 then
gen_modrm(R_NO,R_NO,it[i].eb,r1)
else if (t1 and Reg)<>0 then
gen_modrm(R_NO,r1.base,it[i].eb,r1)
else _asm_error(asmerror,aktrec^.linenr);
end;
2 : begin
if (t2 and Mem)<>0 then
gen_modrm(R_NO,R_NO,it[i].eb,r2)
else if (t2 and Reg)<>0 then
gen_modrm(R_NO,r2.base,it[i].eb,r2)
else _asm_error(asmerror,aktrec^.linenr);
end;
else _asm_error(asmerror,aktrec^.linenr);
end;
end
else
begin
if (t2 and Mem)<>0 then
begin
if (t1 and Reg)<>0 then
gen_modrm(r1.base,R_NO,0,r2)
else _asm_error(asmerror,aktrec^.linenr);
end
else if (t2 and Reg)<>0 then
begin
if (t1 and Reg)<>0 then
gen_modrm(r2.base,r1.base,0,r1)
else _asm_error(asmerror,aktrec^.linenr);
end
else _asm_error(asmerror,aktrec^.linenr);
end;
end;
if (it[i].o1 and Imm)<>0 then
begin
if assigned(r1.symbol) then
begin
reloc_sym(_2pchar(r1.symbol),
current_seg);
_2pstring(pchar(r1.symbol));
end;
case (it[i].o1 and t1 and Imm) of
Imm8S,Imm8 : concat(1,r1.offset);
Imm16 : concat(2,r1.offset);
Imm32 : concat(4,r1.offset);
else _asm_error(asmerror,aktrec^.linenr);
end;
end;
end;
end;
if it[i].i=A_NONE then
begin
_asm_error(asmerror,aktrec^.linenr);
break;
end;
inc(i);
end;
if assigned(r1.symbol) then
stringdispose(r1.symbol);
if assigned(r2.symbol) then
stringdispose(r2.symbol);
if assigned(r3.symbol) then
stringdispose(r3.symbol);
end;
procedure tassembler.concat(s : byte;var data);
begin
if (bufp+s)>=bufsize then
_asm_error(asmerror,aktrec^.linenr);
move(data,buffer^[bufp],s);
inc(bufp,s);
end;
procedure tassembler.concatjmp(jmpb : byte;_label : pasmsym;extra : longint);
var
p : pminstruc;
begin
p:=last;
p^.size:=bufp+6;
getmem(p^.data,p^.size);
move(buffer^,p^.data^,bufp);
p^.jmpb:=jmpb;
p^._label:=_label;
p^.extra:=extra;
new(p^.next);
p^.next^.addr:=p^.addr+p^.size;
last:=p^.next;
last^.next:=nil;
end;
procedure tassembler.do_asm(p : pchar);
procedure skip_space;
begin
while (p^=' ') or (p^=#9) or (p^=#10) or (p^=#13) do
p:=p+1;
end;
function readsymbol : string;
var
s : string;
begin
s:='';
while true do
case p^ of
'0'..'9','a'..'z','A'..'Z',
'_','@','$' :
begin
s:=s+p^;
p:=p+1;
end;
else break;
end;
readsymbol:=s;
end;
var
hs : string;
hp : pasmsym;
begin
skip_space;
while true do
begin
case p^ of
'/' : begin
if (p+1)^='/' then
exit
else
_asm_error(asmerror,aktrec^.linenr);
end;
'.' : begin
p:=p+1;
hs:=readsymbol;
if hs='text' then
current_seg:=SEG_TEXT
else if hs='data' then
current_seg:=SEG_DATA
else if hs='globl' then
begin
skip_space;
hs:=readsymbol;
searchl(_2pchar(@hs))^.is_global:=true;
end
else if hs='align' then
begin
{ !!! wird ignoriert }
end
else _asm_error(asmerror,aktrec^.linenr);
exit;
end;
else
begin
hs:=readsymbol;
if p^=':' then
begin
hp:=searchl(_2pchar(@hs));
hp^.seg:=current_seg;
if current_seg=SEG_TEXT then
begin
hp^.codefrag:=last;
hp^.addr:=bufp;
end
else
begin
hp^.addr:=dataseg.size;
end;
end
else
_asm_error(asmerror,aktrec^.linenr);
exit;
end;
end;
end;
end;
procedure tassembler.write_file(var ppufile : file);
procedure write_sym(p : pasmsym);
var
b : byte;
w : word;
l : longint;
hp : preloc;
begin
if not(assigned(p)) then
exit;
b:=102;
binary.setdata(@b,1);
binary.setdata(pbyte(@p^.seg),1);
binary.setdata(pbyte(@p^.is_global),1);
w:=strlen(p^.name);
binary.setdata(pbyte(@w),2);
binary.setdata(pbyte(p^.name),w);
l:=p^.addr+p^.codefrag^.addr;
binary.setdata(pbyte(@l),4);
hp:=p^.relocs;
w:=0;
while assigned(hp) do
begin
inc(w);
hp:=hp^.next;
end;
binary.setdata(pbyte(@w),2);
hp:=p^.relocs;
while assigned(hp) do
begin
binary.setdata(pbyte(@hp^.seg),1);
l:=hp^.codefrag^.addr+hp^.addr;
binary.setdata(pbyte(@l),4);
hp:=hp^.next;
end;
write_sym(p^.left);
write_sym(p^.right);
end;
var
hp : pminstruc;
packedbytes,realpos : longint;
_packed : boolean;
b : byte;
l :longint;
begin
{ letzten Teil des Codes schreiben }
last^.size:=bufp;
getmem(last^.data,last^.size);
move(buffer^,last^.data^,bufp);
{ Größe von Sprüngen berechnen }
repeat
hp:=wurzel;
packedbytes:=0;
_packed:=false;
while assigned(hp^.next) do
begin
dec(hp^.addr,packedbytes);
realpos:=hp^.extra;
if assigned(hp^._label) then
inc(realpos,hp^._label^.addr+hp^._label^.codefrag^.addr)
else
inc(realpos,hp^.addr+hp^.size-6);
if (hp^.jmpb<>0) and
((realpos-(hp^.addr+hp^.size-6))<127) and
((realpos-(hp^.addr+hp^.size-6))>-129) then
begin
pbyte(pchar(hp^.data)+hp^.size-6)^:=hp^.jmpb;
hp^.jmpb:=0;
inc(packedbytes,4);
dec(hp^.size,4);
_packed:=true;
end;
hp:=wurzel^.next;
end;
{ falls einfache Optimierungen, dann Multipass }
until not(cs_optimize in aktswitches) or not(_packed);
{ nun sind alle Adressen festgelegt,
also können die Sprünge berechnet werden }
hp:=wurzel;
while assigned(hp^.next) do
begin
realpos:=hp^.extra;
if assigned(hp^._label) then
inc(realpos,hp^._label^.addr+hp^._label^.codefrag^.addr)
else
inc(realpos,hp^.addr+hp^.size-2);
if hp^.jmpb=0 then
begin
pbyte(pchar(hp^.data)+hp^.size-1)^:=
(realpos-(hp^.addr+hp^.size-2));
end
else
begin
pbyte(pchar(hp^.data)+hp^.size-6)^:=$0f;
pbyte(pchar(hp^.data)+hp^.size-5)^:=$10+hp^.jmpb;
plongint(pchar(hp^.data)+hp^.size-4)^:=
(realpos-(hp^.addr+hp^.size-6));
end;
hp:=hp^.next;
end;
{ Textsegment zusammenbauen }
hp:=wurzel;
while assigned(hp) do
begin
textseg.setdata(pbyte(hp^.data),hp^.size);
hp:=hp^.next;
end;
{ Textsegmentgröße schreiben }
l:=textseg.size;
binary.setdata(pbyte(@l),4);
{ Datensegment... }
l:=dataseg.size;
binary.setdata(pbyte(@l),4);
{ BSS }
binary.setdata(pbyte(@bsssize),4);
{ Symbol- und Reloceinträge erzeugen }
write_sym(syms);
binary.writedata(ppufile);
textseg.writedata(ppufile);
dataseg.writedata(ppufile);
end;
destructor tassembler.done;
begin
end;
procedure writeofile(const filename : string);
var
p : pasmrec;
lastline : longint;
s,hs : string;
infile : pinputstack;
hpp : pchar;
ofile : file;
_assembler : tassembler;
begin
_assembler.init;
lastline:=-1;
infile:=nil;
p:=mainasmlist.wurzel;
while assigned(p) do
begin
{ generate debugger line informations }
if (p^.linenr<>lastline) and (p^.linenr<>0) then
begin
if writeasmfile then
begin
{!!!! writestring(#10#9'// Zeile #'+tostr(p^.linenr)); }
end;
if cs_debuginfo in aktswitches then
begin
{!!!!! writestring(#10#9'.stabd'#9'68,0,'+tostr(p^.linenr)); }
end;
lastline:=p^.linenr;
end;
if (p^.infile<>infile) and (cs_debuginfo in aktswitches) then
begin
if not(assigned(infile)) then
{!!!! writestring(#10'.stabs "'+p^.infile^.filename^+'",100,0,0,Ltext0') }
else
{!!!! writestring(#10'.stabs "'+p^.infile^.filename^+'",132,0,0,Ltext0'); }
infile:=p^.infile;
end;
{ nun Anweisung schreiben }
if p^.instruc=A_NONE then
begin
p:=p^.next;
continue;
end;
if p^.instruc=A_LABEL then
begin
{!!!! writestring(#10+tolabel(p^.l)+':') }
end
else if p^.disposing=D_LABEL then
{!!!!! writestring(#10#9+op_2_asm[p^.instruc]+#9+tolabel(p^.l)) }
else
begin
hpp:=p^.t;
if assigned(hpp) then
begin
if p^.instruc=DIRECT then
_assembler.do_asm(hpp)
else
_assembler.assembl(p^.instruc,p^.opsize,hpp,p);
end
else ;
{!!!! writestring(#10#9+op_2_asm[p^.instruc]+postf_2_asm[p^.opsize]+#9); }
end;
p:=p^.next;
end;
{ now write O file }
assign(ofile,filename);
{$I-}
rewrite(ofile,1);
{$I+}
_assembler.write_file(ofile);
close(ofile);
_assembler.done;
end;
procedure writemainasmlist(const filename : string);
var
p : pasmrec;
lastline : longint;
s,hs : string;
infile : pinputstack;
hpp : pchar;
begin
assign(asmfile,filename);
{$I-}
rewrite(asmfile,1);
{$I+}
if ioresult<>0 then
fatalerror(cannot_open_asmfile);
lastline:=-1;
infile:=nil;
{ Buffer allozieren }
asmbuffersize:=maxavail;
if asmbuffersize>asmbufsize then
asmbuffersize:=asmbufsize;
getmem(asmbuffer,asmbuffersize);
asmbufferpos:=1;
p:=mainasmlist.wurzel;
{$ifdef tp}
while p<>nil do
begin
if use_big then
begin
symbolstream.seek(longint(p));
symbolstream.read(hasmrec^,sizeof(tasmrec));
p:=hasmrec;
end;
{$else}
while assigned(p) do
begin
{$endif}
{ Debuggerinformationen }
if (p^.linenr<>lastline) and (p^.linenr<>0) then
begin
if writeasmfile then
begin
writestring(#10#9'// Zeile #'+tostr(p^.linenr));
inc(asmlines,2);
end;
if cs_debuginfo in aktswitches then
begin
writestring(#10#9'.stabd'#9'68,0,'+tostr(p^.linenr));
inc(asmlines);
end;
lastline:=p^.linenr;
end;
if (p^.infile<>infile) and (cs_debuginfo in aktswitches) then
begin
if not(assigned(infile)) then
writestring(#10'.stabs "'+p^.infile^.filename^+'",100,0,0,Ltext0')
else
writestring(#10'.stabs "'+p^.infile^.filename^+'",132,0,0,Ltext0');
inc(asmlines);
infile:=p^.infile;
end;
{ nun Anweisung schreiben }
if p^.instruc=A_NONE then
begin
p:=p^.next;
continue;
end;
if p^.instruc=A_LABEL then
begin
writestring(#10+tolabel(p^.l)+':')
end
else if p^.disposing=D_LABEL then writestring(#10#9+op_2_asm[p^.instruc]+#9+tolabel(p^.l))
else
begin
hpp:=p^.t;
{$ifdef tp}
if use_big then
begin
symbolstream.seek(longint(hpp));
hpp:=symbolstream.strread;
end;
{$endif}
if hpp<>nil then
begin
if p^.instruc=DIRECT then
begin
writestring(#10);
writechararray(hpp);
end
else if (p^.instruc=PUSH) and (p^.opsize=S_W) and (hpp[0]='$') then
begin
{ Bug im GNU-Assembler umgehen: }
writestring(#10#9'.byte 0x66'#10#9'.byte 0x68');
writestring(#10#9'.word ');
writechararray(hpp+1);
end
else
begin
writestring(#10#9+op_2_asm[p^.instruc]+postf_2_asm[p^.opsize]+#9);
writechararray(hpp);
end;
{$ifdef tp}
if use_big then
freemem(hpp,strlen(hpp)+1);
{$endif}
end
else writestring(#10#9+op_2_asm[p^.instruc]+postf_2_asm[p^.opsize]+#9);
end;
inc(asmlines);
p:=p^.next;
end;
if target_info.target=target_LINUX then
writestring(#10)
else
writestring(#13#10#26);
blockwrite(asmfile,asmbuffer^,asmbufferpos-1);
freemem(asmbuffer,asmbuffersize);
close(asmfile);
end;
end.