Is it possible to instruct C to not zero-initialize global arrays?

12,144

Solution 1

It turned out that the linker-script included in my toolchain has a special "noinit" section.

__attribute__ ((section (".noinit")))

/** Forces the compiler to not automatically zero the given global variable on startup, so that the current RAM contents is retained. Under most conditions this value will be random due to the behaviour of volatile memory once power is removed, but may be used in some specific circumstances, like the passing of values back after a system watchdog reset.

So all global variabeles marked with that attribute will not be zero-initialised during boot.

Solution 2

The problem is that standard C enforces zero initialization of static objects. If the compiler skips it, it wouldn't conform to the C standard.

On embedded systems compilers there is usually a non-standard option "compact startup" or similar. When enabled, no initialization of static/global objects will occur at all, anywhere in the program. How to do this depends on your compiler, or in this case, on your gcc port.

If you mention which system you are using, someone might be able to provide a solution for that particular compiler port.

This means that any static/global (static storage duration) variable that you initialize explicitly will no longer be initialized. You will have to initialize it in runtime, that is, instead of static int x=1; you will have to write static int x; x=1;. It is rather common to write embedded C programs in this manner, to make them compatible with compilers where the static initialization is disabled.

Solution 3

There are a few workarounds like:

  • Deleting the BSS section from the binary or setting its size to 0 or 1. This will not work if the loader must explicitly allocate memory for all sections. This will work if the loader simply copies data to the RAM.
  • Declaring your arrays as extern in C code and defining the symbols (along with their addresses) either in assembly code in separate assembly files or in the linker script. Again, if memory must be explicitly allocated, this won't work.
  • Patching or removing the relevant BSS-zeroing code either in the loader or in the startup code that is executed in your program before main().

Solution 4

All embedded compilers should allow a noinit segment. With the IAR AVR compiler the variables you don't want to be initialised are simply declared as follows:

__no_init uint16_t foo;

The most useful reason for this is to allow variables to maintain their values over a watchdog or brown-out reset, which of course doesn't happen in computer-based C programs, hence its omission from standard C.

Just search you compiler manual for "noinit" or something similar.

Solution 5

The C standard REQUIRES global data to be initialized to zero.

It is possible that SOME embedded system manufacturers provide a way to bypass this option, but there are certainly many typical applications that would simply fail if the "initialize to zero" wasn't done.

Some compilers also allow you to have further sections, which may have other characteristics than the 'bss' section.

The other alternative is of course to "make your own allocation". Since it's an embedded system, I suppose you have control over how the application and data is loaded into RAM, in particular, what addresses are used for that.

So, you could use a pointer, and simply use your own mechanism for assigning the pointer to a memory region that is reserved for whatever you need large arrays for. This avoids the rather complex usage of malloc - and it gives you a more or less permanent address, so you don't have to worry about trying to find where your data is later on. This will of course have a small effect on performance, since it adds another level of indirection, but in most cases, that disappears as soon as the array is used as an argument to a function, as it decays to a pointer at that point anyways.

Share:
12,144
Maestro
Author by

Maestro

Updated on June 03, 2022

Comments

  • Maestro
    Maestro about 2 years

    I'm writing an embedded application and almost all of my RAM is used by global byte-arrays. When my firmware boots it starts by overwriting the whole BSS section in RAM with zeroes, which is completely unnecessary in my case.

    Is there some way I can instruct the compiler that it doesn't need to zero-initialize certain arrays? I know this can also be solved by declaring them as pointers, and using malloc(), but there are several reasons I want to avoid that.