This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RM46L850: startup codes not call global c++ constructors

Part Number: RM46L850
Other Parts Discussed in Thread: HALCOGEN, TMS570LC4357, , LAUNCHXL2-RM46

I'm using HALCoGen generated startup code and linker file. I'm using gcc format outputs.

In C++, if I have a class which is instantiated global, the constructor is never called. 

static myClass myClassObj;

I was never hitting a breakpoint in the constructor, nor were the member variables being set. 

I used some code outlined here in the section Coverage Constructors.

https://mcuoneclipse.com/2014/12/26/code-coverage-for-embedded-target-with-eclipse-gcc-and-gcov/

The linker file already outputted the .init_array all that was needed was the execution of this function.

/* call the coverage initializers if not done by startup code */
void static_init(void) {
  void (**p)(void);
  extern uint32_t __init_array_start, __init_array_end; /* linker defined symbols, array of function pointers */
  uint32_t beg = (uint32_t)&__init_array_start;
  uint32_t end = (uint32_t)&__init_array_end;
 
  while(beg<end) {
    p = (void(**)(void))beg; /* get function pointer */
    (*p)(); /* call constructor */
    beg += sizeof(p); /* next pointer */
  }
}
Is the constructor execution supposed to happen automatically in TI code? In the past I've used HALCoGen and I don't recall needing to do this. 



  • I'm using HALCoGen generated startup code and linker file. I'm using gcc format outputs.

    In C++, if I have a class which is instantiated global, the constructor is never called. 

    I found that with the HL_sys_startup.c created by HALCoGen for GCC and a TMS570LC4357 the issue was that the HALCoGen start-up code calls main() directly, rather than calling  _start(). Where  _start() is the newlib entry point, which will call global constructors (amongst start-up actions), before calling main.

    HL_sys_startup.c is from an example project where code was inserted into HALCoGen USER CODE blocks in the _c_int00() function to call _start() and call global constructors. There are comments describing other project changes which were necessary to ensure _start() sets the correct stack pointer.

    I don't think I previously reported this issue to TI.

  • Thanks Chester 

  • Thank you Chester for the explanation and the link. I followed all of your code in that project, and my newlib _start(); function is causing a _dabort call at instruction "ldmdb r3, {sp}^". 

    QJ Wang, does TI intend to fix this? I would expect that the output is the same whether using "GCC Tools" or "Texas Instrument Tools."

    Any thoughts on why my newlib is faulting and how to fix? 

  • Hi Michael,

    We don't have plan to update the HALCOGen drivers, but I will add the walkaround to the new HAL release note.

  • Any thoughts on why my newlib is faulting and how to fix? 

    Based upon the instruction which causes the dabort, the stack pointer may not be set correctly.

    Which version of GCC are you using?

  • I'm using version 
    gcc version 6.3.1 20170620 (15:6.3.1+svn253039-1build1)

  • I'm using version 
    gcc version 6.3.1 20170620 (15:6.3.1+svn253039-1build1)

    The attached project has been set up for a RM46L850 using gcc-arm-none-eabi-6-2017-q1-update installed by CCS 10.4.0.00006, along with HALCoGen v04.07.01.

    That GCC installed by CCS reports its version as "gcc version 6.3.1 20170215 (release) [ARM/embedded-6-branch revision 245512]" so there might be some differences in newlib.

    https://github.com/Chester-Gillon/E2E_example_projects/commit/4437dc6e2b0d589acceb9e1647b4fe132baf34e6 is the commit which changed the _c_int00() start-up function to call the newlib _start() function rather than directly calling main(), and thus shows the modification in context. As well as changing the _c_int00() function had to modify a linker script to set the __stack symbol which _start() sets the stack pointer to.

    When run on a LAUNCHXL2-RM46 produced the following output on the serial console:

    C++ test
    global_instance.initialised=0xfeedabba
    stack_instance.initialised=0xfeedabba
    sqrtf(123.45)=11.1108
    sqrt(123.456789)=11.11111106055556
    Division by Zero.

    The non-zero value reported for global_instance.initialised shows the global constructor was called.

    If you still have issues with these changes, can you point me at where to download "gcc version 6.3.1 20170620" and possibly post your linker map, as there might be other changes required to allow _start() to be called correctly.

    RM46L850_GCC_halcogen_cpp.zip

  • Hi Chester. Thank you for taking all the time to make the example project and testing it. I took in all of your changes on my board and ran into the same problem. Regarding my gcc version, I think it can be downloaded here. packages.ubuntu.com/.../gcc-arm-none-eabi

  • Regarding my gcc version, I think it can be downloaded here. packages.ubuntu.com/.../gcc-arm-none-eabi

    OK, I installed that version on Ubuntu using:

    sudo apt install gcc-arm-none-eabi

    The CCS C/C++ General -> Preprocessor Include Paths -> Entries -> TI GNU C++ -> CCS Built-in Compiler Settings had __VERSION__="6.3.1 20170620

    Selected that compiler in the CCS 10.4 project and re-built.

    The CCS C/C++ General -> Preprocessor Include Paths -> Entries -> TI GNU C++ -> CCS Built-in Compiler Settings had __VERSION__="6.3.1 20170620

    The linker map file confirmed that was using the libraries from the Ubuntu installed package:

    .text 0x00000000000000e4 0x68 /usr/lib/gcc/arm-none-eabi/6.3.1/../../../arm-none-eabi/lib/thumb/v7-ar/fpv3/hard/crt0.o
    0x00000000000000e4 _start
    0x00000000000000e4 _mainCRTStartup

    I.e. confirm had selected the correct compiler.

    The C++ test project still ran successfully, and the output indicated the global C++ constructor had been called:

    C++ test
    global_instance.initialised=0xfeedabba
    stack_instance.initialised=0xfeedabba
    sqrtf(123.45)=11.1108
    sqrt(123.456789)=11.11111106055556
    Division by Zero.

    I.e. can't repeat your failure.

    Are you able to post the non-working project?

  • Thanks Chester. You did that fast! I appreciate the support.

    I can't post the project. I made same changes to the stack for USB, here are some details that are related to the changes.


    sys_link.ld

    __stack = 0x08001900;

    sys_core.s

    userSp:  .word 0x08000000+0x00001900
    svcSp:   .word 0x08000000+0x00001900+0x00000100
    fiqSp:   .word 0x08000000+0x00001900+0x00000100+0x00000100
    irqSp:   .word 0x08000000+0x00001900+0x00000100+0x00000100+0x00000100
    abortSp: .word 0x08000000+0x00001900+0x00000100+0x00000100+0x00000100+0x00000100
    undefSp: .word 0x08000000+0x00001900+0x00000100+0x00000100+0x00000100+0x00000100+0x00000100

    sys_startup.c entry (same as your code)

        register int *sp asm("sp");
        if (__stack != sp)
        {
            for(;;)
            {
            }
        }
    
        /* Call the newlib entry point, which will call global constructors (amongst start-up actions), before calling main */
        _start();
    
        /* In case _start() returns */
        exit(0);

  • I made same changes to the stack for USB, here are some details that are related to the changes.

    I changed the user stack size in the C++ test program to match your values, in case there was an issue with assumed stack alignment in newlib, but still couldn't repeat the failure.

    I will try and enable coverage, since that is what you mentioned in the original post.

  • I will try and enable coverage, since that is what you mentioned in the original post.

    I enabled coverage via the -fprofile-arcs -ftest-coverage options. Didn't get as far as making changed to save the coverage data but did:

    a. See a compiler gcov constructor for a source file being called from _start()

    b. In the memory browser saw the __gcov0.main counts changed as stepped the code

    I.e. still can't recreate the issue with _start() causing a data abort.

    Although it probably isn't related to your failure, in the example linker script had the following to allow C++ exceptions to work without causing a crash:

    /* Work-around the issue where the HALCoGen generated sys_link.ld places the read-only .ARM.extab section in RAM rather than FLASH.
       Placed in a separate linker script due to sys_link.ld not containing any USER CODE blocks to preserve changes.
       For this to work relies upon this linker script being passed to the linker after sys_link.ld by CCS.
    
       The following thread was raised to report the issue:
       https://e2e.ti.com/support/microcontrollers/other/f/other-microcontrollers-forum/996446/halcogen-halcogen-04-07-01-hl_sys_link-ld-gcc-linker-script-places-read-only-section-arm-extab-section-in-ram-not-flash
    */
    SECTIONS
    {
       .ARM.extab   : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH
    }
    

    I can't post the project

    Could you post just the linker map file, as that might give a clue. E.g. in case some sections aren't being placed correctly as I found with the .ARM.extab section required for C++ exceptions.

  • I took another look at your example project and this thread. I noticed that above you said:

    .text 0x00000000000000e4 0x68 /usr/lib/gcc/arm-none-eabi/6.3.1/../../../arm-none-eabi/lib/thumb/v7-ar/fpv3/hard/crt0.o
    0x00000000000000e4 _start

    My map file had it at a different address, 128 or so. I took another look at your example project and found some differences with the the compiler flags and linked libraries. I added those in, and I'm not sure which of them fixed it, but it is working now. 

    The ones I added in are 

    additional flags for compiler/linker:
    -mfloat-abi=hard
    -mcpu=cortex-r4
    
    and linked to libs:
    c
    stdc++

    Thanks for all the help!