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.

SYS/BIOS large data allocation

Other Parts Discussed in Thread: AM3359

Hi all.

I'm using SYS/BIOS rev 6.33 on a AM3359 ARM cpu

I need to allocate a (quite) large amount of memory (about 32 Mbytes) to log some process value in a circular queue fashion.

I've tried the poor man's solution: 

#define		LARGE_ARRAY_SIZE		(32768)
MY_DATA_TYPE	large_data_array[LARGE_ARRAY_SIZE];

Where:
sizeof (MY_DATA_TYPE) = 1024
		

Everything works fine, but the output binary file becomes 32Mbytes! No surprise, because "large_data_array" is statically declared and placed in .bss section.  The application binary itself, without "large_data_array" is about 400Kbytes.

Problem is that I can't withstand such a big binary file, because it's placed (with other data, FPGA bitstreams and so on...) into a 16Mbit serial flash. 

Then I moved to a dynamic allocation through malloc() function:

#define		LARGE_ARRAY_SIZE		(32768)

large_data_array = ( MY_DATA_TYPE*)malloc( sizeof(MY_DATA_TYPE)*LARGE_ARRAY_SIZE); 

Where: sizeof (MY_DATA_TYPE) = 1024

I've defined a big enough heap size in .cfg SYS/BIOS configuration file, and everything still works fine.

Problem is: the binary file is 32MBytes, so no actual dynamic allocation occurs: it seems that SYS/BIOS statically allocates a 32MBytes array and uses it for malloc() and free() operations. The .map output file confirms that a 32MBytes .object is statically placed in .bss section.

Is there any trick to prevent SYS/BIOS configuration tool to create such a big chunk of static data?

I've also tried to manually place the data in an unused ddr memory region:

large_data_array = ( MY_DATA_TYPE*)0x81000000;

But the application crashes at the very first attempt to read or write.

Any hints?

  • Hi,

    I tried creating a very large heap and do not see what you are seeing above.  Yes, I do see a large section in the .bss section however, its unitialized section so it did not increase the executable size.  My executble size is only ~2MB.

    Judah

  • If you do not declare any heap memory, .bss section is placed *after* the .text section and this directive:

    .init: { boot*(.text)} > 0x80000000 /* make sure we can boot! */

     tells the linker to place the init functions at 0x80000000. The bootloader loads the binary starting from address 0x80000000 and jumps to address 0x80000000; nice and clean.

    When you declare a large heap memory section in SYS/BIOS config file, this happens:

    1) the .bss section is placed at the beginning of the memory area; in AM3359 cpu it's 0x80000000, as declared in platform configuration file.

    2) Run address and entry point are relocated *after* the .bss section.

    3) This linker command file instruction is not considered:

    .init: { boot*(.text)} > 0x80000000 /* make sure we can boot! */

    So the bootloader must load the binary file at the absolute address after the .bss section, and jump to _c_int00 (or whatever is called the entry point) at the right address.

    Step 2) is quite weird, and step 3) sounds to me as a bug... 

  • Hi Eugenio,

    I tried changing heapSize to 32M and dont see the executable size go up. I am not sure why you see the executable size go up but you can try doing the following:

    var Heap = xdc.useModule('ti.sysbios.heaps.HeapMem');   
    var Memory = xdc.useModule('xdc.runtime.Memory');
    
    var heap1 = Heap.create();
    heap1.size = 32*1024*1024; // 32MB
    heap1.sectionName = ".myHeapSect";
    Memory.defaultHeapInstance = heap1;
    
    Program.sectMap[".myHeapSect"] = new Program.SectionSpec();
    Program.sectMap[".myHeapSect"].loadSegment = "DDR3";
    Program.sectMap[".myHeapSect"].type = "NOINIT";
    

    Best,

    Ashish

  • The problem occurs when you want to place the .init section at DDR start address 0x80000000.

    This is needed because it's easier to create the binary file to be loaded starting from address 0x80000000, and the _c_int00 startup function placed at the same absolute address 0x80000000.

    If you add this linker directive:

    SECTIONS
    {
       .init: { boot*(.text)} > 0x80000000 /* make sure we can boot!            */
    }

    you'll see that the _c_int00 is in the right address, but binary size is now 32Mbytes.

    Without this linker specific directive, binary file is small, but load address and _c_int00 address is relocated during every compilation. So you have to manually:

    1. compile and link;
    2. open the .map file;
    3. find out where the linker placed the load address and the start address;
    4. update the "post_build.bat" options and manually execute it;
    5. if you don't want to manually execute that .bat file, relaunch the compiler and let Code Composer do the work.

    I don't know if you are familiar with "post_build.bat" script; it seems to be a AM3359 custom tailored tool:

    Maybe this could help, I'll run some tests.

    SECTIONS
    {
       .init: { boot*(.text)} > 0x82000000 /* make sure we can boot!            */
    }

    Last question: is there any RTSC directive to write this inside .cfg configuration file instead of adding a custom linker command file?

  • Hello,

    Can you try excluding the sections from *.cfg

    Eg: Program.sectionsExclude = "^\\.bss|^\\.data|^\\.stack";

    and adding the sections in *.cmd?

    Eg: 

    GROUP: load > DDR3
    {
    .bss:
    .data:
    .stack:
    }

    Regards,
    Vinesh

  • Hi Vinesh.

    I've tried your suggestion, unluckily with no result. This is the .map file:

    ******************************************************************************
    TI ARM Linker PC v5.0.4 
    ******************************************************************************
    >> Linked Wed Apr 23 10:36:31 2014
    
    OUTPUT FILE NAME: <15BK33G100_test.out>
    ENTRY POINT SYMBOL: "_c_int00" address: 80000000
    
    
    MEMORY CONFIGURATION
    
    name origin length used unused attr fill
    ---------------------- -------- --------- -------- -------- ---- --------
    SRAM_LO 402f0000 00000400 00000000 00000400 RW X
    SRAM_HI 402f0400 0000fc00 00000000 0000fc00 RW X
    OCMC_SRAM 40300000 00010000 00000000 00010000 RW X
    DDR2 80000000 10000000 02024db1 0dfdb24f RW X
    
    
    SEGMENT ALLOCATION MAP
    
    run origin load origin length init length attrs members
    ---------- ----------- ---------- ----------- ----- -------
    80000000 80000000 000000a0 000000a0 r-x
    80000000 80000000 0000009c 0000009c r-x .init
    8000009c 8000009c 00000004 00000004 r-x .text.1
    800000a0 800000a0 020025b0 00000000 rw-
    800000a0 800000a0 020025b0 00000000 rw- .bss
    82002650 82002650 000172cc 000172cc r-x
    82002650 82002650 000172cc 000172cc r-x .text.2
    82019920 82019920 00004a54 00000a54 rw-
    82019920 82019920 00000a54 00000a54 rw- .data
    8201a374 8201a374 00004000 00000000 rw- .stack
    8201e378 8201e378 00001c88 00001c88 r--
    8201e378 8201e378 00001c88 00001c88 r-- .const.1
    82020000 82020000 00004000 00000000 rw-
    82020000 82020000 00004000 00000000 rw- ti.sysbios.family.arm.a8.mmuTableSection
    82024000 82024000 00000669 00000669 r--
    82024000 82024000 00000669 00000669 r-- .const.2
    82024800 82024800 00000750 00000750 r--
    82024800 82024800 00000040 00000040 r-- .vecs
    82024840 82024840 00000710 00000710 r-- .cinit
    
    
    SECTION ALLOCATION MAP
    
    output attributes/
    section page origin length input sections
    -------- ---- ---------- ---------- ----------------
    .init_array 
    * 0 80000000 00000000 UNINITIALIZED
    
    xdc.meta 0 80000000 000000ed COPY SECTION
    80000000 000000ed 15bk33g100_test_pea8fnv.oea8fnv (xdc.meta)
    
    .init 0 80000000 0000009c 
    80000000 00000078 boot.aea8fnv : boot.oea8fnv (.text)
    80000078 0000000c rtsv7A8_A_le_n_v3_eabi.lib : args_main.obj (.tramp._args_main.1)
    80000084 0000000c auto_init.aea8fnv : auto_init.oea8fnv (.tramp.__TI_auto_init.1)
    80000090 0000000c rtsv7A8_A_le_n_v3_eabi.lib : exit.obj (.tramp.exit.1)
    
    .text.1 0 8000009c 00000004 
    8000009c 00000004 sysbios.aea8fnv : BIOS.obj (.text:ti_sysbios_BIOS_nullFunc__I)
    
    .bss 0 800000a0 020025b0 UNINITIALIZED
    800000a0 02000000 15bk33g100_test_pea8fnv.oea8fnv (.bss:ti_sysbios_heaps_HeapMem_Instance_State_0_buf__A)
    

    This is the only working configuration, so far:

    .cfg file:

    var Heap = xdc.useModule('ti.sysbios.heaps.HeapMem');   
    var Memory = xdc.useModule('xdc.runtime.Memory');
    var heap1 = HeapMem.create();
    heap1.size = 32*1024*1024; // 32MB
    heap1.sectionName = ".myHeapSect";
    Memory.defaultHeapInstance = heap1;
    
    Program.sectMap[".myHeapSect"] = new Program.SectionSpec();
    Program.sectMap[".myHeapSect"].loadSegment = "DDR2";
    Program.sectMap[".myHeapSect"].type = "NOINIT";

    .cmd file

    SECTIONS
    {
       .init: { boot*(.text)} > 0x82000000 /* make sure we can boot!            */
    
    }
    

    Bootloader

    Load Address = 0x82000000
    Run Address = 0x82000000

  • Hello,

    I still see .text.2 coming in between bss and stack(which ideally should not).

    The working configuration shifts the Starting point to a different address, instead, you can place the bss, stack etc. there(doesn't make a difference, but consistent with the approach)

    Eg: GROUP: load > DDR3 (HIGH)

    Regards,
    Vinesh

  • Hi Eugenio,

    I tried placing boot code at 0x80000000 but was still unable to repro the 32M binary size. Can you share your *.cfg file ?

    You can place the boot section at 0x80000000 using *.cfg code. I have shown an example below:

    var Heap = xdc.useModule('ti.sysbios.heaps.HeapMem');  
    var Memory = xdc.useModule('xdc.runtime.Memory');
    var heap1 = Heap.create();
    heap1.size = 32*1024*1024; // 32MB
    heap1.sectionName = ".myHeapSect";
    Memory.defaultHeapInstance = heap1;
    Program.sectMap[".myHeapSect"] = new Program.SectionSpec();
    Program.sectMap[".myHeapSect"].loadSegment = "DDR3";
    Program.sectMap[".myHeapSect"].type = "NOINIT";
    
    // Place boot code at 0x80000000
    Program.sectMap[".init: { boot*(.text)}"] = new Program.SectionSpec();
    Program.sectMap[".init: { boot*(.text)}"].loadAddress = 0x80000000;

    Best,

    Ashish

  • Hi Ashish.

    Here you can find two CCS v5.5 projects: the first creates a "big" binary file, the second a "small" binary file. 

    The only difference is where is placed the init section the custom linker command file: 0x80000000 in the first case, 0x82000000 (after heap section) in the second.

    BIG BINARY PROJECT --> 4113.big_binary.zip

    SMALL BINARY PROJECT --> 0116.small_binary.zip

    I've also tried to place the boot code in .cfg file as you suggested: it's very clever and neat (I don't need to add a custom .cmd file in projects), but the results are the same; 

    SECTION IN CFG FILE PROJECT --> 0576.section_in_cfg.zip

  • Hi Vinesh.

    That's correct! 

    You need to create a new section in .cfg file as previously suggested, adding the (HIGH) specifier: .bss is placed *after* code sections and everything is fine.

    I'll do some test to confirm that this code will work on actual target.

    var heap1 = HeapMem.create();
    heap1.size = 32*1024*1024; // 32MB
    heap1.sectionName = ".myHeapSect";
    Memory.defaultHeapInstance = heap1;
    
    Program.sectMap[".myHeapSect"] = new Program.SectionSpec();
    Program.sectMap[".myHeapSect"].loadSegment = "DDR3(HIGH)";
    Program.sectMap[".myHeapSect"].type = "NOINIT";

    NOTE: if you place a space between the keyword "DDR3" and "(HIGH)":

    Program.sectMap[".myHeapSect"].loadSegment = "DDR3 (HIGH)";
    

    the resulting .cmd file does not work because RTSC creates this:

    Program.sectMap[".myHeapSect"].loadSegment = "DDR3 (HIGH)";
    
    
        .ARM.extab: load >> DDR3
        .myHeapSect: load > DDR3 | (HIGH), type = NOINIT
        .vecs: load > DDR3
    

     

  • Thanks to Vinesh contribute now everything is back on its place.

    Thanks to you for suggesting the idea of embedding the init code placement in .cfg file.

    Finally this is the working .cfg script:

    var heap1 = HeapMem.create();
    heap1.size = 32*1024*1024; // 32MB
    heap1.sectionName = ".myHeapSect";
    Memory.defaultHeapInstance = heap1;
    
    Program.sectMap[".myHeapSect"] = new Program.SectionSpec();
    Program.sectMap[".myHeapSect"].loadSegment = "DDR3(HIGH)";
    Program.sectMap[".myHeapSect"].type = "NOINIT";
    
    // Place boot code at 0x80000000
    Program.sectMap[".init: { boot*(.text)}"] = new Program.SectionSpec();
    Program.sectMap[".init: { boot*(.text)}"].loadAddress = 0x80000000;

    A little bit tricky,  but effective.

    Thank you all guys!

    2061.working_project.zip

  • Hi Eugenio,

    Were you able to get the executable size down ?

    I tried importing and building the test_big_binary project you shared earlier. The executable I built with it is small (~1.8MB). I did not change anything in the project except the TI codegen version. My CCS install does not have v5.0.x that the project was pointing to so I used v5.1.1 instead.

    Best,

    Ashish

  • Hi Ashish!

    Everything is at the right place: .bss section is placed "on the high side" of ram space, and thus the binary size is correct.

    In the project I've attached the binary file to wich I refer is called "test_big_binary.bin" (see image below; please do not consider the "cone" icon: VLC takes control over .bin files!).

    "test_big_binary.out" is about 2Mbytes , but this is not what is needed by the bootloader. Actually I never used .out files, except when debugging through JTAG connection.

    I've just tested the same project on 5.1.1 tool version on a my colleague's laptop: same .bin file size (32Mbytes), and .out file size is 1.8Mbytes, exactly as you've reported.

  • Hi Eugenio,

    I think I understand the problem now. The ".bin" file is in raw binary format and is padding the noload sections including the 32MB heap section causing the ".bin" file size to inflate. I believe the solution would be to split the elf image into multiple ".bin" files where each ".bin" file represents one loadable region. I am not sure how to do this with TI codegen tools.

    I will get this post moved to the TI C/C++ compiler forum so they can help you with minimizing the size of the *.bin file.

    Best,

    Ashish

  • Hi Ashish,

    I have the same problem.

    Where is the solution or the follow discussion?

    Christoph

  • Hi Christoph,

    I had put in a request to move this thread to the C/C++ compiler forum but it looks like no one moved the thread.

    Anyways, I did try to explain the problem in my last post. There is a large NOLOAD section between LOAD sections. When the image is converted to ".bin" format, the objcopy tool (or some other similar tool that is used to convert the elf image to bin) has to somehow fill the space allocated to the NOLOAD section and ends up filling it with 0's. If the NOLOAD section is 30MB in size, then this causes the image size to grow by 30MB.

    I can think of 2 ways to fix the large bin size problem. The easier of the 2 is to push all the NOLOAD sections (or atleast the large 30MB NOLOAD section) to the end of the memory map. This will prevent the objcopy tool (elf to bin conversion tool) from filling the space allocated to the NOLOAD section with 0s. In your case, you can put the 30MB array in its own section and place it after all other output sections.

    Can you give this a try and see if it helps ?

    Best,

    Ashish

  • Hi,

    thanks so lot, it works good.

    The solution is also the type NOLOAD, I used the type NOINIT.

    Christoph