Any class that is instantiated in global space doesn't appear to call its constructor to initialise its member variables.
To reproduce:
* Start a new S32DS project
* Select MPC5777C (Not sure if this matters)
* Set language for all cores to C++
* Set the library for all cores to NewLib
Attached is the modifed main_z7_0.cpp that can reproduce the results. I am expecting both glob_val and local_val to be equal to 10 by the time the code gets to the for loop. But I am finding that glob_val is 0 and local_val is 10.
I am unable to use a pointer and initialise it in main.
Is there a configuration I am missing on the compiler/linker? Looking at the map file the crtbegin.o does not get linked in and I believe it has something to do with initialising this type of thing.
Original Attachment has been moved to: main_Z7_0.cpp.zip
Solved! Go to Solution.
Thanks for all the replies. With information from each of your replies I have been able to hack together a solution that works for my test case.
I have attached the start up code and linker files I have modded from defaults created when starting a new project. It comes with the usual warning of use at your own risk because I am by no means a compiler expert. I haven't reviewed what it has added into the binary, pushed it terms of testing other cases or tried it in my actual development code where I originally found the problem.
Martin, the new version of S32DS sounds really good, is it possible to get a pre-release version of it? Or is it possible to get confirmation that the solution to this problem is a fix that applies only to the startup.S and linker file? That info will give me more confidence in the changes I have made. And would it be possible to get a copy of the ones created in your working version?
Hello,
I have just tested your use case in newest S32 Design Studio for Power Architecture v1.2 and the issue with constructors for global defined objects is fixed.
Version 1.2 should be released at the end of May.
If you have any other questions, please feel free to write me back.
Regards,
Martin
Thanks for all the replies. With information from each of your replies I have been able to hack together a solution that works for my test case.
I have attached the start up code and linker files I have modded from defaults created when starting a new project. It comes with the usual warning of use at your own risk because I am by no means a compiler expert. I haven't reviewed what it has added into the binary, pushed it terms of testing other cases or tried it in my actual development code where I originally found the problem.
Martin, the new version of S32DS sounds really good, is it possible to get a pre-release version of it? Or is it possible to get confirmation that the solution to this problem is a fix that applies only to the startup.S and linker file? That info will give me more confidence in the changes I have made. And would it be possible to get a copy of the ones created in your working version?
Does your linker script have something like this in it?:
/*
* Statements in a SECTIONS command describe the placement of each named
* output section and specify which input sections go into them. You are
* only allowed one SECTIONS statement per command file, but it can have
* as many statements in it as necessary.
*
* Including =fill in a section definition specifies the initial fill
* value for that section. Any unallocated holes in the current
* output section when written to the output file will be filled with
* the two least significant bytes of the value, repeated as
* necessary. The fill value can also be changed with a FILL
* statement in the contents of a section definition.
*/
SECTIONS
{
/* The startup code goes first into INTERNAL_FLASH: */
.isr_vector :
{
__vector_table = .; /* Address of the ISR Vector Table */
. = ALIGN(4);
/*
* When link-time garbage collection is in use (-gc-sections), it is
* often useful to mark sections that should not be eliminated. This is
* accomplished by surrounding an input section's wild-card entry with
* KEEP(), as in KEEP(*(.init)) or KEEP(SORT(*)(.ctors)).
*/
KEEP(*(.isr_vector))
. = ALIGN(4);
} > VECTORS =0xFF
.bootloader_configuration_area :
{
. = ALIGN(4);
__bca_cfg = .; /* Address of the BCA Config Table */
KEEP(*(.bootloader_configuration_area )) /* Bootloader Configuration Area (BCA) */
. = ALIGN(4);
} > BOOTCFG =0xFF
...
.ctors : /* Constructors .ctors */
{/* This section contains a list of global constructor function pointers */
__CTOR_LIST__ = .;
/*
* gcc uses crtbegin.o to find the start of
* the constructors, so we make sure it is
* first. Because this is a wildcard, it
* doesn't matter if the user does not
* actually link against crtbegin.o; the
* linker won't look for a file to match a
* wildcard. The wildcard also means that it
* doesn't matter which directory crtbegin.o
* is in.
*/
KEEP (*crtbegin.o(.ctors))
/*
* We don't want to include the .ctor section from
* from the crtend.o file until after the sorted ctors.
* The .ctor section from the crtend file contains the
* end of ctors marker and it must be last.
*/
KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors))
/*
* When the SORT keyword is used, the linker will sort the files or
* sections into ascending order by name before placing them in the
* output file.
*/
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4);
__CTOR_END__ = .;
} > FLASH =0xFF
.dtors : /* Destructors .dtors */
{/* This section contains a list of global destructor function pointers */
__DTOR_LIST__ = .;
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4);
__DTOR_END__ = .;
_etext = .; /* Define a global symbols at end of code [Note single '_'] */
__code_end = .; /* Define a global symbols at end of code */
} > FLASH =0xFF
Thanks for your reply.
I didn't have the section about .ctors and .dtors in my linker file so I have added that in. The other sections I had equivalents to, so I left them out. Adding the .ctors and .dtors has the sections linked in but it is not being called. From my reading (see the links below) I need to call the init function for it to work.
Does anyone have an idea as to what to call specifically for this? Or is there some NXP documentation specifically about the configuration for this for the PowerPC EABI that could help point me in the right direction? My searching for such has not brought up anything but that could be I am learning about this as I go and may not be using the correct terms.
What I have found so for is included with the S32DS in C:\Freescale\S32_Power_v1.1\Cross_Tools\powerpc-eabivle-4_9\lib\gcc\powerpc-eabivle\4.9.2\e200z7 (the core that I am using) there is ercti.o which has labels that are close. But calling this directly won't work. They don't have a return call so don't work when called directly.
Objdump of ercti.o:
C:\>powerpc-eabivle-objdump -d c:\freescale\s32_power_v1.1\cross_tools\powerpc-eabivle-4_9\lib\gcc\powerpc-eabivle\4.9.2\fp\e200z7\ecrti.o
c:\freescale\s32_power_v1.1\cross_tools\powerpc-eabivle-4_9\lib\gcc\powerpc-eabivle\4.9.2\fp\e200z7\ecrti.o: file format elf32-powerpc
Disassembly of section .init:
00000000 <__init>:
0: 18 21 06 f0 e_stwu r1,-16(r1)
4: 00 80 se_mflr r0
6: 54 01 00 14 e_stw r0,20(r1)
Disassembly of section .fini:
00000000 <__fini>:
0: 18 21 06 f0 e_stwu r1,-16(r1)
4: 00 80 se_mflr r0
6: 54 01 00 14 e_stw r0,20(r1)
I am thinking there is something that will need to be added to startup.S. Be it a simple branch and link instruction that does all the work or a more manual calling each constructor in the __CTOR_LIST__ but I am not sure what is the most correct for this application.
I wonder if the PowerPC falls in the ARM class of not using .init and .fini?
To find out write a function in main.c that would use them to turn an LED on.
void main_init( void ) __attribute__ ((naked)) __attribute__ ((section(".init")));
void main_init( void )
{
/* what it takes to see something happen if this function is run */
/* keep it simple as little of the system may be initialized at this point */
}
int main( void )
{
return( 0 );
}
Does the NEWLIB documentation have anything to say about any of this?
ARM requires in the linker script something along the lines of this:
/* For dynamic linking/C++ these needs to be in RAM:
.preinit_array :
{/ * This section holds an array of function pointers that contributes to a single pre-initialization array for the executable or shared object containing the section * /
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array*))
PROVIDE_HIDDEN (__preinit_array_end = .);
} > FLASH
.init_array :
{/ * This section holds an array of function pointers that contributes to a single initialization array for the executable or shared object containing the section * /
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT(.init_array.*)))
KEEP (*(.init_array*))
PROVIDE_HIDDEN (__init_array_end = .);
} > FLASH
.fini_array :
{/ * This section holds an array of function pointers that contributes to a single termination array for the executable or shared object containing the section * /
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT(.fini_array.*)))
KEEP (*(.fini_array*))
PROVIDE_HIDDEN (__fini_array_end = .);
} > FLASH
*/
Hi Peter,
reading your case, it reminded me about a similar problem I had with code coverage, where the startup code missed to call the constructors. I wrote an article about this (Code Coverage for Embedded Target with Eclipse, gcc and gcov | MCU on Eclipse ), see section 'Coverage Constructors'. I have implemented my own startup extension to call these constructors.
Maybe this is helpful,
Erich
Hello Peter,
Yesterday, I spent whole day by searching and testing this use case, but I have to admit, that information I had found did not help me to create working example. I will try to contact my colleague today and ask him, if he can help me. If he does not know, what is wrong, we will contact compiler team and ask them about some additional information.
I will inform you as soon as I have any relevant information.
Regards,
Martin