Parcourir la source

+ implemented proper stack checking for the i8086

git-svn-id: trunk@33787 -
nickysn il y a 9 ans
Parent
commit
c78f406d99

+ 7 - 0
compiler/i8086/cgcpu.pas

@@ -1809,6 +1809,13 @@ unit cgcpu;
 
     procedure tcg8086.g_stackpointer_alloc(list : TAsmList;localsize: longint);
       begin
+        if cs_check_stack in current_settings.localswitches then
+          begin
+            cg.getcpuregister(list,NR_AX);
+            cg.a_load_const_reg(list,OS_16, localsize,NR_AX);
+            cg.a_call_name(list,'FPC_STACKCHECK_I8086',false);
+            cg.ungetcpuregister(list, NR_AX);
+          end;
         if localsize>0 then
           list.concat(Taicpu.Op_const_reg(A_SUB,S_W,localsize,NR_STACK_POINTER_REG));
       end;

+ 2 - 1
compiler/ngenutil.pas

@@ -1317,7 +1317,8 @@ implementation
       );
       tcb.free;
 
-      if not(tf_no_generic_stackcheck in target_info.flags) then
+      if (tf_emit_stklen in target_info.flags) or
+          not(tf_no_generic_stackcheck in target_info.flags) then
         begin
           { stacksize can be specified and is now simulated }
           tcb:=ctai_typedconstbuilder.create([tcalo_new_section,tcalo_make_dead_strippable]);

+ 1 - 0
compiler/systems.pas

@@ -137,6 +137,7 @@ interface
             tf_pic_default,
             { the os does some kind of stack checking and it can be converted into a rte 202 }
             tf_no_generic_stackcheck,
+            tf_emit_stklen,                     // Means that the compiler should emit a _stklen variable with the stack size, even if tf_no_generic_stackcheck is specified
             tf_has_winlike_resources,
             tf_safecall_clearstack,             // With this flag set, after safecall calls the caller cleans up the stack
             tf_safecall_exceptions,             // Exceptions in safecall calls are not raised, but passed to the caller as an ordinal (hresult) in the function result.

+ 2 - 1
compiler/systems/i_msdos.pas

@@ -42,7 +42,8 @@ unit i_msdos;
             name         : 'MS-DOS 16-bit real mode';
             shortname    : 'MSDOS';
             flags        : [tf_use_8_3,tf_smartlink_library,
-                            tf_no_objectfiles_when_smartlinking,tf_cld];
+                            tf_no_objectfiles_when_smartlinking,tf_cld,
+                            tf_no_generic_stackcheck,tf_emit_stklen];
             cpu          : cpu_i8086;
             unit_env     : 'MSDOSUNITS';
             extradefines : '';

+ 1 - 0
compiler/systems/i_win16.pas

@@ -43,6 +43,7 @@ unit i_win16;
             shortname    : 'Win16';
             flags        : [tf_use_8_3,tf_smartlink_library,
                             tf_no_objectfiles_when_smartlinking,tf_cld,
+                            tf_no_generic_stackcheck,tf_emit_stklen,
                             tf_x86_far_procs_push_odd_bp];
             cpu          : cpu_i8086;
             unit_env     : 'WIN16UNITS';

+ 8 - 1
compiler/x86/cgx86.pas

@@ -3067,7 +3067,14 @@ unit cgx86;
                 if current_procinfo.framepointer=NR_STACK_POINTER_REG then
                   current_asmdata.asmcfi.cfa_def_cfa_offset(list,localsize+sizeof(pint));
                 current_procinfo.final_localsize:=localsize;
-              end;
+              end
+{$ifdef i8086}
+            else
+              { on i8086 we always call g_stackpointer_alloc, even with a zero size,
+                because it will generate code for stack checking, if stack checking is on }
+              g_stackpointer_alloc(list,0)
+{$endif i8086}
+              ;
 
 {$ifdef i8086}
               { win16 exported proc prologue follow-up (see the huge comment above for details) }

+ 58 - 0
rtl/i8086/i8086.inc

@@ -727,6 +727,64 @@ asm
 end;
 
 
+{****************************************************************************
+                              Stack checking
+****************************************************************************}
+
+
+procedure fpc_stackcheck_i8086;[public,alias:'FPC_STACKCHECK_I8086'];compilerproc;assembler;nostackframe;
+const
+  STACK_MARGIN=512;
+asm
+  { on entry: AX = required stack size to check if available
+                   (function is called before stack allocation) }
+{$ifdef FPC_MM_HUGE}
+  push ds
+  push ax
+  mov ax, SEG @DATA
+  mov ds, ax
+  pop ax
+{$endif FPC_MM_HUGE}
+  add ax, STACK_MARGIN
+  jc @@stack_overflow
+  add ax, word ptr [__stkbottom]
+  jc @@stack_overflow
+  cmp ax, sp
+  ja @@stack_overflow
+@@no_overflow:
+{$ifdef FPC_MM_HUGE}
+  pop ds
+{$endif FPC_MM_HUGE}
+  ret
+
+@@stack_overflow:
+  { check StackError flag, to avoid recursive calls from the exit routines }
+  cmp byte ptr [StackError], 1
+  je @@no_overflow
+  mov byte ptr [StackError], 1
+  { cleanup return address (and maybe saved ds) from call to this function }
+{$if defined(FPC_MM_HUGE)}
+  add sp, 6
+{$elseif defined(FPC_X86_CODE_FAR)}
+  pop ax
+  pop ax
+{$else}
+  pop ax
+{$endif}
+  { call HandleError(202) }
+{$ifdef CPU8086}
+  xor ax, ax
+  push ax
+  mov al, 202
+  push ax
+{$else}
+  push 0
+  push 202
+{$endif}
+  call HandleError
+end;
+
+
 {****************************************************************************
                                   BSR/BSF
 ****************************************************************************}

+ 3 - 0
rtl/inc/compproc.inc

@@ -756,6 +756,9 @@ function fpc_setjmp(var s : jmp_buf) : {$ifdef CPU16}smallint{$else}longint{$end
 procedure fpc_longjmp(var s : jmp_buf; value : {$ifdef CPU16}smallint{$else}longint{$endif}); compilerproc;
 
 {$ifdef cpui8086}
+{ i8086 stack checking }
+procedure fpc_stackcheck_i8086; compilerproc;
+
 { i8086 huge pointer helpers }
 function fpc_hugeptr_add_longint(p: HugePointer; n: LongInt): HugePointer; compilerproc;
 function fpc_hugeptr_add_longint_normalized(p: HugePointer; n: LongInt): HugePointer; compilerproc;