IAR 链接器配置文件。在运行时知道内存段的结束地址

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

我正在 IAR 上使用 ARM 芯片。它的链接器文件描述了一个 RAM 部分,如下所示:

堆栈和RW 全局变量存储在物理内存RAM 区域的末尾。把它放在最后对我的软件设计很重要,尽管不一定与这个特定问题相关。

我的应用程序使用了一个相当大的文件,我想将其存储在 RAM 部分之外,如下所示:

之所以要把这个“BLOB_FS”放在外面,是因为一开始只用了一次。这样,我以后可以回收该内存用于其他目的,我更喜欢永久保留一个巨大的堆。例如,假设堆栈和 RW 数据来自 0x0175000-0x017FFFF。我想通过执行以下操作来填充 BLOB_FS 数据:

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

直到运行时我才知道 blob_fs 的大小。

问题是 RAM 部分的低地址取决于您可能拥有的任何全局变量,所以我不知道 0x017xxxxx-0x017FFFFF 中的“xxxxx”到底是什么。我的 IAR ICF 文件的相关部分如下所示:

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 };

生成这样的地图文件:

"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

此配置对应于 0x017xxxxx-0x017FFFFF 的 RAM 部分。

有没有办法在运行时获取 0x017xxxxx 的准确值?

如果您知道 blob_fs 的大小上限并且有足够的可用 RAM,您可以让 linker 保留 space 按照 IAR C/C++ Development Guide 部分 RESERVING SPACE IN RAM:

中的建议为其定义一个单独的块

Often, an application must have an empty uninitialized memory area to be used for temporary storage, for example, a heap or a stack. It is easiest to achieve this at link time. You must create a block with a specified size and then place it in a memory.

In the linker configuration file, it can look like this:

define block TempStorage with size = 0x1000, alignment = 4 { };
place in RAM { block TempStorage };

使用特殊运算符 __section_begin()__section_end()__section_size(),您可以访问起始地址和第一个地址 after块以及块的大小。

IAR手册中有如下例子:

To retrieve the start of the allocated memory from the application, the source code could look like this:

/* Define a section for temporary storage. */
#pragma section = "TempStorage"
char *GetTempStorageStartAddress()
{
  /* Return start address of section TempStorage. */
  return __section_begin("TempStorage");
}

如果你不能为你blob_fs定义一个显式块,也应该可以为所有其他[=35]定义一个块=] 部分应该放在 RAM 的末尾。我认为它应该看起来像这样(未经测试):

define block RAMDATA { readwrite, block CSTACK, block SVC_STACK, block IRQ_STACK,
                                  block FIQ_STACK, block UND_STACK, 
                                  block ABT_STACK, block HEAP };

"RAM": place at end of RAM_region { readwrite, block RAMDATA }; 

然后您应该能够再次使用 __section_being("RAMDATA") 来确定在 link 时为变量等保留的 RAM 区域的起始地址,并在运行时将其用于地址计算。

我几乎按照 Blue 的建议做了它。我将我的 ICF 文件变成了(新的粗体):

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 };

新部分 .blobfssizeword 确保我知道我正在寻找的部分的名称。通过将它首先放在“RAM”内存块中(这是正确的词吗?),我确保 .blobfssizeword 占据该组中的 lowest-value 地址。

接下来,我通过一个 32 位整数从用户那里获取运行时 blobfs 的大小。所以在我的 main.cpp 中,我确保在 .blobfssizeword 部分声明:

#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;
}

完成上述操作后,我确保编译器在 .blobfssizeword 部分进行编译,因此映射文件如下所示(新的以粗体显示):

"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