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.

Uninitialized variables using GCC.

Other Parts Discussed in Thread: TM4C123GH6PM

I'm using the latest CCS and gcc with an LM4F120XL launchpad and was investigating porting some code from an AVR project.  During debugging, I found that global variables that were assigned an initial value were being initialized to random data.   The startup ISR seems to be attempting to zero BSS and initialize data during startup, but apparently not in the way I hoped.   I simplified the code to something like:

int j = 7;

main( ...

{

//  j is random at this point.

}

Any ideas on what I might be doing wrong?

  • Moving it to the CCS Forum
  • Patrick Cameron said:
    The startup ISR seems to be attempting to zero BSS and initialize data during startup, but apparently not in the way I hoped.

    In CCS 6.0.1 there was a bug in the startup ISR functions when a new project was created in CCS, which wasn't initializing the data section correctly. See https://e2e.ti.com/support/development_tools/code_composer_studio/f/81/t/365689 for details.

    However, the problem is supposed to be fixed in the *startup_css_gcc.c files in CCS 6.1.

    Can you post the linker .lds script and code in the startup ISR?

  • CCS Version is 6.1.1.00022

    //-----------------------------------------------------------------Code & Build Output-------------------------------------------------------------------------------------
    // The test project is a default main.c project except for selecting the processor and gcc compiler.
    // The same code works properly when selecting the TI compiler but the code I am porting is not TI C compliant.
    /*
    * main.c
    */
    int j = 7;
    int main(void) {

    int i = j; // breakpoint here shows J = 536870920

    return 0;
    }

    "C:\\ti\\ccsv6\\utils\\bin\\gmake" -k all
    'Building file: ../main.c'
    'Invoking: GNU Compiler'
    "C:/ti/ccsv6/tools/compiler/gcc-arm-none-eabi-4_8-2014q3/bin/arm-none-eabi-gcc.exe" -c -mcpu=cortex-m4 -mthumb -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DPART_LM4F120H5QR -I"C:/ti/ccsv6/tools/compiler/gcc-arm-none-eabi-4_8-2014q3/arm-none-eabi/include" -ffunction-sections -fdata-sections -g -gdwarf-3 -gstrict-dwarf -Wall -MD -std=c99 -pedantic -c -MMD -MP -MF"main.d" -MT"main.d" -o"main.o" "../main.c"
    ../main.c: In function 'main':
    ../main.c:7:6: warning: unused variable 'i' [-Wunused-variable]
    int i = j;
    ^
    'Finished building: ../main.c'
    ' '
    'Building target: InitTest.out'
    'Invoking: GNU Linker'
    "C:/ti/ccsv6/tools/compiler/gcc-arm-none-eabi-4_8-2014q3/bin/arm-none-eabi-gcc.exe" -mthumb -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -DPART_LM4F120H5QR -ffunction-sections -fdata-sections -g -gdwarf-3 -gstrict-dwarf -Wall -Wl,-Map,"InitTest.map" -o"InitTest.out" "./lm4f120h5qr_startup_ccs_gcc.o" "./main.o" -Wl,-T"../lm4f120h5qr.lds" -Wl,--start-group -l"c" -l"gcc" -l"nosys" -Wl,--end-group
    'Finished building target: InitTest.out'

    //---------------------------------------------------------------------------Reset ISR-------------------------------------------------------------------------------------------
    // I tried reversing the BSS zero and the initial value copy from flash to be sure it wasn't zeroing my initial values, but they are random
    // so that wasn't likely the trouble. This is what CCS created.
    void
    ResetISR(void)
    {
    uint32_t *pui32Src, *pui32Dest;

    //
    // Copy the data segment initializers from flash to SRAM.
    //
    pui32Src = &__etext;
    for(pui32Dest = &__data_start__; pui32Dest < &__data_end__; )
    {
    *pui32Dest++ = *pui32Src++;
    }

    //
    // Zero fill the bss segment.
    //
    __asm(" ldr r0, =__bss_start__\n"
    " ldr r1, =__bss_end__\n"
    " mov r2, #0\n"
    " .thumb_func\n"
    "zero_loop:\n"
    " cmp r0, r1\n"
    " it lt\n"
    " strlt r2, [r0], #4\n"
    " blt zero_loop");

    //
    // Enable the floating-point unit. This must be done here to handle the
    // case where main() uses floating-point and the function prologue saves
    // floating-point registers (which will fault if floating-point is not
    // enabled). Any configuration of the floating-point unit using DriverLib
    // APIs must be done here prior to the floating-point unit being enabled.
    //
    // Note that this does not use DriverLib since it might not be included in
    // this project.
    //
    HWREG(0xE000ED88) = ((HWREG(0xE000ED88) & ~0x00F00000) | 0x00F00000);

    //
    // Call the application's entry point.
    //
    main();
    }
    //---------------------------------------------------------------------------LDS-------------------------------------------------------------------------------------------


    /******************************************************************************
    *
    * Default Linker script for the Texas Instruments LM4F120H5QR
    *
    * This is part of revision 12770 of the Stellaris Peripheral Driver Library.
    *
    *****************************************************************************/

    MEMORY
    {
    FLASH (RX) : ORIGIN = 0x00000000, LENGTH = 0x00040000
    SRAM (WX) : ORIGIN = 0x20000000, LENGTH = 0x00008000
    }

    REGION_ALIAS("REGION_TEXT", FLASH);
    REGION_ALIAS("REGION_BSS", SRAM);
    REGION_ALIAS("REGION_DATA", SRAM);
    REGION_ALIAS("REGION_STACK", SRAM);
    REGION_ALIAS("REGION_HEAP", SRAM);
    REGION_ALIAS("REGION_ARM_EXIDX", FLASH);
    REGION_ALIAS("REGION_ARM_EXTAB", FLASH);

    SECTIONS {

    PROVIDE (_intvecs_base_address = 0x0);

    .isr_vector (_intvecs_base_address) : AT (_intvecs_base_address) {
    KEEP (*(.isr_vector))
    } > REGION_TEXT

    PROVIDE (_vtable_base_address = 0x20000000);

    .vtable (_vtable_base_address) : AT (_vtable_base_address) {
    KEEP (*(.vtable))
    } > REGION_DATA

    .text : {
    CREATE_OBJECT_SYMBOLS
    KEEP (*(.text))
    *(.text.*)
    . = ALIGN(0x4);
    KEEP (*(.ctors))
    . = ALIGN(0x4);
    KEEP (*(.dtors))
    . = ALIGN(0x4);
    __init_array_start = .;
    KEEP (*(.init_array*))
    __init_array_end = .;
    *(.init)
    *(.fini*)
    } > REGION_TEXT

    PROVIDE (__etext = .);
    PROVIDE (_etext = .);
    PROVIDE (etext = .);

    .rodata : {
    *(.rodata)
    *(.rodata*)
    } > REGION_TEXT

    .data : ALIGN (4) {
    __data_load__ = LOADADDR (.data);
    __data_start__ = .;
    KEEP (*(.data))
    KEEP (*(.data*))
    . = ALIGN (4);
    __data_end__ = .;
    } > REGION_DATA AT> REGION_TEXT

    .ARM.exidx : {
    __exidx_start = .;
    *(.ARM.exidx* .gnu.linkonce.armexidx.*)
    __exidx_end = .;
    } > REGION_ARM_EXIDX

    .ARM.extab : {
    *(.ARM.extab* .gnu.linkonce.armextab.*)
    } > REGION_ARM_EXTAB

    .bss : {
    __bss_start__ = .;
    *(.shbss)
    KEEP (*(.bss))
    *(.bss.*)
    *(COMMON)
    . = ALIGN (4);
    __bss_end__ = .;
    } > REGION_BSS

    .heap : {
    __heap_start__ = .;
    end = __heap_start__;
    _end = end;
    __end = end;
    KEEP(*(.heap))
    __heap_end__ = .;
    __HeapLimit = __heap_end__;
    } > REGION_HEAP

    .stack : ALIGN(0x8) {
    _stack = .;
    __stack = .;
    KEEP(*(.stack))
    } > REGION_STACK
    }
  • Chester - in response to your query, I tried moving the data segment from SRAM into FLASH in the LDS file. This makes more sense to me, since the SRAM wouldn't be a permanent source. If I change from SRAM to FLASH int the LDS:

    REGION_ALIAS("REGION_DATA", FLASH);

    Then the program initializes as expected.

    I've had previous versions of CCS installed on my system. Is it possible that this is a bug that was left over?

    Thanks for the your help.
  • Patrick Cameron said:
    I've had previous versions of CCS installed on my system. Is it possible that this is a bug that was left over?

    I used CCS 6.1.1.00022 to create projects using the GNU v4.8.4 compiler for both a Stellaris LM4F230H5QR and a Tiva TM4C123GH6PM. The main.c contained:

    #include <string.h>
    
    char test_string[20] = "Hello World\n";
    
    int main(void)
    {
    
        volatile size_t len = strlen(test_string);
    
        return len;
    }
    

    After creating the projects, the steps involved to get the programs to run correctly were:

    1) In both the lm4f230h5qr.lds and tm4c123gh6pm.lds add ENTRY(ResetISR) prior to the SECTIONS:

    ENTRY(ResetISR)
    SECTIONS {
    

    This is to ensure the CCS debugger knows the correct entry point for the program when starting a debug session, and that the program runs to main. This was previously reported in https://e2e.ti.com/support/development_tools/code_composer_studio/f/81/t/417208 but neither the Tiva nor Stellaris GNU default linker scripts in CCS have been updated.

    2) Under the CCS project properties for the Stellaris LM4F230H5QR project change CCS Build -> GNU Compiler -> Runtime -> Specify the name of the target architecture (-march) from blank to armv7e-m. This is required to link the correct run time library for a Cortex-M4, to stop the strlen() function generating a hard fault.

    [When the -march is not specified a run time library which uses ARM mode instructions was linked, and the Cortex-M4 can only execute THUMB mode instructions]

    When the Tiva TM4C123GH6PM project was created, CCS 6.1.1 set the correct -march option.

    3) In the Stellaris LM4F230H5QR project the test_string global variable was not initialized with the correct contents. To initialize the data section correctly, in the lm4f230h5qr_startup_ccs_gcc.c file corrected the ResetISR function to copy the data section from __data_load__ rather than __etext:

    //*****************************************************************************
    //
    // The following are constructs created by the linker, indicating where the
    // the "data" and "bss" segments reside in memory.  The initializers for the
    // for the "data" segment resides immediately following the "text" segment.
    //
    //*****************************************************************************
    extern uint32_t __data_load__;
    extern uint32_t __data_start__;
    extern uint32_t __data_end__;
    extern uint32_t __bss_start__;
    extern uint32_t __bss_end__;
    
    //*****************************************************************************
    //
    // This is the code that gets called when the processor first starts execution
    // following a reset event.  Only the absolutely necessary set is performed,
    // after which the application supplied entry() routine is called.  Any fancy
    // actions (such as making decisions based on the reset cause register, and
    // resetting the bits in that register) are left solely in the hands of the
    // application.
    //
    //*****************************************************************************
    void
    ResetISR(void)
    {
        uint32_t *pui32Src, *pui32Dest;
    
        //
        // Copy the data segment initializers from flash to SRAM.
        //
        pui32Src = &__data_load__;
        for(pui32Dest = &__data_start__; pui32Dest < &__data_end__; )
        {
            *pui32Dest++ = *pui32Src++;
        }
    
        //
        // Zero fill the bss segment.
        //
        __asm("    ldr     r0, =__bss_start__\n"
              "    ldr     r1, =__bss_end__\n"
              "    mov     r2, #0\n"
              "    .thumb_func\n"
              "zero_loop:\n"
              "        cmp     r0, r1\n"
              "        it      lt\n"
              "        strlt   r2, [r0], #4\n"
              "        blt     zero_loop");
    
        //
        // Enable the floating-point unit.  This must be done here to handle the
        // case where main() uses floating-point and the function prologue saves
        // floating-point registers (which will fault if floating-point is not
        // enabled).  Any configuration of the floating-point unit using DriverLib
        // APIs must be done here prior to the floating-point unit being enabled.
        //
        // Note that this does not use DriverLib since it might not be included in
        // this project.
        //
        HWREG(0xE000ED88) = ((HWREG(0xE000ED88) & ~0x00F00000) | 0x00F00000);
        
        //
        // Call the application's entry point.
        //
        main();
    }
    

    When the Tiva TM4C123GH6PM project was created, the CCS 6.1.1 tm4c123gh6pm_startup_ccs_gcc.c contained the correct code to initialize the data segment.

    i.e. for points 2 and 3 the CCS 6.1.1 GNU linker scripts and *_startup_ccs_gcc.c files are correct for Tiva devices but incorrect for Stellaris devices. Not sure if this is because StellarisWare is no longer being maintained.

    Hopefully this explains the reason for your problem.

  • Chester,

    Thank you for your valuable and detailed analysis.

    Just FYI for those hitting similar issues, these items are captured in this wiki page:

    http://processors.wiki.ti.com/index.php/Using_GCC_with_Tiva_in_CCSv6