1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-15 02:29:32 +00:00
cc65/libsrc/runtime/stkchk.s
Oliver Schmidt 0ee9b2e446 Changed run location of INIT segment.
So far the INIT segment was run from the later heap+stack. Now the INIT segment is run from the later BSS. The background is that so far the INIT segment was pretty small (from $80 to $180 bytes). But upcoming changes will increase the INIT segment in certain scenarios up to ~ $1000 bytes. So programs with very limited heap+stack might just not been able to move the INIT segment to its run location. But moving the INIT segment to the later BSS allows it to occupy the later BSS+heap+stack.

In order to allow that the constructors are _NOT_ allowed anymore to access the BSS. Rather they must use the DATA segment or the new INITBSS segment. The latter isn't cleared at any point so the constructors may use it to expose values to the main program. However they must make sure to always write the values as they are not pre-initialized.
2015-10-14 22:52:09 +02:00

115 lines
3.1 KiB
ArmAsm

;
; Ullrich von Bassewitz, 19.03.2001
;
; 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 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
; operate using a safety area at the stack bottom. Once the stack reaches this
; safety area, we consider it an overflow, even if the stack is still inside
; its' bounds.
;
.export stkchk, cstkchk
.constructor initstkchk, 25
.import __STACKSIZE__ ; Linker defined
.import pusha0, _exit
.importzp sp
; Use macros for better readability
.macpack generic
.macpack cpu
; ----------------------------------------------------------------------------
; Initialization code. This is a constructor, so it is called on startup if
; the linker has detected references to this module.
.segment "INIT"
.proc initstkchk
lda sp
sta initialsp
sub #<__STACKSIZE__
sta lowwater
lda sp+1
sta initialsp+1
sbc #>__STACKSIZE__
.if (.cpu .bitand ::CPU_ISET_65SC02)
ina ; Add 256 bytes safety area
.else
add #1 ; Add 256 bytes safety area
.endif
sta lowwater+1
rts
.endproc
; ----------------------------------------------------------------------------
; 6502 stack checking routine. Does not need to save any registers.
; Safety zone for the hardware stack is 12 bytes.
.code
stkchk: tsx
cpx #12
bcc Fail ; Jump on stack overflow
rts ; Return if ok
; ----------------------------------------------------------------------------
; C stack checking routine. Does not need to save any registers.
.code
cstkchk:
; Check the high byte of the software stack
@L0: lda lowwater+1
cmp sp+1
bcs @L1
rts
; Check low byte
@L1: bne CStackOverflow
lda lowwater
cmp sp
bcs CStackOverflow
Done: rts
; We have a C stack overflow. Set the stack pointer to the initial value, so
; we can continue without worrying about stack issues.
CStackOverflow:
lda initialsp
sta sp
lda initialsp+1
sta sp+1
; 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
ldx #0
jmp _exit
; ----------------------------------------------------------------------------
; Data
.segment "INITBSS"
; Initial stack pointer value. Stack is reset to this in case of overflows to
; allow program exit processing.
initialsp: .res 2
; Stack low water mark.
lowwater: .res 2