Bladeren bron

+ (slightly) patch by Emelyanov Roman to add support of SEH directive in FPC internal assembler with INTEL syntax, resolves #29894

git-svn-id: trunk@38331 -
florian 7 jaren geleden
bovenliggende
commit
3b779278e2
3 gewijzigde bestanden met toevoegingen van 214 en 29 verwijderingen
  1. 7 3
      compiler/aasmtai.pas
  2. 42 2
      compiler/x86/rax86int.pas
  3. 165 24
      compiler/x86_64/rax64int.pas

+ 7 - 3
compiler/aasmtai.pas

@@ -362,7 +362,8 @@ interface
           ash_endprologue,ash_handler,ash_handlerdata,
           ash_eh,ash_32,ash_no32,
           ash_setframe,ash_stackalloc,ash_pushreg,
-          ash_savereg,ash_savexmm,ash_pushframe
+          ash_savereg,ash_savexmm,ash_pushframe,
+          ash_pushnv,ash_savenv
         );
 
       TSymbolPairKind = (spk_set, spk_thumb_set, spk_localentry);
@@ -398,7 +399,8 @@ interface
         '.seh_endprologue','.seh_handler','.seh_handlerdata',
         '.seh_eh','.seh_32','seh_no32',
         '.seh_setframe','.seh_stackalloc','.seh_pushreg',
-        '.seh_savereg','.seh_savexmm','.seh_pushframe'
+        '.seh_savereg','.seh_savexmm','.seh_pushframe',
+        '.pushnv','.savenv'
       );
       symbolpairkindstr: array[TSymbolPairKind] of string[11]=(
         '.set', '.thumb_set', '.localentry'
@@ -3130,7 +3132,9 @@ implementation
         sd_reg,        { pushreg }
         sd_regoffset,  { savereg }
         sd_regoffset,  { savexmm }
-        sd_none        { pushframe }
+        sd_none,       { pushframe }
+        sd_reg,        { pushnv }
+        sd_none        { savenv }
       );
 
     constructor tai_seh_directive.create(_kind:TAsmSehDirective);

+ 42 - 2
compiler/x86/rax86int.pas

@@ -44,7 +44,7 @@ Unit Rax86int;
        {------------------ Assembler Operators  --------------------}
       AS_BYTE,AS_WORD,AS_DWORD,AS_QWORD,AS_TBYTE,AS_DQWORD,AS_OWORD,AS_XMMWORD,AS_YWORD,AS_YMMWORD,AS_NEAR,AS_FAR,
       AS_HIGH,AS_LOW,AS_OFFSET,AS_SIZEOF,AS_VMTOFFSET,AS_SEG,AS_TYPE,AS_PTR,AS_MOD,AS_SHL,AS_SHR,AS_NOT,
-      AS_AND,AS_OR,AS_XOR,AS_WRT,AS___GOTPCREL);
+      AS_AND,AS_OR,AS_XOR,AS_WRT,AS___GOTPCREL,AS_TARGET_DIRECTIVE);
 
     type
        tx86intreader = class(tasmreader)
@@ -72,6 +72,9 @@ Unit Rax86int;
          procedure BuildConstantOperand(oper: tx86operand);
          procedure BuildOpCode(instr : tx86instruction);
          procedure BuildConstant(constsize: byte);
+
+         function is_targetdirective(const s: string): boolean;virtual;
+         procedure HandleTargetDirective;virtual;
        end;
 
 
@@ -134,7 +137,7 @@ Unit Rax86int;
         '','','','','','','END',
         '','','','','','','','','','','','',
         '','','','sizeof','vmtoffset','','type','ptr','mod','shl','shr','not',
-        'and','or','xor','wrt','..gotpcrel'
+        'and','or','xor','wrt','..gotpcrel',''
       );
 
     constructor tx86intreader.create;
@@ -250,6 +253,17 @@ Unit Rax86int;
       end;
 
 
+    function tx86intreader.is_targetdirective(const s: string): boolean;
+      begin
+        result:=false;
+      end;
+
+
+    procedure tx86intreader.handletargetdirective;
+      begin
+      end;
+
+
     Procedure tx86intreader.GetToken;
       var
         len : longint;
@@ -275,6 +289,29 @@ Unit Rax86int;
          begin
            firsttoken:=FALSE;
            len:=0;
+
+           { directive check }
+           if c = '.' then
+            begin
+              actasmpattern:='.';
+              c:=current_scanner.asmgetchar;
+              while c in ['A'..'Z','a'..'z','0'..'9','_'] do
+                begin
+                 actasmpattern:=actasmpattern+c;
+                 c:=current_scanner.asmgetchar;
+                end;
+              { directives are case sensitive!! }
+              if is_asmdirective(actasmpattern) then
+               exit;
+              if is_targetdirective(actasmpattern) then
+                begin
+                  actasmtoken:=AS_TARGET_DIRECTIVE;
+                  exit;
+                end;
+              Message1(asmr_e_not_directive_or_local_symbol,actasmpattern);
+              exit;
+            end;
+
            while (c in ['A'..'Z','a'..'z','0'..'9','_','@']) or
                  { TP7 also allows $&? characters in local labels }
                  (forcelabel and (c in ['$','&','?'])) do
@@ -2704,6 +2741,9 @@ Unit Rax86int;
               Consume(AS_SEPARATOR);
             end;
 
+          AS_TARGET_DIRECTIVE:
+            HandleTargetDirective;
+
           AS_END :
             break; { end assembly block }
 

+ 165 - 24
compiler/x86_64/rax64int.pas

@@ -26,44 +26,185 @@ Unit rax64int;
   interface
 
     uses
+      aasmtai,
       rax86int;
 
     type
       tx8664intreader = class(tx86intreader)
-        // procedure handleopcode;override;
+        actsehdirective: TAsmSehDirective;
+        function is_targetdirective(const s:string):boolean;override;
+        procedure HandleTargetDirective;override;
       end;
 
 
   implementation
 
     uses
-      rabase,systems;
+      globtype,
+      cutils,
+      systems,
+      verbose,
+      cgbase,
+      symconst,
+      procinfo,
+      rabase;
 
-(*
-    procedure tx8664intreader.handleopcode;
+    const
+      { x86_64 subset of SEH directives. .seh_proc and .seh_endproc excluded
+        because they are generated automatically when needed. }
+      recognized_directives: set of TAsmSehDirective=[
+        ash_endprologue,ash_handler,ash_handlerdata,
+        ash_setframe,ash_stackalloc,ash_pushreg,
+        ash_savereg,ash_savexmm,ash_pushframe{,
+        ash_pushnv,ash_savenv }
+      ];
+
+      { max offset and bitmask for .seh_savereg and .seh_setframe }
+      maxoffset: array[boolean] of aint=(high(dword), 240);
+      modulo: array[boolean] of integer=(7, 15);
+
+    function tx8664intreader.is_targetdirective(const s:string):boolean;
+      var
+        i: TAsmSehDirective;
+      begin
+        result:=false;
+        if target_info.system<>system_x86_64_win64 then exit;
+
+        for i:=low(TAsmSehDirective) to high(TAsmSehDirective) do
+          begin
+            if not (i in recognized_directives) then
+              continue;
+            if s=sehdirectivestr[i] then
+              begin
+                actsehdirective:=i;
+                result:=true;
+                break;
+              end;
+          end;
+        { allow SEH directives only in pure assember routines }
+        if result and not (po_assembler in current_procinfo.procdef.procoptions) then
+          begin
+            Message(asmr_e_seh_in_pure_asm_only);
+            result:=false;
+          end;
+      end;
+
+
+    procedure tx8664intreader.HandleTargetDirective;
       var
-        instr : Tx86Instruction;
+        hreg: TRegister;
+        hnum: aint;
+        flags: integer;
+        ai: tai_seh_directive;
+        hs: string;
+        err: boolean;
       begin
-        instr:=Tx86Instruction.Create(Tx86Operand);
-        instr.OpOrder:=op_att;
-        BuildOpcode(instr);
-        instr.AddReferenceSizes;
-        instr.SetInstructionOpsize;
-        {
-        instr.CheckOperandSizes;
-        }
-        instr.ConcatInstruction(curlist);
-        instr.Free;
+        if actasmtoken<>AS_TARGET_DIRECTIVE then
+          InternalError(2011100201);
+        Consume(AS_TARGET_DIRECTIVE);
+        Include(current_procinfo.flags,pi_has_unwind_info);
+        case actsehdirective of
+          { TODO: .seh_pushframe is supposed to have a boolean parameter,
+                  but GAS 2.21 does not support it. }
+          ash_endprologue,
+          ash_pushframe,
+          ash_handlerdata:
+            curlist.concat(cai_seh_directive.create(actsehdirective));
+          ash_handler:
+            begin
+              hs:=actasmpattern;
+              Consume(AS_ID);
+              flags:=0;
+              err:=false;
+              while actasmtoken=AS_COMMA do
+                begin
+                  Consume(AS_COMMA);
+                  if actasmtoken=AS_ID then
+                    begin
+                      uppervar(actasmpattern);
+                      if actasmpattern='@EXCEPT' then
+                        flags:=flags or 1
+                      else if actasmpattern='@UNWIND' then
+                        flags:=flags or 2
+                      else
+                        err:=true;
+                      Consume(AS_ID);
+                    end
+                  else
+                    err:=true;
+                  if err then
+                    begin
+                      Message(asmr_e_syntax_error);
+                      RecoverConsume(false);
+                      exit;
+                    end;
+                end;
+
+              ai:=cai_seh_directive.create_name(ash_handler,hs);
+              ai.data.flags:=flags;
+              curlist.concat(ai);
+            end;
+          ash_stackalloc:
+            begin
+              hnum:=BuildConstExpression;//(false,false);
+              if (hnum<0) or (hnum>high(dword)) or ((hnum and 7)<>0) then
+                Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_stackalloc])
+              else
+                curlist.concat(cai_seh_directive.create_offset(ash_stackalloc,hnum));
+            end;
+          //ash_pushnv,
+          ash_pushreg:
+            begin
+              hreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBQ) then
+                Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[ash_pushreg])
+              else
+                curlist.concat(cai_seh_directive.create_reg(ash_pushreg,hreg));
+            end;
+          ash_setframe,
+          ash_savereg:
+            begin
+              hreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (getregtype(hreg)<>R_INTREGISTER) or (getsubreg(hreg)<>R_SUBQ) then
+                Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[actsehdirective]);
+              Consume(AS_COMMA);
+              hnum:=BuildConstExpression;//(false,false);
+              if (hnum<0) or (hnum>maxoffset[actsehdirective=ash_setframe]) or
+                ((hnum mod modulo[actsehdirective=ash_setframe])<>0) then
+                Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[actsehdirective])
+              else
+                curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum));
+            end;
+          //ash_savenv,
+          ash_savexmm:
+            begin
+              hreg:=actasmregister;
+              Consume(AS_REGISTER);
+              if (getregtype(hreg)<>R_MMREGISTER) then
+                Message1(asmr_e_bad_seh_directive_register,sehdirectivestr[ash_savexmm]);
+              Consume(AS_COMMA);
+              hnum:=BuildConstExpression;//(false,false);
+              if (hnum<0) or (hnum>high(dword)) or ((hnum and 15)<>0) then
+                Message1(asmr_e_bad_seh_directive_offset,sehdirectivestr[ash_savexmm])
+              else
+                curlist.concat(cai_seh_directive.create_reg_offset(actsehdirective,hreg,hnum));
+            end;
+          else
+            InternalError(2018022401);
+        end;
+        if actasmtoken<>AS_SEPARATOR then
+          Consume(AS_SEPARATOR);
       end;
-*)
-
-const
-  asmmode_x86_64_intel_info : tasmmodeinfo =
-          (
-            id    : asmmode_x86_64_intel;
-            idtxt : 'INTEL';
-            casmreader : tx8664intreader;
-          );
+
+    const
+      asmmode_x86_64_intel_info : tasmmodeinfo =
+              (
+                id    : asmmode_x86_64_intel;
+                idtxt : 'INTEL';
+                casmreader : tx8664intreader;
+              );
 
 initialization
   RegisterAsmMode(asmmode_x86_64_intel_info);