March 30, 2013

Dynamic initialization C++ in IAR

I've been running my demo application only in KEIL for few days which I believe was huge mistake which reflected on me on Friday. When I finally run it in IAR. Once it loaded, first object's method ended up in a default isr handler with the hard fault. My debug session started. First problem I found, was one function was overwritting memory, that one was simple to catch once I found out which memory and what object is located right before overwritten data. Second one was a bit tougher to find out.

I decided to move local user-type objects to a global scope, which means before an application hits main function, global objects must be initialized. No problem with KEIL, but IAR did not do it.

This is quote from EWARM Development Guide (IAR) [3] which is quite comprehensive manual to understand many options it offers through command line options. But it does not provide details which might be handy.
When using the IAR C/C++ compiler and the standard library, C++ dynamic
initialization is handled automatically.


I though all right, how to track it down and see if dynamic allocation is really executed. Let's check map file of my application:

INIT TABLE
          Address     Size
          -------     ----
Zero (__iar_zero_init3)
    1 destination range, total size 0x2a7:
          0x1ffff420  0x2a7
Extra (__iar_cstart_call_ctors)

And here's ENTRY LIST of our interest:

__call_ctors            0x00004775   0x18  Code  Gb  cppinit.o [4]
__iar_cstart_call_ctors
                        0x00004ae5   0x20  Code  Gb  cmain_call_ctors.o [7]

A problem is, they are not invoked, startup function just takes care regular things (copying initialized data from ROM to RAM, .bss data, vector table). There's nothing with dynamic initialization. I placed breakpoint inside __call_ctors and it surprisingly was not reached. How to invoke __call_ctors function? What's it declaration? Exactly this details is not in any documentation provided in IAR doc folder (at least I was not able to find it there). Only one link on google was relevant, let's test it.

extern void * __iar_cstart_call_ctors(void *ptr);

No linker errors, correct declaration. Only one parameter, what it should be? The linker created following sections which are the one we are looking for (more info find in section C++ DYNAMIC INITIALIZATION [3] :

.init_array$$Base       0x00004d58          --   Gb  - Linker created -
.init_array$$Limit      0x00004d5c          --   Gb  - Linker created -
 
SHT$$INIT_ARRAY$$Base   0x00004d58          --   Gb  - Linker created -
SHT$$INIT_ARRAY$$Limit  0x00004d5c          --   Gb  - Linker created -
SHT$$PREINIT_ARRAY$$Base
                        0x00004d58          --   Gb  - Linker created -
SHT$$PREINIT_ARRAY$$Limit
                        0x00004d58          --   Gb  - Linker created -

Each section (INIT_ARRAY, PRE_INIT_ARRAY) contain array of pointers to initialization functions. [2] Let's invoke it in the end of an application's startup with a following line:

void *cpp_init = __section_begin(".init_array");
__iar_cstart_call_ctors(cpp_init);

That calls __call_ctors which initializes all global dynamic objects. Thus application works. An unanswered question is why it was not invoked automatically? I hope I'll come with an answer soon :)

References:
[1] cmain.s [http://code.google.com/p/sdp-firmwares]
[2] System V Application Binary Interface [sco.com/developers/gabi]
[3] EWARM Development Guide - IAR installation folder/arm/doc or online