diff --git a/libsrc/runtime/stkchk.s b/libsrc/runtime/stkchk.s index 53f9e1487..712da3094 100644 --- a/libsrc/runtime/stkchk.s +++ b/libsrc/runtime/stkchk.s @@ -1,9 +1,10 @@ ; ; Ullrich von Bassewitz, 19.03.2001 ; -; Stack checking code. +; Stack checking code. These are actually two routines, one to check the C +; stack, and the other one to check the 6502 hardware stack. ; For performance reasons (to avoid having to pass a parameter), the compiler -; calls the stkchk routine *after* allocating space on the stack. So the +; calls the cstkchk routine *after* allocating space on the stack. So the ; stackpointer may already be invalid if this routine is called. In addition ; to that, pushs and pops that are needed for expression evaluation are not ; checked (this would be way too much overhead). As a consequence we will @@ -12,7 +13,7 @@ ; its' bounds. ; - .export stkchk + .export stkchk, cstkchk .constructor initstkchk, 25 .import __STACKSIZE__ ; Linker defined .import pusha0, _exit @@ -29,51 +30,64 @@ .proc initstkchk - lda sp - sta initialsp - sub #<__STACKSIZE__ - sta lowwater - lda sp+1 - sta initialsp+1 - sbc #>__STACKSIZE__ - add #1 ; Add 256 bytes safety area - sta lowwater+1 + lda sp + sta initialsp + sub #<__STACKSIZE__ + sta lowwater + lda sp+1 + sta initialsp+1 + sbc #>__STACKSIZE__ + add #1 ; Add 256 bytes safety area + sta lowwater+1 rts .endproc ; ---------------------------------------------------------------------------- -; Stack checking routine. Does not need to save any registers. +; 6502 stack checking routine. Does not need to save any registers. +; Safety zone for the hardware stack is 10 bytes. -.proc stkchk +stkchk: tsx + cpx #10 + bcc Fail ; Jump on stack overflow + rts ; Return if ok - lda lowwater+1 - cmp sp+1 - bcs @L1 - rts +; ---------------------------------------------------------------------------- +; C stack checking routine. Does not need to save any registers. + +cstkchk: + +; Check the high byte of the software stack + +@L0: lda lowwater+1 + cmp sp+1 + bcs @L1 + rts ; Check low byte -@L1: bne @Overflow - lda lowwater - cmp sp - bcs @Overflow - rts +@L1: bne CStackOverflow + lda lowwater + cmp sp + bcs CStackOverflow +Done: rts -; We have a stack overflow. Set the stack pointer to the initial value, so +; We have a C stack overflow. Set the stack pointer to the initial value, so ; we can continue without worrying about stack issues. -@Overflow: +CStackOverflow: lda initialsp sta sp lda initialsp+1 sta sp+1 - lda #4 + +; Generic abort entry. We should output a diagnostic here, but this is +; difficult, since we're operating at a lower level here. + +Fail: lda #4 jsr pusha0 jmp _exit -.endproc - ; ---------------------------------------------------------------------------- ; Data diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index b04ac4b38..58595df90 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -2515,6 +2515,14 @@ void g_space (int space) +void g_cstackcheck (void) +/* Check for a C stack overflow */ +{ + AddCodeLine ("\tjsr\tcstkchk"); +} + + + void g_stackcheck (void) /* Check for a stack overflow */ { diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index f568e8152..977b868b7 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -371,6 +371,9 @@ void g_falsejump (unsigned flags, unsigned label); void g_space (int space); /* Create or drop space on the stack */ +void g_cstackcheck (void); +/* Check for a C stack overflow */ + void g_stackcheck (void); /* Check for a stack overflow */ diff --git a/src/cc65/function.c b/src/cc65/function.c index 393679b77..d15fe7262 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -42,6 +42,7 @@ #include "codegen.h" #include "error.h" #include "funcdesc.h" +#include "global.h" #include "litpool.h" #include "locals.h" #include "scanner.h" @@ -229,6 +230,11 @@ void NewFunc (SymEntry* Func) g_usecode (); g_defgloblabel (Func->Name); + /* If stack cehcking code is requested, emit a call to the helper routine */ + if (CheckStack) { + g_stackcheck (); + } + /* Generate function entry code if needed */ g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc)); @@ -254,7 +260,7 @@ void NewFunc (SymEntry* Func) RestoreRegVars (0); Flags = HasVoidReturn (CurrentFunc)? CF_NONE : CF_REG; - g_leave (Flags, 0); + g_leave (Flags, 0); } /* Dump literal data created by the function */ diff --git a/src/cc65/locals.c b/src/cc65/locals.c index c0083ac28..c0a62c9f0 100644 --- a/src/cc65/locals.c +++ b/src/cc65/locals.c @@ -378,7 +378,7 @@ void DeclareLocals (void) * the stack checking routine if stack checks are enabled. */ if (CheckStack && InitialStack != oursp) { - g_stackcheck (); + g_cstackcheck (); } }