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
我正在 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