mirror of
https://github.com/cc65/cc65.git
synced 2024-12-30 05:30:41 +00:00
Added code to check the 6502 stack
git-svn-id: svn://svn.cc65.org/cc65/trunk@638 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
fb76e97575
commit
9528c379c1
@ -1,9 +1,10 @@
|
|||||||
;
|
;
|
||||||
; Ullrich von Bassewitz, 19.03.2001
|
; 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
|
; 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
|
; 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
|
; 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
|
; checked (this would be way too much overhead). As a consequence we will
|
||||||
@ -12,7 +13,7 @@
|
|||||||
; its' bounds.
|
; its' bounds.
|
||||||
;
|
;
|
||||||
|
|
||||||
.export stkchk
|
.export stkchk, cstkchk
|
||||||
.constructor initstkchk, 25
|
.constructor initstkchk, 25
|
||||||
.import __STACKSIZE__ ; Linker defined
|
.import __STACKSIZE__ ; Linker defined
|
||||||
.import pusha0, _exit
|
.import pusha0, _exit
|
||||||
@ -29,51 +30,64 @@
|
|||||||
|
|
||||||
.proc initstkchk
|
.proc initstkchk
|
||||||
|
|
||||||
lda sp
|
lda sp
|
||||||
sta initialsp
|
sta initialsp
|
||||||
sub #<__STACKSIZE__
|
sub #<__STACKSIZE__
|
||||||
sta lowwater
|
sta lowwater
|
||||||
lda sp+1
|
lda sp+1
|
||||||
sta initialsp+1
|
sta initialsp+1
|
||||||
sbc #>__STACKSIZE__
|
sbc #>__STACKSIZE__
|
||||||
add #1 ; Add 256 bytes safety area
|
add #1 ; Add 256 bytes safety area
|
||||||
sta lowwater+1
|
sta lowwater+1
|
||||||
rts
|
rts
|
||||||
|
|
||||||
.endproc
|
.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
|
; C stack checking routine. Does not need to save any registers.
|
||||||
bcs @L1
|
|
||||||
rts
|
cstkchk:
|
||||||
|
|
||||||
|
; Check the high byte of the software stack
|
||||||
|
|
||||||
|
@L0: lda lowwater+1
|
||||||
|
cmp sp+1
|
||||||
|
bcs @L1
|
||||||
|
rts
|
||||||
|
|
||||||
; Check low byte
|
; Check low byte
|
||||||
|
|
||||||
@L1: bne @Overflow
|
@L1: bne CStackOverflow
|
||||||
lda lowwater
|
lda lowwater
|
||||||
cmp sp
|
cmp sp
|
||||||
bcs @Overflow
|
bcs CStackOverflow
|
||||||
rts
|
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.
|
; we can continue without worrying about stack issues.
|
||||||
|
|
||||||
@Overflow:
|
CStackOverflow:
|
||||||
lda initialsp
|
lda initialsp
|
||||||
sta sp
|
sta sp
|
||||||
lda initialsp+1
|
lda initialsp+1
|
||||||
sta sp+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
|
jsr pusha0
|
||||||
jmp _exit
|
jmp _exit
|
||||||
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
; ----------------------------------------------------------------------------
|
; ----------------------------------------------------------------------------
|
||||||
; Data
|
; Data
|
||||||
|
|
||||||
|
@ -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)
|
void g_stackcheck (void)
|
||||||
/* Check for a stack overflow */
|
/* Check for a stack overflow */
|
||||||
{
|
{
|
||||||
|
@ -371,6 +371,9 @@ void g_falsejump (unsigned flags, unsigned label);
|
|||||||
void g_space (int space);
|
void g_space (int space);
|
||||||
/* Create or drop space on the stack */
|
/* Create or drop space on the stack */
|
||||||
|
|
||||||
|
void g_cstackcheck (void);
|
||||||
|
/* Check for a C stack overflow */
|
||||||
|
|
||||||
void g_stackcheck (void);
|
void g_stackcheck (void);
|
||||||
/* Check for a stack overflow */
|
/* Check for a stack overflow */
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "funcdesc.h"
|
#include "funcdesc.h"
|
||||||
|
#include "global.h"
|
||||||
#include "litpool.h"
|
#include "litpool.h"
|
||||||
#include "locals.h"
|
#include "locals.h"
|
||||||
#include "scanner.h"
|
#include "scanner.h"
|
||||||
@ -229,6 +230,11 @@ void NewFunc (SymEntry* Func)
|
|||||||
g_usecode ();
|
g_usecode ();
|
||||||
g_defgloblabel (Func->Name);
|
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 */
|
/* Generate function entry code if needed */
|
||||||
g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc));
|
g_enter (TypeOf (Func->Type), GetParamSize (CurrentFunc));
|
||||||
|
|
||||||
@ -254,7 +260,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
RestoreRegVars (0);
|
RestoreRegVars (0);
|
||||||
|
|
||||||
Flags = HasVoidReturn (CurrentFunc)? CF_NONE : CF_REG;
|
Flags = HasVoidReturn (CurrentFunc)? CF_NONE : CF_REG;
|
||||||
g_leave (Flags, 0);
|
g_leave (Flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dump literal data created by the function */
|
/* Dump literal data created by the function */
|
||||||
|
@ -378,7 +378,7 @@ void DeclareLocals (void)
|
|||||||
* the stack checking routine if stack checks are enabled.
|
* the stack checking routine if stack checks are enabled.
|
||||||
*/
|
*/
|
||||||
if (CheckStack && InitialStack != oursp) {
|
if (CheckStack && InitialStack != oursp) {
|
||||||
g_stackcheck ();
|
g_cstackcheck ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user