Browse Source

* adapted 16 byte alignment handling on linux: it is now assumed that the callee tries to clear the stack, so in the caller, the stack is re-adjusted

git-svn-id: trunk@43176 -
florian 5 năm trước cách đây
mục cha
commit
fb91899457

+ 5 - 4
compiler/i386/cpupi.pas

@@ -88,10 +88,11 @@ unit cpupi;
     procedure tcpuprocinfo.generate_parameter_info;
       begin
         inherited generate_parameter_info;
-        { Para_stack_size is only used to determine how many bytes to remove }
-        { from the stack at the end of the procedure (in the "ret $xx").     }
-        { If the stack is fixed, nothing has to be removed by the callee     }
-        if paramanager.use_fixed_stack then
+        { Para_stack_size is only used to determine how many bytes to remove
+          from the stack at the end of the procedure (in the "ret $xx").
+          If the stack is fixed, nothing has to be removed by the callee, except
+          if a 16 byte aligned stack on i386-linux is used     }
+        if paramanager.use_fixed_stack and not(target_info.abi=abi_linux386_sysv) then
           para_stack_size := 0;
       end;
 

+ 10 - 4
compiler/i386/n386cal.pas

@@ -52,7 +52,8 @@ implementation
       nbas,nmem,nld,ncnv,
       parabase,
       symdef,symsym,symcpu,symconst,
-      cga,cgobj,cpuinfo;
+      cga,cgobj,cgx86,
+      cpuinfo;
 
 
 {*****************************************************************************
@@ -104,16 +105,21 @@ implementation
     procedure ti386callnode.pop_parasize(pop_size:longint);
       var
         hreg : tregister;
+        href : treference;
       begin
-        if (paramanager.use_fixed_stack) then
+        if paramanager.use_fixed_stack then
           begin
             { very weird: in this case the callee does a "ret $4" and the }
             { caller immediately a "subl $4,%esp". Possibly this is for   }
             { use_fixed_stack code to be able to transparently call       }
             { old-style code (JM)                                         }
             dec(pop_size,pushedparasize);
-            if (pop_size < 0) then
-              current_asmdata.CurrAsmList.concat(taicpu.op_const_reg(A_SUB,S_L,-pop_size,NR_ESP));
+            if pop_size<0 then
+              begin
+                reference_reset_base(href,NR_STACK_POINTER_REG,pop_size,ctempposinvalid,0,[]);
+                { it is better to use lea here }
+                current_asmdata.CurrAsmList.concat(Taicpu.op_ref_reg(A_LEA,TCGSize2OpSize[OS_ADDR],href,NR_ESP));
+              end;
             exit;
           end;
 

+ 31 - 16
compiler/ncgcal.pas

@@ -1187,25 +1187,40 @@ implementation
            end;
 
          { Need to remove the parameters from the stack? }
-         if (procdefinition.proccalloption in clearstack_pocalls) then
-          begin
-            pop_size:=pushedparasize;
-            { for Cdecl functions we don't need to pop the funcret when it
-              was pushed by para. Except for safecall functions with
-              safecall-exceptions enabled. In that case the funcret is always
-              returned as a para which is considered a normal para on the
-              c-side, so the funcret has to be pop'ed normally. }
-            if not ((procdefinition.proccalloption=pocall_safecall) and
-                    (tf_safecall_exceptions in target_info.flags)) and
-               paramanager.ret_in_param(procdefinition.returndef,procdefinition) then
-              dec(pop_size,sizeof(pint));
-            { Remove parameters/alignment from the stack }
-            pop_parasize(pop_size);
-          end
+         if procdefinition.proccalloption in clearstack_pocalls then
+           begin
+             pop_size:=pushedparasize;
+             { for Cdecl functions we don't need to pop the funcret when it
+               was pushed by para. Except for safecall functions with
+               safecall-exceptions enabled. In that case the funcret is always
+               returned as a para which is considered a normal para on the
+               c-side, so the funcret has to be pop'ed normally. }
+             if not ((procdefinition.proccalloption=pocall_safecall) and
+                     (tf_safecall_exceptions in target_info.flags)) and
+                paramanager.ret_in_param(procdefinition.returndef,procdefinition) then
+               dec(pop_size,sizeof(pint));
+             { Remove parameters/alignment from the stack }
+             pop_parasize(pop_size);
+           end
+         { in case we use a fixed stack, we did not push anything, if the stack is
+           really adjusted because a ret xxx was done, depends on
+           pop_parasize which uses pushedparasize to determine this
+
+           This does not apply to interrupt procedures, their ret statment never clears any stack parameters }
+         else if paramanager.use_fixed_stack and not(po_interrupt in procdefinition.procoptions) then
+           begin
+             { however, a delphi style frame pointer for a nested subroutine
+               is not cleared by the callee, so we have to compensate for this
+               by passing 4 as pushedparasize does include it }
+             if po_delphi_nested_cc in procdefinition.procoptions then
+               pop_parasize(sizeof(pint))
+             else
+               pop_parasize(0);
+           end
          { frame pointer parameter is popped by the caller when it's passed the
            Delphi way }
          else if (po_delphi_nested_cc in procdefinition.procoptions) and
-                 not paramanager.use_fixed_stack then
+           not paramanager.use_fixed_stack then
            pop_parasize(sizeof(pint));
          { Release registers, but not the registers that contain the
            function result }

+ 2 - 2
compiler/ncgutil.pas

@@ -775,9 +775,9 @@ implementation
         else
           begin
             parasize:=current_procinfo.para_stack_size;
-            { the parent frame pointer para has to be removed by the caller in
+            { the parent frame pointer para has to be removed always by the caller in
               case of Delphi-style parent frame pointer passing }
-            if not paramanager.use_fixed_stack and
+            if (not(paramanager.use_fixed_stack) or (target_info.abi=abi_linux386_sysv)) and
                (po_delphi_nested_cc in current_procinfo.procdef.procoptions) then
               dec(parasize,sizeof(pint));
           end;

+ 1 - 0
compiler/systems.inc

@@ -321,6 +321,7 @@
             ,abi_old_win32_gnu
             ,abi_aarch64_darwin
             ,abi_riscv_hf
+            ,abi_linux386_sysv
        );
 
      const

+ 3 - 2
compiler/systems.pas

@@ -239,7 +239,7 @@ interface
        end;
 
     tabiinfo = record
-      name: string[11];
+      name: string[13];
       supported: boolean;
     end;
 
@@ -433,7 +433,8 @@ interface
          (name: 'EABIHF' ; supported:{$ifdef FPC_ARMHF}true{$else}false{$endif}),
          (name: 'OLDWIN32GNU'; supported:{$ifdef I386}true{$else}false{$endif}),
          (name: 'AARCH64IOS'; supported:{$ifdef aarch64}true{$else}false{$endif}),
-         (name: 'RISCVHF'; supported:{$if defined(riscv32) or defined(riscv64)}true{$else}false{$endif})
+         (name: 'RISCVHF'; supported:{$if defined(riscv32) or defined(riscv64)}true{$else}false{$endif}),
+         (name: 'LINUX386_SYSV'; supported:{$if defined(i386)}true{$else}false{$endif})
        );
 
        { x86 asm modes with an Intel-style syntax }

+ 1 - 1
compiler/systems/i_linux.pas

@@ -101,7 +101,7 @@ unit i_linux;
             first_parm_offset : 8;
             stacksize    : 8*1024*1024;
             stackalign   : 16;
-            abi : abi_default;
+            abi : abi_linux386_sysv;
             { note: default LLVM stack alignment is 16 bytes for this target }
             llvmdatalayout : 'e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32';
           );

+ 2 - 2
tests/webtbs/tw7808.pp

@@ -20,9 +20,9 @@ begin
 {$endif FPC_STACKALIGNMENT=16}  
     push word $dead
     push word $beef
-    call test    
+    call test        
 {$if FPC_STACKALIGNMENT=16}
-    lea esp,[esp+16]
+    lea esp,[esp-4]
 {$endif FPC_STACKALIGNMENT=16}  
   end;
 end.