Metropoli BBS
VIEWER: asmgen.pas MODE: TEXT (CP437)
{****************************************************************************

                  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.
[ RETURN TO DIRECTORY ]