Global Variable Initialisation to Zero

Go To Last Post
6 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all,

I woudl like to ask about Global Variable initialisation using avr-gcc (WinAVR 20090313).

According to the FAQ, any global variables not explicly set should automatically be initialised to zero:

int variable;    // Should be zero
int foo = 0;     // Apparently redundant, but does it make a difference to my question below?

int main(void)
{
    if (0 == variable)
    {
        // Should always be true....
    }

    ...

My question is about if the zeros are set explicitly by code before main() runs, or relies on the chip resetting RAM to zero on reset.

The reasoning being, if I'm using a bootloader which will pollute the RAM before jumping to 0x0000, can I guaruntee that the RAM will be set to zero by the regular application before main(), or do I explicitly have to zero the RAM myself in the bootloader before handing control from the bootloader to my application?

-- Damien

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

they are set to 0 by code, not hardware. One of the initialization routines that GCC calls before entering your main() function does this. So no you don't have to do it explicately, GCC automatically does this for you.

The state of ram on reset is considered to be random, there is nothing in hardware that will force it to be 0 or any other fixed value.

Writing code is like having sex.... make one little mistake, and you're supporting it for life.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks very much!

-- Damien

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Damien,

You can see this for yourself if you study the .lss file. I just built your code snippet and get:

Disassembly of section .text:

00000000 <__vectors>:
   0:	19 c0       	rjmp	.+50     	; 0x34 <__ctors_end>

This is the jmp at location 0 that jumps over the interrupt vector table.

00000034 <__ctors_end>:
  34:	11 24       	eor	r1, r1
  36:	1f be       	out	0x3f, r1	; 63
  38:	cf ef       	ldi	r28, 0xFF	; 255
  3a:	d4 e0       	ldi	r29, 0x04	; 4
  3c:	de bf       	out	0x3e, r29	; 62
  3e:	cd bf       	out	0x3d, r28	; 61

This is the code that (a) guarantees that R1 holds 0 (it's known internally as __zero_reg__ and is used whenever the value 0 is needed by the generated C), (b) it outputs the 0 to the SREG register to ensure that interrupts are disabled and the other flags start in a known state, (c) it sets the stack (SPL/SPH) to "RAMEND" as GCC arranges for the stack with CALL/RET addresses and locally created variables to work down from the very end of SRAM in the device.

00000040 <__do_clear_bss>:
  40:	11 e0       	ldi	r17, 0x01	; 1
  42:	a0 e0       	ldi	r26, 0x00	; 0
  44:	b1 e0       	ldi	r27, 0x01	; 1
  46:	01 c0       	rjmp	.+2      	; 0x4a <.do_clear_bss_start>

00000048 <.do_clear_bss_loop>:
  48:	1d 92       	st	X+, r1

0000004a <.do_clear_bss_start>:
  4a:	a4 30       	cpi	r26, 0x04	; 4
  4c:	b1 07       	cpc	r27, r17
  4e:	e1 f7       	brne	.-8      	; 0x48 <.do_clear_bss_loop>
  50:	02 d0       	rcall	.+4      	; 0x56 
52: 0a c0 rjmp .+20 ; 0x68 <_exit>

And this is the code you were asking about. It clears all variables in .bss (block started by symbol) to 0 with that "ST Z+, R1" (remember R1 is __zero_reg__). In this case it is clearing locations 0x100 (start of SRAM on a mega88) to 0x103 and stopping when it reaches 0x104 (hence the CPI R26, 0x04). The linker will have chosen to place the two bytes of "int variable" at 0x100/0x101 and the two bytes of "int foo = 0;" at 0x102/0x103.

Now if you had made that assignment any value other than "= 0" then 'foo' would have been located into a different memory region called .data which is where the variables with initial values are located in SRAM. The linker positions all the .data items before the .bss. If the code is:

int variable;    // Should be zero 
int foo = 12345;     // Apparently redundant, but does it make a difference to my question below? 

Then the pre-amble code generated consists of TWO loops:

00000040 <__do_copy_data>:
  40:	11 e0       	ldi	r17, 0x01	; 1
  42:	a0 e0       	ldi	r26, 0x00	; 0
  44:	b1 e0       	ldi	r27, 0x01	; 1
  46:	e2 e8       	ldi	r30, 0x82	; 130
  48:	f0 e0       	ldi	r31, 0x00	; 0
  4a:	02 c0       	rjmp	.+4      	; 0x50 <.do_copy_data_start>

0000004c <.do_copy_data_loop>:
  4c:	05 90       	lpm	r0, Z+
  4e:	0d 92       	st	X+, r0

00000050 <.do_copy_data_start>:
  50:	a2 30       	cpi	r26, 0x02	; 2
  52:	b1 07       	cpc	r27, r17
  54:	d9 f7       	brne	.-10     	; 0x4c <.do_copy_data_loop>

This first loop copies initial values (12345) out of code flash using SPM and writes them into RAM. In this case, because .data precedes .bss in RAM it's the case that 'foo' is positioned at 0x100/0x101. Then the linker positions the .bss 'variable' at 0x102/0x103 which can be seen in the modified clear BSS loop:

00000056 <__do_clear_bss>:
  56:	11 e0       	ldi	r17, 0x01	; 1
  58:	a2 e0       	ldi	r26, 0x02	; 2
  5a:	b1 e0       	ldi	r27, 0x01	; 1
  5c:	01 c0       	rjmp	.+2      	; 0x60 <.do_clear_bss_start>

0000005e <.do_clear_bss_loop>:
  5e:	1d 92       	st	X+, r1

00000060 <.do_clear_bss_start>:
  60:	a4 30       	cpi	r26, 0x04	; 4
  62:	b1 07       	cpc	r27, r17
  64:	e1 f7       	brne	.-8      	; 0x5e <.do_clear_bss_loop>
  66:	02 d0       	rcall	.+4      	; 0x6c 
68: 0a c0 rjmp .+20 ; 0x7e <_exit>

In all cases you'll see that after the .bss loop completes the code does an "rcall main" which is the pointer it leaves this pre-amble and enters your own program at "int main(void)". If your program ever makes a return from main() then it will return to the line following the "rcall main" where it does a "rjmp _exit". At that label the code is:

0000007e <_exit>:
  7e:	f8 94       	cli

00000080 <__stop_program>:
  80:	ff cf       	rjmp	.-2      	; 0x80 <__stop_program>

which is the inifinite loop that will "catch control" if it gets out of main().

I think it's useful for all C programmers to understand this and know what .data and .bss are. There's more about how things are laid out here:

http://www.nongnu.org/avr-libc/u...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@clawson,

 

Thank you for this amazing response! I just created an account (10 years after the message was posted) to thank you. It was very helpful to me!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

All part of the service ;-)