Browse Source

+ Support classes for creating unwind bytecode for Win64.

git-svn-id: trunk@19071 -
sergei 14 years ago
parent
commit
1365467b0d

+ 1 - 0
.gitattributes

@@ -664,6 +664,7 @@ compiler/x86_64/r8664std.inc svneol=native#text/plain
 compiler/x86_64/rax64att.pas svneol=native#text/plain
 compiler/x86_64/rax64int.pas svneol=native#text/plain
 compiler/x86_64/rgcpu.pas svneol=native#text/plain
+compiler/x86_64/win64unw.pas svneol=native#text/plain
 compiler/x86_64/x8664ats.inc svneol=native#text/plain
 compiler/x86_64/x8664att.inc svneol=native#text/plain
 compiler/x86_64/x8664int.inc svneol=native#text/plain

+ 158 - 8
compiler/aasmtai.pas

@@ -86,7 +86,9 @@ interface
           { used to mark assembler blocks and inlined functions }
           ait_marker,
           { used to describe a new location of a variable }
-          ait_varloc
+          ait_varloc,
+          { SEH directives used in ARM,MIPS and x86_64 COFF targets }
+          ait_seh_directive
           );
 
         taiconst_type = (
@@ -173,7 +175,8 @@ interface
           'regalloc',
           'tempalloc',
           'marker',
-          'varloc'
+          'varloc',
+          'seh_directive'
           );
 
     type
@@ -237,7 +240,7 @@ interface
       SkipInstr = [ait_comment, ait_symbol,ait_section
                    ,ait_stab, ait_function_name, ait_force_line
                    ,ait_regalloc, ait_tempalloc, ait_symbol_end, ait_directive
-                   ,ait_varloc];
+                   ,ait_varloc,ait_seh_directive];
 
       { ait_* types which do not have line information (and hence which are of type
         tai, otherwise, they are of type tailineinfo }
@@ -250,7 +253,8 @@ interface
                      ait_thumb_func,
 {$endif arm}
                      ait_real_32bit,ait_real_64bit,ait_real_80bit,ait_comp_64bit,ait_real_128bit,
-                     ait_symbol
+                     ait_symbol,
+                     ait_seh_directive
                     ];
 
 
@@ -276,6 +280,15 @@ interface
         asd_weak_definition
       );
 
+      TAsmSehDirective=(
+          ash_proc,ash_endproc,
+          ash_endprologue,ash_handler,ash_handlerdata,
+          ash_eh,ash_32,ash_no32,
+          ash_setframe,ash_stackalloc,ash_pushreg,
+          ash_savereg,ash_savexmm,ash_pushframe
+        );
+
+
     const
       regallocstr : array[tregalloctype] of string[10]=('allocated','released','sync','resized');
       tempallocstr : array[boolean] of string[10]=('released','allocated');
@@ -285,6 +298,13 @@ interface
         'extern','nasm_import', 'tc', 'reference',
         'no_dead_strip','weak_reference','lazy_reference','weak_definition'
       );
+      sehdirectivestr : array[TAsmSehDirective] of string[15]=(
+        'seh_proc','seh_endproc',
+        'seh_endprologue','seh_handler','seh_handlerdata',
+        'seh_eh','seh_32','seh_no32',
+        'seh_setframe','seh_stackalloc','seh_pushreg',
+        'seh_savereg','seh_savexmm','seh_pushframe'
+      );
 
     type
        { abstract assembler item }
@@ -399,7 +419,7 @@ interface
          private
           { this constructor is made private on purpose }
           { because sections should be created via new_section() }
-          constructor Create(Asectype:TAsmSectiontype;Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
+          constructor Create(Asectype:TAsmSectiontype;const Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
        end;
 
 
@@ -661,6 +681,31 @@ interface
            procedure derefimpl;override;
         end;
 
+        TSehDirectiveDatatype=(sd_none,sd_string,sd_reg,sd_offset,sd_regoffset);
+
+        TSehDirectiveData=record
+        case typ: TSehDirectiveDatatype of
+          sd_none: ();
+          sd_string: (name:pshortstring);
+          sd_reg,sd_offset,sd_regoffset: (reg:TRegister;offset:dword);
+        end;
+
+        tai_seh_directive = class(tai)
+          kind: TAsmSehDirective;
+          data: TSehDirectiveData;
+          constructor create(_kind:TAsmSehDirective);
+          constructor create_name(_kind:TAsmSehDirective;const _name: string);
+          constructor create_reg(_kind:TAsmSehDirective;r:TRegister);
+          constructor create_offset(_kind:TAsmSehDirective;ofs:dword);
+          constructor create_reg_offset(_kind:TAsmSehDirective;r:TRegister;ofs:dword);
+          constructor ppuload(t:taitype;ppufile:tcompilerppufile);override;
+          destructor destroy;override;
+          procedure ppuwrite(ppufile:tcompilerppufile);override;
+          procedure generate_code(objdata:TObjData);virtual;
+          property datatype: TSehDirectiveDatatype read data.typ;
+        end;
+        tai_seh_directive_class=class of tai_seh_directive;
+
     var
       { array with all class types for tais }
       aiclass : taiclassarray;
@@ -668,12 +713,13 @@ interface
       { target specific tais, possibly overwritten in target specific aasmcpu }
       cai_align : tai_align_class = tai_align_abstract;
       cai_cpu   : tai_cpu_class = tai_cpu_abstract;
+      cai_seh_directive: tai_seh_directive_class = tai_seh_directive;
 
       { hook to notify uses of registers }
       add_reg_instruction_hook : tadd_reg_instruction_proc;
 
     procedure maybe_new_object_file(list:TAsmList);
-    procedure new_section(list:TAsmList;Asectype:TAsmSectiontype;Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
+    procedure new_section(list:TAsmList;Asectype:TAsmSectiontype;const Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
     procedure section_symbol_start(list:TAsmList;const Aname:string;Asymtyp:Tasmsymtype;
                                    Aglobal:boolean;Asectype:TAsmSectiontype;Aalign:byte);
     procedure section_symbol_end(list:TAsmList;const Aname:string);
@@ -705,7 +751,7 @@ implementation
       end;
 
 
-    procedure new_section(list:TAsmList;Asectype:TAsmSectiontype;Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
+    procedure new_section(list:TAsmList;Asectype:TAsmSectiontype;const Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
       begin
         list.concat(tai_section.create(Asectype,Aname,Aalign,Asecorder));
         list.concat(cai_align.create(Aalign));
@@ -893,7 +939,7 @@ implementation
                              TAI_SECTION
  ****************************************************************************}
 
-    constructor tai_section.Create(Asectype:TAsmSectiontype;Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
+    constructor tai_section.Create(Asectype:TAsmSectiontype;const Aname:string;Aalign:byte;Asecorder:TasmSectionorder=secorder_default);
       begin
         inherited Create;
         typ:=ait_section;
@@ -2486,6 +2532,110 @@ implementation
         ppufile.putbyte(fillop);
         ppufile.putbyte(byte(use_op));
       end;
+
+{****************************************************************************
+                              tai_seh_directive
+ ****************************************************************************}
+
+    const
+      datatypemap: array[TAsmSehDirective] of TSehDirectiveDatatype=(
+        sd_string,     { proc }
+        sd_none,       { endproc }
+        sd_none,       { endprologue }
+        sd_none,       { TODO: handler }
+        sd_none,       { handlerdata }
+        sd_none,sd_none,sd_none,  { eh, 32, no32 }
+        sd_regoffset,  { setframe }
+        sd_offset,     { stackalloc }
+        sd_reg,        { pushreg }
+        sd_regoffset,  { savereg }
+        sd_regoffset,  { savexmm }
+        sd_none        { pushframe }
+      );
+
+    constructor tai_seh_directive.create(_kind:TAsmSehDirective);
+      begin
+        inherited Create;
+        typ:=ait_seh_directive;
+        kind:=_kind;
+        data.typ:=datatypemap[_kind];
+      end;
+
+    constructor tai_seh_directive.create_name(_kind:TAsmSehDirective;const _name:string);
+      begin
+        create(_kind);
+        data.name:=stringdup(_name);
+      end;
+
+    constructor tai_seh_directive.create_reg(_kind:TAsmSehDirective;r:TRegister);
+      begin
+        create(_kind);
+        data.reg:=r;
+      end;
+
+    constructor tai_seh_directive.create_offset(_kind:TAsmSehDirective;ofs:dword);
+      begin
+        create(_kind);
+        data.offset:=ofs;
+      end;
+
+    constructor tai_seh_directive.create_reg_offset(_kind:TAsmSehDirective;
+      r:TRegister;ofs:dword);
+      begin
+        create(_kind);
+        data.offset:=ofs;
+        data.reg:=r;
+      end;
+
+    constructor tai_seh_directive.ppuload(t:taitype;ppufile:tcompilerppufile);
+      begin
+        inherited ppuload(t, ppufile);
+        kind:=TAsmSehDirective(ppufile.getbyte);
+        data.typ:=datatypemap[kind];
+        case data.typ of
+          sd_none: ;
+          sd_string:
+            data.name:=stringdup(ppufile.getstring);
+
+          sd_reg,sd_offset,sd_regoffset:
+            begin
+              ppufile.getdata(data.reg,sizeof(TRegister));
+              data.offset:=ppufile.getdword;
+            end;
+        else
+          InternalError(2011091201);
+        end;
+      end;
+
+    destructor tai_seh_directive.destroy;
+      begin
+        if data.typ=sd_string then
+          stringdispose(data.name);
+        inherited destroy;
+      end;
+
+    procedure tai_seh_directive.ppuwrite(ppufile:tcompilerppufile);
+      begin
+        inherited ppuwrite(ppufile);
+        ppufile.putbyte(ord(kind));
+        case data.typ of
+          sd_none: ;
+          sd_string:
+            ppufile.putstring(data.name^);
+          sd_reg,sd_offset,sd_regoffset:
+            begin
+              ppufile.putdata(data.reg,sizeof(TRegister));
+              ppufile.putdword(data.offset);
+            end;
+        else
+          InternalError(2011091202);
+        end;
+      end;
+
+    procedure tai_seh_directive.generate_code(objdata:TObjData);
+      begin
+      end;
+
 begin
   { taitype should fit into a 4 byte set for speed reasons }
   if ord(high(taitype))>31 then

+ 18 - 0
compiler/aggas.pas

@@ -1236,6 +1236,24 @@ implementation
                AsmLn;
              end;
 
+           ait_seh_directive :
+             begin
+               AsmWrite('.'+sehdirectivestr[tai_seh_directive(hp).kind]);
+               case tai_seh_directive(hp).datatype of
+                 sd_none:;
+                 sd_string:
+                   AsmWrite(' '+tai_seh_directive(hp).data.name^);
+                 sd_reg:
+                   AsmWrite(' '+gas_regname(tai_seh_directive(hp).data.reg));
+                 sd_offset:
+                   AsmWrite(' '+tostr(tai_seh_directive(hp).data.offset));
+                 sd_regoffset:
+                   AsmWrite(' '+gas_regname(tai_seh_directive(hp).data.reg)+', '+
+                     tostr(tai_seh_directive(hp).data.offset));
+               end;
+               AsmLn;
+             end;
+
            else
              internalerror(2006012201);
          end;

+ 2 - 0
compiler/assemble.pas

@@ -1393,6 +1393,8 @@ Implementation
              ait_cutobject :
                if SmartAsm then
                 break;
+             ait_seh_directive :
+               tai_seh_directive(hp).generate_code(objdata);
            end;
            hp:=Tai(hp.next);
          end;

+ 1 - 0
compiler/psystem.pas

@@ -619,6 +619,7 @@ implementation
         aiclass[ait_regalloc]:=tai_regalloc;
         aiclass[ait_tempalloc]:=tai_tempalloc;
         aiclass[ait_marker]:=tai_marker;
+        aiclass[ait_seh_directive]:=tai_seh_directive;
       end;
 
 end.

+ 1 - 0
compiler/x86_64/cputarg.pas

@@ -44,6 +44,7 @@ implementation
     {$endif}
     {$ifndef NOTARGETWIN}
       ,t_win
+      ,win64unw
     {$endif}
     {$ifndef NOTARGETSUNOS}
       ,t_sunos

+ 361 - 0
compiler/x86_64/win64unw.pas

@@ -0,0 +1,361 @@
+{
+    Copyright (c) 2011 by Free Pascal development team
+
+    Support for win64 unwind data
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit win64unw;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  cclasses,globtype,aasmbase,aasmdata,aasmtai,cgbase,ogbase;
+
+type
+  TWin64CFI=class
+  private
+    FFrameOffs, FFrameReg: Integer;
+    FFlags: Integer;
+    FCount: Integer;
+    FElements:TLinkedList;
+    FFrameStartSym:TObjSymbol;
+    FPrologueEndPos:aword;
+    FName: pshortstring;
+    procedure AddElement(objdata:TObjData;aCode,aInfo:Integer;aOffs:dword);
+  public
+    constructor create;
+    destructor destroy;override;
+    procedure generate_code(objdata:TObjData);
+    procedure start_frame(objdata:TObjData; const name: string);
+    procedure end_frame(objdata:TObjData);
+    procedure end_prologue(objdata:TObjData);
+    procedure push_reg(objdata:TObjData;reg:tregister);
+    procedure save_reg(objdata:TObjData;reg:tregister;ofs:dword);
+    procedure save_xmm(objdata:TObjData;reg:tregister;ofs:dword);
+    procedure set_frame(objdata:TObjData; reg:tregister;ofs:dword);
+    procedure stack_alloc(objdata:TObjData;ofs:dword);
+  end;
+
+
+implementation
+
+uses
+  cutils,verbose,cpubase;
+
+const
+  UWOP_PUSH_NONVOL     = 0;  { info = register number }
+  UWOP_ALLOC_LARGE     = 1;  { no info, alloc size in next 2 slots }
+  UWOP_ALLOC_SMALL     = 2;  { info = size of allocation / 8 - 1 }
+  UWOP_SET_FPREG       = 3;  { no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 }
+  UWOP_SAVE_NONVOL     = 4;  { info = register number, offset in next slot }
+  UWOP_SAVE_NONVOL_FAR = 5;  { info = register number, offset in next 2 slots }
+  UWOP_SAVE_XMM        = 6;
+  UWOP_SAVE_XMM_FAR    = 7;
+  UWOP_SAVE_XMM128     = 8;  { info = XMM reg number, offset in next slot }
+  UWOP_SAVE_XMM128_FAR = 9;  { info = XMM reg number, offset in next 2 slots }
+  UWOP_PUSH_MACHFRAME  = 10; { info = 0: no error-code, 1: error-code }
+
+  UNW_FLAG_EHANDLER    = $01; { exceptiion handler }
+  UNW_FLAG_UHANDLER    = $02; { termination handler }
+  UNW_FLAG_FHANDLER    = UNW_FLAG_EHANDLER or UNW_FLAG_UHANDLER;
+  UNW_FLAG_CHAININFO   = $04; { mutually exclusive with the above }
+
+
+type
+  tai_seh_directive_x64=class(tai_seh_directive)
+    procedure generate_code(objdata:TObjData);override;
+  end;
+
+  TPrologueElement=class(TLinkedListItem)
+  public
+    opcode: Integer;  { =(info shl 4) or code }
+    ofs: dword;
+    addr: aword;
+  end;
+
+var
+  current_unw: TWin64Cfi;
+
+{ This generally duplicates private aasmcpu.regval() }
+function EncodeReg(r: TRegister): integer;
+begin
+  case r of
+    NR_RAX: result:=0;
+    NR_RCX: result:=1;
+    NR_RDX: result:=2;
+    NR_RBX: result:=3;
+    NR_RSP: result:=4;
+    NR_RBP: result:=5;
+    NR_RSI: result:=6;
+    NR_RDI: result:=7;
+    NR_R8:  result:=8;
+    NR_R9:  result:=9;
+    NR_R10: result:=10;
+    NR_R11: result:=11;
+    NR_R12: result:=12;
+    NR_R13: result:=13;
+    NR_R14: result:=14;
+    NR_R15: result:=15;
+  else
+    InternalError(2011072305);
+  end;
+end;
+
+function EncodeXMM(r: TRegister): integer;
+begin
+  if getregtype(r)=R_MMREGISTER then
+    result:=getsupreg(r)
+  else
+    InternalError(2011072305);
+end;
+
+
+{ TWin64CFI }
+
+constructor TWin64CFI.create;
+begin
+  inherited create;
+  FElements:=TLinkedList.Create;
+end;
+
+destructor TWin64CFI.destroy;
+begin
+  FElements.Free;
+  stringdispose(FName);
+  inherited destroy;
+end;
+
+procedure TWin64CFI.AddElement(objdata:TObjData;aCode,aInfo:Integer;aOffs:dword);
+var
+  el:TPrologueElement;
+begin
+  el:=TPrologueElement.Create;
+  FElements.concat(el);
+  el.opcode:=(aInfo shl 4) or aCode;
+  el.ofs:=aOffs;
+  el.addr:=objdata.CurrObjSec.Size;
+
+  { a single element may occupy 1,2 or 3 word-sized slots }
+  case aCode of
+    UWOP_ALLOC_LARGE:
+      Inc(FCount,2+ord(aInfo<>0));
+
+    UWOP_SAVE_NONVOL_FAR,
+    UWOP_SAVE_XMM128_FAR:
+      Inc(FCount,3);
+
+    UWOP_SAVE_NONVOL,
+    UWOP_SAVE_XMM128:
+      Inc(FCount,2);
+
+  else
+    inc(FCount);
+  end;
+end;
+
+procedure TWin64CFI.generate_code(objdata:TObjData);
+var
+  hp: TPrologueElement;
+  uwcode: array [0..1] of byte;
+  uwdata: array [0..3] of byte;
+  cursec: TObjSection;
+  xdatasym,pdatasym: TObjSymbol;
+  zero: word;
+begin
+{  if FCount=0 then
+     InternalError(2011072308); }
+  if FCount>255 then
+    InternalError(2011072301);
+
+  cursec:=objdata.CurrObjSec;
+  objdata.createsection('.xdata.n_'+lower(FName^),4,[oso_data,oso_load]);
+  xdatasym:=objdata.symboldefine('$unwind$'+FName^,AB_GLOBAL,AT_DATA);
+  uwdata[0]:=(FFlags shl 3) or 1;
+  uwdata[1]:=FPrologueEndPos-FFrameStartSym.offset;
+  uwdata[2]:=FCount;
+  { Offset is multiple of 16, so it is already shifted into correct position }
+  uwdata[3]:=FFrameOffs or FFrameReg;
+  objdata.writebytes(uwdata,4);
+
+  { write elements in reverse order (offset descending) }
+  hp:=TPrologueElement(FElements.Last);
+  while Assigned(hp) do
+    begin
+      uwcode[0]:=hp.addr-FFrameStartSym.address;
+      uwcode[1]:=hp.opcode;
+      objdata.writebytes(uwcode,2);
+      case hp.opcode and $0F of
+    UWOP_PUSH_NONVOL,
+    UWOP_ALLOC_SMALL,
+    UWOP_SET_FPREG,
+    UWOP_PUSH_MACHFRAME: ;  { These have no extra data }
+
+    UWOP_ALLOC_LARGE:
+      if (hp.opcode and $F0)<>0 then
+            objdata.writebytes(hp.ofs,4)
+          else
+            objdata.writebytes(hp.ofs,2);
+
+    UWOP_SAVE_NONVOL_FAR,
+    UWOP_SAVE_XMM128_FAR:
+      objdata.writebytes(hp.ofs,4);
+
+    UWOP_SAVE_NONVOL,
+    UWOP_SAVE_XMM128:
+          objdata.writebytes(hp.ofs,2);
+      else
+        InternalError(2011072302);
+      end;
+
+      hp:=TPrologueElement(hp.Previous);
+    end;
+  { pad with zeros to dword boundary }
+  zero:=0;
+  if odd(FCount) then
+    objdata.writebytes(zero,2);
+  { TODO: handler rva and data should follow if flags specify a handler }
+
+  FElements.Clear;
+
+  objdata.createsection(sec_pdata,FName^);
+  pdatasym:=objdata.symboldefine('$pdata$'+FName^,AB_LOCAL,AT_DATA);
+  objdata.writereloc(0,4,FFrameStartSym,RELOC_RVA);
+  objdata.writereloc(FFrameStartSym.Size,4,FFrameStartSym,RELOC_RVA);
+  objdata.writereloc(0,4,xdatasym,RELOC_RVA);
+  { restore previous state }
+  objdata.SetSection(cursec);
+  { create a dummy relocation, so pdata is not smartlinked away }
+  objdata.writereloc(0,0,pdatasym,RELOC_NONE);
+end;
+
+procedure TWin64CFI.start_frame(objdata:TObjData;const name:string);
+begin
+  if assigned(FName) then
+    internalerror(2011072306);
+  FName:=stringdup(name);
+  FFrameStartSym:=objdata.symbolref(name);
+  FCount:=0;
+  FFrameReg:=0;
+  FFrameOffs:=0;
+  FPrologueEndPos:=0;
+end;
+
+procedure TWin64CFI.end_frame(objdata:TObjData);
+begin
+  if not assigned(FName) then
+    internalerror(2011072307);
+  generate_code(objdata);
+  FFrameStartSym:=nil;
+  stringdispose(FName);
+end;
+
+procedure TWin64CFI.end_prologue(objdata:TObjData);
+begin
+  FPrologueEndPos:=objdata.CurrObjSec.Size;
+end;
+
+procedure TWin64CFI.push_reg(objdata:TObjData;reg:tregister);
+begin
+  AddElement(objdata,UWOP_PUSH_NONVOL,EncodeReg(reg),0);
+end;
+
+procedure TWin64CFI.save_reg(objdata:TObjData;reg:tregister;ofs:dword);
+var
+  info: Integer;
+begin
+  info:=EncodeReg(reg);
+  if ((ofs and 7) = 0) and (ofs<=$ffff*8) then
+    AddElement(objdata,UWOP_SAVE_NONVOL,info,ofs shr 3)
+  else
+    AddElement(objdata,UWOP_SAVE_NONVOL_FAR,info,ofs);
+end;
+
+procedure TWin64CFI.save_xmm(objdata:TObjData;reg:tregister;ofs:dword);
+var
+  info: Integer;
+begin
+  info:=EncodeXMM(reg);
+  if ((ofs and 15)=0) and (ofs<=$ffff*16) then
+    AddElement(objdata,UWOP_SAVE_XMM128, info, ofs shr 4)
+  else
+    AddElement(objdata,UWOP_SAVE_XMM128_FAR, info, ofs);
+end;
+
+procedure TWin64CFI.set_frame(objdata:TObjData;reg:tregister;ofs:dword);
+var
+  info: Integer;
+begin
+  info:=EncodeReg(reg);
+  if FFrameReg<>0 then
+    InternalError(2011072303);
+  if info=0 then                 { frame register cannot be RAX }
+    InternalError(2011072304);
+  if (ofs>240) or ((ofs and 15)<>0) then
+    InternalError(2011072310);
+  FFrameReg:=info;
+  FFrameOffs:=ofs;
+  { !! looks like docs aren't correct and info should be set to register }
+  AddElement(objdata,UWOP_SET_FPREG,0,0);
+end;
+
+procedure TWin64CFI.stack_alloc(objdata:TObjData;ofs:dword);
+begin
+  if ((ofs and 7)=0) and (ofs<=128) then
+    AddElement(objdata,UWOP_ALLOC_SMALL,(ofs-8) shr 3,0)
+  else if ((ofs and 7) = 0) and (ofs<=$ffff * 8) then
+    AddElement(objdata,UWOP_ALLOC_LARGE,0,ofs shr 3)
+  else
+    AddElement(objdata,UWOP_ALLOC_LARGE,1,ofs);
+end;
+
+procedure tai_seh_directive_x64.generate_code(objdata:TObjData);
+begin
+  case kind of
+    ash_proc:
+      current_unw.start_frame(objdata,data.name^);
+    ash_endproc:
+      current_unw.end_frame(objdata);
+    ash_endprologue:
+      current_unw.end_prologue(objdata);
+    ash_handler:     {TBD};
+    ash_handlerdata: {TBD};
+    ash_eh,ash_32,ash_no32: ; { there are not for x86_64 }
+    ash_setframe:
+      current_unw.set_frame(objdata,data.reg,data.offset);
+    ash_stackalloc:
+      current_unw.stack_alloc(objdata,data.offset);
+    ash_pushreg:
+      current_unw.push_reg(objdata,data.reg);
+    ash_savereg:
+      current_unw.save_reg(objdata,data.reg,data.offset);
+    ash_savexmm:
+      current_unw.save_xmm(objdata,data.reg,data.offset);
+    ash_pushframe: {TBD};
+  end;
+end;
+
+
+initialization
+  cai_seh_directive:=tai_seh_directive_x64;
+  current_unw:=TWin64CFI.Create;
+finalization
+  current_unw.Free;
+end.
+