For the PIC14, SDCC currently doesn't implement a true software stack. Instead, all local variables within a function are assigned with fixed memory addresses. This is implemented as the following. During compile-time by SDCC, SDCC produces a data section declaration udata
in its assembly output, and each used memory location for variables are represented as symbols such as r0x1000
, r0x1001
, r0x1002
, etc., and the assembler instruction res
is used to reserve memory for them. During link-time, the linker will find a spare chunk of memory and convert these memory location symbols to actual fixed addresses. Effectiveness, it means all local variables are static
to an extent.
The outcome of this design is that all functions are not reentrant-safe. If a function is shared for both a non-ISR and an ISR routine, memory corruption is possible.
This problem understandable since it's not unique to SDCC, some embedded compilers from other vendors have the same limitation (at least with some compiler flags). But this behavior should be clearly documented. I didn't check but I suspect PIC16 has the same problem.
This is also not the only memory-corruption problem caused by ISR. See #3536 Calling Functions in ISR Corrupts the Stack, as SDCC Makes no Attempt to Preserve it for another (and more serious) memory-corruption problem related to passing arguments.
For sake of completeness, here's a full description current stack implementation in PIC14 for future documentation updates.
In total, SDCC makes use of three types of stacks in memory, one hardware stack and two software stacks.
The hardware stack is only used for mostly CALL
, RETURN
due to the CPU's heavy restrictions - it's not possible to push
or pop
data, it's not mapped into memory, and it only has 16 words of storage. Thus in SDCC it's only used for saving return addresses, as intended by PIC's design.
The first software stack is the argument-passing stack. PIC uses memory banking because most instructions don't contain enough bits to cover the entire address space. But in each memory bank has a special section called the "Common RAM" with address from 0x70 to 0x7F. It's used as a software stack as STK00 to STK15. When calling a function, the first word is stored into the working register W, and the rest of the stored into STK00, STK01, STK02, etc.
The next software stack is the local variable stack. It's in fact not a true stack at all. During compile-time by SDCC, SDCC produces a data section declaration udata
in its assembly output, and each used memory location for variables are represented as symbols such as r0x1000
, r0x1001
, r0x1002
, etc., and the assembler instruction res
is used to reserve memory for them. During link-time, the linker will find a spare chunk of memory and convert these memory location symbols to actual fixed addresses. Effectiveness, it means all local variables are static
to an extent.
Does your description refer to the compiler's output with or without the command line switch
--stack-auto
?I am asking, because section 3.1.1 of the manual (Standard-Compliance: ISO C90 and ANSI C89) says:
Either way, thanks for your description of the current behavior.
EDIT: Silly me misread pdk as pic, but a note on pic could be added there.
Last edit: Benedikt Freisen 2023-05-08