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.

Compiler/TMS320C6657: Global variables in external memory not initialized to zero.

Part Number: TMS320C6657
Other Parts Discussed in Thread: AM5728, BEAGLEBOARD-X15, TM4C1294NCPDT, SEGGER

Tool/software: TI C/C++ Compiler

What the title says.  According to the ANSI C standard ALL static variables should be initialized to zero or null.  And yes, we are using EABI.

  • lemmiwinks said:
    According to the ANSI C standard ALL static variables should be initialized to zero or null.

    For that to work in all cases on embedded targets may require some action from the boot loader. Some questions to try and understand the problem:

    1) If the Initialization Model linker option is --rom_model then the C run time library start-up code will zero-initialise global variables. Whereas if the Initialization Model linker option is --ram_model then the boot loader is responsible to zero-initialise global variables. Which Initialization Model option is used?

    2) The thread title says "Global variables in external memory not initialized to zero". Are global variables in internal memory being initialized correctly? Is the external memory interface initialized before the program is loaded?

  • 1. --ram model. The "bootloader" is a Blackhawk 560 USB emulator.

    2. "Some" global variables in internal memory are initialized correctly. It definitely seems to be a compiler or linker problem. We have a data section we created called "int_data_sram" which is the L2 memory on the device. If we use #pragma SET_DATA_SECTION("int_data_sram") any global variables placed in that section ARE initialized. However if we use #pragma SET_DATA_SECTION(), which sets the data section to default (which is also L2 memory) global variables are NOT initialized.

    I'm sure there's a setting somewhere to control this but we've spent days looking through the thousands of compiler and linker switches and options and can't find anything.

    If we specifically initialize a variable, i.e. int my_global_var = 0;, then it DOES get initialized but we shouldn't have to do that.
  • lemmiwinks said:
    I'm sure there's a setting somewhere to control this but we've spent days looking through the thousands of compiler and linker switches and options and can't find anything.

    I created the following program to test the behaviour of initialized and un-initialized global variables:

    #include <stdio.h>
    #include <stdbool.h>
    
    #define NUM_DATA_WORDS 32
    
    int uninitialised_data[NUM_DATA_WORDS];
    int initialised_data[NUM_DATA_WORDS] =
    {
        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ,15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
    };
    
    int main(void)
    {
        int index;
        int num_expected_values;
    
        num_expected_values = 0;
        for (index = 0; index < NUM_DATA_WORDS; index++)
        {
            if (uninitialised_data[index] == 0)
            {
                num_expected_values++;
            }
        }
        printf ("num expected uninitialised_values=%d\n", num_expected_values);
    
        num_expected_values = 0;
        for (index = 0; index < NUM_DATA_WORDS; index++)
        {
            if (initialised_data[index] == (index + 1))
            {
                num_expected_values++;
            }
        }
        printf ("num expected initialised_values=%d\n", num_expected_values);
    
        for (index = 0; index < NUM_DATA_WORDS; index++)
        {
            uninitialised_data[index]++;
            initialised_data[index]++;
        }
    
        return 0;
    }

    The tests were performed using:

    1) Running the same program in both the ARM Cortex-A15 and C66 cores of an AM5728.

    2) A BeagleBoard-X15 connected with a Blackhawk USB560-M Emulator, 20-pin JTAG cable used to download the program.

    3) CCS 7.2.0.00013.

    4) Compiler TI v17.3.0.STS for the Cortex-A15 program.

    5) Compiler TI v8.1.4 for the C66 program.

    6) The programs stored in the AM5728 512kB L3 OCMC SRAM1, I.e. internal device memory.

    The results were:

    a) When the Cortex-A15 and C66 programs were set to --rom_model the uninitialised_data[] and initialised_data[] arrays were set to the expected values when the program was loaded or re-loaded from the CCS debugger. The use of --rom_model means code in the compiler run-time library start up zero-initializes variables with a static duration which have no initializer.

    b) When the Cortex-A15 and C66 programs were set to --ram_model the initialised_data[] array was set to the expected value when the program was loaded or re-loaded from the CCS debugger. However, the uninitialised_data[] was NOT zero-initialized when the program was loaded or re-loaded from the CCS debugger. When the program was re-loaded the uninitialised_data[] array had the same contents as the previous run. The use of --ram_model means the CCS debugger is responsible for zero-initialization of variables with a static duration which have no initializer when the program is loaded.

    Taking the C66 example when compiled with --ram_model the linker map file shows the uninitialised_data array is at address 0x40308420:

    .far       0    403082e0    000001c8     UNINITIALIZED
                      403082e0    00000140     (.common:__TI_tmpnams)
                      40308420    00000080     (.common:uninitialised_data)
                      403084a0    00000008     (.common:parmbuf)

    Looking at the ELF program headers generated by the TI linker shows:

    $ readelf.exe -l /cygdrive/C/Users/mr_halfword/workspace_v7/AM5728_C66_global_vars/Debug/AM5728_C66_global_vars.out
    
    Elf file type is EXEC (Executable file)
    Entry point 0x40306c20
    There are 6 program headers, starting at offset 189608
    
    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD           0x000040 0x40300000 0x40300000 0x06f40 0x06f40 R E 0x20
      LOAD           0x006f80 0x40306f40 0x40306f40 0x00000 0x01000 RW  0x8
      LOAD           0x006f80 0x40307f40 0x40307f40 0x0039c 0x00568 RW  0x8
      LOAD           0x007320 0x403084a8 0x403084a8 0x00174 0x00174 R   0x8
      LOAD           0x007498 0x40308620 0x40308620 0x00000 0x00120 RW  0x8
      LOAD           0x007498 0x40308740 0x40308740 0x00038 0x00038 R   0x4
    
     Section to Segment mapping:
      Segment Sections...
       00     .text
       01     .stack .sysmem
       02     .far .fardata
       03     .const
       04     .cio
       05     .switch

    The LOAD segment with the start address of 0x40307f40 has a FileSiz of 0x0039c and MemSiz of 0x00568. Since the MemSiz is greater than the FileSiz my understanding is that when the CCS debugger loads the program it should zero fill the memory range covered from the (load address + FileSiz)  .. (load address + MemSiz  - 1) which is memory addresses 0x403082dc .. 0x403084a7 which covers the location of the uninitialised_data array. Therefore the TI linker has correctly generated ELF program headers which should cause the CCS debugger to perform the zero-initialization of the uninitialised_data array when the program is loaded.

    Therefore, the problem appears to be in the CCS debugger, or possibly the driver for the Blackhawk USB560-M Emulator.

    The example programs are attached.

    AM5728_A15_global_vars.zip

    AM5728_C66_global_vars.zip

  • That was my conclusion as well, either the debugger or the emulator driver.
  • lemmiwinks said:
    That was my conclusion as well, either the debugger or the emulator driver.

    Created a version of my test program which runs in a TM4C1294NCPDT connected with a Segger J-Link. The program was compiled with TI ARM v17.3.0 and the program set to execute from SRAM with --ram_model. This device and debug probe was chosen so that could load the same ELF .out file with the CCS and IAR debuggers.

    When the program was downloaded with the CCS 7.2.0.00013 debugger the initialised_data[] array was set to the expected value when the program was loaded or re-loaded from the CCS debugger. However, the uninitialised_data[] was NOT zero-initialized when the program was loaded or re-loaded from the CCS debugger. When the program was re-loaded the uninitialised_data[] array had the same contents as the previous run.

    When the same program was downloaded with the IAR Embedded Workbench IDE - ARM 8.11.2 the uninitialised_data[] and initialised_data[] arrays were set to the expected values when the program was loaded or re-loaded.

    The ELF program headers for the example program are:

    $ readelf.exe -l /cygdrive/C/Users/mr_halfword/workspace_v7/TM4C129_RAM_global_vars/Debug/TM4C129_RAM_global_vars.out
    
    Elf file type is EXEC (Executable file)
    Entry point 0x20000d47
    There are 4 program headers, starting at offset 78032
    
    Program Headers:
      Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
      LOAD           0x000034 0x00000000 0x00000000 0x00208 0x00208 R   0x4
      LOAD           0x00023c 0x20000000 0x20000000 0x01080 0x01080 R E 0x4
      LOAD           0x0012bc 0x20001080 0x20001080 0x00000 0x00200 RW  0x4
      LOAD           0x0012bc 0x20001280 0x20001280 0x000a0 0x00120 RW  0x4
    
     Section to Segment mapping:
      Segment Sections...
       00     .intvecs .init_array
       01     .text .const
       02     .stack
       03     .data .bss

    When the program is downloaded with the CCS 7.2 debugger the Segger J-Link control panel reports the following memory writes:

    T1410 5175:057 JLINK_WriteMem(0x00000000, 0x0208 Bytes, ...) - Data: 80 12 00 20 47 0D 00 20 ... - In flash
    T1410 5175:058 JLINK_WriteMem(0x20000000, 0x1080 Bytes, ...) - Data: 0E B5 02 92 01 91 00 90 ...
    T1410 5175:211 JLINK_WriteMem(0x20001280, 0x00A0 Bytes, ...) - Data: 01 00 00 00 02 00 00 00 ...
    

    When the program is downloaded with the IAR debugger the Segger J-Link control panel reports the following memory writes:

    T1B90 000:435 JLINK_WriteMem(0x00000000, 0x0208 Bytes, ...) - Data: 80 12 00 20 47 0D 00 20 ... - In flash
    T1B90 000:435 JLINK_WriteMem(0x20000000, 0x13A0 Bytes, ...) - Data: 0E B5 02 92 01 91 00 90 ...

    Comparing the ELF program headers and the memory written to the target shows that:

    a) The IAR debugger is correctly writing to the size of memory regions given by the MemSiz fields, which therefore zero-initializes the .bss segment.

    b) The CCS 7.2 debugger is incorrectly only writing to the size of the memory regions given by the FileSiz fields, and therefore NOT zero-initializing any memory regions where the MemSiz fields are greater than the FileSiz fields.

    The example used is attached TM4C129_RAM_global_vars.zip

  • Chester Gillon said:
    b) The CCS 7.2 debugger is incorrectly only writing to the size of the memory regions given by the FileSiz fields, and therefore NOT zero-initializing any memory regions where the MemSiz fields are greater than the FileSiz fields.

    I also tested CCS 6.01 and CCS 6.2 and they behave in the same way as CCS 7.2.

    For programs using --ram_model one work-around is to place an explicit fill of zeros in the linker command file for the sections which contain the un-initialized variables. E.g. for the C66 example program:

        .far           >  OCMC_RAM1, fill = 0

    This work-around doesn't change the memory usage on the target, but the size of the ELF .out file increases by the size of the un-initialized sections.

  • Thanks for your work Chester. At this point it's in TI's hands and they need to fix it.
  • Hello TI, is there anybody home?
  • I believe this is related to unresolved issue SDSCM00042973
  • Archaeologist said:
    I believe this is related to unresolved issue SDSCM00042973

    SDSCM00042973 was raised 5 1/2 years ago, but against the "TMS470 Code Generation Tools" product even though the problem appears to be in the CCS loader.

    Is that the reason why the defect hasn't been fixed yet?

  • When the issue of the CCS debugger's loader not zero-initializing as per the ELF spec came up originally years ago, the loader was changed to do as the spec says.  The change had the unintended consequence of causing a major performance degradation for some customers. It was decided to leave the ELF standard behaviour in place, but not as the default. The feeling was that very few situations would rely on the debugger's load behaviour for an embedded program as the resulting software may not work in a live system.

    It is possible to enable the non-default zero-fill behaviour though GEL though.  Executing "GEL_EnableZeroFill(1)" in an appropriate GEL callback (StartUp, for example) would enable it.

  • AndyW said:
    It is possible to enable the non-default zero-fill behaviour though GEL though.  Executing "GEL_EnableZeroFill(1)" in an appropriate GEL callback (StartUp, for example) would enable it

    Thank you for the explanation. I confirm that worked with the combination of CCS 7.2.0.00013, Segger J-Link and TM4C1294NCPDT.