Search code examples
carmiarlinker-scripts

IAR Linker Configuration File. Knowing the end address of memory section at runtime


I am working with an ARM chip on IAR. Its linker file describes a RAM section like this: enter image description here

The stack and RW global variables are stored at the end of the RAM region of physical memory. Having it at the end is important to my SW design albeit not necessarily relevant to this particular question.

My application consumes a rather large file that I want to store outside of the RAM section, like so: enter image description here

The reason I want to put this "BLOB_FS" outside is because I only use it once at the beginning. That way, I can recycle that memory for other purposes later, which I prefer over permanently reserving a giant heap. For example, let's say the stack and RW data go from 0x0175000-0x017FFFF. I would want to populate the BLOB_FS data by doing something like:

(uint32_t*) blob_fs_base_ptr = (0x0175000 - sizeof(blob_fs));
memcpy(blob_fs_base_ptr, blob_fs, sizeof(blob_fs));

I do not know the size of the blob_fs until runtime.

The problem is the lower address of the RAM section varies depending on whatever global variables you may have so I don't know what exactly the "xxxxx" in 0x017xxxxx-0x017FFFFF is ahead of time. The relevant section of my IAR ICF file looks like this:

define symbol __ICFEDIT_region_RAM_start__   = 0x01000000;
define symbol __ICFEDIT_region_RAM_end__     = 0x017FFFFF; // 8192K

define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];

"RAM": place at end of RAM_region { readwrite,
block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
block UND_STACK, block ABT_STACK, block HEAP };

Which generates a map file like this:

"RAM":                                        0x11'21d8
  rw-1                            0x16e'de28       0xbc  <Init block>
    .data                inited   0x16e'de28       0x9c  main.cpp.obj [1]
    .data                inited   0x16e'dec4       0x1c  rom_cmd_handler.cpp.obj [12]
    .data                inited   0x16e'dee0        0x4  system_cmsis_falcon2.c.obj [8]
  .bss                   zero     0x16e'dee4       0x40  main.cpp.obj [1]
  .bss                   zero     0x16e'df24      0x400  rom_cmd_handler.cpp.obj [12]
  .bss                   zero     0x16e'e324       0x28  source.cpp.obj [11]
  .bss                   zero     0x16e'e34c        0x4  blob_fs.cpp.obj [5]
  .bss                   zero     0x16e'e350        0x4  blob_fs.cpp.obj [5]
  .bss                   zero     0x16e'e354        0x8  rom_spi2c_handler.cpp.obj [12]
  .bss                   zero     0x16e'e35c      0x2a0  spi2c_falcon2.cpp.obj [13]
  .bss                   zero     0x16e'e5fc       0x7c  vmem_falcon2.cpp.obj [14]
  .bss                   zero     0x16e'e678       0x80  buffer_manager_common.cpp.obj [6]
  .bss                   zero     0x16e'e6f8       0x24  drv_irq_cortex_m3.c.obj [10]
  .bss                   zero     0x16e'e71c       0xe0  drv_irq_common.c.obj [10]
  .bss                   zero     0x16e'e7fc        0x1  buffer_manager_falcon2.cpp.obj [6]
  .bss                   zero     0x16e'e7fd        0x1  rom_spi2c_handler.cpp.obj [12]
  .noinit                uninit   0x16e'e800  0x11'0000  main.cpp.obj [1]
  .noinit                uninit   0x17f'e800      0x800  main.cpp.obj [1]
  CSTACK                          0x17f'f000     0x1000  <Block>
    CSTACK               uninit   0x17f'f000     0x1000  <Block tail>
                                - 0x180'0000  0x11'21d8

This configuration corresponds to the RAM section from 0x017xxxxx-0x017FFFFF.

Is there a way to get the exact value of 0x017xxxxx at runtime?


Solution

  • I got it working by doing pretty much what Blue suggested. I turned my ICF file into (new in bold):

    define symbol __ICFEDIT_region_RAM_start__   = 0x01000000;
    define symbol __ICFEDIT_region_RAM_end__     = 0x017FFFFF; // 8192K
    
    define region RAM_region   = mem:[from __ICFEDIT_region_RAM_start__   to __ICFEDIT_region_RAM_end__];
    
    "RAM": place at end of RAM_region { **readwrite section .blobfssizeword,** readwrite,
    block CSTACK, block SVC_STACK, block IRQ_STACK, block FIQ_STACK,
    block UND_STACK, block ABT_STACK, block HEAP };
    

    The new section .blobfssizeword ensures that I know the name of the section that I'm looking for. And by placing it first in the "RAM" memory block (is that the right word?), I make sure that .blobfssizeword occupies the lowest-value address in that group.

    Next, I get the size of the blobfs at runtime from the user via a 32-bit integer. So in my main.cpp I make sure to declare that in the .blobfssizeword section:

    #define BLOBFS_SIZE_WORD_LENGTH 4 //The blobfs size is stored in a 32-bit value
    static uint8_t __attribute__((section(".blobfssizeword"))) blobfs_size_word[BLOBFS_SIZE_WORD_LENGTH] = {0};
    
    #pragma section = ".blobfssizeword"
    void calculate_blobfs_starting_address() {
        uint32_t blobfs_size = *(reinterpret_cast<uint32_t*>(blobfs_size_word));
        memcpy(blobfs_size_word, (uint8_t*)&blobfs_size, sizeof(blobfs_size_word)); 
        //Write to array to make sure compiler doesn't optimize it out. There's probably a better way to do this, but I'm just trying to make it work
        size_t blobfs_size_word_start = (size_t)__section_begin(".blobfssizeword");
        size_t blobfs_start_addr = blobfs_size_word_start - (size_t)blobfs_size;
        return blobfs_start_addr;
    }
    

    After doing the above, I ensure the compiler compiles in the .blobfssizeword section, so the map file looks like this (new in bold):

    "RAM":                                        0x1'21d4
      **.blobfssizeword                 0x15e'de2c       0x4  <Block>
        .blobfssizeword-1             0x15e'de2c       0x4  <Init block>
          .blobfssizeword    inited   0x15e'de2c       0x4  main.cpp.obj [1]**
      rw-1                            0x15e'de30      0x28  <Init block>
        .data                inited   0x15e'de30       0x4  main.cpp.obj [1]
        .data                inited   0x15e'de34      0x20  rom_cmd_handler.cpp.obj [13]
        .data                inited   0x15e'de54       0x4  system_cmsis_falcon2.c.obj [8]
      .bss                   zero     0x15e'de58      0x40  main.cpp.obj [1]
      .bss                   zero     0x15e'de98       0x4  main.cpp.obj [1]
      .bss                   zero     0x15e'de9c       0xc  main.cpp.obj [1]
      .bss                   zero     0x15e'dea8      0x6c  main.cpp.obj [1]
      .bss                   zero     0x15e'df14      0x24  main.cpp.obj [1]
      .bss                   zero     0x15e'df38     0x400  rom_cmd_handler.cpp.obj [13]
      .bss                   zero     0x15e'e338      0x10  source.cpp.obj [12]
      .bss                   zero     0x15e'e348       0x4  blob_fs.cpp.obj [5]
      .bss                   zero     0x15e'e34c       0x8  rom_spi2c_handler.cpp.obj [13]
      .bss                   zero     0x15e'e354     0x2a0  spi2c_falcon2.cpp.obj [14]
      .bss                   zero     0x15e'e5f4      0x7c  vmem_falcon2.cpp.obj [15]
      .bss                   zero     0x15e'e670       0x8  real_otp.cpp.obj [11]
      .bss                   zero     0x15e'e678      0x80  buffer_manager_common.cpp.obj [6]
      .bss                   zero     0x15e'e6f8      0x24  drv_irq_cortex_m3.c.obj [10]
      .bss                   zero     0x15e'e71c      0xe0  drv_irq_common.c.obj [10]
      .bss                   zero     0x15e'e7fc       0x1  buffer_manager_falcon2.cpp.obj [6]
      .bss                   zero     0x15e'e7fd       0x1  rom_spi2c_handler.cpp.obj [13]
      .noinit                uninit   0x15e'e800  0x1'0000  main.cpp.obj [1]
      .noinit                uninit   0x15f'e800     0x800  main.cpp.obj [1]
      CSTACK                          0x15f'f000    0x1000  <Block>
        CSTACK               uninit   0x15f'f000    0x1000  <Block tail>
                                    - 0x160'0000  0x1'21d4