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.

How to specify entry point using CCSv5 and MSP430 linker v4.2.1

Other Parts Discussed in Thread: MSP430F5438A, MSP-FRAM-UTILITIES

I have been unable to specify an entry point using CCSv5 and MSP430 linker version 4.2.1. I have specified my entry point in Properties->MSP430 Linker->Advanced Options (--entry_point). I have specified the the object file containing my entry point as the first to be linked (Properties->MSP430 Linker->File Search Path). The linker always seems to link _c_int00, as I get the following error with each attempt:

"../lnk_msp430f5438a.cmd", line 221: error #10099-D: program will not fit into
available memory. placement with alignment fails for section ".reset" size
0x4 . Available memory ranges:
RESET size: 0x2 unused: 0x2 max hole: 0x2

Is there any way to stop the linker from linking in _c_int00? I have even tried changing my entry point to _c_int00, but then the linker complains of a duplicate symbol.

  • Hi Steve,

    Interesting question. I was wondering why you are trying to change the entry point? Is there a reason for making your own c-startup code for _c_int00 instead of using the one from the run-time support library? I'm just wondering, because there may be an easier option here (like using __system_pre_init() for example to be able to set some things before main). Or maybe you are implementing a custom main-memory bootloader like in MSP-BOOT (www.ti.com/.../slaa600 )?

    From what I can find in the linker information in www.ti.com/.../slau131 section 8.4.11 Define an Entry Point, it says: "The _c_int00 symbol must be the entry point if you are linking code produced by the C compiler." Which would mean you'd have to override _c_int00 with your own version. Looking at the code that goes with MSP-BOOT software-dl.ti.com/.../index_FDS.html it does include an example of overriding _c_int00 (look in the file boot.c), so you may want to use this as a reference if there's no other way to achieve your goal.

    Regards,
    Katie

  • Thank you for your prompt reply!

    We need our own entry point to save RAM to NVM on reboot due to firmware errors. For all but watchdog timeouts and key violations we can save state in an interrupt service routine. WDT and KEYV errors must determine boot cause and save state before the stack is initialized. __sytetem_pre_init(), as it must, gets called after the stack is initialized.

    Unfortunately, my boot.c looks pretty much the same as the MSP-BOOT file.

    The interesting thing is that this works perfectly well using the 4.1.5 toolchain.
  • Hi Steve,

    Maybe something in your project setting would be needed as well. Your comment reminded me of something from earlier this year: I don't know if this could be related (it was talking about a later compiler version actually). I also know that MSP-BOOT involves some linker file modifications as well so you may want to inspect the custom linker files included with it as well.

    I took a look at boot.c in the run time support library. I'm using a newer compiler version, but hopefully this hasn't changed much. I can find the rts library source code in my ccsv6 installation at C:\ti\ccsv6\tools\compiler\msp430_4.2.6\lib\src. Looking in boot.c, I see this:

    /*****************************************************************************/
    /* C_INT00() - C ENVIRONMENT ENTRY POINT                                     */
    /*****************************************************************************/
    #pragma CLINK(_c_int00)
    CSTART_DECL _c_int00()
    {
       STACK_INIT();
       
       /*------------------------------------------------------------------------*/
       /* Allow for any application-specific low level initialization prior to   */
       /* initializing the C/C++ environment (global variable initialization,    */
       /* constructers).  If _system_pre_init() returns 0, then bypass C/C++     */
       /* initialization.  NOTE: BYPASSING THE CALL TO THE C/C++ INITIALIZATION  */
       /* ROUTINE MAY RESULT IN PROGRAM FAILURE.                                 */
       /*------------------------------------------------------------------------*/
       if(_system_pre_init() != 0)  _auto_init();
    
       /*------------------------------------------------------------------------*/
       /* Handle any argc/argv arguments if supported by an MSP430 loader.       */
       /*------------------------------------------------------------------------*/
       _args_main();
    
       exit(1);
    }

    Then looking in boot.h, I see STACK_INIT() is really just defined as:

    /*---------------------------------------------------------------------------*/
    /* Macro to initialize stack pointer.  Stack grows towards lower memory.     */
    /*---------------------------------------------------------------------------*/
    #if defined(__LARGE_DATA_MODEL__)
    #define STACK_INIT() __asm("\t   MOVX.A\t   #__STACK_END,SP")
    #else
    #define STACK_INIT() __asm("\t   MOV.W\t    #__STACK_END,SP")
    #endif

    So I think really the only thing that STACK_INIT() actually changes is the value of the SP register. You could simply change it back to wherever else you want (wherever maybe you know you have space in RAM to have stack while you are doing your copy to NVM?) in _system_pre_init, and I don't think that should really have changed anything in RAM.

    As a note, this is actually what our new Compute Through Power Loss (CTPL) library does (it is part of our new MSP-FRAM-UTILITIES for FRAM devices). That library is using _system_pre_init to bypass our normal c-startup code variable initialization etc, because in that case we are wanting to copy the variables and peripheral states that we saved to FRAM as we were losing power back into the peripheral registers and RAM, rather than using initial startup values - this includes the stack being initialized to the same state it was in as we were losing power. So that library simply lets the STACK_INIT() call in _c_int00 occur, but then in _system_pre_init simply reinitializes the SP (and stack values in RAM) to whatever we'd saved.

    Regards,

    Katie

  • Katie,

    Again, thank you for the quick response.

    I do understand that STACK_INIT() only modifies the stack pointer, but the SP is the most important bit of state information that we are trying to preserve, as the purpose of saving RAM is for crash analysis. We absolutely must be able to specify our own entry point for this reason.

    - Steve

  • Hi Steve,

    I see that you already tried overriding the _c_int_00, but you got some errors due to duplicate symbols.
    Try declaring the following in your file:
    #pragma CLINK(__TI_cleanup_ptr)
    void (*__TI_cleanup_ptr)(void) = NULL;
    #pragma CLINK(__TI_dtors_ptr)
    void _DATA_ACCESS (*__TI_dtors_ptr)(int) = NULL;

    With versions 4.4.0 and greater of the MSP compiler, the boot routine was changed to use __TI_cleanup_ptr and __TI_dtors_ptr instead of _cleanup_ptr and _dtors_ptr. Without those symbols, the linker ultimately links in the boot routine from the library to resolve them. When those are linked in, we get an extra copy of the reset vector and stack as well.

    Regards,
    Luis R
  • Luis,

    That was it! Thank You!

    I do have another question. It seems the map file generated does not correctly indicate the "used" value in the memory configuration section:

    MEMORY CONFIGURATION

    name origin length used unused attr fill
    ---------------------- -------- --------- -------- -------- ---- --------
    .
    .
    .
    ACTIMG1 00006480 00009b00 00005bd0 00003f30 RWIX
    .
    .
    .
    .text.1 0 00009260 00002df2
    .
    .
    .
    0000c050 00000002 sdfsm.obj (.text:sdSetThreshold)

    As you can see, the 2 bytes at c050 are in the unused space of ACTIMG1.

    The reason this is important is that we have a post build tool that processes the map file in order to create a command file for hex430 to output an intel hex file with no holes. (This is necessary for building an over the air code download file, which needs to be as small as possible.) I am using version 4.2.1 of the toolchain. Has this been fixed in a subsequent release?
  • Hi Steve,

    I wasn't aware of this issue and I don't see any relevant bugs getting fixed in the release notes.
    However, I can't replicate the problem with both CCS 6.1 or CCS 5.5. Do you have a code snippet?

    You are not using absolute memory placement right? I can how placing a constant variable in an absolute memory location can cause such overlap, but if you are not doing that, then this definitively looks like a linker bug. The CCS E2E forum might be a better place to get an answer in such case.


    And just as an additional comment, when you mention that you want to create an hex file output with no holes, do you mean filling all unused memory? What about using something like:
    FLASH : origin = 0x5C00, length = 0xA380, fill = 0x3FFF


    Regards,
    Luis R
  • Luis,

    No, we are not using absolute memory placement. I will post about this issue to the CCS E2E forum.

    When I say no holes, I mean unused space not output to the Intel hex file created by hex430. An additional step takes the hex file and creates a binary image with a header describing each memory region's offset and size.

**Attention** This is a public forum