I have been prototyping some code using the IAR C++ compiler on a DK-TM4C129X dev kit.
When I recently obtained an I-jet debug probe from IAR I was surprised to find that my previously working code was suddenly experiencing a hard fault on startup. After playing around with a lot of things, I discovered that the fault only occurs if I use the C++ compile option along with the I-jet debugger. The C++ code works fine if I use the ICDI debugger, and the C code works fine using the I-jet.
I was able to reproduce the fault using the TI-supplied blinky example code. IAR tech support was able to discover what was going wrong, and I am sharing this info in case others may experience similar problems.
The fix involves modifying the startup_ewarm.c and blinky.icf files:
In startup_ewarm.c:
Replace the iar_program_start extern declaration with
#if defined(__cplusplus) || defined(__embedded_cplusplus)
extern "C" void __iar_program_start(void);
#endif
(Note: The above change has nothing to do with the fault, but is required to eliminate linker errors when using the C++ compiler)
Also replace the first part of the IVT definition with
#pragma section="CSTACK"
__root const uVectorEntry __vector_table[] @ ".intvec" =
{
//{ .ui32Ptr = (uint32_t)pui32Stack + sizeof(pui32Stack) },
{ .ui32Ptr = (uint32_t)__section_end("CSTACK") },
In blinky.icf, replace the "place in SRAM { readwrite, block HEAP };" statement at the end with
define block CSTACK with alignment = 8, size = 0x200 { };
place in SRAM { readwrite, block CSTACK, block HEAP };
The explanation from IAR tech support as to why this is needed is as follows:
For the Blinky project under C++ mode without those changes which I suggested, the linker's generated .map file will show 2 .intvec:
.intvec const 0x00000000 0x26c startup.o [1]
.intvec ro code 0x0000026c 0x40 vector_table_M.o [5]
So it seems that the default "__vector_table" is also being linked in from the library vector_table_M.o file, instead of just the "__vector_table" from your own startup.c file. It is most likely because the EWARM's .\arm\src\lib\cstartup_M.s has:
REQUIRE __vector_table
And hence the linker will try to link all the instances of __vector_table.
When the debugger starts, it usually initializes the PC and SP automatically. And I think that it picks the wrong ones (from vector_table_M.o, instead of startup.o) to initialize the PC and SP.
Since the original blinky.icf does not have the CSTACK section defined, the SP gets initialized to '0'. And any instruction in the
main() using the stack will cause the fault exception because the SP is pointing to an invalid address.
So having the original startup.c to refer to the "CSTACK" seems to be able to prevent the linker from linking in the extra __vector_table.