#1866 PIC16: Global variables not initialized to 0 by default


SDCC : mcs51/gbz80/z80/ds390/pic16/pic14/TININative/ds400/hc08 3.0.0 #6037

uint8_t variable0 = 0;
uint8_t variable1;

Declaring these 2 global variables, both should be initialized to 0 according to ANSI, but only variable0 is.

Bug sample attached showing that variable1 is not initialized to 0 because LED1 blinks (check simple code attached).
When running this code on a simulator it works correctly but I think that it is because RAM values are not random on start. However it's not working on real-life PIC.

Category "none" because I don't know where the bug is.

If you need anything else please let me know.
Thank you very much

P.S: hex file is different if variables are declared this way (and I think that hex file shouldn't change):

uint8_t variable0;
uint8_t variable1;


  • Diego Herranz

    Diego Herranz - 2011-10-28
  • Comment has been marked as spam. 

    You can see all pending comments posted by this user  here


    Anonymous - 2011-10-28

    This sounds like something that your crt0 code should handle (i.e. clearing the bss section). I'm not sure if that could be seen as a bug in SDCC, since the crt0 code can be quite project-specific, so you might be expected to provide your own.

  • Diego Herranz

    Diego Herranz - 2011-10-28

    I'm using crt0i provided by sdcc for pic16. Maybe it's a bug in crt0i.


  • Raphael Neider

    Raphael Neider - 2011-10-28

    Maybe you want to try crt0iz, which initializes and zeroes your memory.
    Initialized variables are copied from ROM/Flash (code memory) to RAM at system startup. Uninitialized data remains ... uninitialized unless you spend some code memory to wipe it on startup -- crt0/i/iz differ in the amount of code they spend for system startup routines.

  • Raphael Neider

    Raphael Neider - 2011-10-28
    • labels: --> pic16 target
    • milestone: --> 100455
    • status: open --> pending-invalid
  • Diego Herranz

    Diego Herranz - 2011-10-30

    Before going any further, let me check if what I know about different crt0x is right.

    crt0 - no initialization at all
    crt0i - initializes variables
    crt0iz - clears all ram and initializes variables

    If it's wrong please let me know. Returning to the topic at hand:

    uint8_t variable0=0;
    uint8_t variable1;

    With these 2 global variable declarations, I don't think that variable1 is uninitialized. I think that it is initialized to 0 exactly like variable0 according to ANSI standard (if it were an automatic variable it would be uninitialized but it's global).

    So, I think that crt0i should initialize variable1 to 0 for ANSI compliance (or using crt0iz by default, but this is slower at startup) .


  • Raphael Neider

    Raphael Neider - 2011-10-30

    What we do here is a non-standard optimization for small devices. For ANSI-compliance, use crt0iz.
    crt0i (currently) initializes only all *explicitly* initialized variables -- those that would lie in .data and .rodata sections if we were using ELF objects -- but leaves the implicitly initialized variables (.bss section) uninitialized.

    I start to agree that "the right way" is between crt0i and crt0iz, namely initializing all explicitly variables plus wiping .bss (rather than the whole memory). Unfortunately, I think that we do not have information on start and end of .bss at runtime. And then there might be multiple .bss sections -- at least one per bank ... Consequently a simple start/end record might not suffice. Probably we should just make crt0iz the default?

  • Raphael Neider

    Raphael Neider - 2011-10-30
    • milestone: 100455 --> known_bugs
    • status: pending-invalid --> open-later
  • Maarten Brock

    Maarten Brock - 2011-10-31
    • summary: Global variables not initialized to 0 by default --> PIC16: Global variables not initialized to 0 by default
  • Diego Herranz

    Diego Herranz - 2011-11-01

    Could we do something like converting this:

    uint8_t variable0=0;
    uint8_t variable1;

    to this:

    uint8_t variable0=0;
    uint8_t variable1=0;

    that is, moving variable1 from .bss to .data, so we can use crt0i as is, and we don't need to make crt0iz the default?

  • Bodo Wenzel

    Bodo Wenzel - 2011-11-01

    What is the problem with clearing just the .bss section in crt0iz?

    They are quite rare but in the last 20 years I have at least written two applications which need a preserved memory outsise .data and .bss. Well, they were no PIC applications. ;-)

  • Raphael Neider

    Raphael Neider - 2011-11-01

    The problem is that we do not know the location(s) of the .bss sections at runtime. Possibly, one can patch gputils to provide this information along with the initializer list: It currently provides us with (src, dst, size) records, instruction sdcc to copy SIZE bytes from SRC (supposed to be in __code space) to DST (in __data space). As a hack, one could use records with SRC == 0 to denote a "set SIZE bytes at DST to 0" .bss section ...
    Alternatively, one could introduce a larger "header" to the list, augmenting it from its current contents (number of records to follow) to include a second counter for .bss records right after the regular ones.
    This should probably be discussed on the gputist list.

  • Borut Ražem

    Borut Ražem - 2011-11-01

    For the beginning I can change the gputils linker to generate section begin and section end symbols fore each section, for example:

    I doubt that this will be of much help since sdcc generates a separate section for each C variable:

    char c[10];
    int a;
    long b;


    ; global definitions
    UD_t_0 udata
    _c res 10

    UD_t_1 udata
    _a res 2

    UD_t_2 udata
    _b res 4


  • Diego Herranz

    Diego Herranz - 2013-04-13

    Now that 3.3.0 is coming, should we use crt0iz by default for a better ANSI compliance?

  • Philipp Klaus Krause

    • Category: --> PIC16
  • Diego Herranz

    Diego Herranz - 2015-04-21

    This bug has been open for almost 4 years. I'd love to have it addressed before 3.5.0 release. Since wiping .bss section is not an easy task, I provide a very simple patch that simply makes crt0iz.o the default crt for PIC16 port.

    My view on this is: Using crt0iz.o we would be more ANSI compliant and the only small drawbacks (that I'm aware of) are longer boot time and increase in memory size used. I think both are negligible in most applications, and if someone needs to optimize, it's always possible explicitly use another crt (e.g. crt0i).

    How do you see it?


    Last edit: Diego Herranz 2015-04-21
  • Maarten Brock

    Maarten Brock - 2015-04-21

    I agree that this should be fixed some day. Leaving uninitialized global/static variables uninitialized is wrong. But the above discussion makes me wonder if crt0iz is the right solution snce it seems to clear all ram. I think Raphael's solution to clear on SRC==0 seems best.

  • Diego Herranz

    Diego Herranz - 2015-04-29

    I agree that Raphael's solution is best but I don't know if we have the time to implement it. What do you think about using crt0iz but leaving this bug open to eventually implement Raphael's solution?


  • David Cary

    David Cary - 2015-05-04

    I agree with Diego's suggestion:

    Get it working first. Then later optimize.

    I agree with Diego and Raphael:
    For now, make crt0iz SDCC's default (rather than crt0i or crt0), so the compiled program zeros all RAM before initializing the non-zero variables, to fix this bug and restore ANSI compliance.

    I don't see any reason not to do this right away.

    After that, I agree we should leave this bug open until crt0i is fixed so it properly zeros variables that are (implicitly or explicitly) initialized to zero.

    Later, after the bug is fixed, we might consider optimizing:

    Raphael's solution of fixing crt0i in a way that only zeros the static variables and global variables that need to be zeroed sounds like a good optimization that may help a few people who need extremely quick startup times, and doesn't hurt ANSI compliance.
    (Either (a) Move the initial values of every implicitly or explicitly initialized variable to the ".data segment", not just the non-zero values, so the crt0i we have now will work.
    Or (b) Implement a ".bss segment" and add a few lines to crt0i to zero out each block of the ".bss segment", which probably means somehow storing in flash the locations of those blocks).

    However, many people are willing to wait a few more clock cycles at startup if they can save a few bytes of flash, especially people who use the "--opt-code-size" option (the "-Os" option).
    Blindly zeroing all variables -- or perhaps even zeroing all RAM -- before initializing non-zero variables, may be the best strategy for most people using SDCC. That would save the few bytes of flash required to tell the startup code exactly where the blocks of ".bss segment" are located.

  • Philipp Klaus Krause

    Changed default to crt0iz in revision #9310.



Log in to post a comment.